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