17c478bd9Sstevel@tonic-gate /* $Id: tg3.c,v 1.5 2003/03/19 21:26:20 gbaum Exp $
27c478bd9Sstevel@tonic-gate  * tg3.c: Broadcom Tigon3 ethernet driver.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
57c478bd9Sstevel@tonic-gate  * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@mandrakesoft.com)
67c478bd9Sstevel@tonic-gate  * Copyright (C) 2003 Eric Biederman (ebiederman@lnxi.com)  [etherboot port]
77c478bd9Sstevel@tonic-gate  */
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /* 11-13-2003	timlegge	Fix Issue with NetGear GA302T
107c478bd9Sstevel@tonic-gate  * 11-18-2003   ebiederm        Generalize NetGear Fix to what the code was supposed to be.
117c478bd9Sstevel@tonic-gate  */
127c478bd9Sstevel@tonic-gate 
137c478bd9Sstevel@tonic-gate #include "etherboot.h"
147c478bd9Sstevel@tonic-gate #include "nic.h"
157c478bd9Sstevel@tonic-gate #include "pci.h"
167c478bd9Sstevel@tonic-gate #include "timer.h"
177c478bd9Sstevel@tonic-gate /*#include "string.h"*/
187c478bd9Sstevel@tonic-gate #include "tg3.h"
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate #define SUPPORT_COPPER_PHY  1
217c478bd9Sstevel@tonic-gate #define SUPPORT_FIBER_PHY   1
227c478bd9Sstevel@tonic-gate #define SUPPORT_LINK_REPORT 1
237c478bd9Sstevel@tonic-gate #define SUPPORT_PARTNO_STR  1
247c478bd9Sstevel@tonic-gate #define SUPPORT_PHY_STR     1
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate struct tg3 tg3;
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /* Dummy defines for error handling */
297c478bd9Sstevel@tonic-gate #define EBUSY  1
307c478bd9Sstevel@tonic-gate #define ENODEV 2
317c478bd9Sstevel@tonic-gate #define EINVAL 3
327c478bd9Sstevel@tonic-gate #define ENOMEM 4
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate /* These numbers seem to be hard coded in the NIC firmware somehow.
367c478bd9Sstevel@tonic-gate  * You can't change the ring sizes, but you can change where you place
377c478bd9Sstevel@tonic-gate  * them in the NIC onboard memory.
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate #define TG3_RX_RING_SIZE		512
407c478bd9Sstevel@tonic-gate #define TG3_DEF_RX_RING_PENDING		20	/* RX_RING_PENDING seems to be o.k. at 20 and 200 */
417c478bd9Sstevel@tonic-gate #define TG3_RX_RCB_RING_SIZE	1024
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*	(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ? \
447c478bd9Sstevel@tonic-gate 	 512 : 1024) */
457c478bd9Sstevel@tonic-gate  #define TG3_TX_RING_SIZE		512
467c478bd9Sstevel@tonic-gate #define TG3_DEF_TX_RING_PENDING		(TG3_TX_RING_SIZE - 1)
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #define TG3_RX_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_RING_SIZE)
497c478bd9Sstevel@tonic-gate #define TG3_RX_RCB_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_RCB_RING_SIZE)
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #define TG3_TX_RING_BYTES	(sizeof(struct tg3_tx_buffer_desc) * TG3_TX_RING_SIZE)
527c478bd9Sstevel@tonic-gate #define NEXT_TX(N)		(((N) + 1) & (TG3_TX_RING_SIZE - 1))
537c478bd9Sstevel@tonic-gate #define PREV_TX(N)		(((N) - 1) & (TG3_TX_RING_SIZE - 1))
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #define RX_PKT_BUF_SZ		(1536 + 2 + 64)
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static struct bss {
597c478bd9Sstevel@tonic-gate 	struct tg3_rx_buffer_desc rx_std[TG3_RX_RING_SIZE];
607c478bd9Sstevel@tonic-gate 	struct tg3_rx_buffer_desc rx_rcb[TG3_RX_RCB_RING_SIZE];
617c478bd9Sstevel@tonic-gate 	struct tg3_tx_buffer_desc tx_ring[TG3_TX_RING_SIZE];
627c478bd9Sstevel@tonic-gate 	struct tg3_hw_status      hw_status;
637c478bd9Sstevel@tonic-gate 	struct tg3_hw_stats       hw_stats;
647c478bd9Sstevel@tonic-gate 	unsigned char             rx_bufs[TG3_DEF_RX_RING_PENDING][RX_PKT_BUF_SZ];
657c478bd9Sstevel@tonic-gate } tg3_bss;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /**
687c478bd9Sstevel@tonic-gate  * pci_save_state - save the PCI configuration space of a device before suspending
697c478bd9Sstevel@tonic-gate  * @dev: - PCI device that we're dealing with
707c478bd9Sstevel@tonic-gate  * @buffer: - buffer to hold config space context
717c478bd9Sstevel@tonic-gate  *
727c478bd9Sstevel@tonic-gate  * @buffer must be large enough to hold the entire PCI 2.2 config space
737c478bd9Sstevel@tonic-gate  * (>= 64 bytes).
747c478bd9Sstevel@tonic-gate  */
pci_save_state(struct pci_device * dev,uint32_t * buffer)757c478bd9Sstevel@tonic-gate static int pci_save_state(struct pci_device *dev, uint32_t *buffer)
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate 	int i;
787c478bd9Sstevel@tonic-gate 	for (i = 0; i < 16; i++)
797c478bd9Sstevel@tonic-gate 		pci_read_config_dword(dev, i * 4,&buffer[i]);
807c478bd9Sstevel@tonic-gate 	return 0;
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /**
847c478bd9Sstevel@tonic-gate  * pci_restore_state - Restore the saved state of a PCI device
857c478bd9Sstevel@tonic-gate  * @dev: - PCI device that we're dealing with
867c478bd9Sstevel@tonic-gate  * @buffer: - saved PCI config space
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  */
pci_restore_state(struct pci_device * dev,uint32_t * buffer)897c478bd9Sstevel@tonic-gate static int pci_restore_state(struct pci_device *dev, uint32_t *buffer)
907c478bd9Sstevel@tonic-gate {
917c478bd9Sstevel@tonic-gate 	int i;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	for (i = 0; i < 16; i++)
947c478bd9Sstevel@tonic-gate 		pci_write_config_dword(dev,i * 4, buffer[i]);
957c478bd9Sstevel@tonic-gate 	return 0;
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
tg3_write_indirect_reg32(uint32_t off,uint32_t val)987c478bd9Sstevel@tonic-gate static void tg3_write_indirect_reg32(uint32_t off, uint32_t val)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate 	pci_write_config_dword(tg3.pdev, TG3PCI_REG_BASE_ADDR, off);
1017c478bd9Sstevel@tonic-gate 	pci_write_config_dword(tg3.pdev, TG3PCI_REG_DATA, val);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate #define tw32(reg,val)		tg3_write_indirect_reg32((reg),(val))
1057c478bd9Sstevel@tonic-gate #define tw32_mailbox(reg, val)	writel(((val) & 0xffffffff), tg3.regs + (reg))
1067c478bd9Sstevel@tonic-gate #define tw16(reg,val)		writew(((val) & 0xffff), tg3.regs + (reg))
1077c478bd9Sstevel@tonic-gate #define tw8(reg,val)		writeb(((val) & 0xff), tg3.regs + (reg))
1087c478bd9Sstevel@tonic-gate #define tr32(reg)		readl(tg3.regs + (reg))
1097c478bd9Sstevel@tonic-gate #define tr16(reg)		readw(tg3.regs + (reg))
1107c478bd9Sstevel@tonic-gate #define tr8(reg)		readb(tg3.regs + (reg))
1117c478bd9Sstevel@tonic-gate 
tw32_carefully(uint32_t reg,uint32_t val)1127c478bd9Sstevel@tonic-gate static void tw32_carefully(uint32_t reg, uint32_t val)
1137c478bd9Sstevel@tonic-gate {
1147c478bd9Sstevel@tonic-gate 	tw32(reg, val);
1157c478bd9Sstevel@tonic-gate 	tr32(reg);
1167c478bd9Sstevel@tonic-gate 	udelay(100);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
tw32_mailbox2(uint32_t reg,uint32_t val)1197c478bd9Sstevel@tonic-gate static void tw32_mailbox2(uint32_t reg, uint32_t val)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate 	tw32_mailbox(reg, val);
1227c478bd9Sstevel@tonic-gate 	tr32(reg);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate 
tg3_write_mem(uint32_t off,uint32_t val)1257c478bd9Sstevel@tonic-gate static void tg3_write_mem(uint32_t off, uint32_t val)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
1287c478bd9Sstevel@tonic-gate 	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_DATA, val);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	/* Always leave this as zero. */
1317c478bd9Sstevel@tonic-gate 	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate 
tg3_read_mem(uint32_t off,uint32_t * val)1347c478bd9Sstevel@tonic-gate static void tg3_read_mem(uint32_t off, uint32_t *val)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
1377c478bd9Sstevel@tonic-gate 	pci_read_config_dword(tg3.pdev, TG3PCI_MEM_WIN_DATA, val);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	/* Always leave this as zero. */
1407c478bd9Sstevel@tonic-gate 	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
tg3_disable_ints(struct tg3 * tp)1437c478bd9Sstevel@tonic-gate static void tg3_disable_ints(struct tg3 *tp)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	tw32(TG3PCI_MISC_HOST_CTRL,
1467c478bd9Sstevel@tonic-gate 	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
1477c478bd9Sstevel@tonic-gate 	tw32_mailbox2(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate 
tg3_switch_clocks(struct tg3 * tp)1507c478bd9Sstevel@tonic-gate static void tg3_switch_clocks(struct tg3 *tp)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	uint32_t orig_clock_ctrl, clock_ctrl;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	orig_clock_ctrl = clock_ctrl;
1577c478bd9Sstevel@tonic-gate 	clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE | 0x1f);
1587c478bd9Sstevel@tonic-gate 	tp->pci_clock_ctrl = clock_ctrl;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
1617c478bd9Sstevel@tonic-gate 		(orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE)!=0) {
1627c478bd9Sstevel@tonic-gate 		tw32_carefully(TG3PCI_CLOCK_CTRL,
1637c478bd9Sstevel@tonic-gate 			clock_ctrl | (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK));
1647c478bd9Sstevel@tonic-gate 		tw32_carefully(TG3PCI_CLOCK_CTRL,
1657c478bd9Sstevel@tonic-gate 			clock_ctrl | (CLOCK_CTRL_ALTCLK));
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 	tw32_carefully(TG3PCI_CLOCK_CTRL, clock_ctrl);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate #define PHY_BUSY_LOOPS	5000
1717c478bd9Sstevel@tonic-gate 
tg3_readphy(struct tg3 * tp,int reg,uint32_t * val)1727c478bd9Sstevel@tonic-gate static int tg3_readphy(struct tg3 *tp, int reg, uint32_t *val)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate 	uint32_t frame_val;
1757c478bd9Sstevel@tonic-gate 	int loops, ret;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MI_MODE, tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	*val = 0xffffffff;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
1827c478bd9Sstevel@tonic-gate 		      MI_COM_PHY_ADDR_MASK);
1837c478bd9Sstevel@tonic-gate 	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
1847c478bd9Sstevel@tonic-gate 		      MI_COM_REG_ADDR_MASK);
1857c478bd9Sstevel@tonic-gate 	frame_val |= (MI_COM_CMD_READ | MI_COM_START);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MI_COM, frame_val);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	loops = PHY_BUSY_LOOPS;
1907c478bd9Sstevel@tonic-gate 	while (loops-- > 0) {
1917c478bd9Sstevel@tonic-gate 		udelay(10);
1927c478bd9Sstevel@tonic-gate 		frame_val = tr32(MAC_MI_COM);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 		if ((frame_val & MI_COM_BUSY) == 0) {
1957c478bd9Sstevel@tonic-gate 			udelay(5);
1967c478bd9Sstevel@tonic-gate 			frame_val = tr32(MAC_MI_COM);
1977c478bd9Sstevel@tonic-gate 			break;
1987c478bd9Sstevel@tonic-gate 		}
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	ret = -EBUSY;
2027c478bd9Sstevel@tonic-gate 	if (loops > 0) {
2037c478bd9Sstevel@tonic-gate 		*val = frame_val & MI_COM_DATA_MASK;
2047c478bd9Sstevel@tonic-gate 		ret = 0;
2057c478bd9Sstevel@tonic-gate 	}
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	return ret;
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
tg3_writephy(struct tg3 * tp,int reg,uint32_t val)2127c478bd9Sstevel@tonic-gate static int tg3_writephy(struct tg3 *tp, int reg, uint32_t val)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate 	uint32_t frame_val;
2157c478bd9Sstevel@tonic-gate 	int loops, ret;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MI_MODE, tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
2207c478bd9Sstevel@tonic-gate 		      MI_COM_PHY_ADDR_MASK);
2217c478bd9Sstevel@tonic-gate 	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
2227c478bd9Sstevel@tonic-gate 		      MI_COM_REG_ADDR_MASK);
2237c478bd9Sstevel@tonic-gate 	frame_val |= (val & MI_COM_DATA_MASK);
2247c478bd9Sstevel@tonic-gate 	frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MI_COM, frame_val);
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	loops = PHY_BUSY_LOOPS;
2297c478bd9Sstevel@tonic-gate 	while (loops-- > 0) {
2307c478bd9Sstevel@tonic-gate 		udelay(10);
2317c478bd9Sstevel@tonic-gate 		frame_val = tr32(MAC_MI_COM);
2327c478bd9Sstevel@tonic-gate 		if ((frame_val & MI_COM_BUSY) == 0) {
2337c478bd9Sstevel@tonic-gate 			udelay(5);
2347c478bd9Sstevel@tonic-gate 			frame_val = tr32(MAC_MI_COM);
2357c478bd9Sstevel@tonic-gate 			break;
2367c478bd9Sstevel@tonic-gate 		}
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	ret = -EBUSY;
2407c478bd9Sstevel@tonic-gate 	if (loops > 0)
2417c478bd9Sstevel@tonic-gate 		ret = 0;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	return ret;
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
tg3_writedsp(struct tg3 * tp,uint16_t addr,uint16_t val)2487c478bd9Sstevel@tonic-gate static int tg3_writedsp(struct tg3 *tp, uint16_t addr, uint16_t val)
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate 	int err;
2517c478bd9Sstevel@tonic-gate 	err  = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, addr);
2527c478bd9Sstevel@tonic-gate 	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
2537c478bd9Sstevel@tonic-gate 	return err;
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 
tg3_phy_set_wirespeed(struct tg3 * tp)2577c478bd9Sstevel@tonic-gate static void tg3_phy_set_wirespeed(struct tg3 *tp)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	uint32_t val;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)
2627c478bd9Sstevel@tonic-gate 		return;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);
2657c478bd9Sstevel@tonic-gate 	tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
2667c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate 
tg3_bmcr_reset(struct tg3 * tp)2697c478bd9Sstevel@tonic-gate static int tg3_bmcr_reset(struct tg3 *tp)
2707c478bd9Sstevel@tonic-gate {
2717c478bd9Sstevel@tonic-gate 	uint32_t phy_control;
2727c478bd9Sstevel@tonic-gate 	int limit, err;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	/* OK, reset it, and poll the BMCR_RESET bit until it
2757c478bd9Sstevel@tonic-gate 	 * clears or we time out.
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 	phy_control = BMCR_RESET;
2787c478bd9Sstevel@tonic-gate 	err = tg3_writephy(tp, MII_BMCR, phy_control);
2797c478bd9Sstevel@tonic-gate 	if (err != 0)
2807c478bd9Sstevel@tonic-gate 		return -EBUSY;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	limit = 5000;
2837c478bd9Sstevel@tonic-gate 	while (limit--) {
2847c478bd9Sstevel@tonic-gate 		err = tg3_readphy(tp, MII_BMCR, &phy_control);
2857c478bd9Sstevel@tonic-gate 		if (err != 0)
2867c478bd9Sstevel@tonic-gate 			return -EBUSY;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 		if ((phy_control & BMCR_RESET) == 0) {
2897c478bd9Sstevel@tonic-gate 			udelay(40);
2907c478bd9Sstevel@tonic-gate 			break;
2917c478bd9Sstevel@tonic-gate 		}
2927c478bd9Sstevel@tonic-gate 		udelay(10);
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 	if (limit <= 0)
2957c478bd9Sstevel@tonic-gate 		return -EBUSY;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	return 0;
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate 
tg3_wait_macro_done(struct tg3 * tp)3007c478bd9Sstevel@tonic-gate static int tg3_wait_macro_done(struct tg3 *tp)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	int limit = 100;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	while (limit--) {
3057c478bd9Sstevel@tonic-gate 		uint32_t tmp32;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, 0x16, &tmp32);
3087c478bd9Sstevel@tonic-gate 		if ((tmp32 & 0x1000) == 0)
3097c478bd9Sstevel@tonic-gate 			break;
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 	if (limit <= 0)
3127c478bd9Sstevel@tonic-gate 		return -EBUSY;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	return 0;
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
tg3_phy_write_and_check_testpat(struct tg3 * tp,int * resetp)3177c478bd9Sstevel@tonic-gate static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate 	static const uint32_t test_pat[4][6] = {
3207c478bd9Sstevel@tonic-gate 	{ 0x00005555, 0x00000005, 0x00002aaa, 0x0000000a, 0x00003456, 0x00000003 },
3217c478bd9Sstevel@tonic-gate 	{ 0x00002aaa, 0x0000000a, 0x00003333, 0x00000003, 0x0000789a, 0x00000005 },
3227c478bd9Sstevel@tonic-gate 	{ 0x00005a5a, 0x00000005, 0x00002a6a, 0x0000000a, 0x00001bcd, 0x00000003 },
3237c478bd9Sstevel@tonic-gate 	{ 0x00002a5a, 0x0000000a, 0x000033c3, 0x00000003, 0x00002ef1, 0x00000005 }
3247c478bd9Sstevel@tonic-gate 	};
3257c478bd9Sstevel@tonic-gate 	int chan;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	for (chan = 0; chan < 4; chan++) {
3287c478bd9Sstevel@tonic-gate 		int i;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
3317c478bd9Sstevel@tonic-gate 			(chan * 0x2000) | 0x0200);
3327c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x16, 0x0002);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 		for (i = 0; i < 6; i++)
3357c478bd9Sstevel@tonic-gate 			tg3_writephy(tp, MII_TG3_DSP_RW_PORT,
3367c478bd9Sstevel@tonic-gate 				test_pat[chan][i]);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x16, 0x0202);
3397c478bd9Sstevel@tonic-gate 		if (tg3_wait_macro_done(tp)) {
3407c478bd9Sstevel@tonic-gate 			*resetp = 1;
3417c478bd9Sstevel@tonic-gate 			return -EBUSY;
3427c478bd9Sstevel@tonic-gate 		}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
3457c478bd9Sstevel@tonic-gate 			     (chan * 0x2000) | 0x0200);
3467c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x16, 0x0082);
3477c478bd9Sstevel@tonic-gate 		if (tg3_wait_macro_done(tp)) {
3487c478bd9Sstevel@tonic-gate 			*resetp = 1;
3497c478bd9Sstevel@tonic-gate 			return -EBUSY;
3507c478bd9Sstevel@tonic-gate 		}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x16, 0x0802);
3537c478bd9Sstevel@tonic-gate 		if (tg3_wait_macro_done(tp)) {
3547c478bd9Sstevel@tonic-gate 			*resetp = 1;
3557c478bd9Sstevel@tonic-gate 			return -EBUSY;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		for (i = 0; i < 6; i += 2) {
3597c478bd9Sstevel@tonic-gate 			uint32_t low, high;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low);
3627c478bd9Sstevel@tonic-gate 			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high);
3637c478bd9Sstevel@tonic-gate 			if (tg3_wait_macro_done(tp)) {
3647c478bd9Sstevel@tonic-gate 				*resetp = 1;
3657c478bd9Sstevel@tonic-gate 				return -EBUSY;
3667c478bd9Sstevel@tonic-gate 			}
3677c478bd9Sstevel@tonic-gate 			low &= 0x7fff;
3687c478bd9Sstevel@tonic-gate 			high &= 0x000f;
3697c478bd9Sstevel@tonic-gate 			if (low != test_pat[chan][i] ||
3707c478bd9Sstevel@tonic-gate 			    high != test_pat[chan][i+1]) {
3717c478bd9Sstevel@tonic-gate 				tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000b);
3727c478bd9Sstevel@tonic-gate 				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4001);
3737c478bd9Sstevel@tonic-gate 				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4005);
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 				return -EBUSY;
3767c478bd9Sstevel@tonic-gate 			}
3777c478bd9Sstevel@tonic-gate 		}
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	return 0;
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate 
tg3_phy_reset_chanpat(struct tg3 * tp)3837c478bd9Sstevel@tonic-gate static int tg3_phy_reset_chanpat(struct tg3 *tp)
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 	int chan;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	for (chan = 0; chan < 4; chan++) {
3887c478bd9Sstevel@tonic-gate 		int i;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
3917c478bd9Sstevel@tonic-gate 			     (chan * 0x2000) | 0x0200);
3927c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x16, 0x0002);
3937c478bd9Sstevel@tonic-gate 		for (i = 0; i < 6; i++)
3947c478bd9Sstevel@tonic-gate 			tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);
3957c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x16, 0x0202);
3967c478bd9Sstevel@tonic-gate 		if (tg3_wait_macro_done(tp))
3977c478bd9Sstevel@tonic-gate 			return -EBUSY;
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	return 0;
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
tg3_phy_reset_5703_4_5(struct tg3 * tp)4037c478bd9Sstevel@tonic-gate static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
4047c478bd9Sstevel@tonic-gate {
4057c478bd9Sstevel@tonic-gate 	uint32_t reg32, phy9_orig;
4067c478bd9Sstevel@tonic-gate 	int retries, do_phy_reset, err;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	retries = 10;
4097c478bd9Sstevel@tonic-gate 	do_phy_reset = 1;
4107c478bd9Sstevel@tonic-gate 	do {
4117c478bd9Sstevel@tonic-gate 		if (do_phy_reset) {
4127c478bd9Sstevel@tonic-gate 			err = tg3_bmcr_reset(tp);
4137c478bd9Sstevel@tonic-gate 			if (err)
4147c478bd9Sstevel@tonic-gate 				return err;
4157c478bd9Sstevel@tonic-gate 			do_phy_reset = 0;
4167c478bd9Sstevel@tonic-gate 		}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 		/* Disable transmitter and interrupt.  */
4197c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
4207c478bd9Sstevel@tonic-gate 		reg32 |= 0x3000;
4217c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 		/* Set full-duplex, 1000 mbps.  */
4247c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_BMCR,
4257c478bd9Sstevel@tonic-gate 			BMCR_FULLDPLX | TG3_BMCR_SPEED1000);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 		/* Set to master mode.  */
4287c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig);
4297c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_CTRL,
4307c478bd9Sstevel@tonic-gate 			(MII_TG3_CTRL_AS_MASTER |
4317c478bd9Sstevel@tonic-gate 				MII_TG3_CTRL_ENABLE_AS_MASTER));
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 		/* Enable SM_DSP_CLOCK and 6dB.  */
4347c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 		/* Block the PHY control access.  */
4377c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
4387c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0800);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 		err = tg3_phy_write_and_check_testpat(tp, &do_phy_reset);
4417c478bd9Sstevel@tonic-gate 		if (!err)
4427c478bd9Sstevel@tonic-gate 			break;
4437c478bd9Sstevel@tonic-gate 	} while (--retries);
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	err = tg3_phy_reset_chanpat(tp);
4467c478bd9Sstevel@tonic-gate 	if (err)
4477c478bd9Sstevel@tonic-gate 		return err;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
4507c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0000);
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
4537c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, 0x16, 0x0000);
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
4607c478bd9Sstevel@tonic-gate 	reg32 &= ~0x3000;
4617c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	return err;
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate /* This will reset the tigon3 PHY if there is no valid
4677c478bd9Sstevel@tonic-gate  * link.
4687c478bd9Sstevel@tonic-gate  */
tg3_phy_reset(struct tg3 * tp)4697c478bd9Sstevel@tonic-gate static int tg3_phy_reset(struct tg3 *tp)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate 	uint32_t phy_status;
4727c478bd9Sstevel@tonic-gate 	int err;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	err  = tg3_readphy(tp, MII_BMSR, &phy_status);
4757c478bd9Sstevel@tonic-gate 	err |= tg3_readphy(tp, MII_BMSR, &phy_status);
4767c478bd9Sstevel@tonic-gate 	if (err != 0)
4777c478bd9Sstevel@tonic-gate 		return -EBUSY;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
4807c478bd9Sstevel@tonic-gate 		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
4817c478bd9Sstevel@tonic-gate 		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
4827c478bd9Sstevel@tonic-gate 		err = tg3_phy_reset_5703_4_5(tp);
4837c478bd9Sstevel@tonic-gate 		if (err)
4847c478bd9Sstevel@tonic-gate 			return err;
4857c478bd9Sstevel@tonic-gate 		goto out;
4867c478bd9Sstevel@tonic-gate 	}
4877c478bd9Sstevel@tonic-gate 	err = tg3_bmcr_reset(tp);
4887c478bd9Sstevel@tonic-gate 	if (err)
4897c478bd9Sstevel@tonic-gate 		return err;
4907c478bd9Sstevel@tonic-gate  out:
4917c478bd9Sstevel@tonic-gate 	tg3_phy_set_wirespeed(tp);
4927c478bd9Sstevel@tonic-gate 	return 0;
4937c478bd9Sstevel@tonic-gate }
4947c478bd9Sstevel@tonic-gate 
tg3_set_power_state_0(struct tg3 * tp)4957c478bd9Sstevel@tonic-gate static void tg3_set_power_state_0(struct tg3 *tp)
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate 	uint16_t power_control;
4987c478bd9Sstevel@tonic-gate 	int pm = tp->pm_cap;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	/* Make sure register accesses (indirect or otherwise)
5017c478bd9Sstevel@tonic-gate 	 * will function correctly.
5027c478bd9Sstevel@tonic-gate 	 */
5037c478bd9Sstevel@tonic-gate 	pci_write_config_dword(tp->pdev,  TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	pci_read_config_word(tp->pdev, pm + PCI_PM_CTRL, &power_control);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	power_control |= PCI_PM_CTRL_PME_STATUS;
5087c478bd9Sstevel@tonic-gate 	power_control &= ~(PCI_PM_CTRL_STATE_MASK);
5097c478bd9Sstevel@tonic-gate 	power_control |= 0;
5107c478bd9Sstevel@tonic-gate 	pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	tw32_carefully(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	return;
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate #if SUPPORT_LINK_REPORT
tg3_link_report(struct tg3 * tp)5197c478bd9Sstevel@tonic-gate static void tg3_link_report(struct tg3 *tp)
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate 	if (!tp->carrier_ok) {
5227c478bd9Sstevel@tonic-gate 		printf("Link is down.\n");
5237c478bd9Sstevel@tonic-gate 	} else {
5247c478bd9Sstevel@tonic-gate 		printf("Link is up at %d Mbps, %s duplex. %s %s %s\n",
5257c478bd9Sstevel@tonic-gate 			(tp->link_config.active_speed == SPEED_1000 ?
5267c478bd9Sstevel@tonic-gate 			       1000 :
5277c478bd9Sstevel@tonic-gate 			(tp->link_config.active_speed == SPEED_100 ?
5287c478bd9Sstevel@tonic-gate 				100 : 10)),
5297c478bd9Sstevel@tonic-gate 			(tp->link_config.active_duplex == DUPLEX_FULL ?
5307c478bd9Sstevel@tonic-gate 				"full" : "half"),
5317c478bd9Sstevel@tonic-gate 			(tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "TX" : "",
5327c478bd9Sstevel@tonic-gate 			(tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "RX" : "",
5337c478bd9Sstevel@tonic-gate 			(tp->tg3_flags & (TG3_FLAG_TX_PAUSE |TG3_FLAG_RX_PAUSE)) ? "flow control" : "");
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate #else
5377c478bd9Sstevel@tonic-gate #define tg3_link_report(tp)
5387c478bd9Sstevel@tonic-gate #endif
5397c478bd9Sstevel@tonic-gate 
tg3_setup_flow_control(struct tg3 * tp,uint32_t local_adv,uint32_t remote_adv)5407c478bd9Sstevel@tonic-gate static void tg3_setup_flow_control(struct tg3 *tp, uint32_t local_adv, uint32_t remote_adv)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate 	uint32_t new_tg3_flags = 0;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	if (local_adv & ADVERTISE_PAUSE_CAP) {
5457c478bd9Sstevel@tonic-gate 		if (local_adv & ADVERTISE_PAUSE_ASYM) {
5467c478bd9Sstevel@tonic-gate 			if (remote_adv & LPA_PAUSE_CAP)
5477c478bd9Sstevel@tonic-gate 				new_tg3_flags |=
5487c478bd9Sstevel@tonic-gate 					(TG3_FLAG_RX_PAUSE |
5497c478bd9Sstevel@tonic-gate 					 TG3_FLAG_TX_PAUSE);
5507c478bd9Sstevel@tonic-gate 			else if (remote_adv & LPA_PAUSE_ASYM)
5517c478bd9Sstevel@tonic-gate 				new_tg3_flags |=
5527c478bd9Sstevel@tonic-gate 					(TG3_FLAG_RX_PAUSE);
5537c478bd9Sstevel@tonic-gate 		} else {
5547c478bd9Sstevel@tonic-gate 			if (remote_adv & LPA_PAUSE_CAP)
5557c478bd9Sstevel@tonic-gate 				new_tg3_flags |=
5567c478bd9Sstevel@tonic-gate 					(TG3_FLAG_RX_PAUSE |
5577c478bd9Sstevel@tonic-gate 					 TG3_FLAG_TX_PAUSE);
5587c478bd9Sstevel@tonic-gate 		}
5597c478bd9Sstevel@tonic-gate 	} else if (local_adv & ADVERTISE_PAUSE_ASYM) {
5607c478bd9Sstevel@tonic-gate 		if ((remote_adv & LPA_PAUSE_CAP) &&
5617c478bd9Sstevel@tonic-gate 		    (remote_adv & LPA_PAUSE_ASYM))
5627c478bd9Sstevel@tonic-gate 			new_tg3_flags |= TG3_FLAG_TX_PAUSE;
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
5667c478bd9Sstevel@tonic-gate 	tp->tg3_flags |= new_tg3_flags;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	if (new_tg3_flags & TG3_FLAG_RX_PAUSE)
5697c478bd9Sstevel@tonic-gate 		tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
5707c478bd9Sstevel@tonic-gate 	else
5717c478bd9Sstevel@tonic-gate 		tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
5747c478bd9Sstevel@tonic-gate 		tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
5757c478bd9Sstevel@tonic-gate 	else
5767c478bd9Sstevel@tonic-gate 		tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate #if SUPPORT_COPPER_PHY
tg3_aux_stat_to_speed_duplex(struct tg3 * tp __unused,uint32_t val,uint8_t * speed,uint8_t * duplex)5807c478bd9Sstevel@tonic-gate static void tg3_aux_stat_to_speed_duplex(
5817c478bd9Sstevel@tonic-gate 	struct tg3 *tp __unused, uint32_t val, uint8_t *speed, uint8_t *duplex)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate 	static const uint8_t map[] = {
5847c478bd9Sstevel@tonic-gate 		[0] = (SPEED_INVALID << 2) | DUPLEX_INVALID,
5857c478bd9Sstevel@tonic-gate 		[MII_TG3_AUX_STAT_10HALF >> 8]   = (SPEED_10 << 2) | DUPLEX_HALF,
5867c478bd9Sstevel@tonic-gate 		[MII_TG3_AUX_STAT_10FULL >> 8]   = (SPEED_10 << 2) | DUPLEX_FULL,
5877c478bd9Sstevel@tonic-gate 		[MII_TG3_AUX_STAT_100HALF >> 8]  = (SPEED_100 << 2) | DUPLEX_HALF,
5887c478bd9Sstevel@tonic-gate 		[MII_TG3_AUX_STAT_100_4 >> 8] = (SPEED_INVALID << 2) | DUPLEX_INVALID,
5897c478bd9Sstevel@tonic-gate 		[MII_TG3_AUX_STAT_100FULL >> 8]  = (SPEED_100 << 2) | DUPLEX_FULL,
5907c478bd9Sstevel@tonic-gate 		[MII_TG3_AUX_STAT_1000HALF >> 8] = (SPEED_1000 << 2) | DUPLEX_HALF,
5917c478bd9Sstevel@tonic-gate 		[MII_TG3_AUX_STAT_1000FULL >> 8] = (SPEED_1000 << 2) | DUPLEX_FULL,
5927c478bd9Sstevel@tonic-gate 	};
5937c478bd9Sstevel@tonic-gate 	uint8_t result;
5947c478bd9Sstevel@tonic-gate 	result = map[(val & MII_TG3_AUX_STAT_SPDMASK) >> 8];
5957c478bd9Sstevel@tonic-gate 	*speed = result >> 2;
5967c478bd9Sstevel@tonic-gate 	*duplex = result & 3;
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate 
tg3_phy_copper_begin(struct tg3 * tp)5997c478bd9Sstevel@tonic-gate static int tg3_phy_copper_begin(struct tg3 *tp)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate 	uint32_t new_adv;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	tp->link_config.advertising =
6047c478bd9Sstevel@tonic-gate 		(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
6057c478bd9Sstevel@tonic-gate 			ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
6067c478bd9Sstevel@tonic-gate 			ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full |
6077c478bd9Sstevel@tonic-gate 			ADVERTISED_Autoneg | ADVERTISED_MII);
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	if (tp->tg3_flags & TG3_FLAG_10_100_ONLY) {
6107c478bd9Sstevel@tonic-gate 		tp->link_config.advertising &=
6117c478bd9Sstevel@tonic-gate 			~(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full);
6127c478bd9Sstevel@tonic-gate 	}
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
6157c478bd9Sstevel@tonic-gate 	if (tp->link_config.advertising & ADVERTISED_10baseT_Half) {
6167c478bd9Sstevel@tonic-gate 		new_adv |= ADVERTISE_10HALF;
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 	if (tp->link_config.advertising & ADVERTISED_10baseT_Full) {
6197c478bd9Sstevel@tonic-gate 		new_adv |= ADVERTISE_10FULL;
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 	if (tp->link_config.advertising & ADVERTISED_100baseT_Half) {
6227c478bd9Sstevel@tonic-gate 		new_adv |= ADVERTISE_100HALF;
6237c478bd9Sstevel@tonic-gate 	}
6247c478bd9Sstevel@tonic-gate 	if (tp->link_config.advertising & ADVERTISED_100baseT_Full) {
6257c478bd9Sstevel@tonic-gate 		new_adv |= ADVERTISE_100FULL;
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_ADVERTISE, new_adv);
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	if (tp->link_config.advertising &
6307c478bd9Sstevel@tonic-gate 		(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
6317c478bd9Sstevel@tonic-gate 		new_adv = 0;
6327c478bd9Sstevel@tonic-gate 		if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) {
6337c478bd9Sstevel@tonic-gate 			new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
6347c478bd9Sstevel@tonic-gate 		}
6357c478bd9Sstevel@tonic-gate 		if (tp->link_config.advertising & ADVERTISED_1000baseT_Full) {
6367c478bd9Sstevel@tonic-gate 			new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
6377c478bd9Sstevel@tonic-gate 		}
6387c478bd9Sstevel@tonic-gate 		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
6397c478bd9Sstevel@tonic-gate 			(tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
6407c478bd9Sstevel@tonic-gate 				tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) {
6417c478bd9Sstevel@tonic-gate 			new_adv |= (MII_TG3_CTRL_AS_MASTER |
6427c478bd9Sstevel@tonic-gate 				MII_TG3_CTRL_ENABLE_AS_MASTER);
6437c478bd9Sstevel@tonic-gate 		}
6447c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_CTRL, new_adv);
6457c478bd9Sstevel@tonic-gate 	} else {
6467c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_CTRL, 0);
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	return 0;
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate 
tg3_init_5401phy_dsp(struct tg3 * tp)6547c478bd9Sstevel@tonic-gate static int tg3_init_5401phy_dsp(struct tg3 *tp)
6557c478bd9Sstevel@tonic-gate {
6567c478bd9Sstevel@tonic-gate 	int err;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	/* Turn off tap power management. */
6597c478bd9Sstevel@tonic-gate 	err  = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c20);
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	err |= tg3_writedsp(tp, 0x0012, 0x1804);
6627c478bd9Sstevel@tonic-gate 	err |= tg3_writedsp(tp, 0x0013, 0x1204);
6637c478bd9Sstevel@tonic-gate 	err |= tg3_writedsp(tp, 0x8006, 0x0132);
6647c478bd9Sstevel@tonic-gate 	err |= tg3_writedsp(tp, 0x8006, 0x0232);
6657c478bd9Sstevel@tonic-gate 	err |= tg3_writedsp(tp, 0x201f, 0x0a20);
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	udelay(40);
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	return err;
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate 
tg3_setup_copper_phy(struct tg3 * tp)6727c478bd9Sstevel@tonic-gate static int tg3_setup_copper_phy(struct tg3 *tp)
6737c478bd9Sstevel@tonic-gate {
6747c478bd9Sstevel@tonic-gate 	int current_link_up;
6757c478bd9Sstevel@tonic-gate 	uint32_t bmsr, dummy;
6767c478bd9Sstevel@tonic-gate 	int i, err;
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_STATUS,
6797c478bd9Sstevel@tonic-gate 		(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	tp->mi_mode = MAC_MI_MODE_BASE;
6827c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	/* Some third-party PHYs need to be reset on link going
6877c478bd9Sstevel@tonic-gate 	 * down.
6887c478bd9Sstevel@tonic-gate 	 */
6897c478bd9Sstevel@tonic-gate 	if (	(	(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
6907c478bd9Sstevel@tonic-gate 			(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
6917c478bd9Sstevel@tonic-gate 			(tp->pci_chip_rev_id == CHIPREV_ID_5705_A0)) &&
6927c478bd9Sstevel@tonic-gate 		(tp->carrier_ok)) {
6937c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_BMSR, &bmsr);
6947c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_BMSR, &bmsr);
6957c478bd9Sstevel@tonic-gate 		if (!(bmsr & BMSR_LSTATUS))
6967c478bd9Sstevel@tonic-gate 			tg3_phy_reset(tp);
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
7007c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_BMSR, &bmsr);
7017c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_BMSR, &bmsr);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 		if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
7047c478bd9Sstevel@tonic-gate 			bmsr = 0;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 		if (!(bmsr & BMSR_LSTATUS)) {
7077c478bd9Sstevel@tonic-gate 			err = tg3_init_5401phy_dsp(tp);
7087c478bd9Sstevel@tonic-gate 			if (err)
7097c478bd9Sstevel@tonic-gate 				return err;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 			tg3_readphy(tp, MII_BMSR, &bmsr);
7127c478bd9Sstevel@tonic-gate 			for (i = 0; i < 1000; i++) {
7137c478bd9Sstevel@tonic-gate 				udelay(10);
7147c478bd9Sstevel@tonic-gate 				tg3_readphy(tp, MII_BMSR, &bmsr);
7157c478bd9Sstevel@tonic-gate 				if (bmsr & BMSR_LSTATUS) {
7167c478bd9Sstevel@tonic-gate 					udelay(40);
7177c478bd9Sstevel@tonic-gate 					break;
7187c478bd9Sstevel@tonic-gate 				}
7197c478bd9Sstevel@tonic-gate 			}
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 			if ((tp->phy_id & PHY_ID_REV_MASK) == PHY_REV_BCM5401_B0 &&
7227c478bd9Sstevel@tonic-gate 			    !(bmsr & BMSR_LSTATUS) &&
7237c478bd9Sstevel@tonic-gate 			    tp->link_config.active_speed == SPEED_1000) {
7247c478bd9Sstevel@tonic-gate 				err = tg3_phy_reset(tp);
7257c478bd9Sstevel@tonic-gate 				if (!err)
7267c478bd9Sstevel@tonic-gate 					err = tg3_init_5401phy_dsp(tp);
7277c478bd9Sstevel@tonic-gate 				if (err)
7287c478bd9Sstevel@tonic-gate 					return err;
7297c478bd9Sstevel@tonic-gate 			}
7307c478bd9Sstevel@tonic-gate 		}
7317c478bd9Sstevel@tonic-gate 	} else if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
7327c478bd9Sstevel@tonic-gate 		   tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
7337c478bd9Sstevel@tonic-gate 		/* 5701 {A0,B0} CRC bug workaround */
7347c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x15, 0x0a75);
7357c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x1c, 0x8c68);
7367c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x1c, 0x8d68);
7377c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x1c, 0x8c68);
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	/* Clear pending interrupts... */
7417c478bd9Sstevel@tonic-gate 	tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
7427c478bd9Sstevel@tonic-gate 	tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	tg3_writephy(tp, MII_TG3_IMASK, ~0);
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	if (tp->led_mode == led_mode_three_link)
7477c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_EXT_CTRL,
7487c478bd9Sstevel@tonic-gate 			     MII_TG3_EXT_CTRL_LNK3_LED_MODE);
7497c478bd9Sstevel@tonic-gate 	else
7507c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_TG3_EXT_CTRL, 0);
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	current_link_up = 0;
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	tg3_readphy(tp, MII_BMSR, &bmsr);
7557c478bd9Sstevel@tonic-gate 	tg3_readphy(tp, MII_BMSR, &bmsr);
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (bmsr & BMSR_LSTATUS) {
7587c478bd9Sstevel@tonic-gate 		uint32_t aux_stat, bmcr;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
7617c478bd9Sstevel@tonic-gate 		for (i = 0; i < 2000; i++) {
7627c478bd9Sstevel@tonic-gate 			udelay(10);
7637c478bd9Sstevel@tonic-gate 			tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
7647c478bd9Sstevel@tonic-gate 			if (aux_stat)
7657c478bd9Sstevel@tonic-gate 				break;
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 		tg3_aux_stat_to_speed_duplex(tp, aux_stat,
7697c478bd9Sstevel@tonic-gate 			&tp->link_config.active_speed,
7707c478bd9Sstevel@tonic-gate 			&tp->link_config.active_duplex);
7717c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_BMCR, &bmcr);
7727c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_BMCR, &bmcr);
7737c478bd9Sstevel@tonic-gate 		if (bmcr & BMCR_ANENABLE) {
7747c478bd9Sstevel@tonic-gate 			uint32_t gig_ctrl;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 			current_link_up = 1;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 			/* Force autoneg restart if we are exiting
7797c478bd9Sstevel@tonic-gate 			 * low power mode.
7807c478bd9Sstevel@tonic-gate 			 */
7817c478bd9Sstevel@tonic-gate 			tg3_readphy(tp, MII_TG3_CTRL, &gig_ctrl);
7827c478bd9Sstevel@tonic-gate 			if (!(gig_ctrl & (MII_TG3_CTRL_ADV_1000_HALF |
7837c478bd9Sstevel@tonic-gate 				      MII_TG3_CTRL_ADV_1000_FULL))) {
7847c478bd9Sstevel@tonic-gate 				current_link_up = 0;
7857c478bd9Sstevel@tonic-gate 			}
7867c478bd9Sstevel@tonic-gate 		} else {
7877c478bd9Sstevel@tonic-gate 			current_link_up = 0;
7887c478bd9Sstevel@tonic-gate 		}
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	if (current_link_up == 1 &&
7927c478bd9Sstevel@tonic-gate 		(tp->link_config.active_duplex == DUPLEX_FULL)) {
7937c478bd9Sstevel@tonic-gate 		uint32_t local_adv, remote_adv;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_ADVERTISE, &local_adv);
7967c478bd9Sstevel@tonic-gate 		local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_LPA, &remote_adv);
7997c478bd9Sstevel@tonic-gate 		remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 		/* If we are not advertising full pause capability,
8027c478bd9Sstevel@tonic-gate 		 * something is wrong.  Bring the link down and reconfigure.
8037c478bd9Sstevel@tonic-gate 		 */
8047c478bd9Sstevel@tonic-gate 		if (local_adv != ADVERTISE_PAUSE_CAP) {
8057c478bd9Sstevel@tonic-gate 			current_link_up = 0;
8067c478bd9Sstevel@tonic-gate 		} else {
8077c478bd9Sstevel@tonic-gate 			tg3_setup_flow_control(tp, local_adv, remote_adv);
8087c478bd9Sstevel@tonic-gate 		}
8097c478bd9Sstevel@tonic-gate 	}
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	if (current_link_up == 0) {
8127c478bd9Sstevel@tonic-gate 		uint32_t tmp;
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 		tg3_phy_copper_begin(tp);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_BMSR, &tmp);
8177c478bd9Sstevel@tonic-gate 		tg3_readphy(tp, MII_BMSR, &tmp);
8187c478bd9Sstevel@tonic-gate 		if (tmp & BMSR_LSTATUS)
8197c478bd9Sstevel@tonic-gate 			current_link_up = 1;
8207c478bd9Sstevel@tonic-gate 	}
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK;
8237c478bd9Sstevel@tonic-gate 	if (current_link_up == 1) {
8247c478bd9Sstevel@tonic-gate 		if (tp->link_config.active_speed == SPEED_100 ||
8257c478bd9Sstevel@tonic-gate 		    tp->link_config.active_speed == SPEED_10)
8267c478bd9Sstevel@tonic-gate 			tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
8277c478bd9Sstevel@tonic-gate 		else
8287c478bd9Sstevel@tonic-gate 			tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
8297c478bd9Sstevel@tonic-gate 	} else
8307c478bd9Sstevel@tonic-gate 		tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
8337c478bd9Sstevel@tonic-gate 	if (tp->link_config.active_duplex == DUPLEX_HALF)
8347c478bd9Sstevel@tonic-gate 		tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
8377c478bd9Sstevel@tonic-gate 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
8387c478bd9Sstevel@tonic-gate 		if ((tp->led_mode == led_mode_link10) ||
8397c478bd9Sstevel@tonic-gate 		    (current_link_up == 1 &&
8407c478bd9Sstevel@tonic-gate 		     tp->link_config.active_speed == SPEED_10))
8417c478bd9Sstevel@tonic-gate 			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
8427c478bd9Sstevel@tonic-gate 	} else {
8437c478bd9Sstevel@tonic-gate 		if (current_link_up == 1)
8447c478bd9Sstevel@tonic-gate 			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
8457c478bd9Sstevel@tonic-gate 		tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1);
8467c478bd9Sstevel@tonic-gate 	}
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	/* ??? Without this setting Netgear GA302T PHY does not
8497c478bd9Sstevel@tonic-gate 	 * ??? send/receive packets...
8507c478bd9Sstevel@tonic-gate 	 * With this other PHYs cannot bring up the link
8517c478bd9Sstevel@tonic-gate 	 */
8527c478bd9Sstevel@tonic-gate 	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411 &&
8537c478bd9Sstevel@tonic-gate 		tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
8547c478bd9Sstevel@tonic-gate 		tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
8557c478bd9Sstevel@tonic-gate 		tw32_carefully(MAC_MI_MODE, tp->mi_mode);
8567c478bd9Sstevel@tonic-gate 	}
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MODE, tp->mac_mode);
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	/* Link change polled. */
8617c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_EVENT, 0);
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
8647c478bd9Sstevel@tonic-gate 	    current_link_up == 1 &&
8657c478bd9Sstevel@tonic-gate 	    tp->link_config.active_speed == SPEED_1000 &&
8667c478bd9Sstevel@tonic-gate 	    ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ||
8677c478bd9Sstevel@tonic-gate 	     (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) {
8687c478bd9Sstevel@tonic-gate 		udelay(120);
8697c478bd9Sstevel@tonic-gate 		tw32_carefully(MAC_STATUS,
8707c478bd9Sstevel@tonic-gate 			(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
8717c478bd9Sstevel@tonic-gate 		tg3_write_mem(
8727c478bd9Sstevel@tonic-gate 			      NIC_SRAM_FIRMWARE_MBOX,
8737c478bd9Sstevel@tonic-gate 			      NIC_SRAM_FIRMWARE_MBOX_MAGIC2);
8747c478bd9Sstevel@tonic-gate 	}
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	if (current_link_up != tp->carrier_ok) {
8777c478bd9Sstevel@tonic-gate 		tp->carrier_ok = current_link_up;
8787c478bd9Sstevel@tonic-gate 		tg3_link_report(tp);
8797c478bd9Sstevel@tonic-gate 	}
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	return 0;
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate #else
8847c478bd9Sstevel@tonic-gate #define tg3_setup_copper_phy(TP) (-EINVAL)
8857c478bd9Sstevel@tonic-gate #endif /* SUPPORT_COPPER_PHY */
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate #if SUPPORT_FIBER_PHY
8887c478bd9Sstevel@tonic-gate struct tg3_fiber_aneginfo {
8897c478bd9Sstevel@tonic-gate 	int state;
8907c478bd9Sstevel@tonic-gate #define ANEG_STATE_UNKNOWN		0
8917c478bd9Sstevel@tonic-gate #define ANEG_STATE_AN_ENABLE		1
8927c478bd9Sstevel@tonic-gate #define ANEG_STATE_RESTART_INIT		2
8937c478bd9Sstevel@tonic-gate #define ANEG_STATE_RESTART		3
8947c478bd9Sstevel@tonic-gate #define ANEG_STATE_DISABLE_LINK_OK	4
8957c478bd9Sstevel@tonic-gate #define ANEG_STATE_ABILITY_DETECT_INIT	5
8967c478bd9Sstevel@tonic-gate #define ANEG_STATE_ABILITY_DETECT	6
8977c478bd9Sstevel@tonic-gate #define ANEG_STATE_ACK_DETECT_INIT	7
8987c478bd9Sstevel@tonic-gate #define ANEG_STATE_ACK_DETECT		8
8997c478bd9Sstevel@tonic-gate #define ANEG_STATE_COMPLETE_ACK_INIT	9
9007c478bd9Sstevel@tonic-gate #define ANEG_STATE_COMPLETE_ACK		10
9017c478bd9Sstevel@tonic-gate #define ANEG_STATE_IDLE_DETECT_INIT	11
9027c478bd9Sstevel@tonic-gate #define ANEG_STATE_IDLE_DETECT		12
9037c478bd9Sstevel@tonic-gate #define ANEG_STATE_LINK_OK		13
9047c478bd9Sstevel@tonic-gate #define ANEG_STATE_NEXT_PAGE_WAIT_INIT	14
9057c478bd9Sstevel@tonic-gate #define ANEG_STATE_NEXT_PAGE_WAIT	15
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	uint32_t flags;
9087c478bd9Sstevel@tonic-gate #define MR_AN_ENABLE		0x00000001
9097c478bd9Sstevel@tonic-gate #define MR_RESTART_AN		0x00000002
9107c478bd9Sstevel@tonic-gate #define MR_AN_COMPLETE		0x00000004
9117c478bd9Sstevel@tonic-gate #define MR_PAGE_RX		0x00000008
9127c478bd9Sstevel@tonic-gate #define MR_NP_LOADED		0x00000010
9137c478bd9Sstevel@tonic-gate #define MR_TOGGLE_TX		0x00000020
9147c478bd9Sstevel@tonic-gate #define MR_LP_ADV_FULL_DUPLEX	0x00000040
9157c478bd9Sstevel@tonic-gate #define MR_LP_ADV_HALF_DUPLEX	0x00000080
9167c478bd9Sstevel@tonic-gate #define MR_LP_ADV_SYM_PAUSE	0x00000100
9177c478bd9Sstevel@tonic-gate #define MR_LP_ADV_ASYM_PAUSE	0x00000200
9187c478bd9Sstevel@tonic-gate #define MR_LP_ADV_REMOTE_FAULT1	0x00000400
9197c478bd9Sstevel@tonic-gate #define MR_LP_ADV_REMOTE_FAULT2	0x00000800
9207c478bd9Sstevel@tonic-gate #define MR_LP_ADV_NEXT_PAGE	0x00001000
9217c478bd9Sstevel@tonic-gate #define MR_TOGGLE_RX		0x00002000
9227c478bd9Sstevel@tonic-gate #define MR_NP_RX		0x00004000
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate #define MR_LINK_OK		0x80000000
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 	unsigned long link_time, cur_time;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	uint32_t ability_match_cfg;
9297c478bd9Sstevel@tonic-gate 	int ability_match_count;
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	char ability_match, idle_match, ack_match;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	uint32_t txconfig, rxconfig;
9347c478bd9Sstevel@tonic-gate #define ANEG_CFG_NP		0x00000080
9357c478bd9Sstevel@tonic-gate #define ANEG_CFG_ACK		0x00000040
9367c478bd9Sstevel@tonic-gate #define ANEG_CFG_RF2		0x00000020
9377c478bd9Sstevel@tonic-gate #define ANEG_CFG_RF1		0x00000010
9387c478bd9Sstevel@tonic-gate #define ANEG_CFG_PS2		0x00000001
9397c478bd9Sstevel@tonic-gate #define ANEG_CFG_PS1		0x00008000
9407c478bd9Sstevel@tonic-gate #define ANEG_CFG_HD		0x00004000
9417c478bd9Sstevel@tonic-gate #define ANEG_CFG_FD		0x00002000
9427c478bd9Sstevel@tonic-gate #define ANEG_CFG_INVAL		0x00001f06
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate };
9457c478bd9Sstevel@tonic-gate #define ANEG_OK		0
9467c478bd9Sstevel@tonic-gate #define ANEG_DONE	1
9477c478bd9Sstevel@tonic-gate #define ANEG_TIMER_ENAB	2
9487c478bd9Sstevel@tonic-gate #define ANEG_FAILED	-1
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate #define ANEG_STATE_SETTLE_TIME	10000
9517c478bd9Sstevel@tonic-gate 
tg3_fiber_aneg_smachine(struct tg3 * tp,struct tg3_fiber_aneginfo * ap)9527c478bd9Sstevel@tonic-gate static int tg3_fiber_aneg_smachine(struct tg3 *tp,
9537c478bd9Sstevel@tonic-gate 				   struct tg3_fiber_aneginfo *ap)
9547c478bd9Sstevel@tonic-gate {
9557c478bd9Sstevel@tonic-gate 	unsigned long delta;
9567c478bd9Sstevel@tonic-gate 	uint32_t rx_cfg_reg;
9577c478bd9Sstevel@tonic-gate 	int ret;
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	if (ap->state == ANEG_STATE_UNKNOWN) {
9607c478bd9Sstevel@tonic-gate 		ap->rxconfig = 0;
9617c478bd9Sstevel@tonic-gate 		ap->link_time = 0;
9627c478bd9Sstevel@tonic-gate 		ap->cur_time = 0;
9637c478bd9Sstevel@tonic-gate 		ap->ability_match_cfg = 0;
9647c478bd9Sstevel@tonic-gate 		ap->ability_match_count = 0;
9657c478bd9Sstevel@tonic-gate 		ap->ability_match = 0;
9667c478bd9Sstevel@tonic-gate 		ap->idle_match = 0;
9677c478bd9Sstevel@tonic-gate 		ap->ack_match = 0;
9687c478bd9Sstevel@tonic-gate 	}
9697c478bd9Sstevel@tonic-gate 	ap->cur_time++;
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	if (tr32(MAC_STATUS) & MAC_STATUS_RCVD_CFG) {
9727c478bd9Sstevel@tonic-gate 		rx_cfg_reg = tr32(MAC_RX_AUTO_NEG);
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 		if (rx_cfg_reg != ap->ability_match_cfg) {
9757c478bd9Sstevel@tonic-gate 			ap->ability_match_cfg = rx_cfg_reg;
9767c478bd9Sstevel@tonic-gate 			ap->ability_match = 0;
9777c478bd9Sstevel@tonic-gate 			ap->ability_match_count = 0;
9787c478bd9Sstevel@tonic-gate 		} else {
9797c478bd9Sstevel@tonic-gate 			if (++ap->ability_match_count > 1) {
9807c478bd9Sstevel@tonic-gate 				ap->ability_match = 1;
9817c478bd9Sstevel@tonic-gate 				ap->ability_match_cfg = rx_cfg_reg;
9827c478bd9Sstevel@tonic-gate 			}
9837c478bd9Sstevel@tonic-gate 		}
9847c478bd9Sstevel@tonic-gate 		if (rx_cfg_reg & ANEG_CFG_ACK)
9857c478bd9Sstevel@tonic-gate 			ap->ack_match = 1;
9867c478bd9Sstevel@tonic-gate 		else
9877c478bd9Sstevel@tonic-gate 			ap->ack_match = 0;
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 		ap->idle_match = 0;
9907c478bd9Sstevel@tonic-gate 	} else {
9917c478bd9Sstevel@tonic-gate 		ap->idle_match = 1;
9927c478bd9Sstevel@tonic-gate 		ap->ability_match_cfg = 0;
9937c478bd9Sstevel@tonic-gate 		ap->ability_match_count = 0;
9947c478bd9Sstevel@tonic-gate 		ap->ability_match = 0;
9957c478bd9Sstevel@tonic-gate 		ap->ack_match = 0;
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 		rx_cfg_reg = 0;
9987c478bd9Sstevel@tonic-gate 	}
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	ap->rxconfig = rx_cfg_reg;
10017c478bd9Sstevel@tonic-gate 	ret = ANEG_OK;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	switch(ap->state) {
10047c478bd9Sstevel@tonic-gate 	case ANEG_STATE_UNKNOWN:
10057c478bd9Sstevel@tonic-gate 		if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN))
10067c478bd9Sstevel@tonic-gate 			ap->state = ANEG_STATE_AN_ENABLE;
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 		/* fallthru */
10097c478bd9Sstevel@tonic-gate 	case ANEG_STATE_AN_ENABLE:
10107c478bd9Sstevel@tonic-gate 		ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX);
10117c478bd9Sstevel@tonic-gate 		if (ap->flags & MR_AN_ENABLE) {
10127c478bd9Sstevel@tonic-gate 			ap->link_time = 0;
10137c478bd9Sstevel@tonic-gate 			ap->cur_time = 0;
10147c478bd9Sstevel@tonic-gate 			ap->ability_match_cfg = 0;
10157c478bd9Sstevel@tonic-gate 			ap->ability_match_count = 0;
10167c478bd9Sstevel@tonic-gate 			ap->ability_match = 0;
10177c478bd9Sstevel@tonic-gate 			ap->idle_match = 0;
10187c478bd9Sstevel@tonic-gate 			ap->ack_match = 0;
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 			ap->state = ANEG_STATE_RESTART_INIT;
10217c478bd9Sstevel@tonic-gate 		} else {
10227c478bd9Sstevel@tonic-gate 			ap->state = ANEG_STATE_DISABLE_LINK_OK;
10237c478bd9Sstevel@tonic-gate 		}
10247c478bd9Sstevel@tonic-gate 		break;
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	case ANEG_STATE_RESTART_INIT:
10277c478bd9Sstevel@tonic-gate 		ap->link_time = ap->cur_time;
10287c478bd9Sstevel@tonic-gate 		ap->flags &= ~(MR_NP_LOADED);
10297c478bd9Sstevel@tonic-gate 		ap->txconfig = 0;
10307c478bd9Sstevel@tonic-gate 		tw32(MAC_TX_AUTO_NEG, 0);
10317c478bd9Sstevel@tonic-gate 		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
10327c478bd9Sstevel@tonic-gate 		tw32_carefully(MAC_MODE, tp->mac_mode);
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 		ret = ANEG_TIMER_ENAB;
10357c478bd9Sstevel@tonic-gate 		ap->state = ANEG_STATE_RESTART;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 		/* fallthru */
10387c478bd9Sstevel@tonic-gate 	case ANEG_STATE_RESTART:
10397c478bd9Sstevel@tonic-gate 		delta = ap->cur_time - ap->link_time;
10407c478bd9Sstevel@tonic-gate 		if (delta > ANEG_STATE_SETTLE_TIME) {
10417c478bd9Sstevel@tonic-gate 			ap->state = ANEG_STATE_ABILITY_DETECT_INIT;
10427c478bd9Sstevel@tonic-gate 		} else {
10437c478bd9Sstevel@tonic-gate 			ret = ANEG_TIMER_ENAB;
10447c478bd9Sstevel@tonic-gate 		}
10457c478bd9Sstevel@tonic-gate 		break;
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	case ANEG_STATE_DISABLE_LINK_OK:
10487c478bd9Sstevel@tonic-gate 		ret = ANEG_DONE;
10497c478bd9Sstevel@tonic-gate 		break;
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	case ANEG_STATE_ABILITY_DETECT_INIT:
10527c478bd9Sstevel@tonic-gate 		ap->flags &= ~(MR_TOGGLE_TX);
10537c478bd9Sstevel@tonic-gate 		ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
10547c478bd9Sstevel@tonic-gate 		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
10557c478bd9Sstevel@tonic-gate 		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
10567c478bd9Sstevel@tonic-gate 		tw32_carefully(MAC_MODE, tp->mac_mode);
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 		ap->state = ANEG_STATE_ABILITY_DETECT;
10597c478bd9Sstevel@tonic-gate 		break;
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	case ANEG_STATE_ABILITY_DETECT:
10627c478bd9Sstevel@tonic-gate 		if (ap->ability_match != 0 && ap->rxconfig != 0) {
10637c478bd9Sstevel@tonic-gate 			ap->state = ANEG_STATE_ACK_DETECT_INIT;
10647c478bd9Sstevel@tonic-gate 		}
10657c478bd9Sstevel@tonic-gate 		break;
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	case ANEG_STATE_ACK_DETECT_INIT:
10687c478bd9Sstevel@tonic-gate 		ap->txconfig |= ANEG_CFG_ACK;
10697c478bd9Sstevel@tonic-gate 		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
10707c478bd9Sstevel@tonic-gate 		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
10717c478bd9Sstevel@tonic-gate 		tw32_carefully(MAC_MODE, tp->mac_mode);
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 		ap->state = ANEG_STATE_ACK_DETECT;
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 		/* fallthru */
10767c478bd9Sstevel@tonic-gate 	case ANEG_STATE_ACK_DETECT:
10777c478bd9Sstevel@tonic-gate 		if (ap->ack_match != 0) {
10787c478bd9Sstevel@tonic-gate 			if ((ap->rxconfig & ~ANEG_CFG_ACK) ==
10797c478bd9Sstevel@tonic-gate 			    (ap->ability_match_cfg & ~ANEG_CFG_ACK)) {
10807c478bd9Sstevel@tonic-gate 				ap->state = ANEG_STATE_COMPLETE_ACK_INIT;
10817c478bd9Sstevel@tonic-gate 			} else {
10827c478bd9Sstevel@tonic-gate 				ap->state = ANEG_STATE_AN_ENABLE;
10837c478bd9Sstevel@tonic-gate 			}
10847c478bd9Sstevel@tonic-gate 		} else if (ap->ability_match != 0 &&
10857c478bd9Sstevel@tonic-gate 			   ap->rxconfig == 0) {
10867c478bd9Sstevel@tonic-gate 			ap->state = ANEG_STATE_AN_ENABLE;
10877c478bd9Sstevel@tonic-gate 		}
10887c478bd9Sstevel@tonic-gate 		break;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	case ANEG_STATE_COMPLETE_ACK_INIT:
10917c478bd9Sstevel@tonic-gate 		if (ap->rxconfig & ANEG_CFG_INVAL) {
10927c478bd9Sstevel@tonic-gate 			ret = ANEG_FAILED;
10937c478bd9Sstevel@tonic-gate 			break;
10947c478bd9Sstevel@tonic-gate 		}
10957c478bd9Sstevel@tonic-gate 		ap->flags &= ~(MR_LP_ADV_FULL_DUPLEX |
10967c478bd9Sstevel@tonic-gate 			       MR_LP_ADV_HALF_DUPLEX |
10977c478bd9Sstevel@tonic-gate 			       MR_LP_ADV_SYM_PAUSE |
10987c478bd9Sstevel@tonic-gate 			       MR_LP_ADV_ASYM_PAUSE |
10997c478bd9Sstevel@tonic-gate 			       MR_LP_ADV_REMOTE_FAULT1 |
11007c478bd9Sstevel@tonic-gate 			       MR_LP_ADV_REMOTE_FAULT2 |
11017c478bd9Sstevel@tonic-gate 			       MR_LP_ADV_NEXT_PAGE |
11027c478bd9Sstevel@tonic-gate 			       MR_TOGGLE_RX |
11037c478bd9Sstevel@tonic-gate 			       MR_NP_RX);
11047c478bd9Sstevel@tonic-gate 		if (ap->rxconfig & ANEG_CFG_FD)
11057c478bd9Sstevel@tonic-gate 			ap->flags |= MR_LP_ADV_FULL_DUPLEX;
11067c478bd9Sstevel@tonic-gate 		if (ap->rxconfig & ANEG_CFG_HD)
11077c478bd9Sstevel@tonic-gate 			ap->flags |= MR_LP_ADV_HALF_DUPLEX;
11087c478bd9Sstevel@tonic-gate 		if (ap->rxconfig & ANEG_CFG_PS1)
11097c478bd9Sstevel@tonic-gate 			ap->flags |= MR_LP_ADV_SYM_PAUSE;
11107c478bd9Sstevel@tonic-gate 		if (ap->rxconfig & ANEG_CFG_PS2)
11117c478bd9Sstevel@tonic-gate 			ap->flags |= MR_LP_ADV_ASYM_PAUSE;
11127c478bd9Sstevel@tonic-gate 		if (ap->rxconfig & ANEG_CFG_RF1)
11137c478bd9Sstevel@tonic-gate 			ap->flags |= MR_LP_ADV_REMOTE_FAULT1;
11147c478bd9Sstevel@tonic-gate 		if (ap->rxconfig & ANEG_CFG_RF2)
11157c478bd9Sstevel@tonic-gate 			ap->flags |= MR_LP_ADV_REMOTE_FAULT2;
11167c478bd9Sstevel@tonic-gate 		if (ap->rxconfig & ANEG_CFG_NP)
11177c478bd9Sstevel@tonic-gate 			ap->flags |= MR_LP_ADV_NEXT_PAGE;
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 		ap->link_time = ap->cur_time;
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 		ap->flags ^= (MR_TOGGLE_TX);
11227c478bd9Sstevel@tonic-gate 		if (ap->rxconfig & 0x0008)
11237c478bd9Sstevel@tonic-gate 			ap->flags |= MR_TOGGLE_RX;
11247c478bd9Sstevel@tonic-gate 		if (ap->rxconfig & ANEG_CFG_NP)
11257c478bd9Sstevel@tonic-gate 			ap->flags |= MR_NP_RX;
11267c478bd9Sstevel@tonic-gate 		ap->flags |= MR_PAGE_RX;
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 		ap->state = ANEG_STATE_COMPLETE_ACK;
11297c478bd9Sstevel@tonic-gate 		ret = ANEG_TIMER_ENAB;
11307c478bd9Sstevel@tonic-gate 		break;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	case ANEG_STATE_COMPLETE_ACK:
11337c478bd9Sstevel@tonic-gate 		if (ap->ability_match != 0 &&
11347c478bd9Sstevel@tonic-gate 		    ap->rxconfig == 0) {
11357c478bd9Sstevel@tonic-gate 			ap->state = ANEG_STATE_AN_ENABLE;
11367c478bd9Sstevel@tonic-gate 			break;
11377c478bd9Sstevel@tonic-gate 		}
11387c478bd9Sstevel@tonic-gate 		delta = ap->cur_time - ap->link_time;
11397c478bd9Sstevel@tonic-gate 		if (delta > ANEG_STATE_SETTLE_TIME) {
11407c478bd9Sstevel@tonic-gate 			if (!(ap->flags & (MR_LP_ADV_NEXT_PAGE))) {
11417c478bd9Sstevel@tonic-gate 				ap->state = ANEG_STATE_IDLE_DETECT_INIT;
11427c478bd9Sstevel@tonic-gate 			} else {
11437c478bd9Sstevel@tonic-gate 				if ((ap->txconfig & ANEG_CFG_NP) == 0 &&
11447c478bd9Sstevel@tonic-gate 				    !(ap->flags & MR_NP_RX)) {
11457c478bd9Sstevel@tonic-gate 					ap->state = ANEG_STATE_IDLE_DETECT_INIT;
11467c478bd9Sstevel@tonic-gate 				} else {
11477c478bd9Sstevel@tonic-gate 					ret = ANEG_FAILED;
11487c478bd9Sstevel@tonic-gate 				}
11497c478bd9Sstevel@tonic-gate 			}
11507c478bd9Sstevel@tonic-gate 		}
11517c478bd9Sstevel@tonic-gate 		break;
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	case ANEG_STATE_IDLE_DETECT_INIT:
11547c478bd9Sstevel@tonic-gate 		ap->link_time = ap->cur_time;
11557c478bd9Sstevel@tonic-gate 		tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
11567c478bd9Sstevel@tonic-gate 		tw32_carefully(MAC_MODE, tp->mac_mode);
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 		ap->state = ANEG_STATE_IDLE_DETECT;
11597c478bd9Sstevel@tonic-gate 		ret = ANEG_TIMER_ENAB;
11607c478bd9Sstevel@tonic-gate 		break;
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	case ANEG_STATE_IDLE_DETECT:
11637c478bd9Sstevel@tonic-gate 		if (ap->ability_match != 0 &&
11647c478bd9Sstevel@tonic-gate 		    ap->rxconfig == 0) {
11657c478bd9Sstevel@tonic-gate 			ap->state = ANEG_STATE_AN_ENABLE;
11667c478bd9Sstevel@tonic-gate 			break;
11677c478bd9Sstevel@tonic-gate 		}
11687c478bd9Sstevel@tonic-gate 		delta = ap->cur_time - ap->link_time;
11697c478bd9Sstevel@tonic-gate 		if (delta > ANEG_STATE_SETTLE_TIME) {
11707c478bd9Sstevel@tonic-gate 			/* XXX another gem from the Broadcom driver :( */
11717c478bd9Sstevel@tonic-gate 			ap->state = ANEG_STATE_LINK_OK;
11727c478bd9Sstevel@tonic-gate 		}
11737c478bd9Sstevel@tonic-gate 		break;
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	case ANEG_STATE_LINK_OK:
11767c478bd9Sstevel@tonic-gate 		ap->flags |= (MR_AN_COMPLETE | MR_LINK_OK);
11777c478bd9Sstevel@tonic-gate 		ret = ANEG_DONE;
11787c478bd9Sstevel@tonic-gate 		break;
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	case ANEG_STATE_NEXT_PAGE_WAIT_INIT:
11817c478bd9Sstevel@tonic-gate 		/* ??? unimplemented */
11827c478bd9Sstevel@tonic-gate 		break;
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	case ANEG_STATE_NEXT_PAGE_WAIT:
11857c478bd9Sstevel@tonic-gate 		/* ??? unimplemented */
11867c478bd9Sstevel@tonic-gate 		break;
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	default:
11897c478bd9Sstevel@tonic-gate 		ret = ANEG_FAILED;
11907c478bd9Sstevel@tonic-gate 		break;
11917c478bd9Sstevel@tonic-gate 	};
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	return ret;
11947c478bd9Sstevel@tonic-gate }
11957c478bd9Sstevel@tonic-gate 
tg3_setup_fiber_phy(struct tg3 * tp)11967c478bd9Sstevel@tonic-gate static int tg3_setup_fiber_phy(struct tg3 *tp)
11977c478bd9Sstevel@tonic-gate {
11987c478bd9Sstevel@tonic-gate 	uint32_t orig_pause_cfg;
11997c478bd9Sstevel@tonic-gate 	uint16_t orig_active_speed;
12007c478bd9Sstevel@tonic-gate 	uint8_t orig_active_duplex;
12017c478bd9Sstevel@tonic-gate 	int current_link_up;
12027c478bd9Sstevel@tonic-gate 	int i;
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	orig_pause_cfg =
12057c478bd9Sstevel@tonic-gate 		(tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
12067c478bd9Sstevel@tonic-gate 				  TG3_FLAG_TX_PAUSE));
12077c478bd9Sstevel@tonic-gate 	orig_active_speed = tp->link_config.active_speed;
12087c478bd9Sstevel@tonic-gate 	orig_active_duplex = tp->link_config.active_duplex;
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 	tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
12117c478bd9Sstevel@tonic-gate 	tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
12127c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MODE, tp->mac_mode);
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	/* Reset when initting first time or we have a link. */
12157c478bd9Sstevel@tonic-gate 	if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
12167c478bd9Sstevel@tonic-gate 	    (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
12177c478bd9Sstevel@tonic-gate 		/* Set PLL lock range. */
12187c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x16, 0x8007);
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 		/* SW reset */
12217c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, MII_BMCR, BMCR_RESET);
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 		/* Wait for reset to complete. */
12247c478bd9Sstevel@tonic-gate 		mdelay(5);
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 		/* Config mode; select PMA/Ch 1 regs. */
12277c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x10, 0x8411);
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 		/* Enable auto-lock and comdet, select txclk for tx. */
12307c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x11, 0x0a10);
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x18, 0x00a0);
12337c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x16, 0x41ff);
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 		/* Assert and deassert POR. */
12367c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x13, 0x0400);
12377c478bd9Sstevel@tonic-gate 		udelay(40);
12387c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x13, 0x0000);
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x11, 0x0a50);
12417c478bd9Sstevel@tonic-gate 		udelay(40);
12427c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x11, 0x0a10);
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 		/* Wait for signal to stabilize */
12457c478bd9Sstevel@tonic-gate 		mdelay(150);
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 		/* Deselect the channel register so we can read the PHYID
12487c478bd9Sstevel@tonic-gate 		 * later.
12497c478bd9Sstevel@tonic-gate 		 */
12507c478bd9Sstevel@tonic-gate 		tg3_writephy(tp, 0x10, 0x8011);
12517c478bd9Sstevel@tonic-gate 	}
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	/* Disable link change interrupt.  */
12547c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_EVENT, 0);
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	current_link_up = 0;
12577c478bd9Sstevel@tonic-gate 	if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
12587c478bd9Sstevel@tonic-gate 		if (!(tp->tg3_flags & TG3_FLAG_GOT_SERDES_FLOWCTL)) {
12597c478bd9Sstevel@tonic-gate 			struct tg3_fiber_aneginfo aninfo;
12607c478bd9Sstevel@tonic-gate 			int status = ANEG_FAILED;
12617c478bd9Sstevel@tonic-gate 			unsigned int tick;
12627c478bd9Sstevel@tonic-gate 			uint32_t tmp;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 			memset(&aninfo, 0, sizeof(aninfo));
12657c478bd9Sstevel@tonic-gate 			aninfo.flags |= (MR_AN_ENABLE);
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 			tw32(MAC_TX_AUTO_NEG, 0);
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 			tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
12707c478bd9Sstevel@tonic-gate 			tw32_carefully(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 			tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 			aninfo.state = ANEG_STATE_UNKNOWN;
12757c478bd9Sstevel@tonic-gate 			aninfo.cur_time = 0;
12767c478bd9Sstevel@tonic-gate 			tick = 0;
12777c478bd9Sstevel@tonic-gate 			while (++tick < 195000) {
12787c478bd9Sstevel@tonic-gate 				status = tg3_fiber_aneg_smachine(tp, &aninfo);
12797c478bd9Sstevel@tonic-gate 				if (status == ANEG_DONE ||
12807c478bd9Sstevel@tonic-gate 				    status == ANEG_FAILED)
12817c478bd9Sstevel@tonic-gate 					break;
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 				udelay(1);
12847c478bd9Sstevel@tonic-gate 			}
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 			tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
12877c478bd9Sstevel@tonic-gate 			tw32_carefully(MAC_MODE, tp->mac_mode);
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 			if (status == ANEG_DONE &&
12907c478bd9Sstevel@tonic-gate 			    (aninfo.flags &
12917c478bd9Sstevel@tonic-gate 			     (MR_AN_COMPLETE | MR_LINK_OK |
12927c478bd9Sstevel@tonic-gate 			      MR_LP_ADV_FULL_DUPLEX))) {
12937c478bd9Sstevel@tonic-gate 				uint32_t local_adv, remote_adv;
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 				local_adv = ADVERTISE_PAUSE_CAP;
12967c478bd9Sstevel@tonic-gate 				remote_adv = 0;
12977c478bd9Sstevel@tonic-gate 				if (aninfo.flags & MR_LP_ADV_SYM_PAUSE)
12987c478bd9Sstevel@tonic-gate 					remote_adv |= LPA_PAUSE_CAP;
12997c478bd9Sstevel@tonic-gate 				if (aninfo.flags & MR_LP_ADV_ASYM_PAUSE)
13007c478bd9Sstevel@tonic-gate 					remote_adv |= LPA_PAUSE_ASYM;
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 				tg3_setup_flow_control(tp, local_adv, remote_adv);
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 				tp->tg3_flags |=
13057c478bd9Sstevel@tonic-gate 					TG3_FLAG_GOT_SERDES_FLOWCTL;
13067c478bd9Sstevel@tonic-gate 				current_link_up = 1;
13077c478bd9Sstevel@tonic-gate 			}
13087c478bd9Sstevel@tonic-gate 			for (i = 0; i < 60; i++) {
13097c478bd9Sstevel@tonic-gate 				udelay(20);
13107c478bd9Sstevel@tonic-gate 				tw32_carefully(MAC_STATUS,
13117c478bd9Sstevel@tonic-gate 					(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
13127c478bd9Sstevel@tonic-gate 				if ((tr32(MAC_STATUS) &
13137c478bd9Sstevel@tonic-gate 				     (MAC_STATUS_SYNC_CHANGED |
13147c478bd9Sstevel@tonic-gate 				      MAC_STATUS_CFG_CHANGED)) == 0)
13157c478bd9Sstevel@tonic-gate 					break;
13167c478bd9Sstevel@tonic-gate 			}
13177c478bd9Sstevel@tonic-gate 			if (current_link_up == 0 &&
13187c478bd9Sstevel@tonic-gate 			    (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
13197c478bd9Sstevel@tonic-gate 				current_link_up = 1;
13207c478bd9Sstevel@tonic-gate 			}
13217c478bd9Sstevel@tonic-gate 		} else {
13227c478bd9Sstevel@tonic-gate 			/* Forcing 1000FD link up. */
13237c478bd9Sstevel@tonic-gate 			current_link_up = 1;
13247c478bd9Sstevel@tonic-gate 		}
13257c478bd9Sstevel@tonic-gate 	}
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
13287c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MODE, tp->mac_mode);
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	tp->hw_status->status =
13317c478bd9Sstevel@tonic-gate 		(SD_STATUS_UPDATED |
13327c478bd9Sstevel@tonic-gate 		 (tp->hw_status->status & ~SD_STATUS_LINK_CHG));
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	for (i = 0; i < 100; i++) {
13357c478bd9Sstevel@tonic-gate 		udelay(20);
13367c478bd9Sstevel@tonic-gate 		tw32_carefully(MAC_STATUS,
13377c478bd9Sstevel@tonic-gate 			(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
13387c478bd9Sstevel@tonic-gate 		if ((tr32(MAC_STATUS) &
13397c478bd9Sstevel@tonic-gate 		     (MAC_STATUS_SYNC_CHANGED |
13407c478bd9Sstevel@tonic-gate 		      MAC_STATUS_CFG_CHANGED)) == 0)
13417c478bd9Sstevel@tonic-gate 			break;
13427c478bd9Sstevel@tonic-gate 	}
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0)
13457c478bd9Sstevel@tonic-gate 		current_link_up = 0;
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	if (current_link_up == 1) {
13487c478bd9Sstevel@tonic-gate 		tp->link_config.active_speed = SPEED_1000;
13497c478bd9Sstevel@tonic-gate 		tp->link_config.active_duplex = DUPLEX_FULL;
13507c478bd9Sstevel@tonic-gate 	} else {
13517c478bd9Sstevel@tonic-gate 		tp->link_config.active_speed = SPEED_INVALID;
13527c478bd9Sstevel@tonic-gate 		tp->link_config.active_duplex = DUPLEX_INVALID;
13537c478bd9Sstevel@tonic-gate 	}
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	if (current_link_up != tp->carrier_ok) {
13567c478bd9Sstevel@tonic-gate 		tp->carrier_ok = current_link_up;
13577c478bd9Sstevel@tonic-gate 		tg3_link_report(tp);
13587c478bd9Sstevel@tonic-gate 	} else {
13597c478bd9Sstevel@tonic-gate 		uint32_t now_pause_cfg =
13607c478bd9Sstevel@tonic-gate 			tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
13617c478bd9Sstevel@tonic-gate 					 TG3_FLAG_TX_PAUSE);
13627c478bd9Sstevel@tonic-gate 		if (orig_pause_cfg != now_pause_cfg ||
13637c478bd9Sstevel@tonic-gate 		    orig_active_speed != tp->link_config.active_speed ||
13647c478bd9Sstevel@tonic-gate 		    orig_active_duplex != tp->link_config.active_duplex)
13657c478bd9Sstevel@tonic-gate 			tg3_link_report(tp);
13667c478bd9Sstevel@tonic-gate 	}
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) {
13697c478bd9Sstevel@tonic-gate 		tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY);
13707c478bd9Sstevel@tonic-gate 		if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
13717c478bd9Sstevel@tonic-gate 			tw32_carefully(MAC_MODE, tp->mac_mode);
13727c478bd9Sstevel@tonic-gate 		}
13737c478bd9Sstevel@tonic-gate 	}
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	return 0;
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate #else
13787c478bd9Sstevel@tonic-gate #define tg3_setup_fiber_phy(TP) (-EINVAL)
13797c478bd9Sstevel@tonic-gate #endif /* SUPPORT_FIBER_PHY */
13807c478bd9Sstevel@tonic-gate 
tg3_setup_phy(struct tg3 * tp)13817c478bd9Sstevel@tonic-gate static int tg3_setup_phy(struct tg3 *tp)
13827c478bd9Sstevel@tonic-gate {
13837c478bd9Sstevel@tonic-gate 	int err;
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	if (tp->phy_id == PHY_ID_SERDES) {
13867c478bd9Sstevel@tonic-gate 		err = tg3_setup_fiber_phy(tp);
13877c478bd9Sstevel@tonic-gate 	} else {
13887c478bd9Sstevel@tonic-gate 		err = tg3_setup_copper_phy(tp);
13897c478bd9Sstevel@tonic-gate 	}
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 	if (tp->link_config.active_speed == SPEED_1000 &&
13927c478bd9Sstevel@tonic-gate 	    tp->link_config.active_duplex == DUPLEX_HALF)
13937c478bd9Sstevel@tonic-gate 		tw32(MAC_TX_LENGTHS,
13947c478bd9Sstevel@tonic-gate 		     ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
13957c478bd9Sstevel@tonic-gate 		      (6 << TX_LENGTHS_IPG_SHIFT) |
13967c478bd9Sstevel@tonic-gate 		      (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)));
13977c478bd9Sstevel@tonic-gate 	else
13987c478bd9Sstevel@tonic-gate 		tw32(MAC_TX_LENGTHS,
13997c478bd9Sstevel@tonic-gate 		     ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
14007c478bd9Sstevel@tonic-gate 		      (6 << TX_LENGTHS_IPG_SHIFT) |
14017c478bd9Sstevel@tonic-gate 		      (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	return err;
14047c478bd9Sstevel@tonic-gate }
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate #define MAX_WAIT_CNT 1000
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate /* To stop a block, clear the enable bit and poll till it
14107c478bd9Sstevel@tonic-gate  * clears.
14117c478bd9Sstevel@tonic-gate  */
tg3_stop_block(struct tg3 * tp,unsigned long ofs,uint32_t enable_bit)14127c478bd9Sstevel@tonic-gate static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, uint32_t enable_bit)
14137c478bd9Sstevel@tonic-gate {
14147c478bd9Sstevel@tonic-gate 	unsigned int i;
14157c478bd9Sstevel@tonic-gate 	uint32_t val;
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
14187c478bd9Sstevel@tonic-gate 		switch(ofs) {
14197c478bd9Sstevel@tonic-gate 		case RCVLSC_MODE:
14207c478bd9Sstevel@tonic-gate 		case DMAC_MODE:
14217c478bd9Sstevel@tonic-gate 		case MBFREE_MODE:
14227c478bd9Sstevel@tonic-gate 		case BUFMGR_MODE:
14237c478bd9Sstevel@tonic-gate 		case MEMARB_MODE:
14247c478bd9Sstevel@tonic-gate 			/* We can't enable/disable these bits of the
14257c478bd9Sstevel@tonic-gate 			 * 5705, just say success.
14267c478bd9Sstevel@tonic-gate 			 */
14277c478bd9Sstevel@tonic-gate 			return 0;
14287c478bd9Sstevel@tonic-gate 		default:
14297c478bd9Sstevel@tonic-gate 			break;
14307c478bd9Sstevel@tonic-gate 		}
14317c478bd9Sstevel@tonic-gate 	}
14327c478bd9Sstevel@tonic-gate 	val = tr32(ofs);
14337c478bd9Sstevel@tonic-gate 	val &= ~enable_bit;
14347c478bd9Sstevel@tonic-gate 	tw32(ofs, val);
14357c478bd9Sstevel@tonic-gate 	tr32(ofs);
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_WAIT_CNT; i++) {
14387c478bd9Sstevel@tonic-gate 		udelay(100);
14397c478bd9Sstevel@tonic-gate 		val = tr32(ofs);
14407c478bd9Sstevel@tonic-gate 		if ((val & enable_bit) == 0)
14417c478bd9Sstevel@tonic-gate 			break;
14427c478bd9Sstevel@tonic-gate 	}
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	if (i == MAX_WAIT_CNT) {
14457c478bd9Sstevel@tonic-gate 		printf("tg3_stop_block timed out, ofs=%lx enable_bit=%x\n",
14467c478bd9Sstevel@tonic-gate 		       ofs, enable_bit);
14477c478bd9Sstevel@tonic-gate 		return -ENODEV;
14487c478bd9Sstevel@tonic-gate 	}
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	return 0;
14517c478bd9Sstevel@tonic-gate }
14527c478bd9Sstevel@tonic-gate 
tg3_abort_hw(struct tg3 * tp)14537c478bd9Sstevel@tonic-gate static int tg3_abort_hw(struct tg3 *tp)
14547c478bd9Sstevel@tonic-gate {
14557c478bd9Sstevel@tonic-gate 	int i, err;
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	tg3_disable_ints(tp);
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	tp->rx_mode &= ~RX_MODE_ENABLE;
14607c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_RX_MODE, tp->rx_mode);
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	err  = tg3_stop_block(tp, RCVBDI_MODE,   RCVBDI_MODE_ENABLE);
14637c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, RCVLPC_MODE,   RCVLPC_MODE_ENABLE);
14647c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, RCVLSC_MODE,   RCVLSC_MODE_ENABLE);
14657c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, RCVDBDI_MODE,  RCVDBDI_MODE_ENABLE);
14667c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, RCVDCC_MODE,   RCVDCC_MODE_ENABLE);
14677c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, RCVCC_MODE,    RCVCC_MODE_ENABLE);
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, SNDBDS_MODE,   SNDBDS_MODE_ENABLE);
14707c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, SNDBDI_MODE,   SNDBDI_MODE_ENABLE);
14717c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
14727c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, RDMAC_MODE,    RDMAC_MODE_ENABLE);
14737c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
14747c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, SNDBDC_MODE,   SNDBDC_MODE_ENABLE);
14757c478bd9Sstevel@tonic-gate 	if (err)
14767c478bd9Sstevel@tonic-gate 		goto out;
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 	tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
14797c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_MODE, tp->mac_mode);
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	tp->tx_mode &= ~TX_MODE_ENABLE;
14827c478bd9Sstevel@tonic-gate 	tw32_carefully(MAC_TX_MODE, tp->tx_mode);
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_WAIT_CNT; i++) {
14857c478bd9Sstevel@tonic-gate 		udelay(100);
14867c478bd9Sstevel@tonic-gate 		if (!(tr32(MAC_TX_MODE) & TX_MODE_ENABLE))
14877c478bd9Sstevel@tonic-gate 			break;
14887c478bd9Sstevel@tonic-gate 	}
14897c478bd9Sstevel@tonic-gate 	if (i >= MAX_WAIT_CNT) {
14907c478bd9Sstevel@tonic-gate 		printf("tg3_abort_hw timed out TX_MODE_ENABLE will not clear MAC_TX_MODE=%x\n",
14917c478bd9Sstevel@tonic-gate 			tr32(MAC_TX_MODE));
14927c478bd9Sstevel@tonic-gate 		return -ENODEV;
14937c478bd9Sstevel@tonic-gate 	}
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	err  = tg3_stop_block(tp, HOSTCC_MODE, HOSTCC_MODE_ENABLE);
14967c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, WDMAC_MODE,  WDMAC_MODE_ENABLE);
14977c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, MBFREE_MODE, MBFREE_MODE_ENABLE);
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 	tw32(FTQ_RESET, 0xffffffff);
15007c478bd9Sstevel@tonic-gate 	tw32(FTQ_RESET, 0x00000000);
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE);
15037c478bd9Sstevel@tonic-gate 	err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE);
15047c478bd9Sstevel@tonic-gate 	if (err)
15057c478bd9Sstevel@tonic-gate 		goto out;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate out:
15107c478bd9Sstevel@tonic-gate 	return err;
15117c478bd9Sstevel@tonic-gate }
15127c478bd9Sstevel@tonic-gate 
tg3_chip_reset(struct tg3 * tp)15137c478bd9Sstevel@tonic-gate static void tg3_chip_reset(struct tg3 *tp)
15147c478bd9Sstevel@tonic-gate {
15157c478bd9Sstevel@tonic-gate 	uint32_t val;
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
15187c478bd9Sstevel@tonic-gate 		/* Force NVRAM to settle.
15197c478bd9Sstevel@tonic-gate 		 * This deals with a chip bug which can result in EEPROM
15207c478bd9Sstevel@tonic-gate 		 * corruption.
15217c478bd9Sstevel@tonic-gate 		 */
15227c478bd9Sstevel@tonic-gate 		if (tp->tg3_flags & TG3_FLAG_NVRAM) {
15237c478bd9Sstevel@tonic-gate 			int i;
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 			tw32(NVRAM_SWARB, SWARB_REQ_SET1);
15267c478bd9Sstevel@tonic-gate 			for (i = 0; i < 100000; i++) {
15277c478bd9Sstevel@tonic-gate 				if (tr32(NVRAM_SWARB) & SWARB_GNT1)
15287c478bd9Sstevel@tonic-gate 					break;
15297c478bd9Sstevel@tonic-gate 				udelay(10);
15307c478bd9Sstevel@tonic-gate 			}
15317c478bd9Sstevel@tonic-gate 		}
15327c478bd9Sstevel@tonic-gate 	}
15337c478bd9Sstevel@tonic-gate 	/* In Etherboot we don't need to worry about the 5701
15347c478bd9Sstevel@tonic-gate 	 * REG_WRITE_BUG because we do all register writes indirectly.
15357c478bd9Sstevel@tonic-gate 	 */
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	/* do the reset */
15387c478bd9Sstevel@tonic-gate 	val = GRC_MISC_CFG_CORECLK_RESET;
15397c478bd9Sstevel@tonic-gate 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
15407c478bd9Sstevel@tonic-gate 		val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
15417c478bd9Sstevel@tonic-gate 	tw32(GRC_MISC_CFG, val);
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 	/* Flush PCI posted writes.  The normal MMIO registers
15447c478bd9Sstevel@tonic-gate 	 * are inaccessible at this time so this is the only
15457c478bd9Sstevel@tonic-gate 	 * way to make this reliably.  I tried to use indirect
15467c478bd9Sstevel@tonic-gate 	 * register read/write but this upset some 5701 variants.
15477c478bd9Sstevel@tonic-gate 	 */
15487c478bd9Sstevel@tonic-gate 	pci_read_config_dword(tp->pdev, PCI_COMMAND, &val);
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	udelay(120);
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 	/* Re-enable indirect register accesses. */
15537c478bd9Sstevel@tonic-gate 	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
15547c478bd9Sstevel@tonic-gate 			       tp->misc_host_ctrl);
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 	/* Set MAX PCI retry to zero. */
15577c478bd9Sstevel@tonic-gate 	val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
15587c478bd9Sstevel@tonic-gate 	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
15597c478bd9Sstevel@tonic-gate 	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
15607c478bd9Sstevel@tonic-gate 		val |= PCISTATE_RETRY_SAME_DMA;
15617c478bd9Sstevel@tonic-gate 	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate