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

📄 bnx2.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				bp->flow_ctrl |= FLOW_CTRL_TX;			if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)				bp->flow_ctrl |= FLOW_CTRL_RX;		}		old_port = bp->phy_port;		if (msg & BNX2_LINK_STATUS_SERDES_LINK)			bp->phy_port = PORT_FIBRE;		else			bp->phy_port = PORT_TP;		if (old_port != bp->phy_port)			bnx2_set_default_link(bp);		spin_unlock(&bp->phy_lock);	}	if (bp->link_up != link_up)		bnx2_report_link(bp);	bnx2_set_mac_link(bp);}static intbnx2_set_remote_link(struct bnx2 *bp){	u32 evt_code;	evt_code = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_EVT_CODE_MB);	switch (evt_code) {		case BNX2_FW_EVT_CODE_LINK_EVENT:			bnx2_remote_phy_event(bp);			break;		case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:		default:			bnx2_send_heart_beat(bp);			break;	}	return 0;}static intbnx2_setup_copper_phy(struct bnx2 *bp){	u32 bmcr;	u32 new_bmcr;	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);	if (bp->autoneg & AUTONEG_SPEED) {		u32 adv_reg, adv1000_reg;		u32 new_adv_reg = 0;		u32 new_adv1000_reg = 0;		bnx2_read_phy(bp, bp->mii_adv, &adv_reg);		adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |			ADVERTISE_PAUSE_ASYM);		bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);		adv1000_reg &= PHY_ALL_1000_SPEED;		if (bp->advertising & ADVERTISED_10baseT_Half)			new_adv_reg |= ADVERTISE_10HALF;		if (bp->advertising & ADVERTISED_10baseT_Full)			new_adv_reg |= ADVERTISE_10FULL;		if (bp->advertising & ADVERTISED_100baseT_Half)			new_adv_reg |= ADVERTISE_100HALF;		if (bp->advertising & ADVERTISED_100baseT_Full)			new_adv_reg |= ADVERTISE_100FULL;		if (bp->advertising & ADVERTISED_1000baseT_Full)			new_adv1000_reg |= ADVERTISE_1000FULL;		new_adv_reg |= ADVERTISE_CSMA;		new_adv_reg |= bnx2_phy_get_pause_adv(bp);		if ((adv1000_reg != new_adv1000_reg) ||			(adv_reg != new_adv_reg) ||			((bmcr & BMCR_ANENABLE) == 0)) {			bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);			bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);			bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |				BMCR_ANENABLE);		}		else if (bp->link_up) {			/* Flow ctrl may have changed from auto to forced */			/* or vice-versa. */			bnx2_resolve_flow_ctrl(bp);			bnx2_set_mac_link(bp);		}		return 0;	}	new_bmcr = 0;	if (bp->req_line_speed == SPEED_100) {		new_bmcr |= BMCR_SPEED100;	}	if (bp->req_duplex == DUPLEX_FULL) {		new_bmcr |= BMCR_FULLDPLX;	}	if (new_bmcr != bmcr) {		u32 bmsr;		bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);		bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);		if (bmsr & BMSR_LSTATUS) {			/* Force link down */			bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);			spin_unlock_bh(&bp->phy_lock);			msleep(50);			spin_lock_bh(&bp->phy_lock);			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);		}		bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);		/* Normally, the new speed is setup after the link has		 * gone down and up again. In some cases, link will not go		 * down so we need to set up the new speed here.		 */		if (bmsr & BMSR_LSTATUS) {			bp->line_speed = bp->req_line_speed;			bp->duplex = bp->req_duplex;			bnx2_resolve_flow_ctrl(bp);			bnx2_set_mac_link(bp);		}	} else {		bnx2_resolve_flow_ctrl(bp);		bnx2_set_mac_link(bp);	}	return 0;}static intbnx2_setup_phy(struct bnx2 *bp, u8 port){	if (bp->loopback == MAC_LOOPBACK)		return 0;	if (bp->phy_flags & PHY_SERDES_FLAG) {		return (bnx2_setup_serdes_phy(bp, port));	}	else {		return (bnx2_setup_copper_phy(bp));	}}static intbnx2_init_5709s_phy(struct bnx2 *bp){	u32 val;	bp->mii_bmcr = MII_BMCR + 0x10;	bp->mii_bmsr = MII_BMSR + 0x10;	bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;	bp->mii_adv = MII_ADVERTISE + 0x10;	bp->mii_lpa = MII_LPA + 0x10;	bp->mii_up1 = MII_BNX2_OVER1G_UP1;	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);	bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);	bnx2_reset_phy(bp);	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);	bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);	val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;	val |= MII_BNX2_SD_1000XCTL1_FIBER;	bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);	bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);	if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)		val |= BCM5708S_UP1_2G5;	else		val &= ~BCM5708S_UP1_2G5;	bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);	bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);	val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;	bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);	val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |	      MII_BNX2_CL73_BAM_NP_AFT_BP_EN;	bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);	return 0;}static intbnx2_init_5708s_phy(struct bnx2 *bp){	u32 val;	bnx2_reset_phy(bp);	bp->mii_up1 = BCM5708S_UP1;	bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);	bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);	bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);	bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);	val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;	bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);	bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);	val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;	bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);	if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {		bnx2_read_phy(bp, BCM5708S_UP1, &val);		val |= BCM5708S_UP1_2G5;		bnx2_write_phy(bp, BCM5708S_UP1, val);	}	if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||	    (CHIP_ID(bp) == CHIP_ID_5708_B0) ||	    (CHIP_ID(bp) == CHIP_ID_5708_B1)) {		/* increase tx signal amplitude */		bnx2_write_phy(bp, BCM5708S_BLK_ADDR,			       BCM5708S_BLK_ADDR_TX_MISC);		bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);		val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;		bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);		bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);	}	val = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG) &	      BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;	if (val) {		u32 is_backplane;		is_backplane = REG_RD_IND(bp, bp->shmem_base +					  BNX2_SHARED_HW_CFG_CONFIG);		if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {			bnx2_write_phy(bp, BCM5708S_BLK_ADDR,				       BCM5708S_BLK_ADDR_TX_MISC);			bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);			bnx2_write_phy(bp, BCM5708S_BLK_ADDR,				       BCM5708S_BLK_ADDR_DIG);		}	}	return 0;}static intbnx2_init_5706s_phy(struct bnx2 *bp){	bnx2_reset_phy(bp);	bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;	if (CHIP_NUM(bp) == CHIP_NUM_5706)        	REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);	if (bp->dev->mtu > 1500) {		u32 val;		/* Set extended packet length bit */		bnx2_write_phy(bp, 0x18, 0x7);		bnx2_read_phy(bp, 0x18, &val);		bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);		bnx2_write_phy(bp, 0x1c, 0x6c00);		bnx2_read_phy(bp, 0x1c, &val);		bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);	}	else {		u32 val;		bnx2_write_phy(bp, 0x18, 0x7);		bnx2_read_phy(bp, 0x18, &val);		bnx2_write_phy(bp, 0x18, val & ~0x4007);		bnx2_write_phy(bp, 0x1c, 0x6c00);		bnx2_read_phy(bp, 0x1c, &val);		bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);	}	return 0;}static intbnx2_init_copper_phy(struct bnx2 *bp){	u32 val;	bnx2_reset_phy(bp);	if (bp->phy_flags & PHY_CRC_FIX_FLAG) {		bnx2_write_phy(bp, 0x18, 0x0c00);		bnx2_write_phy(bp, 0x17, 0x000a);		bnx2_write_phy(bp, 0x15, 0x310b);		bnx2_write_phy(bp, 0x17, 0x201f);		bnx2_write_phy(bp, 0x15, 0x9506);		bnx2_write_phy(bp, 0x17, 0x401f);		bnx2_write_phy(bp, 0x15, 0x14e2);		bnx2_write_phy(bp, 0x18, 0x0400);	}	if (bp->phy_flags & PHY_DIS_EARLY_DAC_FLAG) {		bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,			       MII_BNX2_DSP_EXPAND_REG | 0x8);		bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);		val &= ~(1 << 8);		bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);	}	if (bp->dev->mtu > 1500) {		/* Set extended packet length bit */		bnx2_write_phy(bp, 0x18, 0x7);		bnx2_read_phy(bp, 0x18, &val);		bnx2_write_phy(bp, 0x18, val | 0x4000);		bnx2_read_phy(bp, 0x10, &val);		bnx2_write_phy(bp, 0x10, val | 0x1);	}	else {		bnx2_write_phy(bp, 0x18, 0x7);		bnx2_read_phy(bp, 0x18, &val);		bnx2_write_phy(bp, 0x18, val & ~0x4007);		bnx2_read_phy(bp, 0x10, &val);		bnx2_write_phy(bp, 0x10, val & ~0x1);	}	/* ethernet@wirespeed */	bnx2_write_phy(bp, 0x18, 0x7007);	bnx2_read_phy(bp, 0x18, &val);	bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));	return 0;}static intbnx2_init_phy(struct bnx2 *bp){	u32 val;	int rc = 0;	bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG;	bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG;	bp->mii_bmcr = MII_BMCR;	bp->mii_bmsr = MII_BMSR;	bp->mii_bmsr1 = MII_BMSR;	bp->mii_adv = MII_ADVERTISE;	bp->mii_lpa = MII_LPA;        REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)		goto setup_phy;	bnx2_read_phy(bp, MII_PHYSID1, &val);	bp->phy_id = val << 16;	bnx2_read_phy(bp, MII_PHYSID2, &val);	bp->phy_id |= val & 0xffff;	if (bp->phy_flags & PHY_SERDES_FLAG) {		if (CHIP_NUM(bp) == CHIP_NUM_5706)			rc = bnx2_init_5706s_phy(bp);		else if (CHIP_NUM(bp) == CHIP_NUM_5708)			rc = bnx2_init_5708s_phy(bp);		else if (CHIP_NUM(bp) == CHIP_NUM_5709)			rc = bnx2_init_5709s_phy(bp);	}	else {		rc = bnx2_init_copper_phy(bp);	}setup_phy:	if (!rc)		rc = bnx2_setup_phy(bp, bp->phy_port);	return rc;}static intbnx2_set_mac_loopback(struct bnx2 *bp){	u32 mac_mode;	mac_mode = REG_RD(bp, BNX2_EMAC_MODE);	mac_mode &= ~BNX2_EMAC_MODE_PORT;	mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;	REG_WR(bp, BNX2_EMAC_MODE, mac_mode);	bp->link_up = 1;	return 0;}static int bnx2_test_link(struct bnx2 *);static intbnx2_set_phy_loopback(struct bnx2 *bp){	u32 mac_mode;	int rc, i;	spin_lock_bh(&bp->phy_lock);	rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |			    BMCR_SPEED1000);	spin_unlock_bh(&bp->phy_lock);	if (rc)		return rc;	for (i = 0; i < 10; i++) {		if (bnx2_test_link(bp) == 0)			break;		msleep(100);	}	mac_mode = REG_RD(bp, BNX2_EMAC_MODE);	mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |		      BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |		      BNX2_EMAC_MODE_25G_MODE);	mac_mode |= BNX2_EMAC_MODE_PORT_GMII;	REG_WR(bp, BNX2_EMAC_MODE, mac_mode);	bp->link_up = 1;	return 0;}static intbnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent){	int i;	u32 val;	bp->fw_wr_seq++;	msg_data |= bp->fw_wr_seq;	REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);	/* wait for an acknowledgement. */	for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {		msleep(10);		val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB);		if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))			break;	}	if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)		return 0;	/* If we timed out, inform the firmware that this is the case. */	if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {		if (!silent)			printk(KERN_ERR PFX "fw sync timeout, reset code = "					    "%x\n", msg_data);		msg_data &= ~BNX2_DRV_MSG_CODE;		msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;		REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);		return -EBUSY;	}	if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)		return -EIO;	return 0;}static intbnx2_init_5709_context(struct bnx2 *bp){	int i, ret = 0;	u32 val;	val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);	val |= (BCM_PAGE_BITS - 8) << 16;	REG_WR(bp, BNX2_CTX_COMMAND, val);	for (i = 0; i < 10; i++) {		val = REG_RD(bp, BNX2_CTX_COMMAND);		if (!(val & BNX2_CTX_COMMAND_MEM_INIT))			break;		udelay(2);	}	if (val & BNX2_CTX_COMMAND_MEM_INIT)		return -EBUSY;	for (i = 0; i < bp->ctx_pages; i++) {		int j;		REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,		       (bp->ctx_blk_mapping[i] & 0xffffffff) |		       BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);		REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,		       (u64) bp->ctx_blk_mapping[i] >> 32);		REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |		       BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);		for (j = 0; j < 10; j++) {			val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);			if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))				break;			udelay(5);		}		if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {			ret = -EBUSY;			break;		}	}	return ret;}static voidbnx2_init_context(struct bnx2 *bp)

⌨️ 快捷键说明

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