1*8044SWilliam.Kucharski@Sun.COM /* $Id: tg3.c,v 1.5 2003/03/19 21:26:20 gbaum Exp $
2*8044SWilliam.Kucharski@Sun.COM * tg3.c: Broadcom Tigon3 ethernet driver.
3*8044SWilliam.Kucharski@Sun.COM *
4*8044SWilliam.Kucharski@Sun.COM * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
5*8044SWilliam.Kucharski@Sun.COM * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@mandrakesoft.com)
6*8044SWilliam.Kucharski@Sun.COM * Copyright (C) 2003 Eric Biederman (ebiederman@lnxi.com) [etherboot port]
7*8044SWilliam.Kucharski@Sun.COM */
8*8044SWilliam.Kucharski@Sun.COM
9*8044SWilliam.Kucharski@Sun.COM /* 11-13-2003 timlegge Fix Issue with NetGear GA302T
10*8044SWilliam.Kucharski@Sun.COM * 11-18-2003 ebiederm Generalize NetGear Fix to what the code was supposed to be.
11*8044SWilliam.Kucharski@Sun.COM */
12*8044SWilliam.Kucharski@Sun.COM
13*8044SWilliam.Kucharski@Sun.COM #include "etherboot.h"
14*8044SWilliam.Kucharski@Sun.COM #include "nic.h"
15*8044SWilliam.Kucharski@Sun.COM #include "pci.h"
16*8044SWilliam.Kucharski@Sun.COM #include "timer.h"
17*8044SWilliam.Kucharski@Sun.COM /*#include "string.h"*/
18*8044SWilliam.Kucharski@Sun.COM #include "tg3.h"
19*8044SWilliam.Kucharski@Sun.COM
20*8044SWilliam.Kucharski@Sun.COM #define SUPPORT_COPPER_PHY 1
21*8044SWilliam.Kucharski@Sun.COM #define SUPPORT_FIBER_PHY 1
22*8044SWilliam.Kucharski@Sun.COM #define SUPPORT_LINK_REPORT 1
23*8044SWilliam.Kucharski@Sun.COM #define SUPPORT_PARTNO_STR 1
24*8044SWilliam.Kucharski@Sun.COM #define SUPPORT_PHY_STR 1
25*8044SWilliam.Kucharski@Sun.COM
26*8044SWilliam.Kucharski@Sun.COM struct tg3 tg3;
27*8044SWilliam.Kucharski@Sun.COM
28*8044SWilliam.Kucharski@Sun.COM /* Dummy defines for error handling */
29*8044SWilliam.Kucharski@Sun.COM #define EBUSY 1
30*8044SWilliam.Kucharski@Sun.COM #define ENODEV 2
31*8044SWilliam.Kucharski@Sun.COM #define EINVAL 3
32*8044SWilliam.Kucharski@Sun.COM #define ENOMEM 4
33*8044SWilliam.Kucharski@Sun.COM
34*8044SWilliam.Kucharski@Sun.COM
35*8044SWilliam.Kucharski@Sun.COM /* These numbers seem to be hard coded in the NIC firmware somehow.
36*8044SWilliam.Kucharski@Sun.COM * You can't change the ring sizes, but you can change where you place
37*8044SWilliam.Kucharski@Sun.COM * them in the NIC onboard memory.
38*8044SWilliam.Kucharski@Sun.COM */
39*8044SWilliam.Kucharski@Sun.COM #define TG3_RX_RING_SIZE 512
40*8044SWilliam.Kucharski@Sun.COM #define TG3_DEF_RX_RING_PENDING 20 /* RX_RING_PENDING seems to be o.k. at 20 and 200 */
41*8044SWilliam.Kucharski@Sun.COM #define TG3_RX_RCB_RING_SIZE 1024
42*8044SWilliam.Kucharski@Sun.COM
43*8044SWilliam.Kucharski@Sun.COM /* (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ? \
44*8044SWilliam.Kucharski@Sun.COM 512 : 1024) */
45*8044SWilliam.Kucharski@Sun.COM #define TG3_TX_RING_SIZE 512
46*8044SWilliam.Kucharski@Sun.COM #define TG3_DEF_TX_RING_PENDING (TG3_TX_RING_SIZE - 1)
47*8044SWilliam.Kucharski@Sun.COM
48*8044SWilliam.Kucharski@Sun.COM #define TG3_RX_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * TG3_RX_RING_SIZE)
49*8044SWilliam.Kucharski@Sun.COM #define TG3_RX_RCB_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * TG3_RX_RCB_RING_SIZE)
50*8044SWilliam.Kucharski@Sun.COM
51*8044SWilliam.Kucharski@Sun.COM #define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * TG3_TX_RING_SIZE)
52*8044SWilliam.Kucharski@Sun.COM #define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1))
53*8044SWilliam.Kucharski@Sun.COM #define PREV_TX(N) (((N) - 1) & (TG3_TX_RING_SIZE - 1))
54*8044SWilliam.Kucharski@Sun.COM
55*8044SWilliam.Kucharski@Sun.COM #define RX_PKT_BUF_SZ (1536 + 2 + 64)
56*8044SWilliam.Kucharski@Sun.COM
57*8044SWilliam.Kucharski@Sun.COM
58*8044SWilliam.Kucharski@Sun.COM static struct bss {
59*8044SWilliam.Kucharski@Sun.COM struct tg3_rx_buffer_desc rx_std[TG3_RX_RING_SIZE];
60*8044SWilliam.Kucharski@Sun.COM struct tg3_rx_buffer_desc rx_rcb[TG3_RX_RCB_RING_SIZE];
61*8044SWilliam.Kucharski@Sun.COM struct tg3_tx_buffer_desc tx_ring[TG3_TX_RING_SIZE];
62*8044SWilliam.Kucharski@Sun.COM struct tg3_hw_status hw_status;
63*8044SWilliam.Kucharski@Sun.COM struct tg3_hw_stats hw_stats;
64*8044SWilliam.Kucharski@Sun.COM unsigned char rx_bufs[TG3_DEF_RX_RING_PENDING][RX_PKT_BUF_SZ];
65*8044SWilliam.Kucharski@Sun.COM } tg3_bss;
66*8044SWilliam.Kucharski@Sun.COM
67*8044SWilliam.Kucharski@Sun.COM /**
68*8044SWilliam.Kucharski@Sun.COM * pci_save_state - save the PCI configuration space of a device before suspending
69*8044SWilliam.Kucharski@Sun.COM * @dev: - PCI device that we're dealing with
70*8044SWilliam.Kucharski@Sun.COM * @buffer: - buffer to hold config space context
71*8044SWilliam.Kucharski@Sun.COM *
72*8044SWilliam.Kucharski@Sun.COM * @buffer must be large enough to hold the entire PCI 2.2 config space
73*8044SWilliam.Kucharski@Sun.COM * (>= 64 bytes).
74*8044SWilliam.Kucharski@Sun.COM */
pci_save_state(struct pci_device * dev,uint32_t * buffer)75*8044SWilliam.Kucharski@Sun.COM static int pci_save_state(struct pci_device *dev, uint32_t *buffer)
76*8044SWilliam.Kucharski@Sun.COM {
77*8044SWilliam.Kucharski@Sun.COM int i;
78*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 16; i++)
79*8044SWilliam.Kucharski@Sun.COM pci_read_config_dword(dev, i * 4,&buffer[i]);
80*8044SWilliam.Kucharski@Sun.COM return 0;
81*8044SWilliam.Kucharski@Sun.COM }
82*8044SWilliam.Kucharski@Sun.COM
83*8044SWilliam.Kucharski@Sun.COM /**
84*8044SWilliam.Kucharski@Sun.COM * pci_restore_state - Restore the saved state of a PCI device
85*8044SWilliam.Kucharski@Sun.COM * @dev: - PCI device that we're dealing with
86*8044SWilliam.Kucharski@Sun.COM * @buffer: - saved PCI config space
87*8044SWilliam.Kucharski@Sun.COM *
88*8044SWilliam.Kucharski@Sun.COM */
pci_restore_state(struct pci_device * dev,uint32_t * buffer)89*8044SWilliam.Kucharski@Sun.COM static int pci_restore_state(struct pci_device *dev, uint32_t *buffer)
90*8044SWilliam.Kucharski@Sun.COM {
91*8044SWilliam.Kucharski@Sun.COM int i;
92*8044SWilliam.Kucharski@Sun.COM
93*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 16; i++)
94*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(dev,i * 4, buffer[i]);
95*8044SWilliam.Kucharski@Sun.COM return 0;
96*8044SWilliam.Kucharski@Sun.COM }
97*8044SWilliam.Kucharski@Sun.COM
tg3_write_indirect_reg32(uint32_t off,uint32_t val)98*8044SWilliam.Kucharski@Sun.COM static void tg3_write_indirect_reg32(uint32_t off, uint32_t val)
99*8044SWilliam.Kucharski@Sun.COM {
100*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tg3.pdev, TG3PCI_REG_BASE_ADDR, off);
101*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tg3.pdev, TG3PCI_REG_DATA, val);
102*8044SWilliam.Kucharski@Sun.COM }
103*8044SWilliam.Kucharski@Sun.COM
104*8044SWilliam.Kucharski@Sun.COM #define tw32(reg,val) tg3_write_indirect_reg32((reg),(val))
105*8044SWilliam.Kucharski@Sun.COM #define tw32_mailbox(reg, val) writel(((val) & 0xffffffff), tg3.regs + (reg))
106*8044SWilliam.Kucharski@Sun.COM #define tw16(reg,val) writew(((val) & 0xffff), tg3.regs + (reg))
107*8044SWilliam.Kucharski@Sun.COM #define tw8(reg,val) writeb(((val) & 0xff), tg3.regs + (reg))
108*8044SWilliam.Kucharski@Sun.COM #define tr32(reg) readl(tg3.regs + (reg))
109*8044SWilliam.Kucharski@Sun.COM #define tr16(reg) readw(tg3.regs + (reg))
110*8044SWilliam.Kucharski@Sun.COM #define tr8(reg) readb(tg3.regs + (reg))
111*8044SWilliam.Kucharski@Sun.COM
tw32_carefully(uint32_t reg,uint32_t val)112*8044SWilliam.Kucharski@Sun.COM static void tw32_carefully(uint32_t reg, uint32_t val)
113*8044SWilliam.Kucharski@Sun.COM {
114*8044SWilliam.Kucharski@Sun.COM tw32(reg, val);
115*8044SWilliam.Kucharski@Sun.COM tr32(reg);
116*8044SWilliam.Kucharski@Sun.COM udelay(100);
117*8044SWilliam.Kucharski@Sun.COM }
118*8044SWilliam.Kucharski@Sun.COM
tw32_mailbox2(uint32_t reg,uint32_t val)119*8044SWilliam.Kucharski@Sun.COM static void tw32_mailbox2(uint32_t reg, uint32_t val)
120*8044SWilliam.Kucharski@Sun.COM {
121*8044SWilliam.Kucharski@Sun.COM tw32_mailbox(reg, val);
122*8044SWilliam.Kucharski@Sun.COM tr32(reg);
123*8044SWilliam.Kucharski@Sun.COM }
124*8044SWilliam.Kucharski@Sun.COM
tg3_write_mem(uint32_t off,uint32_t val)125*8044SWilliam.Kucharski@Sun.COM static void tg3_write_mem(uint32_t off, uint32_t val)
126*8044SWilliam.Kucharski@Sun.COM {
127*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
128*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_DATA, val);
129*8044SWilliam.Kucharski@Sun.COM
130*8044SWilliam.Kucharski@Sun.COM /* Always leave this as zero. */
131*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
132*8044SWilliam.Kucharski@Sun.COM }
133*8044SWilliam.Kucharski@Sun.COM
tg3_read_mem(uint32_t off,uint32_t * val)134*8044SWilliam.Kucharski@Sun.COM static void tg3_read_mem(uint32_t off, uint32_t *val)
135*8044SWilliam.Kucharski@Sun.COM {
136*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
137*8044SWilliam.Kucharski@Sun.COM pci_read_config_dword(tg3.pdev, TG3PCI_MEM_WIN_DATA, val);
138*8044SWilliam.Kucharski@Sun.COM
139*8044SWilliam.Kucharski@Sun.COM /* Always leave this as zero. */
140*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
141*8044SWilliam.Kucharski@Sun.COM }
142*8044SWilliam.Kucharski@Sun.COM
tg3_disable_ints(struct tg3 * tp)143*8044SWilliam.Kucharski@Sun.COM static void tg3_disable_ints(struct tg3 *tp)
144*8044SWilliam.Kucharski@Sun.COM {
145*8044SWilliam.Kucharski@Sun.COM tw32(TG3PCI_MISC_HOST_CTRL,
146*8044SWilliam.Kucharski@Sun.COM (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
147*8044SWilliam.Kucharski@Sun.COM tw32_mailbox2(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
148*8044SWilliam.Kucharski@Sun.COM }
149*8044SWilliam.Kucharski@Sun.COM
tg3_switch_clocks(struct tg3 * tp)150*8044SWilliam.Kucharski@Sun.COM static void tg3_switch_clocks(struct tg3 *tp)
151*8044SWilliam.Kucharski@Sun.COM {
152*8044SWilliam.Kucharski@Sun.COM uint32_t orig_clock_ctrl, clock_ctrl;
153*8044SWilliam.Kucharski@Sun.COM
154*8044SWilliam.Kucharski@Sun.COM clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
155*8044SWilliam.Kucharski@Sun.COM
156*8044SWilliam.Kucharski@Sun.COM orig_clock_ctrl = clock_ctrl;
157*8044SWilliam.Kucharski@Sun.COM clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE | 0x1f);
158*8044SWilliam.Kucharski@Sun.COM tp->pci_clock_ctrl = clock_ctrl;
159*8044SWilliam.Kucharski@Sun.COM
160*8044SWilliam.Kucharski@Sun.COM if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
161*8044SWilliam.Kucharski@Sun.COM (orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE)!=0) {
162*8044SWilliam.Kucharski@Sun.COM tw32_carefully(TG3PCI_CLOCK_CTRL,
163*8044SWilliam.Kucharski@Sun.COM clock_ctrl | (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK));
164*8044SWilliam.Kucharski@Sun.COM tw32_carefully(TG3PCI_CLOCK_CTRL,
165*8044SWilliam.Kucharski@Sun.COM clock_ctrl | (CLOCK_CTRL_ALTCLK));
166*8044SWilliam.Kucharski@Sun.COM }
167*8044SWilliam.Kucharski@Sun.COM tw32_carefully(TG3PCI_CLOCK_CTRL, clock_ctrl);
168*8044SWilliam.Kucharski@Sun.COM }
169*8044SWilliam.Kucharski@Sun.COM
170*8044SWilliam.Kucharski@Sun.COM #define PHY_BUSY_LOOPS 5000
171*8044SWilliam.Kucharski@Sun.COM
tg3_readphy(struct tg3 * tp,int reg,uint32_t * val)172*8044SWilliam.Kucharski@Sun.COM static int tg3_readphy(struct tg3 *tp, int reg, uint32_t *val)
173*8044SWilliam.Kucharski@Sun.COM {
174*8044SWilliam.Kucharski@Sun.COM uint32_t frame_val;
175*8044SWilliam.Kucharski@Sun.COM int loops, ret;
176*8044SWilliam.Kucharski@Sun.COM
177*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MI_MODE, tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL);
178*8044SWilliam.Kucharski@Sun.COM
179*8044SWilliam.Kucharski@Sun.COM *val = 0xffffffff;
180*8044SWilliam.Kucharski@Sun.COM
181*8044SWilliam.Kucharski@Sun.COM frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
182*8044SWilliam.Kucharski@Sun.COM MI_COM_PHY_ADDR_MASK);
183*8044SWilliam.Kucharski@Sun.COM frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
184*8044SWilliam.Kucharski@Sun.COM MI_COM_REG_ADDR_MASK);
185*8044SWilliam.Kucharski@Sun.COM frame_val |= (MI_COM_CMD_READ | MI_COM_START);
186*8044SWilliam.Kucharski@Sun.COM
187*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MI_COM, frame_val);
188*8044SWilliam.Kucharski@Sun.COM
189*8044SWilliam.Kucharski@Sun.COM loops = PHY_BUSY_LOOPS;
190*8044SWilliam.Kucharski@Sun.COM while (loops-- > 0) {
191*8044SWilliam.Kucharski@Sun.COM udelay(10);
192*8044SWilliam.Kucharski@Sun.COM frame_val = tr32(MAC_MI_COM);
193*8044SWilliam.Kucharski@Sun.COM
194*8044SWilliam.Kucharski@Sun.COM if ((frame_val & MI_COM_BUSY) == 0) {
195*8044SWilliam.Kucharski@Sun.COM udelay(5);
196*8044SWilliam.Kucharski@Sun.COM frame_val = tr32(MAC_MI_COM);
197*8044SWilliam.Kucharski@Sun.COM break;
198*8044SWilliam.Kucharski@Sun.COM }
199*8044SWilliam.Kucharski@Sun.COM }
200*8044SWilliam.Kucharski@Sun.COM
201*8044SWilliam.Kucharski@Sun.COM ret = -EBUSY;
202*8044SWilliam.Kucharski@Sun.COM if (loops > 0) {
203*8044SWilliam.Kucharski@Sun.COM *val = frame_val & MI_COM_DATA_MASK;
204*8044SWilliam.Kucharski@Sun.COM ret = 0;
205*8044SWilliam.Kucharski@Sun.COM }
206*8044SWilliam.Kucharski@Sun.COM
207*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MI_MODE, tp->mi_mode);
208*8044SWilliam.Kucharski@Sun.COM
209*8044SWilliam.Kucharski@Sun.COM return ret;
210*8044SWilliam.Kucharski@Sun.COM }
211*8044SWilliam.Kucharski@Sun.COM
tg3_writephy(struct tg3 * tp,int reg,uint32_t val)212*8044SWilliam.Kucharski@Sun.COM static int tg3_writephy(struct tg3 *tp, int reg, uint32_t val)
213*8044SWilliam.Kucharski@Sun.COM {
214*8044SWilliam.Kucharski@Sun.COM uint32_t frame_val;
215*8044SWilliam.Kucharski@Sun.COM int loops, ret;
216*8044SWilliam.Kucharski@Sun.COM
217*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MI_MODE, tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL);
218*8044SWilliam.Kucharski@Sun.COM
219*8044SWilliam.Kucharski@Sun.COM frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
220*8044SWilliam.Kucharski@Sun.COM MI_COM_PHY_ADDR_MASK);
221*8044SWilliam.Kucharski@Sun.COM frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
222*8044SWilliam.Kucharski@Sun.COM MI_COM_REG_ADDR_MASK);
223*8044SWilliam.Kucharski@Sun.COM frame_val |= (val & MI_COM_DATA_MASK);
224*8044SWilliam.Kucharski@Sun.COM frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);
225*8044SWilliam.Kucharski@Sun.COM
226*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MI_COM, frame_val);
227*8044SWilliam.Kucharski@Sun.COM
228*8044SWilliam.Kucharski@Sun.COM loops = PHY_BUSY_LOOPS;
229*8044SWilliam.Kucharski@Sun.COM while (loops-- > 0) {
230*8044SWilliam.Kucharski@Sun.COM udelay(10);
231*8044SWilliam.Kucharski@Sun.COM frame_val = tr32(MAC_MI_COM);
232*8044SWilliam.Kucharski@Sun.COM if ((frame_val & MI_COM_BUSY) == 0) {
233*8044SWilliam.Kucharski@Sun.COM udelay(5);
234*8044SWilliam.Kucharski@Sun.COM frame_val = tr32(MAC_MI_COM);
235*8044SWilliam.Kucharski@Sun.COM break;
236*8044SWilliam.Kucharski@Sun.COM }
237*8044SWilliam.Kucharski@Sun.COM }
238*8044SWilliam.Kucharski@Sun.COM
239*8044SWilliam.Kucharski@Sun.COM ret = -EBUSY;
240*8044SWilliam.Kucharski@Sun.COM if (loops > 0)
241*8044SWilliam.Kucharski@Sun.COM ret = 0;
242*8044SWilliam.Kucharski@Sun.COM
243*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MI_MODE, tp->mi_mode);
244*8044SWilliam.Kucharski@Sun.COM
245*8044SWilliam.Kucharski@Sun.COM return ret;
246*8044SWilliam.Kucharski@Sun.COM }
247*8044SWilliam.Kucharski@Sun.COM
tg3_writedsp(struct tg3 * tp,uint16_t addr,uint16_t val)248*8044SWilliam.Kucharski@Sun.COM static int tg3_writedsp(struct tg3 *tp, uint16_t addr, uint16_t val)
249*8044SWilliam.Kucharski@Sun.COM {
250*8044SWilliam.Kucharski@Sun.COM int err;
251*8044SWilliam.Kucharski@Sun.COM err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, addr);
252*8044SWilliam.Kucharski@Sun.COM err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
253*8044SWilliam.Kucharski@Sun.COM return err;
254*8044SWilliam.Kucharski@Sun.COM }
255*8044SWilliam.Kucharski@Sun.COM
256*8044SWilliam.Kucharski@Sun.COM
tg3_phy_set_wirespeed(struct tg3 * tp)257*8044SWilliam.Kucharski@Sun.COM static void tg3_phy_set_wirespeed(struct tg3 *tp)
258*8044SWilliam.Kucharski@Sun.COM {
259*8044SWilliam.Kucharski@Sun.COM uint32_t val;
260*8044SWilliam.Kucharski@Sun.COM
261*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)
262*8044SWilliam.Kucharski@Sun.COM return;
263*8044SWilliam.Kucharski@Sun.COM
264*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);
265*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
266*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));
267*8044SWilliam.Kucharski@Sun.COM }
268*8044SWilliam.Kucharski@Sun.COM
tg3_bmcr_reset(struct tg3 * tp)269*8044SWilliam.Kucharski@Sun.COM static int tg3_bmcr_reset(struct tg3 *tp)
270*8044SWilliam.Kucharski@Sun.COM {
271*8044SWilliam.Kucharski@Sun.COM uint32_t phy_control;
272*8044SWilliam.Kucharski@Sun.COM int limit, err;
273*8044SWilliam.Kucharski@Sun.COM
274*8044SWilliam.Kucharski@Sun.COM /* OK, reset it, and poll the BMCR_RESET bit until it
275*8044SWilliam.Kucharski@Sun.COM * clears or we time out.
276*8044SWilliam.Kucharski@Sun.COM */
277*8044SWilliam.Kucharski@Sun.COM phy_control = BMCR_RESET;
278*8044SWilliam.Kucharski@Sun.COM err = tg3_writephy(tp, MII_BMCR, phy_control);
279*8044SWilliam.Kucharski@Sun.COM if (err != 0)
280*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
281*8044SWilliam.Kucharski@Sun.COM
282*8044SWilliam.Kucharski@Sun.COM limit = 5000;
283*8044SWilliam.Kucharski@Sun.COM while (limit--) {
284*8044SWilliam.Kucharski@Sun.COM err = tg3_readphy(tp, MII_BMCR, &phy_control);
285*8044SWilliam.Kucharski@Sun.COM if (err != 0)
286*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
287*8044SWilliam.Kucharski@Sun.COM
288*8044SWilliam.Kucharski@Sun.COM if ((phy_control & BMCR_RESET) == 0) {
289*8044SWilliam.Kucharski@Sun.COM udelay(40);
290*8044SWilliam.Kucharski@Sun.COM break;
291*8044SWilliam.Kucharski@Sun.COM }
292*8044SWilliam.Kucharski@Sun.COM udelay(10);
293*8044SWilliam.Kucharski@Sun.COM }
294*8044SWilliam.Kucharski@Sun.COM if (limit <= 0)
295*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
296*8044SWilliam.Kucharski@Sun.COM
297*8044SWilliam.Kucharski@Sun.COM return 0;
298*8044SWilliam.Kucharski@Sun.COM }
299*8044SWilliam.Kucharski@Sun.COM
tg3_wait_macro_done(struct tg3 * tp)300*8044SWilliam.Kucharski@Sun.COM static int tg3_wait_macro_done(struct tg3 *tp)
301*8044SWilliam.Kucharski@Sun.COM {
302*8044SWilliam.Kucharski@Sun.COM int limit = 100;
303*8044SWilliam.Kucharski@Sun.COM
304*8044SWilliam.Kucharski@Sun.COM while (limit--) {
305*8044SWilliam.Kucharski@Sun.COM uint32_t tmp32;
306*8044SWilliam.Kucharski@Sun.COM
307*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, 0x16, &tmp32);
308*8044SWilliam.Kucharski@Sun.COM if ((tmp32 & 0x1000) == 0)
309*8044SWilliam.Kucharski@Sun.COM break;
310*8044SWilliam.Kucharski@Sun.COM }
311*8044SWilliam.Kucharski@Sun.COM if (limit <= 0)
312*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
313*8044SWilliam.Kucharski@Sun.COM
314*8044SWilliam.Kucharski@Sun.COM return 0;
315*8044SWilliam.Kucharski@Sun.COM }
316*8044SWilliam.Kucharski@Sun.COM
tg3_phy_write_and_check_testpat(struct tg3 * tp,int * resetp)317*8044SWilliam.Kucharski@Sun.COM static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp)
318*8044SWilliam.Kucharski@Sun.COM {
319*8044SWilliam.Kucharski@Sun.COM static const uint32_t test_pat[4][6] = {
320*8044SWilliam.Kucharski@Sun.COM { 0x00005555, 0x00000005, 0x00002aaa, 0x0000000a, 0x00003456, 0x00000003 },
321*8044SWilliam.Kucharski@Sun.COM { 0x00002aaa, 0x0000000a, 0x00003333, 0x00000003, 0x0000789a, 0x00000005 },
322*8044SWilliam.Kucharski@Sun.COM { 0x00005a5a, 0x00000005, 0x00002a6a, 0x0000000a, 0x00001bcd, 0x00000003 },
323*8044SWilliam.Kucharski@Sun.COM { 0x00002a5a, 0x0000000a, 0x000033c3, 0x00000003, 0x00002ef1, 0x00000005 }
324*8044SWilliam.Kucharski@Sun.COM };
325*8044SWilliam.Kucharski@Sun.COM int chan;
326*8044SWilliam.Kucharski@Sun.COM
327*8044SWilliam.Kucharski@Sun.COM for (chan = 0; chan < 4; chan++) {
328*8044SWilliam.Kucharski@Sun.COM int i;
329*8044SWilliam.Kucharski@Sun.COM
330*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
331*8044SWilliam.Kucharski@Sun.COM (chan * 0x2000) | 0x0200);
332*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x16, 0x0002);
333*8044SWilliam.Kucharski@Sun.COM
334*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 6; i++)
335*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_RW_PORT,
336*8044SWilliam.Kucharski@Sun.COM test_pat[chan][i]);
337*8044SWilliam.Kucharski@Sun.COM
338*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x16, 0x0202);
339*8044SWilliam.Kucharski@Sun.COM if (tg3_wait_macro_done(tp)) {
340*8044SWilliam.Kucharski@Sun.COM *resetp = 1;
341*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
342*8044SWilliam.Kucharski@Sun.COM }
343*8044SWilliam.Kucharski@Sun.COM
344*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
345*8044SWilliam.Kucharski@Sun.COM (chan * 0x2000) | 0x0200);
346*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x16, 0x0082);
347*8044SWilliam.Kucharski@Sun.COM if (tg3_wait_macro_done(tp)) {
348*8044SWilliam.Kucharski@Sun.COM *resetp = 1;
349*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
350*8044SWilliam.Kucharski@Sun.COM }
351*8044SWilliam.Kucharski@Sun.COM
352*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x16, 0x0802);
353*8044SWilliam.Kucharski@Sun.COM if (tg3_wait_macro_done(tp)) {
354*8044SWilliam.Kucharski@Sun.COM *resetp = 1;
355*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
356*8044SWilliam.Kucharski@Sun.COM }
357*8044SWilliam.Kucharski@Sun.COM
358*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 6; i += 2) {
359*8044SWilliam.Kucharski@Sun.COM uint32_t low, high;
360*8044SWilliam.Kucharski@Sun.COM
361*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low);
362*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high);
363*8044SWilliam.Kucharski@Sun.COM if (tg3_wait_macro_done(tp)) {
364*8044SWilliam.Kucharski@Sun.COM *resetp = 1;
365*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
366*8044SWilliam.Kucharski@Sun.COM }
367*8044SWilliam.Kucharski@Sun.COM low &= 0x7fff;
368*8044SWilliam.Kucharski@Sun.COM high &= 0x000f;
369*8044SWilliam.Kucharski@Sun.COM if (low != test_pat[chan][i] ||
370*8044SWilliam.Kucharski@Sun.COM high != test_pat[chan][i+1]) {
371*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000b);
372*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4001);
373*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4005);
374*8044SWilliam.Kucharski@Sun.COM
375*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
376*8044SWilliam.Kucharski@Sun.COM }
377*8044SWilliam.Kucharski@Sun.COM }
378*8044SWilliam.Kucharski@Sun.COM }
379*8044SWilliam.Kucharski@Sun.COM
380*8044SWilliam.Kucharski@Sun.COM return 0;
381*8044SWilliam.Kucharski@Sun.COM }
382*8044SWilliam.Kucharski@Sun.COM
tg3_phy_reset_chanpat(struct tg3 * tp)383*8044SWilliam.Kucharski@Sun.COM static int tg3_phy_reset_chanpat(struct tg3 *tp)
384*8044SWilliam.Kucharski@Sun.COM {
385*8044SWilliam.Kucharski@Sun.COM int chan;
386*8044SWilliam.Kucharski@Sun.COM
387*8044SWilliam.Kucharski@Sun.COM for (chan = 0; chan < 4; chan++) {
388*8044SWilliam.Kucharski@Sun.COM int i;
389*8044SWilliam.Kucharski@Sun.COM
390*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
391*8044SWilliam.Kucharski@Sun.COM (chan * 0x2000) | 0x0200);
392*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x16, 0x0002);
393*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 6; i++)
394*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);
395*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x16, 0x0202);
396*8044SWilliam.Kucharski@Sun.COM if (tg3_wait_macro_done(tp))
397*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
398*8044SWilliam.Kucharski@Sun.COM }
399*8044SWilliam.Kucharski@Sun.COM
400*8044SWilliam.Kucharski@Sun.COM return 0;
401*8044SWilliam.Kucharski@Sun.COM }
402*8044SWilliam.Kucharski@Sun.COM
tg3_phy_reset_5703_4_5(struct tg3 * tp)403*8044SWilliam.Kucharski@Sun.COM static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
404*8044SWilliam.Kucharski@Sun.COM {
405*8044SWilliam.Kucharski@Sun.COM uint32_t reg32, phy9_orig;
406*8044SWilliam.Kucharski@Sun.COM int retries, do_phy_reset, err;
407*8044SWilliam.Kucharski@Sun.COM
408*8044SWilliam.Kucharski@Sun.COM retries = 10;
409*8044SWilliam.Kucharski@Sun.COM do_phy_reset = 1;
410*8044SWilliam.Kucharski@Sun.COM do {
411*8044SWilliam.Kucharski@Sun.COM if (do_phy_reset) {
412*8044SWilliam.Kucharski@Sun.COM err = tg3_bmcr_reset(tp);
413*8044SWilliam.Kucharski@Sun.COM if (err)
414*8044SWilliam.Kucharski@Sun.COM return err;
415*8044SWilliam.Kucharski@Sun.COM do_phy_reset = 0;
416*8044SWilliam.Kucharski@Sun.COM }
417*8044SWilliam.Kucharski@Sun.COM
418*8044SWilliam.Kucharski@Sun.COM /* Disable transmitter and interrupt. */
419*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_EXT_CTRL, ®32);
420*8044SWilliam.Kucharski@Sun.COM reg32 |= 0x3000;
421*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
422*8044SWilliam.Kucharski@Sun.COM
423*8044SWilliam.Kucharski@Sun.COM /* Set full-duplex, 1000 mbps. */
424*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_BMCR,
425*8044SWilliam.Kucharski@Sun.COM BMCR_FULLDPLX | TG3_BMCR_SPEED1000);
426*8044SWilliam.Kucharski@Sun.COM
427*8044SWilliam.Kucharski@Sun.COM /* Set to master mode. */
428*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig);
429*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_CTRL,
430*8044SWilliam.Kucharski@Sun.COM (MII_TG3_CTRL_AS_MASTER |
431*8044SWilliam.Kucharski@Sun.COM MII_TG3_CTRL_ENABLE_AS_MASTER));
432*8044SWilliam.Kucharski@Sun.COM
433*8044SWilliam.Kucharski@Sun.COM /* Enable SM_DSP_CLOCK and 6dB. */
434*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
435*8044SWilliam.Kucharski@Sun.COM
436*8044SWilliam.Kucharski@Sun.COM /* Block the PHY control access. */
437*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
438*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0800);
439*8044SWilliam.Kucharski@Sun.COM
440*8044SWilliam.Kucharski@Sun.COM err = tg3_phy_write_and_check_testpat(tp, &do_phy_reset);
441*8044SWilliam.Kucharski@Sun.COM if (!err)
442*8044SWilliam.Kucharski@Sun.COM break;
443*8044SWilliam.Kucharski@Sun.COM } while (--retries);
444*8044SWilliam.Kucharski@Sun.COM
445*8044SWilliam.Kucharski@Sun.COM err = tg3_phy_reset_chanpat(tp);
446*8044SWilliam.Kucharski@Sun.COM if (err)
447*8044SWilliam.Kucharski@Sun.COM return err;
448*8044SWilliam.Kucharski@Sun.COM
449*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
450*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0000);
451*8044SWilliam.Kucharski@Sun.COM
452*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
453*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x16, 0x0000);
454*8044SWilliam.Kucharski@Sun.COM
455*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
456*8044SWilliam.Kucharski@Sun.COM
457*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
458*8044SWilliam.Kucharski@Sun.COM
459*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_EXT_CTRL, ®32);
460*8044SWilliam.Kucharski@Sun.COM reg32 &= ~0x3000;
461*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
462*8044SWilliam.Kucharski@Sun.COM
463*8044SWilliam.Kucharski@Sun.COM return err;
464*8044SWilliam.Kucharski@Sun.COM }
465*8044SWilliam.Kucharski@Sun.COM
466*8044SWilliam.Kucharski@Sun.COM /* This will reset the tigon3 PHY if there is no valid
467*8044SWilliam.Kucharski@Sun.COM * link.
468*8044SWilliam.Kucharski@Sun.COM */
tg3_phy_reset(struct tg3 * tp)469*8044SWilliam.Kucharski@Sun.COM static int tg3_phy_reset(struct tg3 *tp)
470*8044SWilliam.Kucharski@Sun.COM {
471*8044SWilliam.Kucharski@Sun.COM uint32_t phy_status;
472*8044SWilliam.Kucharski@Sun.COM int err;
473*8044SWilliam.Kucharski@Sun.COM
474*8044SWilliam.Kucharski@Sun.COM err = tg3_readphy(tp, MII_BMSR, &phy_status);
475*8044SWilliam.Kucharski@Sun.COM err |= tg3_readphy(tp, MII_BMSR, &phy_status);
476*8044SWilliam.Kucharski@Sun.COM if (err != 0)
477*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
478*8044SWilliam.Kucharski@Sun.COM
479*8044SWilliam.Kucharski@Sun.COM if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
480*8044SWilliam.Kucharski@Sun.COM (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
481*8044SWilliam.Kucharski@Sun.COM (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
482*8044SWilliam.Kucharski@Sun.COM err = tg3_phy_reset_5703_4_5(tp);
483*8044SWilliam.Kucharski@Sun.COM if (err)
484*8044SWilliam.Kucharski@Sun.COM return err;
485*8044SWilliam.Kucharski@Sun.COM goto out;
486*8044SWilliam.Kucharski@Sun.COM }
487*8044SWilliam.Kucharski@Sun.COM err = tg3_bmcr_reset(tp);
488*8044SWilliam.Kucharski@Sun.COM if (err)
489*8044SWilliam.Kucharski@Sun.COM return err;
490*8044SWilliam.Kucharski@Sun.COM out:
491*8044SWilliam.Kucharski@Sun.COM tg3_phy_set_wirespeed(tp);
492*8044SWilliam.Kucharski@Sun.COM return 0;
493*8044SWilliam.Kucharski@Sun.COM }
494*8044SWilliam.Kucharski@Sun.COM
tg3_set_power_state_0(struct tg3 * tp)495*8044SWilliam.Kucharski@Sun.COM static void tg3_set_power_state_0(struct tg3 *tp)
496*8044SWilliam.Kucharski@Sun.COM {
497*8044SWilliam.Kucharski@Sun.COM uint16_t power_control;
498*8044SWilliam.Kucharski@Sun.COM int pm = tp->pm_cap;
499*8044SWilliam.Kucharski@Sun.COM
500*8044SWilliam.Kucharski@Sun.COM /* Make sure register accesses (indirect or otherwise)
501*8044SWilliam.Kucharski@Sun.COM * will function correctly.
502*8044SWilliam.Kucharski@Sun.COM */
503*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
504*8044SWilliam.Kucharski@Sun.COM
505*8044SWilliam.Kucharski@Sun.COM pci_read_config_word(tp->pdev, pm + PCI_PM_CTRL, &power_control);
506*8044SWilliam.Kucharski@Sun.COM
507*8044SWilliam.Kucharski@Sun.COM power_control |= PCI_PM_CTRL_PME_STATUS;
508*8044SWilliam.Kucharski@Sun.COM power_control &= ~(PCI_PM_CTRL_STATE_MASK);
509*8044SWilliam.Kucharski@Sun.COM power_control |= 0;
510*8044SWilliam.Kucharski@Sun.COM pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
511*8044SWilliam.Kucharski@Sun.COM
512*8044SWilliam.Kucharski@Sun.COM tw32_carefully(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
513*8044SWilliam.Kucharski@Sun.COM
514*8044SWilliam.Kucharski@Sun.COM return;
515*8044SWilliam.Kucharski@Sun.COM }
516*8044SWilliam.Kucharski@Sun.COM
517*8044SWilliam.Kucharski@Sun.COM
518*8044SWilliam.Kucharski@Sun.COM #if SUPPORT_LINK_REPORT
tg3_link_report(struct tg3 * tp)519*8044SWilliam.Kucharski@Sun.COM static void tg3_link_report(struct tg3 *tp)
520*8044SWilliam.Kucharski@Sun.COM {
521*8044SWilliam.Kucharski@Sun.COM if (!tp->carrier_ok) {
522*8044SWilliam.Kucharski@Sun.COM printf("Link is down.\n");
523*8044SWilliam.Kucharski@Sun.COM } else {
524*8044SWilliam.Kucharski@Sun.COM printf("Link is up at %d Mbps, %s duplex. %s %s %s\n",
525*8044SWilliam.Kucharski@Sun.COM (tp->link_config.active_speed == SPEED_1000 ?
526*8044SWilliam.Kucharski@Sun.COM 1000 :
527*8044SWilliam.Kucharski@Sun.COM (tp->link_config.active_speed == SPEED_100 ?
528*8044SWilliam.Kucharski@Sun.COM 100 : 10)),
529*8044SWilliam.Kucharski@Sun.COM (tp->link_config.active_duplex == DUPLEX_FULL ?
530*8044SWilliam.Kucharski@Sun.COM "full" : "half"),
531*8044SWilliam.Kucharski@Sun.COM (tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "TX" : "",
532*8044SWilliam.Kucharski@Sun.COM (tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "RX" : "",
533*8044SWilliam.Kucharski@Sun.COM (tp->tg3_flags & (TG3_FLAG_TX_PAUSE |TG3_FLAG_RX_PAUSE)) ? "flow control" : "");
534*8044SWilliam.Kucharski@Sun.COM }
535*8044SWilliam.Kucharski@Sun.COM }
536*8044SWilliam.Kucharski@Sun.COM #else
537*8044SWilliam.Kucharski@Sun.COM #define tg3_link_report(tp)
538*8044SWilliam.Kucharski@Sun.COM #endif
539*8044SWilliam.Kucharski@Sun.COM
tg3_setup_flow_control(struct tg3 * tp,uint32_t local_adv,uint32_t remote_adv)540*8044SWilliam.Kucharski@Sun.COM static void tg3_setup_flow_control(struct tg3 *tp, uint32_t local_adv, uint32_t remote_adv)
541*8044SWilliam.Kucharski@Sun.COM {
542*8044SWilliam.Kucharski@Sun.COM uint32_t new_tg3_flags = 0;
543*8044SWilliam.Kucharski@Sun.COM
544*8044SWilliam.Kucharski@Sun.COM if (local_adv & ADVERTISE_PAUSE_CAP) {
545*8044SWilliam.Kucharski@Sun.COM if (local_adv & ADVERTISE_PAUSE_ASYM) {
546*8044SWilliam.Kucharski@Sun.COM if (remote_adv & LPA_PAUSE_CAP)
547*8044SWilliam.Kucharski@Sun.COM new_tg3_flags |=
548*8044SWilliam.Kucharski@Sun.COM (TG3_FLAG_RX_PAUSE |
549*8044SWilliam.Kucharski@Sun.COM TG3_FLAG_TX_PAUSE);
550*8044SWilliam.Kucharski@Sun.COM else if (remote_adv & LPA_PAUSE_ASYM)
551*8044SWilliam.Kucharski@Sun.COM new_tg3_flags |=
552*8044SWilliam.Kucharski@Sun.COM (TG3_FLAG_RX_PAUSE);
553*8044SWilliam.Kucharski@Sun.COM } else {
554*8044SWilliam.Kucharski@Sun.COM if (remote_adv & LPA_PAUSE_CAP)
555*8044SWilliam.Kucharski@Sun.COM new_tg3_flags |=
556*8044SWilliam.Kucharski@Sun.COM (TG3_FLAG_RX_PAUSE |
557*8044SWilliam.Kucharski@Sun.COM TG3_FLAG_TX_PAUSE);
558*8044SWilliam.Kucharski@Sun.COM }
559*8044SWilliam.Kucharski@Sun.COM } else if (local_adv & ADVERTISE_PAUSE_ASYM) {
560*8044SWilliam.Kucharski@Sun.COM if ((remote_adv & LPA_PAUSE_CAP) &&
561*8044SWilliam.Kucharski@Sun.COM (remote_adv & LPA_PAUSE_ASYM))
562*8044SWilliam.Kucharski@Sun.COM new_tg3_flags |= TG3_FLAG_TX_PAUSE;
563*8044SWilliam.Kucharski@Sun.COM }
564*8044SWilliam.Kucharski@Sun.COM
565*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
566*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= new_tg3_flags;
567*8044SWilliam.Kucharski@Sun.COM
568*8044SWilliam.Kucharski@Sun.COM if (new_tg3_flags & TG3_FLAG_RX_PAUSE)
569*8044SWilliam.Kucharski@Sun.COM tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
570*8044SWilliam.Kucharski@Sun.COM else
571*8044SWilliam.Kucharski@Sun.COM tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
572*8044SWilliam.Kucharski@Sun.COM
573*8044SWilliam.Kucharski@Sun.COM if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
574*8044SWilliam.Kucharski@Sun.COM tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
575*8044SWilliam.Kucharski@Sun.COM else
576*8044SWilliam.Kucharski@Sun.COM tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
577*8044SWilliam.Kucharski@Sun.COM }
578*8044SWilliam.Kucharski@Sun.COM
579*8044SWilliam.Kucharski@Sun.COM #if SUPPORT_COPPER_PHY
tg3_aux_stat_to_speed_duplex(struct tg3 * tp __unused,uint32_t val,uint8_t * speed,uint8_t * duplex)580*8044SWilliam.Kucharski@Sun.COM static void tg3_aux_stat_to_speed_duplex(
581*8044SWilliam.Kucharski@Sun.COM struct tg3 *tp __unused, uint32_t val, uint8_t *speed, uint8_t *duplex)
582*8044SWilliam.Kucharski@Sun.COM {
583*8044SWilliam.Kucharski@Sun.COM static const uint8_t map[] = {
584*8044SWilliam.Kucharski@Sun.COM [0] = (SPEED_INVALID << 2) | DUPLEX_INVALID,
585*8044SWilliam.Kucharski@Sun.COM [MII_TG3_AUX_STAT_10HALF >> 8] = (SPEED_10 << 2) | DUPLEX_HALF,
586*8044SWilliam.Kucharski@Sun.COM [MII_TG3_AUX_STAT_10FULL >> 8] = (SPEED_10 << 2) | DUPLEX_FULL,
587*8044SWilliam.Kucharski@Sun.COM [MII_TG3_AUX_STAT_100HALF >> 8] = (SPEED_100 << 2) | DUPLEX_HALF,
588*8044SWilliam.Kucharski@Sun.COM [MII_TG3_AUX_STAT_100_4 >> 8] = (SPEED_INVALID << 2) | DUPLEX_INVALID,
589*8044SWilliam.Kucharski@Sun.COM [MII_TG3_AUX_STAT_100FULL >> 8] = (SPEED_100 << 2) | DUPLEX_FULL,
590*8044SWilliam.Kucharski@Sun.COM [MII_TG3_AUX_STAT_1000HALF >> 8] = (SPEED_1000 << 2) | DUPLEX_HALF,
591*8044SWilliam.Kucharski@Sun.COM [MII_TG3_AUX_STAT_1000FULL >> 8] = (SPEED_1000 << 2) | DUPLEX_FULL,
592*8044SWilliam.Kucharski@Sun.COM };
593*8044SWilliam.Kucharski@Sun.COM uint8_t result;
594*8044SWilliam.Kucharski@Sun.COM result = map[(val & MII_TG3_AUX_STAT_SPDMASK) >> 8];
595*8044SWilliam.Kucharski@Sun.COM *speed = result >> 2;
596*8044SWilliam.Kucharski@Sun.COM *duplex = result & 3;
597*8044SWilliam.Kucharski@Sun.COM }
598*8044SWilliam.Kucharski@Sun.COM
tg3_phy_copper_begin(struct tg3 * tp)599*8044SWilliam.Kucharski@Sun.COM static int tg3_phy_copper_begin(struct tg3 *tp)
600*8044SWilliam.Kucharski@Sun.COM {
601*8044SWilliam.Kucharski@Sun.COM uint32_t new_adv;
602*8044SWilliam.Kucharski@Sun.COM
603*8044SWilliam.Kucharski@Sun.COM tp->link_config.advertising =
604*8044SWilliam.Kucharski@Sun.COM (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
605*8044SWilliam.Kucharski@Sun.COM ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
606*8044SWilliam.Kucharski@Sun.COM ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full |
607*8044SWilliam.Kucharski@Sun.COM ADVERTISED_Autoneg | ADVERTISED_MII);
608*8044SWilliam.Kucharski@Sun.COM
609*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags & TG3_FLAG_10_100_ONLY) {
610*8044SWilliam.Kucharski@Sun.COM tp->link_config.advertising &=
611*8044SWilliam.Kucharski@Sun.COM ~(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full);
612*8044SWilliam.Kucharski@Sun.COM }
613*8044SWilliam.Kucharski@Sun.COM
614*8044SWilliam.Kucharski@Sun.COM new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
615*8044SWilliam.Kucharski@Sun.COM if (tp->link_config.advertising & ADVERTISED_10baseT_Half) {
616*8044SWilliam.Kucharski@Sun.COM new_adv |= ADVERTISE_10HALF;
617*8044SWilliam.Kucharski@Sun.COM }
618*8044SWilliam.Kucharski@Sun.COM if (tp->link_config.advertising & ADVERTISED_10baseT_Full) {
619*8044SWilliam.Kucharski@Sun.COM new_adv |= ADVERTISE_10FULL;
620*8044SWilliam.Kucharski@Sun.COM }
621*8044SWilliam.Kucharski@Sun.COM if (tp->link_config.advertising & ADVERTISED_100baseT_Half) {
622*8044SWilliam.Kucharski@Sun.COM new_adv |= ADVERTISE_100HALF;
623*8044SWilliam.Kucharski@Sun.COM }
624*8044SWilliam.Kucharski@Sun.COM if (tp->link_config.advertising & ADVERTISED_100baseT_Full) {
625*8044SWilliam.Kucharski@Sun.COM new_adv |= ADVERTISE_100FULL;
626*8044SWilliam.Kucharski@Sun.COM }
627*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_ADVERTISE, new_adv);
628*8044SWilliam.Kucharski@Sun.COM
629*8044SWilliam.Kucharski@Sun.COM if (tp->link_config.advertising &
630*8044SWilliam.Kucharski@Sun.COM (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
631*8044SWilliam.Kucharski@Sun.COM new_adv = 0;
632*8044SWilliam.Kucharski@Sun.COM if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) {
633*8044SWilliam.Kucharski@Sun.COM new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
634*8044SWilliam.Kucharski@Sun.COM }
635*8044SWilliam.Kucharski@Sun.COM if (tp->link_config.advertising & ADVERTISED_1000baseT_Full) {
636*8044SWilliam.Kucharski@Sun.COM new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
637*8044SWilliam.Kucharski@Sun.COM }
638*8044SWilliam.Kucharski@Sun.COM if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
639*8044SWilliam.Kucharski@Sun.COM (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
640*8044SWilliam.Kucharski@Sun.COM tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) {
641*8044SWilliam.Kucharski@Sun.COM new_adv |= (MII_TG3_CTRL_AS_MASTER |
642*8044SWilliam.Kucharski@Sun.COM MII_TG3_CTRL_ENABLE_AS_MASTER);
643*8044SWilliam.Kucharski@Sun.COM }
644*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_CTRL, new_adv);
645*8044SWilliam.Kucharski@Sun.COM } else {
646*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_CTRL, 0);
647*8044SWilliam.Kucharski@Sun.COM }
648*8044SWilliam.Kucharski@Sun.COM
649*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
650*8044SWilliam.Kucharski@Sun.COM
651*8044SWilliam.Kucharski@Sun.COM return 0;
652*8044SWilliam.Kucharski@Sun.COM }
653*8044SWilliam.Kucharski@Sun.COM
tg3_init_5401phy_dsp(struct tg3 * tp)654*8044SWilliam.Kucharski@Sun.COM static int tg3_init_5401phy_dsp(struct tg3 *tp)
655*8044SWilliam.Kucharski@Sun.COM {
656*8044SWilliam.Kucharski@Sun.COM int err;
657*8044SWilliam.Kucharski@Sun.COM
658*8044SWilliam.Kucharski@Sun.COM /* Turn off tap power management. */
659*8044SWilliam.Kucharski@Sun.COM err = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c20);
660*8044SWilliam.Kucharski@Sun.COM
661*8044SWilliam.Kucharski@Sun.COM err |= tg3_writedsp(tp, 0x0012, 0x1804);
662*8044SWilliam.Kucharski@Sun.COM err |= tg3_writedsp(tp, 0x0013, 0x1204);
663*8044SWilliam.Kucharski@Sun.COM err |= tg3_writedsp(tp, 0x8006, 0x0132);
664*8044SWilliam.Kucharski@Sun.COM err |= tg3_writedsp(tp, 0x8006, 0x0232);
665*8044SWilliam.Kucharski@Sun.COM err |= tg3_writedsp(tp, 0x201f, 0x0a20);
666*8044SWilliam.Kucharski@Sun.COM
667*8044SWilliam.Kucharski@Sun.COM udelay(40);
668*8044SWilliam.Kucharski@Sun.COM
669*8044SWilliam.Kucharski@Sun.COM return err;
670*8044SWilliam.Kucharski@Sun.COM }
671*8044SWilliam.Kucharski@Sun.COM
tg3_setup_copper_phy(struct tg3 * tp)672*8044SWilliam.Kucharski@Sun.COM static int tg3_setup_copper_phy(struct tg3 *tp)
673*8044SWilliam.Kucharski@Sun.COM {
674*8044SWilliam.Kucharski@Sun.COM int current_link_up;
675*8044SWilliam.Kucharski@Sun.COM uint32_t bmsr, dummy;
676*8044SWilliam.Kucharski@Sun.COM int i, err;
677*8044SWilliam.Kucharski@Sun.COM
678*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_STATUS,
679*8044SWilliam.Kucharski@Sun.COM (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
680*8044SWilliam.Kucharski@Sun.COM
681*8044SWilliam.Kucharski@Sun.COM tp->mi_mode = MAC_MI_MODE_BASE;
682*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MI_MODE, tp->mi_mode);
683*8044SWilliam.Kucharski@Sun.COM
684*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
685*8044SWilliam.Kucharski@Sun.COM
686*8044SWilliam.Kucharski@Sun.COM /* Some third-party PHYs need to be reset on link going
687*8044SWilliam.Kucharski@Sun.COM * down.
688*8044SWilliam.Kucharski@Sun.COM */
689*8044SWilliam.Kucharski@Sun.COM if ( ( (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
690*8044SWilliam.Kucharski@Sun.COM (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
691*8044SWilliam.Kucharski@Sun.COM (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0)) &&
692*8044SWilliam.Kucharski@Sun.COM (tp->carrier_ok)) {
693*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMSR, &bmsr);
694*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMSR, &bmsr);
695*8044SWilliam.Kucharski@Sun.COM if (!(bmsr & BMSR_LSTATUS))
696*8044SWilliam.Kucharski@Sun.COM tg3_phy_reset(tp);
697*8044SWilliam.Kucharski@Sun.COM }
698*8044SWilliam.Kucharski@Sun.COM
699*8044SWilliam.Kucharski@Sun.COM if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
700*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMSR, &bmsr);
701*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMSR, &bmsr);
702*8044SWilliam.Kucharski@Sun.COM
703*8044SWilliam.Kucharski@Sun.COM if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
704*8044SWilliam.Kucharski@Sun.COM bmsr = 0;
705*8044SWilliam.Kucharski@Sun.COM
706*8044SWilliam.Kucharski@Sun.COM if (!(bmsr & BMSR_LSTATUS)) {
707*8044SWilliam.Kucharski@Sun.COM err = tg3_init_5401phy_dsp(tp);
708*8044SWilliam.Kucharski@Sun.COM if (err)
709*8044SWilliam.Kucharski@Sun.COM return err;
710*8044SWilliam.Kucharski@Sun.COM
711*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMSR, &bmsr);
712*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 1000; i++) {
713*8044SWilliam.Kucharski@Sun.COM udelay(10);
714*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMSR, &bmsr);
715*8044SWilliam.Kucharski@Sun.COM if (bmsr & BMSR_LSTATUS) {
716*8044SWilliam.Kucharski@Sun.COM udelay(40);
717*8044SWilliam.Kucharski@Sun.COM break;
718*8044SWilliam.Kucharski@Sun.COM }
719*8044SWilliam.Kucharski@Sun.COM }
720*8044SWilliam.Kucharski@Sun.COM
721*8044SWilliam.Kucharski@Sun.COM if ((tp->phy_id & PHY_ID_REV_MASK) == PHY_REV_BCM5401_B0 &&
722*8044SWilliam.Kucharski@Sun.COM !(bmsr & BMSR_LSTATUS) &&
723*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_speed == SPEED_1000) {
724*8044SWilliam.Kucharski@Sun.COM err = tg3_phy_reset(tp);
725*8044SWilliam.Kucharski@Sun.COM if (!err)
726*8044SWilliam.Kucharski@Sun.COM err = tg3_init_5401phy_dsp(tp);
727*8044SWilliam.Kucharski@Sun.COM if (err)
728*8044SWilliam.Kucharski@Sun.COM return err;
729*8044SWilliam.Kucharski@Sun.COM }
730*8044SWilliam.Kucharski@Sun.COM }
731*8044SWilliam.Kucharski@Sun.COM } else if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
732*8044SWilliam.Kucharski@Sun.COM tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
733*8044SWilliam.Kucharski@Sun.COM /* 5701 {A0,B0} CRC bug workaround */
734*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x15, 0x0a75);
735*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x1c, 0x8c68);
736*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x1c, 0x8d68);
737*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x1c, 0x8c68);
738*8044SWilliam.Kucharski@Sun.COM }
739*8044SWilliam.Kucharski@Sun.COM
740*8044SWilliam.Kucharski@Sun.COM /* Clear pending interrupts... */
741*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
742*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
743*8044SWilliam.Kucharski@Sun.COM
744*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_IMASK, ~0);
745*8044SWilliam.Kucharski@Sun.COM
746*8044SWilliam.Kucharski@Sun.COM if (tp->led_mode == led_mode_three_link)
747*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_EXT_CTRL,
748*8044SWilliam.Kucharski@Sun.COM MII_TG3_EXT_CTRL_LNK3_LED_MODE);
749*8044SWilliam.Kucharski@Sun.COM else
750*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_EXT_CTRL, 0);
751*8044SWilliam.Kucharski@Sun.COM
752*8044SWilliam.Kucharski@Sun.COM current_link_up = 0;
753*8044SWilliam.Kucharski@Sun.COM
754*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMSR, &bmsr);
755*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMSR, &bmsr);
756*8044SWilliam.Kucharski@Sun.COM
757*8044SWilliam.Kucharski@Sun.COM if (bmsr & BMSR_LSTATUS) {
758*8044SWilliam.Kucharski@Sun.COM uint32_t aux_stat, bmcr;
759*8044SWilliam.Kucharski@Sun.COM
760*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
761*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 2000; i++) {
762*8044SWilliam.Kucharski@Sun.COM udelay(10);
763*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
764*8044SWilliam.Kucharski@Sun.COM if (aux_stat)
765*8044SWilliam.Kucharski@Sun.COM break;
766*8044SWilliam.Kucharski@Sun.COM }
767*8044SWilliam.Kucharski@Sun.COM
768*8044SWilliam.Kucharski@Sun.COM tg3_aux_stat_to_speed_duplex(tp, aux_stat,
769*8044SWilliam.Kucharski@Sun.COM &tp->link_config.active_speed,
770*8044SWilliam.Kucharski@Sun.COM &tp->link_config.active_duplex);
771*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMCR, &bmcr);
772*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMCR, &bmcr);
773*8044SWilliam.Kucharski@Sun.COM if (bmcr & BMCR_ANENABLE) {
774*8044SWilliam.Kucharski@Sun.COM uint32_t gig_ctrl;
775*8044SWilliam.Kucharski@Sun.COM
776*8044SWilliam.Kucharski@Sun.COM current_link_up = 1;
777*8044SWilliam.Kucharski@Sun.COM
778*8044SWilliam.Kucharski@Sun.COM /* Force autoneg restart if we are exiting
779*8044SWilliam.Kucharski@Sun.COM * low power mode.
780*8044SWilliam.Kucharski@Sun.COM */
781*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_TG3_CTRL, &gig_ctrl);
782*8044SWilliam.Kucharski@Sun.COM if (!(gig_ctrl & (MII_TG3_CTRL_ADV_1000_HALF |
783*8044SWilliam.Kucharski@Sun.COM MII_TG3_CTRL_ADV_1000_FULL))) {
784*8044SWilliam.Kucharski@Sun.COM current_link_up = 0;
785*8044SWilliam.Kucharski@Sun.COM }
786*8044SWilliam.Kucharski@Sun.COM } else {
787*8044SWilliam.Kucharski@Sun.COM current_link_up = 0;
788*8044SWilliam.Kucharski@Sun.COM }
789*8044SWilliam.Kucharski@Sun.COM }
790*8044SWilliam.Kucharski@Sun.COM
791*8044SWilliam.Kucharski@Sun.COM if (current_link_up == 1 &&
792*8044SWilliam.Kucharski@Sun.COM (tp->link_config.active_duplex == DUPLEX_FULL)) {
793*8044SWilliam.Kucharski@Sun.COM uint32_t local_adv, remote_adv;
794*8044SWilliam.Kucharski@Sun.COM
795*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_ADVERTISE, &local_adv);
796*8044SWilliam.Kucharski@Sun.COM local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
797*8044SWilliam.Kucharski@Sun.COM
798*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_LPA, &remote_adv);
799*8044SWilliam.Kucharski@Sun.COM remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
800*8044SWilliam.Kucharski@Sun.COM
801*8044SWilliam.Kucharski@Sun.COM /* If we are not advertising full pause capability,
802*8044SWilliam.Kucharski@Sun.COM * something is wrong. Bring the link down and reconfigure.
803*8044SWilliam.Kucharski@Sun.COM */
804*8044SWilliam.Kucharski@Sun.COM if (local_adv != ADVERTISE_PAUSE_CAP) {
805*8044SWilliam.Kucharski@Sun.COM current_link_up = 0;
806*8044SWilliam.Kucharski@Sun.COM } else {
807*8044SWilliam.Kucharski@Sun.COM tg3_setup_flow_control(tp, local_adv, remote_adv);
808*8044SWilliam.Kucharski@Sun.COM }
809*8044SWilliam.Kucharski@Sun.COM }
810*8044SWilliam.Kucharski@Sun.COM
811*8044SWilliam.Kucharski@Sun.COM if (current_link_up == 0) {
812*8044SWilliam.Kucharski@Sun.COM uint32_t tmp;
813*8044SWilliam.Kucharski@Sun.COM
814*8044SWilliam.Kucharski@Sun.COM tg3_phy_copper_begin(tp);
815*8044SWilliam.Kucharski@Sun.COM
816*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMSR, &tmp);
817*8044SWilliam.Kucharski@Sun.COM tg3_readphy(tp, MII_BMSR, &tmp);
818*8044SWilliam.Kucharski@Sun.COM if (tmp & BMSR_LSTATUS)
819*8044SWilliam.Kucharski@Sun.COM current_link_up = 1;
820*8044SWilliam.Kucharski@Sun.COM }
821*8044SWilliam.Kucharski@Sun.COM
822*8044SWilliam.Kucharski@Sun.COM tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK;
823*8044SWilliam.Kucharski@Sun.COM if (current_link_up == 1) {
824*8044SWilliam.Kucharski@Sun.COM if (tp->link_config.active_speed == SPEED_100 ||
825*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_speed == SPEED_10)
826*8044SWilliam.Kucharski@Sun.COM tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
827*8044SWilliam.Kucharski@Sun.COM else
828*8044SWilliam.Kucharski@Sun.COM tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
829*8044SWilliam.Kucharski@Sun.COM } else
830*8044SWilliam.Kucharski@Sun.COM tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
831*8044SWilliam.Kucharski@Sun.COM
832*8044SWilliam.Kucharski@Sun.COM tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
833*8044SWilliam.Kucharski@Sun.COM if (tp->link_config.active_duplex == DUPLEX_HALF)
834*8044SWilliam.Kucharski@Sun.COM tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
835*8044SWilliam.Kucharski@Sun.COM
836*8044SWilliam.Kucharski@Sun.COM tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
837*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
838*8044SWilliam.Kucharski@Sun.COM if ((tp->led_mode == led_mode_link10) ||
839*8044SWilliam.Kucharski@Sun.COM (current_link_up == 1 &&
840*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_speed == SPEED_10))
841*8044SWilliam.Kucharski@Sun.COM tp->mac_mode |= MAC_MODE_LINK_POLARITY;
842*8044SWilliam.Kucharski@Sun.COM } else {
843*8044SWilliam.Kucharski@Sun.COM if (current_link_up == 1)
844*8044SWilliam.Kucharski@Sun.COM tp->mac_mode |= MAC_MODE_LINK_POLARITY;
845*8044SWilliam.Kucharski@Sun.COM tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1);
846*8044SWilliam.Kucharski@Sun.COM }
847*8044SWilliam.Kucharski@Sun.COM
848*8044SWilliam.Kucharski@Sun.COM /* ??? Without this setting Netgear GA302T PHY does not
849*8044SWilliam.Kucharski@Sun.COM * ??? send/receive packets...
850*8044SWilliam.Kucharski@Sun.COM * With this other PHYs cannot bring up the link
851*8044SWilliam.Kucharski@Sun.COM */
852*8044SWilliam.Kucharski@Sun.COM if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411 &&
853*8044SWilliam.Kucharski@Sun.COM tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
854*8044SWilliam.Kucharski@Sun.COM tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
855*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MI_MODE, tp->mi_mode);
856*8044SWilliam.Kucharski@Sun.COM }
857*8044SWilliam.Kucharski@Sun.COM
858*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
859*8044SWilliam.Kucharski@Sun.COM
860*8044SWilliam.Kucharski@Sun.COM /* Link change polled. */
861*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_EVENT, 0);
862*8044SWilliam.Kucharski@Sun.COM
863*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
864*8044SWilliam.Kucharski@Sun.COM current_link_up == 1 &&
865*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_speed == SPEED_1000 &&
866*8044SWilliam.Kucharski@Sun.COM ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ||
867*8044SWilliam.Kucharski@Sun.COM (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) {
868*8044SWilliam.Kucharski@Sun.COM udelay(120);
869*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_STATUS,
870*8044SWilliam.Kucharski@Sun.COM (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
871*8044SWilliam.Kucharski@Sun.COM tg3_write_mem(
872*8044SWilliam.Kucharski@Sun.COM NIC_SRAM_FIRMWARE_MBOX,
873*8044SWilliam.Kucharski@Sun.COM NIC_SRAM_FIRMWARE_MBOX_MAGIC2);
874*8044SWilliam.Kucharski@Sun.COM }
875*8044SWilliam.Kucharski@Sun.COM
876*8044SWilliam.Kucharski@Sun.COM if (current_link_up != tp->carrier_ok) {
877*8044SWilliam.Kucharski@Sun.COM tp->carrier_ok = current_link_up;
878*8044SWilliam.Kucharski@Sun.COM tg3_link_report(tp);
879*8044SWilliam.Kucharski@Sun.COM }
880*8044SWilliam.Kucharski@Sun.COM
881*8044SWilliam.Kucharski@Sun.COM return 0;
882*8044SWilliam.Kucharski@Sun.COM }
883*8044SWilliam.Kucharski@Sun.COM #else
884*8044SWilliam.Kucharski@Sun.COM #define tg3_setup_copper_phy(TP) (-EINVAL)
885*8044SWilliam.Kucharski@Sun.COM #endif /* SUPPORT_COPPER_PHY */
886*8044SWilliam.Kucharski@Sun.COM
887*8044SWilliam.Kucharski@Sun.COM #if SUPPORT_FIBER_PHY
888*8044SWilliam.Kucharski@Sun.COM struct tg3_fiber_aneginfo {
889*8044SWilliam.Kucharski@Sun.COM int state;
890*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_UNKNOWN 0
891*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_AN_ENABLE 1
892*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_RESTART_INIT 2
893*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_RESTART 3
894*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_DISABLE_LINK_OK 4
895*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_ABILITY_DETECT_INIT 5
896*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_ABILITY_DETECT 6
897*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_ACK_DETECT_INIT 7
898*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_ACK_DETECT 8
899*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_COMPLETE_ACK_INIT 9
900*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_COMPLETE_ACK 10
901*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_IDLE_DETECT_INIT 11
902*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_IDLE_DETECT 12
903*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_LINK_OK 13
904*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_NEXT_PAGE_WAIT_INIT 14
905*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_NEXT_PAGE_WAIT 15
906*8044SWilliam.Kucharski@Sun.COM
907*8044SWilliam.Kucharski@Sun.COM uint32_t flags;
908*8044SWilliam.Kucharski@Sun.COM #define MR_AN_ENABLE 0x00000001
909*8044SWilliam.Kucharski@Sun.COM #define MR_RESTART_AN 0x00000002
910*8044SWilliam.Kucharski@Sun.COM #define MR_AN_COMPLETE 0x00000004
911*8044SWilliam.Kucharski@Sun.COM #define MR_PAGE_RX 0x00000008
912*8044SWilliam.Kucharski@Sun.COM #define MR_NP_LOADED 0x00000010
913*8044SWilliam.Kucharski@Sun.COM #define MR_TOGGLE_TX 0x00000020
914*8044SWilliam.Kucharski@Sun.COM #define MR_LP_ADV_FULL_DUPLEX 0x00000040
915*8044SWilliam.Kucharski@Sun.COM #define MR_LP_ADV_HALF_DUPLEX 0x00000080
916*8044SWilliam.Kucharski@Sun.COM #define MR_LP_ADV_SYM_PAUSE 0x00000100
917*8044SWilliam.Kucharski@Sun.COM #define MR_LP_ADV_ASYM_PAUSE 0x00000200
918*8044SWilliam.Kucharski@Sun.COM #define MR_LP_ADV_REMOTE_FAULT1 0x00000400
919*8044SWilliam.Kucharski@Sun.COM #define MR_LP_ADV_REMOTE_FAULT2 0x00000800
920*8044SWilliam.Kucharski@Sun.COM #define MR_LP_ADV_NEXT_PAGE 0x00001000
921*8044SWilliam.Kucharski@Sun.COM #define MR_TOGGLE_RX 0x00002000
922*8044SWilliam.Kucharski@Sun.COM #define MR_NP_RX 0x00004000
923*8044SWilliam.Kucharski@Sun.COM
924*8044SWilliam.Kucharski@Sun.COM #define MR_LINK_OK 0x80000000
925*8044SWilliam.Kucharski@Sun.COM
926*8044SWilliam.Kucharski@Sun.COM unsigned long link_time, cur_time;
927*8044SWilliam.Kucharski@Sun.COM
928*8044SWilliam.Kucharski@Sun.COM uint32_t ability_match_cfg;
929*8044SWilliam.Kucharski@Sun.COM int ability_match_count;
930*8044SWilliam.Kucharski@Sun.COM
931*8044SWilliam.Kucharski@Sun.COM char ability_match, idle_match, ack_match;
932*8044SWilliam.Kucharski@Sun.COM
933*8044SWilliam.Kucharski@Sun.COM uint32_t txconfig, rxconfig;
934*8044SWilliam.Kucharski@Sun.COM #define ANEG_CFG_NP 0x00000080
935*8044SWilliam.Kucharski@Sun.COM #define ANEG_CFG_ACK 0x00000040
936*8044SWilliam.Kucharski@Sun.COM #define ANEG_CFG_RF2 0x00000020
937*8044SWilliam.Kucharski@Sun.COM #define ANEG_CFG_RF1 0x00000010
938*8044SWilliam.Kucharski@Sun.COM #define ANEG_CFG_PS2 0x00000001
939*8044SWilliam.Kucharski@Sun.COM #define ANEG_CFG_PS1 0x00008000
940*8044SWilliam.Kucharski@Sun.COM #define ANEG_CFG_HD 0x00004000
941*8044SWilliam.Kucharski@Sun.COM #define ANEG_CFG_FD 0x00002000
942*8044SWilliam.Kucharski@Sun.COM #define ANEG_CFG_INVAL 0x00001f06
943*8044SWilliam.Kucharski@Sun.COM
944*8044SWilliam.Kucharski@Sun.COM };
945*8044SWilliam.Kucharski@Sun.COM #define ANEG_OK 0
946*8044SWilliam.Kucharski@Sun.COM #define ANEG_DONE 1
947*8044SWilliam.Kucharski@Sun.COM #define ANEG_TIMER_ENAB 2
948*8044SWilliam.Kucharski@Sun.COM #define ANEG_FAILED -1
949*8044SWilliam.Kucharski@Sun.COM
950*8044SWilliam.Kucharski@Sun.COM #define ANEG_STATE_SETTLE_TIME 10000
951*8044SWilliam.Kucharski@Sun.COM
tg3_fiber_aneg_smachine(struct tg3 * tp,struct tg3_fiber_aneginfo * ap)952*8044SWilliam.Kucharski@Sun.COM static int tg3_fiber_aneg_smachine(struct tg3 *tp,
953*8044SWilliam.Kucharski@Sun.COM struct tg3_fiber_aneginfo *ap)
954*8044SWilliam.Kucharski@Sun.COM {
955*8044SWilliam.Kucharski@Sun.COM unsigned long delta;
956*8044SWilliam.Kucharski@Sun.COM uint32_t rx_cfg_reg;
957*8044SWilliam.Kucharski@Sun.COM int ret;
958*8044SWilliam.Kucharski@Sun.COM
959*8044SWilliam.Kucharski@Sun.COM if (ap->state == ANEG_STATE_UNKNOWN) {
960*8044SWilliam.Kucharski@Sun.COM ap->rxconfig = 0;
961*8044SWilliam.Kucharski@Sun.COM ap->link_time = 0;
962*8044SWilliam.Kucharski@Sun.COM ap->cur_time = 0;
963*8044SWilliam.Kucharski@Sun.COM ap->ability_match_cfg = 0;
964*8044SWilliam.Kucharski@Sun.COM ap->ability_match_count = 0;
965*8044SWilliam.Kucharski@Sun.COM ap->ability_match = 0;
966*8044SWilliam.Kucharski@Sun.COM ap->idle_match = 0;
967*8044SWilliam.Kucharski@Sun.COM ap->ack_match = 0;
968*8044SWilliam.Kucharski@Sun.COM }
969*8044SWilliam.Kucharski@Sun.COM ap->cur_time++;
970*8044SWilliam.Kucharski@Sun.COM
971*8044SWilliam.Kucharski@Sun.COM if (tr32(MAC_STATUS) & MAC_STATUS_RCVD_CFG) {
972*8044SWilliam.Kucharski@Sun.COM rx_cfg_reg = tr32(MAC_RX_AUTO_NEG);
973*8044SWilliam.Kucharski@Sun.COM
974*8044SWilliam.Kucharski@Sun.COM if (rx_cfg_reg != ap->ability_match_cfg) {
975*8044SWilliam.Kucharski@Sun.COM ap->ability_match_cfg = rx_cfg_reg;
976*8044SWilliam.Kucharski@Sun.COM ap->ability_match = 0;
977*8044SWilliam.Kucharski@Sun.COM ap->ability_match_count = 0;
978*8044SWilliam.Kucharski@Sun.COM } else {
979*8044SWilliam.Kucharski@Sun.COM if (++ap->ability_match_count > 1) {
980*8044SWilliam.Kucharski@Sun.COM ap->ability_match = 1;
981*8044SWilliam.Kucharski@Sun.COM ap->ability_match_cfg = rx_cfg_reg;
982*8044SWilliam.Kucharski@Sun.COM }
983*8044SWilliam.Kucharski@Sun.COM }
984*8044SWilliam.Kucharski@Sun.COM if (rx_cfg_reg & ANEG_CFG_ACK)
985*8044SWilliam.Kucharski@Sun.COM ap->ack_match = 1;
986*8044SWilliam.Kucharski@Sun.COM else
987*8044SWilliam.Kucharski@Sun.COM ap->ack_match = 0;
988*8044SWilliam.Kucharski@Sun.COM
989*8044SWilliam.Kucharski@Sun.COM ap->idle_match = 0;
990*8044SWilliam.Kucharski@Sun.COM } else {
991*8044SWilliam.Kucharski@Sun.COM ap->idle_match = 1;
992*8044SWilliam.Kucharski@Sun.COM ap->ability_match_cfg = 0;
993*8044SWilliam.Kucharski@Sun.COM ap->ability_match_count = 0;
994*8044SWilliam.Kucharski@Sun.COM ap->ability_match = 0;
995*8044SWilliam.Kucharski@Sun.COM ap->ack_match = 0;
996*8044SWilliam.Kucharski@Sun.COM
997*8044SWilliam.Kucharski@Sun.COM rx_cfg_reg = 0;
998*8044SWilliam.Kucharski@Sun.COM }
999*8044SWilliam.Kucharski@Sun.COM
1000*8044SWilliam.Kucharski@Sun.COM ap->rxconfig = rx_cfg_reg;
1001*8044SWilliam.Kucharski@Sun.COM ret = ANEG_OK;
1002*8044SWilliam.Kucharski@Sun.COM
1003*8044SWilliam.Kucharski@Sun.COM switch(ap->state) {
1004*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_UNKNOWN:
1005*8044SWilliam.Kucharski@Sun.COM if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN))
1006*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_AN_ENABLE;
1007*8044SWilliam.Kucharski@Sun.COM
1008*8044SWilliam.Kucharski@Sun.COM /* fallthru */
1009*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_AN_ENABLE:
1010*8044SWilliam.Kucharski@Sun.COM ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX);
1011*8044SWilliam.Kucharski@Sun.COM if (ap->flags & MR_AN_ENABLE) {
1012*8044SWilliam.Kucharski@Sun.COM ap->link_time = 0;
1013*8044SWilliam.Kucharski@Sun.COM ap->cur_time = 0;
1014*8044SWilliam.Kucharski@Sun.COM ap->ability_match_cfg = 0;
1015*8044SWilliam.Kucharski@Sun.COM ap->ability_match_count = 0;
1016*8044SWilliam.Kucharski@Sun.COM ap->ability_match = 0;
1017*8044SWilliam.Kucharski@Sun.COM ap->idle_match = 0;
1018*8044SWilliam.Kucharski@Sun.COM ap->ack_match = 0;
1019*8044SWilliam.Kucharski@Sun.COM
1020*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_RESTART_INIT;
1021*8044SWilliam.Kucharski@Sun.COM } else {
1022*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_DISABLE_LINK_OK;
1023*8044SWilliam.Kucharski@Sun.COM }
1024*8044SWilliam.Kucharski@Sun.COM break;
1025*8044SWilliam.Kucharski@Sun.COM
1026*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_RESTART_INIT:
1027*8044SWilliam.Kucharski@Sun.COM ap->link_time = ap->cur_time;
1028*8044SWilliam.Kucharski@Sun.COM ap->flags &= ~(MR_NP_LOADED);
1029*8044SWilliam.Kucharski@Sun.COM ap->txconfig = 0;
1030*8044SWilliam.Kucharski@Sun.COM tw32(MAC_TX_AUTO_NEG, 0);
1031*8044SWilliam.Kucharski@Sun.COM tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
1032*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
1033*8044SWilliam.Kucharski@Sun.COM
1034*8044SWilliam.Kucharski@Sun.COM ret = ANEG_TIMER_ENAB;
1035*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_RESTART;
1036*8044SWilliam.Kucharski@Sun.COM
1037*8044SWilliam.Kucharski@Sun.COM /* fallthru */
1038*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_RESTART:
1039*8044SWilliam.Kucharski@Sun.COM delta = ap->cur_time - ap->link_time;
1040*8044SWilliam.Kucharski@Sun.COM if (delta > ANEG_STATE_SETTLE_TIME) {
1041*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_ABILITY_DETECT_INIT;
1042*8044SWilliam.Kucharski@Sun.COM } else {
1043*8044SWilliam.Kucharski@Sun.COM ret = ANEG_TIMER_ENAB;
1044*8044SWilliam.Kucharski@Sun.COM }
1045*8044SWilliam.Kucharski@Sun.COM break;
1046*8044SWilliam.Kucharski@Sun.COM
1047*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_DISABLE_LINK_OK:
1048*8044SWilliam.Kucharski@Sun.COM ret = ANEG_DONE;
1049*8044SWilliam.Kucharski@Sun.COM break;
1050*8044SWilliam.Kucharski@Sun.COM
1051*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_ABILITY_DETECT_INIT:
1052*8044SWilliam.Kucharski@Sun.COM ap->flags &= ~(MR_TOGGLE_TX);
1053*8044SWilliam.Kucharski@Sun.COM ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
1054*8044SWilliam.Kucharski@Sun.COM tw32(MAC_TX_AUTO_NEG, ap->txconfig);
1055*8044SWilliam.Kucharski@Sun.COM tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
1056*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
1057*8044SWilliam.Kucharski@Sun.COM
1058*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_ABILITY_DETECT;
1059*8044SWilliam.Kucharski@Sun.COM break;
1060*8044SWilliam.Kucharski@Sun.COM
1061*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_ABILITY_DETECT:
1062*8044SWilliam.Kucharski@Sun.COM if (ap->ability_match != 0 && ap->rxconfig != 0) {
1063*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_ACK_DETECT_INIT;
1064*8044SWilliam.Kucharski@Sun.COM }
1065*8044SWilliam.Kucharski@Sun.COM break;
1066*8044SWilliam.Kucharski@Sun.COM
1067*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_ACK_DETECT_INIT:
1068*8044SWilliam.Kucharski@Sun.COM ap->txconfig |= ANEG_CFG_ACK;
1069*8044SWilliam.Kucharski@Sun.COM tw32(MAC_TX_AUTO_NEG, ap->txconfig);
1070*8044SWilliam.Kucharski@Sun.COM tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
1071*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
1072*8044SWilliam.Kucharski@Sun.COM
1073*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_ACK_DETECT;
1074*8044SWilliam.Kucharski@Sun.COM
1075*8044SWilliam.Kucharski@Sun.COM /* fallthru */
1076*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_ACK_DETECT:
1077*8044SWilliam.Kucharski@Sun.COM if (ap->ack_match != 0) {
1078*8044SWilliam.Kucharski@Sun.COM if ((ap->rxconfig & ~ANEG_CFG_ACK) ==
1079*8044SWilliam.Kucharski@Sun.COM (ap->ability_match_cfg & ~ANEG_CFG_ACK)) {
1080*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_COMPLETE_ACK_INIT;
1081*8044SWilliam.Kucharski@Sun.COM } else {
1082*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_AN_ENABLE;
1083*8044SWilliam.Kucharski@Sun.COM }
1084*8044SWilliam.Kucharski@Sun.COM } else if (ap->ability_match != 0 &&
1085*8044SWilliam.Kucharski@Sun.COM ap->rxconfig == 0) {
1086*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_AN_ENABLE;
1087*8044SWilliam.Kucharski@Sun.COM }
1088*8044SWilliam.Kucharski@Sun.COM break;
1089*8044SWilliam.Kucharski@Sun.COM
1090*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_COMPLETE_ACK_INIT:
1091*8044SWilliam.Kucharski@Sun.COM if (ap->rxconfig & ANEG_CFG_INVAL) {
1092*8044SWilliam.Kucharski@Sun.COM ret = ANEG_FAILED;
1093*8044SWilliam.Kucharski@Sun.COM break;
1094*8044SWilliam.Kucharski@Sun.COM }
1095*8044SWilliam.Kucharski@Sun.COM ap->flags &= ~(MR_LP_ADV_FULL_DUPLEX |
1096*8044SWilliam.Kucharski@Sun.COM MR_LP_ADV_HALF_DUPLEX |
1097*8044SWilliam.Kucharski@Sun.COM MR_LP_ADV_SYM_PAUSE |
1098*8044SWilliam.Kucharski@Sun.COM MR_LP_ADV_ASYM_PAUSE |
1099*8044SWilliam.Kucharski@Sun.COM MR_LP_ADV_REMOTE_FAULT1 |
1100*8044SWilliam.Kucharski@Sun.COM MR_LP_ADV_REMOTE_FAULT2 |
1101*8044SWilliam.Kucharski@Sun.COM MR_LP_ADV_NEXT_PAGE |
1102*8044SWilliam.Kucharski@Sun.COM MR_TOGGLE_RX |
1103*8044SWilliam.Kucharski@Sun.COM MR_NP_RX);
1104*8044SWilliam.Kucharski@Sun.COM if (ap->rxconfig & ANEG_CFG_FD)
1105*8044SWilliam.Kucharski@Sun.COM ap->flags |= MR_LP_ADV_FULL_DUPLEX;
1106*8044SWilliam.Kucharski@Sun.COM if (ap->rxconfig & ANEG_CFG_HD)
1107*8044SWilliam.Kucharski@Sun.COM ap->flags |= MR_LP_ADV_HALF_DUPLEX;
1108*8044SWilliam.Kucharski@Sun.COM if (ap->rxconfig & ANEG_CFG_PS1)
1109*8044SWilliam.Kucharski@Sun.COM ap->flags |= MR_LP_ADV_SYM_PAUSE;
1110*8044SWilliam.Kucharski@Sun.COM if (ap->rxconfig & ANEG_CFG_PS2)
1111*8044SWilliam.Kucharski@Sun.COM ap->flags |= MR_LP_ADV_ASYM_PAUSE;
1112*8044SWilliam.Kucharski@Sun.COM if (ap->rxconfig & ANEG_CFG_RF1)
1113*8044SWilliam.Kucharski@Sun.COM ap->flags |= MR_LP_ADV_REMOTE_FAULT1;
1114*8044SWilliam.Kucharski@Sun.COM if (ap->rxconfig & ANEG_CFG_RF2)
1115*8044SWilliam.Kucharski@Sun.COM ap->flags |= MR_LP_ADV_REMOTE_FAULT2;
1116*8044SWilliam.Kucharski@Sun.COM if (ap->rxconfig & ANEG_CFG_NP)
1117*8044SWilliam.Kucharski@Sun.COM ap->flags |= MR_LP_ADV_NEXT_PAGE;
1118*8044SWilliam.Kucharski@Sun.COM
1119*8044SWilliam.Kucharski@Sun.COM ap->link_time = ap->cur_time;
1120*8044SWilliam.Kucharski@Sun.COM
1121*8044SWilliam.Kucharski@Sun.COM ap->flags ^= (MR_TOGGLE_TX);
1122*8044SWilliam.Kucharski@Sun.COM if (ap->rxconfig & 0x0008)
1123*8044SWilliam.Kucharski@Sun.COM ap->flags |= MR_TOGGLE_RX;
1124*8044SWilliam.Kucharski@Sun.COM if (ap->rxconfig & ANEG_CFG_NP)
1125*8044SWilliam.Kucharski@Sun.COM ap->flags |= MR_NP_RX;
1126*8044SWilliam.Kucharski@Sun.COM ap->flags |= MR_PAGE_RX;
1127*8044SWilliam.Kucharski@Sun.COM
1128*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_COMPLETE_ACK;
1129*8044SWilliam.Kucharski@Sun.COM ret = ANEG_TIMER_ENAB;
1130*8044SWilliam.Kucharski@Sun.COM break;
1131*8044SWilliam.Kucharski@Sun.COM
1132*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_COMPLETE_ACK:
1133*8044SWilliam.Kucharski@Sun.COM if (ap->ability_match != 0 &&
1134*8044SWilliam.Kucharski@Sun.COM ap->rxconfig == 0) {
1135*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_AN_ENABLE;
1136*8044SWilliam.Kucharski@Sun.COM break;
1137*8044SWilliam.Kucharski@Sun.COM }
1138*8044SWilliam.Kucharski@Sun.COM delta = ap->cur_time - ap->link_time;
1139*8044SWilliam.Kucharski@Sun.COM if (delta > ANEG_STATE_SETTLE_TIME) {
1140*8044SWilliam.Kucharski@Sun.COM if (!(ap->flags & (MR_LP_ADV_NEXT_PAGE))) {
1141*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_IDLE_DETECT_INIT;
1142*8044SWilliam.Kucharski@Sun.COM } else {
1143*8044SWilliam.Kucharski@Sun.COM if ((ap->txconfig & ANEG_CFG_NP) == 0 &&
1144*8044SWilliam.Kucharski@Sun.COM !(ap->flags & MR_NP_RX)) {
1145*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_IDLE_DETECT_INIT;
1146*8044SWilliam.Kucharski@Sun.COM } else {
1147*8044SWilliam.Kucharski@Sun.COM ret = ANEG_FAILED;
1148*8044SWilliam.Kucharski@Sun.COM }
1149*8044SWilliam.Kucharski@Sun.COM }
1150*8044SWilliam.Kucharski@Sun.COM }
1151*8044SWilliam.Kucharski@Sun.COM break;
1152*8044SWilliam.Kucharski@Sun.COM
1153*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_IDLE_DETECT_INIT:
1154*8044SWilliam.Kucharski@Sun.COM ap->link_time = ap->cur_time;
1155*8044SWilliam.Kucharski@Sun.COM tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
1156*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
1157*8044SWilliam.Kucharski@Sun.COM
1158*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_IDLE_DETECT;
1159*8044SWilliam.Kucharski@Sun.COM ret = ANEG_TIMER_ENAB;
1160*8044SWilliam.Kucharski@Sun.COM break;
1161*8044SWilliam.Kucharski@Sun.COM
1162*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_IDLE_DETECT:
1163*8044SWilliam.Kucharski@Sun.COM if (ap->ability_match != 0 &&
1164*8044SWilliam.Kucharski@Sun.COM ap->rxconfig == 0) {
1165*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_AN_ENABLE;
1166*8044SWilliam.Kucharski@Sun.COM break;
1167*8044SWilliam.Kucharski@Sun.COM }
1168*8044SWilliam.Kucharski@Sun.COM delta = ap->cur_time - ap->link_time;
1169*8044SWilliam.Kucharski@Sun.COM if (delta > ANEG_STATE_SETTLE_TIME) {
1170*8044SWilliam.Kucharski@Sun.COM /* XXX another gem from the Broadcom driver :( */
1171*8044SWilliam.Kucharski@Sun.COM ap->state = ANEG_STATE_LINK_OK;
1172*8044SWilliam.Kucharski@Sun.COM }
1173*8044SWilliam.Kucharski@Sun.COM break;
1174*8044SWilliam.Kucharski@Sun.COM
1175*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_LINK_OK:
1176*8044SWilliam.Kucharski@Sun.COM ap->flags |= (MR_AN_COMPLETE | MR_LINK_OK);
1177*8044SWilliam.Kucharski@Sun.COM ret = ANEG_DONE;
1178*8044SWilliam.Kucharski@Sun.COM break;
1179*8044SWilliam.Kucharski@Sun.COM
1180*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_NEXT_PAGE_WAIT_INIT:
1181*8044SWilliam.Kucharski@Sun.COM /* ??? unimplemented */
1182*8044SWilliam.Kucharski@Sun.COM break;
1183*8044SWilliam.Kucharski@Sun.COM
1184*8044SWilliam.Kucharski@Sun.COM case ANEG_STATE_NEXT_PAGE_WAIT:
1185*8044SWilliam.Kucharski@Sun.COM /* ??? unimplemented */
1186*8044SWilliam.Kucharski@Sun.COM break;
1187*8044SWilliam.Kucharski@Sun.COM
1188*8044SWilliam.Kucharski@Sun.COM default:
1189*8044SWilliam.Kucharski@Sun.COM ret = ANEG_FAILED;
1190*8044SWilliam.Kucharski@Sun.COM break;
1191*8044SWilliam.Kucharski@Sun.COM };
1192*8044SWilliam.Kucharski@Sun.COM
1193*8044SWilliam.Kucharski@Sun.COM return ret;
1194*8044SWilliam.Kucharski@Sun.COM }
1195*8044SWilliam.Kucharski@Sun.COM
tg3_setup_fiber_phy(struct tg3 * tp)1196*8044SWilliam.Kucharski@Sun.COM static int tg3_setup_fiber_phy(struct tg3 *tp)
1197*8044SWilliam.Kucharski@Sun.COM {
1198*8044SWilliam.Kucharski@Sun.COM uint32_t orig_pause_cfg;
1199*8044SWilliam.Kucharski@Sun.COM uint16_t orig_active_speed;
1200*8044SWilliam.Kucharski@Sun.COM uint8_t orig_active_duplex;
1201*8044SWilliam.Kucharski@Sun.COM int current_link_up;
1202*8044SWilliam.Kucharski@Sun.COM int i;
1203*8044SWilliam.Kucharski@Sun.COM
1204*8044SWilliam.Kucharski@Sun.COM orig_pause_cfg =
1205*8044SWilliam.Kucharski@Sun.COM (tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
1206*8044SWilliam.Kucharski@Sun.COM TG3_FLAG_TX_PAUSE));
1207*8044SWilliam.Kucharski@Sun.COM orig_active_speed = tp->link_config.active_speed;
1208*8044SWilliam.Kucharski@Sun.COM orig_active_duplex = tp->link_config.active_duplex;
1209*8044SWilliam.Kucharski@Sun.COM
1210*8044SWilliam.Kucharski@Sun.COM tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
1211*8044SWilliam.Kucharski@Sun.COM tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
1212*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
1213*8044SWilliam.Kucharski@Sun.COM
1214*8044SWilliam.Kucharski@Sun.COM /* Reset when initting first time or we have a link. */
1215*8044SWilliam.Kucharski@Sun.COM if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
1216*8044SWilliam.Kucharski@Sun.COM (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
1217*8044SWilliam.Kucharski@Sun.COM /* Set PLL lock range. */
1218*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x16, 0x8007);
1219*8044SWilliam.Kucharski@Sun.COM
1220*8044SWilliam.Kucharski@Sun.COM /* SW reset */
1221*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_BMCR, BMCR_RESET);
1222*8044SWilliam.Kucharski@Sun.COM
1223*8044SWilliam.Kucharski@Sun.COM /* Wait for reset to complete. */
1224*8044SWilliam.Kucharski@Sun.COM mdelay(5);
1225*8044SWilliam.Kucharski@Sun.COM
1226*8044SWilliam.Kucharski@Sun.COM /* Config mode; select PMA/Ch 1 regs. */
1227*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x10, 0x8411);
1228*8044SWilliam.Kucharski@Sun.COM
1229*8044SWilliam.Kucharski@Sun.COM /* Enable auto-lock and comdet, select txclk for tx. */
1230*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x11, 0x0a10);
1231*8044SWilliam.Kucharski@Sun.COM
1232*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x18, 0x00a0);
1233*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x16, 0x41ff);
1234*8044SWilliam.Kucharski@Sun.COM
1235*8044SWilliam.Kucharski@Sun.COM /* Assert and deassert POR. */
1236*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x13, 0x0400);
1237*8044SWilliam.Kucharski@Sun.COM udelay(40);
1238*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x13, 0x0000);
1239*8044SWilliam.Kucharski@Sun.COM
1240*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x11, 0x0a50);
1241*8044SWilliam.Kucharski@Sun.COM udelay(40);
1242*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x11, 0x0a10);
1243*8044SWilliam.Kucharski@Sun.COM
1244*8044SWilliam.Kucharski@Sun.COM /* Wait for signal to stabilize */
1245*8044SWilliam.Kucharski@Sun.COM mdelay(150);
1246*8044SWilliam.Kucharski@Sun.COM
1247*8044SWilliam.Kucharski@Sun.COM /* Deselect the channel register so we can read the PHYID
1248*8044SWilliam.Kucharski@Sun.COM * later.
1249*8044SWilliam.Kucharski@Sun.COM */
1250*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x10, 0x8011);
1251*8044SWilliam.Kucharski@Sun.COM }
1252*8044SWilliam.Kucharski@Sun.COM
1253*8044SWilliam.Kucharski@Sun.COM /* Disable link change interrupt. */
1254*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_EVENT, 0);
1255*8044SWilliam.Kucharski@Sun.COM
1256*8044SWilliam.Kucharski@Sun.COM current_link_up = 0;
1257*8044SWilliam.Kucharski@Sun.COM if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
1258*8044SWilliam.Kucharski@Sun.COM if (!(tp->tg3_flags & TG3_FLAG_GOT_SERDES_FLOWCTL)) {
1259*8044SWilliam.Kucharski@Sun.COM struct tg3_fiber_aneginfo aninfo;
1260*8044SWilliam.Kucharski@Sun.COM int status = ANEG_FAILED;
1261*8044SWilliam.Kucharski@Sun.COM unsigned int tick;
1262*8044SWilliam.Kucharski@Sun.COM uint32_t tmp;
1263*8044SWilliam.Kucharski@Sun.COM
1264*8044SWilliam.Kucharski@Sun.COM memset(&aninfo, 0, sizeof(aninfo));
1265*8044SWilliam.Kucharski@Sun.COM aninfo.flags |= (MR_AN_ENABLE);
1266*8044SWilliam.Kucharski@Sun.COM
1267*8044SWilliam.Kucharski@Sun.COM tw32(MAC_TX_AUTO_NEG, 0);
1268*8044SWilliam.Kucharski@Sun.COM
1269*8044SWilliam.Kucharski@Sun.COM tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
1270*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
1271*8044SWilliam.Kucharski@Sun.COM
1272*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
1273*8044SWilliam.Kucharski@Sun.COM
1274*8044SWilliam.Kucharski@Sun.COM aninfo.state = ANEG_STATE_UNKNOWN;
1275*8044SWilliam.Kucharski@Sun.COM aninfo.cur_time = 0;
1276*8044SWilliam.Kucharski@Sun.COM tick = 0;
1277*8044SWilliam.Kucharski@Sun.COM while (++tick < 195000) {
1278*8044SWilliam.Kucharski@Sun.COM status = tg3_fiber_aneg_smachine(tp, &aninfo);
1279*8044SWilliam.Kucharski@Sun.COM if (status == ANEG_DONE ||
1280*8044SWilliam.Kucharski@Sun.COM status == ANEG_FAILED)
1281*8044SWilliam.Kucharski@Sun.COM break;
1282*8044SWilliam.Kucharski@Sun.COM
1283*8044SWilliam.Kucharski@Sun.COM udelay(1);
1284*8044SWilliam.Kucharski@Sun.COM }
1285*8044SWilliam.Kucharski@Sun.COM
1286*8044SWilliam.Kucharski@Sun.COM tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
1287*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
1288*8044SWilliam.Kucharski@Sun.COM
1289*8044SWilliam.Kucharski@Sun.COM if (status == ANEG_DONE &&
1290*8044SWilliam.Kucharski@Sun.COM (aninfo.flags &
1291*8044SWilliam.Kucharski@Sun.COM (MR_AN_COMPLETE | MR_LINK_OK |
1292*8044SWilliam.Kucharski@Sun.COM MR_LP_ADV_FULL_DUPLEX))) {
1293*8044SWilliam.Kucharski@Sun.COM uint32_t local_adv, remote_adv;
1294*8044SWilliam.Kucharski@Sun.COM
1295*8044SWilliam.Kucharski@Sun.COM local_adv = ADVERTISE_PAUSE_CAP;
1296*8044SWilliam.Kucharski@Sun.COM remote_adv = 0;
1297*8044SWilliam.Kucharski@Sun.COM if (aninfo.flags & MR_LP_ADV_SYM_PAUSE)
1298*8044SWilliam.Kucharski@Sun.COM remote_adv |= LPA_PAUSE_CAP;
1299*8044SWilliam.Kucharski@Sun.COM if (aninfo.flags & MR_LP_ADV_ASYM_PAUSE)
1300*8044SWilliam.Kucharski@Sun.COM remote_adv |= LPA_PAUSE_ASYM;
1301*8044SWilliam.Kucharski@Sun.COM
1302*8044SWilliam.Kucharski@Sun.COM tg3_setup_flow_control(tp, local_adv, remote_adv);
1303*8044SWilliam.Kucharski@Sun.COM
1304*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |=
1305*8044SWilliam.Kucharski@Sun.COM TG3_FLAG_GOT_SERDES_FLOWCTL;
1306*8044SWilliam.Kucharski@Sun.COM current_link_up = 1;
1307*8044SWilliam.Kucharski@Sun.COM }
1308*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 60; i++) {
1309*8044SWilliam.Kucharski@Sun.COM udelay(20);
1310*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_STATUS,
1311*8044SWilliam.Kucharski@Sun.COM (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
1312*8044SWilliam.Kucharski@Sun.COM if ((tr32(MAC_STATUS) &
1313*8044SWilliam.Kucharski@Sun.COM (MAC_STATUS_SYNC_CHANGED |
1314*8044SWilliam.Kucharski@Sun.COM MAC_STATUS_CFG_CHANGED)) == 0)
1315*8044SWilliam.Kucharski@Sun.COM break;
1316*8044SWilliam.Kucharski@Sun.COM }
1317*8044SWilliam.Kucharski@Sun.COM if (current_link_up == 0 &&
1318*8044SWilliam.Kucharski@Sun.COM (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
1319*8044SWilliam.Kucharski@Sun.COM current_link_up = 1;
1320*8044SWilliam.Kucharski@Sun.COM }
1321*8044SWilliam.Kucharski@Sun.COM } else {
1322*8044SWilliam.Kucharski@Sun.COM /* Forcing 1000FD link up. */
1323*8044SWilliam.Kucharski@Sun.COM current_link_up = 1;
1324*8044SWilliam.Kucharski@Sun.COM }
1325*8044SWilliam.Kucharski@Sun.COM }
1326*8044SWilliam.Kucharski@Sun.COM
1327*8044SWilliam.Kucharski@Sun.COM tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
1328*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
1329*8044SWilliam.Kucharski@Sun.COM
1330*8044SWilliam.Kucharski@Sun.COM tp->hw_status->status =
1331*8044SWilliam.Kucharski@Sun.COM (SD_STATUS_UPDATED |
1332*8044SWilliam.Kucharski@Sun.COM (tp->hw_status->status & ~SD_STATUS_LINK_CHG));
1333*8044SWilliam.Kucharski@Sun.COM
1334*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 100; i++) {
1335*8044SWilliam.Kucharski@Sun.COM udelay(20);
1336*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_STATUS,
1337*8044SWilliam.Kucharski@Sun.COM (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
1338*8044SWilliam.Kucharski@Sun.COM if ((tr32(MAC_STATUS) &
1339*8044SWilliam.Kucharski@Sun.COM (MAC_STATUS_SYNC_CHANGED |
1340*8044SWilliam.Kucharski@Sun.COM MAC_STATUS_CFG_CHANGED)) == 0)
1341*8044SWilliam.Kucharski@Sun.COM break;
1342*8044SWilliam.Kucharski@Sun.COM }
1343*8044SWilliam.Kucharski@Sun.COM
1344*8044SWilliam.Kucharski@Sun.COM if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0)
1345*8044SWilliam.Kucharski@Sun.COM current_link_up = 0;
1346*8044SWilliam.Kucharski@Sun.COM
1347*8044SWilliam.Kucharski@Sun.COM if (current_link_up == 1) {
1348*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_speed = SPEED_1000;
1349*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_duplex = DUPLEX_FULL;
1350*8044SWilliam.Kucharski@Sun.COM } else {
1351*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_speed = SPEED_INVALID;
1352*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_duplex = DUPLEX_INVALID;
1353*8044SWilliam.Kucharski@Sun.COM }
1354*8044SWilliam.Kucharski@Sun.COM
1355*8044SWilliam.Kucharski@Sun.COM if (current_link_up != tp->carrier_ok) {
1356*8044SWilliam.Kucharski@Sun.COM tp->carrier_ok = current_link_up;
1357*8044SWilliam.Kucharski@Sun.COM tg3_link_report(tp);
1358*8044SWilliam.Kucharski@Sun.COM } else {
1359*8044SWilliam.Kucharski@Sun.COM uint32_t now_pause_cfg =
1360*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
1361*8044SWilliam.Kucharski@Sun.COM TG3_FLAG_TX_PAUSE);
1362*8044SWilliam.Kucharski@Sun.COM if (orig_pause_cfg != now_pause_cfg ||
1363*8044SWilliam.Kucharski@Sun.COM orig_active_speed != tp->link_config.active_speed ||
1364*8044SWilliam.Kucharski@Sun.COM orig_active_duplex != tp->link_config.active_duplex)
1365*8044SWilliam.Kucharski@Sun.COM tg3_link_report(tp);
1366*8044SWilliam.Kucharski@Sun.COM }
1367*8044SWilliam.Kucharski@Sun.COM
1368*8044SWilliam.Kucharski@Sun.COM if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) {
1369*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY);
1370*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
1371*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
1372*8044SWilliam.Kucharski@Sun.COM }
1373*8044SWilliam.Kucharski@Sun.COM }
1374*8044SWilliam.Kucharski@Sun.COM
1375*8044SWilliam.Kucharski@Sun.COM return 0;
1376*8044SWilliam.Kucharski@Sun.COM }
1377*8044SWilliam.Kucharski@Sun.COM #else
1378*8044SWilliam.Kucharski@Sun.COM #define tg3_setup_fiber_phy(TP) (-EINVAL)
1379*8044SWilliam.Kucharski@Sun.COM #endif /* SUPPORT_FIBER_PHY */
1380*8044SWilliam.Kucharski@Sun.COM
tg3_setup_phy(struct tg3 * tp)1381*8044SWilliam.Kucharski@Sun.COM static int tg3_setup_phy(struct tg3 *tp)
1382*8044SWilliam.Kucharski@Sun.COM {
1383*8044SWilliam.Kucharski@Sun.COM int err;
1384*8044SWilliam.Kucharski@Sun.COM
1385*8044SWilliam.Kucharski@Sun.COM if (tp->phy_id == PHY_ID_SERDES) {
1386*8044SWilliam.Kucharski@Sun.COM err = tg3_setup_fiber_phy(tp);
1387*8044SWilliam.Kucharski@Sun.COM } else {
1388*8044SWilliam.Kucharski@Sun.COM err = tg3_setup_copper_phy(tp);
1389*8044SWilliam.Kucharski@Sun.COM }
1390*8044SWilliam.Kucharski@Sun.COM
1391*8044SWilliam.Kucharski@Sun.COM if (tp->link_config.active_speed == SPEED_1000 &&
1392*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_duplex == DUPLEX_HALF)
1393*8044SWilliam.Kucharski@Sun.COM tw32(MAC_TX_LENGTHS,
1394*8044SWilliam.Kucharski@Sun.COM ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
1395*8044SWilliam.Kucharski@Sun.COM (6 << TX_LENGTHS_IPG_SHIFT) |
1396*8044SWilliam.Kucharski@Sun.COM (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)));
1397*8044SWilliam.Kucharski@Sun.COM else
1398*8044SWilliam.Kucharski@Sun.COM tw32(MAC_TX_LENGTHS,
1399*8044SWilliam.Kucharski@Sun.COM ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
1400*8044SWilliam.Kucharski@Sun.COM (6 << TX_LENGTHS_IPG_SHIFT) |
1401*8044SWilliam.Kucharski@Sun.COM (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
1402*8044SWilliam.Kucharski@Sun.COM
1403*8044SWilliam.Kucharski@Sun.COM return err;
1404*8044SWilliam.Kucharski@Sun.COM }
1405*8044SWilliam.Kucharski@Sun.COM
1406*8044SWilliam.Kucharski@Sun.COM
1407*8044SWilliam.Kucharski@Sun.COM #define MAX_WAIT_CNT 1000
1408*8044SWilliam.Kucharski@Sun.COM
1409*8044SWilliam.Kucharski@Sun.COM /* To stop a block, clear the enable bit and poll till it
1410*8044SWilliam.Kucharski@Sun.COM * clears.
1411*8044SWilliam.Kucharski@Sun.COM */
tg3_stop_block(struct tg3 * tp,unsigned long ofs,uint32_t enable_bit)1412*8044SWilliam.Kucharski@Sun.COM static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, uint32_t enable_bit)
1413*8044SWilliam.Kucharski@Sun.COM {
1414*8044SWilliam.Kucharski@Sun.COM unsigned int i;
1415*8044SWilliam.Kucharski@Sun.COM uint32_t val;
1416*8044SWilliam.Kucharski@Sun.COM
1417*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
1418*8044SWilliam.Kucharski@Sun.COM switch(ofs) {
1419*8044SWilliam.Kucharski@Sun.COM case RCVLSC_MODE:
1420*8044SWilliam.Kucharski@Sun.COM case DMAC_MODE:
1421*8044SWilliam.Kucharski@Sun.COM case MBFREE_MODE:
1422*8044SWilliam.Kucharski@Sun.COM case BUFMGR_MODE:
1423*8044SWilliam.Kucharski@Sun.COM case MEMARB_MODE:
1424*8044SWilliam.Kucharski@Sun.COM /* We can't enable/disable these bits of the
1425*8044SWilliam.Kucharski@Sun.COM * 5705, just say success.
1426*8044SWilliam.Kucharski@Sun.COM */
1427*8044SWilliam.Kucharski@Sun.COM return 0;
1428*8044SWilliam.Kucharski@Sun.COM default:
1429*8044SWilliam.Kucharski@Sun.COM break;
1430*8044SWilliam.Kucharski@Sun.COM }
1431*8044SWilliam.Kucharski@Sun.COM }
1432*8044SWilliam.Kucharski@Sun.COM val = tr32(ofs);
1433*8044SWilliam.Kucharski@Sun.COM val &= ~enable_bit;
1434*8044SWilliam.Kucharski@Sun.COM tw32(ofs, val);
1435*8044SWilliam.Kucharski@Sun.COM tr32(ofs);
1436*8044SWilliam.Kucharski@Sun.COM
1437*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < MAX_WAIT_CNT; i++) {
1438*8044SWilliam.Kucharski@Sun.COM udelay(100);
1439*8044SWilliam.Kucharski@Sun.COM val = tr32(ofs);
1440*8044SWilliam.Kucharski@Sun.COM if ((val & enable_bit) == 0)
1441*8044SWilliam.Kucharski@Sun.COM break;
1442*8044SWilliam.Kucharski@Sun.COM }
1443*8044SWilliam.Kucharski@Sun.COM
1444*8044SWilliam.Kucharski@Sun.COM if (i == MAX_WAIT_CNT) {
1445*8044SWilliam.Kucharski@Sun.COM printf("tg3_stop_block timed out, ofs=%lx enable_bit=%x\n",
1446*8044SWilliam.Kucharski@Sun.COM ofs, enable_bit);
1447*8044SWilliam.Kucharski@Sun.COM return -ENODEV;
1448*8044SWilliam.Kucharski@Sun.COM }
1449*8044SWilliam.Kucharski@Sun.COM
1450*8044SWilliam.Kucharski@Sun.COM return 0;
1451*8044SWilliam.Kucharski@Sun.COM }
1452*8044SWilliam.Kucharski@Sun.COM
tg3_abort_hw(struct tg3 * tp)1453*8044SWilliam.Kucharski@Sun.COM static int tg3_abort_hw(struct tg3 *tp)
1454*8044SWilliam.Kucharski@Sun.COM {
1455*8044SWilliam.Kucharski@Sun.COM int i, err;
1456*8044SWilliam.Kucharski@Sun.COM
1457*8044SWilliam.Kucharski@Sun.COM tg3_disable_ints(tp);
1458*8044SWilliam.Kucharski@Sun.COM
1459*8044SWilliam.Kucharski@Sun.COM tp->rx_mode &= ~RX_MODE_ENABLE;
1460*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_RX_MODE, tp->rx_mode);
1461*8044SWilliam.Kucharski@Sun.COM
1462*8044SWilliam.Kucharski@Sun.COM err = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE);
1463*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, RCVLPC_MODE, RCVLPC_MODE_ENABLE);
1464*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, RCVLSC_MODE, RCVLSC_MODE_ENABLE);
1465*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, RCVDBDI_MODE, RCVDBDI_MODE_ENABLE);
1466*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, RCVDCC_MODE, RCVDCC_MODE_ENABLE);
1467*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, RCVCC_MODE, RCVCC_MODE_ENABLE);
1468*8044SWilliam.Kucharski@Sun.COM
1469*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, SNDBDS_MODE, SNDBDS_MODE_ENABLE);
1470*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, SNDBDI_MODE, SNDBDI_MODE_ENABLE);
1471*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
1472*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, RDMAC_MODE, RDMAC_MODE_ENABLE);
1473*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
1474*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, SNDBDC_MODE, SNDBDC_MODE_ENABLE);
1475*8044SWilliam.Kucharski@Sun.COM if (err)
1476*8044SWilliam.Kucharski@Sun.COM goto out;
1477*8044SWilliam.Kucharski@Sun.COM
1478*8044SWilliam.Kucharski@Sun.COM tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
1479*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
1480*8044SWilliam.Kucharski@Sun.COM
1481*8044SWilliam.Kucharski@Sun.COM tp->tx_mode &= ~TX_MODE_ENABLE;
1482*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_TX_MODE, tp->tx_mode);
1483*8044SWilliam.Kucharski@Sun.COM
1484*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < MAX_WAIT_CNT; i++) {
1485*8044SWilliam.Kucharski@Sun.COM udelay(100);
1486*8044SWilliam.Kucharski@Sun.COM if (!(tr32(MAC_TX_MODE) & TX_MODE_ENABLE))
1487*8044SWilliam.Kucharski@Sun.COM break;
1488*8044SWilliam.Kucharski@Sun.COM }
1489*8044SWilliam.Kucharski@Sun.COM if (i >= MAX_WAIT_CNT) {
1490*8044SWilliam.Kucharski@Sun.COM printf("tg3_abort_hw timed out TX_MODE_ENABLE will not clear MAC_TX_MODE=%x\n",
1491*8044SWilliam.Kucharski@Sun.COM tr32(MAC_TX_MODE));
1492*8044SWilliam.Kucharski@Sun.COM return -ENODEV;
1493*8044SWilliam.Kucharski@Sun.COM }
1494*8044SWilliam.Kucharski@Sun.COM
1495*8044SWilliam.Kucharski@Sun.COM err = tg3_stop_block(tp, HOSTCC_MODE, HOSTCC_MODE_ENABLE);
1496*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, WDMAC_MODE, WDMAC_MODE_ENABLE);
1497*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, MBFREE_MODE, MBFREE_MODE_ENABLE);
1498*8044SWilliam.Kucharski@Sun.COM
1499*8044SWilliam.Kucharski@Sun.COM tw32(FTQ_RESET, 0xffffffff);
1500*8044SWilliam.Kucharski@Sun.COM tw32(FTQ_RESET, 0x00000000);
1501*8044SWilliam.Kucharski@Sun.COM
1502*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE);
1503*8044SWilliam.Kucharski@Sun.COM err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE);
1504*8044SWilliam.Kucharski@Sun.COM if (err)
1505*8044SWilliam.Kucharski@Sun.COM goto out;
1506*8044SWilliam.Kucharski@Sun.COM
1507*8044SWilliam.Kucharski@Sun.COM memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
1508*8044SWilliam.Kucharski@Sun.COM
1509*8044SWilliam.Kucharski@Sun.COM out:
1510*8044SWilliam.Kucharski@Sun.COM return err;
1511*8044SWilliam.Kucharski@Sun.COM }
1512*8044SWilliam.Kucharski@Sun.COM
tg3_chip_reset(struct tg3 * tp)1513*8044SWilliam.Kucharski@Sun.COM static void tg3_chip_reset(struct tg3 *tp)
1514*8044SWilliam.Kucharski@Sun.COM {
1515*8044SWilliam.Kucharski@Sun.COM uint32_t val;
1516*8044SWilliam.Kucharski@Sun.COM
1517*8044SWilliam.Kucharski@Sun.COM if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
1518*8044SWilliam.Kucharski@Sun.COM /* Force NVRAM to settle.
1519*8044SWilliam.Kucharski@Sun.COM * This deals with a chip bug which can result in EEPROM
1520*8044SWilliam.Kucharski@Sun.COM * corruption.
1521*8044SWilliam.Kucharski@Sun.COM */
1522*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags & TG3_FLAG_NVRAM) {
1523*8044SWilliam.Kucharski@Sun.COM int i;
1524*8044SWilliam.Kucharski@Sun.COM
1525*8044SWilliam.Kucharski@Sun.COM tw32(NVRAM_SWARB, SWARB_REQ_SET1);
1526*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 100000; i++) {
1527*8044SWilliam.Kucharski@Sun.COM if (tr32(NVRAM_SWARB) & SWARB_GNT1)
1528*8044SWilliam.Kucharski@Sun.COM break;
1529*8044SWilliam.Kucharski@Sun.COM udelay(10);
1530*8044SWilliam.Kucharski@Sun.COM }
1531*8044SWilliam.Kucharski@Sun.COM }
1532*8044SWilliam.Kucharski@Sun.COM }
1533*8044SWilliam.Kucharski@Sun.COM /* In Etherboot we don't need to worry about the 5701
1534*8044SWilliam.Kucharski@Sun.COM * REG_WRITE_BUG because we do all register writes indirectly.
1535*8044SWilliam.Kucharski@Sun.COM */
1536*8044SWilliam.Kucharski@Sun.COM
1537*8044SWilliam.Kucharski@Sun.COM /* do the reset */
1538*8044SWilliam.Kucharski@Sun.COM val = GRC_MISC_CFG_CORECLK_RESET;
1539*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
1540*8044SWilliam.Kucharski@Sun.COM val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
1541*8044SWilliam.Kucharski@Sun.COM tw32(GRC_MISC_CFG, val);
1542*8044SWilliam.Kucharski@Sun.COM
1543*8044SWilliam.Kucharski@Sun.COM /* Flush PCI posted writes. The normal MMIO registers
1544*8044SWilliam.Kucharski@Sun.COM * are inaccessible at this time so this is the only
1545*8044SWilliam.Kucharski@Sun.COM * way to make this reliably. I tried to use indirect
1546*8044SWilliam.Kucharski@Sun.COM * register read/write but this upset some 5701 variants.
1547*8044SWilliam.Kucharski@Sun.COM */
1548*8044SWilliam.Kucharski@Sun.COM pci_read_config_dword(tp->pdev, PCI_COMMAND, &val);
1549*8044SWilliam.Kucharski@Sun.COM
1550*8044SWilliam.Kucharski@Sun.COM udelay(120);
1551*8044SWilliam.Kucharski@Sun.COM
1552*8044SWilliam.Kucharski@Sun.COM /* Re-enable indirect register accesses. */
1553*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
1554*8044SWilliam.Kucharski@Sun.COM tp->misc_host_ctrl);
1555*8044SWilliam.Kucharski@Sun.COM
1556*8044SWilliam.Kucharski@Sun.COM /* Set MAX PCI retry to zero. */
1557*8044SWilliam.Kucharski@Sun.COM val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
1558*8044SWilliam.Kucharski@Sun.COM if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
1559*8044SWilliam.Kucharski@Sun.COM (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
1560*8044SWilliam.Kucharski@Sun.COM val |= PCISTATE_RETRY_SAME_DMA;
1561*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
1562*8044SWilliam.Kucharski@Sun.COM
1563*8044SWilliam.Kucharski@Sun.COM pci_restore_state(tp->pdev, tp->pci_cfg_state);
1564*8044SWilliam.Kucharski@Sun.COM
1565*8044SWilliam.Kucharski@Sun.COM /* Make sure PCI-X relaxed ordering bit is clear. */
1566*8044SWilliam.Kucharski@Sun.COM pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
1567*8044SWilliam.Kucharski@Sun.COM val &= ~PCIX_CAPS_RELAXED_ORDERING;
1568*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
1569*8044SWilliam.Kucharski@Sun.COM
1570*8044SWilliam.Kucharski@Sun.COM tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
1571*8044SWilliam.Kucharski@Sun.COM
1572*8044SWilliam.Kucharski@Sun.COM if (((tp->nic_sram_data_cfg & NIC_SRAM_DATA_CFG_MINI_PCI) != 0) &&
1573*8044SWilliam.Kucharski@Sun.COM (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
1574*8044SWilliam.Kucharski@Sun.COM tp->pci_clock_ctrl |=
1575*8044SWilliam.Kucharski@Sun.COM (CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE);
1576*8044SWilliam.Kucharski@Sun.COM tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
1577*8044SWilliam.Kucharski@Sun.COM }
1578*8044SWilliam.Kucharski@Sun.COM
1579*8044SWilliam.Kucharski@Sun.COM tw32(TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
1580*8044SWilliam.Kucharski@Sun.COM }
1581*8044SWilliam.Kucharski@Sun.COM
tg3_stop_fw(struct tg3 * tp)1582*8044SWilliam.Kucharski@Sun.COM static void tg3_stop_fw(struct tg3 *tp)
1583*8044SWilliam.Kucharski@Sun.COM {
1584*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
1585*8044SWilliam.Kucharski@Sun.COM uint32_t val;
1586*8044SWilliam.Kucharski@Sun.COM int i;
1587*8044SWilliam.Kucharski@Sun.COM
1588*8044SWilliam.Kucharski@Sun.COM tg3_write_mem(NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
1589*8044SWilliam.Kucharski@Sun.COM val = tr32(GRC_RX_CPU_EVENT);
1590*8044SWilliam.Kucharski@Sun.COM val |= (1 << 14);
1591*8044SWilliam.Kucharski@Sun.COM tw32(GRC_RX_CPU_EVENT, val);
1592*8044SWilliam.Kucharski@Sun.COM
1593*8044SWilliam.Kucharski@Sun.COM /* Wait for RX cpu to ACK the event. */
1594*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 100; i++) {
1595*8044SWilliam.Kucharski@Sun.COM if (!(tr32(GRC_RX_CPU_EVENT) & (1 << 14)))
1596*8044SWilliam.Kucharski@Sun.COM break;
1597*8044SWilliam.Kucharski@Sun.COM udelay(1);
1598*8044SWilliam.Kucharski@Sun.COM }
1599*8044SWilliam.Kucharski@Sun.COM }
1600*8044SWilliam.Kucharski@Sun.COM }
1601*8044SWilliam.Kucharski@Sun.COM
tg3_restart_fw(struct tg3 * tp,uint32_t state)1602*8044SWilliam.Kucharski@Sun.COM static int tg3_restart_fw(struct tg3 *tp, uint32_t state)
1603*8044SWilliam.Kucharski@Sun.COM {
1604*8044SWilliam.Kucharski@Sun.COM uint32_t val;
1605*8044SWilliam.Kucharski@Sun.COM int i;
1606*8044SWilliam.Kucharski@Sun.COM
1607*8044SWilliam.Kucharski@Sun.COM tg3_write_mem(NIC_SRAM_FIRMWARE_MBOX,
1608*8044SWilliam.Kucharski@Sun.COM NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
1609*8044SWilliam.Kucharski@Sun.COM /* Wait for firmware initialization to complete. */
1610*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 100000; i++) {
1611*8044SWilliam.Kucharski@Sun.COM tg3_read_mem(NIC_SRAM_FIRMWARE_MBOX, &val);
1612*8044SWilliam.Kucharski@Sun.COM if (val == (uint32_t) ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
1613*8044SWilliam.Kucharski@Sun.COM break;
1614*8044SWilliam.Kucharski@Sun.COM udelay(10);
1615*8044SWilliam.Kucharski@Sun.COM }
1616*8044SWilliam.Kucharski@Sun.COM if (i >= 100000 &&
1617*8044SWilliam.Kucharski@Sun.COM !(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
1618*8044SWilliam.Kucharski@Sun.COM printf("Firmware will not restart magic=%x\n",
1619*8044SWilliam.Kucharski@Sun.COM val);
1620*8044SWilliam.Kucharski@Sun.COM return -ENODEV;
1621*8044SWilliam.Kucharski@Sun.COM }
1622*8044SWilliam.Kucharski@Sun.COM if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
1623*8044SWilliam.Kucharski@Sun.COM state = DRV_STATE_SUSPEND;
1624*8044SWilliam.Kucharski@Sun.COM }
1625*8044SWilliam.Kucharski@Sun.COM tg3_write_mem(NIC_SRAM_FW_DRV_STATE_MBOX, state);
1626*8044SWilliam.Kucharski@Sun.COM return 0;
1627*8044SWilliam.Kucharski@Sun.COM }
1628*8044SWilliam.Kucharski@Sun.COM
tg3_halt(struct tg3 * tp)1629*8044SWilliam.Kucharski@Sun.COM static int tg3_halt(struct tg3 *tp)
1630*8044SWilliam.Kucharski@Sun.COM {
1631*8044SWilliam.Kucharski@Sun.COM tg3_stop_fw(tp);
1632*8044SWilliam.Kucharski@Sun.COM tg3_abort_hw(tp);
1633*8044SWilliam.Kucharski@Sun.COM tg3_chip_reset(tp);
1634*8044SWilliam.Kucharski@Sun.COM return tg3_restart_fw(tp, DRV_STATE_UNLOAD);
1635*8044SWilliam.Kucharski@Sun.COM }
1636*8044SWilliam.Kucharski@Sun.COM
__tg3_set_mac_addr(struct tg3 * tp)1637*8044SWilliam.Kucharski@Sun.COM static void __tg3_set_mac_addr(struct tg3 *tp)
1638*8044SWilliam.Kucharski@Sun.COM {
1639*8044SWilliam.Kucharski@Sun.COM uint32_t addr_high, addr_low;
1640*8044SWilliam.Kucharski@Sun.COM int i;
1641*8044SWilliam.Kucharski@Sun.COM
1642*8044SWilliam.Kucharski@Sun.COM addr_high = ((tp->nic->node_addr[0] << 8) |
1643*8044SWilliam.Kucharski@Sun.COM tp->nic->node_addr[1]);
1644*8044SWilliam.Kucharski@Sun.COM addr_low = ((tp->nic->node_addr[2] << 24) |
1645*8044SWilliam.Kucharski@Sun.COM (tp->nic->node_addr[3] << 16) |
1646*8044SWilliam.Kucharski@Sun.COM (tp->nic->node_addr[4] << 8) |
1647*8044SWilliam.Kucharski@Sun.COM (tp->nic->node_addr[5] << 0));
1648*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 4; i++) {
1649*8044SWilliam.Kucharski@Sun.COM tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high);
1650*8044SWilliam.Kucharski@Sun.COM tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
1651*8044SWilliam.Kucharski@Sun.COM }
1652*8044SWilliam.Kucharski@Sun.COM
1653*8044SWilliam.Kucharski@Sun.COM if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
1654*8044SWilliam.Kucharski@Sun.COM (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
1655*8044SWilliam.Kucharski@Sun.COM (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)) {
1656*8044SWilliam.Kucharski@Sun.COM for(i = 0; i < 12; i++) {
1657*8044SWilliam.Kucharski@Sun.COM tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
1658*8044SWilliam.Kucharski@Sun.COM tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
1659*8044SWilliam.Kucharski@Sun.COM }
1660*8044SWilliam.Kucharski@Sun.COM }
1661*8044SWilliam.Kucharski@Sun.COM addr_high = (tp->nic->node_addr[0] +
1662*8044SWilliam.Kucharski@Sun.COM tp->nic->node_addr[1] +
1663*8044SWilliam.Kucharski@Sun.COM tp->nic->node_addr[2] +
1664*8044SWilliam.Kucharski@Sun.COM tp->nic->node_addr[3] +
1665*8044SWilliam.Kucharski@Sun.COM tp->nic->node_addr[4] +
1666*8044SWilliam.Kucharski@Sun.COM tp->nic->node_addr[5]) &
1667*8044SWilliam.Kucharski@Sun.COM TX_BACKOFF_SEED_MASK;
1668*8044SWilliam.Kucharski@Sun.COM tw32(MAC_TX_BACKOFF_SEED, addr_high);
1669*8044SWilliam.Kucharski@Sun.COM }
1670*8044SWilliam.Kucharski@Sun.COM
tg3_set_bdinfo(struct tg3 * tp,uint32_t bdinfo_addr,dma_addr_t mapping,uint32_t maxlen_flags,uint32_t nic_addr)1671*8044SWilliam.Kucharski@Sun.COM static void tg3_set_bdinfo(struct tg3 *tp, uint32_t bdinfo_addr,
1672*8044SWilliam.Kucharski@Sun.COM dma_addr_t mapping, uint32_t maxlen_flags,
1673*8044SWilliam.Kucharski@Sun.COM uint32_t nic_addr)
1674*8044SWilliam.Kucharski@Sun.COM {
1675*8044SWilliam.Kucharski@Sun.COM tg3_write_mem((bdinfo_addr +
1676*8044SWilliam.Kucharski@Sun.COM TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH),
1677*8044SWilliam.Kucharski@Sun.COM ((uint64_t) mapping >> 32));
1678*8044SWilliam.Kucharski@Sun.COM tg3_write_mem((bdinfo_addr +
1679*8044SWilliam.Kucharski@Sun.COM TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW),
1680*8044SWilliam.Kucharski@Sun.COM ((uint64_t) mapping & 0xffffffff));
1681*8044SWilliam.Kucharski@Sun.COM tg3_write_mem((bdinfo_addr +
1682*8044SWilliam.Kucharski@Sun.COM TG3_BDINFO_MAXLEN_FLAGS),
1683*8044SWilliam.Kucharski@Sun.COM maxlen_flags);
1684*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
1685*8044SWilliam.Kucharski@Sun.COM tg3_write_mem((bdinfo_addr + TG3_BDINFO_NIC_ADDR), nic_addr);
1686*8044SWilliam.Kucharski@Sun.COM }
1687*8044SWilliam.Kucharski@Sun.COM }
1688*8044SWilliam.Kucharski@Sun.COM
1689*8044SWilliam.Kucharski@Sun.COM
tg3_init_rings(struct tg3 * tp)1690*8044SWilliam.Kucharski@Sun.COM static void tg3_init_rings(struct tg3 *tp)
1691*8044SWilliam.Kucharski@Sun.COM {
1692*8044SWilliam.Kucharski@Sun.COM unsigned i;
1693*8044SWilliam.Kucharski@Sun.COM
1694*8044SWilliam.Kucharski@Sun.COM /* Zero out the tg3 variables */
1695*8044SWilliam.Kucharski@Sun.COM memset(&tg3_bss, 0, sizeof(tg3_bss));
1696*8044SWilliam.Kucharski@Sun.COM tp->rx_std = &tg3_bss.rx_std[0];
1697*8044SWilliam.Kucharski@Sun.COM tp->rx_rcb = &tg3_bss.rx_rcb[0];
1698*8044SWilliam.Kucharski@Sun.COM tp->tx_ring = &tg3_bss.tx_ring[0];
1699*8044SWilliam.Kucharski@Sun.COM tp->hw_status = &tg3_bss.hw_status;
1700*8044SWilliam.Kucharski@Sun.COM tp->hw_stats = &tg3_bss.hw_stats;
1701*8044SWilliam.Kucharski@Sun.COM tp->mac_mode = 0;
1702*8044SWilliam.Kucharski@Sun.COM
1703*8044SWilliam.Kucharski@Sun.COM
1704*8044SWilliam.Kucharski@Sun.COM /* Initialize tx/rx rings for packet processing.
1705*8044SWilliam.Kucharski@Sun.COM *
1706*8044SWilliam.Kucharski@Sun.COM * The chip has been shut down and the driver detached from
1707*8044SWilliam.Kucharski@Sun.COM * the networking, so no interrupts or new tx packets will
1708*8044SWilliam.Kucharski@Sun.COM * end up in the driver.
1709*8044SWilliam.Kucharski@Sun.COM */
1710*8044SWilliam.Kucharski@Sun.COM
1711*8044SWilliam.Kucharski@Sun.COM /* Initialize invariants of the rings, we only set this
1712*8044SWilliam.Kucharski@Sun.COM * stuff once. This works because the card does not
1713*8044SWilliam.Kucharski@Sun.COM * write into the rx buffer posting rings.
1714*8044SWilliam.Kucharski@Sun.COM */
1715*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < TG3_RX_RING_SIZE; i++) {
1716*8044SWilliam.Kucharski@Sun.COM struct tg3_rx_buffer_desc *rxd;
1717*8044SWilliam.Kucharski@Sun.COM
1718*8044SWilliam.Kucharski@Sun.COM rxd = &tp->rx_std[i];
1719*8044SWilliam.Kucharski@Sun.COM rxd->idx_len = (RX_PKT_BUF_SZ - 2 - 64) << RXD_LEN_SHIFT;
1720*8044SWilliam.Kucharski@Sun.COM rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT);
1721*8044SWilliam.Kucharski@Sun.COM rxd->opaque = (RXD_OPAQUE_RING_STD | (i << RXD_OPAQUE_INDEX_SHIFT));
1722*8044SWilliam.Kucharski@Sun.COM
1723*8044SWilliam.Kucharski@Sun.COM /* Note where the receive buffer for the ring is placed */
1724*8044SWilliam.Kucharski@Sun.COM rxd->addr_hi = 0;
1725*8044SWilliam.Kucharski@Sun.COM rxd->addr_lo = virt_to_bus(
1726*8044SWilliam.Kucharski@Sun.COM &tg3_bss.rx_bufs[i%TG3_DEF_RX_RING_PENDING][2]);
1727*8044SWilliam.Kucharski@Sun.COM }
1728*8044SWilliam.Kucharski@Sun.COM }
1729*8044SWilliam.Kucharski@Sun.COM
1730*8044SWilliam.Kucharski@Sun.COM #define TG3_WRITE_SETTINGS(TABLE) \
1731*8044SWilliam.Kucharski@Sun.COM do { \
1732*8044SWilliam.Kucharski@Sun.COM const uint32_t *_table, *_end; \
1733*8044SWilliam.Kucharski@Sun.COM _table = TABLE; \
1734*8044SWilliam.Kucharski@Sun.COM _end = _table + sizeof(TABLE)/sizeof(TABLE[0]); \
1735*8044SWilliam.Kucharski@Sun.COM for(; _table < _end; _table += 2) { \
1736*8044SWilliam.Kucharski@Sun.COM tw32(_table[0], _table[1]); \
1737*8044SWilliam.Kucharski@Sun.COM } \
1738*8044SWilliam.Kucharski@Sun.COM } while(0)
1739*8044SWilliam.Kucharski@Sun.COM
1740*8044SWilliam.Kucharski@Sun.COM
1741*8044SWilliam.Kucharski@Sun.COM /* initialize/reset the tg3 */
tg3_setup_hw(struct tg3 * tp)1742*8044SWilliam.Kucharski@Sun.COM static int tg3_setup_hw(struct tg3 *tp)
1743*8044SWilliam.Kucharski@Sun.COM {
1744*8044SWilliam.Kucharski@Sun.COM uint32_t val, rdmac_mode;
1745*8044SWilliam.Kucharski@Sun.COM int i, err, limit;
1746*8044SWilliam.Kucharski@Sun.COM
1747*8044SWilliam.Kucharski@Sun.COM /* Simply don't support setups with extremly buggy firmware in etherboot */
1748*8044SWilliam.Kucharski@Sun.COM if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) {
1749*8044SWilliam.Kucharski@Sun.COM printf("Error 5701_A0 firmware bug detected\n");
1750*8044SWilliam.Kucharski@Sun.COM return -EINVAL;
1751*8044SWilliam.Kucharski@Sun.COM }
1752*8044SWilliam.Kucharski@Sun.COM
1753*8044SWilliam.Kucharski@Sun.COM tg3_disable_ints(tp);
1754*8044SWilliam.Kucharski@Sun.COM
1755*8044SWilliam.Kucharski@Sun.COM /* Originally this was all in tg3_init_hw */
1756*8044SWilliam.Kucharski@Sun.COM
1757*8044SWilliam.Kucharski@Sun.COM /* Force the chip into D0. */
1758*8044SWilliam.Kucharski@Sun.COM tg3_set_power_state_0(tp);
1759*8044SWilliam.Kucharski@Sun.COM
1760*8044SWilliam.Kucharski@Sun.COM tg3_switch_clocks(tp);
1761*8044SWilliam.Kucharski@Sun.COM
1762*8044SWilliam.Kucharski@Sun.COM tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
1763*8044SWilliam.Kucharski@Sun.COM
1764*8044SWilliam.Kucharski@Sun.COM
1765*8044SWilliam.Kucharski@Sun.COM /* Originally this was all in tg3_reset_hw */
1766*8044SWilliam.Kucharski@Sun.COM
1767*8044SWilliam.Kucharski@Sun.COM tg3_stop_fw(tp);
1768*8044SWilliam.Kucharski@Sun.COM
1769*8044SWilliam.Kucharski@Sun.COM /* No need to call tg3_abort_hw here, it is called before tg3_setup_hw. */
1770*8044SWilliam.Kucharski@Sun.COM
1771*8044SWilliam.Kucharski@Sun.COM tg3_chip_reset(tp);
1772*8044SWilliam.Kucharski@Sun.COM
1773*8044SWilliam.Kucharski@Sun.COM tw32(GRC_MODE, tp->grc_mode); /* Redundant? */
1774*8044SWilliam.Kucharski@Sun.COM
1775*8044SWilliam.Kucharski@Sun.COM err = tg3_restart_fw(tp, DRV_STATE_START);
1776*8044SWilliam.Kucharski@Sun.COM if (err)
1777*8044SWilliam.Kucharski@Sun.COM return err;
1778*8044SWilliam.Kucharski@Sun.COM
1779*8044SWilliam.Kucharski@Sun.COM if (tp->phy_id == PHY_ID_SERDES) {
1780*8044SWilliam.Kucharski@Sun.COM tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
1781*8044SWilliam.Kucharski@Sun.COM }
1782*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
1783*8044SWilliam.Kucharski@Sun.COM
1784*8044SWilliam.Kucharski@Sun.COM
1785*8044SWilliam.Kucharski@Sun.COM /* This works around an issue with Athlon chipsets on
1786*8044SWilliam.Kucharski@Sun.COM * B3 tigon3 silicon. This bit has no effect on any
1787*8044SWilliam.Kucharski@Sun.COM * other revision.
1788*8044SWilliam.Kucharski@Sun.COM */
1789*8044SWilliam.Kucharski@Sun.COM tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
1790*8044SWilliam.Kucharski@Sun.COM tw32_carefully(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
1791*8044SWilliam.Kucharski@Sun.COM
1792*8044SWilliam.Kucharski@Sun.COM if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
1793*8044SWilliam.Kucharski@Sun.COM (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
1794*8044SWilliam.Kucharski@Sun.COM val = tr32(TG3PCI_PCISTATE);
1795*8044SWilliam.Kucharski@Sun.COM val |= PCISTATE_RETRY_SAME_DMA;
1796*8044SWilliam.Kucharski@Sun.COM tw32(TG3PCI_PCISTATE, val);
1797*8044SWilliam.Kucharski@Sun.COM }
1798*8044SWilliam.Kucharski@Sun.COM
1799*8044SWilliam.Kucharski@Sun.COM /* Descriptor ring init may make accesses to the
1800*8044SWilliam.Kucharski@Sun.COM * NIC SRAM area to setup the TX descriptors, so we
1801*8044SWilliam.Kucharski@Sun.COM * can only do this after the hardware has been
1802*8044SWilliam.Kucharski@Sun.COM * successfully reset.
1803*8044SWilliam.Kucharski@Sun.COM */
1804*8044SWilliam.Kucharski@Sun.COM tg3_init_rings(tp);
1805*8044SWilliam.Kucharski@Sun.COM
1806*8044SWilliam.Kucharski@Sun.COM /* Clear statistics/status block in chip */
1807*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
1808*8044SWilliam.Kucharski@Sun.COM for (i = NIC_SRAM_STATS_BLK;
1809*8044SWilliam.Kucharski@Sun.COM i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE;
1810*8044SWilliam.Kucharski@Sun.COM i += sizeof(uint32_t)) {
1811*8044SWilliam.Kucharski@Sun.COM tg3_write_mem(i, 0);
1812*8044SWilliam.Kucharski@Sun.COM udelay(40);
1813*8044SWilliam.Kucharski@Sun.COM }
1814*8044SWilliam.Kucharski@Sun.COM }
1815*8044SWilliam.Kucharski@Sun.COM
1816*8044SWilliam.Kucharski@Sun.COM /* This value is determined during the probe time DMA
1817*8044SWilliam.Kucharski@Sun.COM * engine test, tg3_setup_dma.
1818*8044SWilliam.Kucharski@Sun.COM */
1819*8044SWilliam.Kucharski@Sun.COM tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
1820*8044SWilliam.Kucharski@Sun.COM
1821*8044SWilliam.Kucharski@Sun.COM tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS |
1822*8044SWilliam.Kucharski@Sun.COM GRC_MODE_4X_NIC_SEND_RINGS |
1823*8044SWilliam.Kucharski@Sun.COM GRC_MODE_NO_TX_PHDR_CSUM |
1824*8044SWilliam.Kucharski@Sun.COM GRC_MODE_NO_RX_PHDR_CSUM);
1825*8044SWilliam.Kucharski@Sun.COM tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
1826*8044SWilliam.Kucharski@Sun.COM tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
1827*8044SWilliam.Kucharski@Sun.COM tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM;
1828*8044SWilliam.Kucharski@Sun.COM
1829*8044SWilliam.Kucharski@Sun.COM tw32(GRC_MODE,
1830*8044SWilliam.Kucharski@Sun.COM tp->grc_mode |
1831*8044SWilliam.Kucharski@Sun.COM (GRC_MODE_IRQ_ON_MAC_ATTN | GRC_MODE_HOST_STACKUP));
1832*8044SWilliam.Kucharski@Sun.COM
1833*8044SWilliam.Kucharski@Sun.COM /* Setup the timer prescalar register. Clock is always 66Mhz. */
1834*8044SWilliam.Kucharski@Sun.COM tw32(GRC_MISC_CFG,
1835*8044SWilliam.Kucharski@Sun.COM (65 << GRC_MISC_CFG_PRESCALAR_SHIFT));
1836*8044SWilliam.Kucharski@Sun.COM
1837*8044SWilliam.Kucharski@Sun.COM /* Initialize MBUF/DESC pool. */
1838*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
1839*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
1840*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
1841*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64);
1842*8044SWilliam.Kucharski@Sun.COM else
1843*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
1844*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
1845*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
1846*8044SWilliam.Kucharski@Sun.COM }
1847*8044SWilliam.Kucharski@Sun.COM if (!(tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)) {
1848*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_MB_RDMA_LOW_WATER,
1849*8044SWilliam.Kucharski@Sun.COM tp->bufmgr_config.mbuf_read_dma_low_water);
1850*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_MB_MACRX_LOW_WATER,
1851*8044SWilliam.Kucharski@Sun.COM tp->bufmgr_config.mbuf_mac_rx_low_water);
1852*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_MB_HIGH_WATER,
1853*8044SWilliam.Kucharski@Sun.COM tp->bufmgr_config.mbuf_high_water);
1854*8044SWilliam.Kucharski@Sun.COM } else {
1855*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_MB_RDMA_LOW_WATER,
1856*8044SWilliam.Kucharski@Sun.COM tp->bufmgr_config.mbuf_read_dma_low_water_jumbo);
1857*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_MB_MACRX_LOW_WATER,
1858*8044SWilliam.Kucharski@Sun.COM tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo);
1859*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_MB_HIGH_WATER,
1860*8044SWilliam.Kucharski@Sun.COM tp->bufmgr_config.mbuf_high_water_jumbo);
1861*8044SWilliam.Kucharski@Sun.COM }
1862*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_DMA_LOW_WATER,
1863*8044SWilliam.Kucharski@Sun.COM tp->bufmgr_config.dma_low_water);
1864*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_DMA_HIGH_WATER,
1865*8044SWilliam.Kucharski@Sun.COM tp->bufmgr_config.dma_high_water);
1866*8044SWilliam.Kucharski@Sun.COM
1867*8044SWilliam.Kucharski@Sun.COM tw32(BUFMGR_MODE, BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE);
1868*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 2000; i++) {
1869*8044SWilliam.Kucharski@Sun.COM if (tr32(BUFMGR_MODE) & BUFMGR_MODE_ENABLE)
1870*8044SWilliam.Kucharski@Sun.COM break;
1871*8044SWilliam.Kucharski@Sun.COM udelay(10);
1872*8044SWilliam.Kucharski@Sun.COM }
1873*8044SWilliam.Kucharski@Sun.COM if (i >= 2000) {
1874*8044SWilliam.Kucharski@Sun.COM printf("tg3_setup_hw cannot enable BUFMGR\n");
1875*8044SWilliam.Kucharski@Sun.COM return -ENODEV;
1876*8044SWilliam.Kucharski@Sun.COM }
1877*8044SWilliam.Kucharski@Sun.COM
1878*8044SWilliam.Kucharski@Sun.COM tw32(FTQ_RESET, 0xffffffff);
1879*8044SWilliam.Kucharski@Sun.COM tw32(FTQ_RESET, 0x00000000);
1880*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 2000; i++) {
1881*8044SWilliam.Kucharski@Sun.COM if (tr32(FTQ_RESET) == 0x00000000)
1882*8044SWilliam.Kucharski@Sun.COM break;
1883*8044SWilliam.Kucharski@Sun.COM udelay(10);
1884*8044SWilliam.Kucharski@Sun.COM }
1885*8044SWilliam.Kucharski@Sun.COM if (i >= 2000) {
1886*8044SWilliam.Kucharski@Sun.COM printf("tg3_setup_hw cannot reset FTQ\n");
1887*8044SWilliam.Kucharski@Sun.COM return -ENODEV;
1888*8044SWilliam.Kucharski@Sun.COM }
1889*8044SWilliam.Kucharski@Sun.COM
1890*8044SWilliam.Kucharski@Sun.COM /* Initialize TG3_BDINFO's at:
1891*8044SWilliam.Kucharski@Sun.COM * RCVDBDI_STD_BD: standard eth size rx ring
1892*8044SWilliam.Kucharski@Sun.COM * RCVDBDI_JUMBO_BD: jumbo frame rx ring
1893*8044SWilliam.Kucharski@Sun.COM * RCVDBDI_MINI_BD: small frame rx ring (??? does not work)
1894*8044SWilliam.Kucharski@Sun.COM *
1895*8044SWilliam.Kucharski@Sun.COM * like so:
1896*8044SWilliam.Kucharski@Sun.COM * TG3_BDINFO_HOST_ADDR: high/low parts of DMA address of ring
1897*8044SWilliam.Kucharski@Sun.COM * TG3_BDINFO_MAXLEN_FLAGS: (rx max buffer size << 16) |
1898*8044SWilliam.Kucharski@Sun.COM * ring attribute flags
1899*8044SWilliam.Kucharski@Sun.COM * TG3_BDINFO_NIC_ADDR: location of descriptors in nic SRAM
1900*8044SWilliam.Kucharski@Sun.COM *
1901*8044SWilliam.Kucharski@Sun.COM * Standard receive ring @ NIC_SRAM_RX_BUFFER_DESC, 512 entries.
1902*8044SWilliam.Kucharski@Sun.COM * Jumbo receive ring @ NIC_SRAM_RX_JUMBO_BUFFER_DESC, 256 entries.
1903*8044SWilliam.Kucharski@Sun.COM *
1904*8044SWilliam.Kucharski@Sun.COM * ??? No space allocated for mini receive ring? :(
1905*8044SWilliam.Kucharski@Sun.COM *
1906*8044SWilliam.Kucharski@Sun.COM * The size of each ring is fixed in the firmware, but the location is
1907*8044SWilliam.Kucharski@Sun.COM * configurable.
1908*8044SWilliam.Kucharski@Sun.COM */
1909*8044SWilliam.Kucharski@Sun.COM {
1910*8044SWilliam.Kucharski@Sun.COM static const uint32_t table_all[] = {
1911*8044SWilliam.Kucharski@Sun.COM /* Setup replenish thresholds. */
1912*8044SWilliam.Kucharski@Sun.COM RCVBDI_STD_THRESH, TG3_DEF_RX_RING_PENDING / 8,
1913*8044SWilliam.Kucharski@Sun.COM
1914*8044SWilliam.Kucharski@Sun.COM /* Etherboot lives below 4GB */
1915*8044SWilliam.Kucharski@Sun.COM RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, 0,
1916*8044SWilliam.Kucharski@Sun.COM RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC,
1917*8044SWilliam.Kucharski@Sun.COM };
1918*8044SWilliam.Kucharski@Sun.COM static const uint32_t table_not_5705[] = {
1919*8044SWilliam.Kucharski@Sun.COM /* Buffer maximum length */
1920*8044SWilliam.Kucharski@Sun.COM RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT,
1921*8044SWilliam.Kucharski@Sun.COM
1922*8044SWilliam.Kucharski@Sun.COM /* Disable the mini frame rx ring */
1923*8044SWilliam.Kucharski@Sun.COM RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED,
1924*8044SWilliam.Kucharski@Sun.COM
1925*8044SWilliam.Kucharski@Sun.COM /* Disable the jumbo frame rx ring */
1926*8044SWilliam.Kucharski@Sun.COM RCVBDI_JUMBO_THRESH, 0,
1927*8044SWilliam.Kucharski@Sun.COM RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED,
1928*8044SWilliam.Kucharski@Sun.COM
1929*8044SWilliam.Kucharski@Sun.COM
1930*8044SWilliam.Kucharski@Sun.COM };
1931*8044SWilliam.Kucharski@Sun.COM TG3_WRITE_SETTINGS(table_all);
1932*8044SWilliam.Kucharski@Sun.COM tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
1933*8044SWilliam.Kucharski@Sun.COM virt_to_bus(tp->rx_std));
1934*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
1935*8044SWilliam.Kucharski@Sun.COM tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS,
1936*8044SWilliam.Kucharski@Sun.COM RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT);
1937*8044SWilliam.Kucharski@Sun.COM } else {
1938*8044SWilliam.Kucharski@Sun.COM TG3_WRITE_SETTINGS(table_not_5705);
1939*8044SWilliam.Kucharski@Sun.COM }
1940*8044SWilliam.Kucharski@Sun.COM }
1941*8044SWilliam.Kucharski@Sun.COM
1942*8044SWilliam.Kucharski@Sun.COM
1943*8044SWilliam.Kucharski@Sun.COM /* There is only one send ring on 5705, no need to explicitly
1944*8044SWilliam.Kucharski@Sun.COM * disable the others.
1945*8044SWilliam.Kucharski@Sun.COM */
1946*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
1947*8044SWilliam.Kucharski@Sun.COM /* Clear out send RCB ring in SRAM. */
1948*8044SWilliam.Kucharski@Sun.COM for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE)
1949*8044SWilliam.Kucharski@Sun.COM tg3_write_mem(i + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED);
1950*8044SWilliam.Kucharski@Sun.COM }
1951*8044SWilliam.Kucharski@Sun.COM
1952*8044SWilliam.Kucharski@Sun.COM tp->tx_prod = 0;
1953*8044SWilliam.Kucharski@Sun.COM tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
1954*8044SWilliam.Kucharski@Sun.COM tw32_mailbox2(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
1955*8044SWilliam.Kucharski@Sun.COM
1956*8044SWilliam.Kucharski@Sun.COM tg3_set_bdinfo(tp,
1957*8044SWilliam.Kucharski@Sun.COM NIC_SRAM_SEND_RCB,
1958*8044SWilliam.Kucharski@Sun.COM virt_to_bus(tp->tx_ring),
1959*8044SWilliam.Kucharski@Sun.COM (TG3_TX_RING_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT),
1960*8044SWilliam.Kucharski@Sun.COM NIC_SRAM_TX_BUFFER_DESC);
1961*8044SWilliam.Kucharski@Sun.COM
1962*8044SWilliam.Kucharski@Sun.COM /* There is only one receive return ring on 5705, no need to explicitly
1963*8044SWilliam.Kucharski@Sun.COM * disable the others.
1964*8044SWilliam.Kucharski@Sun.COM */
1965*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
1966*8044SWilliam.Kucharski@Sun.COM for (i = NIC_SRAM_RCV_RET_RCB; i < NIC_SRAM_STATS_BLK; i += TG3_BDINFO_SIZE) {
1967*8044SWilliam.Kucharski@Sun.COM tg3_write_mem(i + TG3_BDINFO_MAXLEN_FLAGS,
1968*8044SWilliam.Kucharski@Sun.COM BDINFO_FLAGS_DISABLED);
1969*8044SWilliam.Kucharski@Sun.COM }
1970*8044SWilliam.Kucharski@Sun.COM }
1971*8044SWilliam.Kucharski@Sun.COM
1972*8044SWilliam.Kucharski@Sun.COM tp->rx_rcb_ptr = 0;
1973*8044SWilliam.Kucharski@Sun.COM tw32_mailbox2(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0);
1974*8044SWilliam.Kucharski@Sun.COM
1975*8044SWilliam.Kucharski@Sun.COM tg3_set_bdinfo(tp,
1976*8044SWilliam.Kucharski@Sun.COM NIC_SRAM_RCV_RET_RCB,
1977*8044SWilliam.Kucharski@Sun.COM virt_to_bus(tp->rx_rcb),
1978*8044SWilliam.Kucharski@Sun.COM (TG3_RX_RCB_RING_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT),
1979*8044SWilliam.Kucharski@Sun.COM 0);
1980*8044SWilliam.Kucharski@Sun.COM
1981*8044SWilliam.Kucharski@Sun.COM tp->rx_std_ptr = TG3_DEF_RX_RING_PENDING;
1982*8044SWilliam.Kucharski@Sun.COM tw32_mailbox2(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
1983*8044SWilliam.Kucharski@Sun.COM tp->rx_std_ptr);
1984*8044SWilliam.Kucharski@Sun.COM
1985*8044SWilliam.Kucharski@Sun.COM tw32_mailbox2(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, 0);
1986*8044SWilliam.Kucharski@Sun.COM
1987*8044SWilliam.Kucharski@Sun.COM /* Initialize MAC address and backoff seed. */
1988*8044SWilliam.Kucharski@Sun.COM __tg3_set_mac_addr(tp);
1989*8044SWilliam.Kucharski@Sun.COM
1990*8044SWilliam.Kucharski@Sun.COM /* Calculate RDMAC_MODE setting early, we need it to determine
1991*8044SWilliam.Kucharski@Sun.COM * the RCVLPC_STATE_ENABLE mask.
1992*8044SWilliam.Kucharski@Sun.COM */
1993*8044SWilliam.Kucharski@Sun.COM rdmac_mode = (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
1994*8044SWilliam.Kucharski@Sun.COM RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
1995*8044SWilliam.Kucharski@Sun.COM RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
1996*8044SWilliam.Kucharski@Sun.COM RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
1997*8044SWilliam.Kucharski@Sun.COM RDMAC_MODE_LNGREAD_ENAB);
1998*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
1999*8044SWilliam.Kucharski@Sun.COM rdmac_mode |= RDMAC_MODE_SPLIT_ENABLE;
2000*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
2001*8044SWilliam.Kucharski@Sun.COM if (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
2002*8044SWilliam.Kucharski@Sun.COM if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
2003*8044SWilliam.Kucharski@Sun.COM !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
2004*8044SWilliam.Kucharski@Sun.COM rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
2005*8044SWilliam.Kucharski@Sun.COM }
2006*8044SWilliam.Kucharski@Sun.COM }
2007*8044SWilliam.Kucharski@Sun.COM }
2008*8044SWilliam.Kucharski@Sun.COM
2009*8044SWilliam.Kucharski@Sun.COM /* Setup host coalescing engine. */
2010*8044SWilliam.Kucharski@Sun.COM tw32(HOSTCC_MODE, 0);
2011*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 2000; i++) {
2012*8044SWilliam.Kucharski@Sun.COM if (!(tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE))
2013*8044SWilliam.Kucharski@Sun.COM break;
2014*8044SWilliam.Kucharski@Sun.COM udelay(10);
2015*8044SWilliam.Kucharski@Sun.COM }
2016*8044SWilliam.Kucharski@Sun.COM
2017*8044SWilliam.Kucharski@Sun.COM tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
2018*8044SWilliam.Kucharski@Sun.COM MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
2019*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
2020*8044SWilliam.Kucharski@Sun.COM
2021*8044SWilliam.Kucharski@Sun.COM tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM;
2022*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
2023*8044SWilliam.Kucharski@Sun.COM tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
2024*8044SWilliam.Kucharski@Sun.COM GRC_LCLCTRL_GPIO_OUTPUT1);
2025*8044SWilliam.Kucharski@Sun.COM tw32_carefully(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
2026*8044SWilliam.Kucharski@Sun.COM
2027*8044SWilliam.Kucharski@Sun.COM tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
2028*8044SWilliam.Kucharski@Sun.COM tr32(MAILBOX_INTERRUPT_0);
2029*8044SWilliam.Kucharski@Sun.COM
2030*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
2031*8044SWilliam.Kucharski@Sun.COM tw32_carefully(DMAC_MODE, DMAC_MODE_ENABLE);
2032*8044SWilliam.Kucharski@Sun.COM }
2033*8044SWilliam.Kucharski@Sun.COM
2034*8044SWilliam.Kucharski@Sun.COM val = ( WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB |
2035*8044SWilliam.Kucharski@Sun.COM WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB |
2036*8044SWilliam.Kucharski@Sun.COM WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB |
2037*8044SWilliam.Kucharski@Sun.COM WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
2038*8044SWilliam.Kucharski@Sun.COM WDMAC_MODE_LNGREAD_ENAB);
2039*8044SWilliam.Kucharski@Sun.COM if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
2040*8044SWilliam.Kucharski@Sun.COM ((tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) != 0) &&
2041*8044SWilliam.Kucharski@Sun.COM !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
2042*8044SWilliam.Kucharski@Sun.COM val |= WDMAC_MODE_RX_ACCEL;
2043*8044SWilliam.Kucharski@Sun.COM }
2044*8044SWilliam.Kucharski@Sun.COM tw32_carefully(WDMAC_MODE, val);
2045*8044SWilliam.Kucharski@Sun.COM
2046*8044SWilliam.Kucharski@Sun.COM if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
2047*8044SWilliam.Kucharski@Sun.COM val = tr32(TG3PCI_X_CAPS);
2048*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
2049*8044SWilliam.Kucharski@Sun.COM val &= PCIX_CAPS_BURST_MASK;
2050*8044SWilliam.Kucharski@Sun.COM val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
2051*8044SWilliam.Kucharski@Sun.COM } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
2052*8044SWilliam.Kucharski@Sun.COM val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
2053*8044SWilliam.Kucharski@Sun.COM val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
2054*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
2055*8044SWilliam.Kucharski@Sun.COM val |= (tp->split_mode_max_reqs <<
2056*8044SWilliam.Kucharski@Sun.COM PCIX_CAPS_SPLIT_SHIFT);
2057*8044SWilliam.Kucharski@Sun.COM }
2058*8044SWilliam.Kucharski@Sun.COM tw32(TG3PCI_X_CAPS, val);
2059*8044SWilliam.Kucharski@Sun.COM }
2060*8044SWilliam.Kucharski@Sun.COM
2061*8044SWilliam.Kucharski@Sun.COM tw32_carefully(RDMAC_MODE, rdmac_mode);
2062*8044SWilliam.Kucharski@Sun.COM {
2063*8044SWilliam.Kucharski@Sun.COM static const uint32_t table_all[] = {
2064*8044SWilliam.Kucharski@Sun.COM /* MTU + ethernet header + FCS + optional VLAN tag */
2065*8044SWilliam.Kucharski@Sun.COM MAC_RX_MTU_SIZE, ETH_MAX_MTU + ETH_HLEN + 8,
2066*8044SWilliam.Kucharski@Sun.COM
2067*8044SWilliam.Kucharski@Sun.COM /* The slot time is changed by tg3_setup_phy if we
2068*8044SWilliam.Kucharski@Sun.COM * run at gigabit with half duplex.
2069*8044SWilliam.Kucharski@Sun.COM */
2070*8044SWilliam.Kucharski@Sun.COM MAC_TX_LENGTHS,
2071*8044SWilliam.Kucharski@Sun.COM (2 << TX_LENGTHS_IPG_CRS_SHIFT) |
2072*8044SWilliam.Kucharski@Sun.COM (6 << TX_LENGTHS_IPG_SHIFT) |
2073*8044SWilliam.Kucharski@Sun.COM (32 << TX_LENGTHS_SLOT_TIME_SHIFT),
2074*8044SWilliam.Kucharski@Sun.COM
2075*8044SWilliam.Kucharski@Sun.COM /* Receive rules. */
2076*8044SWilliam.Kucharski@Sun.COM MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS,
2077*8044SWilliam.Kucharski@Sun.COM RCVLPC_CONFIG, 0x0181,
2078*8044SWilliam.Kucharski@Sun.COM
2079*8044SWilliam.Kucharski@Sun.COM /* Receive/send statistics. */
2080*8044SWilliam.Kucharski@Sun.COM RCVLPC_STATS_ENABLE, 0xffffff,
2081*8044SWilliam.Kucharski@Sun.COM RCVLPC_STATSCTRL, RCVLPC_STATSCTRL_ENABLE,
2082*8044SWilliam.Kucharski@Sun.COM SNDDATAI_STATSENAB, 0xffffff,
2083*8044SWilliam.Kucharski@Sun.COM SNDDATAI_STATSCTRL, (SNDDATAI_SCTRL_ENABLE |SNDDATAI_SCTRL_FASTUPD),
2084*8044SWilliam.Kucharski@Sun.COM
2085*8044SWilliam.Kucharski@Sun.COM /* Host coalescing engine */
2086*8044SWilliam.Kucharski@Sun.COM HOSTCC_RXCOL_TICKS, 0,
2087*8044SWilliam.Kucharski@Sun.COM HOSTCC_TXCOL_TICKS, LOW_TXCOL_TICKS,
2088*8044SWilliam.Kucharski@Sun.COM HOSTCC_RXMAX_FRAMES, 1,
2089*8044SWilliam.Kucharski@Sun.COM HOSTCC_TXMAX_FRAMES, LOW_RXMAX_FRAMES,
2090*8044SWilliam.Kucharski@Sun.COM HOSTCC_RXCOAL_MAXF_INT, 1,
2091*8044SWilliam.Kucharski@Sun.COM HOSTCC_TXCOAL_MAXF_INT, 0,
2092*8044SWilliam.Kucharski@Sun.COM
2093*8044SWilliam.Kucharski@Sun.COM /* Status/statistics block address. */
2094*8044SWilliam.Kucharski@Sun.COM /* Etherboot lives below 4GB, so HIGH == 0 */
2095*8044SWilliam.Kucharski@Sun.COM HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, 0,
2096*8044SWilliam.Kucharski@Sun.COM
2097*8044SWilliam.Kucharski@Sun.COM /* No need to enable 32byte coalesce mode. */
2098*8044SWilliam.Kucharski@Sun.COM HOSTCC_MODE, HOSTCC_MODE_ENABLE | 0,
2099*8044SWilliam.Kucharski@Sun.COM
2100*8044SWilliam.Kucharski@Sun.COM RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE,
2101*8044SWilliam.Kucharski@Sun.COM RCVLPC_MODE, RCVLPC_MODE_ENABLE,
2102*8044SWilliam.Kucharski@Sun.COM
2103*8044SWilliam.Kucharski@Sun.COM RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE,
2104*8044SWilliam.Kucharski@Sun.COM
2105*8044SWilliam.Kucharski@Sun.COM SNDDATAC_MODE, SNDDATAC_MODE_ENABLE,
2106*8044SWilliam.Kucharski@Sun.COM SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE,
2107*8044SWilliam.Kucharski@Sun.COM RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB,
2108*8044SWilliam.Kucharski@Sun.COM RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ,
2109*8044SWilliam.Kucharski@Sun.COM SNDDATAI_MODE, SNDDATAI_MODE_ENABLE,
2110*8044SWilliam.Kucharski@Sun.COM SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE,
2111*8044SWilliam.Kucharski@Sun.COM SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE,
2112*8044SWilliam.Kucharski@Sun.COM
2113*8044SWilliam.Kucharski@Sun.COM /* Accept all multicast frames. */
2114*8044SWilliam.Kucharski@Sun.COM MAC_HASH_REG_0, 0xffffffff,
2115*8044SWilliam.Kucharski@Sun.COM MAC_HASH_REG_1, 0xffffffff,
2116*8044SWilliam.Kucharski@Sun.COM MAC_HASH_REG_2, 0xffffffff,
2117*8044SWilliam.Kucharski@Sun.COM MAC_HASH_REG_3, 0xffffffff,
2118*8044SWilliam.Kucharski@Sun.COM };
2119*8044SWilliam.Kucharski@Sun.COM static const uint32_t table_not_5705[] = {
2120*8044SWilliam.Kucharski@Sun.COM /* Host coalescing engine */
2121*8044SWilliam.Kucharski@Sun.COM HOSTCC_RXCOAL_TICK_INT, 0,
2122*8044SWilliam.Kucharski@Sun.COM HOSTCC_TXCOAL_TICK_INT, 0,
2123*8044SWilliam.Kucharski@Sun.COM
2124*8044SWilliam.Kucharski@Sun.COM /* Status/statistics block address. */
2125*8044SWilliam.Kucharski@Sun.COM /* Etherboot lives below 4GB, so HIGH == 0 */
2126*8044SWilliam.Kucharski@Sun.COM HOSTCC_STAT_COAL_TICKS, DEFAULT_STAT_COAL_TICKS,
2127*8044SWilliam.Kucharski@Sun.COM HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, 0,
2128*8044SWilliam.Kucharski@Sun.COM HOSTCC_STATS_BLK_NIC_ADDR, NIC_SRAM_STATS_BLK,
2129*8044SWilliam.Kucharski@Sun.COM HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK,
2130*8044SWilliam.Kucharski@Sun.COM
2131*8044SWilliam.Kucharski@Sun.COM RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE,
2132*8044SWilliam.Kucharski@Sun.COM
2133*8044SWilliam.Kucharski@Sun.COM MBFREE_MODE, MBFREE_MODE_ENABLE,
2134*8044SWilliam.Kucharski@Sun.COM };
2135*8044SWilliam.Kucharski@Sun.COM TG3_WRITE_SETTINGS(table_all);
2136*8044SWilliam.Kucharski@Sun.COM tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
2137*8044SWilliam.Kucharski@Sun.COM virt_to_bus(tp->hw_stats));
2138*8044SWilliam.Kucharski@Sun.COM tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
2139*8044SWilliam.Kucharski@Sun.COM virt_to_bus(tp->hw_status));
2140*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
2141*8044SWilliam.Kucharski@Sun.COM TG3_WRITE_SETTINGS(table_not_5705);
2142*8044SWilliam.Kucharski@Sun.COM }
2143*8044SWilliam.Kucharski@Sun.COM }
2144*8044SWilliam.Kucharski@Sun.COM
2145*8044SWilliam.Kucharski@Sun.COM tp->tx_mode = TX_MODE_ENABLE;
2146*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_TX_MODE, tp->tx_mode);
2147*8044SWilliam.Kucharski@Sun.COM
2148*8044SWilliam.Kucharski@Sun.COM tp->rx_mode = RX_MODE_ENABLE;
2149*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_RX_MODE, tp->rx_mode);
2150*8044SWilliam.Kucharski@Sun.COM
2151*8044SWilliam.Kucharski@Sun.COM tp->mi_mode = MAC_MI_MODE_BASE;
2152*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MI_MODE, tp->mi_mode);
2153*8044SWilliam.Kucharski@Sun.COM
2154*8044SWilliam.Kucharski@Sun.COM tw32(MAC_LED_CTRL, 0);
2155*8044SWilliam.Kucharski@Sun.COM tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
2156*8044SWilliam.Kucharski@Sun.COM if (tp->phy_id == PHY_ID_SERDES) {
2157*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_RX_MODE, RX_MODE_RESET);
2158*8044SWilliam.Kucharski@Sun.COM }
2159*8044SWilliam.Kucharski@Sun.COM tp->rx_mode |= RX_MODE_KEEP_VLAN_TAG; /* drop tagged vlan packets */
2160*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_RX_MODE, tp->rx_mode);
2161*8044SWilliam.Kucharski@Sun.COM
2162*8044SWilliam.Kucharski@Sun.COM if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
2163*8044SWilliam.Kucharski@Sun.COM tw32(MAC_SERDES_CFG, 0x616000);
2164*8044SWilliam.Kucharski@Sun.COM
2165*8044SWilliam.Kucharski@Sun.COM /* Prevent chip from dropping frames when flow control
2166*8044SWilliam.Kucharski@Sun.COM * is enabled.
2167*8044SWilliam.Kucharski@Sun.COM */
2168*8044SWilliam.Kucharski@Sun.COM tw32(MAC_LOW_WMARK_MAX_RX_FRAME, 2);
2169*8044SWilliam.Kucharski@Sun.COM tr32(MAC_LOW_WMARK_MAX_RX_FRAME);
2170*8044SWilliam.Kucharski@Sun.COM
2171*8044SWilliam.Kucharski@Sun.COM err = tg3_setup_phy(tp);
2172*8044SWilliam.Kucharski@Sun.COM
2173*8044SWilliam.Kucharski@Sun.COM /* Ignore CRC stats */
2174*8044SWilliam.Kucharski@Sun.COM
2175*8044SWilliam.Kucharski@Sun.COM /* Initialize receive rules. */
2176*8044SWilliam.Kucharski@Sun.COM tw32(MAC_RCV_RULE_0, 0xc2000000 & RCV_RULE_DISABLE_MASK);
2177*8044SWilliam.Kucharski@Sun.COM tw32(MAC_RCV_VALUE_0, 0xffffffff & RCV_RULE_DISABLE_MASK);
2178*8044SWilliam.Kucharski@Sun.COM tw32(MAC_RCV_RULE_1, 0x86000004 & RCV_RULE_DISABLE_MASK);
2179*8044SWilliam.Kucharski@Sun.COM tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK);
2180*8044SWilliam.Kucharski@Sun.COM
2181*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
2182*8044SWilliam.Kucharski@Sun.COM limit = 8;
2183*8044SWilliam.Kucharski@Sun.COM else
2184*8044SWilliam.Kucharski@Sun.COM limit = 16;
2185*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
2186*8044SWilliam.Kucharski@Sun.COM limit -= 4;
2187*8044SWilliam.Kucharski@Sun.COM switch (limit) {
2188*8044SWilliam.Kucharski@Sun.COM case 16: tw32(MAC_RCV_RULE_15, 0); tw32(MAC_RCV_VALUE_15, 0);
2189*8044SWilliam.Kucharski@Sun.COM case 15: tw32(MAC_RCV_RULE_14, 0); tw32(MAC_RCV_VALUE_14, 0);
2190*8044SWilliam.Kucharski@Sun.COM case 14: tw32(MAC_RCV_RULE_13, 0); tw32(MAC_RCV_VALUE_13, 0);
2191*8044SWilliam.Kucharski@Sun.COM case 13: tw32(MAC_RCV_RULE_12, 0); tw32(MAC_RCV_VALUE_12, 0);
2192*8044SWilliam.Kucharski@Sun.COM case 12: tw32(MAC_RCV_RULE_11, 0); tw32(MAC_RCV_VALUE_11, 0);
2193*8044SWilliam.Kucharski@Sun.COM case 11: tw32(MAC_RCV_RULE_10, 0); tw32(MAC_RCV_VALUE_10, 0);
2194*8044SWilliam.Kucharski@Sun.COM case 10: tw32(MAC_RCV_RULE_9, 0); tw32(MAC_RCV_VALUE_9, 0);
2195*8044SWilliam.Kucharski@Sun.COM case 9: tw32(MAC_RCV_RULE_8, 0); tw32(MAC_RCV_VALUE_8, 0);
2196*8044SWilliam.Kucharski@Sun.COM case 8: tw32(MAC_RCV_RULE_7, 0); tw32(MAC_RCV_VALUE_7, 0);
2197*8044SWilliam.Kucharski@Sun.COM case 7: tw32(MAC_RCV_RULE_6, 0); tw32(MAC_RCV_VALUE_6, 0);
2198*8044SWilliam.Kucharski@Sun.COM case 6: tw32(MAC_RCV_RULE_5, 0); tw32(MAC_RCV_VALUE_5, 0);
2199*8044SWilliam.Kucharski@Sun.COM case 5: tw32(MAC_RCV_RULE_4, 0); tw32(MAC_RCV_VALUE_4, 0);
2200*8044SWilliam.Kucharski@Sun.COM case 4: /* tw32(MAC_RCV_RULE_3, 0); tw32(MAC_RCV_VALUE_3, 0); */
2201*8044SWilliam.Kucharski@Sun.COM case 3: /* tw32(MAC_RCV_RULE_2, 0); tw32(MAC_RCV_VALUE_2, 0); */
2202*8044SWilliam.Kucharski@Sun.COM case 2:
2203*8044SWilliam.Kucharski@Sun.COM case 1:
2204*8044SWilliam.Kucharski@Sun.COM default:
2205*8044SWilliam.Kucharski@Sun.COM break;
2206*8044SWilliam.Kucharski@Sun.COM };
2207*8044SWilliam.Kucharski@Sun.COM
2208*8044SWilliam.Kucharski@Sun.COM return err;
2209*8044SWilliam.Kucharski@Sun.COM }
2210*8044SWilliam.Kucharski@Sun.COM
2211*8044SWilliam.Kucharski@Sun.COM
2212*8044SWilliam.Kucharski@Sun.COM
2213*8044SWilliam.Kucharski@Sun.COM /* Chips other than 5700/5701 use the NVRAM for fetching info. */
tg3_nvram_init(struct tg3 * tp)2214*8044SWilliam.Kucharski@Sun.COM static void tg3_nvram_init(struct tg3 *tp)
2215*8044SWilliam.Kucharski@Sun.COM {
2216*8044SWilliam.Kucharski@Sun.COM tw32(GRC_EEPROM_ADDR,
2217*8044SWilliam.Kucharski@Sun.COM (EEPROM_ADDR_FSM_RESET |
2218*8044SWilliam.Kucharski@Sun.COM (EEPROM_DEFAULT_CLOCK_PERIOD <<
2219*8044SWilliam.Kucharski@Sun.COM EEPROM_ADDR_CLKPERD_SHIFT)));
2220*8044SWilliam.Kucharski@Sun.COM
2221*8044SWilliam.Kucharski@Sun.COM mdelay(1);
2222*8044SWilliam.Kucharski@Sun.COM
2223*8044SWilliam.Kucharski@Sun.COM /* Enable seeprom accesses. */
2224*8044SWilliam.Kucharski@Sun.COM tw32_carefully(GRC_LOCAL_CTRL,
2225*8044SWilliam.Kucharski@Sun.COM tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM);
2226*8044SWilliam.Kucharski@Sun.COM
2227*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
2228*8044SWilliam.Kucharski@Sun.COM GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
2229*8044SWilliam.Kucharski@Sun.COM uint32_t nvcfg1 = tr32(NVRAM_CFG1);
2230*8044SWilliam.Kucharski@Sun.COM
2231*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_NVRAM;
2232*8044SWilliam.Kucharski@Sun.COM if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
2233*8044SWilliam.Kucharski@Sun.COM if (nvcfg1 & NVRAM_CFG1_BUFFERED_MODE)
2234*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
2235*8044SWilliam.Kucharski@Sun.COM } else {
2236*8044SWilliam.Kucharski@Sun.COM nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
2237*8044SWilliam.Kucharski@Sun.COM tw32(NVRAM_CFG1, nvcfg1);
2238*8044SWilliam.Kucharski@Sun.COM }
2239*8044SWilliam.Kucharski@Sun.COM
2240*8044SWilliam.Kucharski@Sun.COM } else {
2241*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
2242*8044SWilliam.Kucharski@Sun.COM }
2243*8044SWilliam.Kucharski@Sun.COM }
2244*8044SWilliam.Kucharski@Sun.COM
2245*8044SWilliam.Kucharski@Sun.COM
tg3_nvram_read_using_eeprom(struct tg3 * tp __unused,uint32_t offset,uint32_t * val)2246*8044SWilliam.Kucharski@Sun.COM static int tg3_nvram_read_using_eeprom(
2247*8044SWilliam.Kucharski@Sun.COM struct tg3 *tp __unused, uint32_t offset, uint32_t *val)
2248*8044SWilliam.Kucharski@Sun.COM {
2249*8044SWilliam.Kucharski@Sun.COM uint32_t tmp;
2250*8044SWilliam.Kucharski@Sun.COM int i;
2251*8044SWilliam.Kucharski@Sun.COM
2252*8044SWilliam.Kucharski@Sun.COM if (offset > EEPROM_ADDR_ADDR_MASK ||
2253*8044SWilliam.Kucharski@Sun.COM (offset % 4) != 0) {
2254*8044SWilliam.Kucharski@Sun.COM return -EINVAL;
2255*8044SWilliam.Kucharski@Sun.COM }
2256*8044SWilliam.Kucharski@Sun.COM
2257*8044SWilliam.Kucharski@Sun.COM tmp = tr32(GRC_EEPROM_ADDR) & ~(EEPROM_ADDR_ADDR_MASK |
2258*8044SWilliam.Kucharski@Sun.COM EEPROM_ADDR_DEVID_MASK |
2259*8044SWilliam.Kucharski@Sun.COM EEPROM_ADDR_READ);
2260*8044SWilliam.Kucharski@Sun.COM tw32(GRC_EEPROM_ADDR,
2261*8044SWilliam.Kucharski@Sun.COM tmp |
2262*8044SWilliam.Kucharski@Sun.COM (0 << EEPROM_ADDR_DEVID_SHIFT) |
2263*8044SWilliam.Kucharski@Sun.COM ((offset << EEPROM_ADDR_ADDR_SHIFT) &
2264*8044SWilliam.Kucharski@Sun.COM EEPROM_ADDR_ADDR_MASK) |
2265*8044SWilliam.Kucharski@Sun.COM EEPROM_ADDR_READ | EEPROM_ADDR_START);
2266*8044SWilliam.Kucharski@Sun.COM
2267*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 10000; i++) {
2268*8044SWilliam.Kucharski@Sun.COM tmp = tr32(GRC_EEPROM_ADDR);
2269*8044SWilliam.Kucharski@Sun.COM
2270*8044SWilliam.Kucharski@Sun.COM if (tmp & EEPROM_ADDR_COMPLETE)
2271*8044SWilliam.Kucharski@Sun.COM break;
2272*8044SWilliam.Kucharski@Sun.COM udelay(100);
2273*8044SWilliam.Kucharski@Sun.COM }
2274*8044SWilliam.Kucharski@Sun.COM if (!(tmp & EEPROM_ADDR_COMPLETE)) {
2275*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
2276*8044SWilliam.Kucharski@Sun.COM }
2277*8044SWilliam.Kucharski@Sun.COM
2278*8044SWilliam.Kucharski@Sun.COM *val = tr32(GRC_EEPROM_DATA);
2279*8044SWilliam.Kucharski@Sun.COM return 0;
2280*8044SWilliam.Kucharski@Sun.COM }
2281*8044SWilliam.Kucharski@Sun.COM
tg3_nvram_read(struct tg3 * tp,uint32_t offset,uint32_t * val)2282*8044SWilliam.Kucharski@Sun.COM static int tg3_nvram_read(struct tg3 *tp, uint32_t offset, uint32_t *val)
2283*8044SWilliam.Kucharski@Sun.COM {
2284*8044SWilliam.Kucharski@Sun.COM int i, saw_done_clear;
2285*8044SWilliam.Kucharski@Sun.COM
2286*8044SWilliam.Kucharski@Sun.COM if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
2287*8044SWilliam.Kucharski@Sun.COM return tg3_nvram_read_using_eeprom(tp, offset, val);
2288*8044SWilliam.Kucharski@Sun.COM
2289*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED)
2290*8044SWilliam.Kucharski@Sun.COM offset = ((offset / NVRAM_BUFFERED_PAGE_SIZE) <<
2291*8044SWilliam.Kucharski@Sun.COM NVRAM_BUFFERED_PAGE_POS) +
2292*8044SWilliam.Kucharski@Sun.COM (offset % NVRAM_BUFFERED_PAGE_SIZE);
2293*8044SWilliam.Kucharski@Sun.COM
2294*8044SWilliam.Kucharski@Sun.COM if (offset > NVRAM_ADDR_MSK)
2295*8044SWilliam.Kucharski@Sun.COM return -EINVAL;
2296*8044SWilliam.Kucharski@Sun.COM
2297*8044SWilliam.Kucharski@Sun.COM tw32(NVRAM_SWARB, SWARB_REQ_SET1);
2298*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 1000; i++) {
2299*8044SWilliam.Kucharski@Sun.COM if (tr32(NVRAM_SWARB) & SWARB_GNT1)
2300*8044SWilliam.Kucharski@Sun.COM break;
2301*8044SWilliam.Kucharski@Sun.COM udelay(20);
2302*8044SWilliam.Kucharski@Sun.COM }
2303*8044SWilliam.Kucharski@Sun.COM
2304*8044SWilliam.Kucharski@Sun.COM tw32(NVRAM_ADDR, offset);
2305*8044SWilliam.Kucharski@Sun.COM tw32(NVRAM_CMD,
2306*8044SWilliam.Kucharski@Sun.COM NVRAM_CMD_RD | NVRAM_CMD_GO |
2307*8044SWilliam.Kucharski@Sun.COM NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
2308*8044SWilliam.Kucharski@Sun.COM
2309*8044SWilliam.Kucharski@Sun.COM /* Wait for done bit to clear then set again. */
2310*8044SWilliam.Kucharski@Sun.COM saw_done_clear = 0;
2311*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 1000; i++) {
2312*8044SWilliam.Kucharski@Sun.COM udelay(10);
2313*8044SWilliam.Kucharski@Sun.COM if (!saw_done_clear &&
2314*8044SWilliam.Kucharski@Sun.COM !(tr32(NVRAM_CMD) & NVRAM_CMD_DONE))
2315*8044SWilliam.Kucharski@Sun.COM saw_done_clear = 1;
2316*8044SWilliam.Kucharski@Sun.COM else if (saw_done_clear &&
2317*8044SWilliam.Kucharski@Sun.COM (tr32(NVRAM_CMD) & NVRAM_CMD_DONE))
2318*8044SWilliam.Kucharski@Sun.COM break;
2319*8044SWilliam.Kucharski@Sun.COM }
2320*8044SWilliam.Kucharski@Sun.COM if (i >= 1000) {
2321*8044SWilliam.Kucharski@Sun.COM tw32(NVRAM_SWARB, SWARB_REQ_CLR1);
2322*8044SWilliam.Kucharski@Sun.COM return -EBUSY;
2323*8044SWilliam.Kucharski@Sun.COM }
2324*8044SWilliam.Kucharski@Sun.COM
2325*8044SWilliam.Kucharski@Sun.COM *val = bswap_32(tr32(NVRAM_RDDATA));
2326*8044SWilliam.Kucharski@Sun.COM tw32(NVRAM_SWARB, 0x20);
2327*8044SWilliam.Kucharski@Sun.COM
2328*8044SWilliam.Kucharski@Sun.COM return 0;
2329*8044SWilliam.Kucharski@Sun.COM }
2330*8044SWilliam.Kucharski@Sun.COM
2331*8044SWilliam.Kucharski@Sun.COM struct subsys_tbl_ent {
2332*8044SWilliam.Kucharski@Sun.COM uint16_t subsys_vendor, subsys_devid;
2333*8044SWilliam.Kucharski@Sun.COM uint32_t phy_id;
2334*8044SWilliam.Kucharski@Sun.COM };
2335*8044SWilliam.Kucharski@Sun.COM
2336*8044SWilliam.Kucharski@Sun.COM static struct subsys_tbl_ent subsys_id_to_phy_id[] = {
2337*8044SWilliam.Kucharski@Sun.COM /* Broadcom boards. */
2338*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */
2339*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */
2340*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */
2341*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x0003, PHY_ID_SERDES }, /* BCM95700A9 */
2342*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */
2343*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */
2344*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x0007, PHY_ID_SERDES }, /* BCM95701A7 */
2345*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */
2346*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */
2347*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x0009, PHY_ID_BCM5701 }, /* BCM95703Ax1 */
2348*8044SWilliam.Kucharski@Sun.COM { 0x14e4, 0x8009, PHY_ID_BCM5701 }, /* BCM95703Ax2 */
2349*8044SWilliam.Kucharski@Sun.COM
2350*8044SWilliam.Kucharski@Sun.COM /* 3com boards. */
2351*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */
2352*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */
2353*8044SWilliam.Kucharski@Sun.COM /* { PCI_VENDOR_ID_3COM, 0x1002, PHY_ID_XXX }, 3C996CT */
2354*8044SWilliam.Kucharski@Sun.COM /* { PCI_VENDOR_ID_3COM, 0x1003, PHY_ID_XXX }, 3C997T */
2355*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_3COM, 0x1004, PHY_ID_SERDES }, /* 3C996SX */
2356*8044SWilliam.Kucharski@Sun.COM /* { PCI_VENDOR_ID_3COM, 0x1005, PHY_ID_XXX }, 3C997SZ */
2357*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */
2358*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */
2359*8044SWilliam.Kucharski@Sun.COM
2360*8044SWilliam.Kucharski@Sun.COM /* DELL boards. */
2361*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_DELL, 0x00d1, PHY_ID_BCM5401 }, /* VIPER */
2362*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_DELL, 0x0106, PHY_ID_BCM5401 }, /* JAGUAR */
2363*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */
2364*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */
2365*8044SWilliam.Kucharski@Sun.COM
2366*8044SWilliam.Kucharski@Sun.COM /* Compaq boards. */
2367*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */
2368*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */
2369*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_COMPAQ, 0x007d, PHY_ID_SERDES }, /* CHANGELING */
2370*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */
2371*8044SWilliam.Kucharski@Sun.COM { PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 } /* NC7780_2 */
2372*8044SWilliam.Kucharski@Sun.COM };
2373*8044SWilliam.Kucharski@Sun.COM
tg3_phy_probe(struct tg3 * tp)2374*8044SWilliam.Kucharski@Sun.COM static int tg3_phy_probe(struct tg3 *tp)
2375*8044SWilliam.Kucharski@Sun.COM {
2376*8044SWilliam.Kucharski@Sun.COM uint32_t eeprom_phy_id, hw_phy_id_1, hw_phy_id_2;
2377*8044SWilliam.Kucharski@Sun.COM uint32_t hw_phy_id, hw_phy_id_masked;
2378*8044SWilliam.Kucharski@Sun.COM enum phy_led_mode eeprom_led_mode;
2379*8044SWilliam.Kucharski@Sun.COM uint32_t val;
2380*8044SWilliam.Kucharski@Sun.COM unsigned i;
2381*8044SWilliam.Kucharski@Sun.COM int eeprom_signature_found, err;
2382*8044SWilliam.Kucharski@Sun.COM
2383*8044SWilliam.Kucharski@Sun.COM tp->phy_id = PHY_ID_INVALID;
2384*8044SWilliam.Kucharski@Sun.COM
2385*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < sizeof(subsys_id_to_phy_id)/sizeof(subsys_id_to_phy_id[0]); i++) {
2386*8044SWilliam.Kucharski@Sun.COM if ((subsys_id_to_phy_id[i].subsys_vendor == tp->subsystem_vendor) &&
2387*8044SWilliam.Kucharski@Sun.COM (subsys_id_to_phy_id[i].subsys_devid == tp->subsystem_device)) {
2388*8044SWilliam.Kucharski@Sun.COM tp->phy_id = subsys_id_to_phy_id[i].phy_id;
2389*8044SWilliam.Kucharski@Sun.COM break;
2390*8044SWilliam.Kucharski@Sun.COM }
2391*8044SWilliam.Kucharski@Sun.COM }
2392*8044SWilliam.Kucharski@Sun.COM
2393*8044SWilliam.Kucharski@Sun.COM eeprom_phy_id = PHY_ID_INVALID;
2394*8044SWilliam.Kucharski@Sun.COM eeprom_led_mode = led_mode_auto;
2395*8044SWilliam.Kucharski@Sun.COM eeprom_signature_found = 0;
2396*8044SWilliam.Kucharski@Sun.COM tg3_read_mem(NIC_SRAM_DATA_SIG, &val);
2397*8044SWilliam.Kucharski@Sun.COM if (val == NIC_SRAM_DATA_SIG_MAGIC) {
2398*8044SWilliam.Kucharski@Sun.COM uint32_t nic_cfg;
2399*8044SWilliam.Kucharski@Sun.COM
2400*8044SWilliam.Kucharski@Sun.COM tg3_read_mem(NIC_SRAM_DATA_CFG, &nic_cfg);
2401*8044SWilliam.Kucharski@Sun.COM tp->nic_sram_data_cfg = nic_cfg;
2402*8044SWilliam.Kucharski@Sun.COM
2403*8044SWilliam.Kucharski@Sun.COM eeprom_signature_found = 1;
2404*8044SWilliam.Kucharski@Sun.COM
2405*8044SWilliam.Kucharski@Sun.COM if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
2406*8044SWilliam.Kucharski@Sun.COM NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) {
2407*8044SWilliam.Kucharski@Sun.COM eeprom_phy_id = PHY_ID_SERDES;
2408*8044SWilliam.Kucharski@Sun.COM } else {
2409*8044SWilliam.Kucharski@Sun.COM uint32_t nic_phy_id;
2410*8044SWilliam.Kucharski@Sun.COM
2411*8044SWilliam.Kucharski@Sun.COM tg3_read_mem(NIC_SRAM_DATA_PHY_ID, &nic_phy_id);
2412*8044SWilliam.Kucharski@Sun.COM if (nic_phy_id != 0) {
2413*8044SWilliam.Kucharski@Sun.COM uint32_t id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK;
2414*8044SWilliam.Kucharski@Sun.COM uint32_t id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK;
2415*8044SWilliam.Kucharski@Sun.COM
2416*8044SWilliam.Kucharski@Sun.COM eeprom_phy_id = (id1 >> 16) << 10;
2417*8044SWilliam.Kucharski@Sun.COM eeprom_phy_id |= (id2 & 0xfc00) << 16;
2418*8044SWilliam.Kucharski@Sun.COM eeprom_phy_id |= (id2 & 0x03ff) << 0;
2419*8044SWilliam.Kucharski@Sun.COM }
2420*8044SWilliam.Kucharski@Sun.COM }
2421*8044SWilliam.Kucharski@Sun.COM
2422*8044SWilliam.Kucharski@Sun.COM switch (nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK) {
2423*8044SWilliam.Kucharski@Sun.COM case NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD:
2424*8044SWilliam.Kucharski@Sun.COM eeprom_led_mode = led_mode_three_link;
2425*8044SWilliam.Kucharski@Sun.COM break;
2426*8044SWilliam.Kucharski@Sun.COM
2427*8044SWilliam.Kucharski@Sun.COM case NIC_SRAM_DATA_CFG_LED_LINK_SPD:
2428*8044SWilliam.Kucharski@Sun.COM eeprom_led_mode = led_mode_link10;
2429*8044SWilliam.Kucharski@Sun.COM break;
2430*8044SWilliam.Kucharski@Sun.COM
2431*8044SWilliam.Kucharski@Sun.COM default:
2432*8044SWilliam.Kucharski@Sun.COM eeprom_led_mode = led_mode_auto;
2433*8044SWilliam.Kucharski@Sun.COM break;
2434*8044SWilliam.Kucharski@Sun.COM };
2435*8044SWilliam.Kucharski@Sun.COM if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
2436*8044SWilliam.Kucharski@Sun.COM (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
2437*8044SWilliam.Kucharski@Sun.COM (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) &&
2438*8044SWilliam.Kucharski@Sun.COM (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP)) {
2439*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
2440*8044SWilliam.Kucharski@Sun.COM }
2441*8044SWilliam.Kucharski@Sun.COM
2442*8044SWilliam.Kucharski@Sun.COM if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE)
2443*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
2444*8044SWilliam.Kucharski@Sun.COM if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
2445*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
2446*8044SWilliam.Kucharski@Sun.COM }
2447*8044SWilliam.Kucharski@Sun.COM
2448*8044SWilliam.Kucharski@Sun.COM /* Now read the physical PHY_ID from the chip and verify
2449*8044SWilliam.Kucharski@Sun.COM * that it is sane. If it doesn't look good, we fall back
2450*8044SWilliam.Kucharski@Sun.COM * to either the hard-coded table based PHY_ID and failing
2451*8044SWilliam.Kucharski@Sun.COM * that the value found in the eeprom area.
2452*8044SWilliam.Kucharski@Sun.COM */
2453*8044SWilliam.Kucharski@Sun.COM err = tg3_readphy(tp, MII_PHYSID1, &hw_phy_id_1);
2454*8044SWilliam.Kucharski@Sun.COM err |= tg3_readphy(tp, MII_PHYSID2, &hw_phy_id_2);
2455*8044SWilliam.Kucharski@Sun.COM
2456*8044SWilliam.Kucharski@Sun.COM hw_phy_id = (hw_phy_id_1 & 0xffff) << 10;
2457*8044SWilliam.Kucharski@Sun.COM hw_phy_id |= (hw_phy_id_2 & 0xfc00) << 16;
2458*8044SWilliam.Kucharski@Sun.COM hw_phy_id |= (hw_phy_id_2 & 0x03ff) << 0;
2459*8044SWilliam.Kucharski@Sun.COM
2460*8044SWilliam.Kucharski@Sun.COM hw_phy_id_masked = hw_phy_id & PHY_ID_MASK;
2461*8044SWilliam.Kucharski@Sun.COM
2462*8044SWilliam.Kucharski@Sun.COM if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) {
2463*8044SWilliam.Kucharski@Sun.COM tp->phy_id = hw_phy_id;
2464*8044SWilliam.Kucharski@Sun.COM } else {
2465*8044SWilliam.Kucharski@Sun.COM /* phy_id currently holds the value found in the
2466*8044SWilliam.Kucharski@Sun.COM * subsys_id_to_phy_id[] table or PHY_ID_INVALID
2467*8044SWilliam.Kucharski@Sun.COM * if a match was not found there.
2468*8044SWilliam.Kucharski@Sun.COM */
2469*8044SWilliam.Kucharski@Sun.COM if (tp->phy_id == PHY_ID_INVALID) {
2470*8044SWilliam.Kucharski@Sun.COM if (!eeprom_signature_found ||
2471*8044SWilliam.Kucharski@Sun.COM !KNOWN_PHY_ID(eeprom_phy_id & PHY_ID_MASK))
2472*8044SWilliam.Kucharski@Sun.COM return -ENODEV;
2473*8044SWilliam.Kucharski@Sun.COM tp->phy_id = eeprom_phy_id;
2474*8044SWilliam.Kucharski@Sun.COM }
2475*8044SWilliam.Kucharski@Sun.COM }
2476*8044SWilliam.Kucharski@Sun.COM
2477*8044SWilliam.Kucharski@Sun.COM err = tg3_phy_reset(tp);
2478*8044SWilliam.Kucharski@Sun.COM if (err)
2479*8044SWilliam.Kucharski@Sun.COM return err;
2480*8044SWilliam.Kucharski@Sun.COM
2481*8044SWilliam.Kucharski@Sun.COM if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
2482*8044SWilliam.Kucharski@Sun.COM tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
2483*8044SWilliam.Kucharski@Sun.COM uint32_t mii_tg3_ctrl;
2484*8044SWilliam.Kucharski@Sun.COM
2485*8044SWilliam.Kucharski@Sun.COM /* These chips, when reset, only advertise 10Mb
2486*8044SWilliam.Kucharski@Sun.COM * capabilities. Fix that.
2487*8044SWilliam.Kucharski@Sun.COM */
2488*8044SWilliam.Kucharski@Sun.COM err = tg3_writephy(tp, MII_ADVERTISE,
2489*8044SWilliam.Kucharski@Sun.COM (ADVERTISE_CSMA |
2490*8044SWilliam.Kucharski@Sun.COM ADVERTISE_PAUSE_CAP |
2491*8044SWilliam.Kucharski@Sun.COM ADVERTISE_10HALF |
2492*8044SWilliam.Kucharski@Sun.COM ADVERTISE_10FULL |
2493*8044SWilliam.Kucharski@Sun.COM ADVERTISE_100HALF |
2494*8044SWilliam.Kucharski@Sun.COM ADVERTISE_100FULL));
2495*8044SWilliam.Kucharski@Sun.COM mii_tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF |
2496*8044SWilliam.Kucharski@Sun.COM MII_TG3_CTRL_ADV_1000_FULL |
2497*8044SWilliam.Kucharski@Sun.COM MII_TG3_CTRL_AS_MASTER |
2498*8044SWilliam.Kucharski@Sun.COM MII_TG3_CTRL_ENABLE_AS_MASTER);
2499*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
2500*8044SWilliam.Kucharski@Sun.COM mii_tg3_ctrl = 0;
2501*8044SWilliam.Kucharski@Sun.COM
2502*8044SWilliam.Kucharski@Sun.COM err |= tg3_writephy(tp, MII_TG3_CTRL, mii_tg3_ctrl);
2503*8044SWilliam.Kucharski@Sun.COM err |= tg3_writephy(tp, MII_BMCR,
2504*8044SWilliam.Kucharski@Sun.COM (BMCR_ANRESTART | BMCR_ANENABLE));
2505*8044SWilliam.Kucharski@Sun.COM }
2506*8044SWilliam.Kucharski@Sun.COM
2507*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
2508*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
2509*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
2510*8044SWilliam.Kucharski@Sun.COM tg3_writedsp(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
2511*8044SWilliam.Kucharski@Sun.COM }
2512*8044SWilliam.Kucharski@Sun.COM
2513*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
2514*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x1c, 0x8d68);
2515*8044SWilliam.Kucharski@Sun.COM tg3_writephy(tp, 0x1c, 0x8d68);
2516*8044SWilliam.Kucharski@Sun.COM }
2517*8044SWilliam.Kucharski@Sun.COM
2518*8044SWilliam.Kucharski@Sun.COM /* Enable Ethernet@WireSpeed */
2519*8044SWilliam.Kucharski@Sun.COM tg3_phy_set_wirespeed(tp);
2520*8044SWilliam.Kucharski@Sun.COM
2521*8044SWilliam.Kucharski@Sun.COM if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) {
2522*8044SWilliam.Kucharski@Sun.COM err = tg3_init_5401phy_dsp(tp);
2523*8044SWilliam.Kucharski@Sun.COM }
2524*8044SWilliam.Kucharski@Sun.COM
2525*8044SWilliam.Kucharski@Sun.COM /* Determine the PHY led mode.
2526*8044SWilliam.Kucharski@Sun.COM * Be careful if this gets set wrong it can result in an inability to
2527*8044SWilliam.Kucharski@Sun.COM * establish a link.
2528*8044SWilliam.Kucharski@Sun.COM */
2529*8044SWilliam.Kucharski@Sun.COM if (tp->phy_id == PHY_ID_SERDES) {
2530*8044SWilliam.Kucharski@Sun.COM tp->led_mode = led_mode_three_link;
2531*8044SWilliam.Kucharski@Sun.COM }
2532*8044SWilliam.Kucharski@Sun.COM else if (tp->subsystem_vendor == PCI_VENDOR_ID_DELL) {
2533*8044SWilliam.Kucharski@Sun.COM tp->led_mode = led_mode_link10;
2534*8044SWilliam.Kucharski@Sun.COM } else {
2535*8044SWilliam.Kucharski@Sun.COM tp->led_mode = led_mode_three_link;
2536*8044SWilliam.Kucharski@Sun.COM if (eeprom_signature_found &&
2537*8044SWilliam.Kucharski@Sun.COM eeprom_led_mode != led_mode_auto)
2538*8044SWilliam.Kucharski@Sun.COM tp->led_mode = eeprom_led_mode;
2539*8044SWilliam.Kucharski@Sun.COM }
2540*8044SWilliam.Kucharski@Sun.COM
2541*8044SWilliam.Kucharski@Sun.COM if (tp->phy_id == PHY_ID_SERDES)
2542*8044SWilliam.Kucharski@Sun.COM tp->link_config.advertising =
2543*8044SWilliam.Kucharski@Sun.COM (ADVERTISED_1000baseT_Half |
2544*8044SWilliam.Kucharski@Sun.COM ADVERTISED_1000baseT_Full |
2545*8044SWilliam.Kucharski@Sun.COM ADVERTISED_Autoneg |
2546*8044SWilliam.Kucharski@Sun.COM ADVERTISED_FIBRE);
2547*8044SWilliam.Kucharski@Sun.COM if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
2548*8044SWilliam.Kucharski@Sun.COM tp->link_config.advertising &=
2549*8044SWilliam.Kucharski@Sun.COM ~(ADVERTISED_1000baseT_Half |
2550*8044SWilliam.Kucharski@Sun.COM ADVERTISED_1000baseT_Full);
2551*8044SWilliam.Kucharski@Sun.COM
2552*8044SWilliam.Kucharski@Sun.COM return err;
2553*8044SWilliam.Kucharski@Sun.COM }
2554*8044SWilliam.Kucharski@Sun.COM
2555*8044SWilliam.Kucharski@Sun.COM #if SUPPORT_PARTNO_STR
tg3_read_partno(struct tg3 * tp)2556*8044SWilliam.Kucharski@Sun.COM static void tg3_read_partno(struct tg3 *tp)
2557*8044SWilliam.Kucharski@Sun.COM {
2558*8044SWilliam.Kucharski@Sun.COM unsigned char vpd_data[256];
2559*8044SWilliam.Kucharski@Sun.COM int i;
2560*8044SWilliam.Kucharski@Sun.COM
2561*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 256; i += 4) {
2562*8044SWilliam.Kucharski@Sun.COM uint32_t tmp;
2563*8044SWilliam.Kucharski@Sun.COM
2564*8044SWilliam.Kucharski@Sun.COM if (tg3_nvram_read(tp, 0x100 + i, &tmp))
2565*8044SWilliam.Kucharski@Sun.COM goto out_not_found;
2566*8044SWilliam.Kucharski@Sun.COM
2567*8044SWilliam.Kucharski@Sun.COM vpd_data[i + 0] = ((tmp >> 0) & 0xff);
2568*8044SWilliam.Kucharski@Sun.COM vpd_data[i + 1] = ((tmp >> 8) & 0xff);
2569*8044SWilliam.Kucharski@Sun.COM vpd_data[i + 2] = ((tmp >> 16) & 0xff);
2570*8044SWilliam.Kucharski@Sun.COM vpd_data[i + 3] = ((tmp >> 24) & 0xff);
2571*8044SWilliam.Kucharski@Sun.COM }
2572*8044SWilliam.Kucharski@Sun.COM
2573*8044SWilliam.Kucharski@Sun.COM /* Now parse and find the part number. */
2574*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 256; ) {
2575*8044SWilliam.Kucharski@Sun.COM unsigned char val = vpd_data[i];
2576*8044SWilliam.Kucharski@Sun.COM int block_end;
2577*8044SWilliam.Kucharski@Sun.COM
2578*8044SWilliam.Kucharski@Sun.COM if (val == 0x82 || val == 0x91) {
2579*8044SWilliam.Kucharski@Sun.COM i = (i + 3 +
2580*8044SWilliam.Kucharski@Sun.COM (vpd_data[i + 1] +
2581*8044SWilliam.Kucharski@Sun.COM (vpd_data[i + 2] << 8)));
2582*8044SWilliam.Kucharski@Sun.COM continue;
2583*8044SWilliam.Kucharski@Sun.COM }
2584*8044SWilliam.Kucharski@Sun.COM
2585*8044SWilliam.Kucharski@Sun.COM if (val != 0x90)
2586*8044SWilliam.Kucharski@Sun.COM goto out_not_found;
2587*8044SWilliam.Kucharski@Sun.COM
2588*8044SWilliam.Kucharski@Sun.COM block_end = (i + 3 +
2589*8044SWilliam.Kucharski@Sun.COM (vpd_data[i + 1] +
2590*8044SWilliam.Kucharski@Sun.COM (vpd_data[i + 2] << 8)));
2591*8044SWilliam.Kucharski@Sun.COM i += 3;
2592*8044SWilliam.Kucharski@Sun.COM while (i < block_end) {
2593*8044SWilliam.Kucharski@Sun.COM if (vpd_data[i + 0] == 'P' &&
2594*8044SWilliam.Kucharski@Sun.COM vpd_data[i + 1] == 'N') {
2595*8044SWilliam.Kucharski@Sun.COM int partno_len = vpd_data[i + 2];
2596*8044SWilliam.Kucharski@Sun.COM
2597*8044SWilliam.Kucharski@Sun.COM if (partno_len > 24)
2598*8044SWilliam.Kucharski@Sun.COM goto out_not_found;
2599*8044SWilliam.Kucharski@Sun.COM
2600*8044SWilliam.Kucharski@Sun.COM memcpy(tp->board_part_number,
2601*8044SWilliam.Kucharski@Sun.COM &vpd_data[i + 3],
2602*8044SWilliam.Kucharski@Sun.COM partno_len);
2603*8044SWilliam.Kucharski@Sun.COM
2604*8044SWilliam.Kucharski@Sun.COM /* Success. */
2605*8044SWilliam.Kucharski@Sun.COM return;
2606*8044SWilliam.Kucharski@Sun.COM }
2607*8044SWilliam.Kucharski@Sun.COM }
2608*8044SWilliam.Kucharski@Sun.COM
2609*8044SWilliam.Kucharski@Sun.COM /* Part number not found. */
2610*8044SWilliam.Kucharski@Sun.COM goto out_not_found;
2611*8044SWilliam.Kucharski@Sun.COM }
2612*8044SWilliam.Kucharski@Sun.COM
2613*8044SWilliam.Kucharski@Sun.COM out_not_found:
2614*8044SWilliam.Kucharski@Sun.COM memcpy(tp->board_part_number, "none", sizeof("none"));
2615*8044SWilliam.Kucharski@Sun.COM }
2616*8044SWilliam.Kucharski@Sun.COM #else
2617*8044SWilliam.Kucharski@Sun.COM #define tg3_read_partno(TP) ((TP)->board_part_number[0] = '\0')
2618*8044SWilliam.Kucharski@Sun.COM #endif
2619*8044SWilliam.Kucharski@Sun.COM
tg3_get_invariants(struct tg3 * tp)2620*8044SWilliam.Kucharski@Sun.COM static int tg3_get_invariants(struct tg3 *tp)
2621*8044SWilliam.Kucharski@Sun.COM {
2622*8044SWilliam.Kucharski@Sun.COM uint32_t misc_ctrl_reg;
2623*8044SWilliam.Kucharski@Sun.COM uint32_t pci_state_reg, grc_misc_cfg;
2624*8044SWilliam.Kucharski@Sun.COM uint16_t pci_cmd;
2625*8044SWilliam.Kucharski@Sun.COM uint8_t pci_latency;
2626*8044SWilliam.Kucharski@Sun.COM int err;
2627*8044SWilliam.Kucharski@Sun.COM
2628*8044SWilliam.Kucharski@Sun.COM /* Read the subsystem vendor and device ids */
2629*8044SWilliam.Kucharski@Sun.COM pci_read_config_word(tp->pdev, PCI_SUBSYSTEM_VENDOR_ID, &tp->subsystem_vendor);
2630*8044SWilliam.Kucharski@Sun.COM pci_read_config_word(tp->pdev, PCI_SUBSYSTEM_ID, &tp->subsystem_device);
2631*8044SWilliam.Kucharski@Sun.COM
2632*8044SWilliam.Kucharski@Sun.COM /* The sun_5704 code needs infrastructure etherboot does have
2633*8044SWilliam.Kucharski@Sun.COM * ignore it for now.
2634*8044SWilliam.Kucharski@Sun.COM */
2635*8044SWilliam.Kucharski@Sun.COM
2636*8044SWilliam.Kucharski@Sun.COM /* If we have an AMD 762 or Intel ICH/ICH0 chipset, write
2637*8044SWilliam.Kucharski@Sun.COM * reordering to the mailbox registers done by the host
2638*8044SWilliam.Kucharski@Sun.COM * controller can cause major troubles. We read back from
2639*8044SWilliam.Kucharski@Sun.COM * every mailbox register write to force the writes to be
2640*8044SWilliam.Kucharski@Sun.COM * posted to the chip in order.
2641*8044SWilliam.Kucharski@Sun.COM *
2642*8044SWilliam.Kucharski@Sun.COM * TG3_FLAG_MBOX_WRITE_REORDER has been forced on.
2643*8044SWilliam.Kucharski@Sun.COM */
2644*8044SWilliam.Kucharski@Sun.COM
2645*8044SWilliam.Kucharski@Sun.COM /* Force memory write invalidate off. If we leave it on,
2646*8044SWilliam.Kucharski@Sun.COM * then on 5700_BX chips we have to enable a workaround.
2647*8044SWilliam.Kucharski@Sun.COM * The workaround is to set the TG3PCI_DMA_RW_CTRL boundry
2648*8044SWilliam.Kucharski@Sun.COM * to match the cacheline size. The Broadcom driver have this
2649*8044SWilliam.Kucharski@Sun.COM * workaround but turns MWI off all the times so never uses
2650*8044SWilliam.Kucharski@Sun.COM * it. This seems to suggest that the workaround is insufficient.
2651*8044SWilliam.Kucharski@Sun.COM */
2652*8044SWilliam.Kucharski@Sun.COM pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
2653*8044SWilliam.Kucharski@Sun.COM pci_cmd &= ~PCI_COMMAND_INVALIDATE;
2654*8044SWilliam.Kucharski@Sun.COM /* Also, force SERR#/PERR# in PCI command. */
2655*8044SWilliam.Kucharski@Sun.COM pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
2656*8044SWilliam.Kucharski@Sun.COM pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
2657*8044SWilliam.Kucharski@Sun.COM
2658*8044SWilliam.Kucharski@Sun.COM /* It is absolutely critical that TG3PCI_MISC_HOST_CTRL
2659*8044SWilliam.Kucharski@Sun.COM * has the register indirect write enable bit set before
2660*8044SWilliam.Kucharski@Sun.COM * we try to access any of the MMIO registers. It is also
2661*8044SWilliam.Kucharski@Sun.COM * critical that the PCI-X hw workaround situation is decided
2662*8044SWilliam.Kucharski@Sun.COM * before that as well.
2663*8044SWilliam.Kucharski@Sun.COM */
2664*8044SWilliam.Kucharski@Sun.COM pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, &misc_ctrl_reg);
2665*8044SWilliam.Kucharski@Sun.COM
2666*8044SWilliam.Kucharski@Sun.COM tp->pci_chip_rev_id = (misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT);
2667*8044SWilliam.Kucharski@Sun.COM
2668*8044SWilliam.Kucharski@Sun.COM /* Initialize misc host control in PCI block. */
2669*8044SWilliam.Kucharski@Sun.COM tp->misc_host_ctrl |= (misc_ctrl_reg &
2670*8044SWilliam.Kucharski@Sun.COM MISC_HOST_CTRL_CHIPREV);
2671*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
2672*8044SWilliam.Kucharski@Sun.COM tp->misc_host_ctrl);
2673*8044SWilliam.Kucharski@Sun.COM
2674*8044SWilliam.Kucharski@Sun.COM pci_read_config_byte(tp->pdev, PCI_LATENCY_TIMER, &pci_latency);
2675*8044SWilliam.Kucharski@Sun.COM if (pci_latency < 64) {
2676*8044SWilliam.Kucharski@Sun.COM pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER, 64);
2677*8044SWilliam.Kucharski@Sun.COM }
2678*8044SWilliam.Kucharski@Sun.COM
2679*8044SWilliam.Kucharski@Sun.COM pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg);
2680*8044SWilliam.Kucharski@Sun.COM
2681*8044SWilliam.Kucharski@Sun.COM /* If this is a 5700 BX chipset, and we are in PCI-X
2682*8044SWilliam.Kucharski@Sun.COM * mode, enable register write workaround.
2683*8044SWilliam.Kucharski@Sun.COM *
2684*8044SWilliam.Kucharski@Sun.COM * The workaround is to use indirect register accesses
2685*8044SWilliam.Kucharski@Sun.COM * for all chip writes not to mailbox registers.
2686*8044SWilliam.Kucharski@Sun.COM *
2687*8044SWilliam.Kucharski@Sun.COM * In etherboot to simplify things we just always use this work around.
2688*8044SWilliam.Kucharski@Sun.COM */
2689*8044SWilliam.Kucharski@Sun.COM if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
2690*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_PCIX_MODE;
2691*8044SWilliam.Kucharski@Sun.COM }
2692*8044SWilliam.Kucharski@Sun.COM /* Back to back register writes can cause problems on the 5701,
2693*8044SWilliam.Kucharski@Sun.COM * the workaround is to read back all reg writes except those to
2694*8044SWilliam.Kucharski@Sun.COM * mailbox regs.
2695*8044SWilliam.Kucharski@Sun.COM * In etherboot we always use indirect register accesses so
2696*8044SWilliam.Kucharski@Sun.COM * we don't see this.
2697*8044SWilliam.Kucharski@Sun.COM */
2698*8044SWilliam.Kucharski@Sun.COM
2699*8044SWilliam.Kucharski@Sun.COM if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
2700*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED;
2701*8044SWilliam.Kucharski@Sun.COM if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
2702*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_PCI_32BIT;
2703*8044SWilliam.Kucharski@Sun.COM
2704*8044SWilliam.Kucharski@Sun.COM /* Chip-specific fixup from Broadcom driver */
2705*8044SWilliam.Kucharski@Sun.COM if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) &&
2706*8044SWilliam.Kucharski@Sun.COM (!(pci_state_reg & PCISTATE_RETRY_SAME_DMA))) {
2707*8044SWilliam.Kucharski@Sun.COM pci_state_reg |= PCISTATE_RETRY_SAME_DMA;
2708*8044SWilliam.Kucharski@Sun.COM pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
2709*8044SWilliam.Kucharski@Sun.COM }
2710*8044SWilliam.Kucharski@Sun.COM
2711*8044SWilliam.Kucharski@Sun.COM /* Force the chip into D0. */
2712*8044SWilliam.Kucharski@Sun.COM tg3_set_power_state_0(tp);
2713*8044SWilliam.Kucharski@Sun.COM
2714*8044SWilliam.Kucharski@Sun.COM /* Etherboot does not ask the tg3 to do checksums */
2715*8044SWilliam.Kucharski@Sun.COM /* Etherboot does not ask the tg3 to do jumbo frames */
2716*8044SWilliam.Kucharski@Sun.COM /* Ehterboot does not ask the tg3 to use WakeOnLan. */
2717*8044SWilliam.Kucharski@Sun.COM
2718*8044SWilliam.Kucharski@Sun.COM /* A few boards don't want Ethernet@WireSpeed phy feature */
2719*8044SWilliam.Kucharski@Sun.COM if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) ||
2720*8044SWilliam.Kucharski@Sun.COM ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
2721*8044SWilliam.Kucharski@Sun.COM (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
2722*8044SWilliam.Kucharski@Sun.COM (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1))) {
2723*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
2724*8044SWilliam.Kucharski@Sun.COM }
2725*8044SWilliam.Kucharski@Sun.COM
2726*8044SWilliam.Kucharski@Sun.COM /* Avoid tagged irq status etherboot does not use irqs */
2727*8044SWilliam.Kucharski@Sun.COM
2728*8044SWilliam.Kucharski@Sun.COM /* Only 5701 and later support tagged irq status mode.
2729*8044SWilliam.Kucharski@Sun.COM * Also, 5788 chips cannot use tagged irq status.
2730*8044SWilliam.Kucharski@Sun.COM *
2731*8044SWilliam.Kucharski@Sun.COM * However, since etherboot does not use irqs avoid tagged irqs
2732*8044SWilliam.Kucharski@Sun.COM * status because the interrupt condition is more difficult to
2733*8044SWilliam.Kucharski@Sun.COM * fully clear in that mode.
2734*8044SWilliam.Kucharski@Sun.COM */
2735*8044SWilliam.Kucharski@Sun.COM
2736*8044SWilliam.Kucharski@Sun.COM /* Since some 5700_AX && 5700_BX have problems with 32BYTE
2737*8044SWilliam.Kucharski@Sun.COM * coalesce_mode, and the rest work fine anything set.
2738*8044SWilliam.Kucharski@Sun.COM * Don't enable HOST_CC_MODE_32BYTE in etherboot.
2739*8044SWilliam.Kucharski@Sun.COM */
2740*8044SWilliam.Kucharski@Sun.COM
2741*8044SWilliam.Kucharski@Sun.COM /* Initialize MAC MI mode, polling disabled. */
2742*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MI_MODE, tp->mi_mode);
2743*8044SWilliam.Kucharski@Sun.COM
2744*8044SWilliam.Kucharski@Sun.COM /* Initialize data/descriptor byte/word swapping. */
2745*8044SWilliam.Kucharski@Sun.COM tw32(GRC_MODE, tp->grc_mode);
2746*8044SWilliam.Kucharski@Sun.COM
2747*8044SWilliam.Kucharski@Sun.COM tg3_switch_clocks(tp);
2748*8044SWilliam.Kucharski@Sun.COM
2749*8044SWilliam.Kucharski@Sun.COM /* Clear this out for sanity. */
2750*8044SWilliam.Kucharski@Sun.COM tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
2751*8044SWilliam.Kucharski@Sun.COM
2752*8044SWilliam.Kucharski@Sun.COM /* Etherboot does not need to check if the PCIX_TARGET_HWBUG
2753*8044SWilliam.Kucharski@Sun.COM * is needed. It always uses it.
2754*8044SWilliam.Kucharski@Sun.COM */
2755*8044SWilliam.Kucharski@Sun.COM
2756*8044SWilliam.Kucharski@Sun.COM udelay(50);
2757*8044SWilliam.Kucharski@Sun.COM tg3_nvram_init(tp);
2758*8044SWilliam.Kucharski@Sun.COM
2759*8044SWilliam.Kucharski@Sun.COM /* The TX descriptors will reside in main memory.
2760*8044SWilliam.Kucharski@Sun.COM */
2761*8044SWilliam.Kucharski@Sun.COM
2762*8044SWilliam.Kucharski@Sun.COM /* See which board we are using.
2763*8044SWilliam.Kucharski@Sun.COM */
2764*8044SWilliam.Kucharski@Sun.COM grc_misc_cfg = tr32(GRC_MISC_CFG);
2765*8044SWilliam.Kucharski@Sun.COM grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
2766*8044SWilliam.Kucharski@Sun.COM
2767*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
2768*8044SWilliam.Kucharski@Sun.COM grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) {
2769*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_SPLIT_MODE;
2770*8044SWilliam.Kucharski@Sun.COM tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ;
2771*8044SWilliam.Kucharski@Sun.COM }
2772*8044SWilliam.Kucharski@Sun.COM
2773*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
2774*8044SWilliam.Kucharski@Sun.COM (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 ||
2775*8044SWilliam.Kucharski@Sun.COM grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
2776*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags2 |= TG3_FLG2_IS_5788;
2777*8044SWilliam.Kucharski@Sun.COM
2778*8044SWilliam.Kucharski@Sun.COM /* these are limited to 10/100 only */
2779*8044SWilliam.Kucharski@Sun.COM if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) &&
2780*8044SWilliam.Kucharski@Sun.COM ((grc_misc_cfg == 0x8000) || (grc_misc_cfg == 0x4000))) ||
2781*8044SWilliam.Kucharski@Sun.COM ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
2782*8044SWilliam.Kucharski@Sun.COM (tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM) &&
2783*8044SWilliam.Kucharski@Sun.COM ((tp->pdev->dev_id == PCI_DEVICE_ID_TIGON3_5901) ||
2784*8044SWilliam.Kucharski@Sun.COM (tp->pdev->dev_id == PCI_DEVICE_ID_TIGON3_5901_2)))) {
2785*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
2786*8044SWilliam.Kucharski@Sun.COM }
2787*8044SWilliam.Kucharski@Sun.COM
2788*8044SWilliam.Kucharski@Sun.COM err = tg3_phy_probe(tp);
2789*8044SWilliam.Kucharski@Sun.COM if (err) {
2790*8044SWilliam.Kucharski@Sun.COM printf("phy probe failed, err %d\n", err);
2791*8044SWilliam.Kucharski@Sun.COM }
2792*8044SWilliam.Kucharski@Sun.COM
2793*8044SWilliam.Kucharski@Sun.COM tg3_read_partno(tp);
2794*8044SWilliam.Kucharski@Sun.COM
2795*8044SWilliam.Kucharski@Sun.COM
2796*8044SWilliam.Kucharski@Sun.COM /* 5700 BX chips need to have their TX producer index mailboxes
2797*8044SWilliam.Kucharski@Sun.COM * written twice to workaround a bug.
2798*8044SWilliam.Kucharski@Sun.COM * In etherboot we do this unconditionally to simplify things.
2799*8044SWilliam.Kucharski@Sun.COM */
2800*8044SWilliam.Kucharski@Sun.COM
2801*8044SWilliam.Kucharski@Sun.COM /* 5700 chips can get confused if TX buffers straddle the
2802*8044SWilliam.Kucharski@Sun.COM * 4GB address boundary in some cases.
2803*8044SWilliam.Kucharski@Sun.COM *
2804*8044SWilliam.Kucharski@Sun.COM * In etherboot we can ignore the problem as etherboot lives below 4GB.
2805*8044SWilliam.Kucharski@Sun.COM */
2806*8044SWilliam.Kucharski@Sun.COM
2807*8044SWilliam.Kucharski@Sun.COM /* In etherboot wake-on-lan is unconditionally disabled */
2808*8044SWilliam.Kucharski@Sun.COM return err;
2809*8044SWilliam.Kucharski@Sun.COM }
2810*8044SWilliam.Kucharski@Sun.COM
tg3_get_device_address(struct tg3 * tp)2811*8044SWilliam.Kucharski@Sun.COM static int tg3_get_device_address(struct tg3 *tp)
2812*8044SWilliam.Kucharski@Sun.COM {
2813*8044SWilliam.Kucharski@Sun.COM struct nic *nic = tp->nic;
2814*8044SWilliam.Kucharski@Sun.COM uint32_t hi, lo, mac_offset;
2815*8044SWilliam.Kucharski@Sun.COM
2816*8044SWilliam.Kucharski@Sun.COM if (PCI_FUNC(tp->pdev->devfn) == 0)
2817*8044SWilliam.Kucharski@Sun.COM mac_offset = 0x7c;
2818*8044SWilliam.Kucharski@Sun.COM else
2819*8044SWilliam.Kucharski@Sun.COM mac_offset = 0xcc;
2820*8044SWilliam.Kucharski@Sun.COM
2821*8044SWilliam.Kucharski@Sun.COM /* First try to get it from MAC address mailbox. */
2822*8044SWilliam.Kucharski@Sun.COM tg3_read_mem(NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
2823*8044SWilliam.Kucharski@Sun.COM if ((hi >> 16) == 0x484b) {
2824*8044SWilliam.Kucharski@Sun.COM nic->node_addr[0] = (hi >> 8) & 0xff;
2825*8044SWilliam.Kucharski@Sun.COM nic->node_addr[1] = (hi >> 0) & 0xff;
2826*8044SWilliam.Kucharski@Sun.COM
2827*8044SWilliam.Kucharski@Sun.COM tg3_read_mem(NIC_SRAM_MAC_ADDR_LOW_MBOX, &lo);
2828*8044SWilliam.Kucharski@Sun.COM nic->node_addr[2] = (lo >> 24) & 0xff;
2829*8044SWilliam.Kucharski@Sun.COM nic->node_addr[3] = (lo >> 16) & 0xff;
2830*8044SWilliam.Kucharski@Sun.COM nic->node_addr[4] = (lo >> 8) & 0xff;
2831*8044SWilliam.Kucharski@Sun.COM nic->node_addr[5] = (lo >> 0) & 0xff;
2832*8044SWilliam.Kucharski@Sun.COM }
2833*8044SWilliam.Kucharski@Sun.COM /* Next, try NVRAM. */
2834*8044SWilliam.Kucharski@Sun.COM else if (!tg3_nvram_read(tp, mac_offset + 0, &hi) &&
2835*8044SWilliam.Kucharski@Sun.COM !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
2836*8044SWilliam.Kucharski@Sun.COM nic->node_addr[0] = ((hi >> 16) & 0xff);
2837*8044SWilliam.Kucharski@Sun.COM nic->node_addr[1] = ((hi >> 24) & 0xff);
2838*8044SWilliam.Kucharski@Sun.COM nic->node_addr[2] = ((lo >> 0) & 0xff);
2839*8044SWilliam.Kucharski@Sun.COM nic->node_addr[3] = ((lo >> 8) & 0xff);
2840*8044SWilliam.Kucharski@Sun.COM nic->node_addr[4] = ((lo >> 16) & 0xff);
2841*8044SWilliam.Kucharski@Sun.COM nic->node_addr[5] = ((lo >> 24) & 0xff);
2842*8044SWilliam.Kucharski@Sun.COM }
2843*8044SWilliam.Kucharski@Sun.COM /* Finally just fetch it out of the MAC control regs. */
2844*8044SWilliam.Kucharski@Sun.COM else {
2845*8044SWilliam.Kucharski@Sun.COM hi = tr32(MAC_ADDR_0_HIGH);
2846*8044SWilliam.Kucharski@Sun.COM lo = tr32(MAC_ADDR_0_LOW);
2847*8044SWilliam.Kucharski@Sun.COM
2848*8044SWilliam.Kucharski@Sun.COM nic->node_addr[5] = lo & 0xff;
2849*8044SWilliam.Kucharski@Sun.COM nic->node_addr[4] = (lo >> 8) & 0xff;
2850*8044SWilliam.Kucharski@Sun.COM nic->node_addr[3] = (lo >> 16) & 0xff;
2851*8044SWilliam.Kucharski@Sun.COM nic->node_addr[2] = (lo >> 24) & 0xff;
2852*8044SWilliam.Kucharski@Sun.COM nic->node_addr[1] = hi & 0xff;
2853*8044SWilliam.Kucharski@Sun.COM nic->node_addr[0] = (hi >> 8) & 0xff;
2854*8044SWilliam.Kucharski@Sun.COM }
2855*8044SWilliam.Kucharski@Sun.COM
2856*8044SWilliam.Kucharski@Sun.COM return 0;
2857*8044SWilliam.Kucharski@Sun.COM }
2858*8044SWilliam.Kucharski@Sun.COM
2859*8044SWilliam.Kucharski@Sun.COM
tg3_setup_dma(struct tg3 * tp)2860*8044SWilliam.Kucharski@Sun.COM static int tg3_setup_dma(struct tg3 *tp)
2861*8044SWilliam.Kucharski@Sun.COM {
2862*8044SWilliam.Kucharski@Sun.COM tw32(TG3PCI_CLOCK_CTRL, 0);
2863*8044SWilliam.Kucharski@Sun.COM
2864*8044SWilliam.Kucharski@Sun.COM if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) == 0) {
2865*8044SWilliam.Kucharski@Sun.COM tp->dma_rwctrl =
2866*8044SWilliam.Kucharski@Sun.COM (0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
2867*8044SWilliam.Kucharski@Sun.COM (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
2868*8044SWilliam.Kucharski@Sun.COM (0x7 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
2869*8044SWilliam.Kucharski@Sun.COM (0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
2870*8044SWilliam.Kucharski@Sun.COM (0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
2871*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
2872*8044SWilliam.Kucharski@Sun.COM tp->dma_rwctrl &= ~(DMA_RWCTRL_MIN_DMA << DMA_RWCTRL_MIN_DMA_SHIFT);
2873*8044SWilliam.Kucharski@Sun.COM }
2874*8044SWilliam.Kucharski@Sun.COM } else {
2875*8044SWilliam.Kucharski@Sun.COM if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
2876*8044SWilliam.Kucharski@Sun.COM tp->dma_rwctrl =
2877*8044SWilliam.Kucharski@Sun.COM (0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
2878*8044SWilliam.Kucharski@Sun.COM (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
2879*8044SWilliam.Kucharski@Sun.COM (0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
2880*8044SWilliam.Kucharski@Sun.COM (0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
2881*8044SWilliam.Kucharski@Sun.COM (0x00 << DMA_RWCTRL_MIN_DMA_SHIFT);
2882*8044SWilliam.Kucharski@Sun.COM else
2883*8044SWilliam.Kucharski@Sun.COM tp->dma_rwctrl =
2884*8044SWilliam.Kucharski@Sun.COM (0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
2885*8044SWilliam.Kucharski@Sun.COM (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
2886*8044SWilliam.Kucharski@Sun.COM (0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
2887*8044SWilliam.Kucharski@Sun.COM (0x3 << DMA_RWCTRL_READ_WATER_SHIFT) |
2888*8044SWilliam.Kucharski@Sun.COM (0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
2889*8044SWilliam.Kucharski@Sun.COM
2890*8044SWilliam.Kucharski@Sun.COM /* Wheee, some more chip bugs... */
2891*8044SWilliam.Kucharski@Sun.COM if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
2892*8044SWilliam.Kucharski@Sun.COM (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)) {
2893*8044SWilliam.Kucharski@Sun.COM uint32_t ccval = tr32(TG3PCI_CLOCK_CTRL) & 0x1f;
2894*8044SWilliam.Kucharski@Sun.COM
2895*8044SWilliam.Kucharski@Sun.COM if ((ccval == 0x6) || (ccval == 0x7)) {
2896*8044SWilliam.Kucharski@Sun.COM tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
2897*8044SWilliam.Kucharski@Sun.COM }
2898*8044SWilliam.Kucharski@Sun.COM }
2899*8044SWilliam.Kucharski@Sun.COM }
2900*8044SWilliam.Kucharski@Sun.COM
2901*8044SWilliam.Kucharski@Sun.COM if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
2902*8044SWilliam.Kucharski@Sun.COM (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)) {
2903*8044SWilliam.Kucharski@Sun.COM tp->dma_rwctrl &= ~(DMA_RWCTRL_MIN_DMA << DMA_RWCTRL_MIN_DMA_SHIFT);
2904*8044SWilliam.Kucharski@Sun.COM }
2905*8044SWilliam.Kucharski@Sun.COM
2906*8044SWilliam.Kucharski@Sun.COM tp->dma_rwctrl |= DMA_RWCTRL_ASSERT_ALL_BE;
2907*8044SWilliam.Kucharski@Sun.COM
2908*8044SWilliam.Kucharski@Sun.COM tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
2909*8044SWilliam.Kucharski@Sun.COM
2910*8044SWilliam.Kucharski@Sun.COM return 0;
2911*8044SWilliam.Kucharski@Sun.COM }
2912*8044SWilliam.Kucharski@Sun.COM
tg3_init_link_config(struct tg3 * tp)2913*8044SWilliam.Kucharski@Sun.COM static void tg3_init_link_config(struct tg3 *tp)
2914*8044SWilliam.Kucharski@Sun.COM {
2915*8044SWilliam.Kucharski@Sun.COM tp->link_config.advertising =
2916*8044SWilliam.Kucharski@Sun.COM (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
2917*8044SWilliam.Kucharski@Sun.COM ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
2918*8044SWilliam.Kucharski@Sun.COM ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full |
2919*8044SWilliam.Kucharski@Sun.COM ADVERTISED_Autoneg | ADVERTISED_MII);
2920*8044SWilliam.Kucharski@Sun.COM tp->carrier_ok = 0;
2921*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_speed = SPEED_INVALID;
2922*8044SWilliam.Kucharski@Sun.COM tp->link_config.active_duplex = DUPLEX_INVALID;
2923*8044SWilliam.Kucharski@Sun.COM }
2924*8044SWilliam.Kucharski@Sun.COM
2925*8044SWilliam.Kucharski@Sun.COM
2926*8044SWilliam.Kucharski@Sun.COM #if SUPPORT_PHY_STR
tg3_phy_string(struct tg3 * tp)2927*8044SWilliam.Kucharski@Sun.COM static const char * tg3_phy_string(struct tg3 *tp)
2928*8044SWilliam.Kucharski@Sun.COM {
2929*8044SWilliam.Kucharski@Sun.COM switch (tp->phy_id & PHY_ID_MASK) {
2930*8044SWilliam.Kucharski@Sun.COM case PHY_ID_BCM5400: return "5400";
2931*8044SWilliam.Kucharski@Sun.COM case PHY_ID_BCM5401: return "5401";
2932*8044SWilliam.Kucharski@Sun.COM case PHY_ID_BCM5411: return "5411";
2933*8044SWilliam.Kucharski@Sun.COM case PHY_ID_BCM5701: return "5701";
2934*8044SWilliam.Kucharski@Sun.COM case PHY_ID_BCM5703: return "5703";
2935*8044SWilliam.Kucharski@Sun.COM case PHY_ID_BCM5704: return "5704";
2936*8044SWilliam.Kucharski@Sun.COM case PHY_ID_BCM8002: return "8002";
2937*8044SWilliam.Kucharski@Sun.COM case PHY_ID_SERDES: return "serdes";
2938*8044SWilliam.Kucharski@Sun.COM default: return "unknown";
2939*8044SWilliam.Kucharski@Sun.COM };
2940*8044SWilliam.Kucharski@Sun.COM }
2941*8044SWilliam.Kucharski@Sun.COM #else
2942*8044SWilliam.Kucharski@Sun.COM #define tg3_phy_string(TP) "?"
2943*8044SWilliam.Kucharski@Sun.COM #endif
2944*8044SWilliam.Kucharski@Sun.COM
2945*8044SWilliam.Kucharski@Sun.COM
tg3_poll_link(struct tg3 * tp)2946*8044SWilliam.Kucharski@Sun.COM static void tg3_poll_link(struct tg3 *tp)
2947*8044SWilliam.Kucharski@Sun.COM {
2948*8044SWilliam.Kucharski@Sun.COM uint32_t mac_stat;
2949*8044SWilliam.Kucharski@Sun.COM
2950*8044SWilliam.Kucharski@Sun.COM mac_stat = tr32(MAC_STATUS);
2951*8044SWilliam.Kucharski@Sun.COM if (tp->phy_id == PHY_ID_SERDES) {
2952*8044SWilliam.Kucharski@Sun.COM if (tp->carrier_ok?
2953*8044SWilliam.Kucharski@Sun.COM (mac_stat & MAC_STATUS_LNKSTATE_CHANGED):
2954*8044SWilliam.Kucharski@Sun.COM (mac_stat & MAC_STATUS_PCS_SYNCED)) {
2955*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK);
2956*8044SWilliam.Kucharski@Sun.COM tw32_carefully(MAC_MODE, tp->mac_mode);
2957*8044SWilliam.Kucharski@Sun.COM
2958*8044SWilliam.Kucharski@Sun.COM tg3_setup_phy(tp);
2959*8044SWilliam.Kucharski@Sun.COM }
2960*8044SWilliam.Kucharski@Sun.COM }
2961*8044SWilliam.Kucharski@Sun.COM else {
2962*8044SWilliam.Kucharski@Sun.COM if (mac_stat & MAC_STATUS_LNKSTATE_CHANGED) {
2963*8044SWilliam.Kucharski@Sun.COM tg3_setup_phy(tp);
2964*8044SWilliam.Kucharski@Sun.COM }
2965*8044SWilliam.Kucharski@Sun.COM }
2966*8044SWilliam.Kucharski@Sun.COM }
2967*8044SWilliam.Kucharski@Sun.COM
2968*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
2969*8044SWilliam.Kucharski@Sun.COM POLL - Wait for a frame
2970*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
tg3_ack_irqs(struct tg3 * tp)2971*8044SWilliam.Kucharski@Sun.COM static void tg3_ack_irqs(struct tg3 *tp)
2972*8044SWilliam.Kucharski@Sun.COM {
2973*8044SWilliam.Kucharski@Sun.COM if (tp->hw_status->status & SD_STATUS_UPDATED) {
2974*8044SWilliam.Kucharski@Sun.COM /*
2975*8044SWilliam.Kucharski@Sun.COM * writing any value to intr-mbox-0 clears PCI INTA# and
2976*8044SWilliam.Kucharski@Sun.COM * chip-internal interrupt pending events.
2977*8044SWilliam.Kucharski@Sun.COM * writing non-zero to intr-mbox-0 additional tells the
2978*8044SWilliam.Kucharski@Sun.COM * NIC to stop sending us irqs, engaging "in-intr-handler"
2979*8044SWilliam.Kucharski@Sun.COM * event coalescing.
2980*8044SWilliam.Kucharski@Sun.COM */
2981*8044SWilliam.Kucharski@Sun.COM tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
2982*8044SWilliam.Kucharski@Sun.COM 0x00000001);
2983*8044SWilliam.Kucharski@Sun.COM /*
2984*8044SWilliam.Kucharski@Sun.COM * Flush PCI write. This also guarantees that our
2985*8044SWilliam.Kucharski@Sun.COM * status block has been flushed to host memory.
2986*8044SWilliam.Kucharski@Sun.COM */
2987*8044SWilliam.Kucharski@Sun.COM tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
2988*8044SWilliam.Kucharski@Sun.COM tp->hw_status->status &= ~SD_STATUS_UPDATED;
2989*8044SWilliam.Kucharski@Sun.COM }
2990*8044SWilliam.Kucharski@Sun.COM }
2991*8044SWilliam.Kucharski@Sun.COM
tg3_poll(struct nic * nic,int retrieve)2992*8044SWilliam.Kucharski@Sun.COM static int tg3_poll(struct nic *nic, int retrieve)
2993*8044SWilliam.Kucharski@Sun.COM {
2994*8044SWilliam.Kucharski@Sun.COM /* return true if there's an ethernet packet ready to read */
2995*8044SWilliam.Kucharski@Sun.COM /* nic->packet should contain data on return */
2996*8044SWilliam.Kucharski@Sun.COM /* nic->packetlen should contain length of data */
2997*8044SWilliam.Kucharski@Sun.COM
2998*8044SWilliam.Kucharski@Sun.COM struct tg3 *tp = &tg3;
2999*8044SWilliam.Kucharski@Sun.COM int result;
3000*8044SWilliam.Kucharski@Sun.COM
3001*8044SWilliam.Kucharski@Sun.COM result = 0;
3002*8044SWilliam.Kucharski@Sun.COM
3003*8044SWilliam.Kucharski@Sun.COM if ( (tp->hw_status->idx[0].rx_producer != tp->rx_rcb_ptr) && !retrieve )
3004*8044SWilliam.Kucharski@Sun.COM return 1;
3005*8044SWilliam.Kucharski@Sun.COM
3006*8044SWilliam.Kucharski@Sun.COM tg3_ack_irqs(tp);
3007*8044SWilliam.Kucharski@Sun.COM
3008*8044SWilliam.Kucharski@Sun.COM if (tp->hw_status->idx[0].rx_producer != tp->rx_rcb_ptr) {
3009*8044SWilliam.Kucharski@Sun.COM struct tg3_rx_buffer_desc *desc;
3010*8044SWilliam.Kucharski@Sun.COM unsigned int len;
3011*8044SWilliam.Kucharski@Sun.COM desc = &tp->rx_rcb[tp->rx_rcb_ptr];
3012*8044SWilliam.Kucharski@Sun.COM if ((desc->opaque & RXD_OPAQUE_RING_MASK) == RXD_OPAQUE_RING_STD) {
3013*8044SWilliam.Kucharski@Sun.COM len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
3014*8044SWilliam.Kucharski@Sun.COM
3015*8044SWilliam.Kucharski@Sun.COM nic->packetlen = len;
3016*8044SWilliam.Kucharski@Sun.COM memcpy(nic->packet, bus_to_virt(desc->addr_lo), len);
3017*8044SWilliam.Kucharski@Sun.COM result = 1;
3018*8044SWilliam.Kucharski@Sun.COM }
3019*8044SWilliam.Kucharski@Sun.COM tp->rx_rcb_ptr = (tp->rx_rcb_ptr + 1) % TG3_RX_RCB_RING_SIZE;
3020*8044SWilliam.Kucharski@Sun.COM
3021*8044SWilliam.Kucharski@Sun.COM /* ACK the status ring */
3022*8044SWilliam.Kucharski@Sun.COM tw32_mailbox2(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, tp->rx_rcb_ptr);
3023*8044SWilliam.Kucharski@Sun.COM
3024*8044SWilliam.Kucharski@Sun.COM /* Refill RX ring. */
3025*8044SWilliam.Kucharski@Sun.COM if (result) {
3026*8044SWilliam.Kucharski@Sun.COM tp->rx_std_ptr = (tp->rx_std_ptr + 1) % TG3_RX_RING_SIZE;
3027*8044SWilliam.Kucharski@Sun.COM tw32_mailbox2(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, tp->rx_std_ptr);
3028*8044SWilliam.Kucharski@Sun.COM }
3029*8044SWilliam.Kucharski@Sun.COM }
3030*8044SWilliam.Kucharski@Sun.COM tg3_poll_link(tp);
3031*8044SWilliam.Kucharski@Sun.COM return result;
3032*8044SWilliam.Kucharski@Sun.COM }
3033*8044SWilliam.Kucharski@Sun.COM
3034*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
3035*8044SWilliam.Kucharski@Sun.COM TRANSMIT - Transmit a frame
3036*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
3037*8044SWilliam.Kucharski@Sun.COM #if 0
3038*8044SWilliam.Kucharski@Sun.COM static void tg3_set_txd(struct tg3 *tp, int entry,
3039*8044SWilliam.Kucharski@Sun.COM dma_addr_t mapping, int len, uint32_t flags,
3040*8044SWilliam.Kucharski@Sun.COM uint32_t mss_and_is_end)
3041*8044SWilliam.Kucharski@Sun.COM {
3042*8044SWilliam.Kucharski@Sun.COM struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
3043*8044SWilliam.Kucharski@Sun.COM int is_end = (mss_and_is_end & 0x1);
3044*8044SWilliam.Kucharski@Sun.COM if (is_end) {
3045*8044SWilliam.Kucharski@Sun.COM flags |= TXD_FLAG_END;
3046*8044SWilliam.Kucharski@Sun.COM }
3047*8044SWilliam.Kucharski@Sun.COM
3048*8044SWilliam.Kucharski@Sun.COM txd->addr_hi = 0;
3049*8044SWilliam.Kucharski@Sun.COM txd->addr_lo = mapping & 0xffffffff;
3050*8044SWilliam.Kucharski@Sun.COM txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
3051*8044SWilliam.Kucharski@Sun.COM txd->vlan_tag = 0 << TXD_VLAN_TAG_SHIFT;
3052*8044SWilliam.Kucharski@Sun.COM }
3053*8044SWilliam.Kucharski@Sun.COM #endif
3054*8044SWilliam.Kucharski@Sun.COM
tg3_transmit(struct nic * nic,const char * dst_addr,unsigned int type,unsigned int size,const char * packet)3055*8044SWilliam.Kucharski@Sun.COM static void tg3_transmit(struct nic *nic, const char *dst_addr,
3056*8044SWilliam.Kucharski@Sun.COM unsigned int type, unsigned int size, const char *packet)
3057*8044SWilliam.Kucharski@Sun.COM {
3058*8044SWilliam.Kucharski@Sun.COM static struct eth_frame {
3059*8044SWilliam.Kucharski@Sun.COM uint8_t dst_addr[ETH_ALEN];
3060*8044SWilliam.Kucharski@Sun.COM uint8_t src_addr[ETH_ALEN];
3061*8044SWilliam.Kucharski@Sun.COM uint16_t type;
3062*8044SWilliam.Kucharski@Sun.COM uint8_t data [ETH_FRAME_LEN - ETH_HLEN];
3063*8044SWilliam.Kucharski@Sun.COM } frame[2];
3064*8044SWilliam.Kucharski@Sun.COM static int frame_idx;
3065*8044SWilliam.Kucharski@Sun.COM
3066*8044SWilliam.Kucharski@Sun.COM /* send the packet to destination */
3067*8044SWilliam.Kucharski@Sun.COM struct tg3_tx_buffer_desc *txd;
3068*8044SWilliam.Kucharski@Sun.COM struct tg3 *tp;
3069*8044SWilliam.Kucharski@Sun.COM uint32_t entry;
3070*8044SWilliam.Kucharski@Sun.COM int i;
3071*8044SWilliam.Kucharski@Sun.COM
3072*8044SWilliam.Kucharski@Sun.COM /* Wait until there is a free packet frame */
3073*8044SWilliam.Kucharski@Sun.COM tp = &tg3;
3074*8044SWilliam.Kucharski@Sun.COM i = 0;
3075*8044SWilliam.Kucharski@Sun.COM entry = tp->tx_prod;
3076*8044SWilliam.Kucharski@Sun.COM while((tp->hw_status->idx[0].tx_consumer != entry) &&
3077*8044SWilliam.Kucharski@Sun.COM (tp->hw_status->idx[0].tx_consumer != PREV_TX(entry))) {
3078*8044SWilliam.Kucharski@Sun.COM mdelay(10); /* give the nick a chance */
3079*8044SWilliam.Kucharski@Sun.COM poll_interruptions();
3080*8044SWilliam.Kucharski@Sun.COM if (++i > 500) { /* timeout 5s for transmit */
3081*8044SWilliam.Kucharski@Sun.COM printf("transmit timed out\n");
3082*8044SWilliam.Kucharski@Sun.COM tg3_halt(tp);
3083*8044SWilliam.Kucharski@Sun.COM tg3_setup_hw(tp);
3084*8044SWilliam.Kucharski@Sun.COM return;
3085*8044SWilliam.Kucharski@Sun.COM }
3086*8044SWilliam.Kucharski@Sun.COM }
3087*8044SWilliam.Kucharski@Sun.COM if (i != 0) {
3088*8044SWilliam.Kucharski@Sun.COM printf("#");
3089*8044SWilliam.Kucharski@Sun.COM }
3090*8044SWilliam.Kucharski@Sun.COM
3091*8044SWilliam.Kucharski@Sun.COM /* Copy the packet to the our local buffer */
3092*8044SWilliam.Kucharski@Sun.COM memcpy(&frame[frame_idx].dst_addr, dst_addr, ETH_ALEN);
3093*8044SWilliam.Kucharski@Sun.COM memcpy(&frame[frame_idx].src_addr, nic->node_addr, ETH_ALEN);
3094*8044SWilliam.Kucharski@Sun.COM frame[frame_idx].type = htons(type);
3095*8044SWilliam.Kucharski@Sun.COM memset(&frame[frame_idx].data, 0, sizeof(frame[frame_idx].data));
3096*8044SWilliam.Kucharski@Sun.COM memcpy(&frame[frame_idx].data, packet, size);
3097*8044SWilliam.Kucharski@Sun.COM
3098*8044SWilliam.Kucharski@Sun.COM /* Setup the ring buffer entry to transmit */
3099*8044SWilliam.Kucharski@Sun.COM txd = &tp->tx_ring[entry];
3100*8044SWilliam.Kucharski@Sun.COM txd->addr_hi = 0; /* Etherboot runs under 4GB */
3101*8044SWilliam.Kucharski@Sun.COM txd->addr_lo = virt_to_bus(&frame[frame_idx]);
3102*8044SWilliam.Kucharski@Sun.COM txd->len_flags = ((size + ETH_HLEN) << TXD_LEN_SHIFT) | TXD_FLAG_END;
3103*8044SWilliam.Kucharski@Sun.COM txd->vlan_tag = 0 << TXD_VLAN_TAG_SHIFT;
3104*8044SWilliam.Kucharski@Sun.COM
3105*8044SWilliam.Kucharski@Sun.COM /* Advance to the next entry */
3106*8044SWilliam.Kucharski@Sun.COM entry = NEXT_TX(entry);
3107*8044SWilliam.Kucharski@Sun.COM frame_idx ^= 1;
3108*8044SWilliam.Kucharski@Sun.COM
3109*8044SWilliam.Kucharski@Sun.COM /* Packets are ready, update Tx producer idx local and on card */
3110*8044SWilliam.Kucharski@Sun.COM tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
3111*8044SWilliam.Kucharski@Sun.COM tw32_mailbox2((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
3112*8044SWilliam.Kucharski@Sun.COM tp->tx_prod = entry;
3113*8044SWilliam.Kucharski@Sun.COM }
3114*8044SWilliam.Kucharski@Sun.COM
3115*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
3116*8044SWilliam.Kucharski@Sun.COM DISABLE - Turn off ethernet interface
3117*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
tg3_disable(struct dev * dev __unused)3118*8044SWilliam.Kucharski@Sun.COM static void tg3_disable(struct dev *dev __unused)
3119*8044SWilliam.Kucharski@Sun.COM {
3120*8044SWilliam.Kucharski@Sun.COM struct tg3 *tp = &tg3;
3121*8044SWilliam.Kucharski@Sun.COM /* put the card in its initial state */
3122*8044SWilliam.Kucharski@Sun.COM /* This function serves 3 purposes.
3123*8044SWilliam.Kucharski@Sun.COM * This disables DMA and interrupts so we don't receive
3124*8044SWilliam.Kucharski@Sun.COM * unexpected packets or interrupts from the card after
3125*8044SWilliam.Kucharski@Sun.COM * etherboot has finished.
3126*8044SWilliam.Kucharski@Sun.COM * This frees resources so etherboot may use
3127*8044SWilliam.Kucharski@Sun.COM * this driver on another interface
3128*8044SWilliam.Kucharski@Sun.COM * This allows etherboot to reinitialize the interface
3129*8044SWilliam.Kucharski@Sun.COM * if something is something goes wrong.
3130*8044SWilliam.Kucharski@Sun.COM */
3131*8044SWilliam.Kucharski@Sun.COM tg3_halt(tp);
3132*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags &= ~(TG3_FLAG_INIT_COMPLETE|TG3_FLAG_GOT_SERDES_FLOWCTL);
3133*8044SWilliam.Kucharski@Sun.COM tp->carrier_ok = 0;
3134*8044SWilliam.Kucharski@Sun.COM iounmap((void *)tp->regs);
3135*8044SWilliam.Kucharski@Sun.COM }
3136*8044SWilliam.Kucharski@Sun.COM
3137*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
3138*8044SWilliam.Kucharski@Sun.COM IRQ - Enable, Disable, or Force interrupts
3139*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
tg3_irq(struct nic * nic __unused,irq_action_t action __unused)3140*8044SWilliam.Kucharski@Sun.COM static void tg3_irq(struct nic *nic __unused, irq_action_t action __unused)
3141*8044SWilliam.Kucharski@Sun.COM {
3142*8044SWilliam.Kucharski@Sun.COM switch ( action ) {
3143*8044SWilliam.Kucharski@Sun.COM case DISABLE :
3144*8044SWilliam.Kucharski@Sun.COM break;
3145*8044SWilliam.Kucharski@Sun.COM case ENABLE :
3146*8044SWilliam.Kucharski@Sun.COM break;
3147*8044SWilliam.Kucharski@Sun.COM case FORCE :
3148*8044SWilliam.Kucharski@Sun.COM break;
3149*8044SWilliam.Kucharski@Sun.COM }
3150*8044SWilliam.Kucharski@Sun.COM }
3151*8044SWilliam.Kucharski@Sun.COM
3152*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
3153*8044SWilliam.Kucharski@Sun.COM PROBE - Look for an adapter, this routine's visible to the outside
3154*8044SWilliam.Kucharski@Sun.COM You should omit the last argument struct pci_device * for a non-PCI NIC
3155*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
tg3_probe(struct dev * dev,struct pci_device * pdev)3156*8044SWilliam.Kucharski@Sun.COM static int tg3_probe(struct dev *dev, struct pci_device *pdev)
3157*8044SWilliam.Kucharski@Sun.COM {
3158*8044SWilliam.Kucharski@Sun.COM struct nic *nic = (struct nic *)dev;
3159*8044SWilliam.Kucharski@Sun.COM struct tg3 *tp = &tg3;
3160*8044SWilliam.Kucharski@Sun.COM unsigned long tg3reg_base, tg3reg_len;
3161*8044SWilliam.Kucharski@Sun.COM int i, err, pm_cap;
3162*8044SWilliam.Kucharski@Sun.COM
3163*8044SWilliam.Kucharski@Sun.COM if (pdev == 0)
3164*8044SWilliam.Kucharski@Sun.COM return 0;
3165*8044SWilliam.Kucharski@Sun.COM
3166*8044SWilliam.Kucharski@Sun.COM memset(tp, 0, sizeof(*tp));
3167*8044SWilliam.Kucharski@Sun.COM
3168*8044SWilliam.Kucharski@Sun.COM adjust_pci_device(pdev);
3169*8044SWilliam.Kucharski@Sun.COM
3170*8044SWilliam.Kucharski@Sun.COM nic->irqno = 0;
3171*8044SWilliam.Kucharski@Sun.COM nic->ioaddr = pdev->ioaddr & ~3;
3172*8044SWilliam.Kucharski@Sun.COM
3173*8044SWilliam.Kucharski@Sun.COM /* Find power-management capability. */
3174*8044SWilliam.Kucharski@Sun.COM pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
3175*8044SWilliam.Kucharski@Sun.COM if (pm_cap == 0) {
3176*8044SWilliam.Kucharski@Sun.COM printf("Cannot find PowerManagement capability, aborting.\n");
3177*8044SWilliam.Kucharski@Sun.COM return 0;
3178*8044SWilliam.Kucharski@Sun.COM }
3179*8044SWilliam.Kucharski@Sun.COM tg3reg_base = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
3180*8044SWilliam.Kucharski@Sun.COM if (tg3reg_base == -1UL) {
3181*8044SWilliam.Kucharski@Sun.COM printf("Unuseable bar\n");
3182*8044SWilliam.Kucharski@Sun.COM return 0;
3183*8044SWilliam.Kucharski@Sun.COM }
3184*8044SWilliam.Kucharski@Sun.COM tg3reg_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_0);
3185*8044SWilliam.Kucharski@Sun.COM
3186*8044SWilliam.Kucharski@Sun.COM tp->pdev = pdev;
3187*8044SWilliam.Kucharski@Sun.COM tp->nic = nic;
3188*8044SWilliam.Kucharski@Sun.COM tp->pm_cap = pm_cap;
3189*8044SWilliam.Kucharski@Sun.COM tp->rx_mode = 0;
3190*8044SWilliam.Kucharski@Sun.COM tp->tx_mode = 0;
3191*8044SWilliam.Kucharski@Sun.COM tp->mi_mode = MAC_MI_MODE_BASE;
3192*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags = 0 & ~TG3_FLAG_INIT_COMPLETE;
3193*8044SWilliam.Kucharski@Sun.COM
3194*8044SWilliam.Kucharski@Sun.COM /* The word/byte swap controls here control register access byte
3195*8044SWilliam.Kucharski@Sun.COM * swapping. DMA data byte swapping is controlled in the GRC_MODE
3196*8044SWilliam.Kucharski@Sun.COM * setting below.
3197*8044SWilliam.Kucharski@Sun.COM */
3198*8044SWilliam.Kucharski@Sun.COM tp->misc_host_ctrl =
3199*8044SWilliam.Kucharski@Sun.COM MISC_HOST_CTRL_MASK_PCI_INT |
3200*8044SWilliam.Kucharski@Sun.COM MISC_HOST_CTRL_WORD_SWAP |
3201*8044SWilliam.Kucharski@Sun.COM MISC_HOST_CTRL_INDIR_ACCESS |
3202*8044SWilliam.Kucharski@Sun.COM MISC_HOST_CTRL_PCISTATE_RW;
3203*8044SWilliam.Kucharski@Sun.COM
3204*8044SWilliam.Kucharski@Sun.COM /* The NONFRM (non-frame) byte/word swap controls take effect
3205*8044SWilliam.Kucharski@Sun.COM * on descriptor entries, anything which isn't packet data.
3206*8044SWilliam.Kucharski@Sun.COM *
3207*8044SWilliam.Kucharski@Sun.COM * The StrongARM chips on the board (one for tx, one for rx)
3208*8044SWilliam.Kucharski@Sun.COM * are running in big-endian mode.
3209*8044SWilliam.Kucharski@Sun.COM */
3210*8044SWilliam.Kucharski@Sun.COM tp->grc_mode = (GRC_MODE_WSWAP_DATA | GRC_MODE_BSWAP_DATA |
3211*8044SWilliam.Kucharski@Sun.COM GRC_MODE_WSWAP_NONFRM_DATA);
3212*8044SWilliam.Kucharski@Sun.COM #if __BYTE_ORDER == __BIG_ENDIAN
3213*8044SWilliam.Kucharski@Sun.COM tp->grc_mode |= GRC_MODE_BSWAP_NONFRM_DATA;
3214*8044SWilliam.Kucharski@Sun.COM #endif
3215*8044SWilliam.Kucharski@Sun.COM tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);
3216*8044SWilliam.Kucharski@Sun.COM if (tp->regs == 0UL) {
3217*8044SWilliam.Kucharski@Sun.COM printf("Cannot map device registers, aborting\n");
3218*8044SWilliam.Kucharski@Sun.COM return 0;
3219*8044SWilliam.Kucharski@Sun.COM }
3220*8044SWilliam.Kucharski@Sun.COM
3221*8044SWilliam.Kucharski@Sun.COM tg3_init_link_config(tp);
3222*8044SWilliam.Kucharski@Sun.COM
3223*8044SWilliam.Kucharski@Sun.COM err = tg3_get_invariants(tp);
3224*8044SWilliam.Kucharski@Sun.COM if (err) {
3225*8044SWilliam.Kucharski@Sun.COM printf("Problem fetching invariants of chip, aborting.\n");
3226*8044SWilliam.Kucharski@Sun.COM goto err_out_iounmap;
3227*8044SWilliam.Kucharski@Sun.COM }
3228*8044SWilliam.Kucharski@Sun.COM
3229*8044SWilliam.Kucharski@Sun.COM err = tg3_get_device_address(tp);
3230*8044SWilliam.Kucharski@Sun.COM if (err) {
3231*8044SWilliam.Kucharski@Sun.COM printf("Could not obtain valid ethernet address, aborting.\n");
3232*8044SWilliam.Kucharski@Sun.COM goto err_out_iounmap;
3233*8044SWilliam.Kucharski@Sun.COM }
3234*8044SWilliam.Kucharski@Sun.COM printf("Ethernet addr: %!\n", nic->node_addr);
3235*8044SWilliam.Kucharski@Sun.COM
3236*8044SWilliam.Kucharski@Sun.COM tg3_setup_dma(tp);
3237*8044SWilliam.Kucharski@Sun.COM
3238*8044SWilliam.Kucharski@Sun.COM /* Now that we have fully setup the chip, save away a snapshot
3239*8044SWilliam.Kucharski@Sun.COM * of the PCI config space. We need to restore this after
3240*8044SWilliam.Kucharski@Sun.COM * GRC_MISC_CFG core clock resets and some resume events.
3241*8044SWilliam.Kucharski@Sun.COM */
3242*8044SWilliam.Kucharski@Sun.COM pci_save_state(tp->pdev, tp->pci_cfg_state);
3243*8044SWilliam.Kucharski@Sun.COM
3244*8044SWilliam.Kucharski@Sun.COM printf("Tigon3 [partno(%s) rev %hx PHY(%s)] (PCI%s:%s:%s)\n",
3245*8044SWilliam.Kucharski@Sun.COM tp->board_part_number,
3246*8044SWilliam.Kucharski@Sun.COM tp->pci_chip_rev_id,
3247*8044SWilliam.Kucharski@Sun.COM tg3_phy_string(tp),
3248*8044SWilliam.Kucharski@Sun.COM ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "X" : ""),
3249*8044SWilliam.Kucharski@Sun.COM ((tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED) ?
3250*8044SWilliam.Kucharski@Sun.COM ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "133MHz" : "66MHz") :
3251*8044SWilliam.Kucharski@Sun.COM ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "100MHz" : "33MHz")),
3252*8044SWilliam.Kucharski@Sun.COM ((tp->tg3_flags & TG3_FLAG_PCI_32BIT) ? "32-bit" : "64-bit"));
3253*8044SWilliam.Kucharski@Sun.COM
3254*8044SWilliam.Kucharski@Sun.COM
3255*8044SWilliam.Kucharski@Sun.COM err = tg3_setup_hw(tp);
3256*8044SWilliam.Kucharski@Sun.COM if (err) {
3257*8044SWilliam.Kucharski@Sun.COM goto err_out_disable;
3258*8044SWilliam.Kucharski@Sun.COM }
3259*8044SWilliam.Kucharski@Sun.COM tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
3260*8044SWilliam.Kucharski@Sun.COM
3261*8044SWilliam.Kucharski@Sun.COM /* Wait for a reasonable time for the link to come up */
3262*8044SWilliam.Kucharski@Sun.COM tg3_poll_link(tp);
3263*8044SWilliam.Kucharski@Sun.COM for(i = 0; !tp->carrier_ok && (i < VALID_LINK_TIMEOUT*100); i++) {
3264*8044SWilliam.Kucharski@Sun.COM mdelay(1);
3265*8044SWilliam.Kucharski@Sun.COM tg3_poll_link(tp);
3266*8044SWilliam.Kucharski@Sun.COM }
3267*8044SWilliam.Kucharski@Sun.COM if (!tp->carrier_ok){
3268*8044SWilliam.Kucharski@Sun.COM printf("Valid link not established\n");
3269*8044SWilliam.Kucharski@Sun.COM goto err_out_disable;
3270*8044SWilliam.Kucharski@Sun.COM }
3271*8044SWilliam.Kucharski@Sun.COM
3272*8044SWilliam.Kucharski@Sun.COM dev->disable = tg3_disable;
3273*8044SWilliam.Kucharski@Sun.COM nic->poll = tg3_poll;
3274*8044SWilliam.Kucharski@Sun.COM nic->transmit = tg3_transmit;
3275*8044SWilliam.Kucharski@Sun.COM nic->irq = tg3_irq;
3276*8044SWilliam.Kucharski@Sun.COM
3277*8044SWilliam.Kucharski@Sun.COM return 1;
3278*8044SWilliam.Kucharski@Sun.COM
3279*8044SWilliam.Kucharski@Sun.COM err_out_iounmap:
3280*8044SWilliam.Kucharski@Sun.COM iounmap((void *)tp->regs);
3281*8044SWilliam.Kucharski@Sun.COM return 0;
3282*8044SWilliam.Kucharski@Sun.COM err_out_disable:
3283*8044SWilliam.Kucharski@Sun.COM tg3_disable(dev);
3284*8044SWilliam.Kucharski@Sun.COM return 0;
3285*8044SWilliam.Kucharski@Sun.COM }
3286*8044SWilliam.Kucharski@Sun.COM
3287*8044SWilliam.Kucharski@Sun.COM static struct pci_id tg3_nics[] = {
3288*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x1644, "tg3-5700", "Broadcom Tigon 3 5700"),
3289*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x1645, "tg3-5701", "Broadcom Tigon 3 5701"),
3290*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x1646, "tg3-5702", "Broadcom Tigon 3 5702"),
3291*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x1647, "tg3-5703", "Broadcom Tigon 3 5703"),
3292*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x1648, "tg3-5704", "Broadcom Tigon 3 5704"),
3293*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x164d, "tg3-5702FE", "Broadcom Tigon 3 5702FE"),
3294*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x1653, "tg3-5705", "Broadcom Tigon 3 5705"),
3295*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x1654, "tg3-5705_2", "Broadcom Tigon 3 5705_2"),
3296*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x165d, "tg3-5705M", "Broadcom Tigon 3 5705M"),
3297*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x165e, "tg3-5705M_2", "Broadcom Tigon 3 5705M_2"),
3298*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x1696, "tg3-5782", "Broadcom Tigon 3 5782"),
3299*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x169c, "tg3-5788", "Broadcom Tigon 3 5788"),
3300*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x16a6, "tg3-5702X", "Broadcom Tigon 3 5702X"),
3301*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x16a7, "tg3-5703X", "Broadcom Tigon 3 5703X"),
3302*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x16a8, "tg3-5704S", "Broadcom Tigon 3 5704S"),
3303*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x16c6, "tg3-5702A3", "Broadcom Tigon 3 5702A3"),
3304*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x16c7, "tg3-5703A3", "Broadcom Tigon 3 5703A3"),
3305*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x170d, "tg3-5901", "Broadcom Tigon 3 5901"),
3306*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x14e4, 0x170e, "tg3-5901_2", "Broadcom Tigon 3 5901_2"),
3307*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1148, 0x4400, "tg3-9DXX", "Syskonnect 9DXX"),
3308*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1148, 0x4500, "tg3-9MXX", "Syskonnect 9MXX"),
3309*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x173b, 0x03e8, "tg3-ac1000", "Altima AC1000"),
3310*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x173b, 0x03e9, "tg3-ac1001", "Altima AC1001"),
3311*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x173b, 0x03ea, "tg3-ac9100", "Altima AC9100"),
3312*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x173b, 0x03eb, "tg3-ac1003", "Altima AC1003"),
3313*8044SWilliam.Kucharski@Sun.COM };
3314*8044SWilliam.Kucharski@Sun.COM
3315*8044SWilliam.Kucharski@Sun.COM struct pci_driver tg3_driver = {
3316*8044SWilliam.Kucharski@Sun.COM .type = NIC_DRIVER,
3317*8044SWilliam.Kucharski@Sun.COM .name = "TG3",
3318*8044SWilliam.Kucharski@Sun.COM .probe = tg3_probe,
3319*8044SWilliam.Kucharski@Sun.COM .ids = tg3_nics,
3320*8044SWilliam.Kucharski@Sun.COM .id_count = sizeof(tg3_nics)/sizeof(tg3_nics[0]),
3321*8044SWilliam.Kucharski@Sun.COM .class = 0,
3322*8044SWilliam.Kucharski@Sun.COM };
3323