📄 bnx2.c
字号:
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 + -