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

📄 bnx2.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	return ret;}static voidbnx2_enable_forced_2g5(struct bnx2 *bp){	u32 bmcr;	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))		return;	if (CHIP_NUM(bp) == CHIP_NUM_5709) {		u32 val;		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,			       MII_BNX2_BLK_ADDR_SERDES_DIG);		bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);		val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;		val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;		bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);	} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);		bmcr |= BCM5708S_BMCR_FORCE_2500;	}	if (bp->autoneg & AUTONEG_SPEED) {		bmcr &= ~BMCR_ANENABLE;		if (bp->req_duplex == DUPLEX_FULL)			bmcr |= BMCR_FULLDPLX;	}	bnx2_write_phy(bp, bp->mii_bmcr, bmcr);}static voidbnx2_disable_forced_2g5(struct bnx2 *bp){	u32 bmcr;	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))		return;	if (CHIP_NUM(bp) == CHIP_NUM_5709) {		u32 val;		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,			       MII_BNX2_BLK_ADDR_SERDES_DIG);		bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);		val &= ~MII_BNX2_SD_MISC1_FORCE;		bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);	} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);		bmcr &= ~BCM5708S_BMCR_FORCE_2500;	}	if (bp->autoneg & AUTONEG_SPEED)		bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;	bnx2_write_phy(bp, bp->mii_bmcr, bmcr);}static intbnx2_set_link(struct bnx2 *bp){	u32 bmsr;	u8 link_up;	if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {		bp->link_up = 1;		return 0;	}	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)		return 0;	link_up = bp->link_up;	bnx2_enable_bmsr1(bp);	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);	bnx2_disable_bmsr1(bp);	if ((bp->phy_flags & PHY_SERDES_FLAG) &&	    (CHIP_NUM(bp) == CHIP_NUM_5706)) {		u32 val;		val = REG_RD(bp, BNX2_EMAC_STATUS);		if (val & BNX2_EMAC_STATUS_LINK)			bmsr |= BMSR_LSTATUS;		else			bmsr &= ~BMSR_LSTATUS;	}	if (bmsr & BMSR_LSTATUS) {		bp->link_up = 1;		if (bp->phy_flags & PHY_SERDES_FLAG) {			if (CHIP_NUM(bp) == CHIP_NUM_5706)				bnx2_5706s_linkup(bp);			else if (CHIP_NUM(bp) == CHIP_NUM_5708)				bnx2_5708s_linkup(bp);			else if (CHIP_NUM(bp) == CHIP_NUM_5709)				bnx2_5709s_linkup(bp);		}		else {			bnx2_copper_linkup(bp);		}		bnx2_resolve_flow_ctrl(bp);	}	else {		if ((bp->phy_flags & PHY_SERDES_FLAG) &&		    (bp->autoneg & AUTONEG_SPEED))			bnx2_disable_forced_2g5(bp);		bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;		bp->link_up = 0;	}	if (bp->link_up != link_up) {		bnx2_report_link(bp);	}	bnx2_set_mac_link(bp);	return 0;}static intbnx2_reset_phy(struct bnx2 *bp){	int i;	u32 reg;        bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);#define PHY_RESET_MAX_WAIT 100	for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {		udelay(10);		bnx2_read_phy(bp, bp->mii_bmcr, &reg);		if (!(reg & BMCR_RESET)) {			udelay(20);			break;		}	}	if (i == PHY_RESET_MAX_WAIT) {		return -EBUSY;	}	return 0;}static u32bnx2_phy_get_pause_adv(struct bnx2 *bp){	u32 adv = 0;	if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==		(FLOW_CTRL_RX | FLOW_CTRL_TX)) {		if (bp->phy_flags & PHY_SERDES_FLAG) {			adv = ADVERTISE_1000XPAUSE;		}		else {			adv = ADVERTISE_PAUSE_CAP;		}	}	else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {		if (bp->phy_flags & PHY_SERDES_FLAG) {			adv = ADVERTISE_1000XPSE_ASYM;		}		else {			adv = ADVERTISE_PAUSE_ASYM;		}	}	else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {		if (bp->phy_flags & PHY_SERDES_FLAG) {			adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;		}		else {			adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;		}	}	return adv;}static int bnx2_fw_sync(struct bnx2 *, u32, int);static intbnx2_setup_remote_phy(struct bnx2 *bp, u8 port){	u32 speed_arg = 0, pause_adv;	pause_adv = bnx2_phy_get_pause_adv(bp);	if (bp->autoneg & AUTONEG_SPEED) {		speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;		if (bp->advertising & ADVERTISED_10baseT_Half)			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;		if (bp->advertising & ADVERTISED_10baseT_Full)			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;		if (bp->advertising & ADVERTISED_100baseT_Half)			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;		if (bp->advertising & ADVERTISED_100baseT_Full)			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;		if (bp->advertising & ADVERTISED_1000baseT_Full)			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;		if (bp->advertising & ADVERTISED_2500baseX_Full)			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;	} else {		if (bp->req_line_speed == SPEED_2500)			speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;		else if (bp->req_line_speed == SPEED_1000)			speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;		else if (bp->req_line_speed == SPEED_100) {			if (bp->req_duplex == DUPLEX_FULL)				speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;			else				speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;		} else if (bp->req_line_speed == SPEED_10) {			if (bp->req_duplex == DUPLEX_FULL)				speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;			else				speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;		}	}	if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))		speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;	if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_1000XPSE_ASYM))		speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;	if (port == PORT_TP)		speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |			     BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;	REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB_ARG0, speed_arg);	spin_unlock_bh(&bp->phy_lock);	bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0);	spin_lock_bh(&bp->phy_lock);	return 0;}static intbnx2_setup_serdes_phy(struct bnx2 *bp, u8 port){	u32 adv, bmcr;	u32 new_adv = 0;	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)		return (bnx2_setup_remote_phy(bp, port));	if (!(bp->autoneg & AUTONEG_SPEED)) {		u32 new_bmcr;		int force_link_down = 0;		if (bp->req_line_speed == SPEED_2500) {			if (!bnx2_test_and_enable_2g5(bp))				force_link_down = 1;		} else if (bp->req_line_speed == SPEED_1000) {			if (bnx2_test_and_disable_2g5(bp))				force_link_down = 1;		}		bnx2_read_phy(bp, bp->mii_adv, &adv);		adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);		new_bmcr = bmcr & ~BMCR_ANENABLE;		new_bmcr |= BMCR_SPEED1000;		if (CHIP_NUM(bp) == CHIP_NUM_5709) {			if (bp->req_line_speed == SPEED_2500)				bnx2_enable_forced_2g5(bp);			else if (bp->req_line_speed == SPEED_1000) {				bnx2_disable_forced_2g5(bp);				new_bmcr &= ~0x2000;			}		} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {			if (bp->req_line_speed == SPEED_2500)				new_bmcr |= BCM5708S_BMCR_FORCE_2500;			else				new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;		}		if (bp->req_duplex == DUPLEX_FULL) {			adv |= ADVERTISE_1000XFULL;			new_bmcr |= BMCR_FULLDPLX;		}		else {			adv |= ADVERTISE_1000XHALF;			new_bmcr &= ~BMCR_FULLDPLX;		}		if ((new_bmcr != bmcr) || (force_link_down)) {			/* Force a link down visible on the other side */			if (bp->link_up) {				bnx2_write_phy(bp, bp->mii_adv, adv &					       ~(ADVERTISE_1000XFULL |						 ADVERTISE_1000XHALF));				bnx2_write_phy(bp, bp->mii_bmcr, bmcr |					BMCR_ANRESTART | BMCR_ANENABLE);				bp->link_up = 0;				netif_carrier_off(bp->dev);				bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);				bnx2_report_link(bp);			}			bnx2_write_phy(bp, bp->mii_adv, adv);			bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);		} else {			bnx2_resolve_flow_ctrl(bp);			bnx2_set_mac_link(bp);		}		return 0;	}	bnx2_test_and_enable_2g5(bp);	if (bp->advertising & ADVERTISED_1000baseT_Full)		new_adv |= ADVERTISE_1000XFULL;	new_adv |= bnx2_phy_get_pause_adv(bp);	bnx2_read_phy(bp, bp->mii_adv, &adv);	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);	bp->serdes_an_pending = 0;	if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {		/* Force a link down visible on the other side */		if (bp->link_up) {			bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);			spin_unlock_bh(&bp->phy_lock);			msleep(20);			spin_lock_bh(&bp->phy_lock);		}		bnx2_write_phy(bp, bp->mii_adv, new_adv);		bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |			BMCR_ANENABLE);		/* Speed up link-up time when the link partner		 * does not autonegotiate which is very common		 * in blade servers. Some blade servers use		 * IPMI for kerboard input and it's important		 * to minimize link disruptions. Autoneg. involves		 * exchanging base pages plus 3 next pages and		 * normally completes in about 120 msec.		 */		bp->current_interval = SERDES_AN_TIMEOUT;		bp->serdes_an_pending = 1;		mod_timer(&bp->timer, jiffies + bp->current_interval);	} else {		bnx2_resolve_flow_ctrl(bp);		bnx2_set_mac_link(bp);	}	return 0;}#define ETHTOOL_ALL_FIBRE_SPEED						\	(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ?			\		(ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\		(ADVERTISED_1000baseT_Full)#define ETHTOOL_ALL_COPPER_SPEED					\	(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |		\	ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |		\	ADVERTISED_1000baseT_Full)#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \	ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)static voidbnx2_set_default_remote_link(struct bnx2 *bp){	u32 link;	if (bp->phy_port == PORT_TP)		link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_COPPER_LINK);	else		link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_SERDES_LINK);	if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {		bp->req_line_speed = 0;		bp->autoneg |= AUTONEG_SPEED;		bp->advertising = ADVERTISED_Autoneg;		if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)			bp->advertising |= ADVERTISED_10baseT_Half;		if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)			bp->advertising |= ADVERTISED_10baseT_Full;		if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)			bp->advertising |= ADVERTISED_100baseT_Half;		if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)			bp->advertising |= ADVERTISED_100baseT_Full;		if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)			bp->advertising |= ADVERTISED_1000baseT_Full;		if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)			bp->advertising |= ADVERTISED_2500baseX_Full;	} else {		bp->autoneg = 0;		bp->advertising = 0;		bp->req_duplex = DUPLEX_FULL;		if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {			bp->req_line_speed = SPEED_10;			if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)				bp->req_duplex = DUPLEX_HALF;		}		if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {			bp->req_line_speed = SPEED_100;			if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)				bp->req_duplex = DUPLEX_HALF;		}		if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)			bp->req_line_speed = SPEED_1000;		if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)			bp->req_line_speed = SPEED_2500;	}}static voidbnx2_set_default_link(struct bnx2 *bp){	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)		return bnx2_set_default_remote_link(bp);	bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;	bp->req_line_speed = 0;	if (bp->phy_flags & PHY_SERDES_FLAG) {		u32 reg;		bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;		reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);		reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;		if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {			bp->autoneg = 0;			bp->req_line_speed = bp->line_speed = SPEED_1000;			bp->req_duplex = DUPLEX_FULL;		}	} else		bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;}static voidbnx2_send_heart_beat(struct bnx2 *bp){	u32 msg;	u32 addr;	spin_lock(&bp->indirect_lock);	msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);	addr = bp->shmem_base + BNX2_DRV_PULSE_MB;	REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);	REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);	spin_unlock(&bp->indirect_lock);}static voidbnx2_remote_phy_event(struct bnx2 *bp){	u32 msg;	u8 link_up = bp->link_up;	u8 old_port;	msg = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);	if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)		bnx2_send_heart_beat(bp);	msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;	if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)		bp->link_up = 0;	else {		u32 speed;		bp->link_up = 1;		speed = msg & BNX2_LINK_STATUS_SPEED_MASK;		bp->duplex = DUPLEX_FULL;		switch (speed) {			case BNX2_LINK_STATUS_10HALF:				bp->duplex = DUPLEX_HALF;			case BNX2_LINK_STATUS_10FULL:				bp->line_speed = SPEED_10;				break;			case BNX2_LINK_STATUS_100HALF:				bp->duplex = DUPLEX_HALF;			case BNX2_LINK_STATUS_100BASE_T4:			case BNX2_LINK_STATUS_100FULL:				bp->line_speed = SPEED_100;				break;			case BNX2_LINK_STATUS_1000HALF:				bp->duplex = DUPLEX_HALF;			case BNX2_LINK_STATUS_1000FULL:				bp->line_speed = SPEED_1000;				break;			case BNX2_LINK_STATUS_2500HALF:				bp->duplex = DUPLEX_HALF;			case BNX2_LINK_STATUS_2500FULL:				bp->line_speed = SPEED_2500;				break;			default:				bp->line_speed = 0;				break;		}		spin_lock(&bp->phy_lock);		bp->flow_ctrl = 0;		if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=		    (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {			if (bp->duplex == DUPLEX_FULL)				bp->flow_ctrl = bp->req_flow_ctrl;		} else {			if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)

⌨️ 快捷键说明

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