xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/micrel/ksz884x.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * drivers/net/ethernet/micrel/ksx884x.c - Micrel KSZ8841/2 PCI Ethernet driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2009-2010 Micrel, Inc.
6*4882a593Smuzhiyun  * 	Tristram Ha <Tristram.Ha@micrel.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/ioport.h>
16*4882a593Smuzhiyun #include <linux/pci.h>
17*4882a593Smuzhiyun #include <linux/proc_fs.h>
18*4882a593Smuzhiyun #include <linux/mii.h>
19*4882a593Smuzhiyun #include <linux/platform_device.h>
20*4882a593Smuzhiyun #include <linux/ethtool.h>
21*4882a593Smuzhiyun #include <linux/etherdevice.h>
22*4882a593Smuzhiyun #include <linux/in.h>
23*4882a593Smuzhiyun #include <linux/ip.h>
24*4882a593Smuzhiyun #include <linux/if_vlan.h>
25*4882a593Smuzhiyun #include <linux/crc32.h>
26*4882a593Smuzhiyun #include <linux/sched.h>
27*4882a593Smuzhiyun #include <linux/slab.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /* DMA Registers */
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #define KS_DMA_TX_CTRL			0x0000
33*4882a593Smuzhiyun #define DMA_TX_ENABLE			0x00000001
34*4882a593Smuzhiyun #define DMA_TX_CRC_ENABLE		0x00000002
35*4882a593Smuzhiyun #define DMA_TX_PAD_ENABLE		0x00000004
36*4882a593Smuzhiyun #define DMA_TX_LOOPBACK			0x00000100
37*4882a593Smuzhiyun #define DMA_TX_FLOW_ENABLE		0x00000200
38*4882a593Smuzhiyun #define DMA_TX_CSUM_IP			0x00010000
39*4882a593Smuzhiyun #define DMA_TX_CSUM_TCP			0x00020000
40*4882a593Smuzhiyun #define DMA_TX_CSUM_UDP			0x00040000
41*4882a593Smuzhiyun #define DMA_TX_BURST_SIZE		0x3F000000
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define KS_DMA_RX_CTRL			0x0004
44*4882a593Smuzhiyun #define DMA_RX_ENABLE			0x00000001
45*4882a593Smuzhiyun #define KS884X_DMA_RX_MULTICAST		0x00000002
46*4882a593Smuzhiyun #define DMA_RX_PROMISCUOUS		0x00000004
47*4882a593Smuzhiyun #define DMA_RX_ERROR			0x00000008
48*4882a593Smuzhiyun #define DMA_RX_UNICAST			0x00000010
49*4882a593Smuzhiyun #define DMA_RX_ALL_MULTICAST		0x00000020
50*4882a593Smuzhiyun #define DMA_RX_BROADCAST		0x00000040
51*4882a593Smuzhiyun #define DMA_RX_FLOW_ENABLE		0x00000200
52*4882a593Smuzhiyun #define DMA_RX_CSUM_IP			0x00010000
53*4882a593Smuzhiyun #define DMA_RX_CSUM_TCP			0x00020000
54*4882a593Smuzhiyun #define DMA_RX_CSUM_UDP			0x00040000
55*4882a593Smuzhiyun #define DMA_RX_BURST_SIZE		0x3F000000
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #define DMA_BURST_SHIFT			24
58*4882a593Smuzhiyun #define DMA_BURST_DEFAULT		8
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #define KS_DMA_TX_START			0x0008
61*4882a593Smuzhiyun #define KS_DMA_RX_START			0x000C
62*4882a593Smuzhiyun #define DMA_START			0x00000001
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #define KS_DMA_TX_ADDR			0x0010
65*4882a593Smuzhiyun #define KS_DMA_RX_ADDR			0x0014
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #define DMA_ADDR_LIST_MASK		0xFFFFFFFC
68*4882a593Smuzhiyun #define DMA_ADDR_LIST_SHIFT		2
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /* MTR0 */
71*4882a593Smuzhiyun #define KS884X_MULTICAST_0_OFFSET	0x0020
72*4882a593Smuzhiyun #define KS884X_MULTICAST_1_OFFSET	0x0021
73*4882a593Smuzhiyun #define KS884X_MULTICAST_2_OFFSET	0x0022
74*4882a593Smuzhiyun #define KS884x_MULTICAST_3_OFFSET	0x0023
75*4882a593Smuzhiyun /* MTR1 */
76*4882a593Smuzhiyun #define KS884X_MULTICAST_4_OFFSET	0x0024
77*4882a593Smuzhiyun #define KS884X_MULTICAST_5_OFFSET	0x0025
78*4882a593Smuzhiyun #define KS884X_MULTICAST_6_OFFSET	0x0026
79*4882a593Smuzhiyun #define KS884X_MULTICAST_7_OFFSET	0x0027
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /* Interrupt Registers */
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun /* INTEN */
84*4882a593Smuzhiyun #define KS884X_INTERRUPTS_ENABLE	0x0028
85*4882a593Smuzhiyun /* INTST */
86*4882a593Smuzhiyun #define KS884X_INTERRUPTS_STATUS	0x002C
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun #define KS884X_INT_RX_STOPPED		0x02000000
89*4882a593Smuzhiyun #define KS884X_INT_TX_STOPPED		0x04000000
90*4882a593Smuzhiyun #define KS884X_INT_RX_OVERRUN		0x08000000
91*4882a593Smuzhiyun #define KS884X_INT_TX_EMPTY		0x10000000
92*4882a593Smuzhiyun #define KS884X_INT_RX			0x20000000
93*4882a593Smuzhiyun #define KS884X_INT_TX			0x40000000
94*4882a593Smuzhiyun #define KS884X_INT_PHY			0x80000000
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #define KS884X_INT_RX_MASK		\
97*4882a593Smuzhiyun 	(KS884X_INT_RX | KS884X_INT_RX_OVERRUN)
98*4882a593Smuzhiyun #define KS884X_INT_TX_MASK		\
99*4882a593Smuzhiyun 	(KS884X_INT_TX | KS884X_INT_TX_EMPTY)
100*4882a593Smuzhiyun #define KS884X_INT_MASK	(KS884X_INT_RX | KS884X_INT_TX | KS884X_INT_PHY)
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /* MAC Additional Station Address */
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun /* MAAL0 */
105*4882a593Smuzhiyun #define KS_ADD_ADDR_0_LO		0x0080
106*4882a593Smuzhiyun /* MAAH0 */
107*4882a593Smuzhiyun #define KS_ADD_ADDR_0_HI		0x0084
108*4882a593Smuzhiyun /* MAAL1 */
109*4882a593Smuzhiyun #define KS_ADD_ADDR_1_LO		0x0088
110*4882a593Smuzhiyun /* MAAH1 */
111*4882a593Smuzhiyun #define KS_ADD_ADDR_1_HI		0x008C
112*4882a593Smuzhiyun /* MAAL2 */
113*4882a593Smuzhiyun #define KS_ADD_ADDR_2_LO		0x0090
114*4882a593Smuzhiyun /* MAAH2 */
115*4882a593Smuzhiyun #define KS_ADD_ADDR_2_HI		0x0094
116*4882a593Smuzhiyun /* MAAL3 */
117*4882a593Smuzhiyun #define KS_ADD_ADDR_3_LO		0x0098
118*4882a593Smuzhiyun /* MAAH3 */
119*4882a593Smuzhiyun #define KS_ADD_ADDR_3_HI		0x009C
120*4882a593Smuzhiyun /* MAAL4 */
121*4882a593Smuzhiyun #define KS_ADD_ADDR_4_LO		0x00A0
122*4882a593Smuzhiyun /* MAAH4 */
123*4882a593Smuzhiyun #define KS_ADD_ADDR_4_HI		0x00A4
124*4882a593Smuzhiyun /* MAAL5 */
125*4882a593Smuzhiyun #define KS_ADD_ADDR_5_LO		0x00A8
126*4882a593Smuzhiyun /* MAAH5 */
127*4882a593Smuzhiyun #define KS_ADD_ADDR_5_HI		0x00AC
128*4882a593Smuzhiyun /* MAAL6 */
129*4882a593Smuzhiyun #define KS_ADD_ADDR_6_LO		0x00B0
130*4882a593Smuzhiyun /* MAAH6 */
131*4882a593Smuzhiyun #define KS_ADD_ADDR_6_HI		0x00B4
132*4882a593Smuzhiyun /* MAAL7 */
133*4882a593Smuzhiyun #define KS_ADD_ADDR_7_LO		0x00B8
134*4882a593Smuzhiyun /* MAAH7 */
135*4882a593Smuzhiyun #define KS_ADD_ADDR_7_HI		0x00BC
136*4882a593Smuzhiyun /* MAAL8 */
137*4882a593Smuzhiyun #define KS_ADD_ADDR_8_LO		0x00C0
138*4882a593Smuzhiyun /* MAAH8 */
139*4882a593Smuzhiyun #define KS_ADD_ADDR_8_HI		0x00C4
140*4882a593Smuzhiyun /* MAAL9 */
141*4882a593Smuzhiyun #define KS_ADD_ADDR_9_LO		0x00C8
142*4882a593Smuzhiyun /* MAAH9 */
143*4882a593Smuzhiyun #define KS_ADD_ADDR_9_HI		0x00CC
144*4882a593Smuzhiyun /* MAAL10 */
145*4882a593Smuzhiyun #define KS_ADD_ADDR_A_LO		0x00D0
146*4882a593Smuzhiyun /* MAAH10 */
147*4882a593Smuzhiyun #define KS_ADD_ADDR_A_HI		0x00D4
148*4882a593Smuzhiyun /* MAAL11 */
149*4882a593Smuzhiyun #define KS_ADD_ADDR_B_LO		0x00D8
150*4882a593Smuzhiyun /* MAAH11 */
151*4882a593Smuzhiyun #define KS_ADD_ADDR_B_HI		0x00DC
152*4882a593Smuzhiyun /* MAAL12 */
153*4882a593Smuzhiyun #define KS_ADD_ADDR_C_LO		0x00E0
154*4882a593Smuzhiyun /* MAAH12 */
155*4882a593Smuzhiyun #define KS_ADD_ADDR_C_HI		0x00E4
156*4882a593Smuzhiyun /* MAAL13 */
157*4882a593Smuzhiyun #define KS_ADD_ADDR_D_LO		0x00E8
158*4882a593Smuzhiyun /* MAAH13 */
159*4882a593Smuzhiyun #define KS_ADD_ADDR_D_HI		0x00EC
160*4882a593Smuzhiyun /* MAAL14 */
161*4882a593Smuzhiyun #define KS_ADD_ADDR_E_LO		0x00F0
162*4882a593Smuzhiyun /* MAAH14 */
163*4882a593Smuzhiyun #define KS_ADD_ADDR_E_HI		0x00F4
164*4882a593Smuzhiyun /* MAAL15 */
165*4882a593Smuzhiyun #define KS_ADD_ADDR_F_LO		0x00F8
166*4882a593Smuzhiyun /* MAAH15 */
167*4882a593Smuzhiyun #define KS_ADD_ADDR_F_HI		0x00FC
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun #define ADD_ADDR_HI_MASK		0x0000FFFF
170*4882a593Smuzhiyun #define ADD_ADDR_ENABLE			0x80000000
171*4882a593Smuzhiyun #define ADD_ADDR_INCR			8
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun /* Miscellaneous Registers */
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun /* MARL */
176*4882a593Smuzhiyun #define KS884X_ADDR_0_OFFSET		0x0200
177*4882a593Smuzhiyun #define KS884X_ADDR_1_OFFSET		0x0201
178*4882a593Smuzhiyun /* MARM */
179*4882a593Smuzhiyun #define KS884X_ADDR_2_OFFSET		0x0202
180*4882a593Smuzhiyun #define KS884X_ADDR_3_OFFSET		0x0203
181*4882a593Smuzhiyun /* MARH */
182*4882a593Smuzhiyun #define KS884X_ADDR_4_OFFSET		0x0204
183*4882a593Smuzhiyun #define KS884X_ADDR_5_OFFSET		0x0205
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun /* OBCR */
186*4882a593Smuzhiyun #define KS884X_BUS_CTRL_OFFSET		0x0210
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun #define BUS_SPEED_125_MHZ		0x0000
189*4882a593Smuzhiyun #define BUS_SPEED_62_5_MHZ		0x0001
190*4882a593Smuzhiyun #define BUS_SPEED_41_66_MHZ		0x0002
191*4882a593Smuzhiyun #define BUS_SPEED_25_MHZ		0x0003
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun /* EEPCR */
194*4882a593Smuzhiyun #define KS884X_EEPROM_CTRL_OFFSET	0x0212
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun #define EEPROM_CHIP_SELECT		0x0001
197*4882a593Smuzhiyun #define EEPROM_SERIAL_CLOCK		0x0002
198*4882a593Smuzhiyun #define EEPROM_DATA_OUT			0x0004
199*4882a593Smuzhiyun #define EEPROM_DATA_IN			0x0008
200*4882a593Smuzhiyun #define EEPROM_ACCESS_ENABLE		0x0010
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun /* MBIR */
203*4882a593Smuzhiyun #define KS884X_MEM_INFO_OFFSET		0x0214
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun #define RX_MEM_TEST_FAILED		0x0008
206*4882a593Smuzhiyun #define RX_MEM_TEST_FINISHED		0x0010
207*4882a593Smuzhiyun #define TX_MEM_TEST_FAILED		0x0800
208*4882a593Smuzhiyun #define TX_MEM_TEST_FINISHED		0x1000
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun /* GCR */
211*4882a593Smuzhiyun #define KS884X_GLOBAL_CTRL_OFFSET	0x0216
212*4882a593Smuzhiyun #define GLOBAL_SOFTWARE_RESET		0x0001
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun #define KS8841_POWER_MANAGE_OFFSET	0x0218
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun /* WFCR */
217*4882a593Smuzhiyun #define KS8841_WOL_CTRL_OFFSET		0x021A
218*4882a593Smuzhiyun #define KS8841_WOL_MAGIC_ENABLE		0x0080
219*4882a593Smuzhiyun #define KS8841_WOL_FRAME3_ENABLE	0x0008
220*4882a593Smuzhiyun #define KS8841_WOL_FRAME2_ENABLE	0x0004
221*4882a593Smuzhiyun #define KS8841_WOL_FRAME1_ENABLE	0x0002
222*4882a593Smuzhiyun #define KS8841_WOL_FRAME0_ENABLE	0x0001
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun /* WF0 */
225*4882a593Smuzhiyun #define KS8841_WOL_FRAME_CRC_OFFSET	0x0220
226*4882a593Smuzhiyun #define KS8841_WOL_FRAME_BYTE0_OFFSET	0x0224
227*4882a593Smuzhiyun #define KS8841_WOL_FRAME_BYTE2_OFFSET	0x0228
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun /* IACR */
230*4882a593Smuzhiyun #define KS884X_IACR_P			0x04A0
231*4882a593Smuzhiyun #define KS884X_IACR_OFFSET		KS884X_IACR_P
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun /* IADR1 */
234*4882a593Smuzhiyun #define KS884X_IADR1_P			0x04A2
235*4882a593Smuzhiyun #define KS884X_IADR2_P			0x04A4
236*4882a593Smuzhiyun #define KS884X_IADR3_P			0x04A6
237*4882a593Smuzhiyun #define KS884X_IADR4_P			0x04A8
238*4882a593Smuzhiyun #define KS884X_IADR5_P			0x04AA
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun #define KS884X_ACC_CTRL_SEL_OFFSET	KS884X_IACR_P
241*4882a593Smuzhiyun #define KS884X_ACC_CTRL_INDEX_OFFSET	(KS884X_ACC_CTRL_SEL_OFFSET + 1)
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun #define KS884X_ACC_DATA_0_OFFSET	KS884X_IADR4_P
244*4882a593Smuzhiyun #define KS884X_ACC_DATA_1_OFFSET	(KS884X_ACC_DATA_0_OFFSET + 1)
245*4882a593Smuzhiyun #define KS884X_ACC_DATA_2_OFFSET	KS884X_IADR5_P
246*4882a593Smuzhiyun #define KS884X_ACC_DATA_3_OFFSET	(KS884X_ACC_DATA_2_OFFSET + 1)
247*4882a593Smuzhiyun #define KS884X_ACC_DATA_4_OFFSET	KS884X_IADR2_P
248*4882a593Smuzhiyun #define KS884X_ACC_DATA_5_OFFSET	(KS884X_ACC_DATA_4_OFFSET + 1)
249*4882a593Smuzhiyun #define KS884X_ACC_DATA_6_OFFSET	KS884X_IADR3_P
250*4882a593Smuzhiyun #define KS884X_ACC_DATA_7_OFFSET	(KS884X_ACC_DATA_6_OFFSET + 1)
251*4882a593Smuzhiyun #define KS884X_ACC_DATA_8_OFFSET	KS884X_IADR1_P
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun /* P1MBCR */
254*4882a593Smuzhiyun #define KS884X_P1MBCR_P			0x04D0
255*4882a593Smuzhiyun #define KS884X_P1MBSR_P			0x04D2
256*4882a593Smuzhiyun #define KS884X_PHY1ILR_P		0x04D4
257*4882a593Smuzhiyun #define KS884X_PHY1IHR_P		0x04D6
258*4882a593Smuzhiyun #define KS884X_P1ANAR_P			0x04D8
259*4882a593Smuzhiyun #define KS884X_P1ANLPR_P		0x04DA
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun /* P2MBCR */
262*4882a593Smuzhiyun #define KS884X_P2MBCR_P			0x04E0
263*4882a593Smuzhiyun #define KS884X_P2MBSR_P			0x04E2
264*4882a593Smuzhiyun #define KS884X_PHY2ILR_P		0x04E4
265*4882a593Smuzhiyun #define KS884X_PHY2IHR_P		0x04E6
266*4882a593Smuzhiyun #define KS884X_P2ANAR_P			0x04E8
267*4882a593Smuzhiyun #define KS884X_P2ANLPR_P		0x04EA
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun #define KS884X_PHY_1_CTRL_OFFSET	KS884X_P1MBCR_P
270*4882a593Smuzhiyun #define PHY_CTRL_INTERVAL		(KS884X_P2MBCR_P - KS884X_P1MBCR_P)
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun #define KS884X_PHY_CTRL_OFFSET		0x00
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun /* Mode Control Register */
275*4882a593Smuzhiyun #define PHY_REG_CTRL			0
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun #define PHY_RESET			0x8000
278*4882a593Smuzhiyun #define PHY_LOOPBACK			0x4000
279*4882a593Smuzhiyun #define PHY_SPEED_100MBIT		0x2000
280*4882a593Smuzhiyun #define PHY_AUTO_NEG_ENABLE		0x1000
281*4882a593Smuzhiyun #define PHY_POWER_DOWN			0x0800
282*4882a593Smuzhiyun #define PHY_MII_DISABLE			0x0400
283*4882a593Smuzhiyun #define PHY_AUTO_NEG_RESTART		0x0200
284*4882a593Smuzhiyun #define PHY_FULL_DUPLEX			0x0100
285*4882a593Smuzhiyun #define PHY_COLLISION_TEST		0x0080
286*4882a593Smuzhiyun #define PHY_HP_MDIX			0x0020
287*4882a593Smuzhiyun #define PHY_FORCE_MDIX			0x0010
288*4882a593Smuzhiyun #define PHY_AUTO_MDIX_DISABLE		0x0008
289*4882a593Smuzhiyun #define PHY_REMOTE_FAULT_DISABLE	0x0004
290*4882a593Smuzhiyun #define PHY_TRANSMIT_DISABLE		0x0002
291*4882a593Smuzhiyun #define PHY_LED_DISABLE			0x0001
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun #define KS884X_PHY_STATUS_OFFSET	0x02
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun /* Mode Status Register */
296*4882a593Smuzhiyun #define PHY_REG_STATUS			1
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun #define PHY_100BT4_CAPABLE		0x8000
299*4882a593Smuzhiyun #define PHY_100BTX_FD_CAPABLE		0x4000
300*4882a593Smuzhiyun #define PHY_100BTX_CAPABLE		0x2000
301*4882a593Smuzhiyun #define PHY_10BT_FD_CAPABLE		0x1000
302*4882a593Smuzhiyun #define PHY_10BT_CAPABLE		0x0800
303*4882a593Smuzhiyun #define PHY_MII_SUPPRESS_CAPABLE	0x0040
304*4882a593Smuzhiyun #define PHY_AUTO_NEG_ACKNOWLEDGE	0x0020
305*4882a593Smuzhiyun #define PHY_REMOTE_FAULT		0x0010
306*4882a593Smuzhiyun #define PHY_AUTO_NEG_CAPABLE		0x0008
307*4882a593Smuzhiyun #define PHY_LINK_STATUS			0x0004
308*4882a593Smuzhiyun #define PHY_JABBER_DETECT		0x0002
309*4882a593Smuzhiyun #define PHY_EXTENDED_CAPABILITY		0x0001
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun #define KS884X_PHY_ID_1_OFFSET		0x04
312*4882a593Smuzhiyun #define KS884X_PHY_ID_2_OFFSET		0x06
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun /* PHY Identifier Registers */
315*4882a593Smuzhiyun #define PHY_REG_ID_1			2
316*4882a593Smuzhiyun #define PHY_REG_ID_2			3
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun #define KS884X_PHY_AUTO_NEG_OFFSET	0x08
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun /* Auto-Negotiation Advertisement Register */
321*4882a593Smuzhiyun #define PHY_REG_AUTO_NEGOTIATION	4
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun #define PHY_AUTO_NEG_NEXT_PAGE		0x8000
324*4882a593Smuzhiyun #define PHY_AUTO_NEG_REMOTE_FAULT	0x2000
325*4882a593Smuzhiyun /* Not supported. */
326*4882a593Smuzhiyun #define PHY_AUTO_NEG_ASYM_PAUSE		0x0800
327*4882a593Smuzhiyun #define PHY_AUTO_NEG_SYM_PAUSE		0x0400
328*4882a593Smuzhiyun #define PHY_AUTO_NEG_100BT4		0x0200
329*4882a593Smuzhiyun #define PHY_AUTO_NEG_100BTX_FD		0x0100
330*4882a593Smuzhiyun #define PHY_AUTO_NEG_100BTX		0x0080
331*4882a593Smuzhiyun #define PHY_AUTO_NEG_10BT_FD		0x0040
332*4882a593Smuzhiyun #define PHY_AUTO_NEG_10BT		0x0020
333*4882a593Smuzhiyun #define PHY_AUTO_NEG_SELECTOR		0x001F
334*4882a593Smuzhiyun #define PHY_AUTO_NEG_802_3		0x0001
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun #define PHY_AUTO_NEG_PAUSE  (PHY_AUTO_NEG_SYM_PAUSE | PHY_AUTO_NEG_ASYM_PAUSE)
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun #define KS884X_PHY_REMOTE_CAP_OFFSET	0x0A
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun /* Auto-Negotiation Link Partner Ability Register */
341*4882a593Smuzhiyun #define PHY_REG_REMOTE_CAPABILITY	5
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun #define PHY_REMOTE_NEXT_PAGE		0x8000
344*4882a593Smuzhiyun #define PHY_REMOTE_ACKNOWLEDGE		0x4000
345*4882a593Smuzhiyun #define PHY_REMOTE_REMOTE_FAULT		0x2000
346*4882a593Smuzhiyun #define PHY_REMOTE_SYM_PAUSE		0x0400
347*4882a593Smuzhiyun #define PHY_REMOTE_100BTX_FD		0x0100
348*4882a593Smuzhiyun #define PHY_REMOTE_100BTX		0x0080
349*4882a593Smuzhiyun #define PHY_REMOTE_10BT_FD		0x0040
350*4882a593Smuzhiyun #define PHY_REMOTE_10BT			0x0020
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun /* P1VCT */
353*4882a593Smuzhiyun #define KS884X_P1VCT_P			0x04F0
354*4882a593Smuzhiyun #define KS884X_P1PHYCTRL_P		0x04F2
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun /* P2VCT */
357*4882a593Smuzhiyun #define KS884X_P2VCT_P			0x04F4
358*4882a593Smuzhiyun #define KS884X_P2PHYCTRL_P		0x04F6
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun #define KS884X_PHY_SPECIAL_OFFSET	KS884X_P1VCT_P
361*4882a593Smuzhiyun #define PHY_SPECIAL_INTERVAL		(KS884X_P2VCT_P - KS884X_P1VCT_P)
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun #define KS884X_PHY_LINK_MD_OFFSET	0x00
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun #define PHY_START_CABLE_DIAG		0x8000
366*4882a593Smuzhiyun #define PHY_CABLE_DIAG_RESULT		0x6000
367*4882a593Smuzhiyun #define PHY_CABLE_STAT_NORMAL		0x0000
368*4882a593Smuzhiyun #define PHY_CABLE_STAT_OPEN		0x2000
369*4882a593Smuzhiyun #define PHY_CABLE_STAT_SHORT		0x4000
370*4882a593Smuzhiyun #define PHY_CABLE_STAT_FAILED		0x6000
371*4882a593Smuzhiyun #define PHY_CABLE_10M_SHORT		0x1000
372*4882a593Smuzhiyun #define PHY_CABLE_FAULT_COUNTER		0x01FF
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun #define KS884X_PHY_PHY_CTRL_OFFSET	0x02
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun #define PHY_STAT_REVERSED_POLARITY	0x0020
377*4882a593Smuzhiyun #define PHY_STAT_MDIX			0x0010
378*4882a593Smuzhiyun #define PHY_FORCE_LINK			0x0008
379*4882a593Smuzhiyun #define PHY_POWER_SAVING_DISABLE	0x0004
380*4882a593Smuzhiyun #define PHY_REMOTE_LOOPBACK		0x0002
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun /* SIDER */
383*4882a593Smuzhiyun #define KS884X_SIDER_P			0x0400
384*4882a593Smuzhiyun #define KS884X_CHIP_ID_OFFSET		KS884X_SIDER_P
385*4882a593Smuzhiyun #define KS884X_FAMILY_ID_OFFSET		(KS884X_CHIP_ID_OFFSET + 1)
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun #define REG_FAMILY_ID			0x88
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun #define REG_CHIP_ID_41			0x8810
390*4882a593Smuzhiyun #define REG_CHIP_ID_42			0x8800
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun #define KS884X_CHIP_ID_MASK_41		0xFF10
393*4882a593Smuzhiyun #define KS884X_CHIP_ID_MASK		0xFFF0
394*4882a593Smuzhiyun #define KS884X_CHIP_ID_SHIFT		4
395*4882a593Smuzhiyun #define KS884X_REVISION_MASK		0x000E
396*4882a593Smuzhiyun #define KS884X_REVISION_SHIFT		1
397*4882a593Smuzhiyun #define KS8842_START			0x0001
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun #define CHIP_IP_41_M			0x8810
400*4882a593Smuzhiyun #define CHIP_IP_42_M			0x8800
401*4882a593Smuzhiyun #define CHIP_IP_61_M			0x8890
402*4882a593Smuzhiyun #define CHIP_IP_62_M			0x8880
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun #define CHIP_IP_41_P			0x8850
405*4882a593Smuzhiyun #define CHIP_IP_42_P			0x8840
406*4882a593Smuzhiyun #define CHIP_IP_61_P			0x88D0
407*4882a593Smuzhiyun #define CHIP_IP_62_P			0x88C0
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun /* SGCR1 */
410*4882a593Smuzhiyun #define KS8842_SGCR1_P			0x0402
411*4882a593Smuzhiyun #define KS8842_SWITCH_CTRL_1_OFFSET	KS8842_SGCR1_P
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun #define SWITCH_PASS_ALL			0x8000
414*4882a593Smuzhiyun #define SWITCH_TX_FLOW_CTRL		0x2000
415*4882a593Smuzhiyun #define SWITCH_RX_FLOW_CTRL		0x1000
416*4882a593Smuzhiyun #define SWITCH_CHECK_LENGTH		0x0800
417*4882a593Smuzhiyun #define SWITCH_AGING_ENABLE		0x0400
418*4882a593Smuzhiyun #define SWITCH_FAST_AGING		0x0200
419*4882a593Smuzhiyun #define SWITCH_AGGR_BACKOFF		0x0100
420*4882a593Smuzhiyun #define SWITCH_PASS_PAUSE		0x0008
421*4882a593Smuzhiyun #define SWITCH_LINK_AUTO_AGING		0x0001
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun /* SGCR2 */
424*4882a593Smuzhiyun #define KS8842_SGCR2_P			0x0404
425*4882a593Smuzhiyun #define KS8842_SWITCH_CTRL_2_OFFSET	KS8842_SGCR2_P
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun #define SWITCH_VLAN_ENABLE		0x8000
428*4882a593Smuzhiyun #define SWITCH_IGMP_SNOOP		0x4000
429*4882a593Smuzhiyun #define IPV6_MLD_SNOOP_ENABLE		0x2000
430*4882a593Smuzhiyun #define IPV6_MLD_SNOOP_OPTION		0x1000
431*4882a593Smuzhiyun #define PRIORITY_SCHEME_SELECT		0x0800
432*4882a593Smuzhiyun #define SWITCH_MIRROR_RX_TX		0x0100
433*4882a593Smuzhiyun #define UNICAST_VLAN_BOUNDARY		0x0080
434*4882a593Smuzhiyun #define MULTICAST_STORM_DISABLE		0x0040
435*4882a593Smuzhiyun #define SWITCH_BACK_PRESSURE		0x0020
436*4882a593Smuzhiyun #define FAIR_FLOW_CTRL			0x0010
437*4882a593Smuzhiyun #define NO_EXC_COLLISION_DROP		0x0008
438*4882a593Smuzhiyun #define SWITCH_HUGE_PACKET		0x0004
439*4882a593Smuzhiyun #define SWITCH_LEGAL_PACKET		0x0002
440*4882a593Smuzhiyun #define SWITCH_BUF_RESERVE		0x0001
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun /* SGCR3 */
443*4882a593Smuzhiyun #define KS8842_SGCR3_P			0x0406
444*4882a593Smuzhiyun #define KS8842_SWITCH_CTRL_3_OFFSET	KS8842_SGCR3_P
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun #define BROADCAST_STORM_RATE_LO		0xFF00
447*4882a593Smuzhiyun #define SWITCH_REPEATER			0x0080
448*4882a593Smuzhiyun #define SWITCH_HALF_DUPLEX		0x0040
449*4882a593Smuzhiyun #define SWITCH_FLOW_CTRL		0x0020
450*4882a593Smuzhiyun #define SWITCH_10_MBIT			0x0010
451*4882a593Smuzhiyun #define SWITCH_REPLACE_NULL_VID		0x0008
452*4882a593Smuzhiyun #define BROADCAST_STORM_RATE_HI		0x0007
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun #define BROADCAST_STORM_RATE		0x07FF
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun /* SGCR4 */
457*4882a593Smuzhiyun #define KS8842_SGCR4_P			0x0408
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun /* SGCR5 */
460*4882a593Smuzhiyun #define KS8842_SGCR5_P			0x040A
461*4882a593Smuzhiyun #define KS8842_SWITCH_CTRL_5_OFFSET	KS8842_SGCR5_P
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun #define LED_MODE			0x8200
464*4882a593Smuzhiyun #define LED_SPEED_DUPLEX_ACT		0x0000
465*4882a593Smuzhiyun #define LED_SPEED_DUPLEX_LINK_ACT	0x8000
466*4882a593Smuzhiyun #define LED_DUPLEX_10_100		0x0200
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun /* SGCR6 */
469*4882a593Smuzhiyun #define KS8842_SGCR6_P			0x0410
470*4882a593Smuzhiyun #define KS8842_SWITCH_CTRL_6_OFFSET	KS8842_SGCR6_P
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun #define KS8842_PRIORITY_MASK		3
473*4882a593Smuzhiyun #define KS8842_PRIORITY_SHIFT		2
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun /* SGCR7 */
476*4882a593Smuzhiyun #define KS8842_SGCR7_P			0x0412
477*4882a593Smuzhiyun #define KS8842_SWITCH_CTRL_7_OFFSET	KS8842_SGCR7_P
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun #define SWITCH_UNK_DEF_PORT_ENABLE	0x0008
480*4882a593Smuzhiyun #define SWITCH_UNK_DEF_PORT_3		0x0004
481*4882a593Smuzhiyun #define SWITCH_UNK_DEF_PORT_2		0x0002
482*4882a593Smuzhiyun #define SWITCH_UNK_DEF_PORT_1		0x0001
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun /* MACAR1 */
485*4882a593Smuzhiyun #define KS8842_MACAR1_P			0x0470
486*4882a593Smuzhiyun #define KS8842_MACAR2_P			0x0472
487*4882a593Smuzhiyun #define KS8842_MACAR3_P			0x0474
488*4882a593Smuzhiyun #define KS8842_MAC_ADDR_1_OFFSET	KS8842_MACAR1_P
489*4882a593Smuzhiyun #define KS8842_MAC_ADDR_0_OFFSET	(KS8842_MAC_ADDR_1_OFFSET + 1)
490*4882a593Smuzhiyun #define KS8842_MAC_ADDR_3_OFFSET	KS8842_MACAR2_P
491*4882a593Smuzhiyun #define KS8842_MAC_ADDR_2_OFFSET	(KS8842_MAC_ADDR_3_OFFSET + 1)
492*4882a593Smuzhiyun #define KS8842_MAC_ADDR_5_OFFSET	KS8842_MACAR3_P
493*4882a593Smuzhiyun #define KS8842_MAC_ADDR_4_OFFSET	(KS8842_MAC_ADDR_5_OFFSET + 1)
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun /* TOSR1 */
496*4882a593Smuzhiyun #define KS8842_TOSR1_P			0x0480
497*4882a593Smuzhiyun #define KS8842_TOSR2_P			0x0482
498*4882a593Smuzhiyun #define KS8842_TOSR3_P			0x0484
499*4882a593Smuzhiyun #define KS8842_TOSR4_P			0x0486
500*4882a593Smuzhiyun #define KS8842_TOSR5_P			0x0488
501*4882a593Smuzhiyun #define KS8842_TOSR6_P			0x048A
502*4882a593Smuzhiyun #define KS8842_TOSR7_P			0x0490
503*4882a593Smuzhiyun #define KS8842_TOSR8_P			0x0492
504*4882a593Smuzhiyun #define KS8842_TOS_1_OFFSET		KS8842_TOSR1_P
505*4882a593Smuzhiyun #define KS8842_TOS_2_OFFSET		KS8842_TOSR2_P
506*4882a593Smuzhiyun #define KS8842_TOS_3_OFFSET		KS8842_TOSR3_P
507*4882a593Smuzhiyun #define KS8842_TOS_4_OFFSET		KS8842_TOSR4_P
508*4882a593Smuzhiyun #define KS8842_TOS_5_OFFSET		KS8842_TOSR5_P
509*4882a593Smuzhiyun #define KS8842_TOS_6_OFFSET		KS8842_TOSR6_P
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun #define KS8842_TOS_7_OFFSET		KS8842_TOSR7_P
512*4882a593Smuzhiyun #define KS8842_TOS_8_OFFSET		KS8842_TOSR8_P
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun /* P1CR1 */
515*4882a593Smuzhiyun #define KS8842_P1CR1_P			0x0500
516*4882a593Smuzhiyun #define KS8842_P1CR2_P			0x0502
517*4882a593Smuzhiyun #define KS8842_P1VIDR_P			0x0504
518*4882a593Smuzhiyun #define KS8842_P1CR3_P			0x0506
519*4882a593Smuzhiyun #define KS8842_P1IRCR_P			0x0508
520*4882a593Smuzhiyun #define KS8842_P1ERCR_P			0x050A
521*4882a593Smuzhiyun #define KS884X_P1SCSLMD_P		0x0510
522*4882a593Smuzhiyun #define KS884X_P1CR4_P			0x0512
523*4882a593Smuzhiyun #define KS884X_P1SR_P			0x0514
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun /* P2CR1 */
526*4882a593Smuzhiyun #define KS8842_P2CR1_P			0x0520
527*4882a593Smuzhiyun #define KS8842_P2CR2_P			0x0522
528*4882a593Smuzhiyun #define KS8842_P2VIDR_P			0x0524
529*4882a593Smuzhiyun #define KS8842_P2CR3_P			0x0526
530*4882a593Smuzhiyun #define KS8842_P2IRCR_P			0x0528
531*4882a593Smuzhiyun #define KS8842_P2ERCR_P			0x052A
532*4882a593Smuzhiyun #define KS884X_P2SCSLMD_P		0x0530
533*4882a593Smuzhiyun #define KS884X_P2CR4_P			0x0532
534*4882a593Smuzhiyun #define KS884X_P2SR_P			0x0534
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun /* P3CR1 */
537*4882a593Smuzhiyun #define KS8842_P3CR1_P			0x0540
538*4882a593Smuzhiyun #define KS8842_P3CR2_P			0x0542
539*4882a593Smuzhiyun #define KS8842_P3VIDR_P			0x0544
540*4882a593Smuzhiyun #define KS8842_P3CR3_P			0x0546
541*4882a593Smuzhiyun #define KS8842_P3IRCR_P			0x0548
542*4882a593Smuzhiyun #define KS8842_P3ERCR_P			0x054A
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun #define KS8842_PORT_1_CTRL_1		KS8842_P1CR1_P
545*4882a593Smuzhiyun #define KS8842_PORT_2_CTRL_1		KS8842_P2CR1_P
546*4882a593Smuzhiyun #define KS8842_PORT_3_CTRL_1		KS8842_P3CR1_P
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun #define PORT_CTRL_ADDR(port, addr)		\
549*4882a593Smuzhiyun 	(addr = KS8842_PORT_1_CTRL_1 + (port) *	\
550*4882a593Smuzhiyun 		(KS8842_PORT_2_CTRL_1 - KS8842_PORT_1_CTRL_1))
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun #define KS8842_PORT_CTRL_1_OFFSET	0x00
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun #define PORT_BROADCAST_STORM		0x0080
555*4882a593Smuzhiyun #define PORT_DIFFSERV_ENABLE		0x0040
556*4882a593Smuzhiyun #define PORT_802_1P_ENABLE		0x0020
557*4882a593Smuzhiyun #define PORT_BASED_PRIORITY_MASK	0x0018
558*4882a593Smuzhiyun #define PORT_BASED_PRIORITY_BASE	0x0003
559*4882a593Smuzhiyun #define PORT_BASED_PRIORITY_SHIFT	3
560*4882a593Smuzhiyun #define PORT_BASED_PRIORITY_0		0x0000
561*4882a593Smuzhiyun #define PORT_BASED_PRIORITY_1		0x0008
562*4882a593Smuzhiyun #define PORT_BASED_PRIORITY_2		0x0010
563*4882a593Smuzhiyun #define PORT_BASED_PRIORITY_3		0x0018
564*4882a593Smuzhiyun #define PORT_INSERT_TAG			0x0004
565*4882a593Smuzhiyun #define PORT_REMOVE_TAG			0x0002
566*4882a593Smuzhiyun #define PORT_PRIO_QUEUE_ENABLE		0x0001
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun #define KS8842_PORT_CTRL_2_OFFSET	0x02
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun #define PORT_INGRESS_VLAN_FILTER	0x4000
571*4882a593Smuzhiyun #define PORT_DISCARD_NON_VID		0x2000
572*4882a593Smuzhiyun #define PORT_FORCE_FLOW_CTRL		0x1000
573*4882a593Smuzhiyun #define PORT_BACK_PRESSURE		0x0800
574*4882a593Smuzhiyun #define PORT_TX_ENABLE			0x0400
575*4882a593Smuzhiyun #define PORT_RX_ENABLE			0x0200
576*4882a593Smuzhiyun #define PORT_LEARN_DISABLE		0x0100
577*4882a593Smuzhiyun #define PORT_MIRROR_SNIFFER		0x0080
578*4882a593Smuzhiyun #define PORT_MIRROR_RX			0x0040
579*4882a593Smuzhiyun #define PORT_MIRROR_TX			0x0020
580*4882a593Smuzhiyun #define PORT_USER_PRIORITY_CEILING	0x0008
581*4882a593Smuzhiyun #define PORT_VLAN_MEMBERSHIP		0x0007
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun #define KS8842_PORT_CTRL_VID_OFFSET	0x04
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun #define PORT_DEFAULT_VID		0x0001
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun #define KS8842_PORT_CTRL_3_OFFSET	0x06
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun #define PORT_INGRESS_LIMIT_MODE		0x000C
590*4882a593Smuzhiyun #define PORT_INGRESS_ALL		0x0000
591*4882a593Smuzhiyun #define PORT_INGRESS_UNICAST		0x0004
592*4882a593Smuzhiyun #define PORT_INGRESS_MULTICAST		0x0008
593*4882a593Smuzhiyun #define PORT_INGRESS_BROADCAST		0x000C
594*4882a593Smuzhiyun #define PORT_COUNT_IFG			0x0002
595*4882a593Smuzhiyun #define PORT_COUNT_PREAMBLE		0x0001
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun #define KS8842_PORT_IN_RATE_OFFSET	0x08
598*4882a593Smuzhiyun #define KS8842_PORT_OUT_RATE_OFFSET	0x0A
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun #define PORT_PRIORITY_RATE		0x0F
601*4882a593Smuzhiyun #define PORT_PRIORITY_RATE_SHIFT	4
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun #define KS884X_PORT_LINK_MD		0x10
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun #define PORT_CABLE_10M_SHORT		0x8000
606*4882a593Smuzhiyun #define PORT_CABLE_DIAG_RESULT		0x6000
607*4882a593Smuzhiyun #define PORT_CABLE_STAT_NORMAL		0x0000
608*4882a593Smuzhiyun #define PORT_CABLE_STAT_OPEN		0x2000
609*4882a593Smuzhiyun #define PORT_CABLE_STAT_SHORT		0x4000
610*4882a593Smuzhiyun #define PORT_CABLE_STAT_FAILED		0x6000
611*4882a593Smuzhiyun #define PORT_START_CABLE_DIAG		0x1000
612*4882a593Smuzhiyun #define PORT_FORCE_LINK			0x0800
613*4882a593Smuzhiyun #define PORT_POWER_SAVING_DISABLE	0x0400
614*4882a593Smuzhiyun #define PORT_PHY_REMOTE_LOOPBACK	0x0200
615*4882a593Smuzhiyun #define PORT_CABLE_FAULT_COUNTER	0x01FF
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun #define KS884X_PORT_CTRL_4_OFFSET	0x12
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun #define PORT_LED_OFF			0x8000
620*4882a593Smuzhiyun #define PORT_TX_DISABLE			0x4000
621*4882a593Smuzhiyun #define PORT_AUTO_NEG_RESTART		0x2000
622*4882a593Smuzhiyun #define PORT_REMOTE_FAULT_DISABLE	0x1000
623*4882a593Smuzhiyun #define PORT_POWER_DOWN			0x0800
624*4882a593Smuzhiyun #define PORT_AUTO_MDIX_DISABLE		0x0400
625*4882a593Smuzhiyun #define PORT_FORCE_MDIX			0x0200
626*4882a593Smuzhiyun #define PORT_LOOPBACK			0x0100
627*4882a593Smuzhiyun #define PORT_AUTO_NEG_ENABLE		0x0080
628*4882a593Smuzhiyun #define PORT_FORCE_100_MBIT		0x0040
629*4882a593Smuzhiyun #define PORT_FORCE_FULL_DUPLEX		0x0020
630*4882a593Smuzhiyun #define PORT_AUTO_NEG_SYM_PAUSE		0x0010
631*4882a593Smuzhiyun #define PORT_AUTO_NEG_100BTX_FD		0x0008
632*4882a593Smuzhiyun #define PORT_AUTO_NEG_100BTX		0x0004
633*4882a593Smuzhiyun #define PORT_AUTO_NEG_10BT_FD		0x0002
634*4882a593Smuzhiyun #define PORT_AUTO_NEG_10BT		0x0001
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun #define KS884X_PORT_STATUS_OFFSET	0x14
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun #define PORT_HP_MDIX			0x8000
639*4882a593Smuzhiyun #define PORT_REVERSED_POLARITY		0x2000
640*4882a593Smuzhiyun #define PORT_RX_FLOW_CTRL		0x0800
641*4882a593Smuzhiyun #define PORT_TX_FLOW_CTRL		0x1000
642*4882a593Smuzhiyun #define PORT_STATUS_SPEED_100MBIT	0x0400
643*4882a593Smuzhiyun #define PORT_STATUS_FULL_DUPLEX		0x0200
644*4882a593Smuzhiyun #define PORT_REMOTE_FAULT		0x0100
645*4882a593Smuzhiyun #define PORT_MDIX_STATUS		0x0080
646*4882a593Smuzhiyun #define PORT_AUTO_NEG_COMPLETE		0x0040
647*4882a593Smuzhiyun #define PORT_STATUS_LINK_GOOD		0x0020
648*4882a593Smuzhiyun #define PORT_REMOTE_SYM_PAUSE		0x0010
649*4882a593Smuzhiyun #define PORT_REMOTE_100BTX_FD		0x0008
650*4882a593Smuzhiyun #define PORT_REMOTE_100BTX		0x0004
651*4882a593Smuzhiyun #define PORT_REMOTE_10BT_FD		0x0002
652*4882a593Smuzhiyun #define PORT_REMOTE_10BT		0x0001
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun /*
655*4882a593Smuzhiyun #define STATIC_MAC_TABLE_ADDR		00-0000FFFF-FFFFFFFF
656*4882a593Smuzhiyun #define STATIC_MAC_TABLE_FWD_PORTS	00-00070000-00000000
657*4882a593Smuzhiyun #define STATIC_MAC_TABLE_VALID		00-00080000-00000000
658*4882a593Smuzhiyun #define STATIC_MAC_TABLE_OVERRIDE	00-00100000-00000000
659*4882a593Smuzhiyun #define STATIC_MAC_TABLE_USE_FID	00-00200000-00000000
660*4882a593Smuzhiyun #define STATIC_MAC_TABLE_FID		00-03C00000-00000000
661*4882a593Smuzhiyun */
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun #define STATIC_MAC_TABLE_ADDR		0x0000FFFF
664*4882a593Smuzhiyun #define STATIC_MAC_TABLE_FWD_PORTS	0x00070000
665*4882a593Smuzhiyun #define STATIC_MAC_TABLE_VALID		0x00080000
666*4882a593Smuzhiyun #define STATIC_MAC_TABLE_OVERRIDE	0x00100000
667*4882a593Smuzhiyun #define STATIC_MAC_TABLE_USE_FID	0x00200000
668*4882a593Smuzhiyun #define STATIC_MAC_TABLE_FID		0x03C00000
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun #define STATIC_MAC_FWD_PORTS_SHIFT	16
671*4882a593Smuzhiyun #define STATIC_MAC_FID_SHIFT		22
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun /*
674*4882a593Smuzhiyun #define VLAN_TABLE_VID			00-00000000-00000FFF
675*4882a593Smuzhiyun #define VLAN_TABLE_FID			00-00000000-0000F000
676*4882a593Smuzhiyun #define VLAN_TABLE_MEMBERSHIP		00-00000000-00070000
677*4882a593Smuzhiyun #define VLAN_TABLE_VALID		00-00000000-00080000
678*4882a593Smuzhiyun */
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun #define VLAN_TABLE_VID			0x00000FFF
681*4882a593Smuzhiyun #define VLAN_TABLE_FID			0x0000F000
682*4882a593Smuzhiyun #define VLAN_TABLE_MEMBERSHIP		0x00070000
683*4882a593Smuzhiyun #define VLAN_TABLE_VALID		0x00080000
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun #define VLAN_TABLE_FID_SHIFT		12
686*4882a593Smuzhiyun #define VLAN_TABLE_MEMBERSHIP_SHIFT	16
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun /*
689*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_ADDR		00-0000FFFF-FFFFFFFF
690*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_FID		00-000F0000-00000000
691*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_SRC_PORT	00-00300000-00000000
692*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_TIMESTAMP	00-00C00000-00000000
693*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_ENTRIES	03-FF000000-00000000
694*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_MAC_EMPTY	04-00000000-00000000
695*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_RESERVED	78-00000000-00000000
696*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_NOT_READY	80-00000000-00000000
697*4882a593Smuzhiyun */
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_ADDR		0x0000FFFF
700*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_FID		0x000F0000
701*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_SRC_PORT	0x00300000
702*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_TIMESTAMP	0x00C00000
703*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_ENTRIES	0xFF000000
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_ENTRIES_H	0x03
706*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_MAC_EMPTY	0x04
707*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_RESERVED	0x78
708*4882a593Smuzhiyun #define DYNAMIC_MAC_TABLE_NOT_READY	0x80
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun #define DYNAMIC_MAC_FID_SHIFT		16
711*4882a593Smuzhiyun #define DYNAMIC_MAC_SRC_PORT_SHIFT	20
712*4882a593Smuzhiyun #define DYNAMIC_MAC_TIMESTAMP_SHIFT	22
713*4882a593Smuzhiyun #define DYNAMIC_MAC_ENTRIES_SHIFT	24
714*4882a593Smuzhiyun #define DYNAMIC_MAC_ENTRIES_H_SHIFT	8
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun /*
717*4882a593Smuzhiyun #define MIB_COUNTER_VALUE		00-00000000-3FFFFFFF
718*4882a593Smuzhiyun #define MIB_COUNTER_VALID		00-00000000-40000000
719*4882a593Smuzhiyun #define MIB_COUNTER_OVERFLOW		00-00000000-80000000
720*4882a593Smuzhiyun */
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun #define MIB_COUNTER_VALUE		0x3FFFFFFF
723*4882a593Smuzhiyun #define MIB_COUNTER_VALID		0x40000000
724*4882a593Smuzhiyun #define MIB_COUNTER_OVERFLOW		0x80000000
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun #define MIB_PACKET_DROPPED		0x0000FFFF
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun #define KS_MIB_PACKET_DROPPED_TX_0	0x100
729*4882a593Smuzhiyun #define KS_MIB_PACKET_DROPPED_TX_1	0x101
730*4882a593Smuzhiyun #define KS_MIB_PACKET_DROPPED_TX	0x102
731*4882a593Smuzhiyun #define KS_MIB_PACKET_DROPPED_RX_0	0x103
732*4882a593Smuzhiyun #define KS_MIB_PACKET_DROPPED_RX_1	0x104
733*4882a593Smuzhiyun #define KS_MIB_PACKET_DROPPED_RX	0x105
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun /* Change default LED mode. */
736*4882a593Smuzhiyun #define SET_DEFAULT_LED			LED_SPEED_DUPLEX_ACT
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun #define MAC_ADDR_ORDER(i)		(ETH_ALEN - 1 - (i))
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun #define MAX_ETHERNET_BODY_SIZE		1500
741*4882a593Smuzhiyun #define ETHERNET_HEADER_SIZE		(14 + VLAN_HLEN)
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun #define MAX_ETHERNET_PACKET_SIZE	\
744*4882a593Smuzhiyun 	(MAX_ETHERNET_BODY_SIZE + ETHERNET_HEADER_SIZE)
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun #define REGULAR_RX_BUF_SIZE		(MAX_ETHERNET_PACKET_SIZE + 4)
747*4882a593Smuzhiyun #define MAX_RX_BUF_SIZE			(1912 + 4)
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun #define ADDITIONAL_ENTRIES		16
750*4882a593Smuzhiyun #define MAX_MULTICAST_LIST		32
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun #define HW_MULTICAST_SIZE		8
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun #define HW_TO_DEV_PORT(port)		(port - 1)
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun enum {
757*4882a593Smuzhiyun 	media_connected,
758*4882a593Smuzhiyun 	media_disconnected
759*4882a593Smuzhiyun };
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun enum {
762*4882a593Smuzhiyun 	OID_COUNTER_UNKOWN,
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	OID_COUNTER_FIRST,
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	/* total transmit errors */
767*4882a593Smuzhiyun 	OID_COUNTER_XMIT_ERROR,
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	/* total receive errors */
770*4882a593Smuzhiyun 	OID_COUNTER_RCV_ERROR,
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	OID_COUNTER_LAST
773*4882a593Smuzhiyun };
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun /*
776*4882a593Smuzhiyun  * Hardware descriptor definitions
777*4882a593Smuzhiyun  */
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun #define DESC_ALIGNMENT			16
780*4882a593Smuzhiyun #define BUFFER_ALIGNMENT		8
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun #define NUM_OF_RX_DESC			64
783*4882a593Smuzhiyun #define NUM_OF_TX_DESC			64
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun #define KS_DESC_RX_FRAME_LEN		0x000007FF
786*4882a593Smuzhiyun #define KS_DESC_RX_FRAME_TYPE		0x00008000
787*4882a593Smuzhiyun #define KS_DESC_RX_ERROR_CRC		0x00010000
788*4882a593Smuzhiyun #define KS_DESC_RX_ERROR_RUNT		0x00020000
789*4882a593Smuzhiyun #define KS_DESC_RX_ERROR_TOO_LONG	0x00040000
790*4882a593Smuzhiyun #define KS_DESC_RX_ERROR_PHY		0x00080000
791*4882a593Smuzhiyun #define KS884X_DESC_RX_PORT_MASK	0x00300000
792*4882a593Smuzhiyun #define KS_DESC_RX_MULTICAST		0x01000000
793*4882a593Smuzhiyun #define KS_DESC_RX_ERROR		0x02000000
794*4882a593Smuzhiyun #define KS_DESC_RX_ERROR_CSUM_UDP	0x04000000
795*4882a593Smuzhiyun #define KS_DESC_RX_ERROR_CSUM_TCP	0x08000000
796*4882a593Smuzhiyun #define KS_DESC_RX_ERROR_CSUM_IP	0x10000000
797*4882a593Smuzhiyun #define KS_DESC_RX_LAST			0x20000000
798*4882a593Smuzhiyun #define KS_DESC_RX_FIRST		0x40000000
799*4882a593Smuzhiyun #define KS_DESC_RX_ERROR_COND		\
800*4882a593Smuzhiyun 	(KS_DESC_RX_ERROR_CRC |		\
801*4882a593Smuzhiyun 	KS_DESC_RX_ERROR_RUNT |		\
802*4882a593Smuzhiyun 	KS_DESC_RX_ERROR_PHY |		\
803*4882a593Smuzhiyun 	KS_DESC_RX_ERROR_TOO_LONG)
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun #define KS_DESC_HW_OWNED		0x80000000
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun #define KS_DESC_BUF_SIZE		0x000007FF
808*4882a593Smuzhiyun #define KS884X_DESC_TX_PORT_MASK	0x00300000
809*4882a593Smuzhiyun #define KS_DESC_END_OF_RING		0x02000000
810*4882a593Smuzhiyun #define KS_DESC_TX_CSUM_GEN_UDP		0x04000000
811*4882a593Smuzhiyun #define KS_DESC_TX_CSUM_GEN_TCP		0x08000000
812*4882a593Smuzhiyun #define KS_DESC_TX_CSUM_GEN_IP		0x10000000
813*4882a593Smuzhiyun #define KS_DESC_TX_LAST			0x20000000
814*4882a593Smuzhiyun #define KS_DESC_TX_FIRST		0x40000000
815*4882a593Smuzhiyun #define KS_DESC_TX_INTERRUPT		0x80000000
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun #define KS_DESC_PORT_SHIFT		20
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun #define KS_DESC_RX_MASK			(KS_DESC_BUF_SIZE)
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun #define KS_DESC_TX_MASK			\
822*4882a593Smuzhiyun 	(KS_DESC_TX_INTERRUPT |		\
823*4882a593Smuzhiyun 	KS_DESC_TX_FIRST |		\
824*4882a593Smuzhiyun 	KS_DESC_TX_LAST |		\
825*4882a593Smuzhiyun 	KS_DESC_TX_CSUM_GEN_IP |	\
826*4882a593Smuzhiyun 	KS_DESC_TX_CSUM_GEN_TCP |	\
827*4882a593Smuzhiyun 	KS_DESC_TX_CSUM_GEN_UDP |	\
828*4882a593Smuzhiyun 	KS_DESC_BUF_SIZE)
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun struct ksz_desc_rx_stat {
831*4882a593Smuzhiyun #ifdef __BIG_ENDIAN_BITFIELD
832*4882a593Smuzhiyun 	u32 hw_owned:1;
833*4882a593Smuzhiyun 	u32 first_desc:1;
834*4882a593Smuzhiyun 	u32 last_desc:1;
835*4882a593Smuzhiyun 	u32 csum_err_ip:1;
836*4882a593Smuzhiyun 	u32 csum_err_tcp:1;
837*4882a593Smuzhiyun 	u32 csum_err_udp:1;
838*4882a593Smuzhiyun 	u32 error:1;
839*4882a593Smuzhiyun 	u32 multicast:1;
840*4882a593Smuzhiyun 	u32 src_port:4;
841*4882a593Smuzhiyun 	u32 err_phy:1;
842*4882a593Smuzhiyun 	u32 err_too_long:1;
843*4882a593Smuzhiyun 	u32 err_runt:1;
844*4882a593Smuzhiyun 	u32 err_crc:1;
845*4882a593Smuzhiyun 	u32 frame_type:1;
846*4882a593Smuzhiyun 	u32 reserved1:4;
847*4882a593Smuzhiyun 	u32 frame_len:11;
848*4882a593Smuzhiyun #else
849*4882a593Smuzhiyun 	u32 frame_len:11;
850*4882a593Smuzhiyun 	u32 reserved1:4;
851*4882a593Smuzhiyun 	u32 frame_type:1;
852*4882a593Smuzhiyun 	u32 err_crc:1;
853*4882a593Smuzhiyun 	u32 err_runt:1;
854*4882a593Smuzhiyun 	u32 err_too_long:1;
855*4882a593Smuzhiyun 	u32 err_phy:1;
856*4882a593Smuzhiyun 	u32 src_port:4;
857*4882a593Smuzhiyun 	u32 multicast:1;
858*4882a593Smuzhiyun 	u32 error:1;
859*4882a593Smuzhiyun 	u32 csum_err_udp:1;
860*4882a593Smuzhiyun 	u32 csum_err_tcp:1;
861*4882a593Smuzhiyun 	u32 csum_err_ip:1;
862*4882a593Smuzhiyun 	u32 last_desc:1;
863*4882a593Smuzhiyun 	u32 first_desc:1;
864*4882a593Smuzhiyun 	u32 hw_owned:1;
865*4882a593Smuzhiyun #endif
866*4882a593Smuzhiyun };
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun struct ksz_desc_tx_stat {
869*4882a593Smuzhiyun #ifdef __BIG_ENDIAN_BITFIELD
870*4882a593Smuzhiyun 	u32 hw_owned:1;
871*4882a593Smuzhiyun 	u32 reserved1:31;
872*4882a593Smuzhiyun #else
873*4882a593Smuzhiyun 	u32 reserved1:31;
874*4882a593Smuzhiyun 	u32 hw_owned:1;
875*4882a593Smuzhiyun #endif
876*4882a593Smuzhiyun };
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun struct ksz_desc_rx_buf {
879*4882a593Smuzhiyun #ifdef __BIG_ENDIAN_BITFIELD
880*4882a593Smuzhiyun 	u32 reserved4:6;
881*4882a593Smuzhiyun 	u32 end_of_ring:1;
882*4882a593Smuzhiyun 	u32 reserved3:14;
883*4882a593Smuzhiyun 	u32 buf_size:11;
884*4882a593Smuzhiyun #else
885*4882a593Smuzhiyun 	u32 buf_size:11;
886*4882a593Smuzhiyun 	u32 reserved3:14;
887*4882a593Smuzhiyun 	u32 end_of_ring:1;
888*4882a593Smuzhiyun 	u32 reserved4:6;
889*4882a593Smuzhiyun #endif
890*4882a593Smuzhiyun };
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun struct ksz_desc_tx_buf {
893*4882a593Smuzhiyun #ifdef __BIG_ENDIAN_BITFIELD
894*4882a593Smuzhiyun 	u32 intr:1;
895*4882a593Smuzhiyun 	u32 first_seg:1;
896*4882a593Smuzhiyun 	u32 last_seg:1;
897*4882a593Smuzhiyun 	u32 csum_gen_ip:1;
898*4882a593Smuzhiyun 	u32 csum_gen_tcp:1;
899*4882a593Smuzhiyun 	u32 csum_gen_udp:1;
900*4882a593Smuzhiyun 	u32 end_of_ring:1;
901*4882a593Smuzhiyun 	u32 reserved4:1;
902*4882a593Smuzhiyun 	u32 dest_port:4;
903*4882a593Smuzhiyun 	u32 reserved3:9;
904*4882a593Smuzhiyun 	u32 buf_size:11;
905*4882a593Smuzhiyun #else
906*4882a593Smuzhiyun 	u32 buf_size:11;
907*4882a593Smuzhiyun 	u32 reserved3:9;
908*4882a593Smuzhiyun 	u32 dest_port:4;
909*4882a593Smuzhiyun 	u32 reserved4:1;
910*4882a593Smuzhiyun 	u32 end_of_ring:1;
911*4882a593Smuzhiyun 	u32 csum_gen_udp:1;
912*4882a593Smuzhiyun 	u32 csum_gen_tcp:1;
913*4882a593Smuzhiyun 	u32 csum_gen_ip:1;
914*4882a593Smuzhiyun 	u32 last_seg:1;
915*4882a593Smuzhiyun 	u32 first_seg:1;
916*4882a593Smuzhiyun 	u32 intr:1;
917*4882a593Smuzhiyun #endif
918*4882a593Smuzhiyun };
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun union desc_stat {
921*4882a593Smuzhiyun 	struct ksz_desc_rx_stat rx;
922*4882a593Smuzhiyun 	struct ksz_desc_tx_stat tx;
923*4882a593Smuzhiyun 	u32 data;
924*4882a593Smuzhiyun };
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun union desc_buf {
927*4882a593Smuzhiyun 	struct ksz_desc_rx_buf rx;
928*4882a593Smuzhiyun 	struct ksz_desc_tx_buf tx;
929*4882a593Smuzhiyun 	u32 data;
930*4882a593Smuzhiyun };
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun /**
933*4882a593Smuzhiyun  * struct ksz_hw_desc - Hardware descriptor data structure
934*4882a593Smuzhiyun  * @ctrl:	Descriptor control value.
935*4882a593Smuzhiyun  * @buf:	Descriptor buffer value.
936*4882a593Smuzhiyun  * @addr:	Physical address of memory buffer.
937*4882a593Smuzhiyun  * @next:	Pointer to next hardware descriptor.
938*4882a593Smuzhiyun  */
939*4882a593Smuzhiyun struct ksz_hw_desc {
940*4882a593Smuzhiyun 	union desc_stat ctrl;
941*4882a593Smuzhiyun 	union desc_buf buf;
942*4882a593Smuzhiyun 	u32 addr;
943*4882a593Smuzhiyun 	u32 next;
944*4882a593Smuzhiyun };
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun /**
947*4882a593Smuzhiyun  * struct ksz_sw_desc - Software descriptor data structure
948*4882a593Smuzhiyun  * @ctrl:	Descriptor control value.
949*4882a593Smuzhiyun  * @buf:	Descriptor buffer value.
950*4882a593Smuzhiyun  * @buf_size:	Current buffers size value in hardware descriptor.
951*4882a593Smuzhiyun  */
952*4882a593Smuzhiyun struct ksz_sw_desc {
953*4882a593Smuzhiyun 	union desc_stat ctrl;
954*4882a593Smuzhiyun 	union desc_buf buf;
955*4882a593Smuzhiyun 	u32 buf_size;
956*4882a593Smuzhiyun };
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun /**
959*4882a593Smuzhiyun  * struct ksz_dma_buf - OS dependent DMA buffer data structure
960*4882a593Smuzhiyun  * @skb:	Associated socket buffer.
961*4882a593Smuzhiyun  * @dma:	Associated physical DMA address.
962*4882a593Smuzhiyun  * @len:	Actual len used.
963*4882a593Smuzhiyun  */
964*4882a593Smuzhiyun struct ksz_dma_buf {
965*4882a593Smuzhiyun 	struct sk_buff *skb;
966*4882a593Smuzhiyun 	dma_addr_t dma;
967*4882a593Smuzhiyun 	int len;
968*4882a593Smuzhiyun };
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun /**
971*4882a593Smuzhiyun  * struct ksz_desc - Descriptor structure
972*4882a593Smuzhiyun  * @phw:	Hardware descriptor pointer to uncached physical memory.
973*4882a593Smuzhiyun  * @sw:		Cached memory to hold hardware descriptor values for
974*4882a593Smuzhiyun  * 		manipulation.
975*4882a593Smuzhiyun  * @dma_buf:	Operating system dependent data structure to hold physical
976*4882a593Smuzhiyun  * 		memory buffer allocation information.
977*4882a593Smuzhiyun  */
978*4882a593Smuzhiyun struct ksz_desc {
979*4882a593Smuzhiyun 	struct ksz_hw_desc *phw;
980*4882a593Smuzhiyun 	struct ksz_sw_desc sw;
981*4882a593Smuzhiyun 	struct ksz_dma_buf dma_buf;
982*4882a593Smuzhiyun };
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun #define DMA_BUFFER(desc)  ((struct ksz_dma_buf *)(&(desc)->dma_buf))
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun /**
987*4882a593Smuzhiyun  * struct ksz_desc_info - Descriptor information data structure
988*4882a593Smuzhiyun  * @ring:	First descriptor in the ring.
989*4882a593Smuzhiyun  * @cur:	Current descriptor being manipulated.
990*4882a593Smuzhiyun  * @ring_virt:	First hardware descriptor in the ring.
991*4882a593Smuzhiyun  * @ring_phys:	The physical address of the first descriptor of the ring.
992*4882a593Smuzhiyun  * @size:	Size of hardware descriptor.
993*4882a593Smuzhiyun  * @alloc:	Number of descriptors allocated.
994*4882a593Smuzhiyun  * @avail:	Number of descriptors available for use.
995*4882a593Smuzhiyun  * @last:	Index for last descriptor released to hardware.
996*4882a593Smuzhiyun  * @next:	Index for next descriptor available for use.
997*4882a593Smuzhiyun  * @mask:	Mask for index wrapping.
998*4882a593Smuzhiyun  */
999*4882a593Smuzhiyun struct ksz_desc_info {
1000*4882a593Smuzhiyun 	struct ksz_desc *ring;
1001*4882a593Smuzhiyun 	struct ksz_desc *cur;
1002*4882a593Smuzhiyun 	struct ksz_hw_desc *ring_virt;
1003*4882a593Smuzhiyun 	u32 ring_phys;
1004*4882a593Smuzhiyun 	int size;
1005*4882a593Smuzhiyun 	int alloc;
1006*4882a593Smuzhiyun 	int avail;
1007*4882a593Smuzhiyun 	int last;
1008*4882a593Smuzhiyun 	int next;
1009*4882a593Smuzhiyun 	int mask;
1010*4882a593Smuzhiyun };
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun /*
1013*4882a593Smuzhiyun  * KSZ8842 switch definitions
1014*4882a593Smuzhiyun  */
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun enum {
1017*4882a593Smuzhiyun 	TABLE_STATIC_MAC = 0,
1018*4882a593Smuzhiyun 	TABLE_VLAN,
1019*4882a593Smuzhiyun 	TABLE_DYNAMIC_MAC,
1020*4882a593Smuzhiyun 	TABLE_MIB
1021*4882a593Smuzhiyun };
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun #define LEARNED_MAC_TABLE_ENTRIES	1024
1024*4882a593Smuzhiyun #define STATIC_MAC_TABLE_ENTRIES	8
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun /**
1027*4882a593Smuzhiyun  * struct ksz_mac_table - Static MAC table data structure
1028*4882a593Smuzhiyun  * @mac_addr:	MAC address to filter.
1029*4882a593Smuzhiyun  * @vid:	VID value.
1030*4882a593Smuzhiyun  * @fid:	FID value.
1031*4882a593Smuzhiyun  * @ports:	Port membership.
1032*4882a593Smuzhiyun  * @override:	Override setting.
1033*4882a593Smuzhiyun  * @use_fid:	FID use setting.
1034*4882a593Smuzhiyun  * @valid:	Valid setting indicating the entry is being used.
1035*4882a593Smuzhiyun  */
1036*4882a593Smuzhiyun struct ksz_mac_table {
1037*4882a593Smuzhiyun 	u8 mac_addr[ETH_ALEN];
1038*4882a593Smuzhiyun 	u16 vid;
1039*4882a593Smuzhiyun 	u8 fid;
1040*4882a593Smuzhiyun 	u8 ports;
1041*4882a593Smuzhiyun 	u8 override:1;
1042*4882a593Smuzhiyun 	u8 use_fid:1;
1043*4882a593Smuzhiyun 	u8 valid:1;
1044*4882a593Smuzhiyun };
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun #define VLAN_TABLE_ENTRIES		16
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun /**
1049*4882a593Smuzhiyun  * struct ksz_vlan_table - VLAN table data structure
1050*4882a593Smuzhiyun  * @vid:	VID value.
1051*4882a593Smuzhiyun  * @fid:	FID value.
1052*4882a593Smuzhiyun  * @member:	Port membership.
1053*4882a593Smuzhiyun  */
1054*4882a593Smuzhiyun struct ksz_vlan_table {
1055*4882a593Smuzhiyun 	u16 vid;
1056*4882a593Smuzhiyun 	u8 fid;
1057*4882a593Smuzhiyun 	u8 member;
1058*4882a593Smuzhiyun };
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun #define DIFFSERV_ENTRIES		64
1061*4882a593Smuzhiyun #define PRIO_802_1P_ENTRIES		8
1062*4882a593Smuzhiyun #define PRIO_QUEUES			4
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun #define SWITCH_PORT_NUM			2
1065*4882a593Smuzhiyun #define TOTAL_PORT_NUM			(SWITCH_PORT_NUM + 1)
1066*4882a593Smuzhiyun #define HOST_MASK			(1 << SWITCH_PORT_NUM)
1067*4882a593Smuzhiyun #define PORT_MASK			7
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun #define MAIN_PORT			0
1070*4882a593Smuzhiyun #define OTHER_PORT			1
1071*4882a593Smuzhiyun #define HOST_PORT			SWITCH_PORT_NUM
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun #define PORT_COUNTER_NUM		0x20
1074*4882a593Smuzhiyun #define TOTAL_PORT_COUNTER_NUM		(PORT_COUNTER_NUM + 2)
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun #define MIB_COUNTER_RX_LO_PRIORITY	0x00
1077*4882a593Smuzhiyun #define MIB_COUNTER_RX_HI_PRIORITY	0x01
1078*4882a593Smuzhiyun #define MIB_COUNTER_RX_UNDERSIZE	0x02
1079*4882a593Smuzhiyun #define MIB_COUNTER_RX_FRAGMENT		0x03
1080*4882a593Smuzhiyun #define MIB_COUNTER_RX_OVERSIZE		0x04
1081*4882a593Smuzhiyun #define MIB_COUNTER_RX_JABBER		0x05
1082*4882a593Smuzhiyun #define MIB_COUNTER_RX_SYMBOL_ERR	0x06
1083*4882a593Smuzhiyun #define MIB_COUNTER_RX_CRC_ERR		0x07
1084*4882a593Smuzhiyun #define MIB_COUNTER_RX_ALIGNMENT_ERR	0x08
1085*4882a593Smuzhiyun #define MIB_COUNTER_RX_CTRL_8808	0x09
1086*4882a593Smuzhiyun #define MIB_COUNTER_RX_PAUSE		0x0A
1087*4882a593Smuzhiyun #define MIB_COUNTER_RX_BROADCAST	0x0B
1088*4882a593Smuzhiyun #define MIB_COUNTER_RX_MULTICAST	0x0C
1089*4882a593Smuzhiyun #define MIB_COUNTER_RX_UNICAST		0x0D
1090*4882a593Smuzhiyun #define MIB_COUNTER_RX_OCTET_64		0x0E
1091*4882a593Smuzhiyun #define MIB_COUNTER_RX_OCTET_65_127	0x0F
1092*4882a593Smuzhiyun #define MIB_COUNTER_RX_OCTET_128_255	0x10
1093*4882a593Smuzhiyun #define MIB_COUNTER_RX_OCTET_256_511	0x11
1094*4882a593Smuzhiyun #define MIB_COUNTER_RX_OCTET_512_1023	0x12
1095*4882a593Smuzhiyun #define MIB_COUNTER_RX_OCTET_1024_1522	0x13
1096*4882a593Smuzhiyun #define MIB_COUNTER_TX_LO_PRIORITY	0x14
1097*4882a593Smuzhiyun #define MIB_COUNTER_TX_HI_PRIORITY	0x15
1098*4882a593Smuzhiyun #define MIB_COUNTER_TX_LATE_COLLISION	0x16
1099*4882a593Smuzhiyun #define MIB_COUNTER_TX_PAUSE		0x17
1100*4882a593Smuzhiyun #define MIB_COUNTER_TX_BROADCAST	0x18
1101*4882a593Smuzhiyun #define MIB_COUNTER_TX_MULTICAST	0x19
1102*4882a593Smuzhiyun #define MIB_COUNTER_TX_UNICAST		0x1A
1103*4882a593Smuzhiyun #define MIB_COUNTER_TX_DEFERRED		0x1B
1104*4882a593Smuzhiyun #define MIB_COUNTER_TX_TOTAL_COLLISION	0x1C
1105*4882a593Smuzhiyun #define MIB_COUNTER_TX_EXCESS_COLLISION	0x1D
1106*4882a593Smuzhiyun #define MIB_COUNTER_TX_SINGLE_COLLISION	0x1E
1107*4882a593Smuzhiyun #define MIB_COUNTER_TX_MULTI_COLLISION	0x1F
1108*4882a593Smuzhiyun 
1109*4882a593Smuzhiyun #define MIB_COUNTER_RX_DROPPED_PACKET	0x20
1110*4882a593Smuzhiyun #define MIB_COUNTER_TX_DROPPED_PACKET	0x21
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun /**
1113*4882a593Smuzhiyun  * struct ksz_port_mib - Port MIB data structure
1114*4882a593Smuzhiyun  * @cnt_ptr:	Current pointer to MIB counter index.
1115*4882a593Smuzhiyun  * @link_down:	Indication the link has just gone down.
1116*4882a593Smuzhiyun  * @state:	Connection status of the port.
1117*4882a593Smuzhiyun  * @mib_start:	The starting counter index.  Some ports do not start at 0.
1118*4882a593Smuzhiyun  * @counter:	64-bit MIB counter value.
1119*4882a593Smuzhiyun  * @dropped:	Temporary buffer to remember last read packet dropped values.
1120*4882a593Smuzhiyun  *
1121*4882a593Smuzhiyun  * MIB counters needs to be read periodically so that counters do not get
1122*4882a593Smuzhiyun  * overflowed and give incorrect values.  A right balance is needed to
1123*4882a593Smuzhiyun  * satisfy this condition and not waste too much CPU time.
1124*4882a593Smuzhiyun  *
1125*4882a593Smuzhiyun  * It is pointless to read MIB counters when the port is disconnected.  The
1126*4882a593Smuzhiyun  * @state provides the connection status so that MIB counters are read only
1127*4882a593Smuzhiyun  * when the port is connected.  The @link_down indicates the port is just
1128*4882a593Smuzhiyun  * disconnected so that all MIB counters are read one last time to update the
1129*4882a593Smuzhiyun  * information.
1130*4882a593Smuzhiyun  */
1131*4882a593Smuzhiyun struct ksz_port_mib {
1132*4882a593Smuzhiyun 	u8 cnt_ptr;
1133*4882a593Smuzhiyun 	u8 link_down;
1134*4882a593Smuzhiyun 	u8 state;
1135*4882a593Smuzhiyun 	u8 mib_start;
1136*4882a593Smuzhiyun 
1137*4882a593Smuzhiyun 	u64 counter[TOTAL_PORT_COUNTER_NUM];
1138*4882a593Smuzhiyun 	u32 dropped[2];
1139*4882a593Smuzhiyun };
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun /**
1142*4882a593Smuzhiyun  * struct ksz_port_cfg - Port configuration data structure
1143*4882a593Smuzhiyun  * @vid:	VID value.
1144*4882a593Smuzhiyun  * @member:	Port membership.
1145*4882a593Smuzhiyun  * @port_prio:	Port priority.
1146*4882a593Smuzhiyun  * @rx_rate:	Receive priority rate.
1147*4882a593Smuzhiyun  * @tx_rate:	Transmit priority rate.
1148*4882a593Smuzhiyun  * @stp_state:	Current Spanning Tree Protocol state.
1149*4882a593Smuzhiyun  */
1150*4882a593Smuzhiyun struct ksz_port_cfg {
1151*4882a593Smuzhiyun 	u16 vid;
1152*4882a593Smuzhiyun 	u8 member;
1153*4882a593Smuzhiyun 	u8 port_prio;
1154*4882a593Smuzhiyun 	u32 rx_rate[PRIO_QUEUES];
1155*4882a593Smuzhiyun 	u32 tx_rate[PRIO_QUEUES];
1156*4882a593Smuzhiyun 	int stp_state;
1157*4882a593Smuzhiyun };
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun /**
1160*4882a593Smuzhiyun  * struct ksz_switch - KSZ8842 switch data structure
1161*4882a593Smuzhiyun  * @mac_table:	MAC table entries information.
1162*4882a593Smuzhiyun  * @vlan_table:	VLAN table entries information.
1163*4882a593Smuzhiyun  * @port_cfg:	Port configuration information.
1164*4882a593Smuzhiyun  * @diffserv:	DiffServ priority settings.  Possible values from 6-bit of ToS
1165*4882a593Smuzhiyun  * 		(bit7 ~ bit2) field.
1166*4882a593Smuzhiyun  * @p_802_1p:	802.1P priority settings.  Possible values from 3-bit of 802.1p
1167*4882a593Smuzhiyun  * 		Tag priority field.
1168*4882a593Smuzhiyun  * @br_addr:	Bridge address.  Used for STP.
1169*4882a593Smuzhiyun  * @other_addr:	Other MAC address.  Used for multiple network device mode.
1170*4882a593Smuzhiyun  * @broad_per:	Broadcast storm percentage.
1171*4882a593Smuzhiyun  * @member:	Current port membership.  Used for STP.
1172*4882a593Smuzhiyun  */
1173*4882a593Smuzhiyun struct ksz_switch {
1174*4882a593Smuzhiyun 	struct ksz_mac_table mac_table[STATIC_MAC_TABLE_ENTRIES];
1175*4882a593Smuzhiyun 	struct ksz_vlan_table vlan_table[VLAN_TABLE_ENTRIES];
1176*4882a593Smuzhiyun 	struct ksz_port_cfg port_cfg[TOTAL_PORT_NUM];
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	u8 diffserv[DIFFSERV_ENTRIES];
1179*4882a593Smuzhiyun 	u8 p_802_1p[PRIO_802_1P_ENTRIES];
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun 	u8 br_addr[ETH_ALEN];
1182*4882a593Smuzhiyun 	u8 other_addr[ETH_ALEN];
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 	u8 broad_per;
1185*4882a593Smuzhiyun 	u8 member;
1186*4882a593Smuzhiyun };
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun #define TX_RATE_UNIT			10000
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun /**
1191*4882a593Smuzhiyun  * struct ksz_port_info - Port information data structure
1192*4882a593Smuzhiyun  * @state:	Connection status of the port.
1193*4882a593Smuzhiyun  * @tx_rate:	Transmit rate divided by 10000 to get Mbit.
1194*4882a593Smuzhiyun  * @duplex:	Duplex mode.
1195*4882a593Smuzhiyun  * @advertised:	Advertised auto-negotiation setting.  Used to determine link.
1196*4882a593Smuzhiyun  * @partner:	Auto-negotiation partner setting.  Used to determine link.
1197*4882a593Smuzhiyun  * @port_id:	Port index to access actual hardware register.
1198*4882a593Smuzhiyun  * @pdev:	Pointer to OS dependent network device.
1199*4882a593Smuzhiyun  */
1200*4882a593Smuzhiyun struct ksz_port_info {
1201*4882a593Smuzhiyun 	uint state;
1202*4882a593Smuzhiyun 	uint tx_rate;
1203*4882a593Smuzhiyun 	u8 duplex;
1204*4882a593Smuzhiyun 	u8 advertised;
1205*4882a593Smuzhiyun 	u8 partner;
1206*4882a593Smuzhiyun 	u8 port_id;
1207*4882a593Smuzhiyun 	void *pdev;
1208*4882a593Smuzhiyun };
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun #define MAX_TX_HELD_SIZE		52000
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun /* Hardware features and bug fixes. */
1213*4882a593Smuzhiyun #define LINK_INT_WORKING		(1 << 0)
1214*4882a593Smuzhiyun #define SMALL_PACKET_TX_BUG		(1 << 1)
1215*4882a593Smuzhiyun #define HALF_DUPLEX_SIGNAL_BUG		(1 << 2)
1216*4882a593Smuzhiyun #define RX_HUGE_FRAME			(1 << 4)
1217*4882a593Smuzhiyun #define STP_SUPPORT			(1 << 8)
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun /* Software overrides. */
1220*4882a593Smuzhiyun #define PAUSE_FLOW_CTRL			(1 << 0)
1221*4882a593Smuzhiyun #define FAST_AGING			(1 << 1)
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun /**
1224*4882a593Smuzhiyun  * struct ksz_hw - KSZ884X hardware data structure
1225*4882a593Smuzhiyun  * @io:			Virtual address assigned.
1226*4882a593Smuzhiyun  * @ksz_switch:		Pointer to KSZ8842 switch.
1227*4882a593Smuzhiyun  * @port_info:		Port information.
1228*4882a593Smuzhiyun  * @port_mib:		Port MIB information.
1229*4882a593Smuzhiyun  * @dev_count:		Number of network devices this hardware supports.
1230*4882a593Smuzhiyun  * @dst_ports:		Destination ports in switch for transmission.
1231*4882a593Smuzhiyun  * @id:			Hardware ID.  Used for display only.
1232*4882a593Smuzhiyun  * @mib_cnt:		Number of MIB counters this hardware has.
1233*4882a593Smuzhiyun  * @mib_port_cnt:	Number of ports with MIB counters.
1234*4882a593Smuzhiyun  * @tx_cfg:		Cached transmit control settings.
1235*4882a593Smuzhiyun  * @rx_cfg:		Cached receive control settings.
1236*4882a593Smuzhiyun  * @intr_mask:		Current interrupt mask.
1237*4882a593Smuzhiyun  * @intr_set:		Current interrup set.
1238*4882a593Smuzhiyun  * @intr_blocked:	Interrupt blocked.
1239*4882a593Smuzhiyun  * @rx_desc_info:	Receive descriptor information.
1240*4882a593Smuzhiyun  * @tx_desc_info:	Transmit descriptor information.
1241*4882a593Smuzhiyun  * @tx_int_cnt:		Transmit interrupt count.  Used for TX optimization.
1242*4882a593Smuzhiyun  * @tx_int_mask:	Transmit interrupt mask.  Used for TX optimization.
1243*4882a593Smuzhiyun  * @tx_size:		Transmit data size.  Used for TX optimization.
1244*4882a593Smuzhiyun  * 			The maximum is defined by MAX_TX_HELD_SIZE.
1245*4882a593Smuzhiyun  * @perm_addr:		Permanent MAC address.
1246*4882a593Smuzhiyun  * @override_addr:	Overridden MAC address.
1247*4882a593Smuzhiyun  * @address:		Additional MAC address entries.
1248*4882a593Smuzhiyun  * @addr_list_size:	Additional MAC address list size.
1249*4882a593Smuzhiyun  * @mac_override:	Indication of MAC address overridden.
1250*4882a593Smuzhiyun  * @promiscuous:	Counter to keep track of promiscuous mode set.
1251*4882a593Smuzhiyun  * @all_multi:		Counter to keep track of all multicast mode set.
1252*4882a593Smuzhiyun  * @multi_list:		Multicast address entries.
1253*4882a593Smuzhiyun  * @multi_bits:		Cached multicast hash table settings.
1254*4882a593Smuzhiyun  * @multi_list_size:	Multicast address list size.
1255*4882a593Smuzhiyun  * @enabled:		Indication of hardware enabled.
1256*4882a593Smuzhiyun  * @rx_stop:		Indication of receive process stop.
1257*4882a593Smuzhiyun  * @reserved2:		none
1258*4882a593Smuzhiyun  * @features:		Hardware features to enable.
1259*4882a593Smuzhiyun  * @overrides:		Hardware features to override.
1260*4882a593Smuzhiyun  * @parent:		Pointer to parent, network device private structure.
1261*4882a593Smuzhiyun  */
1262*4882a593Smuzhiyun struct ksz_hw {
1263*4882a593Smuzhiyun 	void __iomem *io;
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 	struct ksz_switch *ksz_switch;
1266*4882a593Smuzhiyun 	struct ksz_port_info port_info[SWITCH_PORT_NUM];
1267*4882a593Smuzhiyun 	struct ksz_port_mib port_mib[TOTAL_PORT_NUM];
1268*4882a593Smuzhiyun 	int dev_count;
1269*4882a593Smuzhiyun 	int dst_ports;
1270*4882a593Smuzhiyun 	int id;
1271*4882a593Smuzhiyun 	int mib_cnt;
1272*4882a593Smuzhiyun 	int mib_port_cnt;
1273*4882a593Smuzhiyun 
1274*4882a593Smuzhiyun 	u32 tx_cfg;
1275*4882a593Smuzhiyun 	u32 rx_cfg;
1276*4882a593Smuzhiyun 	u32 intr_mask;
1277*4882a593Smuzhiyun 	u32 intr_set;
1278*4882a593Smuzhiyun 	uint intr_blocked;
1279*4882a593Smuzhiyun 
1280*4882a593Smuzhiyun 	struct ksz_desc_info rx_desc_info;
1281*4882a593Smuzhiyun 	struct ksz_desc_info tx_desc_info;
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun 	int tx_int_cnt;
1284*4882a593Smuzhiyun 	int tx_int_mask;
1285*4882a593Smuzhiyun 	int tx_size;
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	u8 perm_addr[ETH_ALEN];
1288*4882a593Smuzhiyun 	u8 override_addr[ETH_ALEN];
1289*4882a593Smuzhiyun 	u8 address[ADDITIONAL_ENTRIES][ETH_ALEN];
1290*4882a593Smuzhiyun 	u8 addr_list_size;
1291*4882a593Smuzhiyun 	u8 mac_override;
1292*4882a593Smuzhiyun 	u8 promiscuous;
1293*4882a593Smuzhiyun 	u8 all_multi;
1294*4882a593Smuzhiyun 	u8 multi_list[MAX_MULTICAST_LIST][ETH_ALEN];
1295*4882a593Smuzhiyun 	u8 multi_bits[HW_MULTICAST_SIZE];
1296*4882a593Smuzhiyun 	u8 multi_list_size;
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 	u8 enabled;
1299*4882a593Smuzhiyun 	u8 rx_stop;
1300*4882a593Smuzhiyun 	u8 reserved2[1];
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun 	uint features;
1303*4882a593Smuzhiyun 	uint overrides;
1304*4882a593Smuzhiyun 
1305*4882a593Smuzhiyun 	void *parent;
1306*4882a593Smuzhiyun };
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun enum {
1309*4882a593Smuzhiyun 	PHY_NO_FLOW_CTRL,
1310*4882a593Smuzhiyun 	PHY_FLOW_CTRL,
1311*4882a593Smuzhiyun 	PHY_TX_ONLY,
1312*4882a593Smuzhiyun 	PHY_RX_ONLY
1313*4882a593Smuzhiyun };
1314*4882a593Smuzhiyun 
1315*4882a593Smuzhiyun /**
1316*4882a593Smuzhiyun  * struct ksz_port - Virtual port data structure
1317*4882a593Smuzhiyun  * @duplex:		Duplex mode setting.  1 for half duplex, 2 for full
1318*4882a593Smuzhiyun  * 			duplex, and 0 for auto, which normally results in full
1319*4882a593Smuzhiyun  * 			duplex.
1320*4882a593Smuzhiyun  * @speed:		Speed setting.  10 for 10 Mbit, 100 for 100 Mbit, and
1321*4882a593Smuzhiyun  * 			0 for auto, which normally results in 100 Mbit.
1322*4882a593Smuzhiyun  * @force_link:		Force link setting.  0 for auto-negotiation, and 1 for
1323*4882a593Smuzhiyun  * 			force.
1324*4882a593Smuzhiyun  * @flow_ctrl:		Flow control setting.  PHY_NO_FLOW_CTRL for no flow
1325*4882a593Smuzhiyun  * 			control, and PHY_FLOW_CTRL for flow control.
1326*4882a593Smuzhiyun  * 			PHY_TX_ONLY and PHY_RX_ONLY are not supported for 100
1327*4882a593Smuzhiyun  * 			Mbit PHY.
1328*4882a593Smuzhiyun  * @first_port:		Index of first port this port supports.
1329*4882a593Smuzhiyun  * @mib_port_cnt:	Number of ports with MIB counters.
1330*4882a593Smuzhiyun  * @port_cnt:		Number of ports this port supports.
1331*4882a593Smuzhiyun  * @counter:		Port statistics counter.
1332*4882a593Smuzhiyun  * @hw:			Pointer to hardware structure.
1333*4882a593Smuzhiyun  * @linked:		Pointer to port information linked to this port.
1334*4882a593Smuzhiyun  */
1335*4882a593Smuzhiyun struct ksz_port {
1336*4882a593Smuzhiyun 	u8 duplex;
1337*4882a593Smuzhiyun 	u8 speed;
1338*4882a593Smuzhiyun 	u8 force_link;
1339*4882a593Smuzhiyun 	u8 flow_ctrl;
1340*4882a593Smuzhiyun 
1341*4882a593Smuzhiyun 	int first_port;
1342*4882a593Smuzhiyun 	int mib_port_cnt;
1343*4882a593Smuzhiyun 	int port_cnt;
1344*4882a593Smuzhiyun 	u64 counter[OID_COUNTER_LAST];
1345*4882a593Smuzhiyun 
1346*4882a593Smuzhiyun 	struct ksz_hw *hw;
1347*4882a593Smuzhiyun 	struct ksz_port_info *linked;
1348*4882a593Smuzhiyun };
1349*4882a593Smuzhiyun 
1350*4882a593Smuzhiyun /**
1351*4882a593Smuzhiyun  * struct ksz_timer_info - Timer information data structure
1352*4882a593Smuzhiyun  * @timer:	Kernel timer.
1353*4882a593Smuzhiyun  * @cnt:	Running timer counter.
1354*4882a593Smuzhiyun  * @max:	Number of times to run timer; -1 for infinity.
1355*4882a593Smuzhiyun  * @period:	Timer period in jiffies.
1356*4882a593Smuzhiyun  */
1357*4882a593Smuzhiyun struct ksz_timer_info {
1358*4882a593Smuzhiyun 	struct timer_list timer;
1359*4882a593Smuzhiyun 	int cnt;
1360*4882a593Smuzhiyun 	int max;
1361*4882a593Smuzhiyun 	int period;
1362*4882a593Smuzhiyun };
1363*4882a593Smuzhiyun 
1364*4882a593Smuzhiyun /**
1365*4882a593Smuzhiyun  * struct ksz_shared_mem - OS dependent shared memory data structure
1366*4882a593Smuzhiyun  * @dma_addr:	Physical DMA address allocated.
1367*4882a593Smuzhiyun  * @alloc_size:	Allocation size.
1368*4882a593Smuzhiyun  * @phys:	Actual physical address used.
1369*4882a593Smuzhiyun  * @alloc_virt:	Virtual address allocated.
1370*4882a593Smuzhiyun  * @virt:	Actual virtual address used.
1371*4882a593Smuzhiyun  */
1372*4882a593Smuzhiyun struct ksz_shared_mem {
1373*4882a593Smuzhiyun 	dma_addr_t dma_addr;
1374*4882a593Smuzhiyun 	uint alloc_size;
1375*4882a593Smuzhiyun 	uint phys;
1376*4882a593Smuzhiyun 	u8 *alloc_virt;
1377*4882a593Smuzhiyun 	u8 *virt;
1378*4882a593Smuzhiyun };
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun /**
1381*4882a593Smuzhiyun  * struct ksz_counter_info - OS dependent counter information data structure
1382*4882a593Smuzhiyun  * @counter:	Wait queue to wakeup after counters are read.
1383*4882a593Smuzhiyun  * @time:	Next time in jiffies to read counter.
1384*4882a593Smuzhiyun  * @read:	Indication of counters read in full or not.
1385*4882a593Smuzhiyun  */
1386*4882a593Smuzhiyun struct ksz_counter_info {
1387*4882a593Smuzhiyun 	wait_queue_head_t counter;
1388*4882a593Smuzhiyun 	unsigned long time;
1389*4882a593Smuzhiyun 	int read;
1390*4882a593Smuzhiyun };
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun /**
1393*4882a593Smuzhiyun  * struct dev_info - Network device information data structure
1394*4882a593Smuzhiyun  * @dev:		Pointer to network device.
1395*4882a593Smuzhiyun  * @pdev:		Pointer to PCI device.
1396*4882a593Smuzhiyun  * @hw:			Hardware structure.
1397*4882a593Smuzhiyun  * @desc_pool:		Physical memory used for descriptor pool.
1398*4882a593Smuzhiyun  * @hwlock:		Spinlock to prevent hardware from accessing.
1399*4882a593Smuzhiyun  * @lock:		Mutex lock to prevent device from accessing.
1400*4882a593Smuzhiyun  * @dev_rcv:		Receive process function used.
1401*4882a593Smuzhiyun  * @last_skb:		Socket buffer allocated for descriptor rx fragments.
1402*4882a593Smuzhiyun  * @skb_index:		Buffer index for receiving fragments.
1403*4882a593Smuzhiyun  * @skb_len:		Buffer length for receiving fragments.
1404*4882a593Smuzhiyun  * @mib_read:		Workqueue to read MIB counters.
1405*4882a593Smuzhiyun  * @mib_timer_info:	Timer to read MIB counters.
1406*4882a593Smuzhiyun  * @counter:		Used for MIB reading.
1407*4882a593Smuzhiyun  * @mtu:		Current MTU used.  The default is REGULAR_RX_BUF_SIZE;
1408*4882a593Smuzhiyun  * 			the maximum is MAX_RX_BUF_SIZE.
1409*4882a593Smuzhiyun  * @opened:		Counter to keep track of device open.
1410*4882a593Smuzhiyun  * @rx_tasklet:		Receive processing tasklet.
1411*4882a593Smuzhiyun  * @tx_tasklet:		Transmit processing tasklet.
1412*4882a593Smuzhiyun  * @wol_enable:		Wake-on-LAN enable set by ethtool.
1413*4882a593Smuzhiyun  * @wol_support:	Wake-on-LAN support used by ethtool.
1414*4882a593Smuzhiyun  * @pme_wait:		Used for KSZ8841 power management.
1415*4882a593Smuzhiyun  */
1416*4882a593Smuzhiyun struct dev_info {
1417*4882a593Smuzhiyun 	struct net_device *dev;
1418*4882a593Smuzhiyun 	struct pci_dev *pdev;
1419*4882a593Smuzhiyun 
1420*4882a593Smuzhiyun 	struct ksz_hw hw;
1421*4882a593Smuzhiyun 	struct ksz_shared_mem desc_pool;
1422*4882a593Smuzhiyun 
1423*4882a593Smuzhiyun 	spinlock_t hwlock;
1424*4882a593Smuzhiyun 	struct mutex lock;
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun 	int (*dev_rcv)(struct dev_info *);
1427*4882a593Smuzhiyun 
1428*4882a593Smuzhiyun 	struct sk_buff *last_skb;
1429*4882a593Smuzhiyun 	int skb_index;
1430*4882a593Smuzhiyun 	int skb_len;
1431*4882a593Smuzhiyun 
1432*4882a593Smuzhiyun 	struct work_struct mib_read;
1433*4882a593Smuzhiyun 	struct ksz_timer_info mib_timer_info;
1434*4882a593Smuzhiyun 	struct ksz_counter_info counter[TOTAL_PORT_NUM];
1435*4882a593Smuzhiyun 
1436*4882a593Smuzhiyun 	int mtu;
1437*4882a593Smuzhiyun 	int opened;
1438*4882a593Smuzhiyun 
1439*4882a593Smuzhiyun 	struct tasklet_struct rx_tasklet;
1440*4882a593Smuzhiyun 	struct tasklet_struct tx_tasklet;
1441*4882a593Smuzhiyun 
1442*4882a593Smuzhiyun 	int wol_enable;
1443*4882a593Smuzhiyun 	int wol_support;
1444*4882a593Smuzhiyun 	unsigned long pme_wait;
1445*4882a593Smuzhiyun };
1446*4882a593Smuzhiyun 
1447*4882a593Smuzhiyun /**
1448*4882a593Smuzhiyun  * struct dev_priv - Network device private data structure
1449*4882a593Smuzhiyun  * @adapter:		Adapter device information.
1450*4882a593Smuzhiyun  * @port:		Port information.
1451*4882a593Smuzhiyun  * @monitor_timer_info:	Timer to monitor ports.
1452*4882a593Smuzhiyun  * @proc_sem:		Semaphore for proc accessing.
1453*4882a593Smuzhiyun  * @id:			Device ID.
1454*4882a593Smuzhiyun  * @mii_if:		MII interface information.
1455*4882a593Smuzhiyun  * @advertising:	Temporary variable to store advertised settings.
1456*4882a593Smuzhiyun  * @msg_enable:		The message flags controlling driver output.
1457*4882a593Smuzhiyun  * @media_state:	The connection status of the device.
1458*4882a593Smuzhiyun  * @multicast:		The all multicast state of the device.
1459*4882a593Smuzhiyun  * @promiscuous:	The promiscuous state of the device.
1460*4882a593Smuzhiyun  */
1461*4882a593Smuzhiyun struct dev_priv {
1462*4882a593Smuzhiyun 	struct dev_info *adapter;
1463*4882a593Smuzhiyun 	struct ksz_port port;
1464*4882a593Smuzhiyun 	struct ksz_timer_info monitor_timer_info;
1465*4882a593Smuzhiyun 
1466*4882a593Smuzhiyun 	struct semaphore proc_sem;
1467*4882a593Smuzhiyun 	int id;
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 	struct mii_if_info mii_if;
1470*4882a593Smuzhiyun 	u32 advertising;
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun 	u32 msg_enable;
1473*4882a593Smuzhiyun 	int media_state;
1474*4882a593Smuzhiyun 	int multicast;
1475*4882a593Smuzhiyun 	int promiscuous;
1476*4882a593Smuzhiyun };
1477*4882a593Smuzhiyun 
1478*4882a593Smuzhiyun #define DRV_NAME		"KSZ884X PCI"
1479*4882a593Smuzhiyun #define DEVICE_NAME		"KSZ884x PCI"
1480*4882a593Smuzhiyun #define DRV_VERSION		"1.0.0"
1481*4882a593Smuzhiyun #define DRV_RELDATE		"Feb 8, 2010"
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun static char version[] =
1484*4882a593Smuzhiyun 	"Micrel " DEVICE_NAME " " DRV_VERSION " (" DRV_RELDATE ")";
1485*4882a593Smuzhiyun 
1486*4882a593Smuzhiyun static u8 DEFAULT_MAC_ADDRESS[] = { 0x00, 0x10, 0xA1, 0x88, 0x42, 0x01 };
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun /*
1489*4882a593Smuzhiyun  * Interrupt processing primary routines
1490*4882a593Smuzhiyun  */
1491*4882a593Smuzhiyun 
hw_ack_intr(struct ksz_hw * hw,uint interrupt)1492*4882a593Smuzhiyun static inline void hw_ack_intr(struct ksz_hw *hw, uint interrupt)
1493*4882a593Smuzhiyun {
1494*4882a593Smuzhiyun 	writel(interrupt, hw->io + KS884X_INTERRUPTS_STATUS);
1495*4882a593Smuzhiyun }
1496*4882a593Smuzhiyun 
hw_dis_intr(struct ksz_hw * hw)1497*4882a593Smuzhiyun static inline void hw_dis_intr(struct ksz_hw *hw)
1498*4882a593Smuzhiyun {
1499*4882a593Smuzhiyun 	hw->intr_blocked = hw->intr_mask;
1500*4882a593Smuzhiyun 	writel(0, hw->io + KS884X_INTERRUPTS_ENABLE);
1501*4882a593Smuzhiyun 	hw->intr_set = readl(hw->io + KS884X_INTERRUPTS_ENABLE);
1502*4882a593Smuzhiyun }
1503*4882a593Smuzhiyun 
hw_set_intr(struct ksz_hw * hw,uint interrupt)1504*4882a593Smuzhiyun static inline void hw_set_intr(struct ksz_hw *hw, uint interrupt)
1505*4882a593Smuzhiyun {
1506*4882a593Smuzhiyun 	hw->intr_set = interrupt;
1507*4882a593Smuzhiyun 	writel(interrupt, hw->io + KS884X_INTERRUPTS_ENABLE);
1508*4882a593Smuzhiyun }
1509*4882a593Smuzhiyun 
hw_ena_intr(struct ksz_hw * hw)1510*4882a593Smuzhiyun static inline void hw_ena_intr(struct ksz_hw *hw)
1511*4882a593Smuzhiyun {
1512*4882a593Smuzhiyun 	hw->intr_blocked = 0;
1513*4882a593Smuzhiyun 	hw_set_intr(hw, hw->intr_mask);
1514*4882a593Smuzhiyun }
1515*4882a593Smuzhiyun 
hw_dis_intr_bit(struct ksz_hw * hw,uint bit)1516*4882a593Smuzhiyun static inline void hw_dis_intr_bit(struct ksz_hw *hw, uint bit)
1517*4882a593Smuzhiyun {
1518*4882a593Smuzhiyun 	hw->intr_mask &= ~(bit);
1519*4882a593Smuzhiyun }
1520*4882a593Smuzhiyun 
hw_turn_off_intr(struct ksz_hw * hw,uint interrupt)1521*4882a593Smuzhiyun static inline void hw_turn_off_intr(struct ksz_hw *hw, uint interrupt)
1522*4882a593Smuzhiyun {
1523*4882a593Smuzhiyun 	u32 read_intr;
1524*4882a593Smuzhiyun 
1525*4882a593Smuzhiyun 	read_intr = readl(hw->io + KS884X_INTERRUPTS_ENABLE);
1526*4882a593Smuzhiyun 	hw->intr_set = read_intr & ~interrupt;
1527*4882a593Smuzhiyun 	writel(hw->intr_set, hw->io + KS884X_INTERRUPTS_ENABLE);
1528*4882a593Smuzhiyun 	hw_dis_intr_bit(hw, interrupt);
1529*4882a593Smuzhiyun }
1530*4882a593Smuzhiyun 
1531*4882a593Smuzhiyun /**
1532*4882a593Smuzhiyun  * hw_turn_on_intr - turn on specified interrupts
1533*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1534*4882a593Smuzhiyun  * @bit:	The interrupt bits to be on.
1535*4882a593Smuzhiyun  *
1536*4882a593Smuzhiyun  * This routine turns on the specified interrupts in the interrupt mask so that
1537*4882a593Smuzhiyun  * those interrupts will be enabled.
1538*4882a593Smuzhiyun  */
hw_turn_on_intr(struct ksz_hw * hw,u32 bit)1539*4882a593Smuzhiyun static void hw_turn_on_intr(struct ksz_hw *hw, u32 bit)
1540*4882a593Smuzhiyun {
1541*4882a593Smuzhiyun 	hw->intr_mask |= bit;
1542*4882a593Smuzhiyun 
1543*4882a593Smuzhiyun 	if (!hw->intr_blocked)
1544*4882a593Smuzhiyun 		hw_set_intr(hw, hw->intr_mask);
1545*4882a593Smuzhiyun }
1546*4882a593Smuzhiyun 
hw_ena_intr_bit(struct ksz_hw * hw,uint interrupt)1547*4882a593Smuzhiyun static inline void hw_ena_intr_bit(struct ksz_hw *hw, uint interrupt)
1548*4882a593Smuzhiyun {
1549*4882a593Smuzhiyun 	u32 read_intr;
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun 	read_intr = readl(hw->io + KS884X_INTERRUPTS_ENABLE);
1552*4882a593Smuzhiyun 	hw->intr_set = read_intr | interrupt;
1553*4882a593Smuzhiyun 	writel(hw->intr_set, hw->io + KS884X_INTERRUPTS_ENABLE);
1554*4882a593Smuzhiyun }
1555*4882a593Smuzhiyun 
hw_read_intr(struct ksz_hw * hw,uint * status)1556*4882a593Smuzhiyun static inline void hw_read_intr(struct ksz_hw *hw, uint *status)
1557*4882a593Smuzhiyun {
1558*4882a593Smuzhiyun 	*status = readl(hw->io + KS884X_INTERRUPTS_STATUS);
1559*4882a593Smuzhiyun 	*status = *status & hw->intr_set;
1560*4882a593Smuzhiyun }
1561*4882a593Smuzhiyun 
hw_restore_intr(struct ksz_hw * hw,uint interrupt)1562*4882a593Smuzhiyun static inline void hw_restore_intr(struct ksz_hw *hw, uint interrupt)
1563*4882a593Smuzhiyun {
1564*4882a593Smuzhiyun 	if (interrupt)
1565*4882a593Smuzhiyun 		hw_ena_intr(hw);
1566*4882a593Smuzhiyun }
1567*4882a593Smuzhiyun 
1568*4882a593Smuzhiyun /**
1569*4882a593Smuzhiyun  * hw_block_intr - block hardware interrupts
1570*4882a593Smuzhiyun  * @hw: The hardware instance.
1571*4882a593Smuzhiyun  *
1572*4882a593Smuzhiyun  * This function blocks all interrupts of the hardware and returns the current
1573*4882a593Smuzhiyun  * interrupt enable mask so that interrupts can be restored later.
1574*4882a593Smuzhiyun  *
1575*4882a593Smuzhiyun  * Return the current interrupt enable mask.
1576*4882a593Smuzhiyun  */
hw_block_intr(struct ksz_hw * hw)1577*4882a593Smuzhiyun static uint hw_block_intr(struct ksz_hw *hw)
1578*4882a593Smuzhiyun {
1579*4882a593Smuzhiyun 	uint interrupt = 0;
1580*4882a593Smuzhiyun 
1581*4882a593Smuzhiyun 	if (!hw->intr_blocked) {
1582*4882a593Smuzhiyun 		hw_dis_intr(hw);
1583*4882a593Smuzhiyun 		interrupt = hw->intr_blocked;
1584*4882a593Smuzhiyun 	}
1585*4882a593Smuzhiyun 	return interrupt;
1586*4882a593Smuzhiyun }
1587*4882a593Smuzhiyun 
1588*4882a593Smuzhiyun /*
1589*4882a593Smuzhiyun  * Hardware descriptor routines
1590*4882a593Smuzhiyun  */
1591*4882a593Smuzhiyun 
reset_desc(struct ksz_desc * desc,union desc_stat status)1592*4882a593Smuzhiyun static inline void reset_desc(struct ksz_desc *desc, union desc_stat status)
1593*4882a593Smuzhiyun {
1594*4882a593Smuzhiyun 	status.rx.hw_owned = 0;
1595*4882a593Smuzhiyun 	desc->phw->ctrl.data = cpu_to_le32(status.data);
1596*4882a593Smuzhiyun }
1597*4882a593Smuzhiyun 
release_desc(struct ksz_desc * desc)1598*4882a593Smuzhiyun static inline void release_desc(struct ksz_desc *desc)
1599*4882a593Smuzhiyun {
1600*4882a593Smuzhiyun 	desc->sw.ctrl.tx.hw_owned = 1;
1601*4882a593Smuzhiyun 	if (desc->sw.buf_size != desc->sw.buf.data) {
1602*4882a593Smuzhiyun 		desc->sw.buf_size = desc->sw.buf.data;
1603*4882a593Smuzhiyun 		desc->phw->buf.data = cpu_to_le32(desc->sw.buf.data);
1604*4882a593Smuzhiyun 	}
1605*4882a593Smuzhiyun 	desc->phw->ctrl.data = cpu_to_le32(desc->sw.ctrl.data);
1606*4882a593Smuzhiyun }
1607*4882a593Smuzhiyun 
get_rx_pkt(struct ksz_desc_info * info,struct ksz_desc ** desc)1608*4882a593Smuzhiyun static void get_rx_pkt(struct ksz_desc_info *info, struct ksz_desc **desc)
1609*4882a593Smuzhiyun {
1610*4882a593Smuzhiyun 	*desc = &info->ring[info->last];
1611*4882a593Smuzhiyun 	info->last++;
1612*4882a593Smuzhiyun 	info->last &= info->mask;
1613*4882a593Smuzhiyun 	info->avail--;
1614*4882a593Smuzhiyun 	(*desc)->sw.buf.data &= ~KS_DESC_RX_MASK;
1615*4882a593Smuzhiyun }
1616*4882a593Smuzhiyun 
set_rx_buf(struct ksz_desc * desc,u32 addr)1617*4882a593Smuzhiyun static inline void set_rx_buf(struct ksz_desc *desc, u32 addr)
1618*4882a593Smuzhiyun {
1619*4882a593Smuzhiyun 	desc->phw->addr = cpu_to_le32(addr);
1620*4882a593Smuzhiyun }
1621*4882a593Smuzhiyun 
set_rx_len(struct ksz_desc * desc,u32 len)1622*4882a593Smuzhiyun static inline void set_rx_len(struct ksz_desc *desc, u32 len)
1623*4882a593Smuzhiyun {
1624*4882a593Smuzhiyun 	desc->sw.buf.rx.buf_size = len;
1625*4882a593Smuzhiyun }
1626*4882a593Smuzhiyun 
get_tx_pkt(struct ksz_desc_info * info,struct ksz_desc ** desc)1627*4882a593Smuzhiyun static inline void get_tx_pkt(struct ksz_desc_info *info,
1628*4882a593Smuzhiyun 	struct ksz_desc **desc)
1629*4882a593Smuzhiyun {
1630*4882a593Smuzhiyun 	*desc = &info->ring[info->next];
1631*4882a593Smuzhiyun 	info->next++;
1632*4882a593Smuzhiyun 	info->next &= info->mask;
1633*4882a593Smuzhiyun 	info->avail--;
1634*4882a593Smuzhiyun 	(*desc)->sw.buf.data &= ~KS_DESC_TX_MASK;
1635*4882a593Smuzhiyun }
1636*4882a593Smuzhiyun 
set_tx_buf(struct ksz_desc * desc,u32 addr)1637*4882a593Smuzhiyun static inline void set_tx_buf(struct ksz_desc *desc, u32 addr)
1638*4882a593Smuzhiyun {
1639*4882a593Smuzhiyun 	desc->phw->addr = cpu_to_le32(addr);
1640*4882a593Smuzhiyun }
1641*4882a593Smuzhiyun 
set_tx_len(struct ksz_desc * desc,u32 len)1642*4882a593Smuzhiyun static inline void set_tx_len(struct ksz_desc *desc, u32 len)
1643*4882a593Smuzhiyun {
1644*4882a593Smuzhiyun 	desc->sw.buf.tx.buf_size = len;
1645*4882a593Smuzhiyun }
1646*4882a593Smuzhiyun 
1647*4882a593Smuzhiyun /* Switch functions */
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun #define TABLE_READ			0x10
1650*4882a593Smuzhiyun #define TABLE_SEL_SHIFT			2
1651*4882a593Smuzhiyun 
1652*4882a593Smuzhiyun #define HW_DELAY(hw, reg)			\
1653*4882a593Smuzhiyun 	do {					\
1654*4882a593Smuzhiyun 		readw(hw->io + reg);		\
1655*4882a593Smuzhiyun 	} while (0)
1656*4882a593Smuzhiyun 
1657*4882a593Smuzhiyun /**
1658*4882a593Smuzhiyun  * sw_r_table - read 4 bytes of data from switch table
1659*4882a593Smuzhiyun  * @hw:		The hardware instance.
1660*4882a593Smuzhiyun  * @table:	The table selector.
1661*4882a593Smuzhiyun  * @addr:	The address of the table entry.
1662*4882a593Smuzhiyun  * @data:	Buffer to store the read data.
1663*4882a593Smuzhiyun  *
1664*4882a593Smuzhiyun  * This routine reads 4 bytes of data from the table of the switch.
1665*4882a593Smuzhiyun  * Hardware interrupts are disabled to minimize corruption of read data.
1666*4882a593Smuzhiyun  */
sw_r_table(struct ksz_hw * hw,int table,u16 addr,u32 * data)1667*4882a593Smuzhiyun static void sw_r_table(struct ksz_hw *hw, int table, u16 addr, u32 *data)
1668*4882a593Smuzhiyun {
1669*4882a593Smuzhiyun 	u16 ctrl_addr;
1670*4882a593Smuzhiyun 	uint interrupt;
1671*4882a593Smuzhiyun 
1672*4882a593Smuzhiyun 	ctrl_addr = (((table << TABLE_SEL_SHIFT) | TABLE_READ) << 8) | addr;
1673*4882a593Smuzhiyun 
1674*4882a593Smuzhiyun 	interrupt = hw_block_intr(hw);
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 	writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET);
1677*4882a593Smuzhiyun 	HW_DELAY(hw, KS884X_IACR_OFFSET);
1678*4882a593Smuzhiyun 	*data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET);
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 	hw_restore_intr(hw, interrupt);
1681*4882a593Smuzhiyun }
1682*4882a593Smuzhiyun 
1683*4882a593Smuzhiyun /**
1684*4882a593Smuzhiyun  * sw_w_table_64 - write 8 bytes of data to the switch table
1685*4882a593Smuzhiyun  * @hw:		The hardware instance.
1686*4882a593Smuzhiyun  * @table:	The table selector.
1687*4882a593Smuzhiyun  * @addr:	The address of the table entry.
1688*4882a593Smuzhiyun  * @data_hi:	The high part of data to be written (bit63 ~ bit32).
1689*4882a593Smuzhiyun  * @data_lo:	The low part of data to be written (bit31 ~ bit0).
1690*4882a593Smuzhiyun  *
1691*4882a593Smuzhiyun  * This routine writes 8 bytes of data to the table of the switch.
1692*4882a593Smuzhiyun  * Hardware interrupts are disabled to minimize corruption of written data.
1693*4882a593Smuzhiyun  */
sw_w_table_64(struct ksz_hw * hw,int table,u16 addr,u32 data_hi,u32 data_lo)1694*4882a593Smuzhiyun static void sw_w_table_64(struct ksz_hw *hw, int table, u16 addr, u32 data_hi,
1695*4882a593Smuzhiyun 	u32 data_lo)
1696*4882a593Smuzhiyun {
1697*4882a593Smuzhiyun 	u16 ctrl_addr;
1698*4882a593Smuzhiyun 	uint interrupt;
1699*4882a593Smuzhiyun 
1700*4882a593Smuzhiyun 	ctrl_addr = ((table << TABLE_SEL_SHIFT) << 8) | addr;
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun 	interrupt = hw_block_intr(hw);
1703*4882a593Smuzhiyun 
1704*4882a593Smuzhiyun 	writel(data_hi, hw->io + KS884X_ACC_DATA_4_OFFSET);
1705*4882a593Smuzhiyun 	writel(data_lo, hw->io + KS884X_ACC_DATA_0_OFFSET);
1706*4882a593Smuzhiyun 
1707*4882a593Smuzhiyun 	writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET);
1708*4882a593Smuzhiyun 	HW_DELAY(hw, KS884X_IACR_OFFSET);
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun 	hw_restore_intr(hw, interrupt);
1711*4882a593Smuzhiyun }
1712*4882a593Smuzhiyun 
1713*4882a593Smuzhiyun /**
1714*4882a593Smuzhiyun  * sw_w_sta_mac_table - write to the static MAC table
1715*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1716*4882a593Smuzhiyun  * @addr:	The address of the table entry.
1717*4882a593Smuzhiyun  * @mac_addr:	The MAC address.
1718*4882a593Smuzhiyun  * @ports:	The port members.
1719*4882a593Smuzhiyun  * @override:	The flag to override the port receive/transmit settings.
1720*4882a593Smuzhiyun  * @valid:	The flag to indicate entry is valid.
1721*4882a593Smuzhiyun  * @use_fid:	The flag to indicate the FID is valid.
1722*4882a593Smuzhiyun  * @fid:	The FID value.
1723*4882a593Smuzhiyun  *
1724*4882a593Smuzhiyun  * This routine writes an entry of the static MAC table of the switch.  It
1725*4882a593Smuzhiyun  * calls sw_w_table_64() to write the data.
1726*4882a593Smuzhiyun  */
sw_w_sta_mac_table(struct ksz_hw * hw,u16 addr,u8 * mac_addr,u8 ports,int override,int valid,int use_fid,u8 fid)1727*4882a593Smuzhiyun static void sw_w_sta_mac_table(struct ksz_hw *hw, u16 addr, u8 *mac_addr,
1728*4882a593Smuzhiyun 	u8 ports, int override, int valid, int use_fid, u8 fid)
1729*4882a593Smuzhiyun {
1730*4882a593Smuzhiyun 	u32 data_hi;
1731*4882a593Smuzhiyun 	u32 data_lo;
1732*4882a593Smuzhiyun 
1733*4882a593Smuzhiyun 	data_lo = ((u32) mac_addr[2] << 24) |
1734*4882a593Smuzhiyun 		((u32) mac_addr[3] << 16) |
1735*4882a593Smuzhiyun 		((u32) mac_addr[4] << 8) | mac_addr[5];
1736*4882a593Smuzhiyun 	data_hi = ((u32) mac_addr[0] << 8) | mac_addr[1];
1737*4882a593Smuzhiyun 	data_hi |= (u32) ports << STATIC_MAC_FWD_PORTS_SHIFT;
1738*4882a593Smuzhiyun 
1739*4882a593Smuzhiyun 	if (override)
1740*4882a593Smuzhiyun 		data_hi |= STATIC_MAC_TABLE_OVERRIDE;
1741*4882a593Smuzhiyun 	if (use_fid) {
1742*4882a593Smuzhiyun 		data_hi |= STATIC_MAC_TABLE_USE_FID;
1743*4882a593Smuzhiyun 		data_hi |= (u32) fid << STATIC_MAC_FID_SHIFT;
1744*4882a593Smuzhiyun 	}
1745*4882a593Smuzhiyun 	if (valid)
1746*4882a593Smuzhiyun 		data_hi |= STATIC_MAC_TABLE_VALID;
1747*4882a593Smuzhiyun 
1748*4882a593Smuzhiyun 	sw_w_table_64(hw, TABLE_STATIC_MAC, addr, data_hi, data_lo);
1749*4882a593Smuzhiyun }
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun /**
1752*4882a593Smuzhiyun  * sw_r_vlan_table - read from the VLAN table
1753*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1754*4882a593Smuzhiyun  * @addr:	The address of the table entry.
1755*4882a593Smuzhiyun  * @vid:	Buffer to store the VID.
1756*4882a593Smuzhiyun  * @fid:	Buffer to store the VID.
1757*4882a593Smuzhiyun  * @member:	Buffer to store the port membership.
1758*4882a593Smuzhiyun  *
1759*4882a593Smuzhiyun  * This function reads an entry of the VLAN table of the switch.  It calls
1760*4882a593Smuzhiyun  * sw_r_table() to get the data.
1761*4882a593Smuzhiyun  *
1762*4882a593Smuzhiyun  * Return 0 if the entry is valid; otherwise -1.
1763*4882a593Smuzhiyun  */
sw_r_vlan_table(struct ksz_hw * hw,u16 addr,u16 * vid,u8 * fid,u8 * member)1764*4882a593Smuzhiyun static int sw_r_vlan_table(struct ksz_hw *hw, u16 addr, u16 *vid, u8 *fid,
1765*4882a593Smuzhiyun 	u8 *member)
1766*4882a593Smuzhiyun {
1767*4882a593Smuzhiyun 	u32 data;
1768*4882a593Smuzhiyun 
1769*4882a593Smuzhiyun 	sw_r_table(hw, TABLE_VLAN, addr, &data);
1770*4882a593Smuzhiyun 	if (data & VLAN_TABLE_VALID) {
1771*4882a593Smuzhiyun 		*vid = (u16)(data & VLAN_TABLE_VID);
1772*4882a593Smuzhiyun 		*fid = (u8)((data & VLAN_TABLE_FID) >> VLAN_TABLE_FID_SHIFT);
1773*4882a593Smuzhiyun 		*member = (u8)((data & VLAN_TABLE_MEMBERSHIP) >>
1774*4882a593Smuzhiyun 			VLAN_TABLE_MEMBERSHIP_SHIFT);
1775*4882a593Smuzhiyun 		return 0;
1776*4882a593Smuzhiyun 	}
1777*4882a593Smuzhiyun 	return -1;
1778*4882a593Smuzhiyun }
1779*4882a593Smuzhiyun 
1780*4882a593Smuzhiyun /**
1781*4882a593Smuzhiyun  * port_r_mib_cnt - read MIB counter
1782*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1783*4882a593Smuzhiyun  * @port:	The port index.
1784*4882a593Smuzhiyun  * @addr:	The address of the counter.
1785*4882a593Smuzhiyun  * @cnt:	Buffer to store the counter.
1786*4882a593Smuzhiyun  *
1787*4882a593Smuzhiyun  * This routine reads a MIB counter of the port.
1788*4882a593Smuzhiyun  * Hardware interrupts are disabled to minimize corruption of read data.
1789*4882a593Smuzhiyun  */
port_r_mib_cnt(struct ksz_hw * hw,int port,u16 addr,u64 * cnt)1790*4882a593Smuzhiyun static void port_r_mib_cnt(struct ksz_hw *hw, int port, u16 addr, u64 *cnt)
1791*4882a593Smuzhiyun {
1792*4882a593Smuzhiyun 	u32 data;
1793*4882a593Smuzhiyun 	u16 ctrl_addr;
1794*4882a593Smuzhiyun 	uint interrupt;
1795*4882a593Smuzhiyun 	int timeout;
1796*4882a593Smuzhiyun 
1797*4882a593Smuzhiyun 	ctrl_addr = addr + PORT_COUNTER_NUM * port;
1798*4882a593Smuzhiyun 
1799*4882a593Smuzhiyun 	interrupt = hw_block_intr(hw);
1800*4882a593Smuzhiyun 
1801*4882a593Smuzhiyun 	ctrl_addr |= (((TABLE_MIB << TABLE_SEL_SHIFT) | TABLE_READ) << 8);
1802*4882a593Smuzhiyun 	writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET);
1803*4882a593Smuzhiyun 	HW_DELAY(hw, KS884X_IACR_OFFSET);
1804*4882a593Smuzhiyun 
1805*4882a593Smuzhiyun 	for (timeout = 100; timeout > 0; timeout--) {
1806*4882a593Smuzhiyun 		data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET);
1807*4882a593Smuzhiyun 
1808*4882a593Smuzhiyun 		if (data & MIB_COUNTER_VALID) {
1809*4882a593Smuzhiyun 			if (data & MIB_COUNTER_OVERFLOW)
1810*4882a593Smuzhiyun 				*cnt += MIB_COUNTER_VALUE + 1;
1811*4882a593Smuzhiyun 			*cnt += data & MIB_COUNTER_VALUE;
1812*4882a593Smuzhiyun 			break;
1813*4882a593Smuzhiyun 		}
1814*4882a593Smuzhiyun 	}
1815*4882a593Smuzhiyun 
1816*4882a593Smuzhiyun 	hw_restore_intr(hw, interrupt);
1817*4882a593Smuzhiyun }
1818*4882a593Smuzhiyun 
1819*4882a593Smuzhiyun /**
1820*4882a593Smuzhiyun  * port_r_mib_pkt - read dropped packet counts
1821*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1822*4882a593Smuzhiyun  * @port:	The port index.
1823*4882a593Smuzhiyun  * @last:	last one
1824*4882a593Smuzhiyun  * @cnt:	Buffer to store the receive and transmit dropped packet counts.
1825*4882a593Smuzhiyun  *
1826*4882a593Smuzhiyun  * This routine reads the dropped packet counts of the port.
1827*4882a593Smuzhiyun  * Hardware interrupts are disabled to minimize corruption of read data.
1828*4882a593Smuzhiyun  */
port_r_mib_pkt(struct ksz_hw * hw,int port,u32 * last,u64 * cnt)1829*4882a593Smuzhiyun static void port_r_mib_pkt(struct ksz_hw *hw, int port, u32 *last, u64 *cnt)
1830*4882a593Smuzhiyun {
1831*4882a593Smuzhiyun 	u32 cur;
1832*4882a593Smuzhiyun 	u32 data;
1833*4882a593Smuzhiyun 	u16 ctrl_addr;
1834*4882a593Smuzhiyun 	uint interrupt;
1835*4882a593Smuzhiyun 	int index;
1836*4882a593Smuzhiyun 
1837*4882a593Smuzhiyun 	index = KS_MIB_PACKET_DROPPED_RX_0 + port;
1838*4882a593Smuzhiyun 	do {
1839*4882a593Smuzhiyun 		interrupt = hw_block_intr(hw);
1840*4882a593Smuzhiyun 
1841*4882a593Smuzhiyun 		ctrl_addr = (u16) index;
1842*4882a593Smuzhiyun 		ctrl_addr |= (((TABLE_MIB << TABLE_SEL_SHIFT) | TABLE_READ)
1843*4882a593Smuzhiyun 			<< 8);
1844*4882a593Smuzhiyun 		writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET);
1845*4882a593Smuzhiyun 		HW_DELAY(hw, KS884X_IACR_OFFSET);
1846*4882a593Smuzhiyun 		data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET);
1847*4882a593Smuzhiyun 
1848*4882a593Smuzhiyun 		hw_restore_intr(hw, interrupt);
1849*4882a593Smuzhiyun 
1850*4882a593Smuzhiyun 		data &= MIB_PACKET_DROPPED;
1851*4882a593Smuzhiyun 		cur = *last;
1852*4882a593Smuzhiyun 		if (data != cur) {
1853*4882a593Smuzhiyun 			*last = data;
1854*4882a593Smuzhiyun 			if (data < cur)
1855*4882a593Smuzhiyun 				data += MIB_PACKET_DROPPED + 1;
1856*4882a593Smuzhiyun 			data -= cur;
1857*4882a593Smuzhiyun 			*cnt += data;
1858*4882a593Smuzhiyun 		}
1859*4882a593Smuzhiyun 		++last;
1860*4882a593Smuzhiyun 		++cnt;
1861*4882a593Smuzhiyun 		index -= KS_MIB_PACKET_DROPPED_TX -
1862*4882a593Smuzhiyun 			KS_MIB_PACKET_DROPPED_TX_0 + 1;
1863*4882a593Smuzhiyun 	} while (index >= KS_MIB_PACKET_DROPPED_TX_0 + port);
1864*4882a593Smuzhiyun }
1865*4882a593Smuzhiyun 
1866*4882a593Smuzhiyun /**
1867*4882a593Smuzhiyun  * port_r_cnt - read MIB counters periodically
1868*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1869*4882a593Smuzhiyun  * @port:	The port index.
1870*4882a593Smuzhiyun  *
1871*4882a593Smuzhiyun  * This routine is used to read the counters of the port periodically to avoid
1872*4882a593Smuzhiyun  * counter overflow.  The hardware should be acquired first before calling this
1873*4882a593Smuzhiyun  * routine.
1874*4882a593Smuzhiyun  *
1875*4882a593Smuzhiyun  * Return non-zero when not all counters not read.
1876*4882a593Smuzhiyun  */
port_r_cnt(struct ksz_hw * hw,int port)1877*4882a593Smuzhiyun static int port_r_cnt(struct ksz_hw *hw, int port)
1878*4882a593Smuzhiyun {
1879*4882a593Smuzhiyun 	struct ksz_port_mib *mib = &hw->port_mib[port];
1880*4882a593Smuzhiyun 
1881*4882a593Smuzhiyun 	if (mib->mib_start < PORT_COUNTER_NUM)
1882*4882a593Smuzhiyun 		while (mib->cnt_ptr < PORT_COUNTER_NUM) {
1883*4882a593Smuzhiyun 			port_r_mib_cnt(hw, port, mib->cnt_ptr,
1884*4882a593Smuzhiyun 				&mib->counter[mib->cnt_ptr]);
1885*4882a593Smuzhiyun 			++mib->cnt_ptr;
1886*4882a593Smuzhiyun 		}
1887*4882a593Smuzhiyun 	if (hw->mib_cnt > PORT_COUNTER_NUM)
1888*4882a593Smuzhiyun 		port_r_mib_pkt(hw, port, mib->dropped,
1889*4882a593Smuzhiyun 			&mib->counter[PORT_COUNTER_NUM]);
1890*4882a593Smuzhiyun 	mib->cnt_ptr = 0;
1891*4882a593Smuzhiyun 	return 0;
1892*4882a593Smuzhiyun }
1893*4882a593Smuzhiyun 
1894*4882a593Smuzhiyun /**
1895*4882a593Smuzhiyun  * port_init_cnt - initialize MIB counter values
1896*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1897*4882a593Smuzhiyun  * @port:	The port index.
1898*4882a593Smuzhiyun  *
1899*4882a593Smuzhiyun  * This routine is used to initialize all counters to zero if the hardware
1900*4882a593Smuzhiyun  * cannot do it after reset.
1901*4882a593Smuzhiyun  */
port_init_cnt(struct ksz_hw * hw,int port)1902*4882a593Smuzhiyun static void port_init_cnt(struct ksz_hw *hw, int port)
1903*4882a593Smuzhiyun {
1904*4882a593Smuzhiyun 	struct ksz_port_mib *mib = &hw->port_mib[port];
1905*4882a593Smuzhiyun 
1906*4882a593Smuzhiyun 	mib->cnt_ptr = 0;
1907*4882a593Smuzhiyun 	if (mib->mib_start < PORT_COUNTER_NUM)
1908*4882a593Smuzhiyun 		do {
1909*4882a593Smuzhiyun 			port_r_mib_cnt(hw, port, mib->cnt_ptr,
1910*4882a593Smuzhiyun 				&mib->counter[mib->cnt_ptr]);
1911*4882a593Smuzhiyun 			++mib->cnt_ptr;
1912*4882a593Smuzhiyun 		} while (mib->cnt_ptr < PORT_COUNTER_NUM);
1913*4882a593Smuzhiyun 	if (hw->mib_cnt > PORT_COUNTER_NUM)
1914*4882a593Smuzhiyun 		port_r_mib_pkt(hw, port, mib->dropped,
1915*4882a593Smuzhiyun 			&mib->counter[PORT_COUNTER_NUM]);
1916*4882a593Smuzhiyun 	memset((void *) mib->counter, 0, sizeof(u64) * TOTAL_PORT_COUNTER_NUM);
1917*4882a593Smuzhiyun 	mib->cnt_ptr = 0;
1918*4882a593Smuzhiyun }
1919*4882a593Smuzhiyun 
1920*4882a593Smuzhiyun /*
1921*4882a593Smuzhiyun  * Port functions
1922*4882a593Smuzhiyun  */
1923*4882a593Smuzhiyun 
1924*4882a593Smuzhiyun /**
1925*4882a593Smuzhiyun  * port_chk - check port register bits
1926*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1927*4882a593Smuzhiyun  * @port:	The port index.
1928*4882a593Smuzhiyun  * @offset:	The offset of the port register.
1929*4882a593Smuzhiyun  * @bits:	The data bits to check.
1930*4882a593Smuzhiyun  *
1931*4882a593Smuzhiyun  * This function checks whether the specified bits of the port register are set
1932*4882a593Smuzhiyun  * or not.
1933*4882a593Smuzhiyun  *
1934*4882a593Smuzhiyun  * Return 0 if the bits are not set.
1935*4882a593Smuzhiyun  */
port_chk(struct ksz_hw * hw,int port,int offset,u16 bits)1936*4882a593Smuzhiyun static int port_chk(struct ksz_hw *hw, int port, int offset, u16 bits)
1937*4882a593Smuzhiyun {
1938*4882a593Smuzhiyun 	u32 addr;
1939*4882a593Smuzhiyun 	u16 data;
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun 	PORT_CTRL_ADDR(port, addr);
1942*4882a593Smuzhiyun 	addr += offset;
1943*4882a593Smuzhiyun 	data = readw(hw->io + addr);
1944*4882a593Smuzhiyun 	return (data & bits) == bits;
1945*4882a593Smuzhiyun }
1946*4882a593Smuzhiyun 
1947*4882a593Smuzhiyun /**
1948*4882a593Smuzhiyun  * port_cfg - set port register bits
1949*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1950*4882a593Smuzhiyun  * @port:	The port index.
1951*4882a593Smuzhiyun  * @offset:	The offset of the port register.
1952*4882a593Smuzhiyun  * @bits:	The data bits to set.
1953*4882a593Smuzhiyun  * @set:	The flag indicating whether the bits are to be set or not.
1954*4882a593Smuzhiyun  *
1955*4882a593Smuzhiyun  * This routine sets or resets the specified bits of the port register.
1956*4882a593Smuzhiyun  */
port_cfg(struct ksz_hw * hw,int port,int offset,u16 bits,int set)1957*4882a593Smuzhiyun static void port_cfg(struct ksz_hw *hw, int port, int offset, u16 bits,
1958*4882a593Smuzhiyun 	int set)
1959*4882a593Smuzhiyun {
1960*4882a593Smuzhiyun 	u32 addr;
1961*4882a593Smuzhiyun 	u16 data;
1962*4882a593Smuzhiyun 
1963*4882a593Smuzhiyun 	PORT_CTRL_ADDR(port, addr);
1964*4882a593Smuzhiyun 	addr += offset;
1965*4882a593Smuzhiyun 	data = readw(hw->io + addr);
1966*4882a593Smuzhiyun 	if (set)
1967*4882a593Smuzhiyun 		data |= bits;
1968*4882a593Smuzhiyun 	else
1969*4882a593Smuzhiyun 		data &= ~bits;
1970*4882a593Smuzhiyun 	writew(data, hw->io + addr);
1971*4882a593Smuzhiyun }
1972*4882a593Smuzhiyun 
1973*4882a593Smuzhiyun /**
1974*4882a593Smuzhiyun  * port_chk_shift - check port bit
1975*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1976*4882a593Smuzhiyun  * @port:	The port index.
1977*4882a593Smuzhiyun  * @addr:	The offset of the register.
1978*4882a593Smuzhiyun  * @shift:	Number of bits to shift.
1979*4882a593Smuzhiyun  *
1980*4882a593Smuzhiyun  * This function checks whether the specified port is set in the register or
1981*4882a593Smuzhiyun  * not.
1982*4882a593Smuzhiyun  *
1983*4882a593Smuzhiyun  * Return 0 if the port is not set.
1984*4882a593Smuzhiyun  */
port_chk_shift(struct ksz_hw * hw,int port,u32 addr,int shift)1985*4882a593Smuzhiyun static int port_chk_shift(struct ksz_hw *hw, int port, u32 addr, int shift)
1986*4882a593Smuzhiyun {
1987*4882a593Smuzhiyun 	u16 data;
1988*4882a593Smuzhiyun 	u16 bit = 1 << port;
1989*4882a593Smuzhiyun 
1990*4882a593Smuzhiyun 	data = readw(hw->io + addr);
1991*4882a593Smuzhiyun 	data >>= shift;
1992*4882a593Smuzhiyun 	return (data & bit) == bit;
1993*4882a593Smuzhiyun }
1994*4882a593Smuzhiyun 
1995*4882a593Smuzhiyun /**
1996*4882a593Smuzhiyun  * port_cfg_shift - set port bit
1997*4882a593Smuzhiyun  * @hw: 	The hardware instance.
1998*4882a593Smuzhiyun  * @port:	The port index.
1999*4882a593Smuzhiyun  * @addr:	The offset of the register.
2000*4882a593Smuzhiyun  * @shift:	Number of bits to shift.
2001*4882a593Smuzhiyun  * @set:	The flag indicating whether the port is to be set or not.
2002*4882a593Smuzhiyun  *
2003*4882a593Smuzhiyun  * This routine sets or resets the specified port in the register.
2004*4882a593Smuzhiyun  */
port_cfg_shift(struct ksz_hw * hw,int port,u32 addr,int shift,int set)2005*4882a593Smuzhiyun static void port_cfg_shift(struct ksz_hw *hw, int port, u32 addr, int shift,
2006*4882a593Smuzhiyun 	int set)
2007*4882a593Smuzhiyun {
2008*4882a593Smuzhiyun 	u16 data;
2009*4882a593Smuzhiyun 	u16 bits = 1 << port;
2010*4882a593Smuzhiyun 
2011*4882a593Smuzhiyun 	data = readw(hw->io + addr);
2012*4882a593Smuzhiyun 	bits <<= shift;
2013*4882a593Smuzhiyun 	if (set)
2014*4882a593Smuzhiyun 		data |= bits;
2015*4882a593Smuzhiyun 	else
2016*4882a593Smuzhiyun 		data &= ~bits;
2017*4882a593Smuzhiyun 	writew(data, hw->io + addr);
2018*4882a593Smuzhiyun }
2019*4882a593Smuzhiyun 
2020*4882a593Smuzhiyun /**
2021*4882a593Smuzhiyun  * port_r8 - read byte from port register
2022*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2023*4882a593Smuzhiyun  * @port:	The port index.
2024*4882a593Smuzhiyun  * @offset:	The offset of the port register.
2025*4882a593Smuzhiyun  * @data:	Buffer to store the data.
2026*4882a593Smuzhiyun  *
2027*4882a593Smuzhiyun  * This routine reads a byte from the port register.
2028*4882a593Smuzhiyun  */
port_r8(struct ksz_hw * hw,int port,int offset,u8 * data)2029*4882a593Smuzhiyun static void port_r8(struct ksz_hw *hw, int port, int offset, u8 *data)
2030*4882a593Smuzhiyun {
2031*4882a593Smuzhiyun 	u32 addr;
2032*4882a593Smuzhiyun 
2033*4882a593Smuzhiyun 	PORT_CTRL_ADDR(port, addr);
2034*4882a593Smuzhiyun 	addr += offset;
2035*4882a593Smuzhiyun 	*data = readb(hw->io + addr);
2036*4882a593Smuzhiyun }
2037*4882a593Smuzhiyun 
2038*4882a593Smuzhiyun /**
2039*4882a593Smuzhiyun  * port_r16 - read word from port register.
2040*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2041*4882a593Smuzhiyun  * @port:	The port index.
2042*4882a593Smuzhiyun  * @offset:	The offset of the port register.
2043*4882a593Smuzhiyun  * @data:	Buffer to store the data.
2044*4882a593Smuzhiyun  *
2045*4882a593Smuzhiyun  * This routine reads a word from the port register.
2046*4882a593Smuzhiyun  */
port_r16(struct ksz_hw * hw,int port,int offset,u16 * data)2047*4882a593Smuzhiyun static void port_r16(struct ksz_hw *hw, int port, int offset, u16 *data)
2048*4882a593Smuzhiyun {
2049*4882a593Smuzhiyun 	u32 addr;
2050*4882a593Smuzhiyun 
2051*4882a593Smuzhiyun 	PORT_CTRL_ADDR(port, addr);
2052*4882a593Smuzhiyun 	addr += offset;
2053*4882a593Smuzhiyun 	*data = readw(hw->io + addr);
2054*4882a593Smuzhiyun }
2055*4882a593Smuzhiyun 
2056*4882a593Smuzhiyun /**
2057*4882a593Smuzhiyun  * port_w16 - write word to port register.
2058*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2059*4882a593Smuzhiyun  * @port:	The port index.
2060*4882a593Smuzhiyun  * @offset:	The offset of the port register.
2061*4882a593Smuzhiyun  * @data:	Data to write.
2062*4882a593Smuzhiyun  *
2063*4882a593Smuzhiyun  * This routine writes a word to the port register.
2064*4882a593Smuzhiyun  */
port_w16(struct ksz_hw * hw,int port,int offset,u16 data)2065*4882a593Smuzhiyun static void port_w16(struct ksz_hw *hw, int port, int offset, u16 data)
2066*4882a593Smuzhiyun {
2067*4882a593Smuzhiyun 	u32 addr;
2068*4882a593Smuzhiyun 
2069*4882a593Smuzhiyun 	PORT_CTRL_ADDR(port, addr);
2070*4882a593Smuzhiyun 	addr += offset;
2071*4882a593Smuzhiyun 	writew(data, hw->io + addr);
2072*4882a593Smuzhiyun }
2073*4882a593Smuzhiyun 
2074*4882a593Smuzhiyun /**
2075*4882a593Smuzhiyun  * sw_chk - check switch register bits
2076*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2077*4882a593Smuzhiyun  * @addr:	The address of the switch register.
2078*4882a593Smuzhiyun  * @bits:	The data bits to check.
2079*4882a593Smuzhiyun  *
2080*4882a593Smuzhiyun  * This function checks whether the specified bits of the switch register are
2081*4882a593Smuzhiyun  * set or not.
2082*4882a593Smuzhiyun  *
2083*4882a593Smuzhiyun  * Return 0 if the bits are not set.
2084*4882a593Smuzhiyun  */
sw_chk(struct ksz_hw * hw,u32 addr,u16 bits)2085*4882a593Smuzhiyun static int sw_chk(struct ksz_hw *hw, u32 addr, u16 bits)
2086*4882a593Smuzhiyun {
2087*4882a593Smuzhiyun 	u16 data;
2088*4882a593Smuzhiyun 
2089*4882a593Smuzhiyun 	data = readw(hw->io + addr);
2090*4882a593Smuzhiyun 	return (data & bits) == bits;
2091*4882a593Smuzhiyun }
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun /**
2094*4882a593Smuzhiyun  * sw_cfg - set switch register bits
2095*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2096*4882a593Smuzhiyun  * @addr:	The address of the switch register.
2097*4882a593Smuzhiyun  * @bits:	The data bits to set.
2098*4882a593Smuzhiyun  * @set:	The flag indicating whether the bits are to be set or not.
2099*4882a593Smuzhiyun  *
2100*4882a593Smuzhiyun  * This function sets or resets the specified bits of the switch register.
2101*4882a593Smuzhiyun  */
sw_cfg(struct ksz_hw * hw,u32 addr,u16 bits,int set)2102*4882a593Smuzhiyun static void sw_cfg(struct ksz_hw *hw, u32 addr, u16 bits, int set)
2103*4882a593Smuzhiyun {
2104*4882a593Smuzhiyun 	u16 data;
2105*4882a593Smuzhiyun 
2106*4882a593Smuzhiyun 	data = readw(hw->io + addr);
2107*4882a593Smuzhiyun 	if (set)
2108*4882a593Smuzhiyun 		data |= bits;
2109*4882a593Smuzhiyun 	else
2110*4882a593Smuzhiyun 		data &= ~bits;
2111*4882a593Smuzhiyun 	writew(data, hw->io + addr);
2112*4882a593Smuzhiyun }
2113*4882a593Smuzhiyun 
2114*4882a593Smuzhiyun /* Bandwidth */
2115*4882a593Smuzhiyun 
port_cfg_broad_storm(struct ksz_hw * hw,int p,int set)2116*4882a593Smuzhiyun static inline void port_cfg_broad_storm(struct ksz_hw *hw, int p, int set)
2117*4882a593Smuzhiyun {
2118*4882a593Smuzhiyun 	port_cfg(hw, p,
2119*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_BROADCAST_STORM, set);
2120*4882a593Smuzhiyun }
2121*4882a593Smuzhiyun 
port_chk_broad_storm(struct ksz_hw * hw,int p)2122*4882a593Smuzhiyun static inline int port_chk_broad_storm(struct ksz_hw *hw, int p)
2123*4882a593Smuzhiyun {
2124*4882a593Smuzhiyun 	return port_chk(hw, p,
2125*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_BROADCAST_STORM);
2126*4882a593Smuzhiyun }
2127*4882a593Smuzhiyun 
2128*4882a593Smuzhiyun /* Driver set switch broadcast storm protection at 10% rate. */
2129*4882a593Smuzhiyun #define BROADCAST_STORM_PROTECTION_RATE	10
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun /* 148,800 frames * 67 ms / 100 */
2132*4882a593Smuzhiyun #define BROADCAST_STORM_VALUE		9969
2133*4882a593Smuzhiyun 
2134*4882a593Smuzhiyun /**
2135*4882a593Smuzhiyun  * sw_cfg_broad_storm - configure broadcast storm threshold
2136*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2137*4882a593Smuzhiyun  * @percent:	Broadcast storm threshold in percent of transmit rate.
2138*4882a593Smuzhiyun  *
2139*4882a593Smuzhiyun  * This routine configures the broadcast storm threshold of the switch.
2140*4882a593Smuzhiyun  */
sw_cfg_broad_storm(struct ksz_hw * hw,u8 percent)2141*4882a593Smuzhiyun static void sw_cfg_broad_storm(struct ksz_hw *hw, u8 percent)
2142*4882a593Smuzhiyun {
2143*4882a593Smuzhiyun 	u16 data;
2144*4882a593Smuzhiyun 	u32 value = ((u32) BROADCAST_STORM_VALUE * (u32) percent / 100);
2145*4882a593Smuzhiyun 
2146*4882a593Smuzhiyun 	if (value > BROADCAST_STORM_RATE)
2147*4882a593Smuzhiyun 		value = BROADCAST_STORM_RATE;
2148*4882a593Smuzhiyun 
2149*4882a593Smuzhiyun 	data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET);
2150*4882a593Smuzhiyun 	data &= ~(BROADCAST_STORM_RATE_LO | BROADCAST_STORM_RATE_HI);
2151*4882a593Smuzhiyun 	data |= ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8);
2152*4882a593Smuzhiyun 	writew(data, hw->io + KS8842_SWITCH_CTRL_3_OFFSET);
2153*4882a593Smuzhiyun }
2154*4882a593Smuzhiyun 
2155*4882a593Smuzhiyun /**
2156*4882a593Smuzhiyun  * sw_get_board_storm - get broadcast storm threshold
2157*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2158*4882a593Smuzhiyun  * @percent:	Buffer to store the broadcast storm threshold percentage.
2159*4882a593Smuzhiyun  *
2160*4882a593Smuzhiyun  * This routine retrieves the broadcast storm threshold of the switch.
2161*4882a593Smuzhiyun  */
sw_get_broad_storm(struct ksz_hw * hw,u8 * percent)2162*4882a593Smuzhiyun static void sw_get_broad_storm(struct ksz_hw *hw, u8 *percent)
2163*4882a593Smuzhiyun {
2164*4882a593Smuzhiyun 	int num;
2165*4882a593Smuzhiyun 	u16 data;
2166*4882a593Smuzhiyun 
2167*4882a593Smuzhiyun 	data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET);
2168*4882a593Smuzhiyun 	num = (data & BROADCAST_STORM_RATE_HI);
2169*4882a593Smuzhiyun 	num <<= 8;
2170*4882a593Smuzhiyun 	num |= (data & BROADCAST_STORM_RATE_LO) >> 8;
2171*4882a593Smuzhiyun 	num = DIV_ROUND_CLOSEST(num * 100, BROADCAST_STORM_VALUE);
2172*4882a593Smuzhiyun 	*percent = (u8) num;
2173*4882a593Smuzhiyun }
2174*4882a593Smuzhiyun 
2175*4882a593Smuzhiyun /**
2176*4882a593Smuzhiyun  * sw_dis_broad_storm - disable broadstorm
2177*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2178*4882a593Smuzhiyun  * @port:	The port index.
2179*4882a593Smuzhiyun  *
2180*4882a593Smuzhiyun  * This routine disables the broadcast storm limit function of the switch.
2181*4882a593Smuzhiyun  */
sw_dis_broad_storm(struct ksz_hw * hw,int port)2182*4882a593Smuzhiyun static void sw_dis_broad_storm(struct ksz_hw *hw, int port)
2183*4882a593Smuzhiyun {
2184*4882a593Smuzhiyun 	port_cfg_broad_storm(hw, port, 0);
2185*4882a593Smuzhiyun }
2186*4882a593Smuzhiyun 
2187*4882a593Smuzhiyun /**
2188*4882a593Smuzhiyun  * sw_ena_broad_storm - enable broadcast storm
2189*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2190*4882a593Smuzhiyun  * @port:	The port index.
2191*4882a593Smuzhiyun  *
2192*4882a593Smuzhiyun  * This routine enables the broadcast storm limit function of the switch.
2193*4882a593Smuzhiyun  */
sw_ena_broad_storm(struct ksz_hw * hw,int port)2194*4882a593Smuzhiyun static void sw_ena_broad_storm(struct ksz_hw *hw, int port)
2195*4882a593Smuzhiyun {
2196*4882a593Smuzhiyun 	sw_cfg_broad_storm(hw, hw->ksz_switch->broad_per);
2197*4882a593Smuzhiyun 	port_cfg_broad_storm(hw, port, 1);
2198*4882a593Smuzhiyun }
2199*4882a593Smuzhiyun 
2200*4882a593Smuzhiyun /**
2201*4882a593Smuzhiyun  * sw_init_broad_storm - initialize broadcast storm
2202*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2203*4882a593Smuzhiyun  *
2204*4882a593Smuzhiyun  * This routine initializes the broadcast storm limit function of the switch.
2205*4882a593Smuzhiyun  */
sw_init_broad_storm(struct ksz_hw * hw)2206*4882a593Smuzhiyun static void sw_init_broad_storm(struct ksz_hw *hw)
2207*4882a593Smuzhiyun {
2208*4882a593Smuzhiyun 	int port;
2209*4882a593Smuzhiyun 
2210*4882a593Smuzhiyun 	hw->ksz_switch->broad_per = 1;
2211*4882a593Smuzhiyun 	sw_cfg_broad_storm(hw, hw->ksz_switch->broad_per);
2212*4882a593Smuzhiyun 	for (port = 0; port < TOTAL_PORT_NUM; port++)
2213*4882a593Smuzhiyun 		sw_dis_broad_storm(hw, port);
2214*4882a593Smuzhiyun 	sw_cfg(hw, KS8842_SWITCH_CTRL_2_OFFSET, MULTICAST_STORM_DISABLE, 1);
2215*4882a593Smuzhiyun }
2216*4882a593Smuzhiyun 
2217*4882a593Smuzhiyun /**
2218*4882a593Smuzhiyun  * hw_cfg_broad_storm - configure broadcast storm
2219*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2220*4882a593Smuzhiyun  * @percent:	Broadcast storm threshold in percent of transmit rate.
2221*4882a593Smuzhiyun  *
2222*4882a593Smuzhiyun  * This routine configures the broadcast storm threshold of the switch.
2223*4882a593Smuzhiyun  * It is called by user functions.  The hardware should be acquired first.
2224*4882a593Smuzhiyun  */
hw_cfg_broad_storm(struct ksz_hw * hw,u8 percent)2225*4882a593Smuzhiyun static void hw_cfg_broad_storm(struct ksz_hw *hw, u8 percent)
2226*4882a593Smuzhiyun {
2227*4882a593Smuzhiyun 	if (percent > 100)
2228*4882a593Smuzhiyun 		percent = 100;
2229*4882a593Smuzhiyun 
2230*4882a593Smuzhiyun 	sw_cfg_broad_storm(hw, percent);
2231*4882a593Smuzhiyun 	sw_get_broad_storm(hw, &percent);
2232*4882a593Smuzhiyun 	hw->ksz_switch->broad_per = percent;
2233*4882a593Smuzhiyun }
2234*4882a593Smuzhiyun 
2235*4882a593Smuzhiyun /**
2236*4882a593Smuzhiyun  * sw_dis_prio_rate - disable switch priority rate
2237*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2238*4882a593Smuzhiyun  * @port:	The port index.
2239*4882a593Smuzhiyun  *
2240*4882a593Smuzhiyun  * This routine disables the priority rate function of the switch.
2241*4882a593Smuzhiyun  */
sw_dis_prio_rate(struct ksz_hw * hw,int port)2242*4882a593Smuzhiyun static void sw_dis_prio_rate(struct ksz_hw *hw, int port)
2243*4882a593Smuzhiyun {
2244*4882a593Smuzhiyun 	u32 addr;
2245*4882a593Smuzhiyun 
2246*4882a593Smuzhiyun 	PORT_CTRL_ADDR(port, addr);
2247*4882a593Smuzhiyun 	addr += KS8842_PORT_IN_RATE_OFFSET;
2248*4882a593Smuzhiyun 	writel(0, hw->io + addr);
2249*4882a593Smuzhiyun }
2250*4882a593Smuzhiyun 
2251*4882a593Smuzhiyun /**
2252*4882a593Smuzhiyun  * sw_init_prio_rate - initialize switch prioirty rate
2253*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2254*4882a593Smuzhiyun  *
2255*4882a593Smuzhiyun  * This routine initializes the priority rate function of the switch.
2256*4882a593Smuzhiyun  */
sw_init_prio_rate(struct ksz_hw * hw)2257*4882a593Smuzhiyun static void sw_init_prio_rate(struct ksz_hw *hw)
2258*4882a593Smuzhiyun {
2259*4882a593Smuzhiyun 	int port;
2260*4882a593Smuzhiyun 	int prio;
2261*4882a593Smuzhiyun 	struct ksz_switch *sw = hw->ksz_switch;
2262*4882a593Smuzhiyun 
2263*4882a593Smuzhiyun 	for (port = 0; port < TOTAL_PORT_NUM; port++) {
2264*4882a593Smuzhiyun 		for (prio = 0; prio < PRIO_QUEUES; prio++) {
2265*4882a593Smuzhiyun 			sw->port_cfg[port].rx_rate[prio] =
2266*4882a593Smuzhiyun 			sw->port_cfg[port].tx_rate[prio] = 0;
2267*4882a593Smuzhiyun 		}
2268*4882a593Smuzhiyun 		sw_dis_prio_rate(hw, port);
2269*4882a593Smuzhiyun 	}
2270*4882a593Smuzhiyun }
2271*4882a593Smuzhiyun 
2272*4882a593Smuzhiyun /* Communication */
2273*4882a593Smuzhiyun 
port_cfg_back_pressure(struct ksz_hw * hw,int p,int set)2274*4882a593Smuzhiyun static inline void port_cfg_back_pressure(struct ksz_hw *hw, int p, int set)
2275*4882a593Smuzhiyun {
2276*4882a593Smuzhiyun 	port_cfg(hw, p,
2277*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_BACK_PRESSURE, set);
2278*4882a593Smuzhiyun }
2279*4882a593Smuzhiyun 
port_cfg_force_flow_ctrl(struct ksz_hw * hw,int p,int set)2280*4882a593Smuzhiyun static inline void port_cfg_force_flow_ctrl(struct ksz_hw *hw, int p, int set)
2281*4882a593Smuzhiyun {
2282*4882a593Smuzhiyun 	port_cfg(hw, p,
2283*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_FORCE_FLOW_CTRL, set);
2284*4882a593Smuzhiyun }
2285*4882a593Smuzhiyun 
port_chk_back_pressure(struct ksz_hw * hw,int p)2286*4882a593Smuzhiyun static inline int port_chk_back_pressure(struct ksz_hw *hw, int p)
2287*4882a593Smuzhiyun {
2288*4882a593Smuzhiyun 	return port_chk(hw, p,
2289*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_BACK_PRESSURE);
2290*4882a593Smuzhiyun }
2291*4882a593Smuzhiyun 
port_chk_force_flow_ctrl(struct ksz_hw * hw,int p)2292*4882a593Smuzhiyun static inline int port_chk_force_flow_ctrl(struct ksz_hw *hw, int p)
2293*4882a593Smuzhiyun {
2294*4882a593Smuzhiyun 	return port_chk(hw, p,
2295*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_FORCE_FLOW_CTRL);
2296*4882a593Smuzhiyun }
2297*4882a593Smuzhiyun 
2298*4882a593Smuzhiyun /* Spanning Tree */
2299*4882a593Smuzhiyun 
port_cfg_rx(struct ksz_hw * hw,int p,int set)2300*4882a593Smuzhiyun static inline void port_cfg_rx(struct ksz_hw *hw, int p, int set)
2301*4882a593Smuzhiyun {
2302*4882a593Smuzhiyun 	port_cfg(hw, p,
2303*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_RX_ENABLE, set);
2304*4882a593Smuzhiyun }
2305*4882a593Smuzhiyun 
port_cfg_tx(struct ksz_hw * hw,int p,int set)2306*4882a593Smuzhiyun static inline void port_cfg_tx(struct ksz_hw *hw, int p, int set)
2307*4882a593Smuzhiyun {
2308*4882a593Smuzhiyun 	port_cfg(hw, p,
2309*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_TX_ENABLE, set);
2310*4882a593Smuzhiyun }
2311*4882a593Smuzhiyun 
sw_cfg_fast_aging(struct ksz_hw * hw,int set)2312*4882a593Smuzhiyun static inline void sw_cfg_fast_aging(struct ksz_hw *hw, int set)
2313*4882a593Smuzhiyun {
2314*4882a593Smuzhiyun 	sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, SWITCH_FAST_AGING, set);
2315*4882a593Smuzhiyun }
2316*4882a593Smuzhiyun 
sw_flush_dyn_mac_table(struct ksz_hw * hw)2317*4882a593Smuzhiyun static inline void sw_flush_dyn_mac_table(struct ksz_hw *hw)
2318*4882a593Smuzhiyun {
2319*4882a593Smuzhiyun 	if (!(hw->overrides & FAST_AGING)) {
2320*4882a593Smuzhiyun 		sw_cfg_fast_aging(hw, 1);
2321*4882a593Smuzhiyun 		mdelay(1);
2322*4882a593Smuzhiyun 		sw_cfg_fast_aging(hw, 0);
2323*4882a593Smuzhiyun 	}
2324*4882a593Smuzhiyun }
2325*4882a593Smuzhiyun 
2326*4882a593Smuzhiyun /* VLAN */
2327*4882a593Smuzhiyun 
port_cfg_ins_tag(struct ksz_hw * hw,int p,int insert)2328*4882a593Smuzhiyun static inline void port_cfg_ins_tag(struct ksz_hw *hw, int p, int insert)
2329*4882a593Smuzhiyun {
2330*4882a593Smuzhiyun 	port_cfg(hw, p,
2331*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_INSERT_TAG, insert);
2332*4882a593Smuzhiyun }
2333*4882a593Smuzhiyun 
port_cfg_rmv_tag(struct ksz_hw * hw,int p,int remove)2334*4882a593Smuzhiyun static inline void port_cfg_rmv_tag(struct ksz_hw *hw, int p, int remove)
2335*4882a593Smuzhiyun {
2336*4882a593Smuzhiyun 	port_cfg(hw, p,
2337*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_REMOVE_TAG, remove);
2338*4882a593Smuzhiyun }
2339*4882a593Smuzhiyun 
port_chk_ins_tag(struct ksz_hw * hw,int p)2340*4882a593Smuzhiyun static inline int port_chk_ins_tag(struct ksz_hw *hw, int p)
2341*4882a593Smuzhiyun {
2342*4882a593Smuzhiyun 	return port_chk(hw, p,
2343*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_INSERT_TAG);
2344*4882a593Smuzhiyun }
2345*4882a593Smuzhiyun 
port_chk_rmv_tag(struct ksz_hw * hw,int p)2346*4882a593Smuzhiyun static inline int port_chk_rmv_tag(struct ksz_hw *hw, int p)
2347*4882a593Smuzhiyun {
2348*4882a593Smuzhiyun 	return port_chk(hw, p,
2349*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_REMOVE_TAG);
2350*4882a593Smuzhiyun }
2351*4882a593Smuzhiyun 
port_cfg_dis_non_vid(struct ksz_hw * hw,int p,int set)2352*4882a593Smuzhiyun static inline void port_cfg_dis_non_vid(struct ksz_hw *hw, int p, int set)
2353*4882a593Smuzhiyun {
2354*4882a593Smuzhiyun 	port_cfg(hw, p,
2355*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_DISCARD_NON_VID, set);
2356*4882a593Smuzhiyun }
2357*4882a593Smuzhiyun 
port_cfg_in_filter(struct ksz_hw * hw,int p,int set)2358*4882a593Smuzhiyun static inline void port_cfg_in_filter(struct ksz_hw *hw, int p, int set)
2359*4882a593Smuzhiyun {
2360*4882a593Smuzhiyun 	port_cfg(hw, p,
2361*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_INGRESS_VLAN_FILTER, set);
2362*4882a593Smuzhiyun }
2363*4882a593Smuzhiyun 
port_chk_dis_non_vid(struct ksz_hw * hw,int p)2364*4882a593Smuzhiyun static inline int port_chk_dis_non_vid(struct ksz_hw *hw, int p)
2365*4882a593Smuzhiyun {
2366*4882a593Smuzhiyun 	return port_chk(hw, p,
2367*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_DISCARD_NON_VID);
2368*4882a593Smuzhiyun }
2369*4882a593Smuzhiyun 
port_chk_in_filter(struct ksz_hw * hw,int p)2370*4882a593Smuzhiyun static inline int port_chk_in_filter(struct ksz_hw *hw, int p)
2371*4882a593Smuzhiyun {
2372*4882a593Smuzhiyun 	return port_chk(hw, p,
2373*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_INGRESS_VLAN_FILTER);
2374*4882a593Smuzhiyun }
2375*4882a593Smuzhiyun 
2376*4882a593Smuzhiyun /* Mirroring */
2377*4882a593Smuzhiyun 
port_cfg_mirror_sniffer(struct ksz_hw * hw,int p,int set)2378*4882a593Smuzhiyun static inline void port_cfg_mirror_sniffer(struct ksz_hw *hw, int p, int set)
2379*4882a593Smuzhiyun {
2380*4882a593Smuzhiyun 	port_cfg(hw, p,
2381*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_SNIFFER, set);
2382*4882a593Smuzhiyun }
2383*4882a593Smuzhiyun 
port_cfg_mirror_rx(struct ksz_hw * hw,int p,int set)2384*4882a593Smuzhiyun static inline void port_cfg_mirror_rx(struct ksz_hw *hw, int p, int set)
2385*4882a593Smuzhiyun {
2386*4882a593Smuzhiyun 	port_cfg(hw, p,
2387*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_RX, set);
2388*4882a593Smuzhiyun }
2389*4882a593Smuzhiyun 
port_cfg_mirror_tx(struct ksz_hw * hw,int p,int set)2390*4882a593Smuzhiyun static inline void port_cfg_mirror_tx(struct ksz_hw *hw, int p, int set)
2391*4882a593Smuzhiyun {
2392*4882a593Smuzhiyun 	port_cfg(hw, p,
2393*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_TX, set);
2394*4882a593Smuzhiyun }
2395*4882a593Smuzhiyun 
sw_cfg_mirror_rx_tx(struct ksz_hw * hw,int set)2396*4882a593Smuzhiyun static inline void sw_cfg_mirror_rx_tx(struct ksz_hw *hw, int set)
2397*4882a593Smuzhiyun {
2398*4882a593Smuzhiyun 	sw_cfg(hw, KS8842_SWITCH_CTRL_2_OFFSET, SWITCH_MIRROR_RX_TX, set);
2399*4882a593Smuzhiyun }
2400*4882a593Smuzhiyun 
sw_init_mirror(struct ksz_hw * hw)2401*4882a593Smuzhiyun static void sw_init_mirror(struct ksz_hw *hw)
2402*4882a593Smuzhiyun {
2403*4882a593Smuzhiyun 	int port;
2404*4882a593Smuzhiyun 
2405*4882a593Smuzhiyun 	for (port = 0; port < TOTAL_PORT_NUM; port++) {
2406*4882a593Smuzhiyun 		port_cfg_mirror_sniffer(hw, port, 0);
2407*4882a593Smuzhiyun 		port_cfg_mirror_rx(hw, port, 0);
2408*4882a593Smuzhiyun 		port_cfg_mirror_tx(hw, port, 0);
2409*4882a593Smuzhiyun 	}
2410*4882a593Smuzhiyun 	sw_cfg_mirror_rx_tx(hw, 0);
2411*4882a593Smuzhiyun }
2412*4882a593Smuzhiyun 
sw_cfg_unk_def_deliver(struct ksz_hw * hw,int set)2413*4882a593Smuzhiyun static inline void sw_cfg_unk_def_deliver(struct ksz_hw *hw, int set)
2414*4882a593Smuzhiyun {
2415*4882a593Smuzhiyun 	sw_cfg(hw, KS8842_SWITCH_CTRL_7_OFFSET,
2416*4882a593Smuzhiyun 		SWITCH_UNK_DEF_PORT_ENABLE, set);
2417*4882a593Smuzhiyun }
2418*4882a593Smuzhiyun 
sw_cfg_chk_unk_def_deliver(struct ksz_hw * hw)2419*4882a593Smuzhiyun static inline int sw_cfg_chk_unk_def_deliver(struct ksz_hw *hw)
2420*4882a593Smuzhiyun {
2421*4882a593Smuzhiyun 	return sw_chk(hw, KS8842_SWITCH_CTRL_7_OFFSET,
2422*4882a593Smuzhiyun 		SWITCH_UNK_DEF_PORT_ENABLE);
2423*4882a593Smuzhiyun }
2424*4882a593Smuzhiyun 
sw_cfg_unk_def_port(struct ksz_hw * hw,int port,int set)2425*4882a593Smuzhiyun static inline void sw_cfg_unk_def_port(struct ksz_hw *hw, int port, int set)
2426*4882a593Smuzhiyun {
2427*4882a593Smuzhiyun 	port_cfg_shift(hw, port, KS8842_SWITCH_CTRL_7_OFFSET, 0, set);
2428*4882a593Smuzhiyun }
2429*4882a593Smuzhiyun 
sw_chk_unk_def_port(struct ksz_hw * hw,int port)2430*4882a593Smuzhiyun static inline int sw_chk_unk_def_port(struct ksz_hw *hw, int port)
2431*4882a593Smuzhiyun {
2432*4882a593Smuzhiyun 	return port_chk_shift(hw, port, KS8842_SWITCH_CTRL_7_OFFSET, 0);
2433*4882a593Smuzhiyun }
2434*4882a593Smuzhiyun 
2435*4882a593Smuzhiyun /* Priority */
2436*4882a593Smuzhiyun 
port_cfg_diffserv(struct ksz_hw * hw,int p,int set)2437*4882a593Smuzhiyun static inline void port_cfg_diffserv(struct ksz_hw *hw, int p, int set)
2438*4882a593Smuzhiyun {
2439*4882a593Smuzhiyun 	port_cfg(hw, p,
2440*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_DIFFSERV_ENABLE, set);
2441*4882a593Smuzhiyun }
2442*4882a593Smuzhiyun 
port_cfg_802_1p(struct ksz_hw * hw,int p,int set)2443*4882a593Smuzhiyun static inline void port_cfg_802_1p(struct ksz_hw *hw, int p, int set)
2444*4882a593Smuzhiyun {
2445*4882a593Smuzhiyun 	port_cfg(hw, p,
2446*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_802_1P_ENABLE, set);
2447*4882a593Smuzhiyun }
2448*4882a593Smuzhiyun 
port_cfg_replace_vid(struct ksz_hw * hw,int p,int set)2449*4882a593Smuzhiyun static inline void port_cfg_replace_vid(struct ksz_hw *hw, int p, int set)
2450*4882a593Smuzhiyun {
2451*4882a593Smuzhiyun 	port_cfg(hw, p,
2452*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_USER_PRIORITY_CEILING, set);
2453*4882a593Smuzhiyun }
2454*4882a593Smuzhiyun 
port_cfg_prio(struct ksz_hw * hw,int p,int set)2455*4882a593Smuzhiyun static inline void port_cfg_prio(struct ksz_hw *hw, int p, int set)
2456*4882a593Smuzhiyun {
2457*4882a593Smuzhiyun 	port_cfg(hw, p,
2458*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_PRIO_QUEUE_ENABLE, set);
2459*4882a593Smuzhiyun }
2460*4882a593Smuzhiyun 
port_chk_diffserv(struct ksz_hw * hw,int p)2461*4882a593Smuzhiyun static inline int port_chk_diffserv(struct ksz_hw *hw, int p)
2462*4882a593Smuzhiyun {
2463*4882a593Smuzhiyun 	return port_chk(hw, p,
2464*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_DIFFSERV_ENABLE);
2465*4882a593Smuzhiyun }
2466*4882a593Smuzhiyun 
port_chk_802_1p(struct ksz_hw * hw,int p)2467*4882a593Smuzhiyun static inline int port_chk_802_1p(struct ksz_hw *hw, int p)
2468*4882a593Smuzhiyun {
2469*4882a593Smuzhiyun 	return port_chk(hw, p,
2470*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_802_1P_ENABLE);
2471*4882a593Smuzhiyun }
2472*4882a593Smuzhiyun 
port_chk_replace_vid(struct ksz_hw * hw,int p)2473*4882a593Smuzhiyun static inline int port_chk_replace_vid(struct ksz_hw *hw, int p)
2474*4882a593Smuzhiyun {
2475*4882a593Smuzhiyun 	return port_chk(hw, p,
2476*4882a593Smuzhiyun 		KS8842_PORT_CTRL_2_OFFSET, PORT_USER_PRIORITY_CEILING);
2477*4882a593Smuzhiyun }
2478*4882a593Smuzhiyun 
port_chk_prio(struct ksz_hw * hw,int p)2479*4882a593Smuzhiyun static inline int port_chk_prio(struct ksz_hw *hw, int p)
2480*4882a593Smuzhiyun {
2481*4882a593Smuzhiyun 	return port_chk(hw, p,
2482*4882a593Smuzhiyun 		KS8842_PORT_CTRL_1_OFFSET, PORT_PRIO_QUEUE_ENABLE);
2483*4882a593Smuzhiyun }
2484*4882a593Smuzhiyun 
2485*4882a593Smuzhiyun /**
2486*4882a593Smuzhiyun  * sw_dis_diffserv - disable switch DiffServ priority
2487*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2488*4882a593Smuzhiyun  * @port:	The port index.
2489*4882a593Smuzhiyun  *
2490*4882a593Smuzhiyun  * This routine disables the DiffServ priority function of the switch.
2491*4882a593Smuzhiyun  */
sw_dis_diffserv(struct ksz_hw * hw,int port)2492*4882a593Smuzhiyun static void sw_dis_diffserv(struct ksz_hw *hw, int port)
2493*4882a593Smuzhiyun {
2494*4882a593Smuzhiyun 	port_cfg_diffserv(hw, port, 0);
2495*4882a593Smuzhiyun }
2496*4882a593Smuzhiyun 
2497*4882a593Smuzhiyun /**
2498*4882a593Smuzhiyun  * sw_dis_802_1p - disable switch 802.1p priority
2499*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2500*4882a593Smuzhiyun  * @port:	The port index.
2501*4882a593Smuzhiyun  *
2502*4882a593Smuzhiyun  * This routine disables the 802.1p priority function of the switch.
2503*4882a593Smuzhiyun  */
sw_dis_802_1p(struct ksz_hw * hw,int port)2504*4882a593Smuzhiyun static void sw_dis_802_1p(struct ksz_hw *hw, int port)
2505*4882a593Smuzhiyun {
2506*4882a593Smuzhiyun 	port_cfg_802_1p(hw, port, 0);
2507*4882a593Smuzhiyun }
2508*4882a593Smuzhiyun 
2509*4882a593Smuzhiyun /**
2510*4882a593Smuzhiyun  * sw_cfg_replace_null_vid -
2511*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2512*4882a593Smuzhiyun  * @set:	The flag to disable or enable.
2513*4882a593Smuzhiyun  *
2514*4882a593Smuzhiyun  */
sw_cfg_replace_null_vid(struct ksz_hw * hw,int set)2515*4882a593Smuzhiyun static void sw_cfg_replace_null_vid(struct ksz_hw *hw, int set)
2516*4882a593Smuzhiyun {
2517*4882a593Smuzhiyun 	sw_cfg(hw, KS8842_SWITCH_CTRL_3_OFFSET, SWITCH_REPLACE_NULL_VID, set);
2518*4882a593Smuzhiyun }
2519*4882a593Smuzhiyun 
2520*4882a593Smuzhiyun /**
2521*4882a593Smuzhiyun  * sw_cfg_replace_vid - enable switch 802.10 priority re-mapping
2522*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2523*4882a593Smuzhiyun  * @port:	The port index.
2524*4882a593Smuzhiyun  * @set:	The flag to disable or enable.
2525*4882a593Smuzhiyun  *
2526*4882a593Smuzhiyun  * This routine enables the 802.1p priority re-mapping function of the switch.
2527*4882a593Smuzhiyun  * That allows 802.1p priority field to be replaced with the port's default
2528*4882a593Smuzhiyun  * tag's priority value if the ingress packet's 802.1p priority has a higher
2529*4882a593Smuzhiyun  * priority than port's default tag's priority.
2530*4882a593Smuzhiyun  */
sw_cfg_replace_vid(struct ksz_hw * hw,int port,int set)2531*4882a593Smuzhiyun static void sw_cfg_replace_vid(struct ksz_hw *hw, int port, int set)
2532*4882a593Smuzhiyun {
2533*4882a593Smuzhiyun 	port_cfg_replace_vid(hw, port, set);
2534*4882a593Smuzhiyun }
2535*4882a593Smuzhiyun 
2536*4882a593Smuzhiyun /**
2537*4882a593Smuzhiyun  * sw_cfg_port_based - configure switch port based priority
2538*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2539*4882a593Smuzhiyun  * @port:	The port index.
2540*4882a593Smuzhiyun  * @prio:	The priority to set.
2541*4882a593Smuzhiyun  *
2542*4882a593Smuzhiyun  * This routine configures the port based priority of the switch.
2543*4882a593Smuzhiyun  */
sw_cfg_port_based(struct ksz_hw * hw,int port,u8 prio)2544*4882a593Smuzhiyun static void sw_cfg_port_based(struct ksz_hw *hw, int port, u8 prio)
2545*4882a593Smuzhiyun {
2546*4882a593Smuzhiyun 	u16 data;
2547*4882a593Smuzhiyun 
2548*4882a593Smuzhiyun 	if (prio > PORT_BASED_PRIORITY_BASE)
2549*4882a593Smuzhiyun 		prio = PORT_BASED_PRIORITY_BASE;
2550*4882a593Smuzhiyun 
2551*4882a593Smuzhiyun 	hw->ksz_switch->port_cfg[port].port_prio = prio;
2552*4882a593Smuzhiyun 
2553*4882a593Smuzhiyun 	port_r16(hw, port, KS8842_PORT_CTRL_1_OFFSET, &data);
2554*4882a593Smuzhiyun 	data &= ~PORT_BASED_PRIORITY_MASK;
2555*4882a593Smuzhiyun 	data |= prio << PORT_BASED_PRIORITY_SHIFT;
2556*4882a593Smuzhiyun 	port_w16(hw, port, KS8842_PORT_CTRL_1_OFFSET, data);
2557*4882a593Smuzhiyun }
2558*4882a593Smuzhiyun 
2559*4882a593Smuzhiyun /**
2560*4882a593Smuzhiyun  * sw_dis_multi_queue - disable transmit multiple queues
2561*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2562*4882a593Smuzhiyun  * @port:	The port index.
2563*4882a593Smuzhiyun  *
2564*4882a593Smuzhiyun  * This routine disables the transmit multiple queues selection of the switch
2565*4882a593Smuzhiyun  * port.  Only single transmit queue on the port.
2566*4882a593Smuzhiyun  */
sw_dis_multi_queue(struct ksz_hw * hw,int port)2567*4882a593Smuzhiyun static void sw_dis_multi_queue(struct ksz_hw *hw, int port)
2568*4882a593Smuzhiyun {
2569*4882a593Smuzhiyun 	port_cfg_prio(hw, port, 0);
2570*4882a593Smuzhiyun }
2571*4882a593Smuzhiyun 
2572*4882a593Smuzhiyun /**
2573*4882a593Smuzhiyun  * sw_init_prio - initialize switch priority
2574*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2575*4882a593Smuzhiyun  *
2576*4882a593Smuzhiyun  * This routine initializes the switch QoS priority functions.
2577*4882a593Smuzhiyun  */
sw_init_prio(struct ksz_hw * hw)2578*4882a593Smuzhiyun static void sw_init_prio(struct ksz_hw *hw)
2579*4882a593Smuzhiyun {
2580*4882a593Smuzhiyun 	int port;
2581*4882a593Smuzhiyun 	int tos;
2582*4882a593Smuzhiyun 	struct ksz_switch *sw = hw->ksz_switch;
2583*4882a593Smuzhiyun 
2584*4882a593Smuzhiyun 	/*
2585*4882a593Smuzhiyun 	 * Init all the 802.1p tag priority value to be assigned to different
2586*4882a593Smuzhiyun 	 * priority queue.
2587*4882a593Smuzhiyun 	 */
2588*4882a593Smuzhiyun 	sw->p_802_1p[0] = 0;
2589*4882a593Smuzhiyun 	sw->p_802_1p[1] = 0;
2590*4882a593Smuzhiyun 	sw->p_802_1p[2] = 1;
2591*4882a593Smuzhiyun 	sw->p_802_1p[3] = 1;
2592*4882a593Smuzhiyun 	sw->p_802_1p[4] = 2;
2593*4882a593Smuzhiyun 	sw->p_802_1p[5] = 2;
2594*4882a593Smuzhiyun 	sw->p_802_1p[6] = 3;
2595*4882a593Smuzhiyun 	sw->p_802_1p[7] = 3;
2596*4882a593Smuzhiyun 
2597*4882a593Smuzhiyun 	/*
2598*4882a593Smuzhiyun 	 * Init all the DiffServ priority value to be assigned to priority
2599*4882a593Smuzhiyun 	 * queue 0.
2600*4882a593Smuzhiyun 	 */
2601*4882a593Smuzhiyun 	for (tos = 0; tos < DIFFSERV_ENTRIES; tos++)
2602*4882a593Smuzhiyun 		sw->diffserv[tos] = 0;
2603*4882a593Smuzhiyun 
2604*4882a593Smuzhiyun 	/* All QoS functions disabled. */
2605*4882a593Smuzhiyun 	for (port = 0; port < TOTAL_PORT_NUM; port++) {
2606*4882a593Smuzhiyun 		sw_dis_multi_queue(hw, port);
2607*4882a593Smuzhiyun 		sw_dis_diffserv(hw, port);
2608*4882a593Smuzhiyun 		sw_dis_802_1p(hw, port);
2609*4882a593Smuzhiyun 		sw_cfg_replace_vid(hw, port, 0);
2610*4882a593Smuzhiyun 
2611*4882a593Smuzhiyun 		sw->port_cfg[port].port_prio = 0;
2612*4882a593Smuzhiyun 		sw_cfg_port_based(hw, port, sw->port_cfg[port].port_prio);
2613*4882a593Smuzhiyun 	}
2614*4882a593Smuzhiyun 	sw_cfg_replace_null_vid(hw, 0);
2615*4882a593Smuzhiyun }
2616*4882a593Smuzhiyun 
2617*4882a593Smuzhiyun /**
2618*4882a593Smuzhiyun  * port_get_def_vid - get port default VID.
2619*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2620*4882a593Smuzhiyun  * @port:	The port index.
2621*4882a593Smuzhiyun  * @vid:	Buffer to store the VID.
2622*4882a593Smuzhiyun  *
2623*4882a593Smuzhiyun  * This routine retrieves the default VID of the port.
2624*4882a593Smuzhiyun  */
port_get_def_vid(struct ksz_hw * hw,int port,u16 * vid)2625*4882a593Smuzhiyun static void port_get_def_vid(struct ksz_hw *hw, int port, u16 *vid)
2626*4882a593Smuzhiyun {
2627*4882a593Smuzhiyun 	u32 addr;
2628*4882a593Smuzhiyun 
2629*4882a593Smuzhiyun 	PORT_CTRL_ADDR(port, addr);
2630*4882a593Smuzhiyun 	addr += KS8842_PORT_CTRL_VID_OFFSET;
2631*4882a593Smuzhiyun 	*vid = readw(hw->io + addr);
2632*4882a593Smuzhiyun }
2633*4882a593Smuzhiyun 
2634*4882a593Smuzhiyun /**
2635*4882a593Smuzhiyun  * sw_init_vlan - initialize switch VLAN
2636*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2637*4882a593Smuzhiyun  *
2638*4882a593Smuzhiyun  * This routine initializes the VLAN function of the switch.
2639*4882a593Smuzhiyun  */
sw_init_vlan(struct ksz_hw * hw)2640*4882a593Smuzhiyun static void sw_init_vlan(struct ksz_hw *hw)
2641*4882a593Smuzhiyun {
2642*4882a593Smuzhiyun 	int port;
2643*4882a593Smuzhiyun 	int entry;
2644*4882a593Smuzhiyun 	struct ksz_switch *sw = hw->ksz_switch;
2645*4882a593Smuzhiyun 
2646*4882a593Smuzhiyun 	/* Read 16 VLAN entries from device's VLAN table. */
2647*4882a593Smuzhiyun 	for (entry = 0; entry < VLAN_TABLE_ENTRIES; entry++) {
2648*4882a593Smuzhiyun 		sw_r_vlan_table(hw, entry,
2649*4882a593Smuzhiyun 			&sw->vlan_table[entry].vid,
2650*4882a593Smuzhiyun 			&sw->vlan_table[entry].fid,
2651*4882a593Smuzhiyun 			&sw->vlan_table[entry].member);
2652*4882a593Smuzhiyun 	}
2653*4882a593Smuzhiyun 
2654*4882a593Smuzhiyun 	for (port = 0; port < TOTAL_PORT_NUM; port++) {
2655*4882a593Smuzhiyun 		port_get_def_vid(hw, port, &sw->port_cfg[port].vid);
2656*4882a593Smuzhiyun 		sw->port_cfg[port].member = PORT_MASK;
2657*4882a593Smuzhiyun 	}
2658*4882a593Smuzhiyun }
2659*4882a593Smuzhiyun 
2660*4882a593Smuzhiyun /**
2661*4882a593Smuzhiyun  * sw_cfg_port_base_vlan - configure port-based VLAN membership
2662*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2663*4882a593Smuzhiyun  * @port:	The port index.
2664*4882a593Smuzhiyun  * @member:	The port-based VLAN membership.
2665*4882a593Smuzhiyun  *
2666*4882a593Smuzhiyun  * This routine configures the port-based VLAN membership of the port.
2667*4882a593Smuzhiyun  */
sw_cfg_port_base_vlan(struct ksz_hw * hw,int port,u8 member)2668*4882a593Smuzhiyun static void sw_cfg_port_base_vlan(struct ksz_hw *hw, int port, u8 member)
2669*4882a593Smuzhiyun {
2670*4882a593Smuzhiyun 	u32 addr;
2671*4882a593Smuzhiyun 	u8 data;
2672*4882a593Smuzhiyun 
2673*4882a593Smuzhiyun 	PORT_CTRL_ADDR(port, addr);
2674*4882a593Smuzhiyun 	addr += KS8842_PORT_CTRL_2_OFFSET;
2675*4882a593Smuzhiyun 
2676*4882a593Smuzhiyun 	data = readb(hw->io + addr);
2677*4882a593Smuzhiyun 	data &= ~PORT_VLAN_MEMBERSHIP;
2678*4882a593Smuzhiyun 	data |= (member & PORT_MASK);
2679*4882a593Smuzhiyun 	writeb(data, hw->io + addr);
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun 	hw->ksz_switch->port_cfg[port].member = member;
2682*4882a593Smuzhiyun }
2683*4882a593Smuzhiyun 
2684*4882a593Smuzhiyun /**
2685*4882a593Smuzhiyun  * sw_get_addr - get the switch MAC address.
2686*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2687*4882a593Smuzhiyun  * @mac_addr:	Buffer to store the MAC address.
2688*4882a593Smuzhiyun  *
2689*4882a593Smuzhiyun  * This function retrieves the MAC address of the switch.
2690*4882a593Smuzhiyun  */
sw_get_addr(struct ksz_hw * hw,u8 * mac_addr)2691*4882a593Smuzhiyun static inline void sw_get_addr(struct ksz_hw *hw, u8 *mac_addr)
2692*4882a593Smuzhiyun {
2693*4882a593Smuzhiyun 	int i;
2694*4882a593Smuzhiyun 
2695*4882a593Smuzhiyun 	for (i = 0; i < 6; i += 2) {
2696*4882a593Smuzhiyun 		mac_addr[i] = readb(hw->io + KS8842_MAC_ADDR_0_OFFSET + i);
2697*4882a593Smuzhiyun 		mac_addr[1 + i] = readb(hw->io + KS8842_MAC_ADDR_1_OFFSET + i);
2698*4882a593Smuzhiyun 	}
2699*4882a593Smuzhiyun }
2700*4882a593Smuzhiyun 
2701*4882a593Smuzhiyun /**
2702*4882a593Smuzhiyun  * sw_set_addr - configure switch MAC address
2703*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2704*4882a593Smuzhiyun  * @mac_addr:	The MAC address.
2705*4882a593Smuzhiyun  *
2706*4882a593Smuzhiyun  * This function configures the MAC address of the switch.
2707*4882a593Smuzhiyun  */
sw_set_addr(struct ksz_hw * hw,u8 * mac_addr)2708*4882a593Smuzhiyun static void sw_set_addr(struct ksz_hw *hw, u8 *mac_addr)
2709*4882a593Smuzhiyun {
2710*4882a593Smuzhiyun 	int i;
2711*4882a593Smuzhiyun 
2712*4882a593Smuzhiyun 	for (i = 0; i < 6; i += 2) {
2713*4882a593Smuzhiyun 		writeb(mac_addr[i], hw->io + KS8842_MAC_ADDR_0_OFFSET + i);
2714*4882a593Smuzhiyun 		writeb(mac_addr[1 + i], hw->io + KS8842_MAC_ADDR_1_OFFSET + i);
2715*4882a593Smuzhiyun 	}
2716*4882a593Smuzhiyun }
2717*4882a593Smuzhiyun 
2718*4882a593Smuzhiyun /**
2719*4882a593Smuzhiyun  * sw_set_global_ctrl - set switch global control
2720*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2721*4882a593Smuzhiyun  *
2722*4882a593Smuzhiyun  * This routine sets the global control of the switch function.
2723*4882a593Smuzhiyun  */
sw_set_global_ctrl(struct ksz_hw * hw)2724*4882a593Smuzhiyun static void sw_set_global_ctrl(struct ksz_hw *hw)
2725*4882a593Smuzhiyun {
2726*4882a593Smuzhiyun 	u16 data;
2727*4882a593Smuzhiyun 
2728*4882a593Smuzhiyun 	/* Enable switch MII flow control. */
2729*4882a593Smuzhiyun 	data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET);
2730*4882a593Smuzhiyun 	data |= SWITCH_FLOW_CTRL;
2731*4882a593Smuzhiyun 	writew(data, hw->io + KS8842_SWITCH_CTRL_3_OFFSET);
2732*4882a593Smuzhiyun 
2733*4882a593Smuzhiyun 	data = readw(hw->io + KS8842_SWITCH_CTRL_1_OFFSET);
2734*4882a593Smuzhiyun 
2735*4882a593Smuzhiyun 	/* Enable aggressive back off algorithm in half duplex mode. */
2736*4882a593Smuzhiyun 	data |= SWITCH_AGGR_BACKOFF;
2737*4882a593Smuzhiyun 
2738*4882a593Smuzhiyun 	/* Enable automatic fast aging when link changed detected. */
2739*4882a593Smuzhiyun 	data |= SWITCH_AGING_ENABLE;
2740*4882a593Smuzhiyun 	data |= SWITCH_LINK_AUTO_AGING;
2741*4882a593Smuzhiyun 
2742*4882a593Smuzhiyun 	if (hw->overrides & FAST_AGING)
2743*4882a593Smuzhiyun 		data |= SWITCH_FAST_AGING;
2744*4882a593Smuzhiyun 	else
2745*4882a593Smuzhiyun 		data &= ~SWITCH_FAST_AGING;
2746*4882a593Smuzhiyun 	writew(data, hw->io + KS8842_SWITCH_CTRL_1_OFFSET);
2747*4882a593Smuzhiyun 
2748*4882a593Smuzhiyun 	data = readw(hw->io + KS8842_SWITCH_CTRL_2_OFFSET);
2749*4882a593Smuzhiyun 
2750*4882a593Smuzhiyun 	/* Enable no excessive collision drop. */
2751*4882a593Smuzhiyun 	data |= NO_EXC_COLLISION_DROP;
2752*4882a593Smuzhiyun 	writew(data, hw->io + KS8842_SWITCH_CTRL_2_OFFSET);
2753*4882a593Smuzhiyun }
2754*4882a593Smuzhiyun 
2755*4882a593Smuzhiyun enum {
2756*4882a593Smuzhiyun 	STP_STATE_DISABLED = 0,
2757*4882a593Smuzhiyun 	STP_STATE_LISTENING,
2758*4882a593Smuzhiyun 	STP_STATE_LEARNING,
2759*4882a593Smuzhiyun 	STP_STATE_FORWARDING,
2760*4882a593Smuzhiyun 	STP_STATE_BLOCKED,
2761*4882a593Smuzhiyun 	STP_STATE_SIMPLE
2762*4882a593Smuzhiyun };
2763*4882a593Smuzhiyun 
2764*4882a593Smuzhiyun /**
2765*4882a593Smuzhiyun  * port_set_stp_state - configure port spanning tree state
2766*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2767*4882a593Smuzhiyun  * @port:	The port index.
2768*4882a593Smuzhiyun  * @state:	The spanning tree state.
2769*4882a593Smuzhiyun  *
2770*4882a593Smuzhiyun  * This routine configures the spanning tree state of the port.
2771*4882a593Smuzhiyun  */
port_set_stp_state(struct ksz_hw * hw,int port,int state)2772*4882a593Smuzhiyun static void port_set_stp_state(struct ksz_hw *hw, int port, int state)
2773*4882a593Smuzhiyun {
2774*4882a593Smuzhiyun 	u16 data;
2775*4882a593Smuzhiyun 
2776*4882a593Smuzhiyun 	port_r16(hw, port, KS8842_PORT_CTRL_2_OFFSET, &data);
2777*4882a593Smuzhiyun 	switch (state) {
2778*4882a593Smuzhiyun 	case STP_STATE_DISABLED:
2779*4882a593Smuzhiyun 		data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE);
2780*4882a593Smuzhiyun 		data |= PORT_LEARN_DISABLE;
2781*4882a593Smuzhiyun 		break;
2782*4882a593Smuzhiyun 	case STP_STATE_LISTENING:
2783*4882a593Smuzhiyun /*
2784*4882a593Smuzhiyun  * No need to turn on transmit because of port direct mode.
2785*4882a593Smuzhiyun  * Turning on receive is required if static MAC table is not setup.
2786*4882a593Smuzhiyun  */
2787*4882a593Smuzhiyun 		data &= ~PORT_TX_ENABLE;
2788*4882a593Smuzhiyun 		data |= PORT_RX_ENABLE;
2789*4882a593Smuzhiyun 		data |= PORT_LEARN_DISABLE;
2790*4882a593Smuzhiyun 		break;
2791*4882a593Smuzhiyun 	case STP_STATE_LEARNING:
2792*4882a593Smuzhiyun 		data &= ~PORT_TX_ENABLE;
2793*4882a593Smuzhiyun 		data |= PORT_RX_ENABLE;
2794*4882a593Smuzhiyun 		data &= ~PORT_LEARN_DISABLE;
2795*4882a593Smuzhiyun 		break;
2796*4882a593Smuzhiyun 	case STP_STATE_FORWARDING:
2797*4882a593Smuzhiyun 		data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
2798*4882a593Smuzhiyun 		data &= ~PORT_LEARN_DISABLE;
2799*4882a593Smuzhiyun 		break;
2800*4882a593Smuzhiyun 	case STP_STATE_BLOCKED:
2801*4882a593Smuzhiyun /*
2802*4882a593Smuzhiyun  * Need to setup static MAC table with override to keep receiving BPDU
2803*4882a593Smuzhiyun  * messages.  See sw_init_stp routine.
2804*4882a593Smuzhiyun  */
2805*4882a593Smuzhiyun 		data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE);
2806*4882a593Smuzhiyun 		data |= PORT_LEARN_DISABLE;
2807*4882a593Smuzhiyun 		break;
2808*4882a593Smuzhiyun 	case STP_STATE_SIMPLE:
2809*4882a593Smuzhiyun 		data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
2810*4882a593Smuzhiyun 		data |= PORT_LEARN_DISABLE;
2811*4882a593Smuzhiyun 		break;
2812*4882a593Smuzhiyun 	}
2813*4882a593Smuzhiyun 	port_w16(hw, port, KS8842_PORT_CTRL_2_OFFSET, data);
2814*4882a593Smuzhiyun 	hw->ksz_switch->port_cfg[port].stp_state = state;
2815*4882a593Smuzhiyun }
2816*4882a593Smuzhiyun 
2817*4882a593Smuzhiyun #define STP_ENTRY			0
2818*4882a593Smuzhiyun #define BROADCAST_ENTRY			1
2819*4882a593Smuzhiyun #define BRIDGE_ADDR_ENTRY		2
2820*4882a593Smuzhiyun #define IPV6_ADDR_ENTRY			3
2821*4882a593Smuzhiyun 
2822*4882a593Smuzhiyun /**
2823*4882a593Smuzhiyun  * sw_clr_sta_mac_table - clear static MAC table
2824*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2825*4882a593Smuzhiyun  *
2826*4882a593Smuzhiyun  * This routine clears the static MAC table.
2827*4882a593Smuzhiyun  */
sw_clr_sta_mac_table(struct ksz_hw * hw)2828*4882a593Smuzhiyun static void sw_clr_sta_mac_table(struct ksz_hw *hw)
2829*4882a593Smuzhiyun {
2830*4882a593Smuzhiyun 	struct ksz_mac_table *entry;
2831*4882a593Smuzhiyun 	int i;
2832*4882a593Smuzhiyun 
2833*4882a593Smuzhiyun 	for (i = 0; i < STATIC_MAC_TABLE_ENTRIES; i++) {
2834*4882a593Smuzhiyun 		entry = &hw->ksz_switch->mac_table[i];
2835*4882a593Smuzhiyun 		sw_w_sta_mac_table(hw, i,
2836*4882a593Smuzhiyun 			entry->mac_addr, entry->ports,
2837*4882a593Smuzhiyun 			entry->override, 0,
2838*4882a593Smuzhiyun 			entry->use_fid, entry->fid);
2839*4882a593Smuzhiyun 	}
2840*4882a593Smuzhiyun }
2841*4882a593Smuzhiyun 
2842*4882a593Smuzhiyun /**
2843*4882a593Smuzhiyun  * sw_init_stp - initialize switch spanning tree support
2844*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2845*4882a593Smuzhiyun  *
2846*4882a593Smuzhiyun  * This routine initializes the spanning tree support of the switch.
2847*4882a593Smuzhiyun  */
sw_init_stp(struct ksz_hw * hw)2848*4882a593Smuzhiyun static void sw_init_stp(struct ksz_hw *hw)
2849*4882a593Smuzhiyun {
2850*4882a593Smuzhiyun 	struct ksz_mac_table *entry;
2851*4882a593Smuzhiyun 
2852*4882a593Smuzhiyun 	entry = &hw->ksz_switch->mac_table[STP_ENTRY];
2853*4882a593Smuzhiyun 	entry->mac_addr[0] = 0x01;
2854*4882a593Smuzhiyun 	entry->mac_addr[1] = 0x80;
2855*4882a593Smuzhiyun 	entry->mac_addr[2] = 0xC2;
2856*4882a593Smuzhiyun 	entry->mac_addr[3] = 0x00;
2857*4882a593Smuzhiyun 	entry->mac_addr[4] = 0x00;
2858*4882a593Smuzhiyun 	entry->mac_addr[5] = 0x00;
2859*4882a593Smuzhiyun 	entry->ports = HOST_MASK;
2860*4882a593Smuzhiyun 	entry->override = 1;
2861*4882a593Smuzhiyun 	entry->valid = 1;
2862*4882a593Smuzhiyun 	sw_w_sta_mac_table(hw, STP_ENTRY,
2863*4882a593Smuzhiyun 		entry->mac_addr, entry->ports,
2864*4882a593Smuzhiyun 		entry->override, entry->valid,
2865*4882a593Smuzhiyun 		entry->use_fid, entry->fid);
2866*4882a593Smuzhiyun }
2867*4882a593Smuzhiyun 
2868*4882a593Smuzhiyun /**
2869*4882a593Smuzhiyun  * sw_block_addr - block certain packets from the host port
2870*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2871*4882a593Smuzhiyun  *
2872*4882a593Smuzhiyun  * This routine blocks certain packets from reaching to the host port.
2873*4882a593Smuzhiyun  */
sw_block_addr(struct ksz_hw * hw)2874*4882a593Smuzhiyun static void sw_block_addr(struct ksz_hw *hw)
2875*4882a593Smuzhiyun {
2876*4882a593Smuzhiyun 	struct ksz_mac_table *entry;
2877*4882a593Smuzhiyun 	int i;
2878*4882a593Smuzhiyun 
2879*4882a593Smuzhiyun 	for (i = BROADCAST_ENTRY; i <= IPV6_ADDR_ENTRY; i++) {
2880*4882a593Smuzhiyun 		entry = &hw->ksz_switch->mac_table[i];
2881*4882a593Smuzhiyun 		entry->valid = 0;
2882*4882a593Smuzhiyun 		sw_w_sta_mac_table(hw, i,
2883*4882a593Smuzhiyun 			entry->mac_addr, entry->ports,
2884*4882a593Smuzhiyun 			entry->override, entry->valid,
2885*4882a593Smuzhiyun 			entry->use_fid, entry->fid);
2886*4882a593Smuzhiyun 	}
2887*4882a593Smuzhiyun }
2888*4882a593Smuzhiyun 
2889*4882a593Smuzhiyun #define PHY_LINK_SUPPORT		\
2890*4882a593Smuzhiyun 	(PHY_AUTO_NEG_ASYM_PAUSE |	\
2891*4882a593Smuzhiyun 	PHY_AUTO_NEG_SYM_PAUSE |	\
2892*4882a593Smuzhiyun 	PHY_AUTO_NEG_100BT4 |		\
2893*4882a593Smuzhiyun 	PHY_AUTO_NEG_100BTX_FD |	\
2894*4882a593Smuzhiyun 	PHY_AUTO_NEG_100BTX |		\
2895*4882a593Smuzhiyun 	PHY_AUTO_NEG_10BT_FD |		\
2896*4882a593Smuzhiyun 	PHY_AUTO_NEG_10BT)
2897*4882a593Smuzhiyun 
hw_r_phy_ctrl(struct ksz_hw * hw,int phy,u16 * data)2898*4882a593Smuzhiyun static inline void hw_r_phy_ctrl(struct ksz_hw *hw, int phy, u16 *data)
2899*4882a593Smuzhiyun {
2900*4882a593Smuzhiyun 	*data = readw(hw->io + phy + KS884X_PHY_CTRL_OFFSET);
2901*4882a593Smuzhiyun }
2902*4882a593Smuzhiyun 
hw_w_phy_ctrl(struct ksz_hw * hw,int phy,u16 data)2903*4882a593Smuzhiyun static inline void hw_w_phy_ctrl(struct ksz_hw *hw, int phy, u16 data)
2904*4882a593Smuzhiyun {
2905*4882a593Smuzhiyun 	writew(data, hw->io + phy + KS884X_PHY_CTRL_OFFSET);
2906*4882a593Smuzhiyun }
2907*4882a593Smuzhiyun 
hw_r_phy_link_stat(struct ksz_hw * hw,int phy,u16 * data)2908*4882a593Smuzhiyun static inline void hw_r_phy_link_stat(struct ksz_hw *hw, int phy, u16 *data)
2909*4882a593Smuzhiyun {
2910*4882a593Smuzhiyun 	*data = readw(hw->io + phy + KS884X_PHY_STATUS_OFFSET);
2911*4882a593Smuzhiyun }
2912*4882a593Smuzhiyun 
hw_r_phy_auto_neg(struct ksz_hw * hw,int phy,u16 * data)2913*4882a593Smuzhiyun static inline void hw_r_phy_auto_neg(struct ksz_hw *hw, int phy, u16 *data)
2914*4882a593Smuzhiyun {
2915*4882a593Smuzhiyun 	*data = readw(hw->io + phy + KS884X_PHY_AUTO_NEG_OFFSET);
2916*4882a593Smuzhiyun }
2917*4882a593Smuzhiyun 
hw_w_phy_auto_neg(struct ksz_hw * hw,int phy,u16 data)2918*4882a593Smuzhiyun static inline void hw_w_phy_auto_neg(struct ksz_hw *hw, int phy, u16 data)
2919*4882a593Smuzhiyun {
2920*4882a593Smuzhiyun 	writew(data, hw->io + phy + KS884X_PHY_AUTO_NEG_OFFSET);
2921*4882a593Smuzhiyun }
2922*4882a593Smuzhiyun 
hw_r_phy_rem_cap(struct ksz_hw * hw,int phy,u16 * data)2923*4882a593Smuzhiyun static inline void hw_r_phy_rem_cap(struct ksz_hw *hw, int phy, u16 *data)
2924*4882a593Smuzhiyun {
2925*4882a593Smuzhiyun 	*data = readw(hw->io + phy + KS884X_PHY_REMOTE_CAP_OFFSET);
2926*4882a593Smuzhiyun }
2927*4882a593Smuzhiyun 
hw_r_phy_crossover(struct ksz_hw * hw,int phy,u16 * data)2928*4882a593Smuzhiyun static inline void hw_r_phy_crossover(struct ksz_hw *hw, int phy, u16 *data)
2929*4882a593Smuzhiyun {
2930*4882a593Smuzhiyun 	*data = readw(hw->io + phy + KS884X_PHY_CTRL_OFFSET);
2931*4882a593Smuzhiyun }
2932*4882a593Smuzhiyun 
hw_w_phy_crossover(struct ksz_hw * hw,int phy,u16 data)2933*4882a593Smuzhiyun static inline void hw_w_phy_crossover(struct ksz_hw *hw, int phy, u16 data)
2934*4882a593Smuzhiyun {
2935*4882a593Smuzhiyun 	writew(data, hw->io + phy + KS884X_PHY_CTRL_OFFSET);
2936*4882a593Smuzhiyun }
2937*4882a593Smuzhiyun 
hw_r_phy_polarity(struct ksz_hw * hw,int phy,u16 * data)2938*4882a593Smuzhiyun static inline void hw_r_phy_polarity(struct ksz_hw *hw, int phy, u16 *data)
2939*4882a593Smuzhiyun {
2940*4882a593Smuzhiyun 	*data = readw(hw->io + phy + KS884X_PHY_PHY_CTRL_OFFSET);
2941*4882a593Smuzhiyun }
2942*4882a593Smuzhiyun 
hw_w_phy_polarity(struct ksz_hw * hw,int phy,u16 data)2943*4882a593Smuzhiyun static inline void hw_w_phy_polarity(struct ksz_hw *hw, int phy, u16 data)
2944*4882a593Smuzhiyun {
2945*4882a593Smuzhiyun 	writew(data, hw->io + phy + KS884X_PHY_PHY_CTRL_OFFSET);
2946*4882a593Smuzhiyun }
2947*4882a593Smuzhiyun 
hw_r_phy_link_md(struct ksz_hw * hw,int phy,u16 * data)2948*4882a593Smuzhiyun static inline void hw_r_phy_link_md(struct ksz_hw *hw, int phy, u16 *data)
2949*4882a593Smuzhiyun {
2950*4882a593Smuzhiyun 	*data = readw(hw->io + phy + KS884X_PHY_LINK_MD_OFFSET);
2951*4882a593Smuzhiyun }
2952*4882a593Smuzhiyun 
hw_w_phy_link_md(struct ksz_hw * hw,int phy,u16 data)2953*4882a593Smuzhiyun static inline void hw_w_phy_link_md(struct ksz_hw *hw, int phy, u16 data)
2954*4882a593Smuzhiyun {
2955*4882a593Smuzhiyun 	writew(data, hw->io + phy + KS884X_PHY_LINK_MD_OFFSET);
2956*4882a593Smuzhiyun }
2957*4882a593Smuzhiyun 
2958*4882a593Smuzhiyun /**
2959*4882a593Smuzhiyun  * hw_r_phy - read data from PHY register
2960*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2961*4882a593Smuzhiyun  * @port:	Port to read.
2962*4882a593Smuzhiyun  * @reg:	PHY register to read.
2963*4882a593Smuzhiyun  * @val:	Buffer to store the read data.
2964*4882a593Smuzhiyun  *
2965*4882a593Smuzhiyun  * This routine reads data from the PHY register.
2966*4882a593Smuzhiyun  */
hw_r_phy(struct ksz_hw * hw,int port,u16 reg,u16 * val)2967*4882a593Smuzhiyun static void hw_r_phy(struct ksz_hw *hw, int port, u16 reg, u16 *val)
2968*4882a593Smuzhiyun {
2969*4882a593Smuzhiyun 	int phy;
2970*4882a593Smuzhiyun 
2971*4882a593Smuzhiyun 	phy = KS884X_PHY_1_CTRL_OFFSET + port * PHY_CTRL_INTERVAL + reg;
2972*4882a593Smuzhiyun 	*val = readw(hw->io + phy);
2973*4882a593Smuzhiyun }
2974*4882a593Smuzhiyun 
2975*4882a593Smuzhiyun /**
2976*4882a593Smuzhiyun  * port_w_phy - write data to PHY register
2977*4882a593Smuzhiyun  * @hw: 	The hardware instance.
2978*4882a593Smuzhiyun  * @port:	Port to write.
2979*4882a593Smuzhiyun  * @reg:	PHY register to write.
2980*4882a593Smuzhiyun  * @val:	Word data to write.
2981*4882a593Smuzhiyun  *
2982*4882a593Smuzhiyun  * This routine writes data to the PHY register.
2983*4882a593Smuzhiyun  */
hw_w_phy(struct ksz_hw * hw,int port,u16 reg,u16 val)2984*4882a593Smuzhiyun static void hw_w_phy(struct ksz_hw *hw, int port, u16 reg, u16 val)
2985*4882a593Smuzhiyun {
2986*4882a593Smuzhiyun 	int phy;
2987*4882a593Smuzhiyun 
2988*4882a593Smuzhiyun 	phy = KS884X_PHY_1_CTRL_OFFSET + port * PHY_CTRL_INTERVAL + reg;
2989*4882a593Smuzhiyun 	writew(val, hw->io + phy);
2990*4882a593Smuzhiyun }
2991*4882a593Smuzhiyun 
2992*4882a593Smuzhiyun /*
2993*4882a593Smuzhiyun  * EEPROM access functions
2994*4882a593Smuzhiyun  */
2995*4882a593Smuzhiyun 
2996*4882a593Smuzhiyun #define AT93C_CODE			0
2997*4882a593Smuzhiyun #define AT93C_WR_OFF			0x00
2998*4882a593Smuzhiyun #define AT93C_WR_ALL			0x10
2999*4882a593Smuzhiyun #define AT93C_ER_ALL			0x20
3000*4882a593Smuzhiyun #define AT93C_WR_ON			0x30
3001*4882a593Smuzhiyun 
3002*4882a593Smuzhiyun #define AT93C_WRITE			1
3003*4882a593Smuzhiyun #define AT93C_READ			2
3004*4882a593Smuzhiyun #define AT93C_ERASE			3
3005*4882a593Smuzhiyun 
3006*4882a593Smuzhiyun #define EEPROM_DELAY			4
3007*4882a593Smuzhiyun 
drop_gpio(struct ksz_hw * hw,u8 gpio)3008*4882a593Smuzhiyun static inline void drop_gpio(struct ksz_hw *hw, u8 gpio)
3009*4882a593Smuzhiyun {
3010*4882a593Smuzhiyun 	u16 data;
3011*4882a593Smuzhiyun 
3012*4882a593Smuzhiyun 	data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET);
3013*4882a593Smuzhiyun 	data &= ~gpio;
3014*4882a593Smuzhiyun 	writew(data, hw->io + KS884X_EEPROM_CTRL_OFFSET);
3015*4882a593Smuzhiyun }
3016*4882a593Smuzhiyun 
raise_gpio(struct ksz_hw * hw,u8 gpio)3017*4882a593Smuzhiyun static inline void raise_gpio(struct ksz_hw *hw, u8 gpio)
3018*4882a593Smuzhiyun {
3019*4882a593Smuzhiyun 	u16 data;
3020*4882a593Smuzhiyun 
3021*4882a593Smuzhiyun 	data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET);
3022*4882a593Smuzhiyun 	data |= gpio;
3023*4882a593Smuzhiyun 	writew(data, hw->io + KS884X_EEPROM_CTRL_OFFSET);
3024*4882a593Smuzhiyun }
3025*4882a593Smuzhiyun 
state_gpio(struct ksz_hw * hw,u8 gpio)3026*4882a593Smuzhiyun static inline u8 state_gpio(struct ksz_hw *hw, u8 gpio)
3027*4882a593Smuzhiyun {
3028*4882a593Smuzhiyun 	u16 data;
3029*4882a593Smuzhiyun 
3030*4882a593Smuzhiyun 	data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET);
3031*4882a593Smuzhiyun 	return (u8)(data & gpio);
3032*4882a593Smuzhiyun }
3033*4882a593Smuzhiyun 
eeprom_clk(struct ksz_hw * hw)3034*4882a593Smuzhiyun static void eeprom_clk(struct ksz_hw *hw)
3035*4882a593Smuzhiyun {
3036*4882a593Smuzhiyun 	raise_gpio(hw, EEPROM_SERIAL_CLOCK);
3037*4882a593Smuzhiyun 	udelay(EEPROM_DELAY);
3038*4882a593Smuzhiyun 	drop_gpio(hw, EEPROM_SERIAL_CLOCK);
3039*4882a593Smuzhiyun 	udelay(EEPROM_DELAY);
3040*4882a593Smuzhiyun }
3041*4882a593Smuzhiyun 
spi_r(struct ksz_hw * hw)3042*4882a593Smuzhiyun static u16 spi_r(struct ksz_hw *hw)
3043*4882a593Smuzhiyun {
3044*4882a593Smuzhiyun 	int i;
3045*4882a593Smuzhiyun 	u16 temp = 0;
3046*4882a593Smuzhiyun 
3047*4882a593Smuzhiyun 	for (i = 15; i >= 0; i--) {
3048*4882a593Smuzhiyun 		raise_gpio(hw, EEPROM_SERIAL_CLOCK);
3049*4882a593Smuzhiyun 		udelay(EEPROM_DELAY);
3050*4882a593Smuzhiyun 
3051*4882a593Smuzhiyun 		temp |= (state_gpio(hw, EEPROM_DATA_IN)) ? 1 << i : 0;
3052*4882a593Smuzhiyun 
3053*4882a593Smuzhiyun 		drop_gpio(hw, EEPROM_SERIAL_CLOCK);
3054*4882a593Smuzhiyun 		udelay(EEPROM_DELAY);
3055*4882a593Smuzhiyun 	}
3056*4882a593Smuzhiyun 	return temp;
3057*4882a593Smuzhiyun }
3058*4882a593Smuzhiyun 
spi_w(struct ksz_hw * hw,u16 data)3059*4882a593Smuzhiyun static void spi_w(struct ksz_hw *hw, u16 data)
3060*4882a593Smuzhiyun {
3061*4882a593Smuzhiyun 	int i;
3062*4882a593Smuzhiyun 
3063*4882a593Smuzhiyun 	for (i = 15; i >= 0; i--) {
3064*4882a593Smuzhiyun 		(data & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) :
3065*4882a593Smuzhiyun 			drop_gpio(hw, EEPROM_DATA_OUT);
3066*4882a593Smuzhiyun 		eeprom_clk(hw);
3067*4882a593Smuzhiyun 	}
3068*4882a593Smuzhiyun }
3069*4882a593Smuzhiyun 
spi_reg(struct ksz_hw * hw,u8 data,u8 reg)3070*4882a593Smuzhiyun static void spi_reg(struct ksz_hw *hw, u8 data, u8 reg)
3071*4882a593Smuzhiyun {
3072*4882a593Smuzhiyun 	int i;
3073*4882a593Smuzhiyun 
3074*4882a593Smuzhiyun 	/* Initial start bit */
3075*4882a593Smuzhiyun 	raise_gpio(hw, EEPROM_DATA_OUT);
3076*4882a593Smuzhiyun 	eeprom_clk(hw);
3077*4882a593Smuzhiyun 
3078*4882a593Smuzhiyun 	/* AT93C operation */
3079*4882a593Smuzhiyun 	for (i = 1; i >= 0; i--) {
3080*4882a593Smuzhiyun 		(data & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) :
3081*4882a593Smuzhiyun 			drop_gpio(hw, EEPROM_DATA_OUT);
3082*4882a593Smuzhiyun 		eeprom_clk(hw);
3083*4882a593Smuzhiyun 	}
3084*4882a593Smuzhiyun 
3085*4882a593Smuzhiyun 	/* Address location */
3086*4882a593Smuzhiyun 	for (i = 5; i >= 0; i--) {
3087*4882a593Smuzhiyun 		(reg & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) :
3088*4882a593Smuzhiyun 			drop_gpio(hw, EEPROM_DATA_OUT);
3089*4882a593Smuzhiyun 		eeprom_clk(hw);
3090*4882a593Smuzhiyun 	}
3091*4882a593Smuzhiyun }
3092*4882a593Smuzhiyun 
3093*4882a593Smuzhiyun #define EEPROM_DATA_RESERVED		0
3094*4882a593Smuzhiyun #define EEPROM_DATA_MAC_ADDR_0		1
3095*4882a593Smuzhiyun #define EEPROM_DATA_MAC_ADDR_1		2
3096*4882a593Smuzhiyun #define EEPROM_DATA_MAC_ADDR_2		3
3097*4882a593Smuzhiyun #define EEPROM_DATA_SUBSYS_ID		4
3098*4882a593Smuzhiyun #define EEPROM_DATA_SUBSYS_VEN_ID	5
3099*4882a593Smuzhiyun #define EEPROM_DATA_PM_CAP		6
3100*4882a593Smuzhiyun 
3101*4882a593Smuzhiyun /* User defined EEPROM data */
3102*4882a593Smuzhiyun #define EEPROM_DATA_OTHER_MAC_ADDR	9
3103*4882a593Smuzhiyun 
3104*4882a593Smuzhiyun /**
3105*4882a593Smuzhiyun  * eeprom_read - read from AT93C46 EEPROM
3106*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3107*4882a593Smuzhiyun  * @reg:	The register offset.
3108*4882a593Smuzhiyun  *
3109*4882a593Smuzhiyun  * This function reads a word from the AT93C46 EEPROM.
3110*4882a593Smuzhiyun  *
3111*4882a593Smuzhiyun  * Return the data value.
3112*4882a593Smuzhiyun  */
eeprom_read(struct ksz_hw * hw,u8 reg)3113*4882a593Smuzhiyun static u16 eeprom_read(struct ksz_hw *hw, u8 reg)
3114*4882a593Smuzhiyun {
3115*4882a593Smuzhiyun 	u16 data;
3116*4882a593Smuzhiyun 
3117*4882a593Smuzhiyun 	raise_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT);
3118*4882a593Smuzhiyun 
3119*4882a593Smuzhiyun 	spi_reg(hw, AT93C_READ, reg);
3120*4882a593Smuzhiyun 	data = spi_r(hw);
3121*4882a593Smuzhiyun 
3122*4882a593Smuzhiyun 	drop_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT);
3123*4882a593Smuzhiyun 
3124*4882a593Smuzhiyun 	return data;
3125*4882a593Smuzhiyun }
3126*4882a593Smuzhiyun 
3127*4882a593Smuzhiyun /**
3128*4882a593Smuzhiyun  * eeprom_write - write to AT93C46 EEPROM
3129*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3130*4882a593Smuzhiyun  * @reg:	The register offset.
3131*4882a593Smuzhiyun  * @data:	The data value.
3132*4882a593Smuzhiyun  *
3133*4882a593Smuzhiyun  * This procedure writes a word to the AT93C46 EEPROM.
3134*4882a593Smuzhiyun  */
eeprom_write(struct ksz_hw * hw,u8 reg,u16 data)3135*4882a593Smuzhiyun static void eeprom_write(struct ksz_hw *hw, u8 reg, u16 data)
3136*4882a593Smuzhiyun {
3137*4882a593Smuzhiyun 	int timeout;
3138*4882a593Smuzhiyun 
3139*4882a593Smuzhiyun 	raise_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT);
3140*4882a593Smuzhiyun 
3141*4882a593Smuzhiyun 	/* Enable write. */
3142*4882a593Smuzhiyun 	spi_reg(hw, AT93C_CODE, AT93C_WR_ON);
3143*4882a593Smuzhiyun 	drop_gpio(hw, EEPROM_CHIP_SELECT);
3144*4882a593Smuzhiyun 	udelay(1);
3145*4882a593Smuzhiyun 
3146*4882a593Smuzhiyun 	/* Erase the register. */
3147*4882a593Smuzhiyun 	raise_gpio(hw, EEPROM_CHIP_SELECT);
3148*4882a593Smuzhiyun 	spi_reg(hw, AT93C_ERASE, reg);
3149*4882a593Smuzhiyun 	drop_gpio(hw, EEPROM_CHIP_SELECT);
3150*4882a593Smuzhiyun 	udelay(1);
3151*4882a593Smuzhiyun 
3152*4882a593Smuzhiyun 	/* Check operation complete. */
3153*4882a593Smuzhiyun 	raise_gpio(hw, EEPROM_CHIP_SELECT);
3154*4882a593Smuzhiyun 	timeout = 8;
3155*4882a593Smuzhiyun 	mdelay(2);
3156*4882a593Smuzhiyun 	do {
3157*4882a593Smuzhiyun 		mdelay(1);
3158*4882a593Smuzhiyun 	} while (!state_gpio(hw, EEPROM_DATA_IN) && --timeout);
3159*4882a593Smuzhiyun 	drop_gpio(hw, EEPROM_CHIP_SELECT);
3160*4882a593Smuzhiyun 	udelay(1);
3161*4882a593Smuzhiyun 
3162*4882a593Smuzhiyun 	/* Write the register. */
3163*4882a593Smuzhiyun 	raise_gpio(hw, EEPROM_CHIP_SELECT);
3164*4882a593Smuzhiyun 	spi_reg(hw, AT93C_WRITE, reg);
3165*4882a593Smuzhiyun 	spi_w(hw, data);
3166*4882a593Smuzhiyun 	drop_gpio(hw, EEPROM_CHIP_SELECT);
3167*4882a593Smuzhiyun 	udelay(1);
3168*4882a593Smuzhiyun 
3169*4882a593Smuzhiyun 	/* Check operation complete. */
3170*4882a593Smuzhiyun 	raise_gpio(hw, EEPROM_CHIP_SELECT);
3171*4882a593Smuzhiyun 	timeout = 8;
3172*4882a593Smuzhiyun 	mdelay(2);
3173*4882a593Smuzhiyun 	do {
3174*4882a593Smuzhiyun 		mdelay(1);
3175*4882a593Smuzhiyun 	} while (!state_gpio(hw, EEPROM_DATA_IN) && --timeout);
3176*4882a593Smuzhiyun 	drop_gpio(hw, EEPROM_CHIP_SELECT);
3177*4882a593Smuzhiyun 	udelay(1);
3178*4882a593Smuzhiyun 
3179*4882a593Smuzhiyun 	/* Disable write. */
3180*4882a593Smuzhiyun 	raise_gpio(hw, EEPROM_CHIP_SELECT);
3181*4882a593Smuzhiyun 	spi_reg(hw, AT93C_CODE, AT93C_WR_OFF);
3182*4882a593Smuzhiyun 
3183*4882a593Smuzhiyun 	drop_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT);
3184*4882a593Smuzhiyun }
3185*4882a593Smuzhiyun 
3186*4882a593Smuzhiyun /*
3187*4882a593Smuzhiyun  * Link detection routines
3188*4882a593Smuzhiyun  */
3189*4882a593Smuzhiyun 
advertised_flow_ctrl(struct ksz_port * port,u16 ctrl)3190*4882a593Smuzhiyun static u16 advertised_flow_ctrl(struct ksz_port *port, u16 ctrl)
3191*4882a593Smuzhiyun {
3192*4882a593Smuzhiyun 	ctrl &= ~PORT_AUTO_NEG_SYM_PAUSE;
3193*4882a593Smuzhiyun 	switch (port->flow_ctrl) {
3194*4882a593Smuzhiyun 	case PHY_FLOW_CTRL:
3195*4882a593Smuzhiyun 		ctrl |= PORT_AUTO_NEG_SYM_PAUSE;
3196*4882a593Smuzhiyun 		break;
3197*4882a593Smuzhiyun 	/* Not supported. */
3198*4882a593Smuzhiyun 	case PHY_TX_ONLY:
3199*4882a593Smuzhiyun 	case PHY_RX_ONLY:
3200*4882a593Smuzhiyun 	default:
3201*4882a593Smuzhiyun 		break;
3202*4882a593Smuzhiyun 	}
3203*4882a593Smuzhiyun 	return ctrl;
3204*4882a593Smuzhiyun }
3205*4882a593Smuzhiyun 
set_flow_ctrl(struct ksz_hw * hw,int rx,int tx)3206*4882a593Smuzhiyun static void set_flow_ctrl(struct ksz_hw *hw, int rx, int tx)
3207*4882a593Smuzhiyun {
3208*4882a593Smuzhiyun 	u32 rx_cfg;
3209*4882a593Smuzhiyun 	u32 tx_cfg;
3210*4882a593Smuzhiyun 
3211*4882a593Smuzhiyun 	rx_cfg = hw->rx_cfg;
3212*4882a593Smuzhiyun 	tx_cfg = hw->tx_cfg;
3213*4882a593Smuzhiyun 	if (rx)
3214*4882a593Smuzhiyun 		hw->rx_cfg |= DMA_RX_FLOW_ENABLE;
3215*4882a593Smuzhiyun 	else
3216*4882a593Smuzhiyun 		hw->rx_cfg &= ~DMA_RX_FLOW_ENABLE;
3217*4882a593Smuzhiyun 	if (tx)
3218*4882a593Smuzhiyun 		hw->tx_cfg |= DMA_TX_FLOW_ENABLE;
3219*4882a593Smuzhiyun 	else
3220*4882a593Smuzhiyun 		hw->tx_cfg &= ~DMA_TX_FLOW_ENABLE;
3221*4882a593Smuzhiyun 	if (hw->enabled) {
3222*4882a593Smuzhiyun 		if (rx_cfg != hw->rx_cfg)
3223*4882a593Smuzhiyun 			writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL);
3224*4882a593Smuzhiyun 		if (tx_cfg != hw->tx_cfg)
3225*4882a593Smuzhiyun 			writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL);
3226*4882a593Smuzhiyun 	}
3227*4882a593Smuzhiyun }
3228*4882a593Smuzhiyun 
determine_flow_ctrl(struct ksz_hw * hw,struct ksz_port * port,u16 local,u16 remote)3229*4882a593Smuzhiyun static void determine_flow_ctrl(struct ksz_hw *hw, struct ksz_port *port,
3230*4882a593Smuzhiyun 	u16 local, u16 remote)
3231*4882a593Smuzhiyun {
3232*4882a593Smuzhiyun 	int rx;
3233*4882a593Smuzhiyun 	int tx;
3234*4882a593Smuzhiyun 
3235*4882a593Smuzhiyun 	if (hw->overrides & PAUSE_FLOW_CTRL)
3236*4882a593Smuzhiyun 		return;
3237*4882a593Smuzhiyun 
3238*4882a593Smuzhiyun 	rx = tx = 0;
3239*4882a593Smuzhiyun 	if (port->force_link)
3240*4882a593Smuzhiyun 		rx = tx = 1;
3241*4882a593Smuzhiyun 	if (remote & PHY_AUTO_NEG_SYM_PAUSE) {
3242*4882a593Smuzhiyun 		if (local & PHY_AUTO_NEG_SYM_PAUSE) {
3243*4882a593Smuzhiyun 			rx = tx = 1;
3244*4882a593Smuzhiyun 		} else if ((remote & PHY_AUTO_NEG_ASYM_PAUSE) &&
3245*4882a593Smuzhiyun 				(local & PHY_AUTO_NEG_PAUSE) ==
3246*4882a593Smuzhiyun 				PHY_AUTO_NEG_ASYM_PAUSE) {
3247*4882a593Smuzhiyun 			tx = 1;
3248*4882a593Smuzhiyun 		}
3249*4882a593Smuzhiyun 	} else if (remote & PHY_AUTO_NEG_ASYM_PAUSE) {
3250*4882a593Smuzhiyun 		if ((local & PHY_AUTO_NEG_PAUSE) == PHY_AUTO_NEG_PAUSE)
3251*4882a593Smuzhiyun 			rx = 1;
3252*4882a593Smuzhiyun 	}
3253*4882a593Smuzhiyun 	if (!hw->ksz_switch)
3254*4882a593Smuzhiyun 		set_flow_ctrl(hw, rx, tx);
3255*4882a593Smuzhiyun }
3256*4882a593Smuzhiyun 
port_cfg_change(struct ksz_hw * hw,struct ksz_port * port,struct ksz_port_info * info,u16 link_status)3257*4882a593Smuzhiyun static inline void port_cfg_change(struct ksz_hw *hw, struct ksz_port *port,
3258*4882a593Smuzhiyun 	struct ksz_port_info *info, u16 link_status)
3259*4882a593Smuzhiyun {
3260*4882a593Smuzhiyun 	if ((hw->features & HALF_DUPLEX_SIGNAL_BUG) &&
3261*4882a593Smuzhiyun 			!(hw->overrides & PAUSE_FLOW_CTRL)) {
3262*4882a593Smuzhiyun 		u32 cfg = hw->tx_cfg;
3263*4882a593Smuzhiyun 
3264*4882a593Smuzhiyun 		/* Disable flow control in the half duplex mode. */
3265*4882a593Smuzhiyun 		if (1 == info->duplex)
3266*4882a593Smuzhiyun 			hw->tx_cfg &= ~DMA_TX_FLOW_ENABLE;
3267*4882a593Smuzhiyun 		if (hw->enabled && cfg != hw->tx_cfg)
3268*4882a593Smuzhiyun 			writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL);
3269*4882a593Smuzhiyun 	}
3270*4882a593Smuzhiyun }
3271*4882a593Smuzhiyun 
3272*4882a593Smuzhiyun /**
3273*4882a593Smuzhiyun  * port_get_link_speed - get current link status
3274*4882a593Smuzhiyun  * @port: 	The port instance.
3275*4882a593Smuzhiyun  *
3276*4882a593Smuzhiyun  * This routine reads PHY registers to determine the current link status of the
3277*4882a593Smuzhiyun  * switch ports.
3278*4882a593Smuzhiyun  */
port_get_link_speed(struct ksz_port * port)3279*4882a593Smuzhiyun static void port_get_link_speed(struct ksz_port *port)
3280*4882a593Smuzhiyun {
3281*4882a593Smuzhiyun 	uint interrupt;
3282*4882a593Smuzhiyun 	struct ksz_port_info *info;
3283*4882a593Smuzhiyun 	struct ksz_port_info *linked = NULL;
3284*4882a593Smuzhiyun 	struct ksz_hw *hw = port->hw;
3285*4882a593Smuzhiyun 	u16 data;
3286*4882a593Smuzhiyun 	u16 status;
3287*4882a593Smuzhiyun 	u8 local;
3288*4882a593Smuzhiyun 	u8 remote;
3289*4882a593Smuzhiyun 	int i;
3290*4882a593Smuzhiyun 	int p;
3291*4882a593Smuzhiyun 	int change = 0;
3292*4882a593Smuzhiyun 
3293*4882a593Smuzhiyun 	interrupt = hw_block_intr(hw);
3294*4882a593Smuzhiyun 
3295*4882a593Smuzhiyun 	for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) {
3296*4882a593Smuzhiyun 		info = &hw->port_info[p];
3297*4882a593Smuzhiyun 		port_r16(hw, p, KS884X_PORT_CTRL_4_OFFSET, &data);
3298*4882a593Smuzhiyun 		port_r16(hw, p, KS884X_PORT_STATUS_OFFSET, &status);
3299*4882a593Smuzhiyun 
3300*4882a593Smuzhiyun 		/*
3301*4882a593Smuzhiyun 		 * Link status is changing all the time even when there is no
3302*4882a593Smuzhiyun 		 * cable connection!
3303*4882a593Smuzhiyun 		 */
3304*4882a593Smuzhiyun 		remote = status & (PORT_AUTO_NEG_COMPLETE |
3305*4882a593Smuzhiyun 			PORT_STATUS_LINK_GOOD);
3306*4882a593Smuzhiyun 		local = (u8) data;
3307*4882a593Smuzhiyun 
3308*4882a593Smuzhiyun 		/* No change to status. */
3309*4882a593Smuzhiyun 		if (local == info->advertised && remote == info->partner)
3310*4882a593Smuzhiyun 			continue;
3311*4882a593Smuzhiyun 
3312*4882a593Smuzhiyun 		info->advertised = local;
3313*4882a593Smuzhiyun 		info->partner = remote;
3314*4882a593Smuzhiyun 		if (status & PORT_STATUS_LINK_GOOD) {
3315*4882a593Smuzhiyun 
3316*4882a593Smuzhiyun 			/* Remember the first linked port. */
3317*4882a593Smuzhiyun 			if (!linked)
3318*4882a593Smuzhiyun 				linked = info;
3319*4882a593Smuzhiyun 
3320*4882a593Smuzhiyun 			info->tx_rate = 10 * TX_RATE_UNIT;
3321*4882a593Smuzhiyun 			if (status & PORT_STATUS_SPEED_100MBIT)
3322*4882a593Smuzhiyun 				info->tx_rate = 100 * TX_RATE_UNIT;
3323*4882a593Smuzhiyun 
3324*4882a593Smuzhiyun 			info->duplex = 1;
3325*4882a593Smuzhiyun 			if (status & PORT_STATUS_FULL_DUPLEX)
3326*4882a593Smuzhiyun 				info->duplex = 2;
3327*4882a593Smuzhiyun 
3328*4882a593Smuzhiyun 			if (media_connected != info->state) {
3329*4882a593Smuzhiyun 				hw_r_phy(hw, p, KS884X_PHY_AUTO_NEG_OFFSET,
3330*4882a593Smuzhiyun 					&data);
3331*4882a593Smuzhiyun 				hw_r_phy(hw, p, KS884X_PHY_REMOTE_CAP_OFFSET,
3332*4882a593Smuzhiyun 					&status);
3333*4882a593Smuzhiyun 				determine_flow_ctrl(hw, port, data, status);
3334*4882a593Smuzhiyun 				if (hw->ksz_switch) {
3335*4882a593Smuzhiyun 					port_cfg_back_pressure(hw, p,
3336*4882a593Smuzhiyun 						(1 == info->duplex));
3337*4882a593Smuzhiyun 				}
3338*4882a593Smuzhiyun 				change |= 1 << i;
3339*4882a593Smuzhiyun 				port_cfg_change(hw, port, info, status);
3340*4882a593Smuzhiyun 			}
3341*4882a593Smuzhiyun 			info->state = media_connected;
3342*4882a593Smuzhiyun 		} else {
3343*4882a593Smuzhiyun 			if (media_disconnected != info->state) {
3344*4882a593Smuzhiyun 				change |= 1 << i;
3345*4882a593Smuzhiyun 
3346*4882a593Smuzhiyun 				/* Indicate the link just goes down. */
3347*4882a593Smuzhiyun 				hw->port_mib[p].link_down = 1;
3348*4882a593Smuzhiyun 			}
3349*4882a593Smuzhiyun 			info->state = media_disconnected;
3350*4882a593Smuzhiyun 		}
3351*4882a593Smuzhiyun 		hw->port_mib[p].state = (u8) info->state;
3352*4882a593Smuzhiyun 	}
3353*4882a593Smuzhiyun 
3354*4882a593Smuzhiyun 	if (linked && media_disconnected == port->linked->state)
3355*4882a593Smuzhiyun 		port->linked = linked;
3356*4882a593Smuzhiyun 
3357*4882a593Smuzhiyun 	hw_restore_intr(hw, interrupt);
3358*4882a593Smuzhiyun }
3359*4882a593Smuzhiyun 
3360*4882a593Smuzhiyun #define PHY_RESET_TIMEOUT		10
3361*4882a593Smuzhiyun 
3362*4882a593Smuzhiyun /**
3363*4882a593Smuzhiyun  * port_set_link_speed - set port speed
3364*4882a593Smuzhiyun  * @port: 	The port instance.
3365*4882a593Smuzhiyun  *
3366*4882a593Smuzhiyun  * This routine sets the link speed of the switch ports.
3367*4882a593Smuzhiyun  */
port_set_link_speed(struct ksz_port * port)3368*4882a593Smuzhiyun static void port_set_link_speed(struct ksz_port *port)
3369*4882a593Smuzhiyun {
3370*4882a593Smuzhiyun 	struct ksz_hw *hw = port->hw;
3371*4882a593Smuzhiyun 	u16 data;
3372*4882a593Smuzhiyun 	u16 cfg;
3373*4882a593Smuzhiyun 	u8 status;
3374*4882a593Smuzhiyun 	int i;
3375*4882a593Smuzhiyun 	int p;
3376*4882a593Smuzhiyun 
3377*4882a593Smuzhiyun 	for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) {
3378*4882a593Smuzhiyun 		port_r16(hw, p, KS884X_PORT_CTRL_4_OFFSET, &data);
3379*4882a593Smuzhiyun 		port_r8(hw, p, KS884X_PORT_STATUS_OFFSET, &status);
3380*4882a593Smuzhiyun 
3381*4882a593Smuzhiyun 		cfg = 0;
3382*4882a593Smuzhiyun 		if (status & PORT_STATUS_LINK_GOOD)
3383*4882a593Smuzhiyun 			cfg = data;
3384*4882a593Smuzhiyun 
3385*4882a593Smuzhiyun 		data |= PORT_AUTO_NEG_ENABLE;
3386*4882a593Smuzhiyun 		data = advertised_flow_ctrl(port, data);
3387*4882a593Smuzhiyun 
3388*4882a593Smuzhiyun 		data |= PORT_AUTO_NEG_100BTX_FD | PORT_AUTO_NEG_100BTX |
3389*4882a593Smuzhiyun 			PORT_AUTO_NEG_10BT_FD | PORT_AUTO_NEG_10BT;
3390*4882a593Smuzhiyun 
3391*4882a593Smuzhiyun 		/* Check if manual configuration is specified by the user. */
3392*4882a593Smuzhiyun 		if (port->speed || port->duplex) {
3393*4882a593Smuzhiyun 			if (10 == port->speed)
3394*4882a593Smuzhiyun 				data &= ~(PORT_AUTO_NEG_100BTX_FD |
3395*4882a593Smuzhiyun 					PORT_AUTO_NEG_100BTX);
3396*4882a593Smuzhiyun 			else if (100 == port->speed)
3397*4882a593Smuzhiyun 				data &= ~(PORT_AUTO_NEG_10BT_FD |
3398*4882a593Smuzhiyun 					PORT_AUTO_NEG_10BT);
3399*4882a593Smuzhiyun 			if (1 == port->duplex)
3400*4882a593Smuzhiyun 				data &= ~(PORT_AUTO_NEG_100BTX_FD |
3401*4882a593Smuzhiyun 					PORT_AUTO_NEG_10BT_FD);
3402*4882a593Smuzhiyun 			else if (2 == port->duplex)
3403*4882a593Smuzhiyun 				data &= ~(PORT_AUTO_NEG_100BTX |
3404*4882a593Smuzhiyun 					PORT_AUTO_NEG_10BT);
3405*4882a593Smuzhiyun 		}
3406*4882a593Smuzhiyun 		if (data != cfg) {
3407*4882a593Smuzhiyun 			data |= PORT_AUTO_NEG_RESTART;
3408*4882a593Smuzhiyun 			port_w16(hw, p, KS884X_PORT_CTRL_4_OFFSET, data);
3409*4882a593Smuzhiyun 		}
3410*4882a593Smuzhiyun 	}
3411*4882a593Smuzhiyun }
3412*4882a593Smuzhiyun 
3413*4882a593Smuzhiyun /**
3414*4882a593Smuzhiyun  * port_force_link_speed - force port speed
3415*4882a593Smuzhiyun  * @port: 	The port instance.
3416*4882a593Smuzhiyun  *
3417*4882a593Smuzhiyun  * This routine forces the link speed of the switch ports.
3418*4882a593Smuzhiyun  */
port_force_link_speed(struct ksz_port * port)3419*4882a593Smuzhiyun static void port_force_link_speed(struct ksz_port *port)
3420*4882a593Smuzhiyun {
3421*4882a593Smuzhiyun 	struct ksz_hw *hw = port->hw;
3422*4882a593Smuzhiyun 	u16 data;
3423*4882a593Smuzhiyun 	int i;
3424*4882a593Smuzhiyun 	int phy;
3425*4882a593Smuzhiyun 	int p;
3426*4882a593Smuzhiyun 
3427*4882a593Smuzhiyun 	for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) {
3428*4882a593Smuzhiyun 		phy = KS884X_PHY_1_CTRL_OFFSET + p * PHY_CTRL_INTERVAL;
3429*4882a593Smuzhiyun 		hw_r_phy_ctrl(hw, phy, &data);
3430*4882a593Smuzhiyun 
3431*4882a593Smuzhiyun 		data &= ~PHY_AUTO_NEG_ENABLE;
3432*4882a593Smuzhiyun 
3433*4882a593Smuzhiyun 		if (10 == port->speed)
3434*4882a593Smuzhiyun 			data &= ~PHY_SPEED_100MBIT;
3435*4882a593Smuzhiyun 		else if (100 == port->speed)
3436*4882a593Smuzhiyun 			data |= PHY_SPEED_100MBIT;
3437*4882a593Smuzhiyun 		if (1 == port->duplex)
3438*4882a593Smuzhiyun 			data &= ~PHY_FULL_DUPLEX;
3439*4882a593Smuzhiyun 		else if (2 == port->duplex)
3440*4882a593Smuzhiyun 			data |= PHY_FULL_DUPLEX;
3441*4882a593Smuzhiyun 		hw_w_phy_ctrl(hw, phy, data);
3442*4882a593Smuzhiyun 	}
3443*4882a593Smuzhiyun }
3444*4882a593Smuzhiyun 
port_set_power_saving(struct ksz_port * port,int enable)3445*4882a593Smuzhiyun static void port_set_power_saving(struct ksz_port *port, int enable)
3446*4882a593Smuzhiyun {
3447*4882a593Smuzhiyun 	struct ksz_hw *hw = port->hw;
3448*4882a593Smuzhiyun 	int i;
3449*4882a593Smuzhiyun 	int p;
3450*4882a593Smuzhiyun 
3451*4882a593Smuzhiyun 	for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++)
3452*4882a593Smuzhiyun 		port_cfg(hw, p,
3453*4882a593Smuzhiyun 			KS884X_PORT_CTRL_4_OFFSET, PORT_POWER_DOWN, enable);
3454*4882a593Smuzhiyun }
3455*4882a593Smuzhiyun 
3456*4882a593Smuzhiyun /*
3457*4882a593Smuzhiyun  * KSZ8841 power management functions
3458*4882a593Smuzhiyun  */
3459*4882a593Smuzhiyun 
3460*4882a593Smuzhiyun /**
3461*4882a593Smuzhiyun  * hw_chk_wol_pme_status - check PMEN pin
3462*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3463*4882a593Smuzhiyun  *
3464*4882a593Smuzhiyun  * This function is used to check PMEN pin is asserted.
3465*4882a593Smuzhiyun  *
3466*4882a593Smuzhiyun  * Return 1 if PMEN pin is asserted; otherwise, 0.
3467*4882a593Smuzhiyun  */
hw_chk_wol_pme_status(struct ksz_hw * hw)3468*4882a593Smuzhiyun static int hw_chk_wol_pme_status(struct ksz_hw *hw)
3469*4882a593Smuzhiyun {
3470*4882a593Smuzhiyun 	struct dev_info *hw_priv = container_of(hw, struct dev_info, hw);
3471*4882a593Smuzhiyun 	struct pci_dev *pdev = hw_priv->pdev;
3472*4882a593Smuzhiyun 	u16 data;
3473*4882a593Smuzhiyun 
3474*4882a593Smuzhiyun 	if (!pdev->pm_cap)
3475*4882a593Smuzhiyun 		return 0;
3476*4882a593Smuzhiyun 	pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data);
3477*4882a593Smuzhiyun 	return (data & PCI_PM_CTRL_PME_STATUS) == PCI_PM_CTRL_PME_STATUS;
3478*4882a593Smuzhiyun }
3479*4882a593Smuzhiyun 
3480*4882a593Smuzhiyun /**
3481*4882a593Smuzhiyun  * hw_clr_wol_pme_status - clear PMEN pin
3482*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3483*4882a593Smuzhiyun  *
3484*4882a593Smuzhiyun  * This routine is used to clear PME_Status to deassert PMEN pin.
3485*4882a593Smuzhiyun  */
hw_clr_wol_pme_status(struct ksz_hw * hw)3486*4882a593Smuzhiyun static void hw_clr_wol_pme_status(struct ksz_hw *hw)
3487*4882a593Smuzhiyun {
3488*4882a593Smuzhiyun 	struct dev_info *hw_priv = container_of(hw, struct dev_info, hw);
3489*4882a593Smuzhiyun 	struct pci_dev *pdev = hw_priv->pdev;
3490*4882a593Smuzhiyun 	u16 data;
3491*4882a593Smuzhiyun 
3492*4882a593Smuzhiyun 	if (!pdev->pm_cap)
3493*4882a593Smuzhiyun 		return;
3494*4882a593Smuzhiyun 
3495*4882a593Smuzhiyun 	/* Clear PME_Status to deassert PMEN pin. */
3496*4882a593Smuzhiyun 	pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data);
3497*4882a593Smuzhiyun 	data |= PCI_PM_CTRL_PME_STATUS;
3498*4882a593Smuzhiyun 	pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, data);
3499*4882a593Smuzhiyun }
3500*4882a593Smuzhiyun 
3501*4882a593Smuzhiyun /**
3502*4882a593Smuzhiyun  * hw_cfg_wol_pme - enable or disable Wake-on-LAN
3503*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3504*4882a593Smuzhiyun  * @set:	The flag indicating whether to enable or disable.
3505*4882a593Smuzhiyun  *
3506*4882a593Smuzhiyun  * This routine is used to enable or disable Wake-on-LAN.
3507*4882a593Smuzhiyun  */
hw_cfg_wol_pme(struct ksz_hw * hw,int set)3508*4882a593Smuzhiyun static void hw_cfg_wol_pme(struct ksz_hw *hw, int set)
3509*4882a593Smuzhiyun {
3510*4882a593Smuzhiyun 	struct dev_info *hw_priv = container_of(hw, struct dev_info, hw);
3511*4882a593Smuzhiyun 	struct pci_dev *pdev = hw_priv->pdev;
3512*4882a593Smuzhiyun 	u16 data;
3513*4882a593Smuzhiyun 
3514*4882a593Smuzhiyun 	if (!pdev->pm_cap)
3515*4882a593Smuzhiyun 		return;
3516*4882a593Smuzhiyun 	pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data);
3517*4882a593Smuzhiyun 	data &= ~PCI_PM_CTRL_STATE_MASK;
3518*4882a593Smuzhiyun 	if (set)
3519*4882a593Smuzhiyun 		data |= PCI_PM_CTRL_PME_ENABLE | PCI_D3hot;
3520*4882a593Smuzhiyun 	else
3521*4882a593Smuzhiyun 		data &= ~PCI_PM_CTRL_PME_ENABLE;
3522*4882a593Smuzhiyun 	pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, data);
3523*4882a593Smuzhiyun }
3524*4882a593Smuzhiyun 
3525*4882a593Smuzhiyun /**
3526*4882a593Smuzhiyun  * hw_cfg_wol - configure Wake-on-LAN features
3527*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3528*4882a593Smuzhiyun  * @frame:	The pattern frame bit.
3529*4882a593Smuzhiyun  * @set:	The flag indicating whether to enable or disable.
3530*4882a593Smuzhiyun  *
3531*4882a593Smuzhiyun  * This routine is used to enable or disable certain Wake-on-LAN features.
3532*4882a593Smuzhiyun  */
hw_cfg_wol(struct ksz_hw * hw,u16 frame,int set)3533*4882a593Smuzhiyun static void hw_cfg_wol(struct ksz_hw *hw, u16 frame, int set)
3534*4882a593Smuzhiyun {
3535*4882a593Smuzhiyun 	u16 data;
3536*4882a593Smuzhiyun 
3537*4882a593Smuzhiyun 	data = readw(hw->io + KS8841_WOL_CTRL_OFFSET);
3538*4882a593Smuzhiyun 	if (set)
3539*4882a593Smuzhiyun 		data |= frame;
3540*4882a593Smuzhiyun 	else
3541*4882a593Smuzhiyun 		data &= ~frame;
3542*4882a593Smuzhiyun 	writew(data, hw->io + KS8841_WOL_CTRL_OFFSET);
3543*4882a593Smuzhiyun }
3544*4882a593Smuzhiyun 
3545*4882a593Smuzhiyun /**
3546*4882a593Smuzhiyun  * hw_set_wol_frame - program Wake-on-LAN pattern
3547*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3548*4882a593Smuzhiyun  * @i:		The frame index.
3549*4882a593Smuzhiyun  * @mask_size:	The size of the mask.
3550*4882a593Smuzhiyun  * @mask:	Mask to ignore certain bytes in the pattern.
3551*4882a593Smuzhiyun  * @frame_size:	The size of the frame.
3552*4882a593Smuzhiyun  * @pattern:	The frame data.
3553*4882a593Smuzhiyun  *
3554*4882a593Smuzhiyun  * This routine is used to program Wake-on-LAN pattern.
3555*4882a593Smuzhiyun  */
hw_set_wol_frame(struct ksz_hw * hw,int i,uint mask_size,const u8 * mask,uint frame_size,const u8 * pattern)3556*4882a593Smuzhiyun static void hw_set_wol_frame(struct ksz_hw *hw, int i, uint mask_size,
3557*4882a593Smuzhiyun 	const u8 *mask, uint frame_size, const u8 *pattern)
3558*4882a593Smuzhiyun {
3559*4882a593Smuzhiyun 	int bits;
3560*4882a593Smuzhiyun 	int from;
3561*4882a593Smuzhiyun 	int len;
3562*4882a593Smuzhiyun 	int to;
3563*4882a593Smuzhiyun 	u32 crc;
3564*4882a593Smuzhiyun 	u8 data[64];
3565*4882a593Smuzhiyun 	u8 val = 0;
3566*4882a593Smuzhiyun 
3567*4882a593Smuzhiyun 	if (frame_size > mask_size * 8)
3568*4882a593Smuzhiyun 		frame_size = mask_size * 8;
3569*4882a593Smuzhiyun 	if (frame_size > 64)
3570*4882a593Smuzhiyun 		frame_size = 64;
3571*4882a593Smuzhiyun 
3572*4882a593Smuzhiyun 	i *= 0x10;
3573*4882a593Smuzhiyun 	writel(0, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i);
3574*4882a593Smuzhiyun 	writel(0, hw->io + KS8841_WOL_FRAME_BYTE2_OFFSET + i);
3575*4882a593Smuzhiyun 
3576*4882a593Smuzhiyun 	bits = len = from = to = 0;
3577*4882a593Smuzhiyun 	do {
3578*4882a593Smuzhiyun 		if (bits) {
3579*4882a593Smuzhiyun 			if ((val & 1))
3580*4882a593Smuzhiyun 				data[to++] = pattern[from];
3581*4882a593Smuzhiyun 			val >>= 1;
3582*4882a593Smuzhiyun 			++from;
3583*4882a593Smuzhiyun 			--bits;
3584*4882a593Smuzhiyun 		} else {
3585*4882a593Smuzhiyun 			val = mask[len];
3586*4882a593Smuzhiyun 			writeb(val, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i
3587*4882a593Smuzhiyun 				+ len);
3588*4882a593Smuzhiyun 			++len;
3589*4882a593Smuzhiyun 			if (val)
3590*4882a593Smuzhiyun 				bits = 8;
3591*4882a593Smuzhiyun 			else
3592*4882a593Smuzhiyun 				from += 8;
3593*4882a593Smuzhiyun 		}
3594*4882a593Smuzhiyun 	} while (from < (int) frame_size);
3595*4882a593Smuzhiyun 	if (val) {
3596*4882a593Smuzhiyun 		bits = mask[len - 1];
3597*4882a593Smuzhiyun 		val <<= (from % 8);
3598*4882a593Smuzhiyun 		bits &= ~val;
3599*4882a593Smuzhiyun 		writeb(bits, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i + len -
3600*4882a593Smuzhiyun 			1);
3601*4882a593Smuzhiyun 	}
3602*4882a593Smuzhiyun 	crc = ether_crc(to, data);
3603*4882a593Smuzhiyun 	writel(crc, hw->io + KS8841_WOL_FRAME_CRC_OFFSET + i);
3604*4882a593Smuzhiyun }
3605*4882a593Smuzhiyun 
3606*4882a593Smuzhiyun /**
3607*4882a593Smuzhiyun  * hw_add_wol_arp - add ARP pattern
3608*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3609*4882a593Smuzhiyun  * @ip_addr:	The IPv4 address assigned to the device.
3610*4882a593Smuzhiyun  *
3611*4882a593Smuzhiyun  * This routine is used to add ARP pattern for waking up the host.
3612*4882a593Smuzhiyun  */
hw_add_wol_arp(struct ksz_hw * hw,const u8 * ip_addr)3613*4882a593Smuzhiyun static void hw_add_wol_arp(struct ksz_hw *hw, const u8 *ip_addr)
3614*4882a593Smuzhiyun {
3615*4882a593Smuzhiyun 	static const u8 mask[6] = { 0x3F, 0xF0, 0x3F, 0x00, 0xC0, 0x03 };
3616*4882a593Smuzhiyun 	u8 pattern[42] = {
3617*4882a593Smuzhiyun 		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
3618*4882a593Smuzhiyun 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3619*4882a593Smuzhiyun 		0x08, 0x06,
3620*4882a593Smuzhiyun 		0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01,
3621*4882a593Smuzhiyun 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3622*4882a593Smuzhiyun 		0x00, 0x00, 0x00, 0x00,
3623*4882a593Smuzhiyun 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3624*4882a593Smuzhiyun 		0x00, 0x00, 0x00, 0x00 };
3625*4882a593Smuzhiyun 
3626*4882a593Smuzhiyun 	memcpy(&pattern[38], ip_addr, 4);
3627*4882a593Smuzhiyun 	hw_set_wol_frame(hw, 3, 6, mask, 42, pattern);
3628*4882a593Smuzhiyun }
3629*4882a593Smuzhiyun 
3630*4882a593Smuzhiyun /**
3631*4882a593Smuzhiyun  * hw_add_wol_bcast - add broadcast pattern
3632*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3633*4882a593Smuzhiyun  *
3634*4882a593Smuzhiyun  * This routine is used to add broadcast pattern for waking up the host.
3635*4882a593Smuzhiyun  */
hw_add_wol_bcast(struct ksz_hw * hw)3636*4882a593Smuzhiyun static void hw_add_wol_bcast(struct ksz_hw *hw)
3637*4882a593Smuzhiyun {
3638*4882a593Smuzhiyun 	static const u8 mask[] = { 0x3F };
3639*4882a593Smuzhiyun 	static const u8 pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
3640*4882a593Smuzhiyun 
3641*4882a593Smuzhiyun 	hw_set_wol_frame(hw, 2, 1, mask, ETH_ALEN, pattern);
3642*4882a593Smuzhiyun }
3643*4882a593Smuzhiyun 
3644*4882a593Smuzhiyun /**
3645*4882a593Smuzhiyun  * hw_add_wol_mcast - add multicast pattern
3646*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3647*4882a593Smuzhiyun  *
3648*4882a593Smuzhiyun  * This routine is used to add multicast pattern for waking up the host.
3649*4882a593Smuzhiyun  *
3650*4882a593Smuzhiyun  * It is assumed the multicast packet is the ICMPv6 neighbor solicitation used
3651*4882a593Smuzhiyun  * by IPv6 ping command.  Note that multicast packets are filtred through the
3652*4882a593Smuzhiyun  * multicast hash table, so not all multicast packets can wake up the host.
3653*4882a593Smuzhiyun  */
hw_add_wol_mcast(struct ksz_hw * hw)3654*4882a593Smuzhiyun static void hw_add_wol_mcast(struct ksz_hw *hw)
3655*4882a593Smuzhiyun {
3656*4882a593Smuzhiyun 	static const u8 mask[] = { 0x3F };
3657*4882a593Smuzhiyun 	u8 pattern[] = { 0x33, 0x33, 0xFF, 0x00, 0x00, 0x00 };
3658*4882a593Smuzhiyun 
3659*4882a593Smuzhiyun 	memcpy(&pattern[3], &hw->override_addr[3], 3);
3660*4882a593Smuzhiyun 	hw_set_wol_frame(hw, 1, 1, mask, 6, pattern);
3661*4882a593Smuzhiyun }
3662*4882a593Smuzhiyun 
3663*4882a593Smuzhiyun /**
3664*4882a593Smuzhiyun  * hw_add_wol_ucast - add unicast pattern
3665*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3666*4882a593Smuzhiyun  *
3667*4882a593Smuzhiyun  * This routine is used to add unicast pattern to wakeup the host.
3668*4882a593Smuzhiyun  *
3669*4882a593Smuzhiyun  * It is assumed the unicast packet is directed to the device, as the hardware
3670*4882a593Smuzhiyun  * can only receive them in normal case.
3671*4882a593Smuzhiyun  */
hw_add_wol_ucast(struct ksz_hw * hw)3672*4882a593Smuzhiyun static void hw_add_wol_ucast(struct ksz_hw *hw)
3673*4882a593Smuzhiyun {
3674*4882a593Smuzhiyun 	static const u8 mask[] = { 0x3F };
3675*4882a593Smuzhiyun 
3676*4882a593Smuzhiyun 	hw_set_wol_frame(hw, 0, 1, mask, ETH_ALEN, hw->override_addr);
3677*4882a593Smuzhiyun }
3678*4882a593Smuzhiyun 
3679*4882a593Smuzhiyun /**
3680*4882a593Smuzhiyun  * hw_enable_wol - enable Wake-on-LAN
3681*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3682*4882a593Smuzhiyun  * @wol_enable:	The Wake-on-LAN settings.
3683*4882a593Smuzhiyun  * @net_addr:	The IPv4 address assigned to the device.
3684*4882a593Smuzhiyun  *
3685*4882a593Smuzhiyun  * This routine is used to enable Wake-on-LAN depending on driver settings.
3686*4882a593Smuzhiyun  */
hw_enable_wol(struct ksz_hw * hw,u32 wol_enable,const u8 * net_addr)3687*4882a593Smuzhiyun static void hw_enable_wol(struct ksz_hw *hw, u32 wol_enable, const u8 *net_addr)
3688*4882a593Smuzhiyun {
3689*4882a593Smuzhiyun 	hw_cfg_wol(hw, KS8841_WOL_MAGIC_ENABLE, (wol_enable & WAKE_MAGIC));
3690*4882a593Smuzhiyun 	hw_cfg_wol(hw, KS8841_WOL_FRAME0_ENABLE, (wol_enable & WAKE_UCAST));
3691*4882a593Smuzhiyun 	hw_add_wol_ucast(hw);
3692*4882a593Smuzhiyun 	hw_cfg_wol(hw, KS8841_WOL_FRAME1_ENABLE, (wol_enable & WAKE_MCAST));
3693*4882a593Smuzhiyun 	hw_add_wol_mcast(hw);
3694*4882a593Smuzhiyun 	hw_cfg_wol(hw, KS8841_WOL_FRAME2_ENABLE, (wol_enable & WAKE_BCAST));
3695*4882a593Smuzhiyun 	hw_cfg_wol(hw, KS8841_WOL_FRAME3_ENABLE, (wol_enable & WAKE_ARP));
3696*4882a593Smuzhiyun 	hw_add_wol_arp(hw, net_addr);
3697*4882a593Smuzhiyun }
3698*4882a593Smuzhiyun 
3699*4882a593Smuzhiyun /**
3700*4882a593Smuzhiyun  * hw_init - check driver is correct for the hardware
3701*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3702*4882a593Smuzhiyun  *
3703*4882a593Smuzhiyun  * This function checks the hardware is correct for this driver and sets the
3704*4882a593Smuzhiyun  * hardware up for proper initialization.
3705*4882a593Smuzhiyun  *
3706*4882a593Smuzhiyun  * Return number of ports or 0 if not right.
3707*4882a593Smuzhiyun  */
hw_init(struct ksz_hw * hw)3708*4882a593Smuzhiyun static int hw_init(struct ksz_hw *hw)
3709*4882a593Smuzhiyun {
3710*4882a593Smuzhiyun 	int rc = 0;
3711*4882a593Smuzhiyun 	u16 data;
3712*4882a593Smuzhiyun 	u16 revision;
3713*4882a593Smuzhiyun 
3714*4882a593Smuzhiyun 	/* Set bus speed to 125MHz. */
3715*4882a593Smuzhiyun 	writew(BUS_SPEED_125_MHZ, hw->io + KS884X_BUS_CTRL_OFFSET);
3716*4882a593Smuzhiyun 
3717*4882a593Smuzhiyun 	/* Check KSZ884x chip ID. */
3718*4882a593Smuzhiyun 	data = readw(hw->io + KS884X_CHIP_ID_OFFSET);
3719*4882a593Smuzhiyun 
3720*4882a593Smuzhiyun 	revision = (data & KS884X_REVISION_MASK) >> KS884X_REVISION_SHIFT;
3721*4882a593Smuzhiyun 	data &= KS884X_CHIP_ID_MASK_41;
3722*4882a593Smuzhiyun 	if (REG_CHIP_ID_41 == data)
3723*4882a593Smuzhiyun 		rc = 1;
3724*4882a593Smuzhiyun 	else if (REG_CHIP_ID_42 == data)
3725*4882a593Smuzhiyun 		rc = 2;
3726*4882a593Smuzhiyun 	else
3727*4882a593Smuzhiyun 		return 0;
3728*4882a593Smuzhiyun 
3729*4882a593Smuzhiyun 	/* Setup hardware features or bug workarounds. */
3730*4882a593Smuzhiyun 	if (revision <= 1) {
3731*4882a593Smuzhiyun 		hw->features |= SMALL_PACKET_TX_BUG;
3732*4882a593Smuzhiyun 		if (1 == rc)
3733*4882a593Smuzhiyun 			hw->features |= HALF_DUPLEX_SIGNAL_BUG;
3734*4882a593Smuzhiyun 	}
3735*4882a593Smuzhiyun 	return rc;
3736*4882a593Smuzhiyun }
3737*4882a593Smuzhiyun 
3738*4882a593Smuzhiyun /**
3739*4882a593Smuzhiyun  * hw_reset - reset the hardware
3740*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3741*4882a593Smuzhiyun  *
3742*4882a593Smuzhiyun  * This routine resets the hardware.
3743*4882a593Smuzhiyun  */
hw_reset(struct ksz_hw * hw)3744*4882a593Smuzhiyun static void hw_reset(struct ksz_hw *hw)
3745*4882a593Smuzhiyun {
3746*4882a593Smuzhiyun 	writew(GLOBAL_SOFTWARE_RESET, hw->io + KS884X_GLOBAL_CTRL_OFFSET);
3747*4882a593Smuzhiyun 
3748*4882a593Smuzhiyun 	/* Wait for device to reset. */
3749*4882a593Smuzhiyun 	mdelay(10);
3750*4882a593Smuzhiyun 
3751*4882a593Smuzhiyun 	/* Write 0 to clear device reset. */
3752*4882a593Smuzhiyun 	writew(0, hw->io + KS884X_GLOBAL_CTRL_OFFSET);
3753*4882a593Smuzhiyun }
3754*4882a593Smuzhiyun 
3755*4882a593Smuzhiyun /**
3756*4882a593Smuzhiyun  * hw_setup - setup the hardware
3757*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3758*4882a593Smuzhiyun  *
3759*4882a593Smuzhiyun  * This routine setup the hardware for proper operation.
3760*4882a593Smuzhiyun  */
hw_setup(struct ksz_hw * hw)3761*4882a593Smuzhiyun static void hw_setup(struct ksz_hw *hw)
3762*4882a593Smuzhiyun {
3763*4882a593Smuzhiyun #if SET_DEFAULT_LED
3764*4882a593Smuzhiyun 	u16 data;
3765*4882a593Smuzhiyun 
3766*4882a593Smuzhiyun 	/* Change default LED mode. */
3767*4882a593Smuzhiyun 	data = readw(hw->io + KS8842_SWITCH_CTRL_5_OFFSET);
3768*4882a593Smuzhiyun 	data &= ~LED_MODE;
3769*4882a593Smuzhiyun 	data |= SET_DEFAULT_LED;
3770*4882a593Smuzhiyun 	writew(data, hw->io + KS8842_SWITCH_CTRL_5_OFFSET);
3771*4882a593Smuzhiyun #endif
3772*4882a593Smuzhiyun 
3773*4882a593Smuzhiyun 	/* Setup transmit control. */
3774*4882a593Smuzhiyun 	hw->tx_cfg = (DMA_TX_PAD_ENABLE | DMA_TX_CRC_ENABLE |
3775*4882a593Smuzhiyun 		(DMA_BURST_DEFAULT << DMA_BURST_SHIFT) | DMA_TX_ENABLE);
3776*4882a593Smuzhiyun 
3777*4882a593Smuzhiyun 	/* Setup receive control. */
3778*4882a593Smuzhiyun 	hw->rx_cfg = (DMA_RX_BROADCAST | DMA_RX_UNICAST |
3779*4882a593Smuzhiyun 		(DMA_BURST_DEFAULT << DMA_BURST_SHIFT) | DMA_RX_ENABLE);
3780*4882a593Smuzhiyun 	hw->rx_cfg |= KS884X_DMA_RX_MULTICAST;
3781*4882a593Smuzhiyun 
3782*4882a593Smuzhiyun 	/* Hardware cannot handle UDP packet in IP fragments. */
3783*4882a593Smuzhiyun 	hw->rx_cfg |= (DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP);
3784*4882a593Smuzhiyun 
3785*4882a593Smuzhiyun 	if (hw->all_multi)
3786*4882a593Smuzhiyun 		hw->rx_cfg |= DMA_RX_ALL_MULTICAST;
3787*4882a593Smuzhiyun 	if (hw->promiscuous)
3788*4882a593Smuzhiyun 		hw->rx_cfg |= DMA_RX_PROMISCUOUS;
3789*4882a593Smuzhiyun }
3790*4882a593Smuzhiyun 
3791*4882a593Smuzhiyun /**
3792*4882a593Smuzhiyun  * hw_setup_intr - setup interrupt mask
3793*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3794*4882a593Smuzhiyun  *
3795*4882a593Smuzhiyun  * This routine setup the interrupt mask for proper operation.
3796*4882a593Smuzhiyun  */
hw_setup_intr(struct ksz_hw * hw)3797*4882a593Smuzhiyun static void hw_setup_intr(struct ksz_hw *hw)
3798*4882a593Smuzhiyun {
3799*4882a593Smuzhiyun 	hw->intr_mask = KS884X_INT_MASK | KS884X_INT_RX_OVERRUN;
3800*4882a593Smuzhiyun }
3801*4882a593Smuzhiyun 
ksz_check_desc_num(struct ksz_desc_info * info)3802*4882a593Smuzhiyun static void ksz_check_desc_num(struct ksz_desc_info *info)
3803*4882a593Smuzhiyun {
3804*4882a593Smuzhiyun #define MIN_DESC_SHIFT  2
3805*4882a593Smuzhiyun 
3806*4882a593Smuzhiyun 	int alloc = info->alloc;
3807*4882a593Smuzhiyun 	int shift;
3808*4882a593Smuzhiyun 
3809*4882a593Smuzhiyun 	shift = 0;
3810*4882a593Smuzhiyun 	while (!(alloc & 1)) {
3811*4882a593Smuzhiyun 		shift++;
3812*4882a593Smuzhiyun 		alloc >>= 1;
3813*4882a593Smuzhiyun 	}
3814*4882a593Smuzhiyun 	if (alloc != 1 || shift < MIN_DESC_SHIFT) {
3815*4882a593Smuzhiyun 		pr_alert("Hardware descriptor numbers not right!\n");
3816*4882a593Smuzhiyun 		while (alloc) {
3817*4882a593Smuzhiyun 			shift++;
3818*4882a593Smuzhiyun 			alloc >>= 1;
3819*4882a593Smuzhiyun 		}
3820*4882a593Smuzhiyun 		if (shift < MIN_DESC_SHIFT)
3821*4882a593Smuzhiyun 			shift = MIN_DESC_SHIFT;
3822*4882a593Smuzhiyun 		alloc = 1 << shift;
3823*4882a593Smuzhiyun 		info->alloc = alloc;
3824*4882a593Smuzhiyun 	}
3825*4882a593Smuzhiyun 	info->mask = info->alloc - 1;
3826*4882a593Smuzhiyun }
3827*4882a593Smuzhiyun 
hw_init_desc(struct ksz_desc_info * desc_info,int transmit)3828*4882a593Smuzhiyun static void hw_init_desc(struct ksz_desc_info *desc_info, int transmit)
3829*4882a593Smuzhiyun {
3830*4882a593Smuzhiyun 	int i;
3831*4882a593Smuzhiyun 	u32 phys = desc_info->ring_phys;
3832*4882a593Smuzhiyun 	struct ksz_hw_desc *desc = desc_info->ring_virt;
3833*4882a593Smuzhiyun 	struct ksz_desc *cur = desc_info->ring;
3834*4882a593Smuzhiyun 	struct ksz_desc *previous = NULL;
3835*4882a593Smuzhiyun 
3836*4882a593Smuzhiyun 	for (i = 0; i < desc_info->alloc; i++) {
3837*4882a593Smuzhiyun 		cur->phw = desc++;
3838*4882a593Smuzhiyun 		phys += desc_info->size;
3839*4882a593Smuzhiyun 		previous = cur++;
3840*4882a593Smuzhiyun 		previous->phw->next = cpu_to_le32(phys);
3841*4882a593Smuzhiyun 	}
3842*4882a593Smuzhiyun 	previous->phw->next = cpu_to_le32(desc_info->ring_phys);
3843*4882a593Smuzhiyun 	previous->sw.buf.rx.end_of_ring = 1;
3844*4882a593Smuzhiyun 	previous->phw->buf.data = cpu_to_le32(previous->sw.buf.data);
3845*4882a593Smuzhiyun 
3846*4882a593Smuzhiyun 	desc_info->avail = desc_info->alloc;
3847*4882a593Smuzhiyun 	desc_info->last = desc_info->next = 0;
3848*4882a593Smuzhiyun 
3849*4882a593Smuzhiyun 	desc_info->cur = desc_info->ring;
3850*4882a593Smuzhiyun }
3851*4882a593Smuzhiyun 
3852*4882a593Smuzhiyun /**
3853*4882a593Smuzhiyun  * hw_set_desc_base - set descriptor base addresses
3854*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3855*4882a593Smuzhiyun  * @tx_addr:	The transmit descriptor base.
3856*4882a593Smuzhiyun  * @rx_addr:	The receive descriptor base.
3857*4882a593Smuzhiyun  *
3858*4882a593Smuzhiyun  * This routine programs the descriptor base addresses after reset.
3859*4882a593Smuzhiyun  */
hw_set_desc_base(struct ksz_hw * hw,u32 tx_addr,u32 rx_addr)3860*4882a593Smuzhiyun static void hw_set_desc_base(struct ksz_hw *hw, u32 tx_addr, u32 rx_addr)
3861*4882a593Smuzhiyun {
3862*4882a593Smuzhiyun 	/* Set base address of Tx/Rx descriptors. */
3863*4882a593Smuzhiyun 	writel(tx_addr, hw->io + KS_DMA_TX_ADDR);
3864*4882a593Smuzhiyun 	writel(rx_addr, hw->io + KS_DMA_RX_ADDR);
3865*4882a593Smuzhiyun }
3866*4882a593Smuzhiyun 
hw_reset_pkts(struct ksz_desc_info * info)3867*4882a593Smuzhiyun static void hw_reset_pkts(struct ksz_desc_info *info)
3868*4882a593Smuzhiyun {
3869*4882a593Smuzhiyun 	info->cur = info->ring;
3870*4882a593Smuzhiyun 	info->avail = info->alloc;
3871*4882a593Smuzhiyun 	info->last = info->next = 0;
3872*4882a593Smuzhiyun }
3873*4882a593Smuzhiyun 
hw_resume_rx(struct ksz_hw * hw)3874*4882a593Smuzhiyun static inline void hw_resume_rx(struct ksz_hw *hw)
3875*4882a593Smuzhiyun {
3876*4882a593Smuzhiyun 	writel(DMA_START, hw->io + KS_DMA_RX_START);
3877*4882a593Smuzhiyun }
3878*4882a593Smuzhiyun 
3879*4882a593Smuzhiyun /**
3880*4882a593Smuzhiyun  * hw_start_rx - start receiving
3881*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3882*4882a593Smuzhiyun  *
3883*4882a593Smuzhiyun  * This routine starts the receive function of the hardware.
3884*4882a593Smuzhiyun  */
hw_start_rx(struct ksz_hw * hw)3885*4882a593Smuzhiyun static void hw_start_rx(struct ksz_hw *hw)
3886*4882a593Smuzhiyun {
3887*4882a593Smuzhiyun 	writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL);
3888*4882a593Smuzhiyun 
3889*4882a593Smuzhiyun 	/* Notify when the receive stops. */
3890*4882a593Smuzhiyun 	hw->intr_mask |= KS884X_INT_RX_STOPPED;
3891*4882a593Smuzhiyun 
3892*4882a593Smuzhiyun 	writel(DMA_START, hw->io + KS_DMA_RX_START);
3893*4882a593Smuzhiyun 	hw_ack_intr(hw, KS884X_INT_RX_STOPPED);
3894*4882a593Smuzhiyun 	hw->rx_stop++;
3895*4882a593Smuzhiyun 
3896*4882a593Smuzhiyun 	/* Variable overflows. */
3897*4882a593Smuzhiyun 	if (0 == hw->rx_stop)
3898*4882a593Smuzhiyun 		hw->rx_stop = 2;
3899*4882a593Smuzhiyun }
3900*4882a593Smuzhiyun 
3901*4882a593Smuzhiyun /**
3902*4882a593Smuzhiyun  * hw_stop_rx - stop receiving
3903*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3904*4882a593Smuzhiyun  *
3905*4882a593Smuzhiyun  * This routine stops the receive function of the hardware.
3906*4882a593Smuzhiyun  */
hw_stop_rx(struct ksz_hw * hw)3907*4882a593Smuzhiyun static void hw_stop_rx(struct ksz_hw *hw)
3908*4882a593Smuzhiyun {
3909*4882a593Smuzhiyun 	hw->rx_stop = 0;
3910*4882a593Smuzhiyun 	hw_turn_off_intr(hw, KS884X_INT_RX_STOPPED);
3911*4882a593Smuzhiyun 	writel((hw->rx_cfg & ~DMA_RX_ENABLE), hw->io + KS_DMA_RX_CTRL);
3912*4882a593Smuzhiyun }
3913*4882a593Smuzhiyun 
3914*4882a593Smuzhiyun /**
3915*4882a593Smuzhiyun  * hw_start_tx - start transmitting
3916*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3917*4882a593Smuzhiyun  *
3918*4882a593Smuzhiyun  * This routine starts the transmit function of the hardware.
3919*4882a593Smuzhiyun  */
hw_start_tx(struct ksz_hw * hw)3920*4882a593Smuzhiyun static void hw_start_tx(struct ksz_hw *hw)
3921*4882a593Smuzhiyun {
3922*4882a593Smuzhiyun 	writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL);
3923*4882a593Smuzhiyun }
3924*4882a593Smuzhiyun 
3925*4882a593Smuzhiyun /**
3926*4882a593Smuzhiyun  * hw_stop_tx - stop transmitting
3927*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3928*4882a593Smuzhiyun  *
3929*4882a593Smuzhiyun  * This routine stops the transmit function of the hardware.
3930*4882a593Smuzhiyun  */
hw_stop_tx(struct ksz_hw * hw)3931*4882a593Smuzhiyun static void hw_stop_tx(struct ksz_hw *hw)
3932*4882a593Smuzhiyun {
3933*4882a593Smuzhiyun 	writel((hw->tx_cfg & ~DMA_TX_ENABLE), hw->io + KS_DMA_TX_CTRL);
3934*4882a593Smuzhiyun }
3935*4882a593Smuzhiyun 
3936*4882a593Smuzhiyun /**
3937*4882a593Smuzhiyun  * hw_disable - disable hardware
3938*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3939*4882a593Smuzhiyun  *
3940*4882a593Smuzhiyun  * This routine disables the hardware.
3941*4882a593Smuzhiyun  */
hw_disable(struct ksz_hw * hw)3942*4882a593Smuzhiyun static void hw_disable(struct ksz_hw *hw)
3943*4882a593Smuzhiyun {
3944*4882a593Smuzhiyun 	hw_stop_rx(hw);
3945*4882a593Smuzhiyun 	hw_stop_tx(hw);
3946*4882a593Smuzhiyun 	hw->enabled = 0;
3947*4882a593Smuzhiyun }
3948*4882a593Smuzhiyun 
3949*4882a593Smuzhiyun /**
3950*4882a593Smuzhiyun  * hw_enable - enable hardware
3951*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3952*4882a593Smuzhiyun  *
3953*4882a593Smuzhiyun  * This routine enables the hardware.
3954*4882a593Smuzhiyun  */
hw_enable(struct ksz_hw * hw)3955*4882a593Smuzhiyun static void hw_enable(struct ksz_hw *hw)
3956*4882a593Smuzhiyun {
3957*4882a593Smuzhiyun 	hw_start_tx(hw);
3958*4882a593Smuzhiyun 	hw_start_rx(hw);
3959*4882a593Smuzhiyun 	hw->enabled = 1;
3960*4882a593Smuzhiyun }
3961*4882a593Smuzhiyun 
3962*4882a593Smuzhiyun /**
3963*4882a593Smuzhiyun  * hw_alloc_pkt - allocate enough descriptors for transmission
3964*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3965*4882a593Smuzhiyun  * @length:	The length of the packet.
3966*4882a593Smuzhiyun  * @physical:	Number of descriptors required.
3967*4882a593Smuzhiyun  *
3968*4882a593Smuzhiyun  * This function allocates descriptors for transmission.
3969*4882a593Smuzhiyun  *
3970*4882a593Smuzhiyun  * Return 0 if not successful; 1 for buffer copy; or number of descriptors.
3971*4882a593Smuzhiyun  */
hw_alloc_pkt(struct ksz_hw * hw,int length,int physical)3972*4882a593Smuzhiyun static int hw_alloc_pkt(struct ksz_hw *hw, int length, int physical)
3973*4882a593Smuzhiyun {
3974*4882a593Smuzhiyun 	/* Always leave one descriptor free. */
3975*4882a593Smuzhiyun 	if (hw->tx_desc_info.avail <= 1)
3976*4882a593Smuzhiyun 		return 0;
3977*4882a593Smuzhiyun 
3978*4882a593Smuzhiyun 	/* Allocate a descriptor for transmission and mark it current. */
3979*4882a593Smuzhiyun 	get_tx_pkt(&hw->tx_desc_info, &hw->tx_desc_info.cur);
3980*4882a593Smuzhiyun 	hw->tx_desc_info.cur->sw.buf.tx.first_seg = 1;
3981*4882a593Smuzhiyun 
3982*4882a593Smuzhiyun 	/* Keep track of number of transmit descriptors used so far. */
3983*4882a593Smuzhiyun 	++hw->tx_int_cnt;
3984*4882a593Smuzhiyun 	hw->tx_size += length;
3985*4882a593Smuzhiyun 
3986*4882a593Smuzhiyun 	/* Cannot hold on too much data. */
3987*4882a593Smuzhiyun 	if (hw->tx_size >= MAX_TX_HELD_SIZE)
3988*4882a593Smuzhiyun 		hw->tx_int_cnt = hw->tx_int_mask + 1;
3989*4882a593Smuzhiyun 
3990*4882a593Smuzhiyun 	if (physical > hw->tx_desc_info.avail)
3991*4882a593Smuzhiyun 		return 1;
3992*4882a593Smuzhiyun 
3993*4882a593Smuzhiyun 	return hw->tx_desc_info.avail;
3994*4882a593Smuzhiyun }
3995*4882a593Smuzhiyun 
3996*4882a593Smuzhiyun /**
3997*4882a593Smuzhiyun  * hw_send_pkt - mark packet for transmission
3998*4882a593Smuzhiyun  * @hw: 	The hardware instance.
3999*4882a593Smuzhiyun  *
4000*4882a593Smuzhiyun  * This routine marks the packet for transmission in PCI version.
4001*4882a593Smuzhiyun  */
hw_send_pkt(struct ksz_hw * hw)4002*4882a593Smuzhiyun static void hw_send_pkt(struct ksz_hw *hw)
4003*4882a593Smuzhiyun {
4004*4882a593Smuzhiyun 	struct ksz_desc *cur = hw->tx_desc_info.cur;
4005*4882a593Smuzhiyun 
4006*4882a593Smuzhiyun 	cur->sw.buf.tx.last_seg = 1;
4007*4882a593Smuzhiyun 
4008*4882a593Smuzhiyun 	/* Interrupt only after specified number of descriptors used. */
4009*4882a593Smuzhiyun 	if (hw->tx_int_cnt > hw->tx_int_mask) {
4010*4882a593Smuzhiyun 		cur->sw.buf.tx.intr = 1;
4011*4882a593Smuzhiyun 		hw->tx_int_cnt = 0;
4012*4882a593Smuzhiyun 		hw->tx_size = 0;
4013*4882a593Smuzhiyun 	}
4014*4882a593Smuzhiyun 
4015*4882a593Smuzhiyun 	/* KSZ8842 supports port directed transmission. */
4016*4882a593Smuzhiyun 	cur->sw.buf.tx.dest_port = hw->dst_ports;
4017*4882a593Smuzhiyun 
4018*4882a593Smuzhiyun 	release_desc(cur);
4019*4882a593Smuzhiyun 
4020*4882a593Smuzhiyun 	writel(0, hw->io + KS_DMA_TX_START);
4021*4882a593Smuzhiyun }
4022*4882a593Smuzhiyun 
empty_addr(u8 * addr)4023*4882a593Smuzhiyun static int empty_addr(u8 *addr)
4024*4882a593Smuzhiyun {
4025*4882a593Smuzhiyun 	u32 *addr1 = (u32 *) addr;
4026*4882a593Smuzhiyun 	u16 *addr2 = (u16 *) &addr[4];
4027*4882a593Smuzhiyun 
4028*4882a593Smuzhiyun 	return 0 == *addr1 && 0 == *addr2;
4029*4882a593Smuzhiyun }
4030*4882a593Smuzhiyun 
4031*4882a593Smuzhiyun /**
4032*4882a593Smuzhiyun  * hw_set_addr - set MAC address
4033*4882a593Smuzhiyun  * @hw: 	The hardware instance.
4034*4882a593Smuzhiyun  *
4035*4882a593Smuzhiyun  * This routine programs the MAC address of the hardware when the address is
4036*4882a593Smuzhiyun  * overridden.
4037*4882a593Smuzhiyun  */
hw_set_addr(struct ksz_hw * hw)4038*4882a593Smuzhiyun static void hw_set_addr(struct ksz_hw *hw)
4039*4882a593Smuzhiyun {
4040*4882a593Smuzhiyun 	int i;
4041*4882a593Smuzhiyun 
4042*4882a593Smuzhiyun 	for (i = 0; i < ETH_ALEN; i++)
4043*4882a593Smuzhiyun 		writeb(hw->override_addr[MAC_ADDR_ORDER(i)],
4044*4882a593Smuzhiyun 			hw->io + KS884X_ADDR_0_OFFSET + i);
4045*4882a593Smuzhiyun 
4046*4882a593Smuzhiyun 	sw_set_addr(hw, hw->override_addr);
4047*4882a593Smuzhiyun }
4048*4882a593Smuzhiyun 
4049*4882a593Smuzhiyun /**
4050*4882a593Smuzhiyun  * hw_read_addr - read MAC address
4051*4882a593Smuzhiyun  * @hw: 	The hardware instance.
4052*4882a593Smuzhiyun  *
4053*4882a593Smuzhiyun  * This routine retrieves the MAC address of the hardware.
4054*4882a593Smuzhiyun  */
hw_read_addr(struct ksz_hw * hw)4055*4882a593Smuzhiyun static void hw_read_addr(struct ksz_hw *hw)
4056*4882a593Smuzhiyun {
4057*4882a593Smuzhiyun 	int i;
4058*4882a593Smuzhiyun 
4059*4882a593Smuzhiyun 	for (i = 0; i < ETH_ALEN; i++)
4060*4882a593Smuzhiyun 		hw->perm_addr[MAC_ADDR_ORDER(i)] = readb(hw->io +
4061*4882a593Smuzhiyun 			KS884X_ADDR_0_OFFSET + i);
4062*4882a593Smuzhiyun 
4063*4882a593Smuzhiyun 	if (!hw->mac_override) {
4064*4882a593Smuzhiyun 		memcpy(hw->override_addr, hw->perm_addr, ETH_ALEN);
4065*4882a593Smuzhiyun 		if (empty_addr(hw->override_addr)) {
4066*4882a593Smuzhiyun 			memcpy(hw->perm_addr, DEFAULT_MAC_ADDRESS, ETH_ALEN);
4067*4882a593Smuzhiyun 			memcpy(hw->override_addr, DEFAULT_MAC_ADDRESS,
4068*4882a593Smuzhiyun 			       ETH_ALEN);
4069*4882a593Smuzhiyun 			hw->override_addr[5] += hw->id;
4070*4882a593Smuzhiyun 			hw_set_addr(hw);
4071*4882a593Smuzhiyun 		}
4072*4882a593Smuzhiyun 	}
4073*4882a593Smuzhiyun }
4074*4882a593Smuzhiyun 
hw_ena_add_addr(struct ksz_hw * hw,int index,u8 * mac_addr)4075*4882a593Smuzhiyun static void hw_ena_add_addr(struct ksz_hw *hw, int index, u8 *mac_addr)
4076*4882a593Smuzhiyun {
4077*4882a593Smuzhiyun 	int i;
4078*4882a593Smuzhiyun 	u32 mac_addr_lo;
4079*4882a593Smuzhiyun 	u32 mac_addr_hi;
4080*4882a593Smuzhiyun 
4081*4882a593Smuzhiyun 	mac_addr_hi = 0;
4082*4882a593Smuzhiyun 	for (i = 0; i < 2; i++) {
4083*4882a593Smuzhiyun 		mac_addr_hi <<= 8;
4084*4882a593Smuzhiyun 		mac_addr_hi |= mac_addr[i];
4085*4882a593Smuzhiyun 	}
4086*4882a593Smuzhiyun 	mac_addr_hi |= ADD_ADDR_ENABLE;
4087*4882a593Smuzhiyun 	mac_addr_lo = 0;
4088*4882a593Smuzhiyun 	for (i = 2; i < 6; i++) {
4089*4882a593Smuzhiyun 		mac_addr_lo <<= 8;
4090*4882a593Smuzhiyun 		mac_addr_lo |= mac_addr[i];
4091*4882a593Smuzhiyun 	}
4092*4882a593Smuzhiyun 	index *= ADD_ADDR_INCR;
4093*4882a593Smuzhiyun 
4094*4882a593Smuzhiyun 	writel(mac_addr_lo, hw->io + index + KS_ADD_ADDR_0_LO);
4095*4882a593Smuzhiyun 	writel(mac_addr_hi, hw->io + index + KS_ADD_ADDR_0_HI);
4096*4882a593Smuzhiyun }
4097*4882a593Smuzhiyun 
hw_set_add_addr(struct ksz_hw * hw)4098*4882a593Smuzhiyun static void hw_set_add_addr(struct ksz_hw *hw)
4099*4882a593Smuzhiyun {
4100*4882a593Smuzhiyun 	int i;
4101*4882a593Smuzhiyun 
4102*4882a593Smuzhiyun 	for (i = 0; i < ADDITIONAL_ENTRIES; i++) {
4103*4882a593Smuzhiyun 		if (empty_addr(hw->address[i]))
4104*4882a593Smuzhiyun 			writel(0, hw->io + ADD_ADDR_INCR * i +
4105*4882a593Smuzhiyun 				KS_ADD_ADDR_0_HI);
4106*4882a593Smuzhiyun 		else
4107*4882a593Smuzhiyun 			hw_ena_add_addr(hw, i, hw->address[i]);
4108*4882a593Smuzhiyun 	}
4109*4882a593Smuzhiyun }
4110*4882a593Smuzhiyun 
hw_add_addr(struct ksz_hw * hw,u8 * mac_addr)4111*4882a593Smuzhiyun static int hw_add_addr(struct ksz_hw *hw, u8 *mac_addr)
4112*4882a593Smuzhiyun {
4113*4882a593Smuzhiyun 	int i;
4114*4882a593Smuzhiyun 	int j = ADDITIONAL_ENTRIES;
4115*4882a593Smuzhiyun 
4116*4882a593Smuzhiyun 	if (ether_addr_equal(hw->override_addr, mac_addr))
4117*4882a593Smuzhiyun 		return 0;
4118*4882a593Smuzhiyun 	for (i = 0; i < hw->addr_list_size; i++) {
4119*4882a593Smuzhiyun 		if (ether_addr_equal(hw->address[i], mac_addr))
4120*4882a593Smuzhiyun 			return 0;
4121*4882a593Smuzhiyun 		if (ADDITIONAL_ENTRIES == j && empty_addr(hw->address[i]))
4122*4882a593Smuzhiyun 			j = i;
4123*4882a593Smuzhiyun 	}
4124*4882a593Smuzhiyun 	if (j < ADDITIONAL_ENTRIES) {
4125*4882a593Smuzhiyun 		memcpy(hw->address[j], mac_addr, ETH_ALEN);
4126*4882a593Smuzhiyun 		hw_ena_add_addr(hw, j, hw->address[j]);
4127*4882a593Smuzhiyun 		return 0;
4128*4882a593Smuzhiyun 	}
4129*4882a593Smuzhiyun 	return -1;
4130*4882a593Smuzhiyun }
4131*4882a593Smuzhiyun 
hw_del_addr(struct ksz_hw * hw,u8 * mac_addr)4132*4882a593Smuzhiyun static int hw_del_addr(struct ksz_hw *hw, u8 *mac_addr)
4133*4882a593Smuzhiyun {
4134*4882a593Smuzhiyun 	int i;
4135*4882a593Smuzhiyun 
4136*4882a593Smuzhiyun 	for (i = 0; i < hw->addr_list_size; i++) {
4137*4882a593Smuzhiyun 		if (ether_addr_equal(hw->address[i], mac_addr)) {
4138*4882a593Smuzhiyun 			eth_zero_addr(hw->address[i]);
4139*4882a593Smuzhiyun 			writel(0, hw->io + ADD_ADDR_INCR * i +
4140*4882a593Smuzhiyun 				KS_ADD_ADDR_0_HI);
4141*4882a593Smuzhiyun 			return 0;
4142*4882a593Smuzhiyun 		}
4143*4882a593Smuzhiyun 	}
4144*4882a593Smuzhiyun 	return -1;
4145*4882a593Smuzhiyun }
4146*4882a593Smuzhiyun 
4147*4882a593Smuzhiyun /**
4148*4882a593Smuzhiyun  * hw_clr_multicast - clear multicast addresses
4149*4882a593Smuzhiyun  * @hw: 	The hardware instance.
4150*4882a593Smuzhiyun  *
4151*4882a593Smuzhiyun  * This routine removes all multicast addresses set in the hardware.
4152*4882a593Smuzhiyun  */
hw_clr_multicast(struct ksz_hw * hw)4153*4882a593Smuzhiyun static void hw_clr_multicast(struct ksz_hw *hw)
4154*4882a593Smuzhiyun {
4155*4882a593Smuzhiyun 	int i;
4156*4882a593Smuzhiyun 
4157*4882a593Smuzhiyun 	for (i = 0; i < HW_MULTICAST_SIZE; i++) {
4158*4882a593Smuzhiyun 		hw->multi_bits[i] = 0;
4159*4882a593Smuzhiyun 
4160*4882a593Smuzhiyun 		writeb(0, hw->io + KS884X_MULTICAST_0_OFFSET + i);
4161*4882a593Smuzhiyun 	}
4162*4882a593Smuzhiyun }
4163*4882a593Smuzhiyun 
4164*4882a593Smuzhiyun /**
4165*4882a593Smuzhiyun  * hw_set_grp_addr - set multicast addresses
4166*4882a593Smuzhiyun  * @hw: 	The hardware instance.
4167*4882a593Smuzhiyun  *
4168*4882a593Smuzhiyun  * This routine programs multicast addresses for the hardware to accept those
4169*4882a593Smuzhiyun  * addresses.
4170*4882a593Smuzhiyun  */
hw_set_grp_addr(struct ksz_hw * hw)4171*4882a593Smuzhiyun static void hw_set_grp_addr(struct ksz_hw *hw)
4172*4882a593Smuzhiyun {
4173*4882a593Smuzhiyun 	int i;
4174*4882a593Smuzhiyun 	int index;
4175*4882a593Smuzhiyun 	int position;
4176*4882a593Smuzhiyun 	int value;
4177*4882a593Smuzhiyun 
4178*4882a593Smuzhiyun 	memset(hw->multi_bits, 0, sizeof(u8) * HW_MULTICAST_SIZE);
4179*4882a593Smuzhiyun 
4180*4882a593Smuzhiyun 	for (i = 0; i < hw->multi_list_size; i++) {
4181*4882a593Smuzhiyun 		position = (ether_crc(6, hw->multi_list[i]) >> 26) & 0x3f;
4182*4882a593Smuzhiyun 		index = position >> 3;
4183*4882a593Smuzhiyun 		value = 1 << (position & 7);
4184*4882a593Smuzhiyun 		hw->multi_bits[index] |= (u8) value;
4185*4882a593Smuzhiyun 	}
4186*4882a593Smuzhiyun 
4187*4882a593Smuzhiyun 	for (i = 0; i < HW_MULTICAST_SIZE; i++)
4188*4882a593Smuzhiyun 		writeb(hw->multi_bits[i], hw->io + KS884X_MULTICAST_0_OFFSET +
4189*4882a593Smuzhiyun 			i);
4190*4882a593Smuzhiyun }
4191*4882a593Smuzhiyun 
4192*4882a593Smuzhiyun /**
4193*4882a593Smuzhiyun  * hw_set_multicast - enable or disable all multicast receiving
4194*4882a593Smuzhiyun  * @hw: 	The hardware instance.
4195*4882a593Smuzhiyun  * @multicast:	To turn on or off the all multicast feature.
4196*4882a593Smuzhiyun  *
4197*4882a593Smuzhiyun  * This routine enables/disables the hardware to accept all multicast packets.
4198*4882a593Smuzhiyun  */
hw_set_multicast(struct ksz_hw * hw,u8 multicast)4199*4882a593Smuzhiyun static void hw_set_multicast(struct ksz_hw *hw, u8 multicast)
4200*4882a593Smuzhiyun {
4201*4882a593Smuzhiyun 	/* Stop receiving for reconfiguration. */
4202*4882a593Smuzhiyun 	hw_stop_rx(hw);
4203*4882a593Smuzhiyun 
4204*4882a593Smuzhiyun 	if (multicast)
4205*4882a593Smuzhiyun 		hw->rx_cfg |= DMA_RX_ALL_MULTICAST;
4206*4882a593Smuzhiyun 	else
4207*4882a593Smuzhiyun 		hw->rx_cfg &= ~DMA_RX_ALL_MULTICAST;
4208*4882a593Smuzhiyun 
4209*4882a593Smuzhiyun 	if (hw->enabled)
4210*4882a593Smuzhiyun 		hw_start_rx(hw);
4211*4882a593Smuzhiyun }
4212*4882a593Smuzhiyun 
4213*4882a593Smuzhiyun /**
4214*4882a593Smuzhiyun  * hw_set_promiscuous - enable or disable promiscuous receiving
4215*4882a593Smuzhiyun  * @hw: 	The hardware instance.
4216*4882a593Smuzhiyun  * @prom:	To turn on or off the promiscuous feature.
4217*4882a593Smuzhiyun  *
4218*4882a593Smuzhiyun  * This routine enables/disables the hardware to accept all packets.
4219*4882a593Smuzhiyun  */
hw_set_promiscuous(struct ksz_hw * hw,u8 prom)4220*4882a593Smuzhiyun static void hw_set_promiscuous(struct ksz_hw *hw, u8 prom)
4221*4882a593Smuzhiyun {
4222*4882a593Smuzhiyun 	/* Stop receiving for reconfiguration. */
4223*4882a593Smuzhiyun 	hw_stop_rx(hw);
4224*4882a593Smuzhiyun 
4225*4882a593Smuzhiyun 	if (prom)
4226*4882a593Smuzhiyun 		hw->rx_cfg |= DMA_RX_PROMISCUOUS;
4227*4882a593Smuzhiyun 	else
4228*4882a593Smuzhiyun 		hw->rx_cfg &= ~DMA_RX_PROMISCUOUS;
4229*4882a593Smuzhiyun 
4230*4882a593Smuzhiyun 	if (hw->enabled)
4231*4882a593Smuzhiyun 		hw_start_rx(hw);
4232*4882a593Smuzhiyun }
4233*4882a593Smuzhiyun 
4234*4882a593Smuzhiyun /**
4235*4882a593Smuzhiyun  * sw_enable - enable the switch
4236*4882a593Smuzhiyun  * @hw: 	The hardware instance.
4237*4882a593Smuzhiyun  * @enable:	The flag to enable or disable the switch
4238*4882a593Smuzhiyun  *
4239*4882a593Smuzhiyun  * This routine is used to enable/disable the switch in KSZ8842.
4240*4882a593Smuzhiyun  */
sw_enable(struct ksz_hw * hw,int enable)4241*4882a593Smuzhiyun static void sw_enable(struct ksz_hw *hw, int enable)
4242*4882a593Smuzhiyun {
4243*4882a593Smuzhiyun 	int port;
4244*4882a593Smuzhiyun 
4245*4882a593Smuzhiyun 	for (port = 0; port < SWITCH_PORT_NUM; port++) {
4246*4882a593Smuzhiyun 		if (hw->dev_count > 1) {
4247*4882a593Smuzhiyun 			/* Set port-base vlan membership with host port. */
4248*4882a593Smuzhiyun 			sw_cfg_port_base_vlan(hw, port,
4249*4882a593Smuzhiyun 				HOST_MASK | (1 << port));
4250*4882a593Smuzhiyun 			port_set_stp_state(hw, port, STP_STATE_DISABLED);
4251*4882a593Smuzhiyun 		} else {
4252*4882a593Smuzhiyun 			sw_cfg_port_base_vlan(hw, port, PORT_MASK);
4253*4882a593Smuzhiyun 			port_set_stp_state(hw, port, STP_STATE_FORWARDING);
4254*4882a593Smuzhiyun 		}
4255*4882a593Smuzhiyun 	}
4256*4882a593Smuzhiyun 	if (hw->dev_count > 1)
4257*4882a593Smuzhiyun 		port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_SIMPLE);
4258*4882a593Smuzhiyun 	else
4259*4882a593Smuzhiyun 		port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_FORWARDING);
4260*4882a593Smuzhiyun 
4261*4882a593Smuzhiyun 	if (enable)
4262*4882a593Smuzhiyun 		enable = KS8842_START;
4263*4882a593Smuzhiyun 	writew(enable, hw->io + KS884X_CHIP_ID_OFFSET);
4264*4882a593Smuzhiyun }
4265*4882a593Smuzhiyun 
4266*4882a593Smuzhiyun /**
4267*4882a593Smuzhiyun  * sw_setup - setup the switch
4268*4882a593Smuzhiyun  * @hw: 	The hardware instance.
4269*4882a593Smuzhiyun  *
4270*4882a593Smuzhiyun  * This routine setup the hardware switch engine for default operation.
4271*4882a593Smuzhiyun  */
sw_setup(struct ksz_hw * hw)4272*4882a593Smuzhiyun static void sw_setup(struct ksz_hw *hw)
4273*4882a593Smuzhiyun {
4274*4882a593Smuzhiyun 	int port;
4275*4882a593Smuzhiyun 
4276*4882a593Smuzhiyun 	sw_set_global_ctrl(hw);
4277*4882a593Smuzhiyun 
4278*4882a593Smuzhiyun 	/* Enable switch broadcast storm protection at 10% percent rate. */
4279*4882a593Smuzhiyun 	sw_init_broad_storm(hw);
4280*4882a593Smuzhiyun 	hw_cfg_broad_storm(hw, BROADCAST_STORM_PROTECTION_RATE);
4281*4882a593Smuzhiyun 	for (port = 0; port < SWITCH_PORT_NUM; port++)
4282*4882a593Smuzhiyun 		sw_ena_broad_storm(hw, port);
4283*4882a593Smuzhiyun 
4284*4882a593Smuzhiyun 	sw_init_prio(hw);
4285*4882a593Smuzhiyun 
4286*4882a593Smuzhiyun 	sw_init_mirror(hw);
4287*4882a593Smuzhiyun 
4288*4882a593Smuzhiyun 	sw_init_prio_rate(hw);
4289*4882a593Smuzhiyun 
4290*4882a593Smuzhiyun 	sw_init_vlan(hw);
4291*4882a593Smuzhiyun 
4292*4882a593Smuzhiyun 	if (hw->features & STP_SUPPORT)
4293*4882a593Smuzhiyun 		sw_init_stp(hw);
4294*4882a593Smuzhiyun 	if (!sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET,
4295*4882a593Smuzhiyun 			SWITCH_TX_FLOW_CTRL | SWITCH_RX_FLOW_CTRL))
4296*4882a593Smuzhiyun 		hw->overrides |= PAUSE_FLOW_CTRL;
4297*4882a593Smuzhiyun 	sw_enable(hw, 1);
4298*4882a593Smuzhiyun }
4299*4882a593Smuzhiyun 
4300*4882a593Smuzhiyun /**
4301*4882a593Smuzhiyun  * ksz_start_timer - start kernel timer
4302*4882a593Smuzhiyun  * @info:	Kernel timer information.
4303*4882a593Smuzhiyun  * @time:	The time tick.
4304*4882a593Smuzhiyun  *
4305*4882a593Smuzhiyun  * This routine starts the kernel timer after the specified time tick.
4306*4882a593Smuzhiyun  */
ksz_start_timer(struct ksz_timer_info * info,int time)4307*4882a593Smuzhiyun static void ksz_start_timer(struct ksz_timer_info *info, int time)
4308*4882a593Smuzhiyun {
4309*4882a593Smuzhiyun 	info->cnt = 0;
4310*4882a593Smuzhiyun 	info->timer.expires = jiffies + time;
4311*4882a593Smuzhiyun 	add_timer(&info->timer);
4312*4882a593Smuzhiyun 
4313*4882a593Smuzhiyun 	/* infinity */
4314*4882a593Smuzhiyun 	info->max = -1;
4315*4882a593Smuzhiyun }
4316*4882a593Smuzhiyun 
4317*4882a593Smuzhiyun /**
4318*4882a593Smuzhiyun  * ksz_stop_timer - stop kernel timer
4319*4882a593Smuzhiyun  * @info:	Kernel timer information.
4320*4882a593Smuzhiyun  *
4321*4882a593Smuzhiyun  * This routine stops the kernel timer.
4322*4882a593Smuzhiyun  */
ksz_stop_timer(struct ksz_timer_info * info)4323*4882a593Smuzhiyun static void ksz_stop_timer(struct ksz_timer_info *info)
4324*4882a593Smuzhiyun {
4325*4882a593Smuzhiyun 	if (info->max) {
4326*4882a593Smuzhiyun 		info->max = 0;
4327*4882a593Smuzhiyun 		del_timer_sync(&info->timer);
4328*4882a593Smuzhiyun 	}
4329*4882a593Smuzhiyun }
4330*4882a593Smuzhiyun 
ksz_init_timer(struct ksz_timer_info * info,int period,void (* function)(struct timer_list *))4331*4882a593Smuzhiyun static void ksz_init_timer(struct ksz_timer_info *info, int period,
4332*4882a593Smuzhiyun 	void (*function)(struct timer_list *))
4333*4882a593Smuzhiyun {
4334*4882a593Smuzhiyun 	info->max = 0;
4335*4882a593Smuzhiyun 	info->period = period;
4336*4882a593Smuzhiyun 	timer_setup(&info->timer, function, 0);
4337*4882a593Smuzhiyun }
4338*4882a593Smuzhiyun 
ksz_update_timer(struct ksz_timer_info * info)4339*4882a593Smuzhiyun static void ksz_update_timer(struct ksz_timer_info *info)
4340*4882a593Smuzhiyun {
4341*4882a593Smuzhiyun 	++info->cnt;
4342*4882a593Smuzhiyun 	if (info->max > 0) {
4343*4882a593Smuzhiyun 		if (info->cnt < info->max) {
4344*4882a593Smuzhiyun 			info->timer.expires = jiffies + info->period;
4345*4882a593Smuzhiyun 			add_timer(&info->timer);
4346*4882a593Smuzhiyun 		} else
4347*4882a593Smuzhiyun 			info->max = 0;
4348*4882a593Smuzhiyun 	} else if (info->max < 0) {
4349*4882a593Smuzhiyun 		info->timer.expires = jiffies + info->period;
4350*4882a593Smuzhiyun 		add_timer(&info->timer);
4351*4882a593Smuzhiyun 	}
4352*4882a593Smuzhiyun }
4353*4882a593Smuzhiyun 
4354*4882a593Smuzhiyun /**
4355*4882a593Smuzhiyun  * ksz_alloc_soft_desc - allocate software descriptors
4356*4882a593Smuzhiyun  * @desc_info:	Descriptor information structure.
4357*4882a593Smuzhiyun  * @transmit:	Indication that descriptors are for transmit.
4358*4882a593Smuzhiyun  *
4359*4882a593Smuzhiyun  * This local function allocates software descriptors for manipulation in
4360*4882a593Smuzhiyun  * memory.
4361*4882a593Smuzhiyun  *
4362*4882a593Smuzhiyun  * Return 0 if successful.
4363*4882a593Smuzhiyun  */
ksz_alloc_soft_desc(struct ksz_desc_info * desc_info,int transmit)4364*4882a593Smuzhiyun static int ksz_alloc_soft_desc(struct ksz_desc_info *desc_info, int transmit)
4365*4882a593Smuzhiyun {
4366*4882a593Smuzhiyun 	desc_info->ring = kcalloc(desc_info->alloc, sizeof(struct ksz_desc),
4367*4882a593Smuzhiyun 				  GFP_KERNEL);
4368*4882a593Smuzhiyun 	if (!desc_info->ring)
4369*4882a593Smuzhiyun 		return 1;
4370*4882a593Smuzhiyun 	hw_init_desc(desc_info, transmit);
4371*4882a593Smuzhiyun 	return 0;
4372*4882a593Smuzhiyun }
4373*4882a593Smuzhiyun 
4374*4882a593Smuzhiyun /**
4375*4882a593Smuzhiyun  * ksz_alloc_desc - allocate hardware descriptors
4376*4882a593Smuzhiyun  * @adapter:	Adapter information structure.
4377*4882a593Smuzhiyun  *
4378*4882a593Smuzhiyun  * This local function allocates hardware descriptors for receiving and
4379*4882a593Smuzhiyun  * transmitting.
4380*4882a593Smuzhiyun  *
4381*4882a593Smuzhiyun  * Return 0 if successful.
4382*4882a593Smuzhiyun  */
ksz_alloc_desc(struct dev_info * adapter)4383*4882a593Smuzhiyun static int ksz_alloc_desc(struct dev_info *adapter)
4384*4882a593Smuzhiyun {
4385*4882a593Smuzhiyun 	struct ksz_hw *hw = &adapter->hw;
4386*4882a593Smuzhiyun 	int offset;
4387*4882a593Smuzhiyun 
4388*4882a593Smuzhiyun 	/* Allocate memory for RX & TX descriptors. */
4389*4882a593Smuzhiyun 	adapter->desc_pool.alloc_size =
4390*4882a593Smuzhiyun 		hw->rx_desc_info.size * hw->rx_desc_info.alloc +
4391*4882a593Smuzhiyun 		hw->tx_desc_info.size * hw->tx_desc_info.alloc +
4392*4882a593Smuzhiyun 		DESC_ALIGNMENT;
4393*4882a593Smuzhiyun 
4394*4882a593Smuzhiyun 	adapter->desc_pool.alloc_virt =
4395*4882a593Smuzhiyun 		dma_alloc_coherent(&adapter->pdev->dev,
4396*4882a593Smuzhiyun 				   adapter->desc_pool.alloc_size,
4397*4882a593Smuzhiyun 				   &adapter->desc_pool.dma_addr, GFP_KERNEL);
4398*4882a593Smuzhiyun 	if (adapter->desc_pool.alloc_virt == NULL) {
4399*4882a593Smuzhiyun 		adapter->desc_pool.alloc_size = 0;
4400*4882a593Smuzhiyun 		return 1;
4401*4882a593Smuzhiyun 	}
4402*4882a593Smuzhiyun 
4403*4882a593Smuzhiyun 	/* Align to the next cache line boundary. */
4404*4882a593Smuzhiyun 	offset = (((ulong) adapter->desc_pool.alloc_virt % DESC_ALIGNMENT) ?
4405*4882a593Smuzhiyun 		(DESC_ALIGNMENT -
4406*4882a593Smuzhiyun 		((ulong) adapter->desc_pool.alloc_virt % DESC_ALIGNMENT)) : 0);
4407*4882a593Smuzhiyun 	adapter->desc_pool.virt = adapter->desc_pool.alloc_virt + offset;
4408*4882a593Smuzhiyun 	adapter->desc_pool.phys = adapter->desc_pool.dma_addr + offset;
4409*4882a593Smuzhiyun 
4410*4882a593Smuzhiyun 	/* Allocate receive/transmit descriptors. */
4411*4882a593Smuzhiyun 	hw->rx_desc_info.ring_virt = (struct ksz_hw_desc *)
4412*4882a593Smuzhiyun 		adapter->desc_pool.virt;
4413*4882a593Smuzhiyun 	hw->rx_desc_info.ring_phys = adapter->desc_pool.phys;
4414*4882a593Smuzhiyun 	offset = hw->rx_desc_info.alloc * hw->rx_desc_info.size;
4415*4882a593Smuzhiyun 	hw->tx_desc_info.ring_virt = (struct ksz_hw_desc *)
4416*4882a593Smuzhiyun 		(adapter->desc_pool.virt + offset);
4417*4882a593Smuzhiyun 	hw->tx_desc_info.ring_phys = adapter->desc_pool.phys + offset;
4418*4882a593Smuzhiyun 
4419*4882a593Smuzhiyun 	if (ksz_alloc_soft_desc(&hw->rx_desc_info, 0))
4420*4882a593Smuzhiyun 		return 1;
4421*4882a593Smuzhiyun 	if (ksz_alloc_soft_desc(&hw->tx_desc_info, 1))
4422*4882a593Smuzhiyun 		return 1;
4423*4882a593Smuzhiyun 
4424*4882a593Smuzhiyun 	return 0;
4425*4882a593Smuzhiyun }
4426*4882a593Smuzhiyun 
4427*4882a593Smuzhiyun /**
4428*4882a593Smuzhiyun  * free_dma_buf - release DMA buffer resources
4429*4882a593Smuzhiyun  * @adapter:	Adapter information structure.
4430*4882a593Smuzhiyun  * @dma_buf:	pointer to buf
4431*4882a593Smuzhiyun  * @direction:	to or from device
4432*4882a593Smuzhiyun  *
4433*4882a593Smuzhiyun  * This routine is just a helper function to release the DMA buffer resources.
4434*4882a593Smuzhiyun  */
free_dma_buf(struct dev_info * adapter,struct ksz_dma_buf * dma_buf,int direction)4435*4882a593Smuzhiyun static void free_dma_buf(struct dev_info *adapter, struct ksz_dma_buf *dma_buf,
4436*4882a593Smuzhiyun 	int direction)
4437*4882a593Smuzhiyun {
4438*4882a593Smuzhiyun 	dma_unmap_single(&adapter->pdev->dev, dma_buf->dma, dma_buf->len,
4439*4882a593Smuzhiyun 			 direction);
4440*4882a593Smuzhiyun 	dev_kfree_skb(dma_buf->skb);
4441*4882a593Smuzhiyun 	dma_buf->skb = NULL;
4442*4882a593Smuzhiyun 	dma_buf->dma = 0;
4443*4882a593Smuzhiyun }
4444*4882a593Smuzhiyun 
4445*4882a593Smuzhiyun /**
4446*4882a593Smuzhiyun  * ksz_init_rx_buffers - initialize receive descriptors
4447*4882a593Smuzhiyun  * @adapter:	Adapter information structure.
4448*4882a593Smuzhiyun  *
4449*4882a593Smuzhiyun  * This routine initializes DMA buffers for receiving.
4450*4882a593Smuzhiyun  */
ksz_init_rx_buffers(struct dev_info * adapter)4451*4882a593Smuzhiyun static void ksz_init_rx_buffers(struct dev_info *adapter)
4452*4882a593Smuzhiyun {
4453*4882a593Smuzhiyun 	int i;
4454*4882a593Smuzhiyun 	struct ksz_desc *desc;
4455*4882a593Smuzhiyun 	struct ksz_dma_buf *dma_buf;
4456*4882a593Smuzhiyun 	struct ksz_hw *hw = &adapter->hw;
4457*4882a593Smuzhiyun 	struct ksz_desc_info *info = &hw->rx_desc_info;
4458*4882a593Smuzhiyun 
4459*4882a593Smuzhiyun 	for (i = 0; i < hw->rx_desc_info.alloc; i++) {
4460*4882a593Smuzhiyun 		get_rx_pkt(info, &desc);
4461*4882a593Smuzhiyun 
4462*4882a593Smuzhiyun 		dma_buf = DMA_BUFFER(desc);
4463*4882a593Smuzhiyun 		if (dma_buf->skb && dma_buf->len != adapter->mtu)
4464*4882a593Smuzhiyun 			free_dma_buf(adapter, dma_buf, DMA_FROM_DEVICE);
4465*4882a593Smuzhiyun 		dma_buf->len = adapter->mtu;
4466*4882a593Smuzhiyun 		if (!dma_buf->skb)
4467*4882a593Smuzhiyun 			dma_buf->skb = alloc_skb(dma_buf->len, GFP_ATOMIC);
4468*4882a593Smuzhiyun 		if (dma_buf->skb && !dma_buf->dma)
4469*4882a593Smuzhiyun 			dma_buf->dma = dma_map_single(&adapter->pdev->dev,
4470*4882a593Smuzhiyun 						skb_tail_pointer(dma_buf->skb),
4471*4882a593Smuzhiyun 						dma_buf->len,
4472*4882a593Smuzhiyun 						DMA_FROM_DEVICE);
4473*4882a593Smuzhiyun 
4474*4882a593Smuzhiyun 		/* Set descriptor. */
4475*4882a593Smuzhiyun 		set_rx_buf(desc, dma_buf->dma);
4476*4882a593Smuzhiyun 		set_rx_len(desc, dma_buf->len);
4477*4882a593Smuzhiyun 		release_desc(desc);
4478*4882a593Smuzhiyun 	}
4479*4882a593Smuzhiyun }
4480*4882a593Smuzhiyun 
4481*4882a593Smuzhiyun /**
4482*4882a593Smuzhiyun  * ksz_alloc_mem - allocate memory for hardware descriptors
4483*4882a593Smuzhiyun  * @adapter:	Adapter information structure.
4484*4882a593Smuzhiyun  *
4485*4882a593Smuzhiyun  * This function allocates memory for use by hardware descriptors for receiving
4486*4882a593Smuzhiyun  * and transmitting.
4487*4882a593Smuzhiyun  *
4488*4882a593Smuzhiyun  * Return 0 if successful.
4489*4882a593Smuzhiyun  */
ksz_alloc_mem(struct dev_info * adapter)4490*4882a593Smuzhiyun static int ksz_alloc_mem(struct dev_info *adapter)
4491*4882a593Smuzhiyun {
4492*4882a593Smuzhiyun 	struct ksz_hw *hw = &adapter->hw;
4493*4882a593Smuzhiyun 
4494*4882a593Smuzhiyun 	/* Determine the number of receive and transmit descriptors. */
4495*4882a593Smuzhiyun 	hw->rx_desc_info.alloc = NUM_OF_RX_DESC;
4496*4882a593Smuzhiyun 	hw->tx_desc_info.alloc = NUM_OF_TX_DESC;
4497*4882a593Smuzhiyun 
4498*4882a593Smuzhiyun 	/* Determine how many descriptors to skip transmit interrupt. */
4499*4882a593Smuzhiyun 	hw->tx_int_cnt = 0;
4500*4882a593Smuzhiyun 	hw->tx_int_mask = NUM_OF_TX_DESC / 4;
4501*4882a593Smuzhiyun 	if (hw->tx_int_mask > 8)
4502*4882a593Smuzhiyun 		hw->tx_int_mask = 8;
4503*4882a593Smuzhiyun 	while (hw->tx_int_mask) {
4504*4882a593Smuzhiyun 		hw->tx_int_cnt++;
4505*4882a593Smuzhiyun 		hw->tx_int_mask >>= 1;
4506*4882a593Smuzhiyun 	}
4507*4882a593Smuzhiyun 	if (hw->tx_int_cnt) {
4508*4882a593Smuzhiyun 		hw->tx_int_mask = (1 << (hw->tx_int_cnt - 1)) - 1;
4509*4882a593Smuzhiyun 		hw->tx_int_cnt = 0;
4510*4882a593Smuzhiyun 	}
4511*4882a593Smuzhiyun 
4512*4882a593Smuzhiyun 	/* Determine the descriptor size. */
4513*4882a593Smuzhiyun 	hw->rx_desc_info.size =
4514*4882a593Smuzhiyun 		(((sizeof(struct ksz_hw_desc) + DESC_ALIGNMENT - 1) /
4515*4882a593Smuzhiyun 		DESC_ALIGNMENT) * DESC_ALIGNMENT);
4516*4882a593Smuzhiyun 	hw->tx_desc_info.size =
4517*4882a593Smuzhiyun 		(((sizeof(struct ksz_hw_desc) + DESC_ALIGNMENT - 1) /
4518*4882a593Smuzhiyun 		DESC_ALIGNMENT) * DESC_ALIGNMENT);
4519*4882a593Smuzhiyun 	if (hw->rx_desc_info.size != sizeof(struct ksz_hw_desc))
4520*4882a593Smuzhiyun 		pr_alert("Hardware descriptor size not right!\n");
4521*4882a593Smuzhiyun 	ksz_check_desc_num(&hw->rx_desc_info);
4522*4882a593Smuzhiyun 	ksz_check_desc_num(&hw->tx_desc_info);
4523*4882a593Smuzhiyun 
4524*4882a593Smuzhiyun 	/* Allocate descriptors. */
4525*4882a593Smuzhiyun 	if (ksz_alloc_desc(adapter))
4526*4882a593Smuzhiyun 		return 1;
4527*4882a593Smuzhiyun 
4528*4882a593Smuzhiyun 	return 0;
4529*4882a593Smuzhiyun }
4530*4882a593Smuzhiyun 
4531*4882a593Smuzhiyun /**
4532*4882a593Smuzhiyun  * ksz_free_desc - free software and hardware descriptors
4533*4882a593Smuzhiyun  * @adapter:	Adapter information structure.
4534*4882a593Smuzhiyun  *
4535*4882a593Smuzhiyun  * This local routine frees the software and hardware descriptors allocated by
4536*4882a593Smuzhiyun  * ksz_alloc_desc().
4537*4882a593Smuzhiyun  */
ksz_free_desc(struct dev_info * adapter)4538*4882a593Smuzhiyun static void ksz_free_desc(struct dev_info *adapter)
4539*4882a593Smuzhiyun {
4540*4882a593Smuzhiyun 	struct ksz_hw *hw = &adapter->hw;
4541*4882a593Smuzhiyun 
4542*4882a593Smuzhiyun 	/* Reset descriptor. */
4543*4882a593Smuzhiyun 	hw->rx_desc_info.ring_virt = NULL;
4544*4882a593Smuzhiyun 	hw->tx_desc_info.ring_virt = NULL;
4545*4882a593Smuzhiyun 	hw->rx_desc_info.ring_phys = 0;
4546*4882a593Smuzhiyun 	hw->tx_desc_info.ring_phys = 0;
4547*4882a593Smuzhiyun 
4548*4882a593Smuzhiyun 	/* Free memory. */
4549*4882a593Smuzhiyun 	if (adapter->desc_pool.alloc_virt)
4550*4882a593Smuzhiyun 		dma_free_coherent(&adapter->pdev->dev,
4551*4882a593Smuzhiyun 				  adapter->desc_pool.alloc_size,
4552*4882a593Smuzhiyun 				  adapter->desc_pool.alloc_virt,
4553*4882a593Smuzhiyun 				  adapter->desc_pool.dma_addr);
4554*4882a593Smuzhiyun 
4555*4882a593Smuzhiyun 	/* Reset resource pool. */
4556*4882a593Smuzhiyun 	adapter->desc_pool.alloc_size = 0;
4557*4882a593Smuzhiyun 	adapter->desc_pool.alloc_virt = NULL;
4558*4882a593Smuzhiyun 
4559*4882a593Smuzhiyun 	kfree(hw->rx_desc_info.ring);
4560*4882a593Smuzhiyun 	hw->rx_desc_info.ring = NULL;
4561*4882a593Smuzhiyun 	kfree(hw->tx_desc_info.ring);
4562*4882a593Smuzhiyun 	hw->tx_desc_info.ring = NULL;
4563*4882a593Smuzhiyun }
4564*4882a593Smuzhiyun 
4565*4882a593Smuzhiyun /**
4566*4882a593Smuzhiyun  * ksz_free_buffers - free buffers used in the descriptors
4567*4882a593Smuzhiyun  * @adapter:	Adapter information structure.
4568*4882a593Smuzhiyun  * @desc_info:	Descriptor information structure.
4569*4882a593Smuzhiyun  * @direction:	to or from device
4570*4882a593Smuzhiyun  *
4571*4882a593Smuzhiyun  * This local routine frees buffers used in the DMA buffers.
4572*4882a593Smuzhiyun  */
ksz_free_buffers(struct dev_info * adapter,struct ksz_desc_info * desc_info,int direction)4573*4882a593Smuzhiyun static void ksz_free_buffers(struct dev_info *adapter,
4574*4882a593Smuzhiyun 	struct ksz_desc_info *desc_info, int direction)
4575*4882a593Smuzhiyun {
4576*4882a593Smuzhiyun 	int i;
4577*4882a593Smuzhiyun 	struct ksz_dma_buf *dma_buf;
4578*4882a593Smuzhiyun 	struct ksz_desc *desc = desc_info->ring;
4579*4882a593Smuzhiyun 
4580*4882a593Smuzhiyun 	for (i = 0; i < desc_info->alloc; i++) {
4581*4882a593Smuzhiyun 		dma_buf = DMA_BUFFER(desc);
4582*4882a593Smuzhiyun 		if (dma_buf->skb)
4583*4882a593Smuzhiyun 			free_dma_buf(adapter, dma_buf, direction);
4584*4882a593Smuzhiyun 		desc++;
4585*4882a593Smuzhiyun 	}
4586*4882a593Smuzhiyun }
4587*4882a593Smuzhiyun 
4588*4882a593Smuzhiyun /**
4589*4882a593Smuzhiyun  * ksz_free_mem - free all resources used by descriptors
4590*4882a593Smuzhiyun  * @adapter:	Adapter information structure.
4591*4882a593Smuzhiyun  *
4592*4882a593Smuzhiyun  * This local routine frees all the resources allocated by ksz_alloc_mem().
4593*4882a593Smuzhiyun  */
ksz_free_mem(struct dev_info * adapter)4594*4882a593Smuzhiyun static void ksz_free_mem(struct dev_info *adapter)
4595*4882a593Smuzhiyun {
4596*4882a593Smuzhiyun 	/* Free transmit buffers. */
4597*4882a593Smuzhiyun 	ksz_free_buffers(adapter, &adapter->hw.tx_desc_info, DMA_TO_DEVICE);
4598*4882a593Smuzhiyun 
4599*4882a593Smuzhiyun 	/* Free receive buffers. */
4600*4882a593Smuzhiyun 	ksz_free_buffers(adapter, &adapter->hw.rx_desc_info, DMA_FROM_DEVICE);
4601*4882a593Smuzhiyun 
4602*4882a593Smuzhiyun 	/* Free descriptors. */
4603*4882a593Smuzhiyun 	ksz_free_desc(adapter);
4604*4882a593Smuzhiyun }
4605*4882a593Smuzhiyun 
get_mib_counters(struct ksz_hw * hw,int first,int cnt,u64 * counter)4606*4882a593Smuzhiyun static void get_mib_counters(struct ksz_hw *hw, int first, int cnt,
4607*4882a593Smuzhiyun 	u64 *counter)
4608*4882a593Smuzhiyun {
4609*4882a593Smuzhiyun 	int i;
4610*4882a593Smuzhiyun 	int mib;
4611*4882a593Smuzhiyun 	int port;
4612*4882a593Smuzhiyun 	struct ksz_port_mib *port_mib;
4613*4882a593Smuzhiyun 
4614*4882a593Smuzhiyun 	memset(counter, 0, sizeof(u64) * TOTAL_PORT_COUNTER_NUM);
4615*4882a593Smuzhiyun 	for (i = 0, port = first; i < cnt; i++, port++) {
4616*4882a593Smuzhiyun 		port_mib = &hw->port_mib[port];
4617*4882a593Smuzhiyun 		for (mib = port_mib->mib_start; mib < hw->mib_cnt; mib++)
4618*4882a593Smuzhiyun 			counter[mib] += port_mib->counter[mib];
4619*4882a593Smuzhiyun 	}
4620*4882a593Smuzhiyun }
4621*4882a593Smuzhiyun 
4622*4882a593Smuzhiyun /**
4623*4882a593Smuzhiyun  * send_packet - send packet
4624*4882a593Smuzhiyun  * @skb:	Socket buffer.
4625*4882a593Smuzhiyun  * @dev:	Network device.
4626*4882a593Smuzhiyun  *
4627*4882a593Smuzhiyun  * This routine is used to send a packet out to the network.
4628*4882a593Smuzhiyun  */
send_packet(struct sk_buff * skb,struct net_device * dev)4629*4882a593Smuzhiyun static void send_packet(struct sk_buff *skb, struct net_device *dev)
4630*4882a593Smuzhiyun {
4631*4882a593Smuzhiyun 	struct ksz_desc *desc;
4632*4882a593Smuzhiyun 	struct ksz_desc *first;
4633*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
4634*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
4635*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
4636*4882a593Smuzhiyun 	struct ksz_desc_info *info = &hw->tx_desc_info;
4637*4882a593Smuzhiyun 	struct ksz_dma_buf *dma_buf;
4638*4882a593Smuzhiyun 	int len;
4639*4882a593Smuzhiyun 	int last_frag = skb_shinfo(skb)->nr_frags;
4640*4882a593Smuzhiyun 
4641*4882a593Smuzhiyun 	/*
4642*4882a593Smuzhiyun 	 * KSZ8842 with multiple device interfaces needs to be told which port
4643*4882a593Smuzhiyun 	 * to send.
4644*4882a593Smuzhiyun 	 */
4645*4882a593Smuzhiyun 	if (hw->dev_count > 1)
4646*4882a593Smuzhiyun 		hw->dst_ports = 1 << priv->port.first_port;
4647*4882a593Smuzhiyun 
4648*4882a593Smuzhiyun 	/* Hardware will pad the length to 60. */
4649*4882a593Smuzhiyun 	len = skb->len;
4650*4882a593Smuzhiyun 
4651*4882a593Smuzhiyun 	/* Remember the very first descriptor. */
4652*4882a593Smuzhiyun 	first = info->cur;
4653*4882a593Smuzhiyun 	desc = first;
4654*4882a593Smuzhiyun 
4655*4882a593Smuzhiyun 	dma_buf = DMA_BUFFER(desc);
4656*4882a593Smuzhiyun 	if (last_frag) {
4657*4882a593Smuzhiyun 		int frag;
4658*4882a593Smuzhiyun 		skb_frag_t *this_frag;
4659*4882a593Smuzhiyun 
4660*4882a593Smuzhiyun 		dma_buf->len = skb_headlen(skb);
4661*4882a593Smuzhiyun 
4662*4882a593Smuzhiyun 		dma_buf->dma = dma_map_single(&hw_priv->pdev->dev, skb->data,
4663*4882a593Smuzhiyun 					      dma_buf->len, DMA_TO_DEVICE);
4664*4882a593Smuzhiyun 		set_tx_buf(desc, dma_buf->dma);
4665*4882a593Smuzhiyun 		set_tx_len(desc, dma_buf->len);
4666*4882a593Smuzhiyun 
4667*4882a593Smuzhiyun 		frag = 0;
4668*4882a593Smuzhiyun 		do {
4669*4882a593Smuzhiyun 			this_frag = &skb_shinfo(skb)->frags[frag];
4670*4882a593Smuzhiyun 
4671*4882a593Smuzhiyun 			/* Get a new descriptor. */
4672*4882a593Smuzhiyun 			get_tx_pkt(info, &desc);
4673*4882a593Smuzhiyun 
4674*4882a593Smuzhiyun 			/* Keep track of descriptors used so far. */
4675*4882a593Smuzhiyun 			++hw->tx_int_cnt;
4676*4882a593Smuzhiyun 
4677*4882a593Smuzhiyun 			dma_buf = DMA_BUFFER(desc);
4678*4882a593Smuzhiyun 			dma_buf->len = skb_frag_size(this_frag);
4679*4882a593Smuzhiyun 
4680*4882a593Smuzhiyun 			dma_buf->dma = dma_map_single(&hw_priv->pdev->dev,
4681*4882a593Smuzhiyun 						      skb_frag_address(this_frag),
4682*4882a593Smuzhiyun 						      dma_buf->len,
4683*4882a593Smuzhiyun 						      DMA_TO_DEVICE);
4684*4882a593Smuzhiyun 			set_tx_buf(desc, dma_buf->dma);
4685*4882a593Smuzhiyun 			set_tx_len(desc, dma_buf->len);
4686*4882a593Smuzhiyun 
4687*4882a593Smuzhiyun 			frag++;
4688*4882a593Smuzhiyun 			if (frag == last_frag)
4689*4882a593Smuzhiyun 				break;
4690*4882a593Smuzhiyun 
4691*4882a593Smuzhiyun 			/* Do not release the last descriptor here. */
4692*4882a593Smuzhiyun 			release_desc(desc);
4693*4882a593Smuzhiyun 		} while (1);
4694*4882a593Smuzhiyun 
4695*4882a593Smuzhiyun 		/* current points to the last descriptor. */
4696*4882a593Smuzhiyun 		info->cur = desc;
4697*4882a593Smuzhiyun 
4698*4882a593Smuzhiyun 		/* Release the first descriptor. */
4699*4882a593Smuzhiyun 		release_desc(first);
4700*4882a593Smuzhiyun 	} else {
4701*4882a593Smuzhiyun 		dma_buf->len = len;
4702*4882a593Smuzhiyun 
4703*4882a593Smuzhiyun 		dma_buf->dma = dma_map_single(&hw_priv->pdev->dev, skb->data,
4704*4882a593Smuzhiyun 					      dma_buf->len, DMA_TO_DEVICE);
4705*4882a593Smuzhiyun 		set_tx_buf(desc, dma_buf->dma);
4706*4882a593Smuzhiyun 		set_tx_len(desc, dma_buf->len);
4707*4882a593Smuzhiyun 	}
4708*4882a593Smuzhiyun 
4709*4882a593Smuzhiyun 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
4710*4882a593Smuzhiyun 		(desc)->sw.buf.tx.csum_gen_tcp = 1;
4711*4882a593Smuzhiyun 		(desc)->sw.buf.tx.csum_gen_udp = 1;
4712*4882a593Smuzhiyun 	}
4713*4882a593Smuzhiyun 
4714*4882a593Smuzhiyun 	/*
4715*4882a593Smuzhiyun 	 * The last descriptor holds the packet so that it can be returned to
4716*4882a593Smuzhiyun 	 * network subsystem after all descriptors are transmitted.
4717*4882a593Smuzhiyun 	 */
4718*4882a593Smuzhiyun 	dma_buf->skb = skb;
4719*4882a593Smuzhiyun 
4720*4882a593Smuzhiyun 	hw_send_pkt(hw);
4721*4882a593Smuzhiyun 
4722*4882a593Smuzhiyun 	/* Update transmit statistics. */
4723*4882a593Smuzhiyun 	dev->stats.tx_packets++;
4724*4882a593Smuzhiyun 	dev->stats.tx_bytes += len;
4725*4882a593Smuzhiyun }
4726*4882a593Smuzhiyun 
4727*4882a593Smuzhiyun /**
4728*4882a593Smuzhiyun  * transmit_cleanup - clean up transmit descriptors
4729*4882a593Smuzhiyun  * @hw_priv:	Network device.
4730*4882a593Smuzhiyun  * @normal:	break if owned
4731*4882a593Smuzhiyun  *
4732*4882a593Smuzhiyun  * This routine is called to clean up the transmitted buffers.
4733*4882a593Smuzhiyun  */
transmit_cleanup(struct dev_info * hw_priv,int normal)4734*4882a593Smuzhiyun static void transmit_cleanup(struct dev_info *hw_priv, int normal)
4735*4882a593Smuzhiyun {
4736*4882a593Smuzhiyun 	int last;
4737*4882a593Smuzhiyun 	union desc_stat status;
4738*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
4739*4882a593Smuzhiyun 	struct ksz_desc_info *info = &hw->tx_desc_info;
4740*4882a593Smuzhiyun 	struct ksz_desc *desc;
4741*4882a593Smuzhiyun 	struct ksz_dma_buf *dma_buf;
4742*4882a593Smuzhiyun 	struct net_device *dev = NULL;
4743*4882a593Smuzhiyun 
4744*4882a593Smuzhiyun 	spin_lock_irq(&hw_priv->hwlock);
4745*4882a593Smuzhiyun 	last = info->last;
4746*4882a593Smuzhiyun 
4747*4882a593Smuzhiyun 	while (info->avail < info->alloc) {
4748*4882a593Smuzhiyun 		/* Get next descriptor which is not hardware owned. */
4749*4882a593Smuzhiyun 		desc = &info->ring[last];
4750*4882a593Smuzhiyun 		status.data = le32_to_cpu(desc->phw->ctrl.data);
4751*4882a593Smuzhiyun 		if (status.tx.hw_owned) {
4752*4882a593Smuzhiyun 			if (normal)
4753*4882a593Smuzhiyun 				break;
4754*4882a593Smuzhiyun 			else
4755*4882a593Smuzhiyun 				reset_desc(desc, status);
4756*4882a593Smuzhiyun 		}
4757*4882a593Smuzhiyun 
4758*4882a593Smuzhiyun 		dma_buf = DMA_BUFFER(desc);
4759*4882a593Smuzhiyun 		dma_unmap_single(&hw_priv->pdev->dev, dma_buf->dma,
4760*4882a593Smuzhiyun 				 dma_buf->len, DMA_TO_DEVICE);
4761*4882a593Smuzhiyun 
4762*4882a593Smuzhiyun 		/* This descriptor contains the last buffer in the packet. */
4763*4882a593Smuzhiyun 		if (dma_buf->skb) {
4764*4882a593Smuzhiyun 			dev = dma_buf->skb->dev;
4765*4882a593Smuzhiyun 
4766*4882a593Smuzhiyun 			/* Release the packet back to network subsystem. */
4767*4882a593Smuzhiyun 			dev_kfree_skb_irq(dma_buf->skb);
4768*4882a593Smuzhiyun 			dma_buf->skb = NULL;
4769*4882a593Smuzhiyun 		}
4770*4882a593Smuzhiyun 
4771*4882a593Smuzhiyun 		/* Free the transmitted descriptor. */
4772*4882a593Smuzhiyun 		last++;
4773*4882a593Smuzhiyun 		last &= info->mask;
4774*4882a593Smuzhiyun 		info->avail++;
4775*4882a593Smuzhiyun 	}
4776*4882a593Smuzhiyun 	info->last = last;
4777*4882a593Smuzhiyun 	spin_unlock_irq(&hw_priv->hwlock);
4778*4882a593Smuzhiyun 
4779*4882a593Smuzhiyun 	/* Notify the network subsystem that the packet has been sent. */
4780*4882a593Smuzhiyun 	if (dev)
4781*4882a593Smuzhiyun 		netif_trans_update(dev);
4782*4882a593Smuzhiyun }
4783*4882a593Smuzhiyun 
4784*4882a593Smuzhiyun /**
4785*4882a593Smuzhiyun  * transmit_done - transmit done processing
4786*4882a593Smuzhiyun  * @hw_priv:	Network device.
4787*4882a593Smuzhiyun  *
4788*4882a593Smuzhiyun  * This routine is called when the transmit interrupt is triggered, indicating
4789*4882a593Smuzhiyun  * either a packet is sent successfully or there are transmit errors.
4790*4882a593Smuzhiyun  */
tx_done(struct dev_info * hw_priv)4791*4882a593Smuzhiyun static void tx_done(struct dev_info *hw_priv)
4792*4882a593Smuzhiyun {
4793*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
4794*4882a593Smuzhiyun 	int port;
4795*4882a593Smuzhiyun 
4796*4882a593Smuzhiyun 	transmit_cleanup(hw_priv, 1);
4797*4882a593Smuzhiyun 
4798*4882a593Smuzhiyun 	for (port = 0; port < hw->dev_count; port++) {
4799*4882a593Smuzhiyun 		struct net_device *dev = hw->port_info[port].pdev;
4800*4882a593Smuzhiyun 
4801*4882a593Smuzhiyun 		if (netif_running(dev) && netif_queue_stopped(dev))
4802*4882a593Smuzhiyun 			netif_wake_queue(dev);
4803*4882a593Smuzhiyun 	}
4804*4882a593Smuzhiyun }
4805*4882a593Smuzhiyun 
copy_old_skb(struct sk_buff * old,struct sk_buff * skb)4806*4882a593Smuzhiyun static inline void copy_old_skb(struct sk_buff *old, struct sk_buff *skb)
4807*4882a593Smuzhiyun {
4808*4882a593Smuzhiyun 	skb->dev = old->dev;
4809*4882a593Smuzhiyun 	skb->protocol = old->protocol;
4810*4882a593Smuzhiyun 	skb->ip_summed = old->ip_summed;
4811*4882a593Smuzhiyun 	skb->csum = old->csum;
4812*4882a593Smuzhiyun 	skb_set_network_header(skb, ETH_HLEN);
4813*4882a593Smuzhiyun 
4814*4882a593Smuzhiyun 	dev_consume_skb_any(old);
4815*4882a593Smuzhiyun }
4816*4882a593Smuzhiyun 
4817*4882a593Smuzhiyun /**
4818*4882a593Smuzhiyun  * netdev_tx - send out packet
4819*4882a593Smuzhiyun  * @skb:	Socket buffer.
4820*4882a593Smuzhiyun  * @dev:	Network device.
4821*4882a593Smuzhiyun  *
4822*4882a593Smuzhiyun  * This function is used by the upper network layer to send out a packet.
4823*4882a593Smuzhiyun  *
4824*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code indicating failure.
4825*4882a593Smuzhiyun  */
netdev_tx(struct sk_buff * skb,struct net_device * dev)4826*4882a593Smuzhiyun static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev)
4827*4882a593Smuzhiyun {
4828*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
4829*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
4830*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
4831*4882a593Smuzhiyun 	int left;
4832*4882a593Smuzhiyun 	int num = 1;
4833*4882a593Smuzhiyun 	int rc = 0;
4834*4882a593Smuzhiyun 
4835*4882a593Smuzhiyun 	if (hw->features & SMALL_PACKET_TX_BUG) {
4836*4882a593Smuzhiyun 		struct sk_buff *org_skb = skb;
4837*4882a593Smuzhiyun 
4838*4882a593Smuzhiyun 		if (skb->len <= 48) {
4839*4882a593Smuzhiyun 			if (skb_end_pointer(skb) - skb->data >= 50) {
4840*4882a593Smuzhiyun 				memset(&skb->data[skb->len], 0, 50 - skb->len);
4841*4882a593Smuzhiyun 				skb->len = 50;
4842*4882a593Smuzhiyun 			} else {
4843*4882a593Smuzhiyun 				skb = netdev_alloc_skb(dev, 50);
4844*4882a593Smuzhiyun 				if (!skb)
4845*4882a593Smuzhiyun 					return NETDEV_TX_BUSY;
4846*4882a593Smuzhiyun 				memcpy(skb->data, org_skb->data, org_skb->len);
4847*4882a593Smuzhiyun 				memset(&skb->data[org_skb->len], 0,
4848*4882a593Smuzhiyun 					50 - org_skb->len);
4849*4882a593Smuzhiyun 				skb->len = 50;
4850*4882a593Smuzhiyun 				copy_old_skb(org_skb, skb);
4851*4882a593Smuzhiyun 			}
4852*4882a593Smuzhiyun 		}
4853*4882a593Smuzhiyun 	}
4854*4882a593Smuzhiyun 
4855*4882a593Smuzhiyun 	spin_lock_irq(&hw_priv->hwlock);
4856*4882a593Smuzhiyun 
4857*4882a593Smuzhiyun 	num = skb_shinfo(skb)->nr_frags + 1;
4858*4882a593Smuzhiyun 	left = hw_alloc_pkt(hw, skb->len, num);
4859*4882a593Smuzhiyun 	if (left) {
4860*4882a593Smuzhiyun 		if (left < num ||
4861*4882a593Smuzhiyun 		    (CHECKSUM_PARTIAL == skb->ip_summed &&
4862*4882a593Smuzhiyun 		     skb->protocol == htons(ETH_P_IPV6))) {
4863*4882a593Smuzhiyun 			struct sk_buff *org_skb = skb;
4864*4882a593Smuzhiyun 
4865*4882a593Smuzhiyun 			skb = netdev_alloc_skb(dev, org_skb->len);
4866*4882a593Smuzhiyun 			if (!skb) {
4867*4882a593Smuzhiyun 				rc = NETDEV_TX_BUSY;
4868*4882a593Smuzhiyun 				goto unlock;
4869*4882a593Smuzhiyun 			}
4870*4882a593Smuzhiyun 			skb_copy_and_csum_dev(org_skb, skb->data);
4871*4882a593Smuzhiyun 			org_skb->ip_summed = CHECKSUM_NONE;
4872*4882a593Smuzhiyun 			skb->len = org_skb->len;
4873*4882a593Smuzhiyun 			copy_old_skb(org_skb, skb);
4874*4882a593Smuzhiyun 		}
4875*4882a593Smuzhiyun 		send_packet(skb, dev);
4876*4882a593Smuzhiyun 		if (left <= num)
4877*4882a593Smuzhiyun 			netif_stop_queue(dev);
4878*4882a593Smuzhiyun 	} else {
4879*4882a593Smuzhiyun 		/* Stop the transmit queue until packet is allocated. */
4880*4882a593Smuzhiyun 		netif_stop_queue(dev);
4881*4882a593Smuzhiyun 		rc = NETDEV_TX_BUSY;
4882*4882a593Smuzhiyun 	}
4883*4882a593Smuzhiyun unlock:
4884*4882a593Smuzhiyun 	spin_unlock_irq(&hw_priv->hwlock);
4885*4882a593Smuzhiyun 
4886*4882a593Smuzhiyun 	return rc;
4887*4882a593Smuzhiyun }
4888*4882a593Smuzhiyun 
4889*4882a593Smuzhiyun /**
4890*4882a593Smuzhiyun  * netdev_tx_timeout - transmit timeout processing
4891*4882a593Smuzhiyun  * @dev:	Network device.
4892*4882a593Smuzhiyun  * @txqueue:	index of hanging queue
4893*4882a593Smuzhiyun  *
4894*4882a593Smuzhiyun  * This routine is called when the transmit timer expires.  That indicates the
4895*4882a593Smuzhiyun  * hardware is not running correctly because transmit interrupts are not
4896*4882a593Smuzhiyun  * triggered to free up resources so that the transmit routine can continue
4897*4882a593Smuzhiyun  * sending out packets.  The hardware is reset to correct the problem.
4898*4882a593Smuzhiyun  */
netdev_tx_timeout(struct net_device * dev,unsigned int txqueue)4899*4882a593Smuzhiyun static void netdev_tx_timeout(struct net_device *dev, unsigned int txqueue)
4900*4882a593Smuzhiyun {
4901*4882a593Smuzhiyun 	static unsigned long last_reset;
4902*4882a593Smuzhiyun 
4903*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
4904*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
4905*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
4906*4882a593Smuzhiyun 	int port;
4907*4882a593Smuzhiyun 
4908*4882a593Smuzhiyun 	if (hw->dev_count > 1) {
4909*4882a593Smuzhiyun 		/*
4910*4882a593Smuzhiyun 		 * Only reset the hardware if time between calls is long
4911*4882a593Smuzhiyun 		 * enough.
4912*4882a593Smuzhiyun 		 */
4913*4882a593Smuzhiyun 		if (time_before_eq(jiffies, last_reset + dev->watchdog_timeo))
4914*4882a593Smuzhiyun 			hw_priv = NULL;
4915*4882a593Smuzhiyun 	}
4916*4882a593Smuzhiyun 
4917*4882a593Smuzhiyun 	last_reset = jiffies;
4918*4882a593Smuzhiyun 	if (hw_priv) {
4919*4882a593Smuzhiyun 		hw_dis_intr(hw);
4920*4882a593Smuzhiyun 		hw_disable(hw);
4921*4882a593Smuzhiyun 
4922*4882a593Smuzhiyun 		transmit_cleanup(hw_priv, 0);
4923*4882a593Smuzhiyun 		hw_reset_pkts(&hw->rx_desc_info);
4924*4882a593Smuzhiyun 		hw_reset_pkts(&hw->tx_desc_info);
4925*4882a593Smuzhiyun 		ksz_init_rx_buffers(hw_priv);
4926*4882a593Smuzhiyun 
4927*4882a593Smuzhiyun 		hw_reset(hw);
4928*4882a593Smuzhiyun 
4929*4882a593Smuzhiyun 		hw_set_desc_base(hw,
4930*4882a593Smuzhiyun 			hw->tx_desc_info.ring_phys,
4931*4882a593Smuzhiyun 			hw->rx_desc_info.ring_phys);
4932*4882a593Smuzhiyun 		hw_set_addr(hw);
4933*4882a593Smuzhiyun 		if (hw->all_multi)
4934*4882a593Smuzhiyun 			hw_set_multicast(hw, hw->all_multi);
4935*4882a593Smuzhiyun 		else if (hw->multi_list_size)
4936*4882a593Smuzhiyun 			hw_set_grp_addr(hw);
4937*4882a593Smuzhiyun 
4938*4882a593Smuzhiyun 		if (hw->dev_count > 1) {
4939*4882a593Smuzhiyun 			hw_set_add_addr(hw);
4940*4882a593Smuzhiyun 			for (port = 0; port < SWITCH_PORT_NUM; port++) {
4941*4882a593Smuzhiyun 				struct net_device *port_dev;
4942*4882a593Smuzhiyun 
4943*4882a593Smuzhiyun 				port_set_stp_state(hw, port,
4944*4882a593Smuzhiyun 					STP_STATE_DISABLED);
4945*4882a593Smuzhiyun 
4946*4882a593Smuzhiyun 				port_dev = hw->port_info[port].pdev;
4947*4882a593Smuzhiyun 				if (netif_running(port_dev))
4948*4882a593Smuzhiyun 					port_set_stp_state(hw, port,
4949*4882a593Smuzhiyun 						STP_STATE_SIMPLE);
4950*4882a593Smuzhiyun 			}
4951*4882a593Smuzhiyun 		}
4952*4882a593Smuzhiyun 
4953*4882a593Smuzhiyun 		hw_enable(hw);
4954*4882a593Smuzhiyun 		hw_ena_intr(hw);
4955*4882a593Smuzhiyun 	}
4956*4882a593Smuzhiyun 
4957*4882a593Smuzhiyun 	netif_trans_update(dev);
4958*4882a593Smuzhiyun 	netif_wake_queue(dev);
4959*4882a593Smuzhiyun }
4960*4882a593Smuzhiyun 
csum_verified(struct sk_buff * skb)4961*4882a593Smuzhiyun static inline void csum_verified(struct sk_buff *skb)
4962*4882a593Smuzhiyun {
4963*4882a593Smuzhiyun 	unsigned short protocol;
4964*4882a593Smuzhiyun 	struct iphdr *iph;
4965*4882a593Smuzhiyun 
4966*4882a593Smuzhiyun 	protocol = skb->protocol;
4967*4882a593Smuzhiyun 	skb_reset_network_header(skb);
4968*4882a593Smuzhiyun 	iph = (struct iphdr *) skb_network_header(skb);
4969*4882a593Smuzhiyun 	if (protocol == htons(ETH_P_8021Q)) {
4970*4882a593Smuzhiyun 		protocol = iph->tot_len;
4971*4882a593Smuzhiyun 		skb_set_network_header(skb, VLAN_HLEN);
4972*4882a593Smuzhiyun 		iph = (struct iphdr *) skb_network_header(skb);
4973*4882a593Smuzhiyun 	}
4974*4882a593Smuzhiyun 	if (protocol == htons(ETH_P_IP)) {
4975*4882a593Smuzhiyun 		if (iph->protocol == IPPROTO_TCP)
4976*4882a593Smuzhiyun 			skb->ip_summed = CHECKSUM_UNNECESSARY;
4977*4882a593Smuzhiyun 	}
4978*4882a593Smuzhiyun }
4979*4882a593Smuzhiyun 
rx_proc(struct net_device * dev,struct ksz_hw * hw,struct ksz_desc * desc,union desc_stat status)4980*4882a593Smuzhiyun static inline int rx_proc(struct net_device *dev, struct ksz_hw* hw,
4981*4882a593Smuzhiyun 	struct ksz_desc *desc, union desc_stat status)
4982*4882a593Smuzhiyun {
4983*4882a593Smuzhiyun 	int packet_len;
4984*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
4985*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
4986*4882a593Smuzhiyun 	struct ksz_dma_buf *dma_buf;
4987*4882a593Smuzhiyun 	struct sk_buff *skb;
4988*4882a593Smuzhiyun 
4989*4882a593Smuzhiyun 	/* Received length includes 4-byte CRC. */
4990*4882a593Smuzhiyun 	packet_len = status.rx.frame_len - 4;
4991*4882a593Smuzhiyun 
4992*4882a593Smuzhiyun 	dma_buf = DMA_BUFFER(desc);
4993*4882a593Smuzhiyun 	dma_sync_single_for_cpu(&hw_priv->pdev->dev, dma_buf->dma,
4994*4882a593Smuzhiyun 				packet_len + 4, DMA_FROM_DEVICE);
4995*4882a593Smuzhiyun 
4996*4882a593Smuzhiyun 	do {
4997*4882a593Smuzhiyun 		/* skb->data != skb->head */
4998*4882a593Smuzhiyun 		skb = netdev_alloc_skb(dev, packet_len + 2);
4999*4882a593Smuzhiyun 		if (!skb) {
5000*4882a593Smuzhiyun 			dev->stats.rx_dropped++;
5001*4882a593Smuzhiyun 			return -ENOMEM;
5002*4882a593Smuzhiyun 		}
5003*4882a593Smuzhiyun 
5004*4882a593Smuzhiyun 		/*
5005*4882a593Smuzhiyun 		 * Align socket buffer in 4-byte boundary for better
5006*4882a593Smuzhiyun 		 * performance.
5007*4882a593Smuzhiyun 		 */
5008*4882a593Smuzhiyun 		skb_reserve(skb, 2);
5009*4882a593Smuzhiyun 
5010*4882a593Smuzhiyun 		skb_put_data(skb, dma_buf->skb->data, packet_len);
5011*4882a593Smuzhiyun 	} while (0);
5012*4882a593Smuzhiyun 
5013*4882a593Smuzhiyun 	skb->protocol = eth_type_trans(skb, dev);
5014*4882a593Smuzhiyun 
5015*4882a593Smuzhiyun 	if (hw->rx_cfg & (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP))
5016*4882a593Smuzhiyun 		csum_verified(skb);
5017*4882a593Smuzhiyun 
5018*4882a593Smuzhiyun 	/* Update receive statistics. */
5019*4882a593Smuzhiyun 	dev->stats.rx_packets++;
5020*4882a593Smuzhiyun 	dev->stats.rx_bytes += packet_len;
5021*4882a593Smuzhiyun 
5022*4882a593Smuzhiyun 	/* Notify upper layer for received packet. */
5023*4882a593Smuzhiyun 	netif_rx(skb);
5024*4882a593Smuzhiyun 
5025*4882a593Smuzhiyun 	return 0;
5026*4882a593Smuzhiyun }
5027*4882a593Smuzhiyun 
dev_rcv_packets(struct dev_info * hw_priv)5028*4882a593Smuzhiyun static int dev_rcv_packets(struct dev_info *hw_priv)
5029*4882a593Smuzhiyun {
5030*4882a593Smuzhiyun 	int next;
5031*4882a593Smuzhiyun 	union desc_stat status;
5032*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5033*4882a593Smuzhiyun 	struct net_device *dev = hw->port_info[0].pdev;
5034*4882a593Smuzhiyun 	struct ksz_desc_info *info = &hw->rx_desc_info;
5035*4882a593Smuzhiyun 	int left = info->alloc;
5036*4882a593Smuzhiyun 	struct ksz_desc *desc;
5037*4882a593Smuzhiyun 	int received = 0;
5038*4882a593Smuzhiyun 
5039*4882a593Smuzhiyun 	next = info->next;
5040*4882a593Smuzhiyun 	while (left--) {
5041*4882a593Smuzhiyun 		/* Get next descriptor which is not hardware owned. */
5042*4882a593Smuzhiyun 		desc = &info->ring[next];
5043*4882a593Smuzhiyun 		status.data = le32_to_cpu(desc->phw->ctrl.data);
5044*4882a593Smuzhiyun 		if (status.rx.hw_owned)
5045*4882a593Smuzhiyun 			break;
5046*4882a593Smuzhiyun 
5047*4882a593Smuzhiyun 		/* Status valid only when last descriptor bit is set. */
5048*4882a593Smuzhiyun 		if (status.rx.last_desc && status.rx.first_desc) {
5049*4882a593Smuzhiyun 			if (rx_proc(dev, hw, desc, status))
5050*4882a593Smuzhiyun 				goto release_packet;
5051*4882a593Smuzhiyun 			received++;
5052*4882a593Smuzhiyun 		}
5053*4882a593Smuzhiyun 
5054*4882a593Smuzhiyun release_packet:
5055*4882a593Smuzhiyun 		release_desc(desc);
5056*4882a593Smuzhiyun 		next++;
5057*4882a593Smuzhiyun 		next &= info->mask;
5058*4882a593Smuzhiyun 	}
5059*4882a593Smuzhiyun 	info->next = next;
5060*4882a593Smuzhiyun 
5061*4882a593Smuzhiyun 	return received;
5062*4882a593Smuzhiyun }
5063*4882a593Smuzhiyun 
port_rcv_packets(struct dev_info * hw_priv)5064*4882a593Smuzhiyun static int port_rcv_packets(struct dev_info *hw_priv)
5065*4882a593Smuzhiyun {
5066*4882a593Smuzhiyun 	int next;
5067*4882a593Smuzhiyun 	union desc_stat status;
5068*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5069*4882a593Smuzhiyun 	struct net_device *dev = hw->port_info[0].pdev;
5070*4882a593Smuzhiyun 	struct ksz_desc_info *info = &hw->rx_desc_info;
5071*4882a593Smuzhiyun 	int left = info->alloc;
5072*4882a593Smuzhiyun 	struct ksz_desc *desc;
5073*4882a593Smuzhiyun 	int received = 0;
5074*4882a593Smuzhiyun 
5075*4882a593Smuzhiyun 	next = info->next;
5076*4882a593Smuzhiyun 	while (left--) {
5077*4882a593Smuzhiyun 		/* Get next descriptor which is not hardware owned. */
5078*4882a593Smuzhiyun 		desc = &info->ring[next];
5079*4882a593Smuzhiyun 		status.data = le32_to_cpu(desc->phw->ctrl.data);
5080*4882a593Smuzhiyun 		if (status.rx.hw_owned)
5081*4882a593Smuzhiyun 			break;
5082*4882a593Smuzhiyun 
5083*4882a593Smuzhiyun 		if (hw->dev_count > 1) {
5084*4882a593Smuzhiyun 			/* Get received port number. */
5085*4882a593Smuzhiyun 			int p = HW_TO_DEV_PORT(status.rx.src_port);
5086*4882a593Smuzhiyun 
5087*4882a593Smuzhiyun 			dev = hw->port_info[p].pdev;
5088*4882a593Smuzhiyun 			if (!netif_running(dev))
5089*4882a593Smuzhiyun 				goto release_packet;
5090*4882a593Smuzhiyun 		}
5091*4882a593Smuzhiyun 
5092*4882a593Smuzhiyun 		/* Status valid only when last descriptor bit is set. */
5093*4882a593Smuzhiyun 		if (status.rx.last_desc && status.rx.first_desc) {
5094*4882a593Smuzhiyun 			if (rx_proc(dev, hw, desc, status))
5095*4882a593Smuzhiyun 				goto release_packet;
5096*4882a593Smuzhiyun 			received++;
5097*4882a593Smuzhiyun 		}
5098*4882a593Smuzhiyun 
5099*4882a593Smuzhiyun release_packet:
5100*4882a593Smuzhiyun 		release_desc(desc);
5101*4882a593Smuzhiyun 		next++;
5102*4882a593Smuzhiyun 		next &= info->mask;
5103*4882a593Smuzhiyun 	}
5104*4882a593Smuzhiyun 	info->next = next;
5105*4882a593Smuzhiyun 
5106*4882a593Smuzhiyun 	return received;
5107*4882a593Smuzhiyun }
5108*4882a593Smuzhiyun 
dev_rcv_special(struct dev_info * hw_priv)5109*4882a593Smuzhiyun static int dev_rcv_special(struct dev_info *hw_priv)
5110*4882a593Smuzhiyun {
5111*4882a593Smuzhiyun 	int next;
5112*4882a593Smuzhiyun 	union desc_stat status;
5113*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5114*4882a593Smuzhiyun 	struct net_device *dev = hw->port_info[0].pdev;
5115*4882a593Smuzhiyun 	struct ksz_desc_info *info = &hw->rx_desc_info;
5116*4882a593Smuzhiyun 	int left = info->alloc;
5117*4882a593Smuzhiyun 	struct ksz_desc *desc;
5118*4882a593Smuzhiyun 	int received = 0;
5119*4882a593Smuzhiyun 
5120*4882a593Smuzhiyun 	next = info->next;
5121*4882a593Smuzhiyun 	while (left--) {
5122*4882a593Smuzhiyun 		/* Get next descriptor which is not hardware owned. */
5123*4882a593Smuzhiyun 		desc = &info->ring[next];
5124*4882a593Smuzhiyun 		status.data = le32_to_cpu(desc->phw->ctrl.data);
5125*4882a593Smuzhiyun 		if (status.rx.hw_owned)
5126*4882a593Smuzhiyun 			break;
5127*4882a593Smuzhiyun 
5128*4882a593Smuzhiyun 		if (hw->dev_count > 1) {
5129*4882a593Smuzhiyun 			/* Get received port number. */
5130*4882a593Smuzhiyun 			int p = HW_TO_DEV_PORT(status.rx.src_port);
5131*4882a593Smuzhiyun 
5132*4882a593Smuzhiyun 			dev = hw->port_info[p].pdev;
5133*4882a593Smuzhiyun 			if (!netif_running(dev))
5134*4882a593Smuzhiyun 				goto release_packet;
5135*4882a593Smuzhiyun 		}
5136*4882a593Smuzhiyun 
5137*4882a593Smuzhiyun 		/* Status valid only when last descriptor bit is set. */
5138*4882a593Smuzhiyun 		if (status.rx.last_desc && status.rx.first_desc) {
5139*4882a593Smuzhiyun 			/*
5140*4882a593Smuzhiyun 			 * Receive without error.  With receive errors
5141*4882a593Smuzhiyun 			 * disabled, packets with receive errors will be
5142*4882a593Smuzhiyun 			 * dropped, so no need to check the error bit.
5143*4882a593Smuzhiyun 			 */
5144*4882a593Smuzhiyun 			if (!status.rx.error || (status.data &
5145*4882a593Smuzhiyun 					KS_DESC_RX_ERROR_COND) ==
5146*4882a593Smuzhiyun 					KS_DESC_RX_ERROR_TOO_LONG) {
5147*4882a593Smuzhiyun 				if (rx_proc(dev, hw, desc, status))
5148*4882a593Smuzhiyun 					goto release_packet;
5149*4882a593Smuzhiyun 				received++;
5150*4882a593Smuzhiyun 			} else {
5151*4882a593Smuzhiyun 				struct dev_priv *priv = netdev_priv(dev);
5152*4882a593Smuzhiyun 
5153*4882a593Smuzhiyun 				/* Update receive error statistics. */
5154*4882a593Smuzhiyun 				priv->port.counter[OID_COUNTER_RCV_ERROR]++;
5155*4882a593Smuzhiyun 			}
5156*4882a593Smuzhiyun 		}
5157*4882a593Smuzhiyun 
5158*4882a593Smuzhiyun release_packet:
5159*4882a593Smuzhiyun 		release_desc(desc);
5160*4882a593Smuzhiyun 		next++;
5161*4882a593Smuzhiyun 		next &= info->mask;
5162*4882a593Smuzhiyun 	}
5163*4882a593Smuzhiyun 	info->next = next;
5164*4882a593Smuzhiyun 
5165*4882a593Smuzhiyun 	return received;
5166*4882a593Smuzhiyun }
5167*4882a593Smuzhiyun 
rx_proc_task(struct tasklet_struct * t)5168*4882a593Smuzhiyun static void rx_proc_task(struct tasklet_struct *t)
5169*4882a593Smuzhiyun {
5170*4882a593Smuzhiyun 	struct dev_info *hw_priv = from_tasklet(hw_priv, t, rx_tasklet);
5171*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5172*4882a593Smuzhiyun 
5173*4882a593Smuzhiyun 	if (!hw->enabled)
5174*4882a593Smuzhiyun 		return;
5175*4882a593Smuzhiyun 	if (unlikely(!hw_priv->dev_rcv(hw_priv))) {
5176*4882a593Smuzhiyun 
5177*4882a593Smuzhiyun 		/* In case receive process is suspended because of overrun. */
5178*4882a593Smuzhiyun 		hw_resume_rx(hw);
5179*4882a593Smuzhiyun 
5180*4882a593Smuzhiyun 		/* tasklets are interruptible. */
5181*4882a593Smuzhiyun 		spin_lock_irq(&hw_priv->hwlock);
5182*4882a593Smuzhiyun 		hw_turn_on_intr(hw, KS884X_INT_RX_MASK);
5183*4882a593Smuzhiyun 		spin_unlock_irq(&hw_priv->hwlock);
5184*4882a593Smuzhiyun 	} else {
5185*4882a593Smuzhiyun 		hw_ack_intr(hw, KS884X_INT_RX);
5186*4882a593Smuzhiyun 		tasklet_schedule(&hw_priv->rx_tasklet);
5187*4882a593Smuzhiyun 	}
5188*4882a593Smuzhiyun }
5189*4882a593Smuzhiyun 
tx_proc_task(struct tasklet_struct * t)5190*4882a593Smuzhiyun static void tx_proc_task(struct tasklet_struct *t)
5191*4882a593Smuzhiyun {
5192*4882a593Smuzhiyun 	struct dev_info *hw_priv = from_tasklet(hw_priv, t, tx_tasklet);
5193*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5194*4882a593Smuzhiyun 
5195*4882a593Smuzhiyun 	hw_ack_intr(hw, KS884X_INT_TX_MASK);
5196*4882a593Smuzhiyun 
5197*4882a593Smuzhiyun 	tx_done(hw_priv);
5198*4882a593Smuzhiyun 
5199*4882a593Smuzhiyun 	/* tasklets are interruptible. */
5200*4882a593Smuzhiyun 	spin_lock_irq(&hw_priv->hwlock);
5201*4882a593Smuzhiyun 	hw_turn_on_intr(hw, KS884X_INT_TX);
5202*4882a593Smuzhiyun 	spin_unlock_irq(&hw_priv->hwlock);
5203*4882a593Smuzhiyun }
5204*4882a593Smuzhiyun 
handle_rx_stop(struct ksz_hw * hw)5205*4882a593Smuzhiyun static inline void handle_rx_stop(struct ksz_hw *hw)
5206*4882a593Smuzhiyun {
5207*4882a593Smuzhiyun 	/* Receive just has been stopped. */
5208*4882a593Smuzhiyun 	if (0 == hw->rx_stop)
5209*4882a593Smuzhiyun 		hw->intr_mask &= ~KS884X_INT_RX_STOPPED;
5210*4882a593Smuzhiyun 	else if (hw->rx_stop > 1) {
5211*4882a593Smuzhiyun 		if (hw->enabled && (hw->rx_cfg & DMA_RX_ENABLE)) {
5212*4882a593Smuzhiyun 			hw_start_rx(hw);
5213*4882a593Smuzhiyun 		} else {
5214*4882a593Smuzhiyun 			hw->intr_mask &= ~KS884X_INT_RX_STOPPED;
5215*4882a593Smuzhiyun 			hw->rx_stop = 0;
5216*4882a593Smuzhiyun 		}
5217*4882a593Smuzhiyun 	} else
5218*4882a593Smuzhiyun 		/* Receive just has been started. */
5219*4882a593Smuzhiyun 		hw->rx_stop++;
5220*4882a593Smuzhiyun }
5221*4882a593Smuzhiyun 
5222*4882a593Smuzhiyun /**
5223*4882a593Smuzhiyun  * netdev_intr - interrupt handling
5224*4882a593Smuzhiyun  * @irq:	Interrupt number.
5225*4882a593Smuzhiyun  * @dev_id:	Network device.
5226*4882a593Smuzhiyun  *
5227*4882a593Smuzhiyun  * This function is called by upper network layer to signal interrupt.
5228*4882a593Smuzhiyun  *
5229*4882a593Smuzhiyun  * Return IRQ_HANDLED if interrupt is handled.
5230*4882a593Smuzhiyun  */
netdev_intr(int irq,void * dev_id)5231*4882a593Smuzhiyun static irqreturn_t netdev_intr(int irq, void *dev_id)
5232*4882a593Smuzhiyun {
5233*4882a593Smuzhiyun 	uint int_enable = 0;
5234*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *) dev_id;
5235*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5236*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5237*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5238*4882a593Smuzhiyun 
5239*4882a593Smuzhiyun 	spin_lock(&hw_priv->hwlock);
5240*4882a593Smuzhiyun 
5241*4882a593Smuzhiyun 	hw_read_intr(hw, &int_enable);
5242*4882a593Smuzhiyun 
5243*4882a593Smuzhiyun 	/* Not our interrupt! */
5244*4882a593Smuzhiyun 	if (!int_enable) {
5245*4882a593Smuzhiyun 		spin_unlock(&hw_priv->hwlock);
5246*4882a593Smuzhiyun 		return IRQ_NONE;
5247*4882a593Smuzhiyun 	}
5248*4882a593Smuzhiyun 
5249*4882a593Smuzhiyun 	do {
5250*4882a593Smuzhiyun 		hw_ack_intr(hw, int_enable);
5251*4882a593Smuzhiyun 		int_enable &= hw->intr_mask;
5252*4882a593Smuzhiyun 
5253*4882a593Smuzhiyun 		if (unlikely(int_enable & KS884X_INT_TX_MASK)) {
5254*4882a593Smuzhiyun 			hw_dis_intr_bit(hw, KS884X_INT_TX_MASK);
5255*4882a593Smuzhiyun 			tasklet_schedule(&hw_priv->tx_tasklet);
5256*4882a593Smuzhiyun 		}
5257*4882a593Smuzhiyun 
5258*4882a593Smuzhiyun 		if (likely(int_enable & KS884X_INT_RX)) {
5259*4882a593Smuzhiyun 			hw_dis_intr_bit(hw, KS884X_INT_RX);
5260*4882a593Smuzhiyun 			tasklet_schedule(&hw_priv->rx_tasklet);
5261*4882a593Smuzhiyun 		}
5262*4882a593Smuzhiyun 
5263*4882a593Smuzhiyun 		if (unlikely(int_enable & KS884X_INT_RX_OVERRUN)) {
5264*4882a593Smuzhiyun 			dev->stats.rx_fifo_errors++;
5265*4882a593Smuzhiyun 			hw_resume_rx(hw);
5266*4882a593Smuzhiyun 		}
5267*4882a593Smuzhiyun 
5268*4882a593Smuzhiyun 		if (unlikely(int_enable & KS884X_INT_PHY)) {
5269*4882a593Smuzhiyun 			struct ksz_port *port = &priv->port;
5270*4882a593Smuzhiyun 
5271*4882a593Smuzhiyun 			hw->features |= LINK_INT_WORKING;
5272*4882a593Smuzhiyun 			port_get_link_speed(port);
5273*4882a593Smuzhiyun 		}
5274*4882a593Smuzhiyun 
5275*4882a593Smuzhiyun 		if (unlikely(int_enable & KS884X_INT_RX_STOPPED)) {
5276*4882a593Smuzhiyun 			handle_rx_stop(hw);
5277*4882a593Smuzhiyun 			break;
5278*4882a593Smuzhiyun 		}
5279*4882a593Smuzhiyun 
5280*4882a593Smuzhiyun 		if (unlikely(int_enable & KS884X_INT_TX_STOPPED)) {
5281*4882a593Smuzhiyun 			u32 data;
5282*4882a593Smuzhiyun 
5283*4882a593Smuzhiyun 			hw->intr_mask &= ~KS884X_INT_TX_STOPPED;
5284*4882a593Smuzhiyun 			pr_info("Tx stopped\n");
5285*4882a593Smuzhiyun 			data = readl(hw->io + KS_DMA_TX_CTRL);
5286*4882a593Smuzhiyun 			if (!(data & DMA_TX_ENABLE))
5287*4882a593Smuzhiyun 				pr_info("Tx disabled\n");
5288*4882a593Smuzhiyun 			break;
5289*4882a593Smuzhiyun 		}
5290*4882a593Smuzhiyun 	} while (0);
5291*4882a593Smuzhiyun 
5292*4882a593Smuzhiyun 	hw_ena_intr(hw);
5293*4882a593Smuzhiyun 
5294*4882a593Smuzhiyun 	spin_unlock(&hw_priv->hwlock);
5295*4882a593Smuzhiyun 
5296*4882a593Smuzhiyun 	return IRQ_HANDLED;
5297*4882a593Smuzhiyun }
5298*4882a593Smuzhiyun 
5299*4882a593Smuzhiyun /*
5300*4882a593Smuzhiyun  * Linux network device functions
5301*4882a593Smuzhiyun  */
5302*4882a593Smuzhiyun 
5303*4882a593Smuzhiyun static unsigned long next_jiffies;
5304*4882a593Smuzhiyun 
5305*4882a593Smuzhiyun #ifdef CONFIG_NET_POLL_CONTROLLER
netdev_netpoll(struct net_device * dev)5306*4882a593Smuzhiyun static void netdev_netpoll(struct net_device *dev)
5307*4882a593Smuzhiyun {
5308*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5309*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5310*4882a593Smuzhiyun 
5311*4882a593Smuzhiyun 	hw_dis_intr(&hw_priv->hw);
5312*4882a593Smuzhiyun 	netdev_intr(dev->irq, dev);
5313*4882a593Smuzhiyun }
5314*4882a593Smuzhiyun #endif
5315*4882a593Smuzhiyun 
bridge_change(struct ksz_hw * hw)5316*4882a593Smuzhiyun static void bridge_change(struct ksz_hw *hw)
5317*4882a593Smuzhiyun {
5318*4882a593Smuzhiyun 	int port;
5319*4882a593Smuzhiyun 	u8  member;
5320*4882a593Smuzhiyun 	struct ksz_switch *sw = hw->ksz_switch;
5321*4882a593Smuzhiyun 
5322*4882a593Smuzhiyun 	/* No ports in forwarding state. */
5323*4882a593Smuzhiyun 	if (!sw->member) {
5324*4882a593Smuzhiyun 		port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_SIMPLE);
5325*4882a593Smuzhiyun 		sw_block_addr(hw);
5326*4882a593Smuzhiyun 	}
5327*4882a593Smuzhiyun 	for (port = 0; port < SWITCH_PORT_NUM; port++) {
5328*4882a593Smuzhiyun 		if (STP_STATE_FORWARDING == sw->port_cfg[port].stp_state)
5329*4882a593Smuzhiyun 			member = HOST_MASK | sw->member;
5330*4882a593Smuzhiyun 		else
5331*4882a593Smuzhiyun 			member = HOST_MASK | (1 << port);
5332*4882a593Smuzhiyun 		if (member != sw->port_cfg[port].member)
5333*4882a593Smuzhiyun 			sw_cfg_port_base_vlan(hw, port, member);
5334*4882a593Smuzhiyun 	}
5335*4882a593Smuzhiyun }
5336*4882a593Smuzhiyun 
5337*4882a593Smuzhiyun /**
5338*4882a593Smuzhiyun  * netdev_close - close network device
5339*4882a593Smuzhiyun  * @dev:	Network device.
5340*4882a593Smuzhiyun  *
5341*4882a593Smuzhiyun  * This function process the close operation of network device.  This is caused
5342*4882a593Smuzhiyun  * by the user command "ifconfig ethX down."
5343*4882a593Smuzhiyun  *
5344*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code indicating failure.
5345*4882a593Smuzhiyun  */
netdev_close(struct net_device * dev)5346*4882a593Smuzhiyun static int netdev_close(struct net_device *dev)
5347*4882a593Smuzhiyun {
5348*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5349*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5350*4882a593Smuzhiyun 	struct ksz_port *port = &priv->port;
5351*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5352*4882a593Smuzhiyun 	int pi;
5353*4882a593Smuzhiyun 
5354*4882a593Smuzhiyun 	netif_stop_queue(dev);
5355*4882a593Smuzhiyun 
5356*4882a593Smuzhiyun 	ksz_stop_timer(&priv->monitor_timer_info);
5357*4882a593Smuzhiyun 
5358*4882a593Smuzhiyun 	/* Need to shut the port manually in multiple device interfaces mode. */
5359*4882a593Smuzhiyun 	if (hw->dev_count > 1) {
5360*4882a593Smuzhiyun 		port_set_stp_state(hw, port->first_port, STP_STATE_DISABLED);
5361*4882a593Smuzhiyun 
5362*4882a593Smuzhiyun 		/* Port is closed.  Need to change bridge setting. */
5363*4882a593Smuzhiyun 		if (hw->features & STP_SUPPORT) {
5364*4882a593Smuzhiyun 			pi = 1 << port->first_port;
5365*4882a593Smuzhiyun 			if (hw->ksz_switch->member & pi) {
5366*4882a593Smuzhiyun 				hw->ksz_switch->member &= ~pi;
5367*4882a593Smuzhiyun 				bridge_change(hw);
5368*4882a593Smuzhiyun 			}
5369*4882a593Smuzhiyun 		}
5370*4882a593Smuzhiyun 	}
5371*4882a593Smuzhiyun 	if (port->first_port > 0)
5372*4882a593Smuzhiyun 		hw_del_addr(hw, dev->dev_addr);
5373*4882a593Smuzhiyun 	if (!hw_priv->wol_enable)
5374*4882a593Smuzhiyun 		port_set_power_saving(port, true);
5375*4882a593Smuzhiyun 
5376*4882a593Smuzhiyun 	if (priv->multicast)
5377*4882a593Smuzhiyun 		--hw->all_multi;
5378*4882a593Smuzhiyun 	if (priv->promiscuous)
5379*4882a593Smuzhiyun 		--hw->promiscuous;
5380*4882a593Smuzhiyun 
5381*4882a593Smuzhiyun 	hw_priv->opened--;
5382*4882a593Smuzhiyun 	if (!(hw_priv->opened)) {
5383*4882a593Smuzhiyun 		ksz_stop_timer(&hw_priv->mib_timer_info);
5384*4882a593Smuzhiyun 		flush_work(&hw_priv->mib_read);
5385*4882a593Smuzhiyun 
5386*4882a593Smuzhiyun 		hw_dis_intr(hw);
5387*4882a593Smuzhiyun 		hw_disable(hw);
5388*4882a593Smuzhiyun 		hw_clr_multicast(hw);
5389*4882a593Smuzhiyun 
5390*4882a593Smuzhiyun 		/* Delay for receive task to stop scheduling itself. */
5391*4882a593Smuzhiyun 		msleep(2000 / HZ);
5392*4882a593Smuzhiyun 
5393*4882a593Smuzhiyun 		tasklet_kill(&hw_priv->rx_tasklet);
5394*4882a593Smuzhiyun 		tasklet_kill(&hw_priv->tx_tasklet);
5395*4882a593Smuzhiyun 		free_irq(dev->irq, hw_priv->dev);
5396*4882a593Smuzhiyun 
5397*4882a593Smuzhiyun 		transmit_cleanup(hw_priv, 0);
5398*4882a593Smuzhiyun 		hw_reset_pkts(&hw->rx_desc_info);
5399*4882a593Smuzhiyun 		hw_reset_pkts(&hw->tx_desc_info);
5400*4882a593Smuzhiyun 
5401*4882a593Smuzhiyun 		/* Clean out static MAC table when the switch is shutdown. */
5402*4882a593Smuzhiyun 		if (hw->features & STP_SUPPORT)
5403*4882a593Smuzhiyun 			sw_clr_sta_mac_table(hw);
5404*4882a593Smuzhiyun 	}
5405*4882a593Smuzhiyun 
5406*4882a593Smuzhiyun 	return 0;
5407*4882a593Smuzhiyun }
5408*4882a593Smuzhiyun 
hw_cfg_huge_frame(struct dev_info * hw_priv,struct ksz_hw * hw)5409*4882a593Smuzhiyun static void hw_cfg_huge_frame(struct dev_info *hw_priv, struct ksz_hw *hw)
5410*4882a593Smuzhiyun {
5411*4882a593Smuzhiyun 	if (hw->ksz_switch) {
5412*4882a593Smuzhiyun 		u32 data;
5413*4882a593Smuzhiyun 
5414*4882a593Smuzhiyun 		data = readw(hw->io + KS8842_SWITCH_CTRL_2_OFFSET);
5415*4882a593Smuzhiyun 		if (hw->features & RX_HUGE_FRAME)
5416*4882a593Smuzhiyun 			data |= SWITCH_HUGE_PACKET;
5417*4882a593Smuzhiyun 		else
5418*4882a593Smuzhiyun 			data &= ~SWITCH_HUGE_PACKET;
5419*4882a593Smuzhiyun 		writew(data, hw->io + KS8842_SWITCH_CTRL_2_OFFSET);
5420*4882a593Smuzhiyun 	}
5421*4882a593Smuzhiyun 	if (hw->features & RX_HUGE_FRAME) {
5422*4882a593Smuzhiyun 		hw->rx_cfg |= DMA_RX_ERROR;
5423*4882a593Smuzhiyun 		hw_priv->dev_rcv = dev_rcv_special;
5424*4882a593Smuzhiyun 	} else {
5425*4882a593Smuzhiyun 		hw->rx_cfg &= ~DMA_RX_ERROR;
5426*4882a593Smuzhiyun 		if (hw->dev_count > 1)
5427*4882a593Smuzhiyun 			hw_priv->dev_rcv = port_rcv_packets;
5428*4882a593Smuzhiyun 		else
5429*4882a593Smuzhiyun 			hw_priv->dev_rcv = dev_rcv_packets;
5430*4882a593Smuzhiyun 	}
5431*4882a593Smuzhiyun }
5432*4882a593Smuzhiyun 
prepare_hardware(struct net_device * dev)5433*4882a593Smuzhiyun static int prepare_hardware(struct net_device *dev)
5434*4882a593Smuzhiyun {
5435*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5436*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5437*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5438*4882a593Smuzhiyun 	int rc = 0;
5439*4882a593Smuzhiyun 
5440*4882a593Smuzhiyun 	/* Remember the network device that requests interrupts. */
5441*4882a593Smuzhiyun 	hw_priv->dev = dev;
5442*4882a593Smuzhiyun 	rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev);
5443*4882a593Smuzhiyun 	if (rc)
5444*4882a593Smuzhiyun 		return rc;
5445*4882a593Smuzhiyun 	tasklet_setup(&hw_priv->rx_tasklet, rx_proc_task);
5446*4882a593Smuzhiyun 	tasklet_setup(&hw_priv->tx_tasklet, tx_proc_task);
5447*4882a593Smuzhiyun 
5448*4882a593Smuzhiyun 	hw->promiscuous = 0;
5449*4882a593Smuzhiyun 	hw->all_multi = 0;
5450*4882a593Smuzhiyun 	hw->multi_list_size = 0;
5451*4882a593Smuzhiyun 
5452*4882a593Smuzhiyun 	hw_reset(hw);
5453*4882a593Smuzhiyun 
5454*4882a593Smuzhiyun 	hw_set_desc_base(hw,
5455*4882a593Smuzhiyun 		hw->tx_desc_info.ring_phys, hw->rx_desc_info.ring_phys);
5456*4882a593Smuzhiyun 	hw_set_addr(hw);
5457*4882a593Smuzhiyun 	hw_cfg_huge_frame(hw_priv, hw);
5458*4882a593Smuzhiyun 	ksz_init_rx_buffers(hw_priv);
5459*4882a593Smuzhiyun 	return 0;
5460*4882a593Smuzhiyun }
5461*4882a593Smuzhiyun 
set_media_state(struct net_device * dev,int media_state)5462*4882a593Smuzhiyun static void set_media_state(struct net_device *dev, int media_state)
5463*4882a593Smuzhiyun {
5464*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5465*4882a593Smuzhiyun 
5466*4882a593Smuzhiyun 	if (media_state == priv->media_state)
5467*4882a593Smuzhiyun 		netif_carrier_on(dev);
5468*4882a593Smuzhiyun 	else
5469*4882a593Smuzhiyun 		netif_carrier_off(dev);
5470*4882a593Smuzhiyun 	netif_info(priv, link, dev, "link %s\n",
5471*4882a593Smuzhiyun 		   media_state == priv->media_state ? "on" : "off");
5472*4882a593Smuzhiyun }
5473*4882a593Smuzhiyun 
5474*4882a593Smuzhiyun /**
5475*4882a593Smuzhiyun  * netdev_open - open network device
5476*4882a593Smuzhiyun  * @dev:	Network device.
5477*4882a593Smuzhiyun  *
5478*4882a593Smuzhiyun  * This function process the open operation of network device.  This is caused
5479*4882a593Smuzhiyun  * by the user command "ifconfig ethX up."
5480*4882a593Smuzhiyun  *
5481*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code indicating failure.
5482*4882a593Smuzhiyun  */
netdev_open(struct net_device * dev)5483*4882a593Smuzhiyun static int netdev_open(struct net_device *dev)
5484*4882a593Smuzhiyun {
5485*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5486*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5487*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5488*4882a593Smuzhiyun 	struct ksz_port *port = &priv->port;
5489*4882a593Smuzhiyun 	int i;
5490*4882a593Smuzhiyun 	int p;
5491*4882a593Smuzhiyun 	int rc = 0;
5492*4882a593Smuzhiyun 
5493*4882a593Smuzhiyun 	priv->multicast = 0;
5494*4882a593Smuzhiyun 	priv->promiscuous = 0;
5495*4882a593Smuzhiyun 
5496*4882a593Smuzhiyun 	/* Reset device statistics. */
5497*4882a593Smuzhiyun 	memset(&dev->stats, 0, sizeof(struct net_device_stats));
5498*4882a593Smuzhiyun 	memset((void *) port->counter, 0,
5499*4882a593Smuzhiyun 		(sizeof(u64) * OID_COUNTER_LAST));
5500*4882a593Smuzhiyun 
5501*4882a593Smuzhiyun 	if (!(hw_priv->opened)) {
5502*4882a593Smuzhiyun 		rc = prepare_hardware(dev);
5503*4882a593Smuzhiyun 		if (rc)
5504*4882a593Smuzhiyun 			return rc;
5505*4882a593Smuzhiyun 		for (i = 0; i < hw->mib_port_cnt; i++) {
5506*4882a593Smuzhiyun 			if (next_jiffies < jiffies)
5507*4882a593Smuzhiyun 				next_jiffies = jiffies + HZ * 2;
5508*4882a593Smuzhiyun 			else
5509*4882a593Smuzhiyun 				next_jiffies += HZ * 1;
5510*4882a593Smuzhiyun 			hw_priv->counter[i].time = next_jiffies;
5511*4882a593Smuzhiyun 			hw->port_mib[i].state = media_disconnected;
5512*4882a593Smuzhiyun 			port_init_cnt(hw, i);
5513*4882a593Smuzhiyun 		}
5514*4882a593Smuzhiyun 		if (hw->ksz_switch)
5515*4882a593Smuzhiyun 			hw->port_mib[HOST_PORT].state = media_connected;
5516*4882a593Smuzhiyun 		else {
5517*4882a593Smuzhiyun 			hw_add_wol_bcast(hw);
5518*4882a593Smuzhiyun 			hw_cfg_wol_pme(hw, 0);
5519*4882a593Smuzhiyun 			hw_clr_wol_pme_status(&hw_priv->hw);
5520*4882a593Smuzhiyun 		}
5521*4882a593Smuzhiyun 	}
5522*4882a593Smuzhiyun 	port_set_power_saving(port, false);
5523*4882a593Smuzhiyun 
5524*4882a593Smuzhiyun 	for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) {
5525*4882a593Smuzhiyun 		/*
5526*4882a593Smuzhiyun 		 * Initialize to invalid value so that link detection
5527*4882a593Smuzhiyun 		 * is done.
5528*4882a593Smuzhiyun 		 */
5529*4882a593Smuzhiyun 		hw->port_info[p].partner = 0xFF;
5530*4882a593Smuzhiyun 		hw->port_info[p].state = media_disconnected;
5531*4882a593Smuzhiyun 	}
5532*4882a593Smuzhiyun 
5533*4882a593Smuzhiyun 	/* Need to open the port in multiple device interfaces mode. */
5534*4882a593Smuzhiyun 	if (hw->dev_count > 1) {
5535*4882a593Smuzhiyun 		port_set_stp_state(hw, port->first_port, STP_STATE_SIMPLE);
5536*4882a593Smuzhiyun 		if (port->first_port > 0)
5537*4882a593Smuzhiyun 			hw_add_addr(hw, dev->dev_addr);
5538*4882a593Smuzhiyun 	}
5539*4882a593Smuzhiyun 
5540*4882a593Smuzhiyun 	port_get_link_speed(port);
5541*4882a593Smuzhiyun 	if (port->force_link)
5542*4882a593Smuzhiyun 		port_force_link_speed(port);
5543*4882a593Smuzhiyun 	else
5544*4882a593Smuzhiyun 		port_set_link_speed(port);
5545*4882a593Smuzhiyun 
5546*4882a593Smuzhiyun 	if (!(hw_priv->opened)) {
5547*4882a593Smuzhiyun 		hw_setup_intr(hw);
5548*4882a593Smuzhiyun 		hw_enable(hw);
5549*4882a593Smuzhiyun 		hw_ena_intr(hw);
5550*4882a593Smuzhiyun 
5551*4882a593Smuzhiyun 		if (hw->mib_port_cnt)
5552*4882a593Smuzhiyun 			ksz_start_timer(&hw_priv->mib_timer_info,
5553*4882a593Smuzhiyun 				hw_priv->mib_timer_info.period);
5554*4882a593Smuzhiyun 	}
5555*4882a593Smuzhiyun 
5556*4882a593Smuzhiyun 	hw_priv->opened++;
5557*4882a593Smuzhiyun 
5558*4882a593Smuzhiyun 	ksz_start_timer(&priv->monitor_timer_info,
5559*4882a593Smuzhiyun 		priv->monitor_timer_info.period);
5560*4882a593Smuzhiyun 
5561*4882a593Smuzhiyun 	priv->media_state = port->linked->state;
5562*4882a593Smuzhiyun 
5563*4882a593Smuzhiyun 	set_media_state(dev, media_connected);
5564*4882a593Smuzhiyun 	netif_start_queue(dev);
5565*4882a593Smuzhiyun 
5566*4882a593Smuzhiyun 	return 0;
5567*4882a593Smuzhiyun }
5568*4882a593Smuzhiyun 
5569*4882a593Smuzhiyun /* RX errors = rx_errors */
5570*4882a593Smuzhiyun /* RX dropped = rx_dropped */
5571*4882a593Smuzhiyun /* RX overruns = rx_fifo_errors */
5572*4882a593Smuzhiyun /* RX frame = rx_crc_errors + rx_frame_errors + rx_length_errors */
5573*4882a593Smuzhiyun /* TX errors = tx_errors */
5574*4882a593Smuzhiyun /* TX dropped = tx_dropped */
5575*4882a593Smuzhiyun /* TX overruns = tx_fifo_errors */
5576*4882a593Smuzhiyun /* TX carrier = tx_aborted_errors + tx_carrier_errors + tx_window_errors */
5577*4882a593Smuzhiyun /* collisions = collisions */
5578*4882a593Smuzhiyun 
5579*4882a593Smuzhiyun /**
5580*4882a593Smuzhiyun  * netdev_query_statistics - query network device statistics
5581*4882a593Smuzhiyun  * @dev:	Network device.
5582*4882a593Smuzhiyun  *
5583*4882a593Smuzhiyun  * This function returns the statistics of the network device.  The device
5584*4882a593Smuzhiyun  * needs not be opened.
5585*4882a593Smuzhiyun  *
5586*4882a593Smuzhiyun  * Return network device statistics.
5587*4882a593Smuzhiyun  */
netdev_query_statistics(struct net_device * dev)5588*4882a593Smuzhiyun static struct net_device_stats *netdev_query_statistics(struct net_device *dev)
5589*4882a593Smuzhiyun {
5590*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5591*4882a593Smuzhiyun 	struct ksz_port *port = &priv->port;
5592*4882a593Smuzhiyun 	struct ksz_hw *hw = &priv->adapter->hw;
5593*4882a593Smuzhiyun 	struct ksz_port_mib *mib;
5594*4882a593Smuzhiyun 	int i;
5595*4882a593Smuzhiyun 	int p;
5596*4882a593Smuzhiyun 
5597*4882a593Smuzhiyun 	dev->stats.rx_errors = port->counter[OID_COUNTER_RCV_ERROR];
5598*4882a593Smuzhiyun 	dev->stats.tx_errors = port->counter[OID_COUNTER_XMIT_ERROR];
5599*4882a593Smuzhiyun 
5600*4882a593Smuzhiyun 	/* Reset to zero to add count later. */
5601*4882a593Smuzhiyun 	dev->stats.multicast = 0;
5602*4882a593Smuzhiyun 	dev->stats.collisions = 0;
5603*4882a593Smuzhiyun 	dev->stats.rx_length_errors = 0;
5604*4882a593Smuzhiyun 	dev->stats.rx_crc_errors = 0;
5605*4882a593Smuzhiyun 	dev->stats.rx_frame_errors = 0;
5606*4882a593Smuzhiyun 	dev->stats.tx_window_errors = 0;
5607*4882a593Smuzhiyun 
5608*4882a593Smuzhiyun 	for (i = 0, p = port->first_port; i < port->mib_port_cnt; i++, p++) {
5609*4882a593Smuzhiyun 		mib = &hw->port_mib[p];
5610*4882a593Smuzhiyun 
5611*4882a593Smuzhiyun 		dev->stats.multicast += (unsigned long)
5612*4882a593Smuzhiyun 			mib->counter[MIB_COUNTER_RX_MULTICAST];
5613*4882a593Smuzhiyun 
5614*4882a593Smuzhiyun 		dev->stats.collisions += (unsigned long)
5615*4882a593Smuzhiyun 			mib->counter[MIB_COUNTER_TX_TOTAL_COLLISION];
5616*4882a593Smuzhiyun 
5617*4882a593Smuzhiyun 		dev->stats.rx_length_errors += (unsigned long)(
5618*4882a593Smuzhiyun 			mib->counter[MIB_COUNTER_RX_UNDERSIZE] +
5619*4882a593Smuzhiyun 			mib->counter[MIB_COUNTER_RX_FRAGMENT] +
5620*4882a593Smuzhiyun 			mib->counter[MIB_COUNTER_RX_OVERSIZE] +
5621*4882a593Smuzhiyun 			mib->counter[MIB_COUNTER_RX_JABBER]);
5622*4882a593Smuzhiyun 		dev->stats.rx_crc_errors += (unsigned long)
5623*4882a593Smuzhiyun 			mib->counter[MIB_COUNTER_RX_CRC_ERR];
5624*4882a593Smuzhiyun 		dev->stats.rx_frame_errors += (unsigned long)(
5625*4882a593Smuzhiyun 			mib->counter[MIB_COUNTER_RX_ALIGNMENT_ERR] +
5626*4882a593Smuzhiyun 			mib->counter[MIB_COUNTER_RX_SYMBOL_ERR]);
5627*4882a593Smuzhiyun 
5628*4882a593Smuzhiyun 		dev->stats.tx_window_errors += (unsigned long)
5629*4882a593Smuzhiyun 			mib->counter[MIB_COUNTER_TX_LATE_COLLISION];
5630*4882a593Smuzhiyun 	}
5631*4882a593Smuzhiyun 
5632*4882a593Smuzhiyun 	return &dev->stats;
5633*4882a593Smuzhiyun }
5634*4882a593Smuzhiyun 
5635*4882a593Smuzhiyun /**
5636*4882a593Smuzhiyun  * netdev_set_mac_address - set network device MAC address
5637*4882a593Smuzhiyun  * @dev:	Network device.
5638*4882a593Smuzhiyun  * @addr:	Buffer of MAC address.
5639*4882a593Smuzhiyun  *
5640*4882a593Smuzhiyun  * This function is used to set the MAC address of the network device.
5641*4882a593Smuzhiyun  *
5642*4882a593Smuzhiyun  * Return 0 to indicate success.
5643*4882a593Smuzhiyun  */
netdev_set_mac_address(struct net_device * dev,void * addr)5644*4882a593Smuzhiyun static int netdev_set_mac_address(struct net_device *dev, void *addr)
5645*4882a593Smuzhiyun {
5646*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5647*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5648*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5649*4882a593Smuzhiyun 	struct sockaddr *mac = addr;
5650*4882a593Smuzhiyun 	uint interrupt;
5651*4882a593Smuzhiyun 
5652*4882a593Smuzhiyun 	if (priv->port.first_port > 0)
5653*4882a593Smuzhiyun 		hw_del_addr(hw, dev->dev_addr);
5654*4882a593Smuzhiyun 	else {
5655*4882a593Smuzhiyun 		hw->mac_override = 1;
5656*4882a593Smuzhiyun 		memcpy(hw->override_addr, mac->sa_data, ETH_ALEN);
5657*4882a593Smuzhiyun 	}
5658*4882a593Smuzhiyun 
5659*4882a593Smuzhiyun 	memcpy(dev->dev_addr, mac->sa_data, ETH_ALEN);
5660*4882a593Smuzhiyun 
5661*4882a593Smuzhiyun 	interrupt = hw_block_intr(hw);
5662*4882a593Smuzhiyun 
5663*4882a593Smuzhiyun 	if (priv->port.first_port > 0)
5664*4882a593Smuzhiyun 		hw_add_addr(hw, dev->dev_addr);
5665*4882a593Smuzhiyun 	else
5666*4882a593Smuzhiyun 		hw_set_addr(hw);
5667*4882a593Smuzhiyun 	hw_restore_intr(hw, interrupt);
5668*4882a593Smuzhiyun 
5669*4882a593Smuzhiyun 	return 0;
5670*4882a593Smuzhiyun }
5671*4882a593Smuzhiyun 
dev_set_promiscuous(struct net_device * dev,struct dev_priv * priv,struct ksz_hw * hw,int promiscuous)5672*4882a593Smuzhiyun static void dev_set_promiscuous(struct net_device *dev, struct dev_priv *priv,
5673*4882a593Smuzhiyun 	struct ksz_hw *hw, int promiscuous)
5674*4882a593Smuzhiyun {
5675*4882a593Smuzhiyun 	if (promiscuous != priv->promiscuous) {
5676*4882a593Smuzhiyun 		u8 prev_state = hw->promiscuous;
5677*4882a593Smuzhiyun 
5678*4882a593Smuzhiyun 		if (promiscuous)
5679*4882a593Smuzhiyun 			++hw->promiscuous;
5680*4882a593Smuzhiyun 		else
5681*4882a593Smuzhiyun 			--hw->promiscuous;
5682*4882a593Smuzhiyun 		priv->promiscuous = promiscuous;
5683*4882a593Smuzhiyun 
5684*4882a593Smuzhiyun 		/* Turn on/off promiscuous mode. */
5685*4882a593Smuzhiyun 		if (hw->promiscuous <= 1 && prev_state <= 1)
5686*4882a593Smuzhiyun 			hw_set_promiscuous(hw, hw->promiscuous);
5687*4882a593Smuzhiyun 
5688*4882a593Smuzhiyun 		/*
5689*4882a593Smuzhiyun 		 * Port is not in promiscuous mode, meaning it is released
5690*4882a593Smuzhiyun 		 * from the bridge.
5691*4882a593Smuzhiyun 		 */
5692*4882a593Smuzhiyun 		if ((hw->features & STP_SUPPORT) && !promiscuous &&
5693*4882a593Smuzhiyun 		    netif_is_bridge_port(dev)) {
5694*4882a593Smuzhiyun 			struct ksz_switch *sw = hw->ksz_switch;
5695*4882a593Smuzhiyun 			int port = priv->port.first_port;
5696*4882a593Smuzhiyun 
5697*4882a593Smuzhiyun 			port_set_stp_state(hw, port, STP_STATE_DISABLED);
5698*4882a593Smuzhiyun 			port = 1 << port;
5699*4882a593Smuzhiyun 			if (sw->member & port) {
5700*4882a593Smuzhiyun 				sw->member &= ~port;
5701*4882a593Smuzhiyun 				bridge_change(hw);
5702*4882a593Smuzhiyun 			}
5703*4882a593Smuzhiyun 		}
5704*4882a593Smuzhiyun 	}
5705*4882a593Smuzhiyun }
5706*4882a593Smuzhiyun 
dev_set_multicast(struct dev_priv * priv,struct ksz_hw * hw,int multicast)5707*4882a593Smuzhiyun static void dev_set_multicast(struct dev_priv *priv, struct ksz_hw *hw,
5708*4882a593Smuzhiyun 	int multicast)
5709*4882a593Smuzhiyun {
5710*4882a593Smuzhiyun 	if (multicast != priv->multicast) {
5711*4882a593Smuzhiyun 		u8 all_multi = hw->all_multi;
5712*4882a593Smuzhiyun 
5713*4882a593Smuzhiyun 		if (multicast)
5714*4882a593Smuzhiyun 			++hw->all_multi;
5715*4882a593Smuzhiyun 		else
5716*4882a593Smuzhiyun 			--hw->all_multi;
5717*4882a593Smuzhiyun 		priv->multicast = multicast;
5718*4882a593Smuzhiyun 
5719*4882a593Smuzhiyun 		/* Turn on/off all multicast mode. */
5720*4882a593Smuzhiyun 		if (hw->all_multi <= 1 && all_multi <= 1)
5721*4882a593Smuzhiyun 			hw_set_multicast(hw, hw->all_multi);
5722*4882a593Smuzhiyun 	}
5723*4882a593Smuzhiyun }
5724*4882a593Smuzhiyun 
5725*4882a593Smuzhiyun /**
5726*4882a593Smuzhiyun  * netdev_set_rx_mode
5727*4882a593Smuzhiyun  * @dev:	Network device.
5728*4882a593Smuzhiyun  *
5729*4882a593Smuzhiyun  * This routine is used to set multicast addresses or put the network device
5730*4882a593Smuzhiyun  * into promiscuous mode.
5731*4882a593Smuzhiyun  */
netdev_set_rx_mode(struct net_device * dev)5732*4882a593Smuzhiyun static void netdev_set_rx_mode(struct net_device *dev)
5733*4882a593Smuzhiyun {
5734*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5735*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5736*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5737*4882a593Smuzhiyun 	struct netdev_hw_addr *ha;
5738*4882a593Smuzhiyun 	int multicast = (dev->flags & IFF_ALLMULTI);
5739*4882a593Smuzhiyun 
5740*4882a593Smuzhiyun 	dev_set_promiscuous(dev, priv, hw, (dev->flags & IFF_PROMISC));
5741*4882a593Smuzhiyun 
5742*4882a593Smuzhiyun 	if (hw_priv->hw.dev_count > 1)
5743*4882a593Smuzhiyun 		multicast |= (dev->flags & IFF_MULTICAST);
5744*4882a593Smuzhiyun 	dev_set_multicast(priv, hw, multicast);
5745*4882a593Smuzhiyun 
5746*4882a593Smuzhiyun 	/* Cannot use different hashes in multiple device interfaces mode. */
5747*4882a593Smuzhiyun 	if (hw_priv->hw.dev_count > 1)
5748*4882a593Smuzhiyun 		return;
5749*4882a593Smuzhiyun 
5750*4882a593Smuzhiyun 	if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) {
5751*4882a593Smuzhiyun 		int i = 0;
5752*4882a593Smuzhiyun 
5753*4882a593Smuzhiyun 		/* List too big to support so turn on all multicast mode. */
5754*4882a593Smuzhiyun 		if (netdev_mc_count(dev) > MAX_MULTICAST_LIST) {
5755*4882a593Smuzhiyun 			if (MAX_MULTICAST_LIST != hw->multi_list_size) {
5756*4882a593Smuzhiyun 				hw->multi_list_size = MAX_MULTICAST_LIST;
5757*4882a593Smuzhiyun 				++hw->all_multi;
5758*4882a593Smuzhiyun 				hw_set_multicast(hw, hw->all_multi);
5759*4882a593Smuzhiyun 			}
5760*4882a593Smuzhiyun 			return;
5761*4882a593Smuzhiyun 		}
5762*4882a593Smuzhiyun 
5763*4882a593Smuzhiyun 		netdev_for_each_mc_addr(ha, dev) {
5764*4882a593Smuzhiyun 			if (i >= MAX_MULTICAST_LIST)
5765*4882a593Smuzhiyun 				break;
5766*4882a593Smuzhiyun 			memcpy(hw->multi_list[i++], ha->addr, ETH_ALEN);
5767*4882a593Smuzhiyun 		}
5768*4882a593Smuzhiyun 		hw->multi_list_size = (u8) i;
5769*4882a593Smuzhiyun 		hw_set_grp_addr(hw);
5770*4882a593Smuzhiyun 	} else {
5771*4882a593Smuzhiyun 		if (MAX_MULTICAST_LIST == hw->multi_list_size) {
5772*4882a593Smuzhiyun 			--hw->all_multi;
5773*4882a593Smuzhiyun 			hw_set_multicast(hw, hw->all_multi);
5774*4882a593Smuzhiyun 		}
5775*4882a593Smuzhiyun 		hw->multi_list_size = 0;
5776*4882a593Smuzhiyun 		hw_clr_multicast(hw);
5777*4882a593Smuzhiyun 	}
5778*4882a593Smuzhiyun }
5779*4882a593Smuzhiyun 
netdev_change_mtu(struct net_device * dev,int new_mtu)5780*4882a593Smuzhiyun static int netdev_change_mtu(struct net_device *dev, int new_mtu)
5781*4882a593Smuzhiyun {
5782*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5783*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5784*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5785*4882a593Smuzhiyun 	int hw_mtu;
5786*4882a593Smuzhiyun 
5787*4882a593Smuzhiyun 	if (netif_running(dev))
5788*4882a593Smuzhiyun 		return -EBUSY;
5789*4882a593Smuzhiyun 
5790*4882a593Smuzhiyun 	/* Cannot use different MTU in multiple device interfaces mode. */
5791*4882a593Smuzhiyun 	if (hw->dev_count > 1)
5792*4882a593Smuzhiyun 		if (dev != hw_priv->dev)
5793*4882a593Smuzhiyun 			return 0;
5794*4882a593Smuzhiyun 
5795*4882a593Smuzhiyun 	hw_mtu = new_mtu + ETHERNET_HEADER_SIZE + 4;
5796*4882a593Smuzhiyun 	if (hw_mtu > REGULAR_RX_BUF_SIZE) {
5797*4882a593Smuzhiyun 		hw->features |= RX_HUGE_FRAME;
5798*4882a593Smuzhiyun 		hw_mtu = MAX_RX_BUF_SIZE;
5799*4882a593Smuzhiyun 	} else {
5800*4882a593Smuzhiyun 		hw->features &= ~RX_HUGE_FRAME;
5801*4882a593Smuzhiyun 		hw_mtu = REGULAR_RX_BUF_SIZE;
5802*4882a593Smuzhiyun 	}
5803*4882a593Smuzhiyun 	hw_mtu = (hw_mtu + 3) & ~3;
5804*4882a593Smuzhiyun 	hw_priv->mtu = hw_mtu;
5805*4882a593Smuzhiyun 	dev->mtu = new_mtu;
5806*4882a593Smuzhiyun 
5807*4882a593Smuzhiyun 	return 0;
5808*4882a593Smuzhiyun }
5809*4882a593Smuzhiyun 
5810*4882a593Smuzhiyun /**
5811*4882a593Smuzhiyun  * netdev_ioctl - I/O control processing
5812*4882a593Smuzhiyun  * @dev:	Network device.
5813*4882a593Smuzhiyun  * @ifr:	Interface request structure.
5814*4882a593Smuzhiyun  * @cmd:	I/O control code.
5815*4882a593Smuzhiyun  *
5816*4882a593Smuzhiyun  * This function is used to process I/O control calls.
5817*4882a593Smuzhiyun  *
5818*4882a593Smuzhiyun  * Return 0 to indicate success.
5819*4882a593Smuzhiyun  */
netdev_ioctl(struct net_device * dev,struct ifreq * ifr,int cmd)5820*4882a593Smuzhiyun static int netdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
5821*4882a593Smuzhiyun {
5822*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5823*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5824*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
5825*4882a593Smuzhiyun 	struct ksz_port *port = &priv->port;
5826*4882a593Smuzhiyun 	int result = 0;
5827*4882a593Smuzhiyun 	struct mii_ioctl_data *data = if_mii(ifr);
5828*4882a593Smuzhiyun 
5829*4882a593Smuzhiyun 	if (down_interruptible(&priv->proc_sem))
5830*4882a593Smuzhiyun 		return -ERESTARTSYS;
5831*4882a593Smuzhiyun 
5832*4882a593Smuzhiyun 	switch (cmd) {
5833*4882a593Smuzhiyun 	/* Get address of MII PHY in use. */
5834*4882a593Smuzhiyun 	case SIOCGMIIPHY:
5835*4882a593Smuzhiyun 		data->phy_id = priv->id;
5836*4882a593Smuzhiyun 		fallthrough;
5837*4882a593Smuzhiyun 
5838*4882a593Smuzhiyun 	/* Read MII PHY register. */
5839*4882a593Smuzhiyun 	case SIOCGMIIREG:
5840*4882a593Smuzhiyun 		if (data->phy_id != priv->id || data->reg_num >= 6)
5841*4882a593Smuzhiyun 			result = -EIO;
5842*4882a593Smuzhiyun 		else
5843*4882a593Smuzhiyun 			hw_r_phy(hw, port->linked->port_id, data->reg_num,
5844*4882a593Smuzhiyun 				&data->val_out);
5845*4882a593Smuzhiyun 		break;
5846*4882a593Smuzhiyun 
5847*4882a593Smuzhiyun 	/* Write MII PHY register. */
5848*4882a593Smuzhiyun 	case SIOCSMIIREG:
5849*4882a593Smuzhiyun 		if (!capable(CAP_NET_ADMIN))
5850*4882a593Smuzhiyun 			result = -EPERM;
5851*4882a593Smuzhiyun 		else if (data->phy_id != priv->id || data->reg_num >= 6)
5852*4882a593Smuzhiyun 			result = -EIO;
5853*4882a593Smuzhiyun 		else
5854*4882a593Smuzhiyun 			hw_w_phy(hw, port->linked->port_id, data->reg_num,
5855*4882a593Smuzhiyun 				data->val_in);
5856*4882a593Smuzhiyun 		break;
5857*4882a593Smuzhiyun 
5858*4882a593Smuzhiyun 	default:
5859*4882a593Smuzhiyun 		result = -EOPNOTSUPP;
5860*4882a593Smuzhiyun 	}
5861*4882a593Smuzhiyun 
5862*4882a593Smuzhiyun 	up(&priv->proc_sem);
5863*4882a593Smuzhiyun 
5864*4882a593Smuzhiyun 	return result;
5865*4882a593Smuzhiyun }
5866*4882a593Smuzhiyun 
5867*4882a593Smuzhiyun /*
5868*4882a593Smuzhiyun  * MII support
5869*4882a593Smuzhiyun  */
5870*4882a593Smuzhiyun 
5871*4882a593Smuzhiyun /**
5872*4882a593Smuzhiyun  * mdio_read - read PHY register
5873*4882a593Smuzhiyun  * @dev:	Network device.
5874*4882a593Smuzhiyun  * @phy_id:	The PHY id.
5875*4882a593Smuzhiyun  * @reg_num:	The register number.
5876*4882a593Smuzhiyun  *
5877*4882a593Smuzhiyun  * This function returns the PHY register value.
5878*4882a593Smuzhiyun  *
5879*4882a593Smuzhiyun  * Return the register value.
5880*4882a593Smuzhiyun  */
mdio_read(struct net_device * dev,int phy_id,int reg_num)5881*4882a593Smuzhiyun static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
5882*4882a593Smuzhiyun {
5883*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5884*4882a593Smuzhiyun 	struct ksz_port *port = &priv->port;
5885*4882a593Smuzhiyun 	struct ksz_hw *hw = port->hw;
5886*4882a593Smuzhiyun 	u16 val_out;
5887*4882a593Smuzhiyun 
5888*4882a593Smuzhiyun 	hw_r_phy(hw, port->linked->port_id, reg_num << 1, &val_out);
5889*4882a593Smuzhiyun 	return val_out;
5890*4882a593Smuzhiyun }
5891*4882a593Smuzhiyun 
5892*4882a593Smuzhiyun /**
5893*4882a593Smuzhiyun  * mdio_write - set PHY register
5894*4882a593Smuzhiyun  * @dev:	Network device.
5895*4882a593Smuzhiyun  * @phy_id:	The PHY id.
5896*4882a593Smuzhiyun  * @reg_num:	The register number.
5897*4882a593Smuzhiyun  * @val:	The register value.
5898*4882a593Smuzhiyun  *
5899*4882a593Smuzhiyun  * This procedure sets the PHY register value.
5900*4882a593Smuzhiyun  */
mdio_write(struct net_device * dev,int phy_id,int reg_num,int val)5901*4882a593Smuzhiyun static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
5902*4882a593Smuzhiyun {
5903*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5904*4882a593Smuzhiyun 	struct ksz_port *port = &priv->port;
5905*4882a593Smuzhiyun 	struct ksz_hw *hw = port->hw;
5906*4882a593Smuzhiyun 	int i;
5907*4882a593Smuzhiyun 	int pi;
5908*4882a593Smuzhiyun 
5909*4882a593Smuzhiyun 	for (i = 0, pi = port->first_port; i < port->port_cnt; i++, pi++)
5910*4882a593Smuzhiyun 		hw_w_phy(hw, pi, reg_num << 1, val);
5911*4882a593Smuzhiyun }
5912*4882a593Smuzhiyun 
5913*4882a593Smuzhiyun /*
5914*4882a593Smuzhiyun  * ethtool support
5915*4882a593Smuzhiyun  */
5916*4882a593Smuzhiyun 
5917*4882a593Smuzhiyun #define EEPROM_SIZE			0x40
5918*4882a593Smuzhiyun 
5919*4882a593Smuzhiyun static u16 eeprom_data[EEPROM_SIZE] = { 0 };
5920*4882a593Smuzhiyun 
5921*4882a593Smuzhiyun #define ADVERTISED_ALL			\
5922*4882a593Smuzhiyun 	(ADVERTISED_10baseT_Half |	\
5923*4882a593Smuzhiyun 	ADVERTISED_10baseT_Full |	\
5924*4882a593Smuzhiyun 	ADVERTISED_100baseT_Half |	\
5925*4882a593Smuzhiyun 	ADVERTISED_100baseT_Full)
5926*4882a593Smuzhiyun 
5927*4882a593Smuzhiyun /* These functions use the MII functions in mii.c. */
5928*4882a593Smuzhiyun 
5929*4882a593Smuzhiyun /**
5930*4882a593Smuzhiyun  * netdev_get_link_ksettings - get network device settings
5931*4882a593Smuzhiyun  * @dev:	Network device.
5932*4882a593Smuzhiyun  * @cmd:	Ethtool command.
5933*4882a593Smuzhiyun  *
5934*4882a593Smuzhiyun  * This function queries the PHY and returns its state in the ethtool command.
5935*4882a593Smuzhiyun  *
5936*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code.
5937*4882a593Smuzhiyun  */
netdev_get_link_ksettings(struct net_device * dev,struct ethtool_link_ksettings * cmd)5938*4882a593Smuzhiyun static int netdev_get_link_ksettings(struct net_device *dev,
5939*4882a593Smuzhiyun 				     struct ethtool_link_ksettings *cmd)
5940*4882a593Smuzhiyun {
5941*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5942*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5943*4882a593Smuzhiyun 
5944*4882a593Smuzhiyun 	mutex_lock(&hw_priv->lock);
5945*4882a593Smuzhiyun 	mii_ethtool_get_link_ksettings(&priv->mii_if, cmd);
5946*4882a593Smuzhiyun 	ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
5947*4882a593Smuzhiyun 	mutex_unlock(&hw_priv->lock);
5948*4882a593Smuzhiyun 
5949*4882a593Smuzhiyun 	/* Save advertised settings for workaround in next function. */
5950*4882a593Smuzhiyun 	ethtool_convert_link_mode_to_legacy_u32(&priv->advertising,
5951*4882a593Smuzhiyun 						cmd->link_modes.advertising);
5952*4882a593Smuzhiyun 
5953*4882a593Smuzhiyun 	return 0;
5954*4882a593Smuzhiyun }
5955*4882a593Smuzhiyun 
5956*4882a593Smuzhiyun /**
5957*4882a593Smuzhiyun  * netdev_set_link_ksettings - set network device settings
5958*4882a593Smuzhiyun  * @dev:	Network device.
5959*4882a593Smuzhiyun  * @cmd:	Ethtool command.
5960*4882a593Smuzhiyun  *
5961*4882a593Smuzhiyun  * This function sets the PHY according to the ethtool command.
5962*4882a593Smuzhiyun  *
5963*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code.
5964*4882a593Smuzhiyun  */
netdev_set_link_ksettings(struct net_device * dev,const struct ethtool_link_ksettings * cmd)5965*4882a593Smuzhiyun static int netdev_set_link_ksettings(struct net_device *dev,
5966*4882a593Smuzhiyun 				     const struct ethtool_link_ksettings *cmd)
5967*4882a593Smuzhiyun {
5968*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
5969*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
5970*4882a593Smuzhiyun 	struct ksz_port *port = &priv->port;
5971*4882a593Smuzhiyun 	struct ethtool_link_ksettings copy_cmd;
5972*4882a593Smuzhiyun 	u32 speed = cmd->base.speed;
5973*4882a593Smuzhiyun 	u32 advertising;
5974*4882a593Smuzhiyun 	int rc;
5975*4882a593Smuzhiyun 
5976*4882a593Smuzhiyun 	ethtool_convert_link_mode_to_legacy_u32(&advertising,
5977*4882a593Smuzhiyun 						cmd->link_modes.advertising);
5978*4882a593Smuzhiyun 
5979*4882a593Smuzhiyun 	/*
5980*4882a593Smuzhiyun 	 * ethtool utility does not change advertised setting if auto
5981*4882a593Smuzhiyun 	 * negotiation is not specified explicitly.
5982*4882a593Smuzhiyun 	 */
5983*4882a593Smuzhiyun 	if (cmd->base.autoneg && priv->advertising == advertising) {
5984*4882a593Smuzhiyun 		advertising |= ADVERTISED_ALL;
5985*4882a593Smuzhiyun 		if (10 == speed)
5986*4882a593Smuzhiyun 			advertising &=
5987*4882a593Smuzhiyun 				~(ADVERTISED_100baseT_Full |
5988*4882a593Smuzhiyun 				ADVERTISED_100baseT_Half);
5989*4882a593Smuzhiyun 		else if (100 == speed)
5990*4882a593Smuzhiyun 			advertising &=
5991*4882a593Smuzhiyun 				~(ADVERTISED_10baseT_Full |
5992*4882a593Smuzhiyun 				ADVERTISED_10baseT_Half);
5993*4882a593Smuzhiyun 		if (0 == cmd->base.duplex)
5994*4882a593Smuzhiyun 			advertising &=
5995*4882a593Smuzhiyun 				~(ADVERTISED_100baseT_Full |
5996*4882a593Smuzhiyun 				ADVERTISED_10baseT_Full);
5997*4882a593Smuzhiyun 		else if (1 == cmd->base.duplex)
5998*4882a593Smuzhiyun 			advertising &=
5999*4882a593Smuzhiyun 				~(ADVERTISED_100baseT_Half |
6000*4882a593Smuzhiyun 				ADVERTISED_10baseT_Half);
6001*4882a593Smuzhiyun 	}
6002*4882a593Smuzhiyun 	mutex_lock(&hw_priv->lock);
6003*4882a593Smuzhiyun 	if (cmd->base.autoneg &&
6004*4882a593Smuzhiyun 	    (advertising & ADVERTISED_ALL) == ADVERTISED_ALL) {
6005*4882a593Smuzhiyun 		port->duplex = 0;
6006*4882a593Smuzhiyun 		port->speed = 0;
6007*4882a593Smuzhiyun 		port->force_link = 0;
6008*4882a593Smuzhiyun 	} else {
6009*4882a593Smuzhiyun 		port->duplex = cmd->base.duplex + 1;
6010*4882a593Smuzhiyun 		if (1000 != speed)
6011*4882a593Smuzhiyun 			port->speed = speed;
6012*4882a593Smuzhiyun 		if (cmd->base.autoneg)
6013*4882a593Smuzhiyun 			port->force_link = 0;
6014*4882a593Smuzhiyun 		else
6015*4882a593Smuzhiyun 			port->force_link = 1;
6016*4882a593Smuzhiyun 	}
6017*4882a593Smuzhiyun 
6018*4882a593Smuzhiyun 	memcpy(&copy_cmd, cmd, sizeof(copy_cmd));
6019*4882a593Smuzhiyun 	ethtool_convert_legacy_u32_to_link_mode(copy_cmd.link_modes.advertising,
6020*4882a593Smuzhiyun 						advertising);
6021*4882a593Smuzhiyun 	rc = mii_ethtool_set_link_ksettings(
6022*4882a593Smuzhiyun 		&priv->mii_if,
6023*4882a593Smuzhiyun 		(const struct ethtool_link_ksettings *)&copy_cmd);
6024*4882a593Smuzhiyun 	mutex_unlock(&hw_priv->lock);
6025*4882a593Smuzhiyun 	return rc;
6026*4882a593Smuzhiyun }
6027*4882a593Smuzhiyun 
6028*4882a593Smuzhiyun /**
6029*4882a593Smuzhiyun  * netdev_nway_reset - restart auto-negotiation
6030*4882a593Smuzhiyun  * @dev:	Network device.
6031*4882a593Smuzhiyun  *
6032*4882a593Smuzhiyun  * This function restarts the PHY for auto-negotiation.
6033*4882a593Smuzhiyun  *
6034*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code.
6035*4882a593Smuzhiyun  */
netdev_nway_reset(struct net_device * dev)6036*4882a593Smuzhiyun static int netdev_nway_reset(struct net_device *dev)
6037*4882a593Smuzhiyun {
6038*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6039*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6040*4882a593Smuzhiyun 	int rc;
6041*4882a593Smuzhiyun 
6042*4882a593Smuzhiyun 	mutex_lock(&hw_priv->lock);
6043*4882a593Smuzhiyun 	rc = mii_nway_restart(&priv->mii_if);
6044*4882a593Smuzhiyun 	mutex_unlock(&hw_priv->lock);
6045*4882a593Smuzhiyun 	return rc;
6046*4882a593Smuzhiyun }
6047*4882a593Smuzhiyun 
6048*4882a593Smuzhiyun /**
6049*4882a593Smuzhiyun  * netdev_get_link - get network device link status
6050*4882a593Smuzhiyun  * @dev:	Network device.
6051*4882a593Smuzhiyun  *
6052*4882a593Smuzhiyun  * This function gets the link status from the PHY.
6053*4882a593Smuzhiyun  *
6054*4882a593Smuzhiyun  * Return true if PHY is linked and false otherwise.
6055*4882a593Smuzhiyun  */
netdev_get_link(struct net_device * dev)6056*4882a593Smuzhiyun static u32 netdev_get_link(struct net_device *dev)
6057*4882a593Smuzhiyun {
6058*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6059*4882a593Smuzhiyun 	int rc;
6060*4882a593Smuzhiyun 
6061*4882a593Smuzhiyun 	rc = mii_link_ok(&priv->mii_if);
6062*4882a593Smuzhiyun 	return rc;
6063*4882a593Smuzhiyun }
6064*4882a593Smuzhiyun 
6065*4882a593Smuzhiyun /**
6066*4882a593Smuzhiyun  * netdev_get_drvinfo - get network driver information
6067*4882a593Smuzhiyun  * @dev:	Network device.
6068*4882a593Smuzhiyun  * @info:	Ethtool driver info data structure.
6069*4882a593Smuzhiyun  *
6070*4882a593Smuzhiyun  * This procedure returns the driver information.
6071*4882a593Smuzhiyun  */
netdev_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)6072*4882a593Smuzhiyun static void netdev_get_drvinfo(struct net_device *dev,
6073*4882a593Smuzhiyun 	struct ethtool_drvinfo *info)
6074*4882a593Smuzhiyun {
6075*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6076*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6077*4882a593Smuzhiyun 
6078*4882a593Smuzhiyun 	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
6079*4882a593Smuzhiyun 	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
6080*4882a593Smuzhiyun 	strlcpy(info->bus_info, pci_name(hw_priv->pdev),
6081*4882a593Smuzhiyun 		sizeof(info->bus_info));
6082*4882a593Smuzhiyun }
6083*4882a593Smuzhiyun 
6084*4882a593Smuzhiyun static struct hw_regs {
6085*4882a593Smuzhiyun 	int start;
6086*4882a593Smuzhiyun 	int end;
6087*4882a593Smuzhiyun } hw_regs_range[] = {
6088*4882a593Smuzhiyun 	{ KS_DMA_TX_CTRL,	KS884X_INTERRUPTS_STATUS },
6089*4882a593Smuzhiyun 	{ KS_ADD_ADDR_0_LO,	KS_ADD_ADDR_F_HI },
6090*4882a593Smuzhiyun 	{ KS884X_ADDR_0_OFFSET,	KS8841_WOL_FRAME_BYTE2_OFFSET },
6091*4882a593Smuzhiyun 	{ KS884X_SIDER_P,	KS8842_SGCR7_P },
6092*4882a593Smuzhiyun 	{ KS8842_MACAR1_P,	KS8842_TOSR8_P },
6093*4882a593Smuzhiyun 	{ KS884X_P1MBCR_P,	KS8842_P3ERCR_P },
6094*4882a593Smuzhiyun 	{ 0, 0 }
6095*4882a593Smuzhiyun };
6096*4882a593Smuzhiyun 
6097*4882a593Smuzhiyun /**
6098*4882a593Smuzhiyun  * netdev_get_regs_len - get length of register dump
6099*4882a593Smuzhiyun  * @dev:	Network device.
6100*4882a593Smuzhiyun  *
6101*4882a593Smuzhiyun  * This function returns the length of the register dump.
6102*4882a593Smuzhiyun  *
6103*4882a593Smuzhiyun  * Return length of the register dump.
6104*4882a593Smuzhiyun  */
netdev_get_regs_len(struct net_device * dev)6105*4882a593Smuzhiyun static int netdev_get_regs_len(struct net_device *dev)
6106*4882a593Smuzhiyun {
6107*4882a593Smuzhiyun 	struct hw_regs *range = hw_regs_range;
6108*4882a593Smuzhiyun 	int regs_len = 0x10 * sizeof(u32);
6109*4882a593Smuzhiyun 
6110*4882a593Smuzhiyun 	while (range->end > range->start) {
6111*4882a593Smuzhiyun 		regs_len += (range->end - range->start + 3) / 4 * 4;
6112*4882a593Smuzhiyun 		range++;
6113*4882a593Smuzhiyun 	}
6114*4882a593Smuzhiyun 	return regs_len;
6115*4882a593Smuzhiyun }
6116*4882a593Smuzhiyun 
6117*4882a593Smuzhiyun /**
6118*4882a593Smuzhiyun  * netdev_get_regs - get register dump
6119*4882a593Smuzhiyun  * @dev:	Network device.
6120*4882a593Smuzhiyun  * @regs:	Ethtool registers data structure.
6121*4882a593Smuzhiyun  * @ptr:	Buffer to store the register values.
6122*4882a593Smuzhiyun  *
6123*4882a593Smuzhiyun  * This procedure dumps the register values in the provided buffer.
6124*4882a593Smuzhiyun  */
netdev_get_regs(struct net_device * dev,struct ethtool_regs * regs,void * ptr)6125*4882a593Smuzhiyun static void netdev_get_regs(struct net_device *dev, struct ethtool_regs *regs,
6126*4882a593Smuzhiyun 	void *ptr)
6127*4882a593Smuzhiyun {
6128*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6129*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6130*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
6131*4882a593Smuzhiyun 	int *buf = (int *) ptr;
6132*4882a593Smuzhiyun 	struct hw_regs *range = hw_regs_range;
6133*4882a593Smuzhiyun 	int len;
6134*4882a593Smuzhiyun 
6135*4882a593Smuzhiyun 	mutex_lock(&hw_priv->lock);
6136*4882a593Smuzhiyun 	regs->version = 0;
6137*4882a593Smuzhiyun 	for (len = 0; len < 0x40; len += 4) {
6138*4882a593Smuzhiyun 		pci_read_config_dword(hw_priv->pdev, len, buf);
6139*4882a593Smuzhiyun 		buf++;
6140*4882a593Smuzhiyun 	}
6141*4882a593Smuzhiyun 	while (range->end > range->start) {
6142*4882a593Smuzhiyun 		for (len = range->start; len < range->end; len += 4) {
6143*4882a593Smuzhiyun 			*buf = readl(hw->io + len);
6144*4882a593Smuzhiyun 			buf++;
6145*4882a593Smuzhiyun 		}
6146*4882a593Smuzhiyun 		range++;
6147*4882a593Smuzhiyun 	}
6148*4882a593Smuzhiyun 	mutex_unlock(&hw_priv->lock);
6149*4882a593Smuzhiyun }
6150*4882a593Smuzhiyun 
6151*4882a593Smuzhiyun #define WOL_SUPPORT			\
6152*4882a593Smuzhiyun 	(WAKE_PHY | WAKE_MAGIC |	\
6153*4882a593Smuzhiyun 	WAKE_UCAST | WAKE_MCAST |	\
6154*4882a593Smuzhiyun 	WAKE_BCAST | WAKE_ARP)
6155*4882a593Smuzhiyun 
6156*4882a593Smuzhiyun /**
6157*4882a593Smuzhiyun  * netdev_get_wol - get Wake-on-LAN support
6158*4882a593Smuzhiyun  * @dev:	Network device.
6159*4882a593Smuzhiyun  * @wol:	Ethtool Wake-on-LAN data structure.
6160*4882a593Smuzhiyun  *
6161*4882a593Smuzhiyun  * This procedure returns Wake-on-LAN support.
6162*4882a593Smuzhiyun  */
netdev_get_wol(struct net_device * dev,struct ethtool_wolinfo * wol)6163*4882a593Smuzhiyun static void netdev_get_wol(struct net_device *dev,
6164*4882a593Smuzhiyun 	struct ethtool_wolinfo *wol)
6165*4882a593Smuzhiyun {
6166*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6167*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6168*4882a593Smuzhiyun 
6169*4882a593Smuzhiyun 	wol->supported = hw_priv->wol_support;
6170*4882a593Smuzhiyun 	wol->wolopts = hw_priv->wol_enable;
6171*4882a593Smuzhiyun 	memset(&wol->sopass, 0, sizeof(wol->sopass));
6172*4882a593Smuzhiyun }
6173*4882a593Smuzhiyun 
6174*4882a593Smuzhiyun /**
6175*4882a593Smuzhiyun  * netdev_set_wol - set Wake-on-LAN support
6176*4882a593Smuzhiyun  * @dev:	Network device.
6177*4882a593Smuzhiyun  * @wol:	Ethtool Wake-on-LAN data structure.
6178*4882a593Smuzhiyun  *
6179*4882a593Smuzhiyun  * This function sets Wake-on-LAN support.
6180*4882a593Smuzhiyun  *
6181*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code.
6182*4882a593Smuzhiyun  */
netdev_set_wol(struct net_device * dev,struct ethtool_wolinfo * wol)6183*4882a593Smuzhiyun static int netdev_set_wol(struct net_device *dev,
6184*4882a593Smuzhiyun 	struct ethtool_wolinfo *wol)
6185*4882a593Smuzhiyun {
6186*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6187*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6188*4882a593Smuzhiyun 
6189*4882a593Smuzhiyun 	/* Need to find a way to retrieve the device IP address. */
6190*4882a593Smuzhiyun 	static const u8 net_addr[] = { 192, 168, 1, 1 };
6191*4882a593Smuzhiyun 
6192*4882a593Smuzhiyun 	if (wol->wolopts & ~hw_priv->wol_support)
6193*4882a593Smuzhiyun 		return -EINVAL;
6194*4882a593Smuzhiyun 
6195*4882a593Smuzhiyun 	hw_priv->wol_enable = wol->wolopts;
6196*4882a593Smuzhiyun 
6197*4882a593Smuzhiyun 	/* Link wakeup cannot really be disabled. */
6198*4882a593Smuzhiyun 	if (wol->wolopts)
6199*4882a593Smuzhiyun 		hw_priv->wol_enable |= WAKE_PHY;
6200*4882a593Smuzhiyun 	hw_enable_wol(&hw_priv->hw, hw_priv->wol_enable, net_addr);
6201*4882a593Smuzhiyun 	return 0;
6202*4882a593Smuzhiyun }
6203*4882a593Smuzhiyun 
6204*4882a593Smuzhiyun /**
6205*4882a593Smuzhiyun  * netdev_get_msglevel - get debug message level
6206*4882a593Smuzhiyun  * @dev:	Network device.
6207*4882a593Smuzhiyun  *
6208*4882a593Smuzhiyun  * This function returns current debug message level.
6209*4882a593Smuzhiyun  *
6210*4882a593Smuzhiyun  * Return current debug message flags.
6211*4882a593Smuzhiyun  */
netdev_get_msglevel(struct net_device * dev)6212*4882a593Smuzhiyun static u32 netdev_get_msglevel(struct net_device *dev)
6213*4882a593Smuzhiyun {
6214*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6215*4882a593Smuzhiyun 
6216*4882a593Smuzhiyun 	return priv->msg_enable;
6217*4882a593Smuzhiyun }
6218*4882a593Smuzhiyun 
6219*4882a593Smuzhiyun /**
6220*4882a593Smuzhiyun  * netdev_set_msglevel - set debug message level
6221*4882a593Smuzhiyun  * @dev:	Network device.
6222*4882a593Smuzhiyun  * @value:	Debug message flags.
6223*4882a593Smuzhiyun  *
6224*4882a593Smuzhiyun  * This procedure sets debug message level.
6225*4882a593Smuzhiyun  */
netdev_set_msglevel(struct net_device * dev,u32 value)6226*4882a593Smuzhiyun static void netdev_set_msglevel(struct net_device *dev, u32 value)
6227*4882a593Smuzhiyun {
6228*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6229*4882a593Smuzhiyun 
6230*4882a593Smuzhiyun 	priv->msg_enable = value;
6231*4882a593Smuzhiyun }
6232*4882a593Smuzhiyun 
6233*4882a593Smuzhiyun /**
6234*4882a593Smuzhiyun  * netdev_get_eeprom_len - get EEPROM length
6235*4882a593Smuzhiyun  * @dev:	Network device.
6236*4882a593Smuzhiyun  *
6237*4882a593Smuzhiyun  * This function returns the length of the EEPROM.
6238*4882a593Smuzhiyun  *
6239*4882a593Smuzhiyun  * Return length of the EEPROM.
6240*4882a593Smuzhiyun  */
netdev_get_eeprom_len(struct net_device * dev)6241*4882a593Smuzhiyun static int netdev_get_eeprom_len(struct net_device *dev)
6242*4882a593Smuzhiyun {
6243*4882a593Smuzhiyun 	return EEPROM_SIZE * 2;
6244*4882a593Smuzhiyun }
6245*4882a593Smuzhiyun 
6246*4882a593Smuzhiyun #define EEPROM_MAGIC			0x10A18842
6247*4882a593Smuzhiyun 
6248*4882a593Smuzhiyun /**
6249*4882a593Smuzhiyun  * netdev_get_eeprom - get EEPROM data
6250*4882a593Smuzhiyun  * @dev:	Network device.
6251*4882a593Smuzhiyun  * @eeprom:	Ethtool EEPROM data structure.
6252*4882a593Smuzhiyun  * @data:	Buffer to store the EEPROM data.
6253*4882a593Smuzhiyun  *
6254*4882a593Smuzhiyun  * This function dumps the EEPROM data in the provided buffer.
6255*4882a593Smuzhiyun  *
6256*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code.
6257*4882a593Smuzhiyun  */
netdev_get_eeprom(struct net_device * dev,struct ethtool_eeprom * eeprom,u8 * data)6258*4882a593Smuzhiyun static int netdev_get_eeprom(struct net_device *dev,
6259*4882a593Smuzhiyun 	struct ethtool_eeprom *eeprom, u8 *data)
6260*4882a593Smuzhiyun {
6261*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6262*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6263*4882a593Smuzhiyun 	u8 *eeprom_byte = (u8 *) eeprom_data;
6264*4882a593Smuzhiyun 	int i;
6265*4882a593Smuzhiyun 	int len;
6266*4882a593Smuzhiyun 
6267*4882a593Smuzhiyun 	len = (eeprom->offset + eeprom->len + 1) / 2;
6268*4882a593Smuzhiyun 	for (i = eeprom->offset / 2; i < len; i++)
6269*4882a593Smuzhiyun 		eeprom_data[i] = eeprom_read(&hw_priv->hw, i);
6270*4882a593Smuzhiyun 	eeprom->magic = EEPROM_MAGIC;
6271*4882a593Smuzhiyun 	memcpy(data, &eeprom_byte[eeprom->offset], eeprom->len);
6272*4882a593Smuzhiyun 
6273*4882a593Smuzhiyun 	return 0;
6274*4882a593Smuzhiyun }
6275*4882a593Smuzhiyun 
6276*4882a593Smuzhiyun /**
6277*4882a593Smuzhiyun  * netdev_set_eeprom - write EEPROM data
6278*4882a593Smuzhiyun  * @dev:	Network device.
6279*4882a593Smuzhiyun  * @eeprom:	Ethtool EEPROM data structure.
6280*4882a593Smuzhiyun  * @data:	Data buffer.
6281*4882a593Smuzhiyun  *
6282*4882a593Smuzhiyun  * This function modifies the EEPROM data one byte at a time.
6283*4882a593Smuzhiyun  *
6284*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code.
6285*4882a593Smuzhiyun  */
netdev_set_eeprom(struct net_device * dev,struct ethtool_eeprom * eeprom,u8 * data)6286*4882a593Smuzhiyun static int netdev_set_eeprom(struct net_device *dev,
6287*4882a593Smuzhiyun 	struct ethtool_eeprom *eeprom, u8 *data)
6288*4882a593Smuzhiyun {
6289*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6290*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6291*4882a593Smuzhiyun 	u16 eeprom_word[EEPROM_SIZE];
6292*4882a593Smuzhiyun 	u8 *eeprom_byte = (u8 *) eeprom_word;
6293*4882a593Smuzhiyun 	int i;
6294*4882a593Smuzhiyun 	int len;
6295*4882a593Smuzhiyun 
6296*4882a593Smuzhiyun 	if (eeprom->magic != EEPROM_MAGIC)
6297*4882a593Smuzhiyun 		return -EINVAL;
6298*4882a593Smuzhiyun 
6299*4882a593Smuzhiyun 	len = (eeprom->offset + eeprom->len + 1) / 2;
6300*4882a593Smuzhiyun 	for (i = eeprom->offset / 2; i < len; i++)
6301*4882a593Smuzhiyun 		eeprom_data[i] = eeprom_read(&hw_priv->hw, i);
6302*4882a593Smuzhiyun 	memcpy(eeprom_word, eeprom_data, EEPROM_SIZE * 2);
6303*4882a593Smuzhiyun 	memcpy(&eeprom_byte[eeprom->offset], data, eeprom->len);
6304*4882a593Smuzhiyun 	for (i = 0; i < EEPROM_SIZE; i++)
6305*4882a593Smuzhiyun 		if (eeprom_word[i] != eeprom_data[i]) {
6306*4882a593Smuzhiyun 			eeprom_data[i] = eeprom_word[i];
6307*4882a593Smuzhiyun 			eeprom_write(&hw_priv->hw, i, eeprom_data[i]);
6308*4882a593Smuzhiyun 	}
6309*4882a593Smuzhiyun 
6310*4882a593Smuzhiyun 	return 0;
6311*4882a593Smuzhiyun }
6312*4882a593Smuzhiyun 
6313*4882a593Smuzhiyun /**
6314*4882a593Smuzhiyun  * netdev_get_pauseparam - get flow control parameters
6315*4882a593Smuzhiyun  * @dev:	Network device.
6316*4882a593Smuzhiyun  * @pause:	Ethtool PAUSE settings data structure.
6317*4882a593Smuzhiyun  *
6318*4882a593Smuzhiyun  * This procedure returns the PAUSE control flow settings.
6319*4882a593Smuzhiyun  */
netdev_get_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)6320*4882a593Smuzhiyun static void netdev_get_pauseparam(struct net_device *dev,
6321*4882a593Smuzhiyun 	struct ethtool_pauseparam *pause)
6322*4882a593Smuzhiyun {
6323*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6324*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6325*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
6326*4882a593Smuzhiyun 
6327*4882a593Smuzhiyun 	pause->autoneg = (hw->overrides & PAUSE_FLOW_CTRL) ? 0 : 1;
6328*4882a593Smuzhiyun 	if (!hw->ksz_switch) {
6329*4882a593Smuzhiyun 		pause->rx_pause =
6330*4882a593Smuzhiyun 			(hw->rx_cfg & DMA_RX_FLOW_ENABLE) ? 1 : 0;
6331*4882a593Smuzhiyun 		pause->tx_pause =
6332*4882a593Smuzhiyun 			(hw->tx_cfg & DMA_TX_FLOW_ENABLE) ? 1 : 0;
6333*4882a593Smuzhiyun 	} else {
6334*4882a593Smuzhiyun 		pause->rx_pause =
6335*4882a593Smuzhiyun 			(sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET,
6336*4882a593Smuzhiyun 				SWITCH_RX_FLOW_CTRL)) ? 1 : 0;
6337*4882a593Smuzhiyun 		pause->tx_pause =
6338*4882a593Smuzhiyun 			(sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET,
6339*4882a593Smuzhiyun 				SWITCH_TX_FLOW_CTRL)) ? 1 : 0;
6340*4882a593Smuzhiyun 	}
6341*4882a593Smuzhiyun }
6342*4882a593Smuzhiyun 
6343*4882a593Smuzhiyun /**
6344*4882a593Smuzhiyun  * netdev_set_pauseparam - set flow control parameters
6345*4882a593Smuzhiyun  * @dev:	Network device.
6346*4882a593Smuzhiyun  * @pause:	Ethtool PAUSE settings data structure.
6347*4882a593Smuzhiyun  *
6348*4882a593Smuzhiyun  * This function sets the PAUSE control flow settings.
6349*4882a593Smuzhiyun  * Not implemented yet.
6350*4882a593Smuzhiyun  *
6351*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code.
6352*4882a593Smuzhiyun  */
netdev_set_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)6353*4882a593Smuzhiyun static int netdev_set_pauseparam(struct net_device *dev,
6354*4882a593Smuzhiyun 	struct ethtool_pauseparam *pause)
6355*4882a593Smuzhiyun {
6356*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6357*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6358*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
6359*4882a593Smuzhiyun 	struct ksz_port *port = &priv->port;
6360*4882a593Smuzhiyun 
6361*4882a593Smuzhiyun 	mutex_lock(&hw_priv->lock);
6362*4882a593Smuzhiyun 	if (pause->autoneg) {
6363*4882a593Smuzhiyun 		if (!pause->rx_pause && !pause->tx_pause)
6364*4882a593Smuzhiyun 			port->flow_ctrl = PHY_NO_FLOW_CTRL;
6365*4882a593Smuzhiyun 		else
6366*4882a593Smuzhiyun 			port->flow_ctrl = PHY_FLOW_CTRL;
6367*4882a593Smuzhiyun 		hw->overrides &= ~PAUSE_FLOW_CTRL;
6368*4882a593Smuzhiyun 		port->force_link = 0;
6369*4882a593Smuzhiyun 		if (hw->ksz_switch) {
6370*4882a593Smuzhiyun 			sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET,
6371*4882a593Smuzhiyun 				SWITCH_RX_FLOW_CTRL, 1);
6372*4882a593Smuzhiyun 			sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET,
6373*4882a593Smuzhiyun 				SWITCH_TX_FLOW_CTRL, 1);
6374*4882a593Smuzhiyun 		}
6375*4882a593Smuzhiyun 		port_set_link_speed(port);
6376*4882a593Smuzhiyun 	} else {
6377*4882a593Smuzhiyun 		hw->overrides |= PAUSE_FLOW_CTRL;
6378*4882a593Smuzhiyun 		if (hw->ksz_switch) {
6379*4882a593Smuzhiyun 			sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET,
6380*4882a593Smuzhiyun 				SWITCH_RX_FLOW_CTRL, pause->rx_pause);
6381*4882a593Smuzhiyun 			sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET,
6382*4882a593Smuzhiyun 				SWITCH_TX_FLOW_CTRL, pause->tx_pause);
6383*4882a593Smuzhiyun 		} else
6384*4882a593Smuzhiyun 			set_flow_ctrl(hw, pause->rx_pause, pause->tx_pause);
6385*4882a593Smuzhiyun 	}
6386*4882a593Smuzhiyun 	mutex_unlock(&hw_priv->lock);
6387*4882a593Smuzhiyun 
6388*4882a593Smuzhiyun 	return 0;
6389*4882a593Smuzhiyun }
6390*4882a593Smuzhiyun 
6391*4882a593Smuzhiyun /**
6392*4882a593Smuzhiyun  * netdev_get_ringparam - get tx/rx ring parameters
6393*4882a593Smuzhiyun  * @dev:	Network device.
6394*4882a593Smuzhiyun  * @ring:	Ethtool RING settings data structure.
6395*4882a593Smuzhiyun  *
6396*4882a593Smuzhiyun  * This procedure returns the TX/RX ring settings.
6397*4882a593Smuzhiyun  */
netdev_get_ringparam(struct net_device * dev,struct ethtool_ringparam * ring)6398*4882a593Smuzhiyun static void netdev_get_ringparam(struct net_device *dev,
6399*4882a593Smuzhiyun 	struct ethtool_ringparam *ring)
6400*4882a593Smuzhiyun {
6401*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6402*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6403*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
6404*4882a593Smuzhiyun 
6405*4882a593Smuzhiyun 	ring->tx_max_pending = (1 << 9);
6406*4882a593Smuzhiyun 	ring->tx_pending = hw->tx_desc_info.alloc;
6407*4882a593Smuzhiyun 	ring->rx_max_pending = (1 << 9);
6408*4882a593Smuzhiyun 	ring->rx_pending = hw->rx_desc_info.alloc;
6409*4882a593Smuzhiyun }
6410*4882a593Smuzhiyun 
6411*4882a593Smuzhiyun #define STATS_LEN			(TOTAL_PORT_COUNTER_NUM)
6412*4882a593Smuzhiyun 
6413*4882a593Smuzhiyun static struct {
6414*4882a593Smuzhiyun 	char string[ETH_GSTRING_LEN];
6415*4882a593Smuzhiyun } ethtool_stats_keys[STATS_LEN] = {
6416*4882a593Smuzhiyun 	{ "rx_lo_priority_octets" },
6417*4882a593Smuzhiyun 	{ "rx_hi_priority_octets" },
6418*4882a593Smuzhiyun 	{ "rx_undersize_packets" },
6419*4882a593Smuzhiyun 	{ "rx_fragments" },
6420*4882a593Smuzhiyun 	{ "rx_oversize_packets" },
6421*4882a593Smuzhiyun 	{ "rx_jabbers" },
6422*4882a593Smuzhiyun 	{ "rx_symbol_errors" },
6423*4882a593Smuzhiyun 	{ "rx_crc_errors" },
6424*4882a593Smuzhiyun 	{ "rx_align_errors" },
6425*4882a593Smuzhiyun 	{ "rx_mac_ctrl_packets" },
6426*4882a593Smuzhiyun 	{ "rx_pause_packets" },
6427*4882a593Smuzhiyun 	{ "rx_bcast_packets" },
6428*4882a593Smuzhiyun 	{ "rx_mcast_packets" },
6429*4882a593Smuzhiyun 	{ "rx_ucast_packets" },
6430*4882a593Smuzhiyun 	{ "rx_64_or_less_octet_packets" },
6431*4882a593Smuzhiyun 	{ "rx_65_to_127_octet_packets" },
6432*4882a593Smuzhiyun 	{ "rx_128_to_255_octet_packets" },
6433*4882a593Smuzhiyun 	{ "rx_256_to_511_octet_packets" },
6434*4882a593Smuzhiyun 	{ "rx_512_to_1023_octet_packets" },
6435*4882a593Smuzhiyun 	{ "rx_1024_to_1522_octet_packets" },
6436*4882a593Smuzhiyun 
6437*4882a593Smuzhiyun 	{ "tx_lo_priority_octets" },
6438*4882a593Smuzhiyun 	{ "tx_hi_priority_octets" },
6439*4882a593Smuzhiyun 	{ "tx_late_collisions" },
6440*4882a593Smuzhiyun 	{ "tx_pause_packets" },
6441*4882a593Smuzhiyun 	{ "tx_bcast_packets" },
6442*4882a593Smuzhiyun 	{ "tx_mcast_packets" },
6443*4882a593Smuzhiyun 	{ "tx_ucast_packets" },
6444*4882a593Smuzhiyun 	{ "tx_deferred" },
6445*4882a593Smuzhiyun 	{ "tx_total_collisions" },
6446*4882a593Smuzhiyun 	{ "tx_excessive_collisions" },
6447*4882a593Smuzhiyun 	{ "tx_single_collisions" },
6448*4882a593Smuzhiyun 	{ "tx_mult_collisions" },
6449*4882a593Smuzhiyun 
6450*4882a593Smuzhiyun 	{ "rx_discards" },
6451*4882a593Smuzhiyun 	{ "tx_discards" },
6452*4882a593Smuzhiyun };
6453*4882a593Smuzhiyun 
6454*4882a593Smuzhiyun /**
6455*4882a593Smuzhiyun  * netdev_get_strings - get statistics identity strings
6456*4882a593Smuzhiyun  * @dev:	Network device.
6457*4882a593Smuzhiyun  * @stringset:	String set identifier.
6458*4882a593Smuzhiyun  * @buf:	Buffer to store the strings.
6459*4882a593Smuzhiyun  *
6460*4882a593Smuzhiyun  * This procedure returns the strings used to identify the statistics.
6461*4882a593Smuzhiyun  */
netdev_get_strings(struct net_device * dev,u32 stringset,u8 * buf)6462*4882a593Smuzhiyun static void netdev_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
6463*4882a593Smuzhiyun {
6464*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6465*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6466*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
6467*4882a593Smuzhiyun 
6468*4882a593Smuzhiyun 	if (ETH_SS_STATS == stringset)
6469*4882a593Smuzhiyun 		memcpy(buf, &ethtool_stats_keys,
6470*4882a593Smuzhiyun 			ETH_GSTRING_LEN * hw->mib_cnt);
6471*4882a593Smuzhiyun }
6472*4882a593Smuzhiyun 
6473*4882a593Smuzhiyun /**
6474*4882a593Smuzhiyun  * netdev_get_sset_count - get statistics size
6475*4882a593Smuzhiyun  * @dev:	Network device.
6476*4882a593Smuzhiyun  * @sset:	The statistics set number.
6477*4882a593Smuzhiyun  *
6478*4882a593Smuzhiyun  * This function returns the size of the statistics to be reported.
6479*4882a593Smuzhiyun  *
6480*4882a593Smuzhiyun  * Return size of the statistics to be reported.
6481*4882a593Smuzhiyun  */
netdev_get_sset_count(struct net_device * dev,int sset)6482*4882a593Smuzhiyun static int netdev_get_sset_count(struct net_device *dev, int sset)
6483*4882a593Smuzhiyun {
6484*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6485*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6486*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
6487*4882a593Smuzhiyun 
6488*4882a593Smuzhiyun 	switch (sset) {
6489*4882a593Smuzhiyun 	case ETH_SS_STATS:
6490*4882a593Smuzhiyun 		return hw->mib_cnt;
6491*4882a593Smuzhiyun 	default:
6492*4882a593Smuzhiyun 		return -EOPNOTSUPP;
6493*4882a593Smuzhiyun 	}
6494*4882a593Smuzhiyun }
6495*4882a593Smuzhiyun 
6496*4882a593Smuzhiyun /**
6497*4882a593Smuzhiyun  * netdev_get_ethtool_stats - get network device statistics
6498*4882a593Smuzhiyun  * @dev:	Network device.
6499*4882a593Smuzhiyun  * @stats:	Ethtool statistics data structure.
6500*4882a593Smuzhiyun  * @data:	Buffer to store the statistics.
6501*4882a593Smuzhiyun  *
6502*4882a593Smuzhiyun  * This procedure returns the statistics.
6503*4882a593Smuzhiyun  */
netdev_get_ethtool_stats(struct net_device * dev,struct ethtool_stats * stats,u64 * data)6504*4882a593Smuzhiyun static void netdev_get_ethtool_stats(struct net_device *dev,
6505*4882a593Smuzhiyun 	struct ethtool_stats *stats, u64 *data)
6506*4882a593Smuzhiyun {
6507*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6508*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6509*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
6510*4882a593Smuzhiyun 	struct ksz_port *port = &priv->port;
6511*4882a593Smuzhiyun 	int n_stats = stats->n_stats;
6512*4882a593Smuzhiyun 	int i;
6513*4882a593Smuzhiyun 	int n;
6514*4882a593Smuzhiyun 	int p;
6515*4882a593Smuzhiyun 	u64 counter[TOTAL_PORT_COUNTER_NUM];
6516*4882a593Smuzhiyun 
6517*4882a593Smuzhiyun 	mutex_lock(&hw_priv->lock);
6518*4882a593Smuzhiyun 	n = SWITCH_PORT_NUM;
6519*4882a593Smuzhiyun 	for (i = 0, p = port->first_port; i < port->mib_port_cnt; i++, p++) {
6520*4882a593Smuzhiyun 		if (media_connected == hw->port_mib[p].state) {
6521*4882a593Smuzhiyun 			hw_priv->counter[p].read = 1;
6522*4882a593Smuzhiyun 
6523*4882a593Smuzhiyun 			/* Remember first port that requests read. */
6524*4882a593Smuzhiyun 			if (n == SWITCH_PORT_NUM)
6525*4882a593Smuzhiyun 				n = p;
6526*4882a593Smuzhiyun 		}
6527*4882a593Smuzhiyun 	}
6528*4882a593Smuzhiyun 	mutex_unlock(&hw_priv->lock);
6529*4882a593Smuzhiyun 
6530*4882a593Smuzhiyun 	if (n < SWITCH_PORT_NUM)
6531*4882a593Smuzhiyun 		schedule_work(&hw_priv->mib_read);
6532*4882a593Smuzhiyun 
6533*4882a593Smuzhiyun 	if (1 == port->mib_port_cnt && n < SWITCH_PORT_NUM) {
6534*4882a593Smuzhiyun 		p = n;
6535*4882a593Smuzhiyun 		wait_event_interruptible_timeout(
6536*4882a593Smuzhiyun 			hw_priv->counter[p].counter,
6537*4882a593Smuzhiyun 			2 == hw_priv->counter[p].read,
6538*4882a593Smuzhiyun 			HZ * 1);
6539*4882a593Smuzhiyun 	} else
6540*4882a593Smuzhiyun 		for (i = 0, p = n; i < port->mib_port_cnt - n; i++, p++) {
6541*4882a593Smuzhiyun 			if (0 == i) {
6542*4882a593Smuzhiyun 				wait_event_interruptible_timeout(
6543*4882a593Smuzhiyun 					hw_priv->counter[p].counter,
6544*4882a593Smuzhiyun 					2 == hw_priv->counter[p].read,
6545*4882a593Smuzhiyun 					HZ * 2);
6546*4882a593Smuzhiyun 			} else if (hw->port_mib[p].cnt_ptr) {
6547*4882a593Smuzhiyun 				wait_event_interruptible_timeout(
6548*4882a593Smuzhiyun 					hw_priv->counter[p].counter,
6549*4882a593Smuzhiyun 					2 == hw_priv->counter[p].read,
6550*4882a593Smuzhiyun 					HZ * 1);
6551*4882a593Smuzhiyun 			}
6552*4882a593Smuzhiyun 		}
6553*4882a593Smuzhiyun 
6554*4882a593Smuzhiyun 	get_mib_counters(hw, port->first_port, port->mib_port_cnt, counter);
6555*4882a593Smuzhiyun 	n = hw->mib_cnt;
6556*4882a593Smuzhiyun 	if (n > n_stats)
6557*4882a593Smuzhiyun 		n = n_stats;
6558*4882a593Smuzhiyun 	n_stats -= n;
6559*4882a593Smuzhiyun 	for (i = 0; i < n; i++)
6560*4882a593Smuzhiyun 		*data++ = counter[i];
6561*4882a593Smuzhiyun }
6562*4882a593Smuzhiyun 
6563*4882a593Smuzhiyun /**
6564*4882a593Smuzhiyun  * netdev_set_features - set receive checksum support
6565*4882a593Smuzhiyun  * @dev:	Network device.
6566*4882a593Smuzhiyun  * @features:	New device features (offloads).
6567*4882a593Smuzhiyun  *
6568*4882a593Smuzhiyun  * This function sets receive checksum support setting.
6569*4882a593Smuzhiyun  *
6570*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code.
6571*4882a593Smuzhiyun  */
netdev_set_features(struct net_device * dev,netdev_features_t features)6572*4882a593Smuzhiyun static int netdev_set_features(struct net_device *dev,
6573*4882a593Smuzhiyun 	netdev_features_t features)
6574*4882a593Smuzhiyun {
6575*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6576*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6577*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
6578*4882a593Smuzhiyun 
6579*4882a593Smuzhiyun 	mutex_lock(&hw_priv->lock);
6580*4882a593Smuzhiyun 
6581*4882a593Smuzhiyun 	/* see note in hw_setup() */
6582*4882a593Smuzhiyun 	if (features & NETIF_F_RXCSUM)
6583*4882a593Smuzhiyun 		hw->rx_cfg |= DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP;
6584*4882a593Smuzhiyun 	else
6585*4882a593Smuzhiyun 		hw->rx_cfg &= ~(DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP);
6586*4882a593Smuzhiyun 
6587*4882a593Smuzhiyun 	if (hw->enabled)
6588*4882a593Smuzhiyun 		writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL);
6589*4882a593Smuzhiyun 
6590*4882a593Smuzhiyun 	mutex_unlock(&hw_priv->lock);
6591*4882a593Smuzhiyun 
6592*4882a593Smuzhiyun 	return 0;
6593*4882a593Smuzhiyun }
6594*4882a593Smuzhiyun 
6595*4882a593Smuzhiyun static const struct ethtool_ops netdev_ethtool_ops = {
6596*4882a593Smuzhiyun 	.nway_reset		= netdev_nway_reset,
6597*4882a593Smuzhiyun 	.get_link		= netdev_get_link,
6598*4882a593Smuzhiyun 	.get_drvinfo		= netdev_get_drvinfo,
6599*4882a593Smuzhiyun 	.get_regs_len		= netdev_get_regs_len,
6600*4882a593Smuzhiyun 	.get_regs		= netdev_get_regs,
6601*4882a593Smuzhiyun 	.get_wol		= netdev_get_wol,
6602*4882a593Smuzhiyun 	.set_wol		= netdev_set_wol,
6603*4882a593Smuzhiyun 	.get_msglevel		= netdev_get_msglevel,
6604*4882a593Smuzhiyun 	.set_msglevel		= netdev_set_msglevel,
6605*4882a593Smuzhiyun 	.get_eeprom_len		= netdev_get_eeprom_len,
6606*4882a593Smuzhiyun 	.get_eeprom		= netdev_get_eeprom,
6607*4882a593Smuzhiyun 	.set_eeprom		= netdev_set_eeprom,
6608*4882a593Smuzhiyun 	.get_pauseparam		= netdev_get_pauseparam,
6609*4882a593Smuzhiyun 	.set_pauseparam		= netdev_set_pauseparam,
6610*4882a593Smuzhiyun 	.get_ringparam		= netdev_get_ringparam,
6611*4882a593Smuzhiyun 	.get_strings		= netdev_get_strings,
6612*4882a593Smuzhiyun 	.get_sset_count		= netdev_get_sset_count,
6613*4882a593Smuzhiyun 	.get_ethtool_stats	= netdev_get_ethtool_stats,
6614*4882a593Smuzhiyun 	.get_link_ksettings	= netdev_get_link_ksettings,
6615*4882a593Smuzhiyun 	.set_link_ksettings	= netdev_set_link_ksettings,
6616*4882a593Smuzhiyun };
6617*4882a593Smuzhiyun 
6618*4882a593Smuzhiyun /*
6619*4882a593Smuzhiyun  * Hardware monitoring
6620*4882a593Smuzhiyun  */
6621*4882a593Smuzhiyun 
update_link(struct net_device * dev,struct dev_priv * priv,struct ksz_port * port)6622*4882a593Smuzhiyun static void update_link(struct net_device *dev, struct dev_priv *priv,
6623*4882a593Smuzhiyun 	struct ksz_port *port)
6624*4882a593Smuzhiyun {
6625*4882a593Smuzhiyun 	if (priv->media_state != port->linked->state) {
6626*4882a593Smuzhiyun 		priv->media_state = port->linked->state;
6627*4882a593Smuzhiyun 		if (netif_running(dev))
6628*4882a593Smuzhiyun 			set_media_state(dev, media_connected);
6629*4882a593Smuzhiyun 	}
6630*4882a593Smuzhiyun }
6631*4882a593Smuzhiyun 
mib_read_work(struct work_struct * work)6632*4882a593Smuzhiyun static void mib_read_work(struct work_struct *work)
6633*4882a593Smuzhiyun {
6634*4882a593Smuzhiyun 	struct dev_info *hw_priv =
6635*4882a593Smuzhiyun 		container_of(work, struct dev_info, mib_read);
6636*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
6637*4882a593Smuzhiyun 	struct ksz_port_mib *mib;
6638*4882a593Smuzhiyun 	int i;
6639*4882a593Smuzhiyun 
6640*4882a593Smuzhiyun 	next_jiffies = jiffies;
6641*4882a593Smuzhiyun 	for (i = 0; i < hw->mib_port_cnt; i++) {
6642*4882a593Smuzhiyun 		mib = &hw->port_mib[i];
6643*4882a593Smuzhiyun 
6644*4882a593Smuzhiyun 		/* Reading MIB counters or requested to read. */
6645*4882a593Smuzhiyun 		if (mib->cnt_ptr || 1 == hw_priv->counter[i].read) {
6646*4882a593Smuzhiyun 
6647*4882a593Smuzhiyun 			/* Need to process receive interrupt. */
6648*4882a593Smuzhiyun 			if (port_r_cnt(hw, i))
6649*4882a593Smuzhiyun 				break;
6650*4882a593Smuzhiyun 			hw_priv->counter[i].read = 0;
6651*4882a593Smuzhiyun 
6652*4882a593Smuzhiyun 			/* Finish reading counters. */
6653*4882a593Smuzhiyun 			if (0 == mib->cnt_ptr) {
6654*4882a593Smuzhiyun 				hw_priv->counter[i].read = 2;
6655*4882a593Smuzhiyun 				wake_up_interruptible(
6656*4882a593Smuzhiyun 					&hw_priv->counter[i].counter);
6657*4882a593Smuzhiyun 			}
6658*4882a593Smuzhiyun 		} else if (time_after_eq(jiffies, hw_priv->counter[i].time)) {
6659*4882a593Smuzhiyun 			/* Only read MIB counters when the port is connected. */
6660*4882a593Smuzhiyun 			if (media_connected == mib->state)
6661*4882a593Smuzhiyun 				hw_priv->counter[i].read = 1;
6662*4882a593Smuzhiyun 			next_jiffies += HZ * 1 * hw->mib_port_cnt;
6663*4882a593Smuzhiyun 			hw_priv->counter[i].time = next_jiffies;
6664*4882a593Smuzhiyun 
6665*4882a593Smuzhiyun 		/* Port is just disconnected. */
6666*4882a593Smuzhiyun 		} else if (mib->link_down) {
6667*4882a593Smuzhiyun 			mib->link_down = 0;
6668*4882a593Smuzhiyun 
6669*4882a593Smuzhiyun 			/* Read counters one last time after link is lost. */
6670*4882a593Smuzhiyun 			hw_priv->counter[i].read = 1;
6671*4882a593Smuzhiyun 		}
6672*4882a593Smuzhiyun 	}
6673*4882a593Smuzhiyun }
6674*4882a593Smuzhiyun 
mib_monitor(struct timer_list * t)6675*4882a593Smuzhiyun static void mib_monitor(struct timer_list *t)
6676*4882a593Smuzhiyun {
6677*4882a593Smuzhiyun 	struct dev_info *hw_priv = from_timer(hw_priv, t, mib_timer_info.timer);
6678*4882a593Smuzhiyun 
6679*4882a593Smuzhiyun 	mib_read_work(&hw_priv->mib_read);
6680*4882a593Smuzhiyun 
6681*4882a593Smuzhiyun 	/* This is used to verify Wake-on-LAN is working. */
6682*4882a593Smuzhiyun 	if (hw_priv->pme_wait) {
6683*4882a593Smuzhiyun 		if (time_is_before_eq_jiffies(hw_priv->pme_wait)) {
6684*4882a593Smuzhiyun 			hw_clr_wol_pme_status(&hw_priv->hw);
6685*4882a593Smuzhiyun 			hw_priv->pme_wait = 0;
6686*4882a593Smuzhiyun 		}
6687*4882a593Smuzhiyun 	} else if (hw_chk_wol_pme_status(&hw_priv->hw)) {
6688*4882a593Smuzhiyun 
6689*4882a593Smuzhiyun 		/* PME is asserted.  Wait 2 seconds to clear it. */
6690*4882a593Smuzhiyun 		hw_priv->pme_wait = jiffies + HZ * 2;
6691*4882a593Smuzhiyun 	}
6692*4882a593Smuzhiyun 
6693*4882a593Smuzhiyun 	ksz_update_timer(&hw_priv->mib_timer_info);
6694*4882a593Smuzhiyun }
6695*4882a593Smuzhiyun 
6696*4882a593Smuzhiyun /**
6697*4882a593Smuzhiyun  * dev_monitor - periodic monitoring
6698*4882a593Smuzhiyun  * @t:	timer list containing a network device pointer.
6699*4882a593Smuzhiyun  *
6700*4882a593Smuzhiyun  * This routine is run in a kernel timer to monitor the network device.
6701*4882a593Smuzhiyun  */
dev_monitor(struct timer_list * t)6702*4882a593Smuzhiyun static void dev_monitor(struct timer_list *t)
6703*4882a593Smuzhiyun {
6704*4882a593Smuzhiyun 	struct dev_priv *priv = from_timer(priv, t, monitor_timer_info.timer);
6705*4882a593Smuzhiyun 	struct net_device *dev = priv->mii_if.dev;
6706*4882a593Smuzhiyun 	struct dev_info *hw_priv = priv->adapter;
6707*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
6708*4882a593Smuzhiyun 	struct ksz_port *port = &priv->port;
6709*4882a593Smuzhiyun 
6710*4882a593Smuzhiyun 	if (!(hw->features & LINK_INT_WORKING))
6711*4882a593Smuzhiyun 		port_get_link_speed(port);
6712*4882a593Smuzhiyun 	update_link(dev, priv, port);
6713*4882a593Smuzhiyun 
6714*4882a593Smuzhiyun 	ksz_update_timer(&priv->monitor_timer_info);
6715*4882a593Smuzhiyun }
6716*4882a593Smuzhiyun 
6717*4882a593Smuzhiyun /*
6718*4882a593Smuzhiyun  * Linux network device interface functions
6719*4882a593Smuzhiyun  */
6720*4882a593Smuzhiyun 
6721*4882a593Smuzhiyun /* Driver exported variables */
6722*4882a593Smuzhiyun 
6723*4882a593Smuzhiyun static int msg_enable;
6724*4882a593Smuzhiyun 
6725*4882a593Smuzhiyun static char *macaddr = ":";
6726*4882a593Smuzhiyun static char *mac1addr = ":";
6727*4882a593Smuzhiyun 
6728*4882a593Smuzhiyun /*
6729*4882a593Smuzhiyun  * This enables multiple network device mode for KSZ8842, which contains a
6730*4882a593Smuzhiyun  * switch with two physical ports.  Some users like to take control of the
6731*4882a593Smuzhiyun  * ports for running Spanning Tree Protocol.  The driver will create an
6732*4882a593Smuzhiyun  * additional eth? device for the other port.
6733*4882a593Smuzhiyun  *
6734*4882a593Smuzhiyun  * Some limitations are the network devices cannot have different MTU and
6735*4882a593Smuzhiyun  * multicast hash tables.
6736*4882a593Smuzhiyun  */
6737*4882a593Smuzhiyun static int multi_dev;
6738*4882a593Smuzhiyun 
6739*4882a593Smuzhiyun /*
6740*4882a593Smuzhiyun  * As most users select multiple network device mode to use Spanning Tree
6741*4882a593Smuzhiyun  * Protocol, this enables a feature in which most unicast and multicast packets
6742*4882a593Smuzhiyun  * are forwarded inside the switch and not passed to the host.  Only packets
6743*4882a593Smuzhiyun  * that need the host's attention are passed to it.  This prevents the host
6744*4882a593Smuzhiyun  * wasting CPU time to examine each and every incoming packets and do the
6745*4882a593Smuzhiyun  * forwarding itself.
6746*4882a593Smuzhiyun  *
6747*4882a593Smuzhiyun  * As the hack requires the private bridge header, the driver cannot compile
6748*4882a593Smuzhiyun  * with just the kernel headers.
6749*4882a593Smuzhiyun  *
6750*4882a593Smuzhiyun  * Enabling STP support also turns on multiple network device mode.
6751*4882a593Smuzhiyun  */
6752*4882a593Smuzhiyun static int stp;
6753*4882a593Smuzhiyun 
6754*4882a593Smuzhiyun /*
6755*4882a593Smuzhiyun  * This enables fast aging in the KSZ8842 switch.  Not sure what situation
6756*4882a593Smuzhiyun  * needs that.  However, fast aging is used to flush the dynamic MAC table when
6757*4882a593Smuzhiyun  * STP support is enabled.
6758*4882a593Smuzhiyun  */
6759*4882a593Smuzhiyun static int fast_aging;
6760*4882a593Smuzhiyun 
6761*4882a593Smuzhiyun /**
6762*4882a593Smuzhiyun  * netdev_init - initialize network device.
6763*4882a593Smuzhiyun  * @dev:	Network device.
6764*4882a593Smuzhiyun  *
6765*4882a593Smuzhiyun  * This function initializes the network device.
6766*4882a593Smuzhiyun  *
6767*4882a593Smuzhiyun  * Return 0 if successful; otherwise an error code indicating failure.
6768*4882a593Smuzhiyun  */
netdev_init(struct net_device * dev)6769*4882a593Smuzhiyun static int __init netdev_init(struct net_device *dev)
6770*4882a593Smuzhiyun {
6771*4882a593Smuzhiyun 	struct dev_priv *priv = netdev_priv(dev);
6772*4882a593Smuzhiyun 
6773*4882a593Smuzhiyun 	/* 500 ms timeout */
6774*4882a593Smuzhiyun 	ksz_init_timer(&priv->monitor_timer_info, 500 * HZ / 1000,
6775*4882a593Smuzhiyun 		dev_monitor);
6776*4882a593Smuzhiyun 
6777*4882a593Smuzhiyun 	/* 500 ms timeout */
6778*4882a593Smuzhiyun 	dev->watchdog_timeo = HZ / 2;
6779*4882a593Smuzhiyun 
6780*4882a593Smuzhiyun 	dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_RXCSUM;
6781*4882a593Smuzhiyun 
6782*4882a593Smuzhiyun 	/*
6783*4882a593Smuzhiyun 	 * Hardware does not really support IPv6 checksum generation, but
6784*4882a593Smuzhiyun 	 * driver actually runs faster with this on.
6785*4882a593Smuzhiyun 	 */
6786*4882a593Smuzhiyun 	dev->hw_features |= NETIF_F_IPV6_CSUM;
6787*4882a593Smuzhiyun 
6788*4882a593Smuzhiyun 	dev->features |= dev->hw_features;
6789*4882a593Smuzhiyun 
6790*4882a593Smuzhiyun 	sema_init(&priv->proc_sem, 1);
6791*4882a593Smuzhiyun 
6792*4882a593Smuzhiyun 	priv->mii_if.phy_id_mask = 0x1;
6793*4882a593Smuzhiyun 	priv->mii_if.reg_num_mask = 0x7;
6794*4882a593Smuzhiyun 	priv->mii_if.dev = dev;
6795*4882a593Smuzhiyun 	priv->mii_if.mdio_read = mdio_read;
6796*4882a593Smuzhiyun 	priv->mii_if.mdio_write = mdio_write;
6797*4882a593Smuzhiyun 	priv->mii_if.phy_id = priv->port.first_port + 1;
6798*4882a593Smuzhiyun 
6799*4882a593Smuzhiyun 	priv->msg_enable = netif_msg_init(msg_enable,
6800*4882a593Smuzhiyun 		(NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK));
6801*4882a593Smuzhiyun 
6802*4882a593Smuzhiyun 	return 0;
6803*4882a593Smuzhiyun }
6804*4882a593Smuzhiyun 
6805*4882a593Smuzhiyun static const struct net_device_ops netdev_ops = {
6806*4882a593Smuzhiyun 	.ndo_init		= netdev_init,
6807*4882a593Smuzhiyun 	.ndo_open		= netdev_open,
6808*4882a593Smuzhiyun 	.ndo_stop		= netdev_close,
6809*4882a593Smuzhiyun 	.ndo_get_stats		= netdev_query_statistics,
6810*4882a593Smuzhiyun 	.ndo_start_xmit		= netdev_tx,
6811*4882a593Smuzhiyun 	.ndo_tx_timeout		= netdev_tx_timeout,
6812*4882a593Smuzhiyun 	.ndo_change_mtu		= netdev_change_mtu,
6813*4882a593Smuzhiyun 	.ndo_set_features	= netdev_set_features,
6814*4882a593Smuzhiyun 	.ndo_set_mac_address	= netdev_set_mac_address,
6815*4882a593Smuzhiyun 	.ndo_validate_addr	= eth_validate_addr,
6816*4882a593Smuzhiyun 	.ndo_do_ioctl		= netdev_ioctl,
6817*4882a593Smuzhiyun 	.ndo_set_rx_mode	= netdev_set_rx_mode,
6818*4882a593Smuzhiyun #ifdef CONFIG_NET_POLL_CONTROLLER
6819*4882a593Smuzhiyun 	.ndo_poll_controller	= netdev_netpoll,
6820*4882a593Smuzhiyun #endif
6821*4882a593Smuzhiyun };
6822*4882a593Smuzhiyun 
netdev_free(struct net_device * dev)6823*4882a593Smuzhiyun static void netdev_free(struct net_device *dev)
6824*4882a593Smuzhiyun {
6825*4882a593Smuzhiyun 	if (dev->watchdog_timeo)
6826*4882a593Smuzhiyun 		unregister_netdev(dev);
6827*4882a593Smuzhiyun 
6828*4882a593Smuzhiyun 	free_netdev(dev);
6829*4882a593Smuzhiyun }
6830*4882a593Smuzhiyun 
6831*4882a593Smuzhiyun struct platform_info {
6832*4882a593Smuzhiyun 	struct dev_info dev_info;
6833*4882a593Smuzhiyun 	struct net_device *netdev[SWITCH_PORT_NUM];
6834*4882a593Smuzhiyun };
6835*4882a593Smuzhiyun 
6836*4882a593Smuzhiyun static int net_device_present;
6837*4882a593Smuzhiyun 
get_mac_addr(struct dev_info * hw_priv,u8 * macaddr,int port)6838*4882a593Smuzhiyun static void get_mac_addr(struct dev_info *hw_priv, u8 *macaddr, int port)
6839*4882a593Smuzhiyun {
6840*4882a593Smuzhiyun 	int i;
6841*4882a593Smuzhiyun 	int j;
6842*4882a593Smuzhiyun 	int got_num;
6843*4882a593Smuzhiyun 	int num;
6844*4882a593Smuzhiyun 
6845*4882a593Smuzhiyun 	i = j = num = got_num = 0;
6846*4882a593Smuzhiyun 	while (j < ETH_ALEN) {
6847*4882a593Smuzhiyun 		if (macaddr[i]) {
6848*4882a593Smuzhiyun 			int digit;
6849*4882a593Smuzhiyun 
6850*4882a593Smuzhiyun 			got_num = 1;
6851*4882a593Smuzhiyun 			digit = hex_to_bin(macaddr[i]);
6852*4882a593Smuzhiyun 			if (digit >= 0)
6853*4882a593Smuzhiyun 				num = num * 16 + digit;
6854*4882a593Smuzhiyun 			else if (':' == macaddr[i])
6855*4882a593Smuzhiyun 				got_num = 2;
6856*4882a593Smuzhiyun 			else
6857*4882a593Smuzhiyun 				break;
6858*4882a593Smuzhiyun 		} else if (got_num)
6859*4882a593Smuzhiyun 			got_num = 2;
6860*4882a593Smuzhiyun 		else
6861*4882a593Smuzhiyun 			break;
6862*4882a593Smuzhiyun 		if (2 == got_num) {
6863*4882a593Smuzhiyun 			if (MAIN_PORT == port) {
6864*4882a593Smuzhiyun 				hw_priv->hw.override_addr[j++] = (u8) num;
6865*4882a593Smuzhiyun 				hw_priv->hw.override_addr[5] +=
6866*4882a593Smuzhiyun 					hw_priv->hw.id;
6867*4882a593Smuzhiyun 			} else {
6868*4882a593Smuzhiyun 				hw_priv->hw.ksz_switch->other_addr[j++] =
6869*4882a593Smuzhiyun 					(u8) num;
6870*4882a593Smuzhiyun 				hw_priv->hw.ksz_switch->other_addr[5] +=
6871*4882a593Smuzhiyun 					hw_priv->hw.id;
6872*4882a593Smuzhiyun 			}
6873*4882a593Smuzhiyun 			num = got_num = 0;
6874*4882a593Smuzhiyun 		}
6875*4882a593Smuzhiyun 		i++;
6876*4882a593Smuzhiyun 	}
6877*4882a593Smuzhiyun 	if (ETH_ALEN == j) {
6878*4882a593Smuzhiyun 		if (MAIN_PORT == port)
6879*4882a593Smuzhiyun 			hw_priv->hw.mac_override = 1;
6880*4882a593Smuzhiyun 	}
6881*4882a593Smuzhiyun }
6882*4882a593Smuzhiyun 
6883*4882a593Smuzhiyun #define KS884X_DMA_MASK			(~0x0UL)
6884*4882a593Smuzhiyun 
read_other_addr(struct ksz_hw * hw)6885*4882a593Smuzhiyun static void read_other_addr(struct ksz_hw *hw)
6886*4882a593Smuzhiyun {
6887*4882a593Smuzhiyun 	int i;
6888*4882a593Smuzhiyun 	u16 data[3];
6889*4882a593Smuzhiyun 	struct ksz_switch *sw = hw->ksz_switch;
6890*4882a593Smuzhiyun 
6891*4882a593Smuzhiyun 	for (i = 0; i < 3; i++)
6892*4882a593Smuzhiyun 		data[i] = eeprom_read(hw, i + EEPROM_DATA_OTHER_MAC_ADDR);
6893*4882a593Smuzhiyun 	if ((data[0] || data[1] || data[2]) && data[0] != 0xffff) {
6894*4882a593Smuzhiyun 		sw->other_addr[5] = (u8) data[0];
6895*4882a593Smuzhiyun 		sw->other_addr[4] = (u8)(data[0] >> 8);
6896*4882a593Smuzhiyun 		sw->other_addr[3] = (u8) data[1];
6897*4882a593Smuzhiyun 		sw->other_addr[2] = (u8)(data[1] >> 8);
6898*4882a593Smuzhiyun 		sw->other_addr[1] = (u8) data[2];
6899*4882a593Smuzhiyun 		sw->other_addr[0] = (u8)(data[2] >> 8);
6900*4882a593Smuzhiyun 	}
6901*4882a593Smuzhiyun }
6902*4882a593Smuzhiyun 
6903*4882a593Smuzhiyun #ifndef PCI_VENDOR_ID_MICREL_KS
6904*4882a593Smuzhiyun #define PCI_VENDOR_ID_MICREL_KS		0x16c6
6905*4882a593Smuzhiyun #endif
6906*4882a593Smuzhiyun 
pcidev_init(struct pci_dev * pdev,const struct pci_device_id * id)6907*4882a593Smuzhiyun static int pcidev_init(struct pci_dev *pdev, const struct pci_device_id *id)
6908*4882a593Smuzhiyun {
6909*4882a593Smuzhiyun 	struct net_device *dev;
6910*4882a593Smuzhiyun 	struct dev_priv *priv;
6911*4882a593Smuzhiyun 	struct dev_info *hw_priv;
6912*4882a593Smuzhiyun 	struct ksz_hw *hw;
6913*4882a593Smuzhiyun 	struct platform_info *info;
6914*4882a593Smuzhiyun 	struct ksz_port *port;
6915*4882a593Smuzhiyun 	unsigned long reg_base;
6916*4882a593Smuzhiyun 	unsigned long reg_len;
6917*4882a593Smuzhiyun 	int cnt;
6918*4882a593Smuzhiyun 	int i;
6919*4882a593Smuzhiyun 	int mib_port_count;
6920*4882a593Smuzhiyun 	int pi;
6921*4882a593Smuzhiyun 	int port_count;
6922*4882a593Smuzhiyun 	int result;
6923*4882a593Smuzhiyun 	char banner[sizeof(version)];
6924*4882a593Smuzhiyun 	struct ksz_switch *sw = NULL;
6925*4882a593Smuzhiyun 
6926*4882a593Smuzhiyun 	result = pcim_enable_device(pdev);
6927*4882a593Smuzhiyun 	if (result)
6928*4882a593Smuzhiyun 		return result;
6929*4882a593Smuzhiyun 
6930*4882a593Smuzhiyun 	result = -ENODEV;
6931*4882a593Smuzhiyun 
6932*4882a593Smuzhiyun 	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) ||
6933*4882a593Smuzhiyun 	    dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)))
6934*4882a593Smuzhiyun 		return result;
6935*4882a593Smuzhiyun 
6936*4882a593Smuzhiyun 	reg_base = pci_resource_start(pdev, 0);
6937*4882a593Smuzhiyun 	reg_len = pci_resource_len(pdev, 0);
6938*4882a593Smuzhiyun 	if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0)
6939*4882a593Smuzhiyun 		return result;
6940*4882a593Smuzhiyun 
6941*4882a593Smuzhiyun 	if (!request_mem_region(reg_base, reg_len, DRV_NAME))
6942*4882a593Smuzhiyun 		return result;
6943*4882a593Smuzhiyun 	pci_set_master(pdev);
6944*4882a593Smuzhiyun 
6945*4882a593Smuzhiyun 	result = -ENOMEM;
6946*4882a593Smuzhiyun 
6947*4882a593Smuzhiyun 	info = kzalloc(sizeof(struct platform_info), GFP_KERNEL);
6948*4882a593Smuzhiyun 	if (!info)
6949*4882a593Smuzhiyun 		goto pcidev_init_dev_err;
6950*4882a593Smuzhiyun 
6951*4882a593Smuzhiyun 	hw_priv = &info->dev_info;
6952*4882a593Smuzhiyun 	hw_priv->pdev = pdev;
6953*4882a593Smuzhiyun 
6954*4882a593Smuzhiyun 	hw = &hw_priv->hw;
6955*4882a593Smuzhiyun 
6956*4882a593Smuzhiyun 	hw->io = ioremap(reg_base, reg_len);
6957*4882a593Smuzhiyun 	if (!hw->io)
6958*4882a593Smuzhiyun 		goto pcidev_init_io_err;
6959*4882a593Smuzhiyun 
6960*4882a593Smuzhiyun 	cnt = hw_init(hw);
6961*4882a593Smuzhiyun 	if (!cnt) {
6962*4882a593Smuzhiyun 		if (msg_enable & NETIF_MSG_PROBE)
6963*4882a593Smuzhiyun 			pr_alert("chip not detected\n");
6964*4882a593Smuzhiyun 		result = -ENODEV;
6965*4882a593Smuzhiyun 		goto pcidev_init_alloc_err;
6966*4882a593Smuzhiyun 	}
6967*4882a593Smuzhiyun 
6968*4882a593Smuzhiyun 	snprintf(banner, sizeof(banner), "%s", version);
6969*4882a593Smuzhiyun 	banner[13] = cnt + '0';		/* Replace x in "Micrel KSZ884x" */
6970*4882a593Smuzhiyun 	dev_info(&hw_priv->pdev->dev, "%s\n", banner);
6971*4882a593Smuzhiyun 	dev_dbg(&hw_priv->pdev->dev, "Mem = %p; IRQ = %d\n", hw->io, pdev->irq);
6972*4882a593Smuzhiyun 
6973*4882a593Smuzhiyun 	/* Assume device is KSZ8841. */
6974*4882a593Smuzhiyun 	hw->dev_count = 1;
6975*4882a593Smuzhiyun 	port_count = 1;
6976*4882a593Smuzhiyun 	mib_port_count = 1;
6977*4882a593Smuzhiyun 	hw->addr_list_size = 0;
6978*4882a593Smuzhiyun 	hw->mib_cnt = PORT_COUNTER_NUM;
6979*4882a593Smuzhiyun 	hw->mib_port_cnt = 1;
6980*4882a593Smuzhiyun 
6981*4882a593Smuzhiyun 	/* KSZ8842 has a switch with multiple ports. */
6982*4882a593Smuzhiyun 	if (2 == cnt) {
6983*4882a593Smuzhiyun 		if (fast_aging)
6984*4882a593Smuzhiyun 			hw->overrides |= FAST_AGING;
6985*4882a593Smuzhiyun 
6986*4882a593Smuzhiyun 		hw->mib_cnt = TOTAL_PORT_COUNTER_NUM;
6987*4882a593Smuzhiyun 
6988*4882a593Smuzhiyun 		/* Multiple network device interfaces are required. */
6989*4882a593Smuzhiyun 		if (multi_dev) {
6990*4882a593Smuzhiyun 			hw->dev_count = SWITCH_PORT_NUM;
6991*4882a593Smuzhiyun 			hw->addr_list_size = SWITCH_PORT_NUM - 1;
6992*4882a593Smuzhiyun 		}
6993*4882a593Smuzhiyun 
6994*4882a593Smuzhiyun 		/* Single network device has multiple ports. */
6995*4882a593Smuzhiyun 		if (1 == hw->dev_count) {
6996*4882a593Smuzhiyun 			port_count = SWITCH_PORT_NUM;
6997*4882a593Smuzhiyun 			mib_port_count = SWITCH_PORT_NUM;
6998*4882a593Smuzhiyun 		}
6999*4882a593Smuzhiyun 		hw->mib_port_cnt = TOTAL_PORT_NUM;
7000*4882a593Smuzhiyun 		hw->ksz_switch = kzalloc(sizeof(struct ksz_switch), GFP_KERNEL);
7001*4882a593Smuzhiyun 		if (!hw->ksz_switch)
7002*4882a593Smuzhiyun 			goto pcidev_init_alloc_err;
7003*4882a593Smuzhiyun 
7004*4882a593Smuzhiyun 		sw = hw->ksz_switch;
7005*4882a593Smuzhiyun 	}
7006*4882a593Smuzhiyun 	for (i = 0; i < hw->mib_port_cnt; i++)
7007*4882a593Smuzhiyun 		hw->port_mib[i].mib_start = 0;
7008*4882a593Smuzhiyun 
7009*4882a593Smuzhiyun 	hw->parent = hw_priv;
7010*4882a593Smuzhiyun 
7011*4882a593Smuzhiyun 	/* Default MTU is 1500. */
7012*4882a593Smuzhiyun 	hw_priv->mtu = (REGULAR_RX_BUF_SIZE + 3) & ~3;
7013*4882a593Smuzhiyun 
7014*4882a593Smuzhiyun 	if (ksz_alloc_mem(hw_priv))
7015*4882a593Smuzhiyun 		goto pcidev_init_mem_err;
7016*4882a593Smuzhiyun 
7017*4882a593Smuzhiyun 	hw_priv->hw.id = net_device_present;
7018*4882a593Smuzhiyun 
7019*4882a593Smuzhiyun 	spin_lock_init(&hw_priv->hwlock);
7020*4882a593Smuzhiyun 	mutex_init(&hw_priv->lock);
7021*4882a593Smuzhiyun 
7022*4882a593Smuzhiyun 	for (i = 0; i < TOTAL_PORT_NUM; i++)
7023*4882a593Smuzhiyun 		init_waitqueue_head(&hw_priv->counter[i].counter);
7024*4882a593Smuzhiyun 
7025*4882a593Smuzhiyun 	if (macaddr[0] != ':')
7026*4882a593Smuzhiyun 		get_mac_addr(hw_priv, macaddr, MAIN_PORT);
7027*4882a593Smuzhiyun 
7028*4882a593Smuzhiyun 	/* Read MAC address and initialize override address if not overridden. */
7029*4882a593Smuzhiyun 	hw_read_addr(hw);
7030*4882a593Smuzhiyun 
7031*4882a593Smuzhiyun 	/* Multiple device interfaces mode requires a second MAC address. */
7032*4882a593Smuzhiyun 	if (hw->dev_count > 1) {
7033*4882a593Smuzhiyun 		memcpy(sw->other_addr, hw->override_addr, ETH_ALEN);
7034*4882a593Smuzhiyun 		read_other_addr(hw);
7035*4882a593Smuzhiyun 		if (mac1addr[0] != ':')
7036*4882a593Smuzhiyun 			get_mac_addr(hw_priv, mac1addr, OTHER_PORT);
7037*4882a593Smuzhiyun 	}
7038*4882a593Smuzhiyun 
7039*4882a593Smuzhiyun 	hw_setup(hw);
7040*4882a593Smuzhiyun 	if (hw->ksz_switch)
7041*4882a593Smuzhiyun 		sw_setup(hw);
7042*4882a593Smuzhiyun 	else {
7043*4882a593Smuzhiyun 		hw_priv->wol_support = WOL_SUPPORT;
7044*4882a593Smuzhiyun 		hw_priv->wol_enable = 0;
7045*4882a593Smuzhiyun 	}
7046*4882a593Smuzhiyun 
7047*4882a593Smuzhiyun 	INIT_WORK(&hw_priv->mib_read, mib_read_work);
7048*4882a593Smuzhiyun 
7049*4882a593Smuzhiyun 	/* 500 ms timeout */
7050*4882a593Smuzhiyun 	ksz_init_timer(&hw_priv->mib_timer_info, 500 * HZ / 1000,
7051*4882a593Smuzhiyun 		mib_monitor);
7052*4882a593Smuzhiyun 
7053*4882a593Smuzhiyun 	for (i = 0; i < hw->dev_count; i++) {
7054*4882a593Smuzhiyun 		dev = alloc_etherdev(sizeof(struct dev_priv));
7055*4882a593Smuzhiyun 		if (!dev)
7056*4882a593Smuzhiyun 			goto pcidev_init_reg_err;
7057*4882a593Smuzhiyun 		SET_NETDEV_DEV(dev, &pdev->dev);
7058*4882a593Smuzhiyun 		info->netdev[i] = dev;
7059*4882a593Smuzhiyun 
7060*4882a593Smuzhiyun 		priv = netdev_priv(dev);
7061*4882a593Smuzhiyun 		priv->adapter = hw_priv;
7062*4882a593Smuzhiyun 		priv->id = net_device_present++;
7063*4882a593Smuzhiyun 
7064*4882a593Smuzhiyun 		port = &priv->port;
7065*4882a593Smuzhiyun 		port->port_cnt = port_count;
7066*4882a593Smuzhiyun 		port->mib_port_cnt = mib_port_count;
7067*4882a593Smuzhiyun 		port->first_port = i;
7068*4882a593Smuzhiyun 		port->flow_ctrl = PHY_FLOW_CTRL;
7069*4882a593Smuzhiyun 
7070*4882a593Smuzhiyun 		port->hw = hw;
7071*4882a593Smuzhiyun 		port->linked = &hw->port_info[port->first_port];
7072*4882a593Smuzhiyun 
7073*4882a593Smuzhiyun 		for (cnt = 0, pi = i; cnt < port_count; cnt++, pi++) {
7074*4882a593Smuzhiyun 			hw->port_info[pi].port_id = pi;
7075*4882a593Smuzhiyun 			hw->port_info[pi].pdev = dev;
7076*4882a593Smuzhiyun 			hw->port_info[pi].state = media_disconnected;
7077*4882a593Smuzhiyun 		}
7078*4882a593Smuzhiyun 
7079*4882a593Smuzhiyun 		dev->mem_start = (unsigned long) hw->io;
7080*4882a593Smuzhiyun 		dev->mem_end = dev->mem_start + reg_len - 1;
7081*4882a593Smuzhiyun 		dev->irq = pdev->irq;
7082*4882a593Smuzhiyun 		if (MAIN_PORT == i)
7083*4882a593Smuzhiyun 			memcpy(dev->dev_addr, hw_priv->hw.override_addr,
7084*4882a593Smuzhiyun 			       ETH_ALEN);
7085*4882a593Smuzhiyun 		else {
7086*4882a593Smuzhiyun 			memcpy(dev->dev_addr, sw->other_addr, ETH_ALEN);
7087*4882a593Smuzhiyun 			if (ether_addr_equal(sw->other_addr, hw->override_addr))
7088*4882a593Smuzhiyun 				dev->dev_addr[5] += port->first_port;
7089*4882a593Smuzhiyun 		}
7090*4882a593Smuzhiyun 
7091*4882a593Smuzhiyun 		dev->netdev_ops = &netdev_ops;
7092*4882a593Smuzhiyun 		dev->ethtool_ops = &netdev_ethtool_ops;
7093*4882a593Smuzhiyun 
7094*4882a593Smuzhiyun 		/* MTU range: 60 - 1894 */
7095*4882a593Smuzhiyun 		dev->min_mtu = ETH_ZLEN;
7096*4882a593Smuzhiyun 		dev->max_mtu = MAX_RX_BUF_SIZE -
7097*4882a593Smuzhiyun 			       (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
7098*4882a593Smuzhiyun 
7099*4882a593Smuzhiyun 		if (register_netdev(dev))
7100*4882a593Smuzhiyun 			goto pcidev_init_reg_err;
7101*4882a593Smuzhiyun 		port_set_power_saving(port, true);
7102*4882a593Smuzhiyun 	}
7103*4882a593Smuzhiyun 
7104*4882a593Smuzhiyun 	pci_dev_get(hw_priv->pdev);
7105*4882a593Smuzhiyun 	pci_set_drvdata(pdev, info);
7106*4882a593Smuzhiyun 	return 0;
7107*4882a593Smuzhiyun 
7108*4882a593Smuzhiyun pcidev_init_reg_err:
7109*4882a593Smuzhiyun 	for (i = 0; i < hw->dev_count; i++) {
7110*4882a593Smuzhiyun 		if (info->netdev[i]) {
7111*4882a593Smuzhiyun 			netdev_free(info->netdev[i]);
7112*4882a593Smuzhiyun 			info->netdev[i] = NULL;
7113*4882a593Smuzhiyun 		}
7114*4882a593Smuzhiyun 	}
7115*4882a593Smuzhiyun 
7116*4882a593Smuzhiyun pcidev_init_mem_err:
7117*4882a593Smuzhiyun 	ksz_free_mem(hw_priv);
7118*4882a593Smuzhiyun 	kfree(hw->ksz_switch);
7119*4882a593Smuzhiyun 
7120*4882a593Smuzhiyun pcidev_init_alloc_err:
7121*4882a593Smuzhiyun 	iounmap(hw->io);
7122*4882a593Smuzhiyun 
7123*4882a593Smuzhiyun pcidev_init_io_err:
7124*4882a593Smuzhiyun 	kfree(info);
7125*4882a593Smuzhiyun 
7126*4882a593Smuzhiyun pcidev_init_dev_err:
7127*4882a593Smuzhiyun 	release_mem_region(reg_base, reg_len);
7128*4882a593Smuzhiyun 
7129*4882a593Smuzhiyun 	return result;
7130*4882a593Smuzhiyun }
7131*4882a593Smuzhiyun 
pcidev_exit(struct pci_dev * pdev)7132*4882a593Smuzhiyun static void pcidev_exit(struct pci_dev *pdev)
7133*4882a593Smuzhiyun {
7134*4882a593Smuzhiyun 	int i;
7135*4882a593Smuzhiyun 	struct platform_info *info = pci_get_drvdata(pdev);
7136*4882a593Smuzhiyun 	struct dev_info *hw_priv = &info->dev_info;
7137*4882a593Smuzhiyun 
7138*4882a593Smuzhiyun 	release_mem_region(pci_resource_start(pdev, 0),
7139*4882a593Smuzhiyun 		pci_resource_len(pdev, 0));
7140*4882a593Smuzhiyun 	for (i = 0; i < hw_priv->hw.dev_count; i++) {
7141*4882a593Smuzhiyun 		if (info->netdev[i])
7142*4882a593Smuzhiyun 			netdev_free(info->netdev[i]);
7143*4882a593Smuzhiyun 	}
7144*4882a593Smuzhiyun 	if (hw_priv->hw.io)
7145*4882a593Smuzhiyun 		iounmap(hw_priv->hw.io);
7146*4882a593Smuzhiyun 	ksz_free_mem(hw_priv);
7147*4882a593Smuzhiyun 	kfree(hw_priv->hw.ksz_switch);
7148*4882a593Smuzhiyun 	pci_dev_put(hw_priv->pdev);
7149*4882a593Smuzhiyun 	kfree(info);
7150*4882a593Smuzhiyun }
7151*4882a593Smuzhiyun 
pcidev_resume(struct device * dev_d)7152*4882a593Smuzhiyun static int __maybe_unused pcidev_resume(struct device *dev_d)
7153*4882a593Smuzhiyun {
7154*4882a593Smuzhiyun 	int i;
7155*4882a593Smuzhiyun 	struct platform_info *info = dev_get_drvdata(dev_d);
7156*4882a593Smuzhiyun 	struct dev_info *hw_priv = &info->dev_info;
7157*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
7158*4882a593Smuzhiyun 
7159*4882a593Smuzhiyun 	device_wakeup_disable(dev_d);
7160*4882a593Smuzhiyun 
7161*4882a593Smuzhiyun 	if (hw_priv->wol_enable)
7162*4882a593Smuzhiyun 		hw_cfg_wol_pme(hw, 0);
7163*4882a593Smuzhiyun 	for (i = 0; i < hw->dev_count; i++) {
7164*4882a593Smuzhiyun 		if (info->netdev[i]) {
7165*4882a593Smuzhiyun 			struct net_device *dev = info->netdev[i];
7166*4882a593Smuzhiyun 
7167*4882a593Smuzhiyun 			if (netif_running(dev)) {
7168*4882a593Smuzhiyun 				netdev_open(dev);
7169*4882a593Smuzhiyun 				netif_device_attach(dev);
7170*4882a593Smuzhiyun 			}
7171*4882a593Smuzhiyun 		}
7172*4882a593Smuzhiyun 	}
7173*4882a593Smuzhiyun 	return 0;
7174*4882a593Smuzhiyun }
7175*4882a593Smuzhiyun 
pcidev_suspend(struct device * dev_d)7176*4882a593Smuzhiyun static int __maybe_unused pcidev_suspend(struct device *dev_d)
7177*4882a593Smuzhiyun {
7178*4882a593Smuzhiyun 	int i;
7179*4882a593Smuzhiyun 	struct platform_info *info = dev_get_drvdata(dev_d);
7180*4882a593Smuzhiyun 	struct dev_info *hw_priv = &info->dev_info;
7181*4882a593Smuzhiyun 	struct ksz_hw *hw = &hw_priv->hw;
7182*4882a593Smuzhiyun 
7183*4882a593Smuzhiyun 	/* Need to find a way to retrieve the device IP address. */
7184*4882a593Smuzhiyun 	static const u8 net_addr[] = { 192, 168, 1, 1 };
7185*4882a593Smuzhiyun 
7186*4882a593Smuzhiyun 	for (i = 0; i < hw->dev_count; i++) {
7187*4882a593Smuzhiyun 		if (info->netdev[i]) {
7188*4882a593Smuzhiyun 			struct net_device *dev = info->netdev[i];
7189*4882a593Smuzhiyun 
7190*4882a593Smuzhiyun 			if (netif_running(dev)) {
7191*4882a593Smuzhiyun 				netif_device_detach(dev);
7192*4882a593Smuzhiyun 				netdev_close(dev);
7193*4882a593Smuzhiyun 			}
7194*4882a593Smuzhiyun 		}
7195*4882a593Smuzhiyun 	}
7196*4882a593Smuzhiyun 	if (hw_priv->wol_enable) {
7197*4882a593Smuzhiyun 		hw_enable_wol(hw, hw_priv->wol_enable, net_addr);
7198*4882a593Smuzhiyun 		hw_cfg_wol_pme(hw, 1);
7199*4882a593Smuzhiyun 	}
7200*4882a593Smuzhiyun 
7201*4882a593Smuzhiyun 	device_wakeup_enable(dev_d);
7202*4882a593Smuzhiyun 	return 0;
7203*4882a593Smuzhiyun }
7204*4882a593Smuzhiyun 
7205*4882a593Smuzhiyun static char pcidev_name[] = "ksz884xp";
7206*4882a593Smuzhiyun 
7207*4882a593Smuzhiyun static const struct pci_device_id pcidev_table[] = {
7208*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_MICREL_KS, 0x8841,
7209*4882a593Smuzhiyun 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
7210*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_MICREL_KS, 0x8842,
7211*4882a593Smuzhiyun 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
7212*4882a593Smuzhiyun 	{ 0 }
7213*4882a593Smuzhiyun };
7214*4882a593Smuzhiyun 
7215*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, pcidev_table);
7216*4882a593Smuzhiyun 
7217*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(pcidev_pm_ops, pcidev_suspend, pcidev_resume);
7218*4882a593Smuzhiyun 
7219*4882a593Smuzhiyun static struct pci_driver pci_device_driver = {
7220*4882a593Smuzhiyun 	.driver.pm	= &pcidev_pm_ops,
7221*4882a593Smuzhiyun 	.name		= pcidev_name,
7222*4882a593Smuzhiyun 	.id_table	= pcidev_table,
7223*4882a593Smuzhiyun 	.probe		= pcidev_init,
7224*4882a593Smuzhiyun 	.remove		= pcidev_exit
7225*4882a593Smuzhiyun };
7226*4882a593Smuzhiyun 
7227*4882a593Smuzhiyun module_pci_driver(pci_device_driver);
7228*4882a593Smuzhiyun 
7229*4882a593Smuzhiyun MODULE_DESCRIPTION("KSZ8841/2 PCI network driver");
7230*4882a593Smuzhiyun MODULE_AUTHOR("Tristram Ha <Tristram.Ha@micrel.com>");
7231*4882a593Smuzhiyun MODULE_LICENSE("GPL");
7232*4882a593Smuzhiyun 
7233*4882a593Smuzhiyun module_param_named(message, msg_enable, int, 0);
7234*4882a593Smuzhiyun MODULE_PARM_DESC(message, "Message verbosity level (0=none, 31=all)");
7235*4882a593Smuzhiyun 
7236*4882a593Smuzhiyun module_param(macaddr, charp, 0);
7237*4882a593Smuzhiyun module_param(mac1addr, charp, 0);
7238*4882a593Smuzhiyun module_param(fast_aging, int, 0);
7239*4882a593Smuzhiyun module_param(multi_dev, int, 0);
7240*4882a593Smuzhiyun module_param(stp, int, 0);
7241*4882a593Smuzhiyun MODULE_PARM_DESC(macaddr, "MAC address");
7242*4882a593Smuzhiyun MODULE_PARM_DESC(mac1addr, "Second MAC address");
7243*4882a593Smuzhiyun MODULE_PARM_DESC(fast_aging, "Fast aging");
7244*4882a593Smuzhiyun MODULE_PARM_DESC(multi_dev, "Multiple device interfaces");
7245*4882a593Smuzhiyun MODULE_PARM_DESC(stp, "STP support");
7246