⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tg3.c

📁 linux下从网卡远程启动
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: tg3.c,v 1.5 2003/03/19 21:26:20 gbaum Exp $ * tg3.c: Broadcom Tigon3 ethernet driver. * * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@mandrakesoft.com) * Copyright (C) 2003 Eric Biederman (ebiederman@lnxi.com)  [etherboot port] *//* 11-13-2003	timlegge	Fix Issue with NetGear GA302T  * 11-18-2003   ebiederm        Generalize NetGear Fix to what the code was supposed to be. */#include "etherboot.h"#include "nic.h"#include "pci.h"#include "timer.h"#include "string.h"#include "tg3.h"#define SUPPORT_COPPER_PHY  1#define SUPPORT_FIBER_PHY   1#define SUPPORT_LINK_REPORT 1#define SUPPORT_PARTNO_STR  1#define SUPPORT_PHY_STR     1struct tg3 tg3;/* Dummy defines for error handling */#define EBUSY  1#define ENODEV 2#define EINVAL 3#define ENOMEM 4/* These numbers seem to be hard coded in the NIC firmware somehow. * You can't change the ring sizes, but you can change where you place * them in the NIC onboard memory. */#define TG3_RX_RING_SIZE		512#define TG3_DEF_RX_RING_PENDING		20	/* RX_RING_PENDING seems to be o.k. at 20 and 200 */#define TG3_RX_RCB_RING_SIZE	1024/*	(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ? \	 512 : 1024) */ #define TG3_TX_RING_SIZE		512#define TG3_DEF_TX_RING_PENDING		(TG3_TX_RING_SIZE - 1)#define TG3_RX_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_RING_SIZE)#define TG3_RX_RCB_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_RCB_RING_SIZE)#define TG3_TX_RING_BYTES	(sizeof(struct tg3_tx_buffer_desc) * TG3_TX_RING_SIZE)#define NEXT_TX(N)		(((N) + 1) & (TG3_TX_RING_SIZE - 1))#define PREV_TX(N)		(((N) - 1) & (TG3_TX_RING_SIZE - 1))#define RX_PKT_BUF_SZ		(1536 + 2 + 64)static struct bss {	struct tg3_rx_buffer_desc rx_std[TG3_RX_RING_SIZE];	struct tg3_rx_buffer_desc rx_rcb[TG3_RX_RCB_RING_SIZE];	struct tg3_tx_buffer_desc tx_ring[TG3_TX_RING_SIZE];	struct tg3_hw_status      hw_status;	struct tg3_hw_stats       hw_stats;	unsigned char             rx_bufs[TG3_DEF_RX_RING_PENDING][RX_PKT_BUF_SZ];} tg3_bss;/** * pci_save_state - save the PCI configuration space of a device before suspending * @dev: - PCI device that we're dealing with * @buffer: - buffer to hold config space context * * @buffer must be large enough to hold the entire PCI 2.2 config space  * (>= 64 bytes). */static int pci_save_state(struct pci_device *dev, uint32_t *buffer){	int i;	for (i = 0; i < 16; i++)		pci_read_config_dword(dev, i * 4,&buffer[i]);	return 0;}/**  * pci_restore_state - Restore the saved state of a PCI device * @dev: - PCI device that we're dealing with * @buffer: - saved PCI config space * */static int pci_restore_state(struct pci_device *dev, uint32_t *buffer){	int i;	for (i = 0; i < 16; i++)		pci_write_config_dword(dev,i * 4, buffer[i]);	return 0;}static void tg3_write_indirect_reg32(uint32_t off, uint32_t val){	pci_write_config_dword(tg3.pdev, TG3PCI_REG_BASE_ADDR, off);	pci_write_config_dword(tg3.pdev, TG3PCI_REG_DATA, val);}#define tw32(reg,val)		tg3_write_indirect_reg32((reg),(val))#define tw32_mailbox(reg, val)	writel(((val) & 0xffffffff), tg3.regs + (reg))#define tw16(reg,val)		writew(((val) & 0xffff), tg3.regs + (reg))#define tw8(reg,val)		writeb(((val) & 0xff), tg3.regs + (reg))#define tr32(reg)		readl(tg3.regs + (reg))#define tr16(reg)		readw(tg3.regs + (reg))#define tr8(reg)		readb(tg3.regs + (reg))static void tw32_carefully(uint32_t reg, uint32_t val){	tw32(reg, val);	tr32(reg);	udelay(100);}static void tw32_mailbox2(uint32_t reg, uint32_t val){	tw32_mailbox(reg, val);	tr32(reg);}static void tg3_write_mem(uint32_t off, uint32_t val){	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_DATA, val);	/* Always leave this as zero. */	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);}static void tg3_read_mem(uint32_t off, uint32_t *val){	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);	pci_read_config_dword(tg3.pdev, TG3PCI_MEM_WIN_DATA, val);	/* Always leave this as zero. */	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);}static void tg3_disable_ints(struct tg3 *tp){	tw32(TG3PCI_MISC_HOST_CTRL,	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));	tw32_mailbox2(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);}static void tg3_switch_clocks(struct tg3 *tp){	uint32_t orig_clock_ctrl, clock_ctrl;	clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);	orig_clock_ctrl = clock_ctrl;	clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE | 0x1f);	tp->pci_clock_ctrl = clock_ctrl;		if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&		(orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE)!=0) {		tw32_carefully(TG3PCI_CLOCK_CTRL, 			clock_ctrl | (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK));		tw32_carefully(TG3PCI_CLOCK_CTRL, 			clock_ctrl | (CLOCK_CTRL_ALTCLK));	}	tw32_carefully(TG3PCI_CLOCK_CTRL, clock_ctrl);}#define PHY_BUSY_LOOPS	5000static int tg3_readphy(struct tg3 *tp, int reg, uint32_t *val){	uint32_t frame_val;	int loops, ret;	tw32_carefully(MAC_MI_MODE, tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL);	*val = 0xffffffff;	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &		      MI_COM_PHY_ADDR_MASK);	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &		      MI_COM_REG_ADDR_MASK);	frame_val |= (MI_COM_CMD_READ | MI_COM_START);		tw32_carefully(MAC_MI_COM, frame_val);	loops = PHY_BUSY_LOOPS;	while (loops-- > 0) {		udelay(10);		frame_val = tr32(MAC_MI_COM);		if ((frame_val & MI_COM_BUSY) == 0) {			udelay(5);			frame_val = tr32(MAC_MI_COM);			break;		}	}	ret = -EBUSY;	if (loops > 0) {		*val = frame_val & MI_COM_DATA_MASK;		ret = 0;	}	tw32_carefully(MAC_MI_MODE, tp->mi_mode);	return ret;}static int tg3_writephy(struct tg3 *tp, int reg, uint32_t val){	uint32_t frame_val;	int loops, ret;	tw32_carefully(MAC_MI_MODE, tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL);	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &		      MI_COM_PHY_ADDR_MASK);	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &		      MI_COM_REG_ADDR_MASK);	frame_val |= (val & MI_COM_DATA_MASK);	frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);		tw32_carefully(MAC_MI_COM, frame_val);	loops = PHY_BUSY_LOOPS;	while (loops-- > 0) {		udelay(10);		frame_val = tr32(MAC_MI_COM);		if ((frame_val & MI_COM_BUSY) == 0) {			udelay(5);			frame_val = tr32(MAC_MI_COM);			break;		}	}	ret = -EBUSY;	if (loops > 0)		ret = 0;	tw32_carefully(MAC_MI_MODE, tp->mi_mode);	return ret;}static int tg3_writedsp(struct tg3 *tp, uint16_t addr, uint16_t val){	int err;	err  = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, addr);	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);	return err;}static void tg3_phy_set_wirespeed(struct tg3 *tp){	uint32_t val;	if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)		return;	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);	tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);	tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));}static int tg3_bmcr_reset(struct tg3 *tp){	uint32_t phy_control;	int limit, err;	/* OK, reset it, and poll the BMCR_RESET bit until it	 * clears or we time out.	 */	phy_control = BMCR_RESET;	err = tg3_writephy(tp, MII_BMCR, phy_control);	if (err != 0)		return -EBUSY;	limit = 5000;	while (limit--) {		err = tg3_readphy(tp, MII_BMCR, &phy_control);		if (err != 0)			return -EBUSY;		if ((phy_control & BMCR_RESET) == 0) {			udelay(40);			break;		}		udelay(10);	}	if (limit <= 0)		return -EBUSY;	return 0;}static int tg3_wait_macro_done(struct tg3 *tp){	int limit = 100;	while (limit--) {		uint32_t tmp32;		tg3_readphy(tp, 0x16, &tmp32);		if ((tmp32 & 0x1000) == 0)			break;	}	if (limit <= 0)		return -EBUSY;	return 0;}static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp){	static const uint32_t test_pat[4][6] = {	{ 0x00005555, 0x00000005, 0x00002aaa, 0x0000000a, 0x00003456, 0x00000003 },	{ 0x00002aaa, 0x0000000a, 0x00003333, 0x00000003, 0x0000789a, 0x00000005 },	{ 0x00005a5a, 0x00000005, 0x00002a6a, 0x0000000a, 0x00001bcd, 0x00000003 },	{ 0x00002a5a, 0x0000000a, 0x000033c3, 0x00000003, 0x00002ef1, 0x00000005 }	};	int chan;	for (chan = 0; chan < 4; chan++) {		int i;		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,			(chan * 0x2000) | 0x0200);		tg3_writephy(tp, 0x16, 0x0002);		for (i = 0; i < 6; i++)			tg3_writephy(tp, MII_TG3_DSP_RW_PORT,				test_pat[chan][i]);		tg3_writephy(tp, 0x16, 0x0202);		if (tg3_wait_macro_done(tp)) {			*resetp = 1;			return -EBUSY;		}		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,			     (chan * 0x2000) | 0x0200);		tg3_writephy(tp, 0x16, 0x0082);		if (tg3_wait_macro_done(tp)) {			*resetp = 1;			return -EBUSY;		}		tg3_writephy(tp, 0x16, 0x0802);		if (tg3_wait_macro_done(tp)) {			*resetp = 1;			return -EBUSY;		}		for (i = 0; i < 6; i += 2) {			uint32_t low, high;			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low);			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high);			if (tg3_wait_macro_done(tp)) {				*resetp = 1;				return -EBUSY;			}			low &= 0x7fff;			high &= 0x000f;			if (low != test_pat[chan][i] ||			    high != test_pat[chan][i+1]) {				tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000b);				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4001);				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4005);				return -EBUSY;			}		}	}	return 0;}static int tg3_phy_reset_chanpat(struct tg3 *tp){	int chan;	for (chan = 0; chan < 4; chan++) {		int i;		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,			     (chan * 0x2000) | 0x0200);		tg3_writephy(tp, 0x16, 0x0002);		for (i = 0; i < 6; i++)			tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);		tg3_writephy(tp, 0x16, 0x0202);		if (tg3_wait_macro_done(tp))			return -EBUSY;	}	return 0;}static int tg3_phy_reset_5703_4_5(struct tg3 *tp){	uint32_t reg32, phy9_orig;	int retries, do_phy_reset, err;	retries = 10;	do_phy_reset = 1;	do {		if (do_phy_reset) {			err = tg3_bmcr_reset(tp);			if (err)				return err;			do_phy_reset = 0;		}				/* Disable transmitter and interrupt.  */		tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);		reg32 |= 0x3000;		tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);		/* Set full-duplex, 1000 mbps.  */		tg3_writephy(tp, MII_BMCR,			BMCR_FULLDPLX | TG3_BMCR_SPEED1000);		/* Set to master mode.  */		tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig);		tg3_writephy(tp, MII_TG3_CTRL,			(MII_TG3_CTRL_AS_MASTER |				MII_TG3_CTRL_ENABLE_AS_MASTER));		/* Enable SM_DSP_CLOCK and 6dB.  */		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);		/* Block the PHY control access.  */		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0800);		err = tg3_phy_write_and_check_testpat(tp, &do_phy_reset);		if (!err)			break;	} while (--retries);	err = tg3_phy_reset_chanpat(tp);	if (err)		return err;	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);	tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0000);	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);	tg3_writephy(tp, 0x16, 0x0000);	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);	tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);	tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);	reg32 &= ~0x3000;	tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);	return err;}/* This will reset the tigon3 PHY if there is no valid * link. */static int tg3_phy_reset(struct tg3 *tp){	uint32_t phy_status;	int err;	err  = tg3_readphy(tp, MII_BMSR, &phy_status);	err |= tg3_readphy(tp, MII_BMSR, &phy_status);	if (err != 0)		return -EBUSY;	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {		err = tg3_phy_reset_5703_4_5(tp);		if (err)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -