xref: /illumos-gate/usr/src/uts/common/io/chxge/com/pm3393.c (revision 2d6eb4a5)
1d39a76e7Sxw /*
2d39a76e7Sxw  * CDDL HEADER START
3d39a76e7Sxw  *
4d39a76e7Sxw  * The contents of this file are subject to the terms of the
5d39a76e7Sxw  * Common Development and Distribution License (the "License").
6d39a76e7Sxw  * You may not use this file except in compliance with the License.
7d39a76e7Sxw  *
8d39a76e7Sxw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d39a76e7Sxw  * or http://www.opensolaris.org/os/licensing.
10d39a76e7Sxw  * See the License for the specific language governing permissions
11d39a76e7Sxw  * and limitations under the License.
12d39a76e7Sxw  *
13d39a76e7Sxw  * When distributing Covered Code, include this CDDL HEADER in each
14d39a76e7Sxw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d39a76e7Sxw  * If applicable, add the following below this CDDL HEADER, with the
16d39a76e7Sxw  * fields enclosed by brackets "[]" replaced with your own identifying
17d39a76e7Sxw  * information: Portions Copyright [yyyy] [name of copyright owner]
18d39a76e7Sxw  *
19d39a76e7Sxw  * CDDL HEADER END
20d39a76e7Sxw  */
21d39a76e7Sxw 
22d39a76e7Sxw /*
23d39a76e7Sxw  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
24d39a76e7Sxw  */
25d39a76e7Sxw 
26d39a76e7Sxw #include "common.h"
27d39a76e7Sxw #include "regs.h"
28d39a76e7Sxw #include "gmac.h"
29d39a76e7Sxw #include "elmer0.h"
30d39a76e7Sxw #include "suni1x10gexp_regs.h"
31d39a76e7Sxw 
32d39a76e7Sxw /* 802.3ae 10Gb/s MDIO Manageable Device(MMD)
33d39a76e7Sxw  */
34d39a76e7Sxw #define MMD_RESERVED        0
35d39a76e7Sxw #define MMD_PMAPMD          1
36d39a76e7Sxw #define MMD_WIS             2
37d39a76e7Sxw #define MMD_PCS             3
38d39a76e7Sxw #define MMD_PHY_XGXS        4	/* XGMII Extender Sublayer */
39d39a76e7Sxw #define MMD_DTE_XGXS        5
40d39a76e7Sxw 
41d39a76e7Sxw #define PHY_XGXS_CTRL_1     0
42d39a76e7Sxw #define PHY_XGXS_STATUS_1   1
43d39a76e7Sxw 
44d39a76e7Sxw #define OFFSET(REG_ADDR)    (REG_ADDR << 2)
45d39a76e7Sxw 
46d39a76e7Sxw /* Max frame size PM3393 can handle. Includes Ethernet header and CRC. */
47d39a76e7Sxw #define MAX_FRAME_SIZE  9600
48d39a76e7Sxw 
49d39a76e7Sxw #define IPG 12
50d39a76e7Sxw #define TXXG_CONF1_VAL ((IPG << SUNI1x10GEXP_BITOFF_TXXG_IPGT) | \
51d39a76e7Sxw     SUNI1x10GEXP_BITMSK_TXXG_32BIT_ALIGN | SUNI1x10GEXP_BITMSK_TXXG_CRCEN | \
52d39a76e7Sxw     SUNI1x10GEXP_BITMSK_TXXG_PADEN)
53d39a76e7Sxw #define RXXG_CONF1_VAL (SUNI1x10GEXP_BITMSK_RXXG_PUREP | 0x14 | \
54d39a76e7Sxw     SUNI1x10GEXP_BITMSK_RXXG_FLCHK | SUNI1x10GEXP_BITMSK_RXXG_CRC_STRIP)
55d39a76e7Sxw 
56d39a76e7Sxw /* Update statistics every 15 minutes */
57d39a76e7Sxw #define STATS_TICK_SECS (15 * 60)
58d39a76e7Sxw 
59d39a76e7Sxw enum {                     /* RMON registers */
60d39a76e7Sxw 	RxOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW,
61d39a76e7Sxw 	RxUnicastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_4_LOW,
62d39a76e7Sxw 	RxMulticastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_5_LOW,
63d39a76e7Sxw 	RxBroadcastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_6_LOW,
64d39a76e7Sxw 	RxPAUSEMACCtrlFramesReceived = SUNI1x10GEXP_REG_MSTAT_COUNTER_8_LOW,
65d39a76e7Sxw 	RxFrameCheckSequenceErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_10_LOW,
66d39a76e7Sxw 	RxFramesLostDueToInternalMACErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_11_LOW,
67d39a76e7Sxw 	RxSymbolErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_12_LOW,
68d39a76e7Sxw 	RxInRangeLengthErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_13_LOW,
69d39a76e7Sxw 	RxFramesTooLongErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_15_LOW,
70d39a76e7Sxw 	RxJabbers = SUNI1x10GEXP_REG_MSTAT_COUNTER_16_LOW,
71d39a76e7Sxw 	RxFragments = SUNI1x10GEXP_REG_MSTAT_COUNTER_17_LOW,
72d39a76e7Sxw 	RxUndersizedFrames =  SUNI1x10GEXP_REG_MSTAT_COUNTER_18_LOW,
73d39a76e7Sxw 	RxJumboFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_25_LOW,
74d39a76e7Sxw 	RxJumboOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_26_LOW,
75d39a76e7Sxw 
76d39a76e7Sxw 	TxOctetsTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW,
77d39a76e7Sxw 	TxFramesLostDueToInternalMACTransmissionError = SUNI1x10GEXP_REG_MSTAT_COUNTER_35_LOW,
78d39a76e7Sxw 	TxTransmitSystemError = SUNI1x10GEXP_REG_MSTAT_COUNTER_36_LOW,
79d39a76e7Sxw 	TxUnicastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_38_LOW,
80d39a76e7Sxw 	TxMulticastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_40_LOW,
81d39a76e7Sxw 	TxBroadcastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_42_LOW,
82d39a76e7Sxw 	TxPAUSEMACCtrlFramesTransmitted = SUNI1x10GEXP_REG_MSTAT_COUNTER_43_LOW,
83d39a76e7Sxw 	TxJumboFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_51_LOW,
84d39a76e7Sxw 	TxJumboOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_52_LOW
85d39a76e7Sxw };
86d39a76e7Sxw 
87d39a76e7Sxw struct _cmac_instance {
88d39a76e7Sxw 	u8 enabled;
89d39a76e7Sxw 	u8 fc;
90d39a76e7Sxw 	u8 mac_addr[6];
91d39a76e7Sxw };
92d39a76e7Sxw 
pmread(struct cmac * cmac,u32 reg,u32 * data32)93d39a76e7Sxw static int pmread(struct cmac *cmac, u32 reg, u32 * data32)
94d39a76e7Sxw {
95d39a76e7Sxw 	(void) t1_tpi_read(cmac->adapter, OFFSET(reg), data32);
96d39a76e7Sxw 	return 0;
97d39a76e7Sxw }
98d39a76e7Sxw 
pmwrite(struct cmac * cmac,u32 reg,u32 data32)99d39a76e7Sxw static int pmwrite(struct cmac *cmac, u32 reg, u32 data32)
100d39a76e7Sxw {
101d39a76e7Sxw 	(void) t1_tpi_write(cmac->adapter, OFFSET(reg), data32);
102d39a76e7Sxw 	return 0;
103d39a76e7Sxw }
104d39a76e7Sxw 
105d39a76e7Sxw /* Port reset. */
106d39a76e7Sxw /* ARGSUSED */
pm3393_reset(struct cmac * cmac)107d39a76e7Sxw static int pm3393_reset(struct cmac *cmac)
108d39a76e7Sxw {
109d39a76e7Sxw 	return 0;
110d39a76e7Sxw }
111d39a76e7Sxw 
112d39a76e7Sxw /*
113d39a76e7Sxw  * Enable interrupts for the PM3393
114*2d6eb4a5SToomas Soome 
115d39a76e7Sxw     1. Enable PM3393 BLOCK interrupts.
116d39a76e7Sxw     2. Enable PM3393 Master Interrupt bit(INTE)
117d39a76e7Sxw     3. Enable ELMER's PM3393 bit.
118d39a76e7Sxw     4. Enable Terminator external interrupt.
119d39a76e7Sxw */
pm3393_interrupt_enable(struct cmac * cmac)120d39a76e7Sxw static int pm3393_interrupt_enable(struct cmac *cmac)
121d39a76e7Sxw {
122d39a76e7Sxw #if 0
123d39a76e7Sxw 	u32 elmer;
124d39a76e7Sxw #endif
125d39a76e7Sxw 	u32 pl_intr;
126d39a76e7Sxw 
127d39a76e7Sxw 	/* PM3393 - Enabling all hardware block interrupts.
128d39a76e7Sxw 	 */
129d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0xffff);
130d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0xffff);
131d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0xffff);
132d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0xffff);
133d39a76e7Sxw 
134d39a76e7Sxw 	/* Don't interrupt on statistics overflow, we are polling */
135d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0);
136d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0);
137d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0);
138d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0);
139d39a76e7Sxw 
140d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0xffff);
141d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0xffff);
142d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0xffff);
143d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0xffff);
144d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0xffff);
145d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0xffff);
146d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0xffff);
147d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0xffff);
148d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0xffff);
149d39a76e7Sxw 
150d39a76e7Sxw 	/* PM3393 - Global interrupt enable
151d39a76e7Sxw 	 */
152d39a76e7Sxw 	/* TBD XXX Disable for now until we figure out why error interrupts keep asserting. */
153d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE,
154d39a76e7Sxw 		0 /*SUNI1x10GEXP_BITMSK_TOP_INTE */ );
155d39a76e7Sxw 
156d39a76e7Sxw #if 0
157d39a76e7Sxw 	/* ELMER - External chip interrupts.
158d39a76e7Sxw 	 */
159d39a76e7Sxw 	(void) t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer);
160d39a76e7Sxw 	elmer |= ELMER0_GP_BIT1;
161d39a76e7Sxw 	(void) t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer);
162d39a76e7Sxw #endif
163d39a76e7Sxw 
164d39a76e7Sxw 	/* TERMINATOR - PL_INTERUPTS_EXT */
165d39a76e7Sxw 	pl_intr = t1_read_reg_4(cmac->adapter, A_PL_ENABLE);
166d39a76e7Sxw 	pl_intr |= F_PL_INTR_EXT;
167d39a76e7Sxw 	t1_write_reg_4(cmac->adapter, A_PL_ENABLE, pl_intr);
168d39a76e7Sxw 	return 0;
169d39a76e7Sxw }
170d39a76e7Sxw 
pm3393_interrupt_disable(struct cmac * cmac)171d39a76e7Sxw static int pm3393_interrupt_disable(struct cmac *cmac)
172d39a76e7Sxw {
173d39a76e7Sxw 	u32 elmer;
174d39a76e7Sxw 
175d39a76e7Sxw 	/* PM3393 - Enabling HW interrupt blocks. */
176d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0);
177d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0);
178d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0);
179d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0);
180d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0);
181d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0);
182d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0);
183d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0);
184d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0);
185d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0);
186d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0);
187d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0);
188d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0);
189d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0);
190d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0);
191d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0);
192d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0);
193d39a76e7Sxw 
194d39a76e7Sxw 	/* PM3393 - Global interrupt enable */
195d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0);
196d39a76e7Sxw 
197d39a76e7Sxw 	/* ELMER - External chip interrupts. */
198d39a76e7Sxw 	(void) t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer);
199d39a76e7Sxw 	elmer &= ~ELMER0_GP_BIT1;
200d39a76e7Sxw 	(void) t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer);
201d39a76e7Sxw 
202d39a76e7Sxw 	/* TERMINATOR - PL_INTERUPTS_EXT */
203d39a76e7Sxw 	/* DO NOT DISABLE TERMINATOR's EXTERNAL INTERRUPTS. ANOTHER CHIP
204d39a76e7Sxw 	 * COULD WANT THEM ENABLED. We disable PM3393 at the ELMER level.
205d39a76e7Sxw 	 */
206d39a76e7Sxw 
207d39a76e7Sxw 	return 0;
208d39a76e7Sxw }
209d39a76e7Sxw 
pm3393_interrupt_clear(struct cmac * cmac)210d39a76e7Sxw static int pm3393_interrupt_clear(struct cmac *cmac)
211d39a76e7Sxw {
212d39a76e7Sxw 	u32 elmer;
213d39a76e7Sxw 	u32 pl_intr;
214d39a76e7Sxw 	u32 val32;
215d39a76e7Sxw 
216d39a76e7Sxw 	/* PM3393 - Clearing HW interrupt blocks. Note, this assumes
217d39a76e7Sxw 	 *          bit WCIMODE=0 for a clear-on-read.
218d39a76e7Sxw 	 */
219d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_STATUS, &val32);
220d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_STATUS, &val32);
221d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_STATUS, &val32);
222d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_STATUS, &val32);
223d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT, &val32);
224d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_STATUS, &val32);
225d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_INTERRUPT, &val32);
226d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_STATUS, &val32);
227d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_RXXG_INTERRUPT, &val32);
228d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_TXXG_INTERRUPT, &val32);
229d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT, &val32);
230d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_INDICATION,
231d39a76e7Sxw 	       &val32);
232d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_STATUS, &val32);
233d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_CHANGE, &val32);
234d39a76e7Sxw 
235*2d6eb4a5SToomas Soome 	/* PM3393 - Global interrupt status
236d39a76e7Sxw 	 */
237d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS, &val32);
238d39a76e7Sxw 
239d39a76e7Sxw 	/* ELMER - External chip interrupts.
240d39a76e7Sxw 	 */
241d39a76e7Sxw 	(void) t1_tpi_read(cmac->adapter, A_ELMER0_INT_CAUSE, &elmer);
242d39a76e7Sxw 	elmer |= ELMER0_GP_BIT1;
243d39a76e7Sxw 	(void) t1_tpi_write(cmac->adapter, A_ELMER0_INT_CAUSE, elmer);
244d39a76e7Sxw 
245*2d6eb4a5SToomas Soome 	/* TERMINATOR - PL_INTERUPTS_EXT
246d39a76e7Sxw 	 */
247d39a76e7Sxw 	pl_intr = t1_read_reg_4(cmac->adapter, A_PL_CAUSE);
248d39a76e7Sxw 	pl_intr |= F_PL_INTR_EXT;
249d39a76e7Sxw 	t1_write_reg_4(cmac->adapter, A_PL_CAUSE, pl_intr);
250d39a76e7Sxw 
251d39a76e7Sxw 	return 0;
252d39a76e7Sxw }
253d39a76e7Sxw 
254d39a76e7Sxw /* Interrupt handler */
pm3393_interrupt_handler(struct cmac * cmac)255d39a76e7Sxw static int pm3393_interrupt_handler(struct cmac *cmac)
256d39a76e7Sxw {
257d39a76e7Sxw 	u32 master_intr_status;
258d39a76e7Sxw /*
259d39a76e7Sxw     1. Read master interrupt register.
260d39a76e7Sxw     2. Read BLOCK's interrupt status registers.
261d39a76e7Sxw     3. Handle BLOCK interrupts.
262d39a76e7Sxw */
263d39a76e7Sxw 	/* Read the master interrupt status register. */
264d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS,
265d39a76e7Sxw 	       &master_intr_status);
266d39a76e7Sxw 	CH_DBG(cmac->adapter, INTR, "PM3393 intr cause 0x%x\n",
267d39a76e7Sxw 	       master_intr_status);
268d39a76e7Sxw 
269d39a76e7Sxw 	/* Handle BLOCK's interrupts. */
270d39a76e7Sxw 
271d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_PL4IO_INT & master_intr_status) {
272d39a76e7Sxw 		/* EMPTY */
273d39a76e7Sxw 	}
274d39a76e7Sxw 
275d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_IRAM_INT & master_intr_status) {
276d39a76e7Sxw 		/* EMPTY */
277d39a76e7Sxw 	}
278d39a76e7Sxw 
279d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_ERAM_INT & master_intr_status) {
280d39a76e7Sxw 		/* EMPTY */
281d39a76e7Sxw 	}
282d39a76e7Sxw 
283d39a76e7Sxw 	/* SERDES */
284d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_XAUI_INT & master_intr_status) {
285d39a76e7Sxw 		/* EMPTY */
286d39a76e7Sxw 	}
287d39a76e7Sxw 
288d39a76e7Sxw 	/* MSTAT */
289d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_MSTAT_INT & master_intr_status) {
290d39a76e7Sxw 		/* EMPTY */
291d39a76e7Sxw 	}
292d39a76e7Sxw 
293d39a76e7Sxw 	/* RXXG */
294d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_RXXG_INT & master_intr_status) {
295d39a76e7Sxw 		/* EMPTY */
296d39a76e7Sxw 	}
297d39a76e7Sxw 
298d39a76e7Sxw 	/* TXXG */
299d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_TXXG_INT & master_intr_status) {
300d39a76e7Sxw 		/* EMPTY */
301d39a76e7Sxw 	}
302d39a76e7Sxw 
303d39a76e7Sxw 	/* XRF */
304d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_XRF_INT & master_intr_status) {
305d39a76e7Sxw 		/* EMPTY */
306d39a76e7Sxw 	}
307d39a76e7Sxw 
308d39a76e7Sxw 	/* XTEF */
309d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_XTEF_INT & master_intr_status) {
310d39a76e7Sxw 		/* EMPTY */
311d39a76e7Sxw 	}
312d39a76e7Sxw 
313d39a76e7Sxw 	/* MDIO */
314d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_MDIO_BUSY_INT & master_intr_status) {
315d39a76e7Sxw 		/* Not used. 8000 uses MDIO through Elmer. */
316d39a76e7Sxw 		/* EMPTY */
317d39a76e7Sxw 	}
318d39a76e7Sxw 
319d39a76e7Sxw 	/* RXOAM */
320d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_RXOAM_INT & master_intr_status) {
321d39a76e7Sxw 		/* EMPTY */
322d39a76e7Sxw 	}
323d39a76e7Sxw 
324d39a76e7Sxw 	/* TXOAM */
325d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_TXOAM_INT & master_intr_status) {
326d39a76e7Sxw 		/* EMPTY */
327d39a76e7Sxw 	}
328d39a76e7Sxw 
329d39a76e7Sxw 	/* IFLX */
330d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_IFLX_INT & master_intr_status) {
331d39a76e7Sxw 		/* EMPTY */
332d39a76e7Sxw 	}
333d39a76e7Sxw 
334d39a76e7Sxw 	/* EFLX */
335d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_EFLX_INT & master_intr_status) {
336d39a76e7Sxw 		/* EMPTY */
337d39a76e7Sxw 	}
338d39a76e7Sxw 
339d39a76e7Sxw 	/* PL4ODP */
340d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_PL4ODP_INT & master_intr_status) {
341d39a76e7Sxw 		/* EMPTY */
342d39a76e7Sxw 	}
343d39a76e7Sxw 
344d39a76e7Sxw 	/* PL4IDU */
345d39a76e7Sxw 	if (SUNI1x10GEXP_BITMSK_TOP_PL4IDU_INT & master_intr_status) {
346d39a76e7Sxw 		/* EMPTY */
347d39a76e7Sxw 	}
348d39a76e7Sxw 
349d39a76e7Sxw 	/* TBD XXX Lets just clear everything for now */
350d39a76e7Sxw 	(void) pm3393_interrupt_clear(cmac);
351d39a76e7Sxw 
352d39a76e7Sxw 	return 0;
353d39a76e7Sxw }
354d39a76e7Sxw 
pm3393_enable(struct cmac * cmac,int which)355d39a76e7Sxw static int pm3393_enable(struct cmac *cmac, int which)
356d39a76e7Sxw {
357d39a76e7Sxw 	if (which & MAC_DIRECTION_RX)
358d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1,
359d39a76e7Sxw 			(RXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_RXXG_RXEN));
360d39a76e7Sxw 
361d39a76e7Sxw 	if (which & MAC_DIRECTION_TX) {
362d39a76e7Sxw 		u32 val = TXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_TXXG_TXEN0;
363d39a76e7Sxw 
364d39a76e7Sxw 		if (cmac->instance->fc & PAUSE_RX)
365d39a76e7Sxw 			val |= SUNI1x10GEXP_BITMSK_TXXG_FCRX;
366d39a76e7Sxw 		if (cmac->instance->fc & PAUSE_TX)
367d39a76e7Sxw 			val |= SUNI1x10GEXP_BITMSK_TXXG_FCTX;
368d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, val);
369d39a76e7Sxw 	}
370d39a76e7Sxw 
371d39a76e7Sxw 	cmac->instance->enabled |= which;
372d39a76e7Sxw 	return 0;
373d39a76e7Sxw }
374d39a76e7Sxw 
375d39a76e7Sxw /* ARGSUSED */
pm3393_enable_port(struct cmac * cmac,int which)376d39a76e7Sxw static int pm3393_enable_port(struct cmac *cmac, int which)
377d39a76e7Sxw {
378d39a76e7Sxw 	/* Clear port statistics */
379d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
380d39a76e7Sxw 		SUNI1x10GEXP_BITMSK_MSTAT_CLEAR);
381d39a76e7Sxw 	DELAY_US(2);
382d39a76e7Sxw 	(void) memset(&cmac->stats, 0, sizeof(struct cmac_statistics));
383d39a76e7Sxw 
384d39a76e7Sxw 	(void) pm3393_enable(cmac, which);
385d39a76e7Sxw 
386d39a76e7Sxw 	/*
387d39a76e7Sxw 	 * XXX This should be done by the PHY and preferrably not at all.
388d39a76e7Sxw 	 * The PHY doesn't give us link status indication on its own so have
389d39a76e7Sxw 	 * the link management code query it instead.
390d39a76e7Sxw 	 */
391d39a76e7Sxw 	{
392d39a76e7Sxw 		extern void link_changed(adapter_t *adapter, int port_id);
393d39a76e7Sxw 		link_changed(cmac->adapter, 0);
394d39a76e7Sxw 	}
395d39a76e7Sxw 	return 0;
396d39a76e7Sxw }
397d39a76e7Sxw 
pm3393_disable(struct cmac * cmac,int which)398d39a76e7Sxw static int pm3393_disable(struct cmac *cmac, int which)
399d39a76e7Sxw {
400d39a76e7Sxw 	if (which & MAC_DIRECTION_RX)
401d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, RXXG_CONF1_VAL);
402d39a76e7Sxw 	if (which & MAC_DIRECTION_TX)
403d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, TXXG_CONF1_VAL);
404d39a76e7Sxw 
405d39a76e7Sxw 	/*
406d39a76e7Sxw 	 * The disable is graceful. Give the PM3393 time.  Can't wait very
407d39a76e7Sxw 	 * long here, we may be holding locks.
408d39a76e7Sxw 	 */
409d39a76e7Sxw 	DELAY_US(20);
410d39a76e7Sxw 
411d39a76e7Sxw 	cmac->instance->enabled &= ~which;
412d39a76e7Sxw 	return 0;
413d39a76e7Sxw }
414d39a76e7Sxw 
415d39a76e7Sxw /* ARGSUSED */
pm3393_loopback_enable(struct cmac * cmac)416d39a76e7Sxw static int pm3393_loopback_enable(struct cmac *cmac)
417d39a76e7Sxw {
418d39a76e7Sxw 	return 0;
419d39a76e7Sxw }
420d39a76e7Sxw 
421d39a76e7Sxw /* ARGSUSED */
pm3393_loopback_disable(struct cmac * cmac)422d39a76e7Sxw static int pm3393_loopback_disable(struct cmac *cmac)
423d39a76e7Sxw {
424d39a76e7Sxw 	return 0;
425d39a76e7Sxw }
426d39a76e7Sxw 
pm3393_set_mtu(struct cmac * cmac,int mtu)427d39a76e7Sxw static int pm3393_set_mtu(struct cmac *cmac, int mtu)
428d39a76e7Sxw {
429d39a76e7Sxw 	int enabled = cmac->instance->enabled;
430d39a76e7Sxw 
431d39a76e7Sxw 	/* MAX_FRAME_SIZE includes header + FCS, mtu doesn't */
432d39a76e7Sxw 	mtu += 14 + 4;
433d39a76e7Sxw 	if (mtu > MAX_FRAME_SIZE)
434d39a76e7Sxw 		return -EINVAL;
435d39a76e7Sxw 
436d39a76e7Sxw 	/* Disable Rx/Tx MAC before configuring it. */
437d39a76e7Sxw 	if (enabled)
438d39a76e7Sxw 		(void) pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
439d39a76e7Sxw 
440d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH, mtu);
441d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE, mtu);
442d39a76e7Sxw 
443d39a76e7Sxw 	if (enabled)
444d39a76e7Sxw 		(void) pm3393_enable(cmac, enabled);
445d39a76e7Sxw 	return 0;
446d39a76e7Sxw }
447d39a76e7Sxw 
calc_crc(u8 * b,int len)448d39a76e7Sxw static u32 calc_crc(u8 *b, int len)
449d39a76e7Sxw {
450d39a76e7Sxw         int i;
451d39a76e7Sxw 	u32 crc = (u32)~0;
452d39a76e7Sxw 
453d39a76e7Sxw 	/* calculate crc one bit at a time */
454d39a76e7Sxw         while (len--) {
455d39a76e7Sxw                 crc ^= *b++;
456d39a76e7Sxw                 for (i = 0; i < 8; i++) {
457d39a76e7Sxw 			if (crc & 0x1)
458d39a76e7Sxw 				crc = (crc >> 1) ^ 0xedb88320;
459d39a76e7Sxw 			else
460d39a76e7Sxw 				crc = (crc >> 1);
461d39a76e7Sxw 		}
462d39a76e7Sxw         }
463d39a76e7Sxw 
464d39a76e7Sxw 	/* reverse bits */
465d39a76e7Sxw         crc = ((crc >> 4) & 0x0f0f0f0f) | ((crc << 4) & 0xf0f0f0f0);
466d39a76e7Sxw         crc = ((crc >> 2) & 0x33333333) | ((crc << 2) & 0xcccccccc);
467d39a76e7Sxw         crc = ((crc >> 1) & 0x55555555) | ((crc << 1) & 0xaaaaaaaa);
468d39a76e7Sxw 	/* swap bytes */
469d39a76e7Sxw         crc = (crc >> 16) | (crc << 16);
470d39a76e7Sxw         crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
471d39a76e7Sxw 
472d39a76e7Sxw         return crc;
473d39a76e7Sxw }
474d39a76e7Sxw 
pm3393_set_rx_mode(struct cmac * cmac,struct t1_rx_mode * rm)475d39a76e7Sxw static int pm3393_set_rx_mode(struct cmac *cmac, struct t1_rx_mode *rm)
476d39a76e7Sxw {
477d39a76e7Sxw 	int enabled = cmac->instance->enabled & MAC_DIRECTION_RX;
478d39a76e7Sxw 	u32 rx_mode;
479d39a76e7Sxw 
480d39a76e7Sxw 	/* Disable MAC RX before reconfiguring it */
481d39a76e7Sxw 	if (enabled)
482d39a76e7Sxw 		(void) pm3393_disable(cmac, MAC_DIRECTION_RX);
483d39a76e7Sxw 
484d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, &rx_mode);
485d39a76e7Sxw 	rx_mode &= ~(SUNI1x10GEXP_BITMSK_RXXG_PMODE | SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN);
486d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, (u16)rx_mode);
487d39a76e7Sxw 
488d39a76e7Sxw         if (t1_rx_mode_promisc(rm)) {
489d39a76e7Sxw                 /* Promiscuous mode. */
490d39a76e7Sxw 		rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_PMODE;
491d39a76e7Sxw         }
492d39a76e7Sxw 	if (t1_rx_mode_allmulti(rm)) {
493d39a76e7Sxw                 /* Accept all multicast. */
494d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, 0xffff);
495d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, 0xffff);
496d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, 0xffff);
497d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, 0xffff);
498d39a76e7Sxw 		rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN;
499d39a76e7Sxw         } else if (t1_rx_mode_mc_cnt(rm)) {
500d39a76e7Sxw                 /* Accept one or more multicast(s). */
501d39a76e7Sxw 		u8 *addr;
502d39a76e7Sxw 		int bit;
503d39a76e7Sxw 		u16 mc_filter[4] = { 0, };
504d39a76e7Sxw 
505d39a76e7Sxw 		while ((addr = t1_get_next_mcaddr(rm))) {
506d39a76e7Sxw 			bit = (calc_crc(addr, ETH_ALEN) >> 23) & 0x3f;	/* bit[23:28] */
507d39a76e7Sxw 			mc_filter[bit >> 4] |= 1 << (bit & 0xf);
508d39a76e7Sxw 		}
509d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, mc_filter[0]);
510d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, mc_filter[1]);
511d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, mc_filter[2]);
512d39a76e7Sxw 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, mc_filter[3]);
513d39a76e7Sxw 		rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN;
514d39a76e7Sxw         }
515d39a76e7Sxw 
516d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, (u16)rx_mode);
517d39a76e7Sxw 
518d39a76e7Sxw 	if (enabled)
519d39a76e7Sxw 		(void) pm3393_enable(cmac, MAC_DIRECTION_RX);
520d39a76e7Sxw 
521d39a76e7Sxw 	return 0;
522d39a76e7Sxw }
523d39a76e7Sxw 
pm3393_get_speed_duplex_fc(struct cmac * cmac,int * speed,int * duplex,int * fc)524d39a76e7Sxw static int pm3393_get_speed_duplex_fc(struct cmac *cmac, int *speed,
525d39a76e7Sxw 				      int *duplex, int *fc)
526d39a76e7Sxw {
527d39a76e7Sxw 	if (speed)
528d39a76e7Sxw 		*speed = SPEED_10000;
529d39a76e7Sxw 	if (duplex)
530d39a76e7Sxw 		*duplex = DUPLEX_FULL;
531d39a76e7Sxw 	if (fc)
532d39a76e7Sxw 		*fc = cmac->instance->fc;
533d39a76e7Sxw 	return 0;
534d39a76e7Sxw }
535d39a76e7Sxw 
pm3393_set_speed_duplex_fc(struct cmac * cmac,int speed,int duplex,int fc)536d39a76e7Sxw static int pm3393_set_speed_duplex_fc(struct cmac *cmac, int speed, int duplex,
537d39a76e7Sxw 				      int fc)
538d39a76e7Sxw {
539d39a76e7Sxw 	if (speed >= 0 && speed != SPEED_10000)
540d39a76e7Sxw 		return -1;
541d39a76e7Sxw 	if (duplex >= 0 && duplex != DUPLEX_FULL)
542d39a76e7Sxw 		return -1;
543d39a76e7Sxw 	if (fc & ~(PAUSE_TX | PAUSE_RX))
544d39a76e7Sxw 		return -1;
545d39a76e7Sxw 
546d39a76e7Sxw 	if (fc != cmac->instance->fc) {
547d39a76e7Sxw 		cmac->instance->fc = (u8) fc;
548d39a76e7Sxw 		if (cmac->instance->enabled & MAC_DIRECTION_TX)
549d39a76e7Sxw 			(void) pm3393_enable(cmac, MAC_DIRECTION_TX);
550d39a76e7Sxw 	}
551d39a76e7Sxw 	return 0;
552d39a76e7Sxw }
553d39a76e7Sxw 
554d39a76e7Sxw #define RMON_UPDATE(mac, name, stat_name) \
555d39a76e7Sxw 	{ \
556d39a76e7Sxw 		(void) t1_tpi_read((mac)->adapter, OFFSET(name), &val0);	\
557d39a76e7Sxw 		(void) t1_tpi_read((mac)->adapter, OFFSET(((name)+1)), &val1); \
558d39a76e7Sxw 		(void) t1_tpi_read((mac)->adapter, OFFSET(((name)+2)), &val2); \
559d39a76e7Sxw 		(mac)->stats.stat_name = (u16)val0  | (((u16)val1) << 16) \
560d39a76e7Sxw 						   | ((u64)((u8)val2) << 32) \
561d39a76e7Sxw 						   | ((mac)->stats.stat_name & (~(u64)0 << 40)); \
562d39a76e7Sxw 		if (ro & ((name -  SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2)) \
563d39a76e7Sxw 			(mac)->stats.stat_name += ((u64)1 << 40); \
564d39a76e7Sxw 	}
565d39a76e7Sxw 
566d39a76e7Sxw /* ARGSUSED */
pm3393_update_statistics(struct cmac * mac,int flag)567d39a76e7Sxw static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
568d39a76e7Sxw 							      int flag)
569d39a76e7Sxw {
570d39a76e7Sxw 	u64	ro;
571d39a76e7Sxw 	u32	val0, val1, val2, val3;
572d39a76e7Sxw 
573d39a76e7Sxw 	/* Snap the counters */
574d39a76e7Sxw 	(void) pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
575d39a76e7Sxw 		SUNI1x10GEXP_BITMSK_MSTAT_SNAP);
576d39a76e7Sxw 
577*2d6eb4a5SToomas Soome 	/* Counter rollover, clear on read */
578d39a76e7Sxw 	(void) pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_0, &val0);
579d39a76e7Sxw 	(void) pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_1, &val1);
580d39a76e7Sxw 	(void) pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_2, &val2);
581d39a76e7Sxw 	(void) pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_3, &val3);
582*2d6eb4a5SToomas Soome 	ro = (u16)val0 | (((u16)val1) << 16) | ((u64)((u16)val2) << 32)
583d39a76e7Sxw 	     | ((u64)((u16)val3) << 48);
584d39a76e7Sxw 
585d39a76e7Sxw 	/* Rx stats */
586d39a76e7Sxw 	RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK);
587d39a76e7Sxw 	RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK);
588d39a76e7Sxw 	RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK);
589d39a76e7Sxw 	RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK);
590d39a76e7Sxw 	RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames);
591d39a76e7Sxw 	RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors);
592d39a76e7Sxw 	RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors, RxInternalMACRcvError);
593d39a76e7Sxw 	RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
594d39a76e7Sxw 	RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors);
595d39a76e7Sxw 	RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors);
596d39a76e7Sxw 	RMON_UPDATE(mac, RxJabbers, RxJabberErrors);
597d39a76e7Sxw 	RMON_UPDATE(mac, RxFragments, RxRuntErrors);
598d39a76e7Sxw 	RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors);
599d39a76e7Sxw 
600d39a76e7Sxw 	/* Tx stats */
601d39a76e7Sxw 	RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK);
602d39a76e7Sxw 	RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError, TxInternalMACXmitError);
603d39a76e7Sxw 	RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors);
604d39a76e7Sxw 	RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK);
605d39a76e7Sxw 	RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK);
606d39a76e7Sxw 	RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK);
607d39a76e7Sxw 	RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames);
608d39a76e7Sxw 
609d39a76e7Sxw 	return &mac->stats;
610d39a76e7Sxw }
611d39a76e7Sxw 
pm3393_macaddress_get(struct cmac * cmac,u8 mac_addr[6])612d39a76e7Sxw static int pm3393_macaddress_get(struct cmac *cmac, u8 mac_addr[6])
613d39a76e7Sxw {
614d39a76e7Sxw 	memcpy(mac_addr, cmac->instance->mac_addr, 6);
615d39a76e7Sxw 	return 0;
616d39a76e7Sxw }
617d39a76e7Sxw 
pm3393_macaddress_set(struct cmac * cmac,u8 ma[6])618d39a76e7Sxw static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6])
619d39a76e7Sxw {
620d39a76e7Sxw 	u32 val, lo, mid, hi, enabled = cmac->instance->enabled;
621d39a76e7Sxw 
622d39a76e7Sxw 	/*
623d39a76e7Sxw 	 * MAC addr: 00:07:43:00:13:09
624d39a76e7Sxw 	 *
625d39a76e7Sxw 	 * ma[5] = 0x09
626d39a76e7Sxw 	 * ma[4] = 0x13
627d39a76e7Sxw 	 * ma[3] = 0x00
628d39a76e7Sxw 	 * ma[2] = 0x43
629d39a76e7Sxw 	 * ma[1] = 0x07
630d39a76e7Sxw 	 * ma[0] = 0x00
631d39a76e7Sxw 	 *
632*2d6eb4a5SToomas Soome 	 * The PM3393 requires byte swapping and reverse order entry
633d39a76e7Sxw 	 * when programming MAC addresses:
634d39a76e7Sxw 	 *
635d39a76e7Sxw 	 * low_bits[15:0]    = ma[1]:ma[0]
636d39a76e7Sxw 	 * mid_bits[31:16]   = ma[3]:ma[2]
637d39a76e7Sxw 	 * high_bits[47:32]  = ma[5]:ma[4]
638d39a76e7Sxw 	 */
639d39a76e7Sxw 
640d39a76e7Sxw 	/* Store local copy */
641d39a76e7Sxw 	memcpy(cmac->instance->mac_addr, ma, 6);
642d39a76e7Sxw 
643d39a76e7Sxw 	lo = ((u32) ma[1] << 8) | (u32) ma[0];
644d39a76e7Sxw 	mid = ((u32) ma[3] << 8) | (u32) ma[2];
645d39a76e7Sxw 	hi = ((u32) ma[5] << 8) | (u32) ma[4];
646d39a76e7Sxw 
647d39a76e7Sxw 	/* Disable Rx/Tx MAC before configuring it. */
648d39a76e7Sxw 	if (enabled)
649d39a76e7Sxw 		(void) pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
650d39a76e7Sxw 
651d39a76e7Sxw 	/* Set RXXG Station Address */
652d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_15_0, lo);
653d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_31_16, mid);
654d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_47_32, hi);
655d39a76e7Sxw 
656d39a76e7Sxw 	/* Set TXXG Station Address */
657d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_15_0, lo);
658d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_31_16, mid);
659d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_47_32, hi);
660d39a76e7Sxw 
661d39a76e7Sxw 	/* Setup Exact Match Filter 1 with our MAC address
662d39a76e7Sxw 	 *
663d39a76e7Sxw 	 * Must disable exact match filter before configuring it.
664d39a76e7Sxw 	 */
665d39a76e7Sxw 	(void) pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, &val);
666d39a76e7Sxw 	val &= 0xff0f;
667d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val);
668d39a76e7Sxw 
669d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_LOW, lo);
670d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_MID, mid);
671d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_HIGH, hi);
672d39a76e7Sxw 
673d39a76e7Sxw 	val |= 0x0090;
674d39a76e7Sxw 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val);
675d39a76e7Sxw 
676d39a76e7Sxw 	if (enabled)
677d39a76e7Sxw 		(void) pm3393_enable(cmac, enabled);
678d39a76e7Sxw 	return 0;
679d39a76e7Sxw }
680d39a76e7Sxw 
pm3393_destroy(struct cmac * cmac)681d39a76e7Sxw static void pm3393_destroy(struct cmac *cmac)
682d39a76e7Sxw {
683d39a76e7Sxw 	t1_os_free((void *)cmac, sizeof(*cmac) + sizeof(cmac_instance));
684d39a76e7Sxw }
685d39a76e7Sxw 
686d39a76e7Sxw #ifdef C99_NOT_SUPPORTED
687d39a76e7Sxw static struct cmac_ops pm3393_ops = {
688d39a76e7Sxw 	pm3393_destroy,
689d39a76e7Sxw 	pm3393_reset,
690d39a76e7Sxw 	pm3393_interrupt_enable,
691d39a76e7Sxw 	pm3393_interrupt_disable,
692d39a76e7Sxw 	pm3393_interrupt_clear,
693d39a76e7Sxw 	pm3393_interrupt_handler,
694d39a76e7Sxw 	pm3393_enable,
695d39a76e7Sxw 	pm3393_disable,
696d39a76e7Sxw 	pm3393_loopback_enable,
697d39a76e7Sxw 	pm3393_loopback_disable,
698d39a76e7Sxw 	pm3393_set_mtu,
699d39a76e7Sxw 	pm3393_set_rx_mode,
700d39a76e7Sxw 	pm3393_set_speed_duplex_fc,
701d39a76e7Sxw 	pm3393_get_speed_duplex_fc,
702d39a76e7Sxw 	pm3393_update_statistics,
703d39a76e7Sxw 	pm3393_macaddress_get,
704d39a76e7Sxw 	pm3393_macaddress_set
705d39a76e7Sxw };
706d39a76e7Sxw #else
707d39a76e7Sxw static struct cmac_ops pm3393_ops = {
708d39a76e7Sxw 	.destroy                 = pm3393_destroy,
709d39a76e7Sxw 	.reset                   = pm3393_reset,
710d39a76e7Sxw 	.interrupt_enable        = pm3393_interrupt_enable,
711d39a76e7Sxw 	.interrupt_disable       = pm3393_interrupt_disable,
712d39a76e7Sxw 	.interrupt_clear         = pm3393_interrupt_clear,
713d39a76e7Sxw 	.interrupt_handler       = pm3393_interrupt_handler,
714d39a76e7Sxw 	.enable                  = pm3393_enable_port,
715d39a76e7Sxw 	.disable                 = pm3393_disable,
716d39a76e7Sxw 	.loopback_enable         = pm3393_loopback_enable,
717d39a76e7Sxw 	.loopback_disable        = pm3393_loopback_disable,
718d39a76e7Sxw 	.set_mtu                 = pm3393_set_mtu,
719d39a76e7Sxw 	.set_rx_mode             = pm3393_set_rx_mode,
720d39a76e7Sxw 	.get_speed_duplex_fc     = pm3393_get_speed_duplex_fc,
721d39a76e7Sxw 	.set_speed_duplex_fc     = pm3393_set_speed_duplex_fc,
722d39a76e7Sxw 	.statistics_update       = pm3393_update_statistics,
723d39a76e7Sxw 	.macaddress_get          = pm3393_macaddress_get,
724d39a76e7Sxw 	.macaddress_set          = pm3393_macaddress_set
725d39a76e7Sxw };
726d39a76e7Sxw #endif
727d39a76e7Sxw 
728d39a76e7Sxw /* ARGSUSED */
pm3393_mac_create(adapter_t * adapter,int index)729d39a76e7Sxw static struct cmac *pm3393_mac_create(adapter_t *adapter, int index)
730d39a76e7Sxw {
731d39a76e7Sxw 	struct cmac *cmac;
732d39a76e7Sxw 
733d39a76e7Sxw 	cmac = t1_os_malloc_wait_zero(sizeof(*cmac) + sizeof(cmac_instance));
734d39a76e7Sxw 	if (!cmac)
735d39a76e7Sxw 		return NULL;
736d39a76e7Sxw 
737d39a76e7Sxw 	cmac->ops = &pm3393_ops;
738d39a76e7Sxw 	cmac->instance = (cmac_instance *) (cmac + 1);
739d39a76e7Sxw 	cmac->adapter = adapter;
740d39a76e7Sxw 	cmac->instance->fc = PAUSE_TX | PAUSE_RX;
741d39a76e7Sxw 
742d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x0001), 0x00008000);
743d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x0001), 0x00000000);
744d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2308), 0x00009800);
745d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2305), 0x00001001);   /* PL4IO Enable */
746d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2320), 0x00008800);
747d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2321), 0x00008800);
748d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2322), 0x00008800);
749d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2323), 0x00008800);
750d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2324), 0x00008800);
751d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2325), 0x00008800);
752d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2326), 0x00008800);
753d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2327), 0x00008800);
754d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2328), 0x00008800);
755d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2329), 0x00008800);
756d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x232a), 0x00008800);
757d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x232b), 0x00008800);
758d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x232c), 0x00008800);
759d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x232d), 0x00008800);
760d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x232e), 0x00008800);
761d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x232f), 0x00008800);
762d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x230d), 0x00009c00);
763d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2304), 0x00000202);	/* PL4IO Calendar Repetitions */
764d39a76e7Sxw 
765d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3200), 0x00008080);	/* EFLX Enable */
766d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3210), 0x00000000);	/* EFLX Channel Deprovision */
767d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3203), 0x00000000);	/* EFLX Low Limit */
768d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3204), 0x00000040);	/* EFLX High Limit */
769d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3205), 0x000002cc);	/* EFLX Almost Full */
770d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3206), 0x00000199);	/* EFLX Almost Empty */
771d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3207), 0x00000240);	/* EFLX Cut Through Threshold */
772d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3202), 0x00000000);	/* EFLX Indirect Register Update */
773d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3210), 0x00000001);	/* EFLX Channel Provision */
774d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3208), 0x0000ffff);	/* EFLX Undocumented */
775d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x320a), 0x0000ffff);	/* EFLX Undocumented */
776d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x320c), 0x0000ffff);	/* EFLX enable overflow interrupt The other bit are undocumented */
777d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x320e), 0x0000ffff);	/* EFLX Undocumented */
778d39a76e7Sxw 
779d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2200), 0x0000c000);	/* IFLX Configuration - enable */
780d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2201), 0x00000000);	/* IFLX Channel Deprovision */
781d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x220e), 0x00000000);	/* IFLX Low Limit */
782d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x220f), 0x00000100);	/* IFLX High Limit */
783d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2210), 0x00000c00);	/* IFLX Almost Full Limit */
784d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2211), 0x00000599);	/* IFLX Almost Empty Limit */
785d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x220d), 0x00000000);	/* IFLX Indirect Register Update */
786d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2201), 0x00000001);	/* IFLX Channel Provision */
787d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2203), 0x0000ffff);	/* IFLX Undocumented */
788d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2205), 0x0000ffff);	/* IFLX Undocumented */
789d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2209), 0x0000ffff);	/* IFLX Enable overflow interrupt.  The other bit are undocumented */
790d39a76e7Sxw 
791d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2241), 0xfffffffe);	/* PL4MOS Undocumented */
792d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2242), 0x0000ffff);	/* PL4MOS Undocumented */
793d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2243), 0x00000008);	/* PL4MOS Starving Burst Size */
794d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2244), 0x00000008);	/* PL4MOS Hungry Burst Size */
795d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2245), 0x00000008);	/* PL4MOS Transfer Size */
796d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2240), 0x00000005);	/* PL4MOS Disable */
797d39a76e7Sxw 
798d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2280), 0x00002103);	/* PL4ODP Training Repeat and SOP rule */
799d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2284), 0x00000000);	/* PL4ODP MAX_T setting */
800d39a76e7Sxw 
801d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3280), 0x00000087);	/* PL4IDU Enable data forward, port state machine. Set ALLOW_NON_ZERO_OLB */
802d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3282), 0x0000001f);	/* PL4IDU Enable Dip4 check error interrupts */
803d39a76e7Sxw 
804d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x3040), 0x0c32);	/* # TXXG Config */
805d39a76e7Sxw 	/* For T1 use timer based Mac flow control. */
806d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x304d), 0x8000);
807d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2040), 0x059c);	/* # RXXG Config */
808d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2049), 0x0001);	/* # RXXG Cut Through */
809d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x2070), 0x0000);	/* # Disable promiscuous mode */
810d39a76e7Sxw 
811d39a76e7Sxw 	/* Setup Exact Match Filter 0 to allow broadcast packets.
812d39a76e7Sxw 	 */
813d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x206e), 0x0000);	/* # Disable Match Enable bit */
814d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x204a), 0xffff);	/* # low addr */
815d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x204b), 0xffff);	/* # mid addr */
816d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x204c), 0xffff);	/* # high addr */
817d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x206e), 0x0009);	/* # Enable Match Enable bit */
818d39a76e7Sxw 
819d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x0003), 0x0000);	/* # NO SOP/ PAD_EN setup */
820d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x0100), 0x0ff0);	/* # RXEQB disabled */
821d39a76e7Sxw 	(void) t1_tpi_write(adapter, OFFSET(0x0101), 0x0f0f);	/* # No Preemphasis */
822d39a76e7Sxw 
823d39a76e7Sxw 	return cmac;
824d39a76e7Sxw }
825d39a76e7Sxw 
pm3393_mac_reset(adapter_t * adapter)826d39a76e7Sxw static int pm3393_mac_reset(adapter_t * adapter)
827d39a76e7Sxw {
828d39a76e7Sxw 	u32 val;
829d39a76e7Sxw 	u32 x;
830d39a76e7Sxw 	u32 is_pl4_reset_finished;
831d39a76e7Sxw 	u32 is_pl4_outof_lock;
832d39a76e7Sxw 	u32 is_xaui_mabc_pll_locked;
833d39a76e7Sxw 	u32 successful_reset;
834d39a76e7Sxw 	int i;
835d39a76e7Sxw 
836d39a76e7Sxw 	/* The following steps are required to properly reset
837d39a76e7Sxw 	 * the PM3393. This information is provided in the
838d39a76e7Sxw 	 * PM3393 datasheet (Issue 2: November 2002)
839d39a76e7Sxw 	 * section 13.1 -- Device Reset.
840d39a76e7Sxw 	 *
841d39a76e7Sxw 	 * The PM3393 has three types of components that are
842d39a76e7Sxw 	 * individually reset:
843d39a76e7Sxw 	 *
844d39a76e7Sxw 	 * DRESETB      - Digital circuitry
845d39a76e7Sxw 	 * PL4_ARESETB  - PL4 analog circuitry
846d39a76e7Sxw 	 * XAUI_ARESETB - XAUI bus analog circuitry
847d39a76e7Sxw 	 *
848d39a76e7Sxw 	 * Steps to reset PM3393 using RSTB pin:
849d39a76e7Sxw 	 *
850d39a76e7Sxw 	 * 1. Assert RSTB pin low ( write 0 )
851d39a76e7Sxw 	 * 2. Wait at least 1ms to initiate a complete initialization of device.
852d39a76e7Sxw 	 * 3. Wait until all external clocks and REFSEL are stable.
853d39a76e7Sxw 	 * 4. Wait minimum of 1ms. (after external clocks and REFEL are stable)
854d39a76e7Sxw 	 * 5. De-assert RSTB ( write 1 )
855d39a76e7Sxw 	 * 6. Wait until internal timers to expires after ~14ms.
856*2d6eb4a5SToomas Soome 	 *    - Allows analog clock synthesizer(PL4CSU) to stabilize to
857d39a76e7Sxw 	 *      selected reference frequency before allowing the digital
858d39a76e7Sxw 	 *      portion of the device to operate.
859d39a76e7Sxw 	 * 7. Wait at least 200us for XAUI interface to stabilize.
860d39a76e7Sxw 	 * 8. Verify the PM3393 came out of reset successfully.
861d39a76e7Sxw 	 *    Set successful reset flag if everything worked else try again
862d39a76e7Sxw 	 *    a few more times.
863d39a76e7Sxw 	 */
864d39a76e7Sxw 
865d39a76e7Sxw 	successful_reset = 0;
866d39a76e7Sxw 	for (i = 0; i < 3 && !successful_reset; i++) {
867d39a76e7Sxw 		/* 1 */
868d39a76e7Sxw 		(void) t1_tpi_read(adapter, A_ELMER0_GPO, &val);
869d39a76e7Sxw 		val &= ~1;
870d39a76e7Sxw 		(void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
871d39a76e7Sxw 
872d39a76e7Sxw 		/* 2 */
873d39a76e7Sxw 		DELAY_MS(1);
874d39a76e7Sxw 
875d39a76e7Sxw 		/* 3 */
876d39a76e7Sxw 		DELAY_MS(1);
877d39a76e7Sxw 
878d39a76e7Sxw 		/* 4 */
879d39a76e7Sxw 		DELAY_MS(2 /*1 extra ms for safety */ );
880d39a76e7Sxw 
881d39a76e7Sxw 		/* 5 */
882d39a76e7Sxw 		val |= 1;
883d39a76e7Sxw 		(void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
884d39a76e7Sxw 
885d39a76e7Sxw 		/* 6 */
886d39a76e7Sxw 		DELAY_MS(15 /*1 extra ms for safety */ );
887d39a76e7Sxw 
888d39a76e7Sxw 		/* 7 */
889d39a76e7Sxw 		DELAY_MS(1);
890d39a76e7Sxw 
891d39a76e7Sxw 		/* 8 */
892d39a76e7Sxw 
893d39a76e7Sxw 		/* Has PL4 analog block come out of reset correctly? */
894d39a76e7Sxw 		(void) t1_tpi_read(adapter, OFFSET(SUNI1x10GEXP_REG_DEVICE_STATUS), &val);
895d39a76e7Sxw 		is_pl4_reset_finished = (val & SUNI1x10GEXP_BITMSK_TOP_EXPIRED);
896d39a76e7Sxw 
897d39a76e7Sxw 		/* TBD XXX SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL gets locked later in the init sequence
898d39a76e7Sxw 		 *         figure out why? */
899d39a76e7Sxw 
900d39a76e7Sxw 		/* Have all PL4 block clocks locked? */
901d39a76e7Sxw 		x = (SUNI1x10GEXP_BITMSK_TOP_PL4_ID_DOOL
902d39a76e7Sxw 		     /*| SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL */  |
903d39a76e7Sxw 		     SUNI1x10GEXP_BITMSK_TOP_PL4_ID_ROOL |
904d39a76e7Sxw 		     SUNI1x10GEXP_BITMSK_TOP_PL4_IS_ROOL |
905d39a76e7Sxw 		     SUNI1x10GEXP_BITMSK_TOP_PL4_OUT_ROOL);
906d39a76e7Sxw 		is_pl4_outof_lock = (val & x);
907d39a76e7Sxw 
908d39a76e7Sxw 		/* ??? If this fails, might be able to software reset the XAUI part
909d39a76e7Sxw 		 *     and try to recover... thus saving us from doing another HW reset */
910d39a76e7Sxw 		/* Has the XAUI MABC PLL circuitry stablized? */
911d39a76e7Sxw 		is_xaui_mabc_pll_locked =
912d39a76e7Sxw 		    (val & SUNI1x10GEXP_BITMSK_TOP_SXRA_EXPIRED);
913d39a76e7Sxw 
914d39a76e7Sxw 		successful_reset = (is_pl4_reset_finished && !is_pl4_outof_lock
915d39a76e7Sxw 				    && is_xaui_mabc_pll_locked);
916d39a76e7Sxw 
917d39a76e7Sxw 		CH_DBG(adapter, HW,
918d39a76e7Sxw 		       "PM3393 HW reset %d: pl4_reset 0x%x, val 0x%x, "
919d39a76e7Sxw 		       "is_pl4_outof_lock 0x%x, xaui_locked 0x%x\n",
920d39a76e7Sxw 		       i, is_pl4_reset_finished, val, is_pl4_outof_lock,
921d39a76e7Sxw 		       is_xaui_mabc_pll_locked);
922d39a76e7Sxw 	}
923d39a76e7Sxw 	return successful_reset ? 0 : 1;
924d39a76e7Sxw }
925d39a76e7Sxw 
926d39a76e7Sxw struct gmac t1_pm3393_ops = {
927d39a76e7Sxw 	STATS_TICK_SECS,
928d39a76e7Sxw 	pm3393_mac_create,
929d39a76e7Sxw 	pm3393_mac_reset
930d39a76e7Sxw };
931