xref: /illumos-gate/usr/src/uts/common/io/chxge/com/ch_subr.c (revision 2d6eb4a5e0a47d30189497241345dc5466bb68ab)
1*d39a76e7Sxw161283 /*
2*d39a76e7Sxw161283  * CDDL HEADER START
3*d39a76e7Sxw161283  *
4*d39a76e7Sxw161283  * The contents of this file are subject to the terms of the
5*d39a76e7Sxw161283  * Common Development and Distribution License (the "License").
6*d39a76e7Sxw161283  * You may not use this file except in compliance with the License.
7*d39a76e7Sxw161283  *
8*d39a76e7Sxw161283  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d39a76e7Sxw161283  * or http://www.opensolaris.org/os/licensing.
10*d39a76e7Sxw161283  * See the License for the specific language governing permissions
11*d39a76e7Sxw161283  * and limitations under the License.
12*d39a76e7Sxw161283  *
13*d39a76e7Sxw161283  * When distributing Covered Code, include this CDDL HEADER in each
14*d39a76e7Sxw161283  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d39a76e7Sxw161283  * If applicable, add the following below this CDDL HEADER, with the
16*d39a76e7Sxw161283  * fields enclosed by brackets "[]" replaced with your own identifying
17*d39a76e7Sxw161283  * information: Portions Copyright [yyyy] [name of copyright owner]
18*d39a76e7Sxw161283  *
19*d39a76e7Sxw161283  * CDDL HEADER END
20*d39a76e7Sxw161283  */
21*d39a76e7Sxw161283 
22*d39a76e7Sxw161283 /*
23*d39a76e7Sxw161283  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
24*d39a76e7Sxw161283  */
25*d39a76e7Sxw161283 
26*d39a76e7Sxw161283 #include "common.h"
27*d39a76e7Sxw161283 #include "elmer0.h"
28*d39a76e7Sxw161283 #include "regs.h"
29*d39a76e7Sxw161283 
30*d39a76e7Sxw161283 #include "gmac.h"
31*d39a76e7Sxw161283 #include "cphy.h"
32*d39a76e7Sxw161283 #include "sge.h"
33*d39a76e7Sxw161283 #include "tp.h"
34*d39a76e7Sxw161283 #include "espi.h"
35*d39a76e7Sxw161283 
36*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
37*d39a76e7Sxw161283 #include "mc3.h"
38*d39a76e7Sxw161283 #include "mc4.h"
39*d39a76e7Sxw161283 #include "mc5.h"
40*d39a76e7Sxw161283 #include "ulp.h"
41*d39a76e7Sxw161283 #endif
42*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_COUGAR
43*d39a76e7Sxw161283 #include "cspi.h"
44*d39a76e7Sxw161283 #endif
45*d39a76e7Sxw161283 
46*d39a76e7Sxw161283 /*
47*d39a76e7Sxw161283  * t1_wait_op_done - wait until an operation is completed
48*d39a76e7Sxw161283  * @adapter: the adapter performing the operation
49*d39a76e7Sxw161283  * @reg: the register to check for completion
50*d39a76e7Sxw161283  * @mask: a single-bit field within @reg that indicates completion
51*d39a76e7Sxw161283  * @polarity: the value of the field when the operation is completed
52*d39a76e7Sxw161283  * @attempts: number of check iterations
53*d39a76e7Sxw161283  * @delay: delay in usecs between iterations
54*d39a76e7Sxw161283  * @attempts: number of check iterations
55*d39a76e7Sxw161283  * @delay: delay in usecs between iterations
56*d39a76e7Sxw161283  *
57*d39a76e7Sxw161283  * Wait until an operation is completed by checking a bit in a register
58*d39a76e7Sxw161283  * up to @attempts times.	Returns %0 if the operation completes and %1
59*d39a76e7Sxw161283  * otherwise.
60*d39a76e7Sxw161283  */
t1_wait_op_done(adapter_t * adapter,int reg,u32 mask,int polarity,int attempts,int delay)61*d39a76e7Sxw161283 int t1_wait_op_done(adapter_t *adapter, int reg, u32 mask, int polarity,
62*d39a76e7Sxw161283 		int attempts, int delay)
63*d39a76e7Sxw161283 {
64*d39a76e7Sxw161283 	while (attempts) {
65*d39a76e7Sxw161283 		u32 val = t1_read_reg_4(adapter, reg) & mask;
66*d39a76e7Sxw161283 		if (!!val == polarity)
67*d39a76e7Sxw161283 			return (0);
68*d39a76e7Sxw161283 		if (--attempts == 0)
69*d39a76e7Sxw161283 			return (1);
70*d39a76e7Sxw161283 		if (delay)
71*d39a76e7Sxw161283 			DELAY_US(delay);
72*d39a76e7Sxw161283 	}
73*d39a76e7Sxw161283 
74*d39a76e7Sxw161283 	return (1);
75*d39a76e7Sxw161283 }
76*d39a76e7Sxw161283 
77*d39a76e7Sxw161283 /* #define TPI_ATTEMPTS 50 */
78*d39a76e7Sxw161283 #define	TPI_ATTEMPTS 100
79*d39a76e7Sxw161283 
80*d39a76e7Sxw161283 /*
81*d39a76e7Sxw161283  * Write a register over the TPI interface (unlocked and locked versions).
82*d39a76e7Sxw161283  */
83*d39a76e7Sxw161283 int
__t1_tpi_write(adapter_t * adapter,u32 addr,u32 value)84*d39a76e7Sxw161283 __t1_tpi_write(adapter_t *adapter, u32 addr, u32 value)
85*d39a76e7Sxw161283 {
86*d39a76e7Sxw161283 	int tpi_busy;
87*d39a76e7Sxw161283 
88*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_TPI_ADDR, addr);
89*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_TPI_WR_DATA, value);
90*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_TPI_CSR, F_TPIWR);
91*d39a76e7Sxw161283 
92*d39a76e7Sxw161283 	tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1,
93*d39a76e7Sxw161283 		TPI_ATTEMPTS, 3);
94*d39a76e7Sxw161283 	if (tpi_busy)
95*d39a76e7Sxw161283 		CH_ALERT("%s: TPI write to 0x%x failed\n",
96*d39a76e7Sxw161283 			adapter_name(adapter), addr);
97*d39a76e7Sxw161283 	return (tpi_busy);
98*d39a76e7Sxw161283 }
99*d39a76e7Sxw161283 
100*d39a76e7Sxw161283 int
t1_tpi_write(adapter_t * adapter,u32 addr,u32 value)101*d39a76e7Sxw161283 t1_tpi_write(adapter_t *adapter, u32 addr, u32 value)
102*d39a76e7Sxw161283 {
103*d39a76e7Sxw161283 	int ret;
104*d39a76e7Sxw161283 
105*d39a76e7Sxw161283 	TPI_LOCK(adapter);
106*d39a76e7Sxw161283 	ret = __t1_tpi_write(adapter, addr, value);
107*d39a76e7Sxw161283 	TPI_UNLOCK(adapter);
108*d39a76e7Sxw161283 	return (ret);
109*d39a76e7Sxw161283 }
110*d39a76e7Sxw161283 
111*d39a76e7Sxw161283 /*
112*d39a76e7Sxw161283  * Read a register over the TPI interface (unlocked and locked versions).
113*d39a76e7Sxw161283  */
114*d39a76e7Sxw161283 int
__t1_tpi_read(adapter_t * adapter,u32 addr,u32 * valp)115*d39a76e7Sxw161283 __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)
116*d39a76e7Sxw161283 {
117*d39a76e7Sxw161283 	int tpi_busy;
118*d39a76e7Sxw161283 
119*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_TPI_ADDR, addr);
120*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_TPI_CSR, 0);
121*d39a76e7Sxw161283 
122*d39a76e7Sxw161283 	tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1,
123*d39a76e7Sxw161283 		TPI_ATTEMPTS, 3);
124*d39a76e7Sxw161283 
125*d39a76e7Sxw161283 	if (tpi_busy)
126*d39a76e7Sxw161283 		CH_ALERT("%s: TPI read from 0x%x failed\n",
127*d39a76e7Sxw161283 			adapter_name(adapter), addr);
128*d39a76e7Sxw161283 	else
129*d39a76e7Sxw161283 		*valp = t1_read_reg_4(adapter, A_TPI_RD_DATA);
130*d39a76e7Sxw161283 	return (tpi_busy);
131*d39a76e7Sxw161283 }
132*d39a76e7Sxw161283 
133*d39a76e7Sxw161283 int
t1_tpi_read(adapter_t * adapter,u32 addr,u32 * valp)134*d39a76e7Sxw161283 t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)
135*d39a76e7Sxw161283 {
136*d39a76e7Sxw161283 	int ret;
137*d39a76e7Sxw161283 
138*d39a76e7Sxw161283 	TPI_LOCK(adapter);
139*d39a76e7Sxw161283 	ret = __t1_tpi_read(adapter, addr, valp);
140*d39a76e7Sxw161283 	TPI_UNLOCK(adapter);
141*d39a76e7Sxw161283 	return (ret);
142*d39a76e7Sxw161283 }
143*d39a76e7Sxw161283 
144*d39a76e7Sxw161283 /*
145*d39a76e7Sxw161283  * Set a TPI parameter.
146*d39a76e7Sxw161283  */
t1_tpi_par(adapter_t * adapter,u32 value)147*d39a76e7Sxw161283 static void t1_tpi_par(adapter_t *adapter, u32 value)
148*d39a76e7Sxw161283 {
149*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_TPI_PAR, V_TPIPAR(value));
150*d39a76e7Sxw161283 }
151*d39a76e7Sxw161283 
152*d39a76e7Sxw161283 /*
153*d39a76e7Sxw161283  * Called when a port's link settings change to propagate the new values to the
154*d39a76e7Sxw161283  * associated PHY and MAC.  After performing the common tasks it invokes an
155*d39a76e7Sxw161283  * OS-specific handler.
156*d39a76e7Sxw161283  */
157*d39a76e7Sxw161283 void
link_changed(adapter_t * adapter,int port_id)158*d39a76e7Sxw161283 link_changed(adapter_t *adapter, int port_id)
159*d39a76e7Sxw161283 {
160*d39a76e7Sxw161283 	int link_ok, speed, duplex, fc;
161*d39a76e7Sxw161283 	struct cphy *phy = adapter->port[port_id].phy;
162*d39a76e7Sxw161283 	struct link_config *lc = &adapter->port[port_id].link_config;
163*d39a76e7Sxw161283 
164*d39a76e7Sxw161283 	phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
165*d39a76e7Sxw161283 
166*d39a76e7Sxw161283 	lc->speed = speed < 0 ? SPEED_INVALID : speed;
167*d39a76e7Sxw161283 	lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
168*d39a76e7Sxw161283 	if (!(lc->requested_fc & PAUSE_AUTONEG))
169*d39a76e7Sxw161283 		fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
170*d39a76e7Sxw161283 
171*d39a76e7Sxw161283 	if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
172*d39a76e7Sxw161283 		/* Set MAC speed, duplex, and flow control to match PHY. */
173*d39a76e7Sxw161283 		struct cmac *mac = adapter->port[port_id].mac;
174*d39a76e7Sxw161283 
175*d39a76e7Sxw161283 		mac->ops->set_speed_duplex_fc(mac, speed, duplex, fc);
176*d39a76e7Sxw161283 		lc->fc = (unsigned char)fc;
177*d39a76e7Sxw161283 	}
178*d39a76e7Sxw161283 	t1_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
179*d39a76e7Sxw161283 }
180*d39a76e7Sxw161283 
t1_pci_intr_handler(adapter_t * adapter)181*d39a76e7Sxw161283 static int t1_pci_intr_handler(adapter_t *adapter)
182*d39a76e7Sxw161283 {
183*d39a76e7Sxw161283 	u32 pcix_cause;
184*d39a76e7Sxw161283 
185*d39a76e7Sxw161283 	(void) t1_os_pci_read_config_4(adapter, A_PCICFG_INTR_CAUSE,
186*d39a76e7Sxw161283 		&pcix_cause);
187*d39a76e7Sxw161283 
188*d39a76e7Sxw161283 	if (pcix_cause) {
189*d39a76e7Sxw161283 		(void) t1_os_pci_write_config_4(adapter, A_PCICFG_INTR_CAUSE,
190*d39a76e7Sxw161283 			pcix_cause);
191*d39a76e7Sxw161283 		t1_fatal_err(adapter);    /* PCI errors are fatal */
192*d39a76e7Sxw161283 	}
193*d39a76e7Sxw161283 	return (0);
194*d39a76e7Sxw161283 }
195*d39a76e7Sxw161283 
196*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
197*d39a76e7Sxw161283 #include "fpga_defs.h"
198*d39a76e7Sxw161283 
199*d39a76e7Sxw161283 /*
200*d39a76e7Sxw161283  * PHY interrupt handler for FPGA boards.
201*d39a76e7Sxw161283  */
fpga_phy_intr_handler(adapter_t * adapter)202*d39a76e7Sxw161283 static int fpga_phy_intr_handler(adapter_t *adapter)
203*d39a76e7Sxw161283 {
204*d39a76e7Sxw161283 	int p;
205*d39a76e7Sxw161283 	u32 cause = t1_read_reg_4(adapter, FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
206*d39a76e7Sxw161283 
207*d39a76e7Sxw161283 	for_each_port(adapter, p)
208*d39a76e7Sxw161283 		if (cause & (1 << p)) {
209*d39a76e7Sxw161283 			struct cphy *phy = adapter->port[p].phy;
210*d39a76e7Sxw161283 			int phy_cause = phy->ops->interrupt_handler(phy);
211*d39a76e7Sxw161283 
212*d39a76e7Sxw161283 			if (phy_cause & cphy_cause_link_change)
213*d39a76e7Sxw161283 				link_changed(adapter, p);
214*d39a76e7Sxw161283 		}
215*d39a76e7Sxw161283 	t1_write_reg_4(adapter, FPGA_GMAC_ADDR_INTERRUPT_CAUSE, cause);
216*d39a76e7Sxw161283 	return (0);
217*d39a76e7Sxw161283 }
218*d39a76e7Sxw161283 
219*d39a76e7Sxw161283 /*
220*d39a76e7Sxw161283  * Slow path interrupt handler for FPGAs.
221*d39a76e7Sxw161283  */
fpga_slow_intr(adapter_t * adapter)222*d39a76e7Sxw161283 static int fpga_slow_intr(adapter_t *adapter)
223*d39a76e7Sxw161283 {
224*d39a76e7Sxw161283 	u32 cause = t1_read_reg_4(adapter, A_PL_CAUSE);
225*d39a76e7Sxw161283 
226*d39a76e7Sxw161283 	cause &= ~F_PL_INTR_SGE_DATA;
227*d39a76e7Sxw161283 	if (cause & F_PL_INTR_SGE_ERR)
228*d39a76e7Sxw161283 		(void) t1_sge_intr_error_handler(adapter->sge);
229*d39a76e7Sxw161283 
230*d39a76e7Sxw161283 	if (cause & FPGA_PCIX_INTERRUPT_GMAC)
231*d39a76e7Sxw161283 		(void) fpga_phy_intr_handler(adapter);
232*d39a76e7Sxw161283 
233*d39a76e7Sxw161283 	if (cause & FPGA_PCIX_INTERRUPT_TP) {
234*d39a76e7Sxw161283 		/*
235*d39a76e7Sxw161283 		 * FPGA doesn't support MC4 interrupts and it requires
236*d39a76e7Sxw161283 		 * this odd layer of indirection for MC5.
237*d39a76e7Sxw161283 		 */
238*d39a76e7Sxw161283 		u32 tp_cause = t1_read_reg_4(adapter,
239*d39a76e7Sxw161283 			FPGA_TP_ADDR_INTERRUPT_CAUSE);
240*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
241*d39a76e7Sxw161283 		if (tp_cause & FPGA_TP_INTERRUPT_MC5)
242*d39a76e7Sxw161283 			t1_mc5_intr_handler(adapter->mc5);
243*d39a76e7Sxw161283 #endif
244*d39a76e7Sxw161283 		/* Clear TP interrupt */
245*d39a76e7Sxw161283 		t1_write_reg_4(adapter, FPGA_TP_ADDR_INTERRUPT_CAUSE,
246*d39a76e7Sxw161283 			tp_cause);
247*d39a76e7Sxw161283 	}
248*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
249*d39a76e7Sxw161283 	if (cause & FPGA_PCIX_INTERRUPT_MC3)
250*d39a76e7Sxw161283 		(void) t1_mc3_intr_handler(adapter->mc3);
251*d39a76e7Sxw161283 #endif
252*d39a76e7Sxw161283 	if (cause & FPGA_PCIX_INTERRUPT_PCIX)
253*d39a76e7Sxw161283 		(void) t1_pci_intr_handler(adapter);
254*d39a76e7Sxw161283 
255*d39a76e7Sxw161283 	/* Clear the interrupts just processed. */
256*d39a76e7Sxw161283 	if (cause)
257*d39a76e7Sxw161283 		t1_write_reg_4(adapter, A_PL_CAUSE, cause);
258*d39a76e7Sxw161283 
259*d39a76e7Sxw161283 	return (cause != 0);
260*d39a76e7Sxw161283 }
261*d39a76e7Sxw161283 
262*d39a76e7Sxw161283 /*
263*d39a76e7Sxw161283  * FPGA MDIO initialization.
264*d39a76e7Sxw161283  */
fpga_mdio_init(adapter_t * adapter,const struct board_info * bi)265*d39a76e7Sxw161283 static void fpga_mdio_init(adapter_t *adapter, const struct board_info *bi)
266*d39a76e7Sxw161283 {
267*d39a76e7Sxw161283 	(void) bi;	/* avoid warnings */
268*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MI0_CLK, V_MI0_CLK_DIV(3));
269*d39a76e7Sxw161283 }
270*d39a76e7Sxw161283 
271*d39a76e7Sxw161283 /*
272*d39a76e7Sxw161283  * FPGA MDIO read/write operations.
273*d39a76e7Sxw161283  */
fpga_mdio_read(adapter_t * adapter,int phy_addr,int mmd_addr,int reg_addr,unsigned int * val)274*d39a76e7Sxw161283 static int fpga_mdio_read(adapter_t *adapter, int phy_addr, int mmd_addr,
275*d39a76e7Sxw161283 	int reg_addr, unsigned int *val)
276*d39a76e7Sxw161283 {
277*d39a76e7Sxw161283 	if (mmd_addr)
278*d39a76e7Sxw161283 		return (-EINVAL);
279*d39a76e7Sxw161283 
280*d39a76e7Sxw161283 	/* Check if MDI is busy; this shouldn't happen. */
281*d39a76e7Sxw161283 	if (t1_read_reg_4(adapter, A_MI0_CSR) & F_MI0_BUSY) {
282*d39a76e7Sxw161283 		CH_ALERT("%s: MDIO busy at start of read\n",
283*d39a76e7Sxw161283 			adapter_name(adapter));
284*d39a76e7Sxw161283 		return (-EBUSY);
285*d39a76e7Sxw161283 	}
286*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MI0_ADDR,
287*d39a76e7Sxw161283 		V_MI0_PHY_REG_ADDR(reg_addr) | V_MI0_PHY_ADDR(phy_addr));
288*d39a76e7Sxw161283 	*val = t1_read_reg_4(adapter, A_MI0_DATA_EXT);
289*d39a76e7Sxw161283 
290*d39a76e7Sxw161283 	return (0);
291*d39a76e7Sxw161283 }
292*d39a76e7Sxw161283 
fpga_mdio_write(adapter_t * adapter,int phy_addr,int mmd_addr,int reg_addr,unsigned int val)293*d39a76e7Sxw161283 static int fpga_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr,
294*d39a76e7Sxw161283 	int reg_addr, unsigned int val)
295*d39a76e7Sxw161283 {
296*d39a76e7Sxw161283 	if (mmd_addr)
297*d39a76e7Sxw161283 		return (-EINVAL);
298*d39a76e7Sxw161283 
299*d39a76e7Sxw161283 	/* Check if MDI is busy; this shouldn't happen. */
300*d39a76e7Sxw161283 	if (t1_read_reg_4(adapter, A_MI0_CSR) & F_MI0_BUSY) {
301*d39a76e7Sxw161283 		CH_ALERT("%s: MDIO busy at start of write\n",
302*d39a76e7Sxw161283 			adapter_name(adapter));
303*d39a76e7Sxw161283 		return (-EBUSY);
304*d39a76e7Sxw161283 	}
305*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MI0_ADDR,
306*d39a76e7Sxw161283 		V_MI0_PHY_REG_ADDR(reg_addr) | V_MI0_PHY_ADDR(phy_addr));
307*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MI0_DATA_EXT, val);
308*d39a76e7Sxw161283 	return (0);
309*d39a76e7Sxw161283 }
310*d39a76e7Sxw161283 
311*d39a76e7Sxw161283 static struct mdio_ops fpga_mdio_ops = {
312*d39a76e7Sxw161283 	fpga_mdio_init,
313*d39a76e7Sxw161283 	fpga_mdio_read,
314*d39a76e7Sxw161283 	fpga_mdio_write
315*d39a76e7Sxw161283 };
316*d39a76e7Sxw161283 #endif
317*d39a76e7Sxw161283 
318*d39a76e7Sxw161283 /*
319*d39a76e7Sxw161283  * Wait until Elmer's MI1 interface is ready for new operations.
320*d39a76e7Sxw161283  */
mi1_wait_until_ready(adapter_t * adapter,int mi1_reg)321*d39a76e7Sxw161283 static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg)
322*d39a76e7Sxw161283 {
323*d39a76e7Sxw161283 	int attempts = 100, busy;
324*d39a76e7Sxw161283 
325*d39a76e7Sxw161283 	do {
326*d39a76e7Sxw161283 		u32 val;
327*d39a76e7Sxw161283 
328*d39a76e7Sxw161283 		(void) __t1_tpi_read(adapter, mi1_reg, &val);
329*d39a76e7Sxw161283 		busy = val & F_MI1_OP_BUSY;
330*d39a76e7Sxw161283 		if (busy)
331*d39a76e7Sxw161283 			DELAY_US(10);
332*d39a76e7Sxw161283 	} while (busy && --attempts);
333*d39a76e7Sxw161283 	if (busy)
334*d39a76e7Sxw161283 		CH_ALERT("%s: MDIO operation timed out\n",
335*d39a76e7Sxw161283 			adapter_name(adapter));
336*d39a76e7Sxw161283 	return (busy);
337*d39a76e7Sxw161283 }
338*d39a76e7Sxw161283 
339*d39a76e7Sxw161283 /*
340*d39a76e7Sxw161283  * MI1 MDIO initialization.
341*d39a76e7Sxw161283  */
mi1_mdio_init(adapter_t * adapter,const struct board_info * bi)342*d39a76e7Sxw161283 static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi)
343*d39a76e7Sxw161283 {
344*d39a76e7Sxw161283 	u32 clkdiv = bi->clock_elmer0 / (2 * bi->mdio_mdc) - 1;
345*d39a76e7Sxw161283 	u32 val = F_MI1_PREAMBLE_ENABLE | V_MI1_MDI_INVERT(bi->mdio_mdiinv) |
346*d39a76e7Sxw161283 		V_MI1_MDI_ENABLE(bi->mdio_mdien) | V_MI1_CLK_DIV(clkdiv);
347*d39a76e7Sxw161283 
348*d39a76e7Sxw161283 	if (!(bi->caps & SUPPORTED_10000baseT_Full))
349*d39a76e7Sxw161283 		val |= V_MI1_SOF(1);
350*d39a76e7Sxw161283 	(void) t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val);
351*d39a76e7Sxw161283 }
352*d39a76e7Sxw161283 
353*d39a76e7Sxw161283 #if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
354*d39a76e7Sxw161283 /*
355*d39a76e7Sxw161283  * Elmer MI1 MDIO read/write operations.
356*d39a76e7Sxw161283  */
mi1_mdio_read(adapter_t * adapter,int phy_addr,int mmd_addr,int reg_addr,unsigned int * valp)357*d39a76e7Sxw161283 static int mi1_mdio_read(adapter_t *adapter, int phy_addr, int mmd_addr,
358*d39a76e7Sxw161283 	int reg_addr, unsigned int *valp)
359*d39a76e7Sxw161283 {
360*d39a76e7Sxw161283 	u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr);
361*d39a76e7Sxw161283 
362*d39a76e7Sxw161283 	if (mmd_addr)
363*d39a76e7Sxw161283 		return (-EINVAL);
364*d39a76e7Sxw161283 
365*d39a76e7Sxw161283 	TPI_LOCK(adapter);
366*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
367*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,
368*d39a76e7Sxw161283 		MI1_OP_DIRECT_READ);
369*d39a76e7Sxw161283 	(void) mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
370*d39a76e7Sxw161283 	(void) __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp);
371*d39a76e7Sxw161283 	TPI_UNLOCK(adapter);
372*d39a76e7Sxw161283 	return (0);
373*d39a76e7Sxw161283 }
374*d39a76e7Sxw161283 
mi1_mdio_write(adapter_t * adapter,int phy_addr,int mmd_addr,int reg_addr,unsigned int val)375*d39a76e7Sxw161283 static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr,
376*d39a76e7Sxw161283 	int reg_addr, unsigned int val)
377*d39a76e7Sxw161283 {
378*d39a76e7Sxw161283 	u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr);
379*d39a76e7Sxw161283 
380*d39a76e7Sxw161283 	if (mmd_addr)
381*d39a76e7Sxw161283 		return (-EINVAL);
382*d39a76e7Sxw161283 
383*d39a76e7Sxw161283 	TPI_LOCK(adapter);
384*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
385*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val);
386*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,
387*d39a76e7Sxw161283 		MI1_OP_DIRECT_WRITE);
388*d39a76e7Sxw161283 	(void) mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
389*d39a76e7Sxw161283 	TPI_UNLOCK(adapter);
390*d39a76e7Sxw161283 	return (0);
391*d39a76e7Sxw161283 }
392*d39a76e7Sxw161283 
393*d39a76e7Sxw161283 #if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
394*d39a76e7Sxw161283 static struct mdio_ops mi1_mdio_ops = {
395*d39a76e7Sxw161283 	mi1_mdio_init,
396*d39a76e7Sxw161283 	mi1_mdio_read,
397*d39a76e7Sxw161283 	mi1_mdio_write
398*d39a76e7Sxw161283 };
399*d39a76e7Sxw161283 #endif
400*d39a76e7Sxw161283 
401*d39a76e7Sxw161283 #endif
402*d39a76e7Sxw161283 
403*d39a76e7Sxw161283 #if 0
404*d39a76e7Sxw161283 static int mi1_mdio_ext_readinc(adapter_t *adapter, int phy_addr, int mmd_addr,
405*d39a76e7Sxw161283 				int reg_addr, unsigned int *valp)
406*d39a76e7Sxw161283 {
407*d39a76e7Sxw161283 	u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);
408*d39a76e7Sxw161283 
409*d39a76e7Sxw161283 	TPI_LOCK(adapter);
410*d39a76e7Sxw161283 
411*d39a76e7Sxw161283 	/* Write the address we want. */
412*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
413*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr);
414*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,
415*d39a76e7Sxw161283 		MI1_OP_INDIRECT_ADDRESS);
416*d39a76e7Sxw161283 	(void) mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
417*d39a76e7Sxw161283 
418*d39a76e7Sxw161283 	/* Write the operation we want. */
419*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,
420*d39a76e7Sxw161283 		MI1_OP_INDIRECT_READ_INC);
421*d39a76e7Sxw161283 	(void) mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
422*d39a76e7Sxw161283 
423*d39a76e7Sxw161283 	/* Read the data. */
424*d39a76e7Sxw161283 	(void) __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp);
425*d39a76e7Sxw161283 	TPI_UNLOCK(adapter);
426*d39a76e7Sxw161283 	return (0);
427*d39a76e7Sxw161283 }
428*d39a76e7Sxw161283 #endif
429*d39a76e7Sxw161283 
mi1_mdio_ext_read(adapter_t * adapter,int phy_addr,int mmd_addr,int reg_addr,unsigned int * valp)430*d39a76e7Sxw161283 static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr,
431*d39a76e7Sxw161283 	int reg_addr, unsigned int *valp)
432*d39a76e7Sxw161283 {
433*d39a76e7Sxw161283 	u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);
434*d39a76e7Sxw161283 
435*d39a76e7Sxw161283 	TPI_LOCK(adapter);
436*d39a76e7Sxw161283 
437*d39a76e7Sxw161283 	/* Write the address we want. */
438*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
439*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr);
440*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,
441*d39a76e7Sxw161283 		MI1_OP_INDIRECT_ADDRESS);
442*d39a76e7Sxw161283 	(void) mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
443*d39a76e7Sxw161283 
444*d39a76e7Sxw161283 	/* Write the operation we want. */
445*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,
446*d39a76e7Sxw161283 		MI1_OP_INDIRECT_READ);
447*d39a76e7Sxw161283 	(void) mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
448*d39a76e7Sxw161283 
449*d39a76e7Sxw161283 	/* Read the data. */
450*d39a76e7Sxw161283 	(void) __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp);
451*d39a76e7Sxw161283 	TPI_UNLOCK(adapter);
452*d39a76e7Sxw161283 	return (0);
453*d39a76e7Sxw161283 }
454*d39a76e7Sxw161283 
mi1_mdio_ext_write(adapter_t * adapter,int phy_addr,int mmd_addr,int reg_addr,unsigned int val)455*d39a76e7Sxw161283 static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr,
456*d39a76e7Sxw161283 	int reg_addr, unsigned int val)
457*d39a76e7Sxw161283 {
458*d39a76e7Sxw161283 	u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);
459*d39a76e7Sxw161283 
460*d39a76e7Sxw161283 	TPI_LOCK(adapter);
461*d39a76e7Sxw161283 
462*d39a76e7Sxw161283 	/* Write the address we want. */
463*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
464*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr);
465*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,
466*d39a76e7Sxw161283 		MI1_OP_INDIRECT_ADDRESS);
467*d39a76e7Sxw161283 	(void) mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
468*d39a76e7Sxw161283 
469*d39a76e7Sxw161283 	/* Write the data. */
470*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val);
471*d39a76e7Sxw161283 	(void) __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,
472*d39a76e7Sxw161283 		MI1_OP_INDIRECT_WRITE);
473*d39a76e7Sxw161283 	(void) mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
474*d39a76e7Sxw161283 	TPI_UNLOCK(adapter);
475*d39a76e7Sxw161283 	return (0);
476*d39a76e7Sxw161283 }
477*d39a76e7Sxw161283 
478*d39a76e7Sxw161283 static struct mdio_ops mi1_mdio_ext_ops = {
479*d39a76e7Sxw161283 	mi1_mdio_init,
480*d39a76e7Sxw161283 	mi1_mdio_ext_read,
481*d39a76e7Sxw161283 	mi1_mdio_ext_write
482*d39a76e7Sxw161283 };
483*d39a76e7Sxw161283 
484*d39a76e7Sxw161283 enum {
485*d39a76e7Sxw161283 	CH_BRD_T110_1CU,
486*d39a76e7Sxw161283 	CH_BRD_N110_1F,
487*d39a76e7Sxw161283 	CH_BRD_N210_1F,
488*d39a76e7Sxw161283 	CH_BRD_T210_1F,
489*d39a76e7Sxw161283 	CH_BRD_T210_1CU,
490*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
491*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
492*d39a76e7Sxw161283 	CH_BRD_T204_4CU,
493*d39a76e7Sxw161283 	CH_BRD_T204V_4CU,
494*d39a76e7Sxw161283 	CH_BRD_6800_4CU,
495*d39a76e7Sxw161283 	CH_BRD_7500_4CU,
496*d39a76e7Sxw161283 	CH_BRD_7500_4F,
497*d39a76e7Sxw161283 	CH_BRD_T101_1CU_LB,
498*d39a76e7Sxw161283 	CH_BRD_T101_1F_LB,
499*d39a76e7Sxw161283 #endif
500*d39a76e7Sxw161283 	CH_BRD_8000_1F,
501*d39a76e7Sxw161283 	CH_BRD_T110_1F,
502*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_COUGAR
503*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
504*d39a76e7Sxw161283 	CH_BRD_COUGAR_4CU,
505*d39a76e7Sxw161283 #endif
506*d39a76e7Sxw161283 	CH_BRD_COUGAR_1F,
507*d39a76e7Sxw161283 #endif
508*d39a76e7Sxw161283 #ifdef CONFIG_USERMODE
509*d39a76e7Sxw161283 	CH_BRD_SIMUL,
510*d39a76e7Sxw161283 #endif
511*d39a76e7Sxw161283 #endif
512*d39a76e7Sxw161283 };
513*d39a76e7Sxw161283 
514*d39a76e7Sxw161283 static struct board_info t1_board[] = {
515*d39a76e7Sxw161283 
516*d39a76e7Sxw161283 { CHBT_BOARD_CHT110, 1/*ports#*/,
517*d39a76e7Sxw161283   SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T1,
518*d39a76e7Sxw161283   CHBT_MAC_PM3393, CHBT_PHY_MY3126,
519*d39a76e7Sxw161283   125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/,
520*d39a76e7Sxw161283   1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
521*d39a76e7Sxw161283   1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
522*d39a76e7Sxw161283   &t1_my3126_ops, &mi1_mdio_ext_ops,
523*d39a76e7Sxw161283   "Chelsio T110 1x10GBase-CX4 TOE" },
524*d39a76e7Sxw161283 
525*d39a76e7Sxw161283 { CHBT_BOARD_N110, 1/*ports#*/,
526*d39a76e7Sxw161283   SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
527*d39a76e7Sxw161283   CHBT_MAC_PM3393, CHBT_PHY_88X2010,
528*d39a76e7Sxw161283   125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
529*d39a76e7Sxw161283   1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
530*d39a76e7Sxw161283   0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
531*d39a76e7Sxw161283   &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
532*d39a76e7Sxw161283   "Chelsio N110 1x10GBaseX NIC" },
533*d39a76e7Sxw161283 
534*d39a76e7Sxw161283 { CHBT_BOARD_N210, 1/*ports#*/,
535*d39a76e7Sxw161283   SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T2,
536*d39a76e7Sxw161283   CHBT_MAC_PM3393, CHBT_PHY_88X2010,
537*d39a76e7Sxw161283   125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
538*d39a76e7Sxw161283   1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
539*d39a76e7Sxw161283   0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
540*d39a76e7Sxw161283   &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
541*d39a76e7Sxw161283   "Chelsio N210 1x10GBaseX NIC" },
542*d39a76e7Sxw161283 
543*d39a76e7Sxw161283 { CHBT_BOARD_CHT210, 1/*ports#*/,
544*d39a76e7Sxw161283   SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
545*d39a76e7Sxw161283   CHBT_MAC_PM3393, CHBT_PHY_88X2010,
546*d39a76e7Sxw161283   125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
547*d39a76e7Sxw161283   1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
548*d39a76e7Sxw161283   0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
549*d39a76e7Sxw161283   &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
550*d39a76e7Sxw161283   "Chelsio T210 1x10GBaseX TOE" },
551*d39a76e7Sxw161283 
552*d39a76e7Sxw161283 { CHBT_BOARD_CHT210, 1/*ports#*/,
553*d39a76e7Sxw161283   SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
554*d39a76e7Sxw161283   CHBT_MAC_PM3393, CHBT_PHY_MY3126,
555*d39a76e7Sxw161283   125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
556*d39a76e7Sxw161283   1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
557*d39a76e7Sxw161283   1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
558*d39a76e7Sxw161283   &t1_my3126_ops, &mi1_mdio_ext_ops,
559*d39a76e7Sxw161283   "Chelsio T210 1x10GBase-CX4 TOE" },
560*d39a76e7Sxw161283 
561*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
562*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
563*d39a76e7Sxw161283 { CHBT_BOARD_CHT204, 4/*ports#*/,
564*d39a76e7Sxw161283   SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
565*d39a76e7Sxw161283   SUPPORTED_PAUSE | SUPPORTED_TP /*caps*/, CHBT_TERM_T2, CHBT_MAC_IXF1010, CHBT_PHY_88E1111,
566*d39a76e7Sxw161283   100000000/*clk-core*/, 133000000/*clk-mc3*/, 100000000/*clk-mc4*/,
567*d39a76e7Sxw161283   4/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
568*d39a76e7Sxw161283   0/*mdiinv*/, 1/*mdc*/, 4/*phybaseaddr*/, &t1_ixf1010_ops,
569*d39a76e7Sxw161283   &t1_mv88e1xxx_ops, &mi1_mdio_ops,
570*d39a76e7Sxw161283   "Chelsio T204 4x100/1000BaseT TOE" },
571*d39a76e7Sxw161283 { CHBT_BOARD_CHT204V, 4/*ports#*/,
572*d39a76e7Sxw161283   SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half |
573*d39a76e7Sxw161283   SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
574*d39a76e7Sxw161283   SUPPORTED_PAUSE | SUPPORTED_TP /*caps*/, CHBT_TERM_T2, CHBT_MAC_VSC7321, CHBT_PHY_88E1111,
575*d39a76e7Sxw161283   100000000/*clk-core*/, 133000000/*clk-mc3*/, 100000000/*clk-mc4*/,
576*d39a76e7Sxw161283   4/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
577*d39a76e7Sxw161283   0/*mdiinv*/, 1/*mdc*/, 4/*phybaseaddr*/, &t1_vsc7326_ops,
578*d39a76e7Sxw161283   &t1_mv88e1xxx_ops, &mi1_mdio_ops,
579*d39a76e7Sxw161283   "Chelsio T204V 4x100/1000BaseT TOE" },
580*d39a76e7Sxw161283 
581*d39a76e7Sxw161283 { CHBT_BOARD_6800, 1/*ports#*/,
582*d39a76e7Sxw161283   SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half |
583*d39a76e7Sxw161283   SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half |
584*d39a76e7Sxw161283   SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP /*caps*/,
585*d39a76e7Sxw161283   CHBT_TERM_FPGA, CHBT_MAC_CHELSIO_A, CHBT_PHY_88E1041,
586*d39a76e7Sxw161283   16000000/*clk-core*/, 16000000/*clk-mc3*/, 16000000/*clk-mc4*/,
587*d39a76e7Sxw161283   0/*espi-ports*/, 0/*clk-cspi*/, 0/*clk-elmer0*/, 0/*mdien*/,
588*d39a76e7Sxw161283   0/*mdiinv*/, 4/*mdc*/, 0/*phybaseaddr*/, &t1_chelsio_mac_ops, &t1_mv88e1xxx_ops, &fpga_mdio_ops,
589*d39a76e7Sxw161283   "Chelsio FPGA 4x10/100/1000BaseT TOE" },
590*d39a76e7Sxw161283 
591*d39a76e7Sxw161283 { CHBT_BOARD_7500, 4/*ports#*/,
592*d39a76e7Sxw161283   SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
593*d39a76e7Sxw161283   SUPPORTED_TP /*caps*/, CHBT_TERM_T1, CHBT_MAC_IXF1010, CHBT_PHY_88E1041,
594*d39a76e7Sxw161283   87500000/*clk-core*/, 87500000/*clk-mc3*/, 87500000/*clk-mc4*/,
595*d39a76e7Sxw161283   4/*espi-ports*/, 0/*clk-cspi*/, 40/*clk-elmer0*/, 0/*mdien*/,
596*d39a76e7Sxw161283   0/*mdiinv*/, 4/*mdc*/, 0/*phybaseaddr*/, &t1_ixf1010_ops,
597*d39a76e7Sxw161283   &t1_mv88e1xxx_ops, &mi1_mdio_ops,
598*d39a76e7Sxw161283   "Chelsio 7500 4x100/1000BaseT TOE" },
599*d39a76e7Sxw161283 
600*d39a76e7Sxw161283 { CHBT_BOARD_7500, 4/*ports#*/,
601*d39a76e7Sxw161283   SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE /*caps*/,
602*d39a76e7Sxw161283   CHBT_TERM_T1, CHBT_MAC_IXF1010, CHBT_PHY_88E1041,
603*d39a76e7Sxw161283   87500000/*clk-core*/, 87500000/*clk-mc3*/, 87500000/*clk-mc4*/,
604*d39a76e7Sxw161283   4/*espi-ports*/, 0/*clk-cspi*/, 40/*clk-elmer0*/, 0/*mdien*/,
605*d39a76e7Sxw161283   0/*mdiinv*/, 4/*mdc*/, 0/*phybaseaddr*/, &t1_ixf1010_ops,
606*d39a76e7Sxw161283   &t1_mv88e1xxx_ops, &mi1_mdio_ops,
607*d39a76e7Sxw161283   "Chelsio 7500 4x1000BaseX TOE" },
608*d39a76e7Sxw161283 
609*d39a76e7Sxw161283 { CHBT_BOARD_CHT101, 1/*ports#*/,
610*d39a76e7Sxw161283   SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
611*d39a76e7Sxw161283   SUPPORTED_TP | SUPPORTED_PAUSE | SUPPORTED_LOOPBACK /*caps*/, CHBT_TERM_T1, CHBT_MAC_IXF1010, CHBT_PHY_88E1111,
612*d39a76e7Sxw161283   83300000/*clk-core*/, 83300000/*clk-mc3*/, 83300000/*clk-mc4*/,
613*d39a76e7Sxw161283   2/*espi-ports*/, 0/*clk-cspi*/, 40/*clk-elmer0*/, 0/*mdien*/,
614*d39a76e7Sxw161283   0/*mdiinv*/, 4/*mdc*/, 4/*phybaseaddr*/, &t1_ixf1010_ops,
615*d39a76e7Sxw161283   &t1_mv88e1xxx_ops, &mi1_mdio_ops,
616*d39a76e7Sxw161283   "Chelsio T101 1x100/1000BaseT TOE" },
617*d39a76e7Sxw161283 
618*d39a76e7Sxw161283 { CHBT_BOARD_CHT101, 1/*ports#*/,
619*d39a76e7Sxw161283   SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE | SUPPORTED_PAUSE | SUPPORTED_LOOPBACK /*caps*/,
620*d39a76e7Sxw161283   CHBT_TERM_T1, CHBT_MAC_IXF1010, CHBT_PHY_88E1111,
621*d39a76e7Sxw161283   83300000/*clk-core*/, 83300000/*clk-mc3*/, 83300000/*clk-mc4*/,
622*d39a76e7Sxw161283   2/*espi-ports*/, 0/*clk-cspi*/, 40/*clk-elmer0*/, 0/*mdien*/,
623*d39a76e7Sxw161283   0/*mdiinv*/, 4/*mdc*/, 4/*phybaseaddr*/, &t1_ixf1010_ops,
624*d39a76e7Sxw161283   &t1_mv88e1xxx_ops, &mi1_mdio_ops,
625*d39a76e7Sxw161283   "Chelsio T101 1x1000BaseX TOE" },
626*d39a76e7Sxw161283 #endif
627*d39a76e7Sxw161283 
628*d39a76e7Sxw161283 { CHBT_BOARD_8000, 1/*ports#*/,
629*d39a76e7Sxw161283   SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
630*d39a76e7Sxw161283   CHBT_MAC_PM3393, CHBT_PHY_XPAK,
631*d39a76e7Sxw161283   125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/,
632*d39a76e7Sxw161283   1/*espi-ports*/, 0/*clk-cspi*/, 40/*clk-elmer0*/, 1/*mdien*/,
633*d39a76e7Sxw161283   1/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
634*d39a76e7Sxw161283   &t1_xpak_ops, &mi1_mdio_ext_ops,
635*d39a76e7Sxw161283   "Chelsio 8000 1x10GBaseX TOE" },
636*d39a76e7Sxw161283 
637*d39a76e7Sxw161283 { CHBT_BOARD_CHT110, 1/*ports#*/,
638*d39a76e7Sxw161283   SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
639*d39a76e7Sxw161283   CHBT_MAC_PM3393, CHBT_PHY_XPAK,
640*d39a76e7Sxw161283   125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/,
641*d39a76e7Sxw161283   1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
642*d39a76e7Sxw161283   1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
643*d39a76e7Sxw161283   &t1_xpak_ops, &mi1_mdio_ext_ops,
644*d39a76e7Sxw161283   "Chelsio T110 1x10GBaseX TOE" },
645*d39a76e7Sxw161283 
646*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_COUGAR
647*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
648*d39a76e7Sxw161283 { CHBT_BOARD_COUGAR, 4/*ports#*/,
649*d39a76e7Sxw161283   SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half |
650*d39a76e7Sxw161283   SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half |
651*d39a76e7Sxw161283   SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP /*caps*/,
652*d39a76e7Sxw161283   CHBT_TERM_T1, CHBT_MAC_VSC7321, CHBT_PHY_88E1041,
653*d39a76e7Sxw161283   87500000/*clk-core*/, 87500000/*clk-mc3*/, 87500000/*clk-mc4*/,
654*d39a76e7Sxw161283   4/*espi-ports*/, 333300000/*clk-cspi*/, 40/*clk-elmer0*/, 0/*mdien*/,
655*d39a76e7Sxw161283   0/*mdiinv*/, 4/*mdc*/, 0/*phybaseaddr*/, &t1_vsc7321_ops,
656*d39a76e7Sxw161283   &t1_mv88e1xxx_ops, &mi1_mdio_ops,
657*d39a76e7Sxw161283   "Chelsio Cougar 4x100/1000BaseT TOE" },
658*d39a76e7Sxw161283 #endif
659*d39a76e7Sxw161283 
660*d39a76e7Sxw161283 { CHBT_BOARD_COUGAR, 1/*ports#*/,
661*d39a76e7Sxw161283   SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
662*d39a76e7Sxw161283   CHBT_MAC_VSC7321, CHBT_PHY_XPAK,
663*d39a76e7Sxw161283   87500000/*clk-core*/, 87500000/*clk-mc3*/, 87500000/*clk-mc4*/,
664*d39a76e7Sxw161283   1/*espi-ports*/, 333300000/*clk-cspi*/, 40/*clk-elmer0*/, 1/*mdien*/,
665*d39a76e7Sxw161283   1/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_vsc7321_ops,
666*d39a76e7Sxw161283   &t1_xpak_ops, &mi1_mdio_ext_ops,
667*d39a76e7Sxw161283   "Chelsio Cougar 1x10GBaseX TOE" },
668*d39a76e7Sxw161283 #endif
669*d39a76e7Sxw161283 
670*d39a76e7Sxw161283 #ifdef CONFIG_USERMODE
671*d39a76e7Sxw161283 { CHBT_BOARD_SIMUL, 1/*ports#*/,
672*d39a76e7Sxw161283   0/*caps*/, CHBT_TERM_T1, CHBT_MAC_DUMMY, CHBT_PHY_DUMMY,
673*d39a76e7Sxw161283   125000000/*clk-core*/, 125000000/*clk-mc3*/, 125000000/*clk-mc4*/,
674*d39a76e7Sxw161283   1/*espi-ports*/, 0/*clk-cspi*/, 0/*clk-elmer0*/, 0/*mdien*/,
675*d39a76e7Sxw161283   0/*mdiinv*/, 0/*mdc*/, 0/*phybaseaddr*/, &t1_dummy_mac_ops,
676*d39a76e7Sxw161283   &t1_dummy_phy_ops, NULL, "Chelsio simulation environment TOE" },
677*d39a76e7Sxw161283 #endif
678*d39a76e7Sxw161283 #endif
679*d39a76e7Sxw161283 };
680*d39a76e7Sxw161283 
681*d39a76e7Sxw161283 struct pci_device_id t1_pci_tbl[] = {
682*d39a76e7Sxw161283 	CH_DEVICE(8, 0, CH_BRD_T110_1CU),
683*d39a76e7Sxw161283 	CH_DEVICE(8, 1, CH_BRD_T110_1CU),
684*d39a76e7Sxw161283 	CH_DEVICE(7, 0, CH_BRD_N110_1F),
685*d39a76e7Sxw161283 	CH_DEVICE(10, 1, CH_BRD_N210_1F),
686*d39a76e7Sxw161283 	CH_DEVICE(11, 1, CH_BRD_T210_1F),
687*d39a76e7Sxw161283 	CH_DEVICE(14, 1, CH_BRD_T210_1CU),
688*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
689*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
690*d39a76e7Sxw161283 	CH_DEVICE(12, 1, CH_BRD_T204_4CU),
691*d39a76e7Sxw161283 	CH_DEVICE(13, 1, CH_BRD_T204V_4CU),
692*d39a76e7Sxw161283 	CH_DEVICE(1, 0, CH_BRD_6800_4CU),
693*d39a76e7Sxw161283 	CH_DEVICE(2, 1, CH_BRD_7500_4CU),
694*d39a76e7Sxw161283 	CH_DEVICE(2, 3, CH_BRD_7500_4F),
695*d39a76e7Sxw161283 	CH_DEVICE(4, 0, CH_BRD_T101_1CU_LB),
696*d39a76e7Sxw161283 	CH_DEVICE(4, 2, CH_BRD_T101_1F_LB),
697*d39a76e7Sxw161283 #endif
698*d39a76e7Sxw161283 	CH_DEVICE(3, 0, CH_BRD_8000_1F),
699*d39a76e7Sxw161283 	CH_DEVICE(3, 1, CH_BRD_8000_1F),
700*d39a76e7Sxw161283 	CH_DEVICE(6, 0, CH_BRD_T110_1F),
701*d39a76e7Sxw161283 	CH_DEVICE(6, 1, CH_BRD_T110_1F),
702*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_COUGAR
703*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
704*d39a76e7Sxw161283 	CH_DEVICE(5, 0, CH_BRD_COUGAR_4CU),
705*d39a76e7Sxw161283 #endif
706*d39a76e7Sxw161283 	CH_DEVICE(5, 1, CH_BRD_COUGAR_1F),
707*d39a76e7Sxw161283 #endif
708*d39a76e7Sxw161283 #ifdef CONFIG_USERMODE
709*d39a76e7Sxw161283 	CH_DEVICE(0x5000, PCI_ANY_ID, CH_BRD_SIMUL),
710*d39a76e7Sxw161283 #endif
711*d39a76e7Sxw161283 #endif
712*d39a76e7Sxw161283         { 0, }
713*d39a76e7Sxw161283 };
714*d39a76e7Sxw161283 
715*d39a76e7Sxw161283 #ifndef CH_DEVICE_COMMON
716*d39a76e7Sxw161283 /*
717*d39a76e7Sxw161283  * Return the board_info structure with a given index.  Out-of-range indices
718*d39a76e7Sxw161283  * return NULL.
719*d39a76e7Sxw161283  */
720*d39a76e7Sxw161283 const struct board_info *
t1_get_board_info(unsigned int board_id)721*d39a76e7Sxw161283 t1_get_board_info(unsigned int board_id)
722*d39a76e7Sxw161283 {
723*d39a76e7Sxw161283 	return (board_id < DIMOF(t1_board) ? &t1_board[board_id] : NULL);
724*d39a76e7Sxw161283 }
725*d39a76e7Sxw161283 #else
726*d39a76e7Sxw161283 /*
727*d39a76e7Sxw161283  * Return the board_info structure that corresponds to a given PCI devid/ssid
728*d39a76e7Sxw161283  * pair.  Return NULL if the id combination is unknown.
729*d39a76e7Sxw161283  */
t1_get_board_info_from_ids(unsigned int devid,unsigned short ssid)730*d39a76e7Sxw161283 const struct board_info *t1_get_board_info_from_ids(unsigned int devid,
731*d39a76e7Sxw161283 						    unsigned short ssid)
732*d39a76e7Sxw161283 {
733*d39a76e7Sxw161283 	struct pci_device_id *p;
734*d39a76e7Sxw161283 
735*d39a76e7Sxw161283 	for (p = t1_pci_tbl; p->devid; ++p)
736*d39a76e7Sxw161283 		if (p->devid == devid && p->ssid == ssid)
737*d39a76e7Sxw161283 			return (&t1_board[p->board_info_index]);
738*d39a76e7Sxw161283 	return (NULL);
739*d39a76e7Sxw161283 }
740*d39a76e7Sxw161283 #endif
741*d39a76e7Sxw161283 
742*d39a76e7Sxw161283 typedef struct {
743*d39a76e7Sxw161283 	u32 format_version;
744*d39a76e7Sxw161283 	u8 serial_number[16];
745*d39a76e7Sxw161283 	u8 mac_base_address[6];
746*d39a76e7Sxw161283 	u8 pad[2];	/* make multiple-of-4 size requirement explicit */
747*d39a76e7Sxw161283 } chelsio_vpd_t;
748*d39a76e7Sxw161283 
749*d39a76e7Sxw161283 #define	EEPROMSIZE	(8 * 1024)
750*d39a76e7Sxw161283 #define	EEPROM_MAX_POLL	4
751*d39a76e7Sxw161283 
752*d39a76e7Sxw161283 /*
753*d39a76e7Sxw161283  * Read SEEPROM. A zero is written to the flag register when the addres is
754*d39a76e7Sxw161283  * written to the Control register. The hardware device will set the flag to a
755*d39a76e7Sxw161283  * one when 4B have been transferred to the Data register.
756*d39a76e7Sxw161283  */
757*d39a76e7Sxw161283 int
t1_seeprom_read(adapter_t * adapter,u32 addr,u32 * data)758*d39a76e7Sxw161283 t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data)
759*d39a76e7Sxw161283 {
760*d39a76e7Sxw161283 	int i = EEPROM_MAX_POLL;
761*d39a76e7Sxw161283 	u16 val;
762*d39a76e7Sxw161283 
763*d39a76e7Sxw161283 	if (addr >= EEPROMSIZE || (addr & 3))
764*d39a76e7Sxw161283 	return (-EINVAL);
765*d39a76e7Sxw161283 
766*d39a76e7Sxw161283 	(void) t1_os_pci_write_config_2(adapter, A_PCICFG_VPD_ADDR, (u16)addr);
767*d39a76e7Sxw161283 	do {
768*d39a76e7Sxw161283 		DELAY_US(50);
769*d39a76e7Sxw161283 		(void) t1_os_pci_read_config_2(adapter,
770*d39a76e7Sxw161283 			A_PCICFG_VPD_ADDR, &val);
771*d39a76e7Sxw161283 	} while (!(val & F_VPD_OP_FLAG) && --i);
772*d39a76e7Sxw161283 
773*d39a76e7Sxw161283 	if (!(val & F_VPD_OP_FLAG)) {
774*d39a76e7Sxw161283 		CH_ERR("%s: reading EEPROM address 0x%x failed\n",
775*d39a76e7Sxw161283 			adapter_name(adapter), addr);
776*d39a76e7Sxw161283 		return (-EIO);
777*d39a76e7Sxw161283 	}
778*d39a76e7Sxw161283 	(void) t1_os_pci_read_config_4(adapter, A_PCICFG_VPD_DATA, data);
779*d39a76e7Sxw161283 	*data = le32_to_cpu(*data);
780*d39a76e7Sxw161283 	return (0);
781*d39a76e7Sxw161283 }
782*d39a76e7Sxw161283 
t1_eeprom_vpd_get(adapter_t * adapter,chelsio_vpd_t * vpd)783*d39a76e7Sxw161283 static int t1_eeprom_vpd_get(adapter_t *adapter, chelsio_vpd_t *vpd)
784*d39a76e7Sxw161283 {
785*d39a76e7Sxw161283 	int addr, ret = 0;
786*d39a76e7Sxw161283 
787*d39a76e7Sxw161283 	for (addr = 0; !ret && addr < sizeof (*vpd); addr += sizeof (u32))
788*d39a76e7Sxw161283 		ret = t1_seeprom_read(adapter, addr,
789*d39a76e7Sxw161283 			(u32 *)((u8 *)vpd + addr));
790*d39a76e7Sxw161283 
791*d39a76e7Sxw161283 	return (ret);
792*d39a76e7Sxw161283 }
793*d39a76e7Sxw161283 
794*d39a76e7Sxw161283 /*
795*d39a76e7Sxw161283  * Read a port's MAC address from the VPD ROM.
796*d39a76e7Sxw161283  */
vpd_macaddress_get(adapter_t * adapter,int index,u8 mac_addr[])797*d39a76e7Sxw161283 static int vpd_macaddress_get(adapter_t *adapter, int index, u8 mac_addr[])
798*d39a76e7Sxw161283 {
799*d39a76e7Sxw161283 	chelsio_vpd_t vpd;
800*d39a76e7Sxw161283 
801*d39a76e7Sxw161283 	if (t1_eeprom_vpd_get(adapter, &vpd))
802*d39a76e7Sxw161283 	return (1);
803*d39a76e7Sxw161283 	memcpy(mac_addr, vpd.mac_base_address, 5);
804*d39a76e7Sxw161283 	mac_addr[5] = vpd.mac_base_address[5] + index;
805*d39a76e7Sxw161283 	return (0);
806*d39a76e7Sxw161283 }
807*d39a76e7Sxw161283 
808*d39a76e7Sxw161283 /*
809*d39a76e7Sxw161283  * Set up the MAC/PHY according to the requested link settings.
810*d39a76e7Sxw161283  *
811*d39a76e7Sxw161283  * If the PHY can auto-negotiate first decide what to advertise, then
812*d39a76e7Sxw161283  * enable/disable auto-negotiation as desired and reset.
813*d39a76e7Sxw161283  *
814*d39a76e7Sxw161283  * If the PHY does not auto-negotiate we just reset it.
815*d39a76e7Sxw161283  *
816*d39a76e7Sxw161283  * If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
817*d39a76e7Sxw161283  * otherwise do it later based on the outcome of auto-negotiation.
818*d39a76e7Sxw161283  */
819*d39a76e7Sxw161283 int
t1_link_start(struct cphy * phy,struct cmac * mac,struct link_config * lc)820*d39a76e7Sxw161283 t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
821*d39a76e7Sxw161283 {
822*d39a76e7Sxw161283 	unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
823*d39a76e7Sxw161283 
824*d39a76e7Sxw161283 	if (lc->supported & SUPPORTED_Autoneg) {
825*d39a76e7Sxw161283 		lc->advertising &= ~(ADVERTISED_ASYM_PAUSE | ADVERTISED_PAUSE);
826*d39a76e7Sxw161283 		if (fc) {
827*d39a76e7Sxw161283 			if (fc == ((PAUSE_RX | PAUSE_TX) & !is_T2(mac->adapter)))
828*d39a76e7Sxw161283 				lc->advertising |= ADVERTISED_PAUSE;
829*d39a76e7Sxw161283 			else {
830*d39a76e7Sxw161283 				lc->advertising |= ADVERTISED_ASYM_PAUSE;
831*d39a76e7Sxw161283 				if (fc == PAUSE_RX)
832*d39a76e7Sxw161283 					lc->advertising |= ADVERTISED_PAUSE;
833*d39a76e7Sxw161283 			}
834*d39a76e7Sxw161283 		}
835*d39a76e7Sxw161283 		phy->ops->advertise(phy, lc->advertising);
836*d39a76e7Sxw161283 
837*d39a76e7Sxw161283 		if (lc->autoneg == AUTONEG_DISABLE) {
838*d39a76e7Sxw161283 			lc->speed = lc->requested_speed;
839*d39a76e7Sxw161283 			lc->duplex = lc->requested_duplex;
840*d39a76e7Sxw161283 			lc->fc = (unsigned char)fc;
841*d39a76e7Sxw161283 			mac->ops->set_speed_duplex_fc(mac, lc->speed,
842*d39a76e7Sxw161283 						      lc->duplex, fc);
843*d39a76e7Sxw161283 			/* Also disables autoneg */
844*d39a76e7Sxw161283 			phy->state = PHY_AUTONEG_RDY;
845*d39a76e7Sxw161283 			phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
846*d39a76e7Sxw161283 			phy->ops->reset(phy, 0);
847*d39a76e7Sxw161283 		} else {
848*d39a76e7Sxw161283 			phy->state = PHY_AUTONEG_EN;
849*d39a76e7Sxw161283 			phy->ops->autoneg_enable(phy); /* also resets PHY */
850*d39a76e7Sxw161283 		}
851*d39a76e7Sxw161283 	} else {
852*d39a76e7Sxw161283 		phy->state = PHY_AUTONEG_RDY;
853*d39a76e7Sxw161283 		mac->ops->set_speed_duplex_fc(mac, -1, -1, fc);
854*d39a76e7Sxw161283 		lc->fc = (unsigned char)fc;
855*d39a76e7Sxw161283 		phy->ops->reset(phy, 0);
856*d39a76e7Sxw161283 	}
857*d39a76e7Sxw161283 	return 0;
858*d39a76e7Sxw161283 }
859*d39a76e7Sxw161283 
860*d39a76e7Sxw161283 /*
861*d39a76e7Sxw161283  * External interrupt handler for boards using elmer0.
862*d39a76e7Sxw161283  */
863*d39a76e7Sxw161283 int
elmer0_ext_intr_handler(adapter_t * adapter)864*d39a76e7Sxw161283 elmer0_ext_intr_handler(adapter_t *adapter)
865*d39a76e7Sxw161283 {
866*d39a76e7Sxw161283 	struct cphy *phy;
867*d39a76e7Sxw161283 	int phy_cause;
868*d39a76e7Sxw161283 	u32 cause;
869*d39a76e7Sxw161283 
870*d39a76e7Sxw161283 	(void) t1_tpi_read(adapter, A_ELMER0_INT_CAUSE, &cause);
871*d39a76e7Sxw161283 
872*d39a76e7Sxw161283 	switch (board_info(adapter)->board) {
873*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
874*d39a76e7Sxw161283         case CHBT_BOARD_CHT204:
875*d39a76e7Sxw161283         case CHBT_BOARD_CHT204V: {
876*d39a76e7Sxw161283                 int i, port_bit;
877*d39a76e7Sxw161283 		for_each_port(adapter, i) {
878*d39a76e7Sxw161283 			port_bit = i ? i + 1 : 0;
879*d39a76e7Sxw161283 			if (!(cause & (1 << port_bit))) continue;
880*d39a76e7Sxw161283 
881*d39a76e7Sxw161283 			phy = adapter->port[i].phy;
882*d39a76e7Sxw161283 			phy_cause = phy->ops->interrupt_handler(phy);
883*d39a76e7Sxw161283 			if (phy_cause & cphy_cause_link_change)
884*d39a76e7Sxw161283 				link_changed(adapter, i);
885*d39a76e7Sxw161283 		}
886*d39a76e7Sxw161283 		break;
887*d39a76e7Sxw161283 	}
888*d39a76e7Sxw161283 	case CHBT_BOARD_CHT101:
889*d39a76e7Sxw161283 		if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */
890*d39a76e7Sxw161283 			phy = adapter->port[0].phy;
891*d39a76e7Sxw161283 			phy_cause = phy->ops->interrupt_handler(phy);
892*d39a76e7Sxw161283 			if (phy_cause & cphy_cause_link_change)
893*d39a76e7Sxw161283 				link_changed(adapter, 0);
894*d39a76e7Sxw161283 		}
895*d39a76e7Sxw161283 		break;
896*d39a76e7Sxw161283 	case CHBT_BOARD_7500: {
897*d39a76e7Sxw161283 		int p;
898*d39a76e7Sxw161283 		/*
899*d39a76e7Sxw161283 		 * Elmer0's interrupt cause isn't useful here because there is
900*d39a76e7Sxw161283 		 * only one bit that can be set for all 4 ports.  This means
901*d39a76e7Sxw161283 		 * we are forced to check every PHY's interrupt status
902*d39a76e7Sxw161283 		 * register to see who initiated the interrupt.
903*d39a76e7Sxw161283 		 */
904*d39a76e7Sxw161283 		for_each_port(adapter, p) {
905*d39a76e7Sxw161283 			phy = adapter->port[p].phy;
906*d39a76e7Sxw161283 			phy_cause = phy->ops->interrupt_handler(phy);
907*d39a76e7Sxw161283 			if (phy_cause & cphy_cause_link_change)
908*d39a76e7Sxw161283 			    link_changed(adapter, p);
909*d39a76e7Sxw161283 		}
910*d39a76e7Sxw161283 		break;
911*d39a76e7Sxw161283 	}
912*d39a76e7Sxw161283 #endif
913*d39a76e7Sxw161283 	case CHBT_BOARD_CHT210:
914*d39a76e7Sxw161283 	case CHBT_BOARD_N210:
915*d39a76e7Sxw161283 	case CHBT_BOARD_N110:
916*d39a76e7Sxw161283 		if (cause & ELMER0_GP_BIT6) { /* Marvell 88x2010 interrupt */
917*d39a76e7Sxw161283 			phy = adapter->port[0].phy;
918*d39a76e7Sxw161283 			phy_cause = phy->ops->interrupt_handler(phy);
919*d39a76e7Sxw161283 			if (phy_cause & cphy_cause_link_change)
920*d39a76e7Sxw161283 				link_changed(adapter, 0);
921*d39a76e7Sxw161283 		}
922*d39a76e7Sxw161283 		break;
923*d39a76e7Sxw161283 	case CHBT_BOARD_8000:
924*d39a76e7Sxw161283 	case CHBT_BOARD_CHT110:
925*d39a76e7Sxw161283 		CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
926*d39a76e7Sxw161283 			cause);
927*d39a76e7Sxw161283 		if (cause & ELMER0_GP_BIT1) {	/* PMC3393 INTB */
928*d39a76e7Sxw161283 			struct cmac *mac = adapter->port[0].mac;
929*d39a76e7Sxw161283 
930*d39a76e7Sxw161283 			mac->ops->interrupt_handler(mac);
931*d39a76e7Sxw161283 		}
932*d39a76e7Sxw161283 		if (cause & ELMER0_GP_BIT5) {	/* XPAK MOD_DETECT */
933*d39a76e7Sxw161283 			u32 mod_detect;
934*d39a76e7Sxw161283 
935*d39a76e7Sxw161283 			(void) t1_tpi_read(adapter, A_ELMER0_GPI_STAT,
936*d39a76e7Sxw161283 				&mod_detect);
937*d39a76e7Sxw161283 			CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
938*d39a76e7Sxw161283 				mod_detect ? "removed" : "inserted");
939*d39a76e7Sxw161283 		}
940*d39a76e7Sxw161283 		break;
941*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_COUGAR
942*d39a76e7Sxw161283 	case CHBT_BOARD_COUGAR:
943*d39a76e7Sxw161283 		if (adapter->params.nports == 1) {
944*d39a76e7Sxw161283 			if (cause & ELMER0_GP_BIT1) {	/* Vitesse MAC */
945*d39a76e7Sxw161283 				struct cmac *mac = adapter->port[0].mac;
946*d39a76e7Sxw161283 				mac->ops->interrupt_handler(mac);
947*d39a76e7Sxw161283 			}
948*d39a76e7Sxw161283 			if (cause & ELMER0_GP_BIT5) {	/* XPAK MOD_DETECT */
949*d39a76e7Sxw161283 			}
950*d39a76e7Sxw161283 		} else {
951*d39a76e7Sxw161283 			int i, port_bit;
952*d39a76e7Sxw161283 
953*d39a76e7Sxw161283 			for_each_port(adapter, i) {
954*d39a76e7Sxw161283 				port_bit = i ? i + 1 : 0;
955*d39a76e7Sxw161283 				if (!(cause & (1 << port_bit))) continue;
956*d39a76e7Sxw161283 
957*d39a76e7Sxw161283 				phy = adapter->port[i].phy;
958*d39a76e7Sxw161283 				phy_cause = phy->ops->interrupt_handler(phy);
959*d39a76e7Sxw161283 				if (phy_cause & cphy_cause_link_change)
960*d39a76e7Sxw161283 					link_changed(adapter, i);
961*d39a76e7Sxw161283 			}
962*d39a76e7Sxw161283 		}
963*d39a76e7Sxw161283 		break;
964*d39a76e7Sxw161283 #endif
965*d39a76e7Sxw161283 	}
966*d39a76e7Sxw161283 	(void) t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause);
967*d39a76e7Sxw161283 	return (0);
968*d39a76e7Sxw161283 }
969*d39a76e7Sxw161283 
970*d39a76e7Sxw161283 /* Enables all interrupts. */
971*d39a76e7Sxw161283 void
t1_interrupts_enable(adapter_t * adapter)972*d39a76e7Sxw161283 t1_interrupts_enable(adapter_t *adapter)
973*d39a76e7Sxw161283 {
974*d39a76e7Sxw161283 	unsigned int i;
975*d39a76e7Sxw161283 
976*d39a76e7Sxw161283 	adapter->slow_intr_mask = F_PL_INTR_SGE_ERR | F_PL_INTR_TP;
977*d39a76e7Sxw161283 	(void) t1_sge_intr_enable(adapter->sge);
978*d39a76e7Sxw161283 	t1_tp_intr_enable(adapter->tp);
979*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
980*d39a76e7Sxw161283 	if (adapter->mc4) {
981*d39a76e7Sxw161283 		adapter->slow_intr_mask |= F_PL_INTR_MC3 | F_PL_INTR_MC4 |
982*d39a76e7Sxw161283 			F_PL_INTR_ULP | F_PL_INTR_MC5;
983*d39a76e7Sxw161283 	/*
984*d39a76e7Sxw161283 	 * T2 -- Disable interrupts for now b/c we are not clearing
985*d39a76e7Sxw161283 	 * correctly yet.
986*d39a76e7Sxw161283 	 */
987*d39a76e7Sxw161283 		/* t1_ulp_intr_enable(adapter->ulp); */
988*d39a76e7Sxw161283 		t1_ulp_intr_disable(adapter->ulp);
989*d39a76e7Sxw161283 
990*d39a76e7Sxw161283 		t1_mc3_intr_enable(adapter->mc3);
991*d39a76e7Sxw161283 		t1_mc4_intr_enable(adapter->mc4);
992*d39a76e7Sxw161283 		t1_mc5_intr_enable(adapter->mc5);
993*d39a76e7Sxw161283 	}
994*d39a76e7Sxw161283 #endif
995*d39a76e7Sxw161283 	if (adapter->espi) {
996*d39a76e7Sxw161283 		adapter->slow_intr_mask |= F_PL_INTR_ESPI;
997*d39a76e7Sxw161283 		t1_espi_intr_enable(adapter->espi);
998*d39a76e7Sxw161283 	}
999*d39a76e7Sxw161283 
1000*d39a76e7Sxw161283 	/* Enable MAC/PHY interrupts for each port. */
1001*d39a76e7Sxw161283 	for_each_port(adapter, i) {
1002*d39a76e7Sxw161283 		adapter->port[i].mac->ops->interrupt_enable(adapter->
1003*d39a76e7Sxw161283 			port[i].mac);
1004*d39a76e7Sxw161283 		adapter->port[i].phy->ops->interrupt_enable(adapter->
1005*d39a76e7Sxw161283 			port[i].phy);
1006*d39a76e7Sxw161283 	}
1007*d39a76e7Sxw161283 
1008*d39a76e7Sxw161283 	/* Enable PCIX & external chip interrupts on ASIC boards. */
1009*d39a76e7Sxw161283 	if (t1_is_asic(adapter)) {
1010*d39a76e7Sxw161283 		u32 pl_intr = t1_read_reg_4(adapter, A_PL_ENABLE);
1011*d39a76e7Sxw161283 
1012*d39a76e7Sxw161283 		/* PCI-X interrupts */
1013*d39a76e7Sxw161283 		(void) t1_os_pci_write_config_4(adapter, A_PCICFG_INTR_ENABLE,
1014*d39a76e7Sxw161283 			0xffffffff);
1015*d39a76e7Sxw161283 
1016*d39a76e7Sxw161283 		adapter->slow_intr_mask |= F_PL_INTR_EXT | F_PL_INTR_PCIX;
1017*d39a76e7Sxw161283 		pl_intr |= F_PL_INTR_EXT | F_PL_INTR_PCIX;
1018*d39a76e7Sxw161283 		t1_write_reg_4(adapter, A_PL_ENABLE, pl_intr);
1019*d39a76e7Sxw161283 	}
1020*d39a76e7Sxw161283 }
1021*d39a76e7Sxw161283 
1022*d39a76e7Sxw161283 /* Disables all interrupts. */
1023*d39a76e7Sxw161283 void
t1_interrupts_disable(adapter_t * adapter)1024*d39a76e7Sxw161283 t1_interrupts_disable(adapter_t * adapter)
1025*d39a76e7Sxw161283 {
1026*d39a76e7Sxw161283 	unsigned int i;
1027*d39a76e7Sxw161283 
1028*d39a76e7Sxw161283 	(void) t1_sge_intr_disable(adapter->sge);
1029*d39a76e7Sxw161283 	t1_tp_intr_disable(adapter->tp);
1030*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
1031*d39a76e7Sxw161283 	if (adapter->mc4) {
1032*d39a76e7Sxw161283 		t1_ulp_intr_disable(adapter->ulp);
1033*d39a76e7Sxw161283 		t1_mc3_intr_disable(adapter->mc3);
1034*d39a76e7Sxw161283 		t1_mc4_intr_disable(adapter->mc4);
1035*d39a76e7Sxw161283 		t1_mc5_intr_disable(adapter->mc5);
1036*d39a76e7Sxw161283 	}
1037*d39a76e7Sxw161283 #endif
1038*d39a76e7Sxw161283 	if (adapter->espi)
1039*d39a76e7Sxw161283 		t1_espi_intr_disable(adapter->espi);
1040*d39a76e7Sxw161283 
1041*d39a76e7Sxw161283 	/* Disable MAC/PHY interrupts for each port. */
1042*d39a76e7Sxw161283 	for_each_port(adapter, i) {
1043*d39a76e7Sxw161283 		adapter->port[i].mac->ops->interrupt_disable(adapter->
1044*d39a76e7Sxw161283 			port[i].mac);
1045*d39a76e7Sxw161283 		adapter->port[i].phy->ops->interrupt_disable(adapter->
1046*d39a76e7Sxw161283 			port[i].phy);
1047*d39a76e7Sxw161283 	}
1048*d39a76e7Sxw161283 
1049*d39a76e7Sxw161283 	/* Disable PCIX & external chip interrupts. */
1050*d39a76e7Sxw161283 	if (t1_is_asic(adapter))
1051*d39a76e7Sxw161283 		t1_write_reg_4(adapter, A_PL_ENABLE, 0);
1052*d39a76e7Sxw161283 
1053*d39a76e7Sxw161283 	/* PCI-X interrupts */
1054*d39a76e7Sxw161283 	(void) t1_os_pci_write_config_4(adapter, A_PCICFG_INTR_ENABLE, 0);
1055*d39a76e7Sxw161283 
1056*d39a76e7Sxw161283 	adapter->slow_intr_mask = 0;
1057*d39a76e7Sxw161283 }
1058*d39a76e7Sxw161283 
1059*d39a76e7Sxw161283 /* Clears all interrupts */
1060*d39a76e7Sxw161283 void
t1_interrupts_clear(adapter_t * adapter)1061*d39a76e7Sxw161283 t1_interrupts_clear(adapter_t * adapter)
1062*d39a76e7Sxw161283 {
1063*d39a76e7Sxw161283 	unsigned int i;
1064*d39a76e7Sxw161283 
1065*d39a76e7Sxw161283 	(void) t1_sge_intr_clear(adapter->sge);
1066*d39a76e7Sxw161283 	t1_tp_intr_clear(adapter->tp);
1067*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
1068*d39a76e7Sxw161283 	if (adapter->mc4) {
1069*d39a76e7Sxw161283 		t1_ulp_intr_clear(adapter->ulp);
1070*d39a76e7Sxw161283 		t1_mc3_intr_clear(adapter->mc3);
1071*d39a76e7Sxw161283 		t1_mc4_intr_clear(adapter->mc4);
1072*d39a76e7Sxw161283 		t1_mc5_intr_clear(adapter->mc5);
1073*d39a76e7Sxw161283 	}
1074*d39a76e7Sxw161283 #endif
1075*d39a76e7Sxw161283 	if (adapter->espi)
1076*d39a76e7Sxw161283 		t1_espi_intr_clear(adapter->espi);
1077*d39a76e7Sxw161283 
1078*d39a76e7Sxw161283 	/* Clear MAC/PHY interrupts for each port. */
1079*d39a76e7Sxw161283 	for_each_port(adapter, i) {
1080*d39a76e7Sxw161283 		adapter->port[i].mac->ops->interrupt_clear(adapter->
1081*d39a76e7Sxw161283 			port[i].mac);
1082*d39a76e7Sxw161283 		adapter->port[i].phy->ops->interrupt_clear(adapter->
1083*d39a76e7Sxw161283 			port[i].phy);
1084*d39a76e7Sxw161283 	}
1085*d39a76e7Sxw161283 
1086*d39a76e7Sxw161283 	/* Enable interrupts for external devices. */
1087*d39a76e7Sxw161283 	if (t1_is_asic(adapter)) {
1088*d39a76e7Sxw161283 		u32 pl_intr = t1_read_reg_4(adapter, A_PL_CAUSE);
1089*d39a76e7Sxw161283 
1090*d39a76e7Sxw161283 		t1_write_reg_4(adapter, A_PL_CAUSE,
1091*d39a76e7Sxw161283 			pl_intr | F_PL_INTR_EXT | F_PL_INTR_PCIX);
1092*d39a76e7Sxw161283 	}
1093*d39a76e7Sxw161283 
1094*d39a76e7Sxw161283 	/* PCI-X interrupts */
1095*d39a76e7Sxw161283 	(void) t1_os_pci_write_config_4(adapter, A_PCICFG_INTR_CAUSE,
1096*d39a76e7Sxw161283 		0xffffffff);
1097*d39a76e7Sxw161283 }
1098*d39a76e7Sxw161283 
1099*d39a76e7Sxw161283 /*
1100*d39a76e7Sxw161283  * Slow path interrupt handler for ASICs.
1101*d39a76e7Sxw161283  */
asic_slow_intr(adapter_t * adapter)1102*d39a76e7Sxw161283 static int asic_slow_intr(adapter_t *adapter)
1103*d39a76e7Sxw161283 {
1104*d39a76e7Sxw161283 	u32 cause = t1_read_reg_4(adapter, A_PL_CAUSE);
1105*d39a76e7Sxw161283 
1106*d39a76e7Sxw161283 	cause &= adapter->slow_intr_mask;
1107*d39a76e7Sxw161283 	if (!cause)
1108*d39a76e7Sxw161283 		return (0);
1109*d39a76e7Sxw161283 	if (cause & F_PL_INTR_SGE_ERR)
1110*d39a76e7Sxw161283 		(void) t1_sge_intr_error_handler(adapter->sge);
1111*d39a76e7Sxw161283 	if (cause & F_PL_INTR_TP)
1112*d39a76e7Sxw161283 		(void) t1_tp_intr_handler(adapter->tp);
1113*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
1114*d39a76e7Sxw161283 	if (cause & F_PL_INTR_MC3)
1115*d39a76e7Sxw161283 		(void) t1_mc3_intr_handler(adapter->mc3);
1116*d39a76e7Sxw161283 	if (cause & F_PL_INTR_MC4)
1117*d39a76e7Sxw161283 		(void) t1_mc4_intr_handler(adapter->mc4);
1118*d39a76e7Sxw161283 	if (cause & F_PL_INTR_ULP)
1119*d39a76e7Sxw161283 		(void) t1_ulp_intr_handler(adapter->ulp);
1120*d39a76e7Sxw161283 	if (cause & F_PL_INTR_MC5)
1121*d39a76e7Sxw161283 		(void) t1_mc5_intr_handler(adapter->mc5);
1122*d39a76e7Sxw161283 #endif
1123*d39a76e7Sxw161283 	if (cause & F_PL_INTR_ESPI)
1124*d39a76e7Sxw161283 		(void) t1_espi_intr_handler(adapter->espi);
1125*d39a76e7Sxw161283 	if (cause & F_PL_INTR_PCIX)
1126*d39a76e7Sxw161283 		(void) t1_pci_intr_handler(adapter);
1127*d39a76e7Sxw161283 	if (cause & F_PL_INTR_EXT)
1128*d39a76e7Sxw161283 		t1_os_elmer0_ext_intr(adapter);
1129*d39a76e7Sxw161283 
1130*d39a76e7Sxw161283 	/* Clear the interrupts just processed. */
1131*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_PL_CAUSE, cause);
1132*d39a76e7Sxw161283 	(void) t1_read_reg_4(adapter, A_PL_CAUSE); /* flush writes */
1133*d39a76e7Sxw161283 	return (1);
1134*d39a76e7Sxw161283 }
1135*d39a76e7Sxw161283 
1136*d39a76e7Sxw161283 int
t1_slow_intr_handler(adapter_t * adapter)1137*d39a76e7Sxw161283 t1_slow_intr_handler(adapter_t *adapter)
1138*d39a76e7Sxw161283 {
1139*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
1140*d39a76e7Sxw161283 	if (!t1_is_asic(adapter))
1141*d39a76e7Sxw161283 		return (fpga_slow_intr(adapter));
1142*d39a76e7Sxw161283 #endif
1143*d39a76e7Sxw161283 	return (asic_slow_intr(adapter));
1144*d39a76e7Sxw161283 }
1145*d39a76e7Sxw161283 
1146*d39a76e7Sxw161283 /* Power sequencing is a work-around for Intel's XPAKs. */
1147*d39a76e7Sxw161283 static void
power_sequence_xpak(adapter_t * adapter)1148*d39a76e7Sxw161283 power_sequence_xpak(adapter_t * adapter)
1149*d39a76e7Sxw161283 {
1150*d39a76e7Sxw161283 	u32 mod_detect;
1151*d39a76e7Sxw161283 	u32 gpo;
1152*d39a76e7Sxw161283 
1153*d39a76e7Sxw161283 	/* Check for XPAK */
1154*d39a76e7Sxw161283 	(void) t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
1155*d39a76e7Sxw161283 	if (!(ELMER0_GP_BIT5 & mod_detect)) {
1156*d39a76e7Sxw161283 		/* XPAK is present */
1157*d39a76e7Sxw161283 		(void) t1_tpi_read(adapter, A_ELMER0_GPO, &gpo);
1158*d39a76e7Sxw161283 		gpo |= ELMER0_GP_BIT18;
1159*d39a76e7Sxw161283 		(void) t1_tpi_write(adapter, A_ELMER0_GPO, gpo);
1160*d39a76e7Sxw161283 	}
1161*d39a76e7Sxw161283 }
1162*d39a76e7Sxw161283 
t1_get_board_rev(adapter_t * adapter,const struct board_info * bi,struct adapter_params * p)1163*d39a76e7Sxw161283 int __devinit t1_get_board_rev(adapter_t *adapter, const struct board_info *bi,
1164*d39a76e7Sxw161283 	struct adapter_params *p)
1165*d39a76e7Sxw161283 {
1166*d39a76e7Sxw161283 	p->chip_version = bi->chip_term;
1167*d39a76e7Sxw161283 	p->is_asic = (p->chip_version != CHBT_TERM_FPGA);
1168*d39a76e7Sxw161283 	if (p->chip_version == CHBT_TERM_T1 ||
1169*d39a76e7Sxw161283 	    p->chip_version == CHBT_TERM_T2 ||
1170*d39a76e7Sxw161283 	    p->chip_version == CHBT_TERM_FPGA) {
1171*d39a76e7Sxw161283 		u32 val = t1_read_reg_4(adapter, A_TP_PC_CONFIG);
1172*d39a76e7Sxw161283 
1173*d39a76e7Sxw161283 		val = G_TP_PC_REV(val);
1174*d39a76e7Sxw161283 		if (val == 2)
1175*d39a76e7Sxw161283 			p->chip_revision = TERM_T1B;
1176*d39a76e7Sxw161283 		else if (val == 3)
1177*d39a76e7Sxw161283 			p->chip_revision = TERM_T2;
1178*d39a76e7Sxw161283 		else
1179*d39a76e7Sxw161283 			return (-1);
1180*d39a76e7Sxw161283 	} else
1181*d39a76e7Sxw161283 		return (-1);
1182*d39a76e7Sxw161283 	return (0);
1183*d39a76e7Sxw161283 }
1184*d39a76e7Sxw161283 
1185*d39a76e7Sxw161283 /*
1186*d39a76e7Sxw161283  * Enable board components other than the Chelsio chip, such as external MAC
1187*d39a76e7Sxw161283  * and PHY.
1188*d39a76e7Sxw161283  */
board_init(adapter_t * adapter,const struct board_info * bi)1189*d39a76e7Sxw161283 static int board_init(adapter_t *adapter, const struct board_info *bi)
1190*d39a76e7Sxw161283 {
1191*d39a76e7Sxw161283 	switch (bi->board) {
1192*d39a76e7Sxw161283 	case CHBT_BOARD_8000:
1193*d39a76e7Sxw161283 	case CHBT_BOARD_N110:
1194*d39a76e7Sxw161283 	case CHBT_BOARD_N210:
1195*d39a76e7Sxw161283 	case CHBT_BOARD_CHT210:
1196*d39a76e7Sxw161283 	case CHBT_BOARD_COUGAR:
1197*d39a76e7Sxw161283 		t1_tpi_par(adapter, 0xf);
1198*d39a76e7Sxw161283 		(void) t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
1199*d39a76e7Sxw161283 		break;
1200*d39a76e7Sxw161283 	case CHBT_BOARD_CHT110:
1201*d39a76e7Sxw161283 		t1_tpi_par(adapter, 0xf);
1202*d39a76e7Sxw161283 		(void) t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
1203*d39a76e7Sxw161283 
1204*d39a76e7Sxw161283 		/*
1205*d39a76e7Sxw161283 		 * TBD XXX Might not need.  This fixes a problem
1206*d39a76e7Sxw161283 		 * described in the Intel SR XPAK errata.
1207*d39a76e7Sxw161283 		 */
1208*d39a76e7Sxw161283 		power_sequence_xpak(adapter);
1209*d39a76e7Sxw161283 		break;
1210*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
1211*d39a76e7Sxw161283 	case CHBT_BOARD_CHT204:
1212*d39a76e7Sxw161283 	case CHBT_BOARD_CHT204V:
1213*d39a76e7Sxw161283                 t1_tpi_par(adapter, 0xf);
1214*d39a76e7Sxw161283                 (void) t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
1215*d39a76e7Sxw161283                 break;
1216*d39a76e7Sxw161283 	case CHBT_BOARD_CHT101:
1217*d39a76e7Sxw161283 	case CHBT_BOARD_7500:
1218*d39a76e7Sxw161283 		t1_tpi_par(adapter, 0xf);
1219*d39a76e7Sxw161283 		(void) t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
1220*d39a76e7Sxw161283 		break;
1221*d39a76e7Sxw161283 #endif
1222*d39a76e7Sxw161283 	}
1223*d39a76e7Sxw161283 	return (0);
1224*d39a76e7Sxw161283 }
1225*d39a76e7Sxw161283 
1226*d39a76e7Sxw161283 /*
1227*d39a76e7Sxw161283  * Initialize and configure the Terminator HW modules.  Note that external
1228*d39a76e7Sxw161283  * MAC and PHYs are initialized separately.
1229*d39a76e7Sxw161283  */
1230*d39a76e7Sxw161283 int
t1_init_hw_modules(adapter_t * adapter)1231*d39a76e7Sxw161283 t1_init_hw_modules(adapter_t *adapter)
1232*d39a76e7Sxw161283 {
1233*d39a76e7Sxw161283 	int err = -EIO;
1234*d39a76e7Sxw161283 	const struct board_info *bi = board_info(adapter);
1235*d39a76e7Sxw161283 
1236*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
1237*d39a76e7Sxw161283 	if (adapter->mc3 && t1_mc3_init(adapter->mc3, bi->clock_mc3))
1238*d39a76e7Sxw161283 		goto out_err;
1239*d39a76e7Sxw161283 	if (adapter->mc4 && t1_mc4_init(adapter->mc4, bi->clock_mc4))
1240*d39a76e7Sxw161283 		goto out_err;
1241*d39a76e7Sxw161283 	if (adapter->mc5 && t1_mc5_init(adapter->mc5,
1242*d39a76e7Sxw161283 					adapter->params.mc5.nservers,
1243*d39a76e7Sxw161283 					adapter->params.mc5.nroutes, 1, 0))
1244*d39a76e7Sxw161283 		goto out_err;
1245*d39a76e7Sxw161283 	if (adapter->ulp && t1_ulp_init(adapter->ulp,
1246*d39a76e7Sxw161283 					adapter->params.tp.pm_tx_base))
1247*d39a76e7Sxw161283 		goto out_err;
1248*d39a76e7Sxw161283 #endif
1249*d39a76e7Sxw161283 	if (!adapter->mc4) {
1250*d39a76e7Sxw161283 		u32 val = t1_read_reg_4(adapter, A_MC4_CFG);
1251*d39a76e7Sxw161283 
1252*d39a76e7Sxw161283 		t1_write_reg_4(adapter, A_MC4_CFG, val | F_READY | F_MC4_SLOW);
1253*d39a76e7Sxw161283 		t1_write_reg_4(adapter, A_MC5_CONFIG,
1254*d39a76e7Sxw161283 			F_M_BUS_ENABLE | F_TCAM_RESET);
1255*d39a76e7Sxw161283 	}
1256*d39a76e7Sxw161283 
1257*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_COUGAR
1258*d39a76e7Sxw161283 	if (adapter->cspi && t1_cspi_init(adapter->cspi))
1259*d39a76e7Sxw161283 		goto out_err;
1260*d39a76e7Sxw161283 #endif
1261*d39a76e7Sxw161283 	if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac,
1262*d39a76e7Sxw161283 		bi->espi_nports))
1263*d39a76e7Sxw161283 		goto out_err;
1264*d39a76e7Sxw161283 
1265*d39a76e7Sxw161283 	if (t1_tp_reset(adapter->tp, &adapter->params.tp, bi->clock_core))
1266*d39a76e7Sxw161283 		goto out_err;
1267*d39a76e7Sxw161283 
1268*d39a76e7Sxw161283 	err = t1_sge_configure(adapter->sge, &adapter->params.sge);
1269*d39a76e7Sxw161283 	if (err)
1270*d39a76e7Sxw161283 		goto out_err;
1271*d39a76e7Sxw161283 
1272*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
1273*d39a76e7Sxw161283 	(void) t1_tp_set_coalescing_size(adapter->tp,
1274*d39a76e7Sxw161283 		min(adapter->params.sge.large_buf_capacity,
1275*d39a76e7Sxw161283 			TP_MAX_RX_COALESCING_SIZE));
1276*d39a76e7Sxw161283 #endif
1277*d39a76e7Sxw161283 	err = 0;
1278*d39a76e7Sxw161283 out_err:
1279*d39a76e7Sxw161283 	return (err);
1280*d39a76e7Sxw161283 }
1281*d39a76e7Sxw161283 
1282*d39a76e7Sxw161283 /*
1283*d39a76e7Sxw161283  * Determine a card's PCI mode.
1284*d39a76e7Sxw161283  */
get_pci_mode(adapter_t * adapter,struct pci_params * p)1285*d39a76e7Sxw161283 static void __devinit get_pci_mode(adapter_t *adapter, struct pci_params *p)
1286*d39a76e7Sxw161283 {
1287*d39a76e7Sxw161283 	static unsigned short speed_map[] = { 33, 66, 100, 133 };
1288*d39a76e7Sxw161283 	u32 pci_mode;
1289*d39a76e7Sxw161283 
1290*d39a76e7Sxw161283 	(void) t1_os_pci_read_config_4(adapter, A_PCICFG_MODE, &pci_mode);
1291*d39a76e7Sxw161283 	p->speed = speed_map[G_PCI_MODE_CLK(pci_mode)];
1292*d39a76e7Sxw161283 	p->width = (pci_mode & F_PCI_MODE_64BIT) ? 64 : 32;
1293*d39a76e7Sxw161283 	p->is_pcix = (pci_mode & F_PCI_MODE_PCIX) != 0;
1294*d39a76e7Sxw161283 }
1295*d39a76e7Sxw161283 
1296*d39a76e7Sxw161283 /*
1297*d39a76e7Sxw161283  * Release the structures holding the SW per-Terminator-HW-module state.
1298*d39a76e7Sxw161283  */
1299*d39a76e7Sxw161283 void
t1_free_sw_modules(adapter_t * adapter)1300*d39a76e7Sxw161283 t1_free_sw_modules(adapter_t *adapter)
1301*d39a76e7Sxw161283 {
1302*d39a76e7Sxw161283 	unsigned int i;
1303*d39a76e7Sxw161283 
1304*d39a76e7Sxw161283 	for_each_port(adapter, i) {
1305*d39a76e7Sxw161283 		struct cmac *mac = adapter->port[i].mac;
1306*d39a76e7Sxw161283 		struct cphy *phy = adapter->port[i].phy;
1307*d39a76e7Sxw161283 
1308*d39a76e7Sxw161283 		if (mac)
1309*d39a76e7Sxw161283 			mac->ops->destroy(mac);
1310*d39a76e7Sxw161283 		if (phy)
1311*d39a76e7Sxw161283 			phy->ops->destroy(phy);
1312*d39a76e7Sxw161283 	}
1313*d39a76e7Sxw161283 
1314*d39a76e7Sxw161283 	if (adapter->sge)
1315*d39a76e7Sxw161283 		(void) t1_sge_destroy(adapter->sge);
1316*d39a76e7Sxw161283 	if (adapter->tp)
1317*d39a76e7Sxw161283 		t1_tp_destroy(adapter->tp);
1318*d39a76e7Sxw161283 	if (adapter->espi)
1319*d39a76e7Sxw161283 		t1_espi_destroy(adapter->espi);
1320*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
1321*d39a76e7Sxw161283 	if (adapter->mc5)
1322*d39a76e7Sxw161283 		t1_mc5_destroy(adapter->mc5);
1323*d39a76e7Sxw161283 	if (adapter->mc3)
1324*d39a76e7Sxw161283 		t1_mc3_destroy(adapter->mc3);
1325*d39a76e7Sxw161283 	if (adapter->mc4)
1326*d39a76e7Sxw161283 		t1_mc4_destroy(adapter->mc4);
1327*d39a76e7Sxw161283 	if (adapter->ulp)
1328*d39a76e7Sxw161283 		t1_ulp_destroy(adapter->ulp);
1329*d39a76e7Sxw161283 #endif
1330*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_COUGAR
1331*d39a76e7Sxw161283 	if (adapter->cspi)
1332*d39a76e7Sxw161283 		t1_cspi_destroy(adapter->cspi);
1333*d39a76e7Sxw161283 #endif
1334*d39a76e7Sxw161283 }
1335*d39a76e7Sxw161283 
init_link_config(struct link_config * lc,const struct board_info * bi)1336*d39a76e7Sxw161283 static void __devinit init_link_config(struct link_config *lc,
1337*d39a76e7Sxw161283 	const struct board_info *bi)
1338*d39a76e7Sxw161283 {
1339*d39a76e7Sxw161283 	lc->supported = bi->caps;
1340*d39a76e7Sxw161283 	lc->requested_speed = lc->speed = SPEED_INVALID;
1341*d39a76e7Sxw161283 	lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
1342*d39a76e7Sxw161283 	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
1343*d39a76e7Sxw161283 	if (lc->supported & SUPPORTED_Autoneg) {
1344*d39a76e7Sxw161283 		lc->advertising = lc->supported;
1345*d39a76e7Sxw161283 		lc->autoneg = AUTONEG_ENABLE;
1346*d39a76e7Sxw161283 		lc->requested_fc |= PAUSE_AUTONEG;
1347*d39a76e7Sxw161283 	} else {
1348*d39a76e7Sxw161283 		lc->advertising = 0;
1349*d39a76e7Sxw161283 		lc->autoneg = AUTONEG_DISABLE;
1350*d39a76e7Sxw161283 	}
1351*d39a76e7Sxw161283 }
1352*d39a76e7Sxw161283 
1353*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
init_mtus(unsigned short mtus[])1354*d39a76e7Sxw161283 void init_mtus(unsigned short mtus[])
1355*d39a76e7Sxw161283 {
1356*d39a76e7Sxw161283 	mtus[0] = 68;
1357*d39a76e7Sxw161283 	mtus[1] = 508;
1358*d39a76e7Sxw161283 	mtus[2] = 576;
1359*d39a76e7Sxw161283 	mtus[3] = 1492;
1360*d39a76e7Sxw161283 	mtus[4] = 1500;
1361*d39a76e7Sxw161283 	mtus[5] = 2000;
1362*d39a76e7Sxw161283 	mtus[6] = 4000;
1363*d39a76e7Sxw161283 	mtus[7] = 9000;
1364*d39a76e7Sxw161283 }
1365*d39a76e7Sxw161283 #endif
1366*d39a76e7Sxw161283 
1367*d39a76e7Sxw161283 /*
1368*d39a76e7Sxw161283  * Allocate and initialize the data structures that hold the SW state of
1369*d39a76e7Sxw161283  * the Terminator HW modules.
1370*d39a76e7Sxw161283  */
t1_init_sw_modules(adapter_t * adapter,const struct board_info * bi)1371*d39a76e7Sxw161283 int __devinit t1_init_sw_modules(adapter_t *adapter,
1372*d39a76e7Sxw161283 	const struct board_info *bi)
1373*d39a76e7Sxw161283 {
1374*d39a76e7Sxw161283 	unsigned int i;
1375*d39a76e7Sxw161283 
1376*d39a76e7Sxw161283 	adapter->params.brd_info = bi;
1377*d39a76e7Sxw161283 	adapter->params.nports = bi->port_number;
1378*d39a76e7Sxw161283 	adapter->params.stats_update_period = bi->gmac->stats_update_period;
1379*d39a76e7Sxw161283 
1380*d39a76e7Sxw161283 	adapter->sge = t1_sge_create(adapter, &adapter->params.sge);
1381*d39a76e7Sxw161283 	if (!adapter->sge) {
1382*d39a76e7Sxw161283 		CH_ERR("%s: SGE initialization failed\n",
1383*d39a76e7Sxw161283 			adapter_name(adapter));
1384*d39a76e7Sxw161283 		goto error;
1385*d39a76e7Sxw161283 	}
1386*d39a76e7Sxw161283 
1387*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
1388*d39a76e7Sxw161283 	if (bi->clock_mc4) {
1389*d39a76e7Sxw161283 		/*
1390*d39a76e7Sxw161283 		 * Must wait 200us after power up before touching the
1391*d39a76e7Sxw161283 		 * memory controllers.
1392*d39a76e7Sxw161283 		 */
1393*d39a76e7Sxw161283 		DELAY_US(200);
1394*d39a76e7Sxw161283 
1395*d39a76e7Sxw161283 		adapter->mc3 = t1_mc3_create(adapter);
1396*d39a76e7Sxw161283 		if (!adapter->mc3) {
1397*d39a76e7Sxw161283 			CH_ERR("%s: MC3 initialization failed\n",
1398*d39a76e7Sxw161283 				adapter_name(adapter));
1399*d39a76e7Sxw161283 			goto error;
1400*d39a76e7Sxw161283 		}
1401*d39a76e7Sxw161283 
1402*d39a76e7Sxw161283 		adapter->mc4 = t1_mc4_create(adapter);
1403*d39a76e7Sxw161283 		if (!adapter->mc4) {
1404*d39a76e7Sxw161283 			CH_ERR("%s: MC4 initialization failed\n",
1405*d39a76e7Sxw161283 				adapter_name(adapter));
1406*d39a76e7Sxw161283 			goto error;
1407*d39a76e7Sxw161283 		}
1408*d39a76e7Sxw161283 
1409*d39a76e7Sxw161283 		if (!adapter->params.mc5.mode)
1410*d39a76e7Sxw161283 			adapter->params.mc5.mode = MC5_MODE_144_BIT;
1411*d39a76e7Sxw161283 		adapter->mc5 = t1_mc5_create(adapter,
1412*d39a76e7Sxw161283 			adapter->params.mc5.mode);
1413*d39a76e7Sxw161283 		if (!adapter->mc5) {
1414*d39a76e7Sxw161283 			CH_ERR("%s: MC5 initialization failed\n",
1415*d39a76e7Sxw161283 				adapter_name(adapter));
1416*d39a76e7Sxw161283 			goto error;
1417*d39a76e7Sxw161283 		}
1418*d39a76e7Sxw161283 
1419*d39a76e7Sxw161283 		adapter->ulp = t1_ulp_create(adapter);
1420*d39a76e7Sxw161283 		if (!adapter->ulp) {
1421*d39a76e7Sxw161283 			CH_ERR("%s: ULP initialization failed\n",
1422*d39a76e7Sxw161283 				adapter_name(adapter));
1423*d39a76e7Sxw161283 			goto error;
1424*d39a76e7Sxw161283 		}
1425*d39a76e7Sxw161283 
1426*d39a76e7Sxw161283 		adapter->params.tp.pm_size = t1_mc3_get_size(adapter->mc3);
1427*d39a76e7Sxw161283 		adapter->params.tp.cm_size = t1_mc4_get_size(adapter->mc4);
1428*d39a76e7Sxw161283 
1429*d39a76e7Sxw161283 		adapter->params.mc5.nservers = DEFAULT_SERVER_REGION_LEN;
1430*d39a76e7Sxw161283 		adapter->params.mc5.nroutes = DEFAULT_RT_REGION_LEN;
1431*d39a76e7Sxw161283 
1432*d39a76e7Sxw161283 		init_mtus(adapter->params.mtus);
1433*d39a76e7Sxw161283 	}
1434*d39a76e7Sxw161283 #endif
1435*d39a76e7Sxw161283 
1436*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_COUGAR
1437*d39a76e7Sxw161283 	if (bi->clock_cspi && !(adapter->cspi = t1_cspi_create(adapter))) {
1438*d39a76e7Sxw161283 		CH_ERR("%s: CSPI initialization failed\n",
1439*d39a76e7Sxw161283 			adapter_name(adapter));
1440*d39a76e7Sxw161283 		goto error;
1441*d39a76e7Sxw161283 	}
1442*d39a76e7Sxw161283 #endif
1443*d39a76e7Sxw161283 
1444*d39a76e7Sxw161283 	if (bi->espi_nports && !(adapter->espi = t1_espi_create(adapter))) {
1445*d39a76e7Sxw161283 		CH_ERR("%s: ESPI initialization failed\n",
1446*d39a76e7Sxw161283 			adapter_name(adapter));
1447*d39a76e7Sxw161283 		goto error;
1448*d39a76e7Sxw161283 	}
1449*d39a76e7Sxw161283 
1450*d39a76e7Sxw161283 	adapter->tp = t1_tp_create(adapter, &adapter->params.tp);
1451*d39a76e7Sxw161283 	if (!adapter->tp) {
1452*d39a76e7Sxw161283 		CH_ERR("%s: TP initialization failed\n",
1453*d39a76e7Sxw161283 			adapter_name(adapter));
1454*d39a76e7Sxw161283 		goto error;
1455*d39a76e7Sxw161283 	}
1456*d39a76e7Sxw161283 
1457*d39a76e7Sxw161283 	(void) board_init(adapter, bi);
1458*d39a76e7Sxw161283 	bi->mdio_ops->init(adapter, bi);
1459*d39a76e7Sxw161283 	if (bi->gphy->reset)
1460*d39a76e7Sxw161283 		bi->gphy->reset(adapter);
1461*d39a76e7Sxw161283 	if (bi->gmac->reset)
1462*d39a76e7Sxw161283 		bi->gmac->reset(adapter);
1463*d39a76e7Sxw161283 
1464*d39a76e7Sxw161283 	for_each_port(adapter, i) {
1465*d39a76e7Sxw161283 		u8 hw_addr[6];
1466*d39a76e7Sxw161283 		struct cmac *mac;
1467*d39a76e7Sxw161283 		int phy_addr = bi->mdio_phybaseaddr + i;
1468*d39a76e7Sxw161283 
1469*d39a76e7Sxw161283 		adapter->port[i].phy = bi->gphy->create(adapter, phy_addr,
1470*d39a76e7Sxw161283 							bi->mdio_ops);
1471*d39a76e7Sxw161283 		if (!adapter->port[i].phy) {
1472*d39a76e7Sxw161283 			CH_ERR("%s: PHY %d initialization failed\n",
1473*d39a76e7Sxw161283 				adapter_name(adapter), i);
1474*d39a76e7Sxw161283 			goto error;
1475*d39a76e7Sxw161283 		}
1476*d39a76e7Sxw161283 
1477*d39a76e7Sxw161283 		adapter->port[i].mac = mac = bi->gmac->create(adapter, i);
1478*d39a76e7Sxw161283 		if (!mac) {
1479*d39a76e7Sxw161283 			CH_ERR("%s: MAC %d initialization failed\n",
1480*d39a76e7Sxw161283 				adapter_name(adapter), i);
1481*d39a76e7Sxw161283 			goto error;
1482*d39a76e7Sxw161283 		}
1483*d39a76e7Sxw161283 
1484*d39a76e7Sxw161283 		/*
1485*d39a76e7Sxw161283 		 * Get the port's MAC addresses either from the EEPROM if one
1486*d39a76e7Sxw161283 		 * exists or the one hardcoded in the MAC.
1487*d39a76e7Sxw161283 		 */
1488*d39a76e7Sxw161283 		if (!t1_is_asic(adapter) || bi->chip_mac == CHBT_MAC_DUMMY)
1489*d39a76e7Sxw161283 			mac->ops->macaddress_get(mac, hw_addr);
1490*d39a76e7Sxw161283 		else if (vpd_macaddress_get(adapter, i, hw_addr)) {
1491*d39a76e7Sxw161283 			CH_ERR("%s: could not read MAC address from VPD ROM\n",
1492*d39a76e7Sxw161283 				port_name(adapter, i));
1493*d39a76e7Sxw161283 			goto error;
1494*d39a76e7Sxw161283 		}
1495*d39a76e7Sxw161283 		t1_os_set_hw_addr(adapter, i, hw_addr);
1496*d39a76e7Sxw161283 		init_link_config(&adapter->port[i].link_config, bi);
1497*d39a76e7Sxw161283 	}
1498*d39a76e7Sxw161283 
1499*d39a76e7Sxw161283 	get_pci_mode(adapter, &adapter->params.pci);
1500*d39a76e7Sxw161283 	t1_interrupts_clear(adapter);
1501*d39a76e7Sxw161283 	return (0);
1502*d39a76e7Sxw161283 
1503*d39a76e7Sxw161283 error:
1504*d39a76e7Sxw161283 	t1_free_sw_modules(adapter);
1505*d39a76e7Sxw161283 	return (-1);
1506*d39a76e7Sxw161283 }
1507