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

📄 bnx2.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Combine status and statistics blocks into one allocation. */	status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));	bp->status_stats_size = status_blk_size +				sizeof(struct statistics_block);	bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,					      &bp->status_blk_mapping);	if (bp->status_blk == NULL)		goto alloc_mem_err;	memset(bp->status_blk, 0, bp->status_stats_size);	bp->stats_blk = (void *) ((unsigned long) bp->status_blk +				  status_blk_size);	bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;	if (CHIP_NUM(bp) == CHIP_NUM_5709) {		bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;		if (bp->ctx_pages == 0)			bp->ctx_pages = 1;		for (i = 0; i < bp->ctx_pages; i++) {			bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,						BCM_PAGE_SIZE,						&bp->ctx_blk_mapping[i]);			if (bp->ctx_blk[i] == NULL)				goto alloc_mem_err;		}	}	return 0;alloc_mem_err:	bnx2_free_mem(bp);	return -ENOMEM;}static voidbnx2_report_fw_link(struct bnx2 *bp){	u32 fw_link_status = 0;	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)		return;	if (bp->link_up) {		u32 bmsr;		switch (bp->line_speed) {		case SPEED_10:			if (bp->duplex == DUPLEX_HALF)				fw_link_status = BNX2_LINK_STATUS_10HALF;			else				fw_link_status = BNX2_LINK_STATUS_10FULL;			break;		case SPEED_100:			if (bp->duplex == DUPLEX_HALF)				fw_link_status = BNX2_LINK_STATUS_100HALF;			else				fw_link_status = BNX2_LINK_STATUS_100FULL;			break;		case SPEED_1000:			if (bp->duplex == DUPLEX_HALF)				fw_link_status = BNX2_LINK_STATUS_1000HALF;			else				fw_link_status = BNX2_LINK_STATUS_1000FULL;			break;		case SPEED_2500:			if (bp->duplex == DUPLEX_HALF)				fw_link_status = BNX2_LINK_STATUS_2500HALF;			else				fw_link_status = BNX2_LINK_STATUS_2500FULL;			break;		}		fw_link_status |= BNX2_LINK_STATUS_LINK_UP;		if (bp->autoneg) {			fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);			if (!(bmsr & BMSR_ANEGCOMPLETE) ||			    bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)				fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;			else				fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;		}	}	else		fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;	REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status);}static char *bnx2_xceiver_str(struct bnx2 *bp){	return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :		((bp->phy_flags & PHY_SERDES_FLAG) ? "Remote Copper" :		 "Copper"));}static voidbnx2_report_link(struct bnx2 *bp){	if (bp->link_up) {		netif_carrier_on(bp->dev);		printk(KERN_INFO PFX "%s NIC %s Link is Up, ", bp->dev->name,		       bnx2_xceiver_str(bp));		printk("%d Mbps ", bp->line_speed);		if (bp->duplex == DUPLEX_FULL)			printk("full duplex");		else			printk("half duplex");		if (bp->flow_ctrl) {			if (bp->flow_ctrl & FLOW_CTRL_RX) {				printk(", receive ");				if (bp->flow_ctrl & FLOW_CTRL_TX)					printk("& transmit ");			}			else {				printk(", transmit ");			}			printk("flow control ON");		}		printk("\n");	}	else {		netif_carrier_off(bp->dev);		printk(KERN_ERR PFX "%s NIC %s Link is Down\n", bp->dev->name,		       bnx2_xceiver_str(bp));	}	bnx2_report_fw_link(bp);}static voidbnx2_resolve_flow_ctrl(struct bnx2 *bp){	u32 local_adv, remote_adv;	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;		}		return;	}	if (bp->duplex != DUPLEX_FULL) {		return;	}	if ((bp->phy_flags & PHY_SERDES_FLAG) &&	    (CHIP_NUM(bp) == CHIP_NUM_5708)) {		u32 val;		bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);		if (val & BCM5708S_1000X_STAT1_TX_PAUSE)			bp->flow_ctrl |= FLOW_CTRL_TX;		if (val & BCM5708S_1000X_STAT1_RX_PAUSE)			bp->flow_ctrl |= FLOW_CTRL_RX;		return;	}	bnx2_read_phy(bp, bp->mii_adv, &local_adv);	bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);	if (bp->phy_flags & PHY_SERDES_FLAG) {		u32 new_local_adv = 0;		u32 new_remote_adv = 0;		if (local_adv & ADVERTISE_1000XPAUSE)			new_local_adv |= ADVERTISE_PAUSE_CAP;		if (local_adv & ADVERTISE_1000XPSE_ASYM)			new_local_adv |= ADVERTISE_PAUSE_ASYM;		if (remote_adv & ADVERTISE_1000XPAUSE)			new_remote_adv |= ADVERTISE_PAUSE_CAP;		if (remote_adv & ADVERTISE_1000XPSE_ASYM)			new_remote_adv |= ADVERTISE_PAUSE_ASYM;		local_adv = new_local_adv;		remote_adv = new_remote_adv;	}	/* See Table 28B-3 of 802.3ab-1999 spec. */	if (local_adv & ADVERTISE_PAUSE_CAP) {		if(local_adv & ADVERTISE_PAUSE_ASYM) {	                if (remote_adv & ADVERTISE_PAUSE_CAP) {				bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;			}			else if (remote_adv & ADVERTISE_PAUSE_ASYM) {				bp->flow_ctrl = FLOW_CTRL_RX;			}		}		else {			if (remote_adv & ADVERTISE_PAUSE_CAP) {				bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;			}		}	}	else if (local_adv & ADVERTISE_PAUSE_ASYM) {		if ((remote_adv & ADVERTISE_PAUSE_CAP) &&			(remote_adv & ADVERTISE_PAUSE_ASYM)) {			bp->flow_ctrl = FLOW_CTRL_TX;		}	}}static intbnx2_5709s_linkup(struct bnx2 *bp){	u32 val, speed;	bp->link_up = 1;	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);	bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);	if ((bp->autoneg & AUTONEG_SPEED) == 0) {		bp->line_speed = bp->req_line_speed;		bp->duplex = bp->req_duplex;		return 0;	}	speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;	switch (speed) {		case MII_BNX2_GP_TOP_AN_SPEED_10:			bp->line_speed = SPEED_10;			break;		case MII_BNX2_GP_TOP_AN_SPEED_100:			bp->line_speed = SPEED_100;			break;		case MII_BNX2_GP_TOP_AN_SPEED_1G:		case MII_BNX2_GP_TOP_AN_SPEED_1GKV:			bp->line_speed = SPEED_1000;			break;		case MII_BNX2_GP_TOP_AN_SPEED_2_5G:			bp->line_speed = SPEED_2500;			break;	}	if (val & MII_BNX2_GP_TOP_AN_FD)		bp->duplex = DUPLEX_FULL;	else		bp->duplex = DUPLEX_HALF;	return 0;}static intbnx2_5708s_linkup(struct bnx2 *bp){	u32 val;	bp->link_up = 1;	bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);	switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {		case BCM5708S_1000X_STAT1_SPEED_10:			bp->line_speed = SPEED_10;			break;		case BCM5708S_1000X_STAT1_SPEED_100:			bp->line_speed = SPEED_100;			break;		case BCM5708S_1000X_STAT1_SPEED_1G:			bp->line_speed = SPEED_1000;			break;		case BCM5708S_1000X_STAT1_SPEED_2G5:			bp->line_speed = SPEED_2500;			break;	}	if (val & BCM5708S_1000X_STAT1_FD)		bp->duplex = DUPLEX_FULL;	else		bp->duplex = DUPLEX_HALF;	return 0;}static intbnx2_5706s_linkup(struct bnx2 *bp){	u32 bmcr, local_adv, remote_adv, common;	bp->link_up = 1;	bp->line_speed = SPEED_1000;	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);	if (bmcr & BMCR_FULLDPLX) {		bp->duplex = DUPLEX_FULL;	}	else {		bp->duplex = DUPLEX_HALF;	}	if (!(bmcr & BMCR_ANENABLE)) {		return 0;	}	bnx2_read_phy(bp, bp->mii_adv, &local_adv);	bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);	common = local_adv & remote_adv;	if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {		if (common & ADVERTISE_1000XFULL) {			bp->duplex = DUPLEX_FULL;		}		else {			bp->duplex = DUPLEX_HALF;		}	}	return 0;}static intbnx2_copper_linkup(struct bnx2 *bp){	u32 bmcr;	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);	if (bmcr & BMCR_ANENABLE) {		u32 local_adv, remote_adv, common;		bnx2_read_phy(bp, MII_CTRL1000, &local_adv);		bnx2_read_phy(bp, MII_STAT1000, &remote_adv);		common = local_adv & (remote_adv >> 2);		if (common & ADVERTISE_1000FULL) {			bp->line_speed = SPEED_1000;			bp->duplex = DUPLEX_FULL;		}		else if (common & ADVERTISE_1000HALF) {			bp->line_speed = SPEED_1000;			bp->duplex = DUPLEX_HALF;		}		else {			bnx2_read_phy(bp, bp->mii_adv, &local_adv);			bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);			common = local_adv & remote_adv;			if (common & ADVERTISE_100FULL) {				bp->line_speed = SPEED_100;				bp->duplex = DUPLEX_FULL;			}			else if (common & ADVERTISE_100HALF) {				bp->line_speed = SPEED_100;				bp->duplex = DUPLEX_HALF;			}			else if (common & ADVERTISE_10FULL) {				bp->line_speed = SPEED_10;				bp->duplex = DUPLEX_FULL;			}			else if (common & ADVERTISE_10HALF) {				bp->line_speed = SPEED_10;				bp->duplex = DUPLEX_HALF;			}			else {				bp->line_speed = 0;				bp->link_up = 0;			}		}	}	else {		if (bmcr & BMCR_SPEED100) {			bp->line_speed = SPEED_100;		}		else {			bp->line_speed = SPEED_10;		}		if (bmcr & BMCR_FULLDPLX) {			bp->duplex = DUPLEX_FULL;		}		else {			bp->duplex = DUPLEX_HALF;		}	}	return 0;}static intbnx2_set_mac_link(struct bnx2 *bp){	u32 val;	REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);	if (bp->link_up && (bp->line_speed == SPEED_1000) &&		(bp->duplex == DUPLEX_HALF)) {		REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);	}	/* Configure the EMAC mode register. */	val = REG_RD(bp, BNX2_EMAC_MODE);	val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |		BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |		BNX2_EMAC_MODE_25G_MODE);	if (bp->link_up) {		switch (bp->line_speed) {			case SPEED_10:				if (CHIP_NUM(bp) != CHIP_NUM_5706) {					val |= BNX2_EMAC_MODE_PORT_MII_10M;					break;				}				/* fall through */			case SPEED_100:				val |= BNX2_EMAC_MODE_PORT_MII;				break;			case SPEED_2500:				val |= BNX2_EMAC_MODE_25G_MODE;				/* fall through */			case SPEED_1000:				val |= BNX2_EMAC_MODE_PORT_GMII;				break;		}	}	else {		val |= BNX2_EMAC_MODE_PORT_GMII;	}	/* Set the MAC to operate in the appropriate duplex mode. */	if (bp->duplex == DUPLEX_HALF)		val |= BNX2_EMAC_MODE_HALF_DUPLEX;	REG_WR(bp, BNX2_EMAC_MODE, val);	/* Enable/disable rx PAUSE. */	bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;	if (bp->flow_ctrl & FLOW_CTRL_RX)		bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;	REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);	/* Enable/disable tx PAUSE. */	val = REG_RD(bp, BNX2_EMAC_TX_MODE);	val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;	if (bp->flow_ctrl & FLOW_CTRL_TX)		val |= BNX2_EMAC_TX_MODE_FLOW_EN;	REG_WR(bp, BNX2_EMAC_TX_MODE, val);	/* Acknowledge the interrupt. */	REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);	return 0;}static voidbnx2_enable_bmsr1(struct bnx2 *bp){	if ((bp->phy_flags & PHY_SERDES_FLAG) &&	    (CHIP_NUM(bp) == CHIP_NUM_5709))		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,			       MII_BNX2_BLK_ADDR_GP_STATUS);}static voidbnx2_disable_bmsr1(struct bnx2 *bp){	if ((bp->phy_flags & PHY_SERDES_FLAG) &&	    (CHIP_NUM(bp) == CHIP_NUM_5709))		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);}static intbnx2_test_and_enable_2g5(struct bnx2 *bp){	u32 up1;	int ret = 1;	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))		return 0;	if (bp->autoneg & AUTONEG_SPEED)		bp->advertising |= ADVERTISED_2500baseX_Full;	if (CHIP_NUM(bp) == CHIP_NUM_5709)		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);	bnx2_read_phy(bp, bp->mii_up1, &up1);	if (!(up1 & BCM5708S_UP1_2G5)) {		up1 |= BCM5708S_UP1_2G5;		bnx2_write_phy(bp, bp->mii_up1, up1);		ret = 0;	}	if (CHIP_NUM(bp) == CHIP_NUM_5709)		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);	return ret;}static intbnx2_test_and_disable_2g5(struct bnx2 *bp){	u32 up1;	int ret = 0;	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))		return 0;	if (CHIP_NUM(bp) == CHIP_NUM_5709)		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);	bnx2_read_phy(bp, bp->mii_up1, &up1);	if (up1 & BCM5708S_UP1_2G5) {		up1 &= ~BCM5708S_UP1_2G5;		bnx2_write_phy(bp, bp->mii_up1, up1);		ret = 1;	}	if (CHIP_NUM(bp) == CHIP_NUM_5709)		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);

⌨️ 快捷键说明

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