📄 tg3.c
字号:
return err; goto out; } err = tg3_bmcr_reset(tp); if (err) return err; out: tg3_phy_set_wirespeed(tp); return 0;}static void tg3_set_power_state_0(struct tg3 *tp){ uint16_t power_control; int pm = tp->pm_cap; /* Make sure register accesses (indirect or otherwise) * will function correctly. */ pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl); pci_read_config_word(tp->pdev, pm + PCI_PM_CTRL, &power_control); power_control |= PCI_PM_CTRL_PME_STATUS; power_control &= ~(PCI_PM_CTRL_STATE_MASK); power_control |= 0; pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); tw32_carefully(GRC_LOCAL_CTRL, tp->grc_local_ctrl); return;}#if SUPPORT_LINK_REPORTstatic void tg3_link_report(struct tg3 *tp){ if (!tp->carrier_ok) { printf("Link is down.\n"); } else { printf("Link is up at %d Mbps, %s duplex. %s %s %s\n", (tp->link_config.active_speed == SPEED_1000 ? 1000 : (tp->link_config.active_speed == SPEED_100 ? 100 : 10)), (tp->link_config.active_duplex == DUPLEX_FULL ? "full" : "half"), (tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "TX" : "", (tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "RX" : "", (tp->tg3_flags & (TG3_FLAG_TX_PAUSE |TG3_FLAG_RX_PAUSE)) ? "flow control" : ""); }}#else#define tg3_link_report(tp)#endifstatic void tg3_setup_flow_control(struct tg3 *tp, uint32_t local_adv, uint32_t remote_adv){ uint32_t new_tg3_flags = 0; if (local_adv & ADVERTISE_PAUSE_CAP) { if (local_adv & ADVERTISE_PAUSE_ASYM) { if (remote_adv & LPA_PAUSE_CAP) new_tg3_flags |= (TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); else if (remote_adv & LPA_PAUSE_ASYM) new_tg3_flags |= (TG3_FLAG_RX_PAUSE); } else { if (remote_adv & LPA_PAUSE_CAP) new_tg3_flags |= (TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); } } else if (local_adv & ADVERTISE_PAUSE_ASYM) { if ((remote_adv & LPA_PAUSE_CAP) && (remote_adv & LPA_PAUSE_ASYM)) new_tg3_flags |= TG3_FLAG_TX_PAUSE; } tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); tp->tg3_flags |= new_tg3_flags; if (new_tg3_flags & TG3_FLAG_RX_PAUSE) tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; else tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; if (new_tg3_flags & TG3_FLAG_TX_PAUSE) tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; else tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;}#if SUPPORT_COPPER_PHYstatic void tg3_aux_stat_to_speed_duplex( struct tg3 *tp __unused, uint32_t val, uint8_t *speed, uint8_t *duplex){ static const uint8_t map[] = { [0] = (SPEED_INVALID << 2) | DUPLEX_INVALID, [MII_TG3_AUX_STAT_10HALF >> 8] = (SPEED_10 << 2) | DUPLEX_HALF, [MII_TG3_AUX_STAT_10FULL >> 8] = (SPEED_10 << 2) | DUPLEX_FULL, [MII_TG3_AUX_STAT_100HALF >> 8] = (SPEED_100 << 2) | DUPLEX_HALF, [MII_TG3_AUX_STAT_100_4 >> 8] = (SPEED_INVALID << 2) | DUPLEX_INVALID, [MII_TG3_AUX_STAT_100FULL >> 8] = (SPEED_100 << 2) | DUPLEX_FULL, [MII_TG3_AUX_STAT_1000HALF >> 8] = (SPEED_1000 << 2) | DUPLEX_HALF, [MII_TG3_AUX_STAT_1000FULL >> 8] = (SPEED_1000 << 2) | DUPLEX_FULL, }; uint8_t result; result = map[(val & MII_TG3_AUX_STAT_SPDMASK) >> 8]; *speed = result >> 2; *duplex = result & 3;}static int tg3_phy_copper_begin(struct tg3 *tp){ uint32_t new_adv; tp->link_config.advertising = (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg | ADVERTISED_MII); if (tp->tg3_flags & TG3_FLAG_10_100_ONLY) { tp->link_config.advertising &= ~(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full); } new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); if (tp->link_config.advertising & ADVERTISED_10baseT_Half) { new_adv |= ADVERTISE_10HALF; } if (tp->link_config.advertising & ADVERTISED_10baseT_Full) { new_adv |= ADVERTISE_10FULL; } if (tp->link_config.advertising & ADVERTISED_100baseT_Half) { new_adv |= ADVERTISE_100HALF; } if (tp->link_config.advertising & ADVERTISED_100baseT_Full) { new_adv |= ADVERTISE_100FULL; } tg3_writephy(tp, MII_ADVERTISE, new_adv); if (tp->link_config.advertising & (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) { new_adv = 0; if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) { new_adv |= MII_TG3_CTRL_ADV_1000_HALF; } if (tp->link_config.advertising & ADVERTISED_1000baseT_Full) { new_adv |= MII_TG3_CTRL_ADV_1000_FULL; } if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) && (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) { new_adv |= (MII_TG3_CTRL_AS_MASTER | MII_TG3_CTRL_ENABLE_AS_MASTER); } tg3_writephy(tp, MII_TG3_CTRL, new_adv); } else { tg3_writephy(tp, MII_TG3_CTRL, 0); } tg3_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); return 0;}static int tg3_init_5401phy_dsp(struct tg3 *tp){ int err; /* Turn off tap power management. */ err = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c20); err |= tg3_writedsp(tp, 0x0012, 0x1804); err |= tg3_writedsp(tp, 0x0013, 0x1204); err |= tg3_writedsp(tp, 0x8006, 0x0132); err |= tg3_writedsp(tp, 0x8006, 0x0232); err |= tg3_writedsp(tp, 0x201f, 0x0a20); udelay(40); return err;}static int tg3_setup_copper_phy(struct tg3 *tp){ int current_link_up; uint32_t bmsr, dummy; int i, err; tw32_carefully(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); tp->mi_mode = MAC_MI_MODE_BASE; tw32_carefully(MAC_MI_MODE, tp->mi_mode); tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02); /* Some third-party PHYs need to be reset on link going * down. */ if ( ( (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0)) && (tp->carrier_ok)) { tg3_readphy(tp, MII_BMSR, &bmsr); tg3_readphy(tp, MII_BMSR, &bmsr); if (!(bmsr & BMSR_LSTATUS)) tg3_phy_reset(tp); } if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { tg3_readphy(tp, MII_BMSR, &bmsr); tg3_readphy(tp, MII_BMSR, &bmsr); if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) bmsr = 0; if (!(bmsr & BMSR_LSTATUS)) { err = tg3_init_5401phy_dsp(tp); if (err) return err; tg3_readphy(tp, MII_BMSR, &bmsr); for (i = 0; i < 1000; i++) { udelay(10); tg3_readphy(tp, MII_BMSR, &bmsr); if (bmsr & BMSR_LSTATUS) { udelay(40); break; } } if ((tp->phy_id & PHY_ID_REV_MASK) == PHY_REV_BCM5401_B0 && !(bmsr & BMSR_LSTATUS) && tp->link_config.active_speed == SPEED_1000) { err = tg3_phy_reset(tp); if (!err) err = tg3_init_5401phy_dsp(tp); if (err) return err; } } } else if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) { /* 5701 {A0,B0} CRC bug workaround */ tg3_writephy(tp, 0x15, 0x0a75); tg3_writephy(tp, 0x1c, 0x8c68); tg3_writephy(tp, 0x1c, 0x8d68); tg3_writephy(tp, 0x1c, 0x8c68); } /* Clear pending interrupts... */ tg3_readphy(tp, MII_TG3_ISTAT, &dummy); tg3_readphy(tp, MII_TG3_ISTAT, &dummy); tg3_writephy(tp, MII_TG3_IMASK, ~0); if (tp->led_mode == led_mode_three_link) tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_LNK3_LED_MODE); else tg3_writephy(tp, MII_TG3_EXT_CTRL, 0); current_link_up = 0; tg3_readphy(tp, MII_BMSR, &bmsr); tg3_readphy(tp, MII_BMSR, &bmsr); if (bmsr & BMSR_LSTATUS) { uint32_t aux_stat, bmcr; tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat); for (i = 0; i < 2000; i++) { udelay(10); tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat); if (aux_stat) break; } tg3_aux_stat_to_speed_duplex(tp, aux_stat, &tp->link_config.active_speed, &tp->link_config.active_duplex); tg3_readphy(tp, MII_BMCR, &bmcr); tg3_readphy(tp, MII_BMCR, &bmcr); if (bmcr & BMCR_ANENABLE) { uint32_t gig_ctrl; current_link_up = 1; /* Force autoneg restart if we are exiting * low power mode. */ tg3_readphy(tp, MII_TG3_CTRL, &gig_ctrl); if (!(gig_ctrl & (MII_TG3_CTRL_ADV_1000_HALF | MII_TG3_CTRL_ADV_1000_FULL))) { current_link_up = 0; } } else { current_link_up = 0; } } if (current_link_up == 1 && (tp->link_config.active_duplex == DUPLEX_FULL)) { uint32_t local_adv, remote_adv; tg3_readphy(tp, MII_ADVERTISE, &local_adv); local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); tg3_readphy(tp, MII_LPA, &remote_adv); remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM); /* If we are not advertising full pause capability, * something is wrong. Bring the link down and reconfigure. */ if (local_adv != ADVERTISE_PAUSE_CAP) { current_link_up = 0; } else { tg3_setup_flow_control(tp, local_adv, remote_adv); } } if (current_link_up == 0) { uint32_t tmp; tg3_phy_copper_begin(tp); tg3_readphy(tp, MII_BMSR, &tmp); tg3_readphy(tp, MII_BMSR, &tmp); if (tmp & BMSR_LSTATUS) current_link_up = 1; } tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK; if (current_link_up == 1) { if (tp->link_config.active_speed == SPEED_100 || tp->link_config.active_speed == SPEED_10) tp->mac_mode |= MAC_MODE_PORT_MODE_MII; else tp->mac_mode |= MAC_MODE_PORT_MODE_GMII; } else tp->mac_mode |= MAC_MODE_PORT_MODE_GMII; tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX; if (tp->link_config.active_duplex == DUPLEX_HALF) tp->mac_mode |= MAC_MODE_HALF_DUPLEX; tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) { if ((tp->led_mode == led_mode_link10) || (current_link_up == 1 && tp->link_config.active_speed == SPEED_10)) tp->mac_mode |= MAC_MODE_LINK_POLARITY; } else { if (current_link_up == 1) tp->mac_mode |= MAC_MODE_LINK_POLARITY; tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1); } /* ??? Without this setting Netgear GA302T PHY does not * ??? send/receive packets... * With this other PHYs cannot bring up the link */ if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411 && tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) { tp->mi_mode |= MAC_MI_MODE_AUTO_POLL; tw32_carefully(MAC_MI_MODE, tp->mi_mode); } tw32_carefully(MAC_MODE, tp->mac_mode); /* Link change polled. */ tw32_carefully(MAC_EVENT, 0); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 && current_link_up == 1 && tp->link_config.active_speed == SPEED_1000 && ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) || (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) { udelay(120); tw32_carefully(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); tg3_write_mem( NIC_SRAM_FIRMWARE_MBOX, NIC_SRAM_FIRMWARE_MBOX_MAGIC2); } if (current_link_up != tp->carrier_ok) { tp->carrier_ok = current_link_up; tg3_link_report(tp); } return 0;}#else#define tg3_setup_copper_phy(TP) (-EINVAL)#endif /* SUPPORT_COPPER_PHY */#if SUPPORT_FIBER_PHYstruct tg3_fiber_aneginfo { int state;#define ANEG_STATE_UNKNOWN 0#define ANEG_STATE_AN_ENABLE 1#define ANEG_STATE_RESTART_INIT 2#define ANEG_STATE_RESTART 3#define ANEG_STATE_DISABLE_LINK_OK 4#define ANEG_STATE_ABILITY_DETECT_INIT 5#define ANEG_STATE_ABILITY_DETECT 6#define ANEG_STATE_ACK_DETECT_INIT 7#define ANEG_STATE_ACK_DETECT 8#define ANEG_STATE_COMPLETE_ACK_INIT 9#define ANEG_STATE_COMPLETE_ACK 10#define ANEG_STATE_IDLE_DETECT_INIT 11#define ANEG_STATE_IDLE_DETECT 12#define ANEG_STATE_LINK_OK 13#define ANEG_STATE_NEXT_PAGE_WAIT_INIT 14#define ANEG_STATE_NEXT_PAGE_WAIT 15 uint32_t flags;#define MR_AN_ENABLE 0x00000001#define MR_RESTART_AN 0x00000002#define MR_AN_COMPLETE 0x00000004#define MR_PAGE_RX 0x00000008#define MR_NP_LOADED 0x00000010#define MR_TOGGLE_TX 0x00000020#define MR_LP_ADV_FULL_DUPLEX 0x00000040#define MR_LP_ADV_HALF_DUPLEX 0x00000080#define MR_LP_ADV_SYM_PAUSE 0x00000100#define MR_LP_ADV_ASYM_PAUSE 0x00000200#define MR_LP_ADV_REMOTE_FAULT1 0x00000400#define MR_LP_ADV_REMOTE_FAULT2 0x00000800#define MR_LP_ADV_NEXT_PAGE 0x00001000#define MR_TOGGLE_RX 0x00002000#define MR_NP_RX 0x00004000#define MR_LINK_OK 0x80000000 unsigned long link_time, cur_time; uint32_t ability_match_cfg; int ability_match_count; char ability_match, idle_match, ack_match; uint32_t txconfig, rxconfig;#define ANEG_CFG_NP 0x00000080#define ANEG_CFG_ACK 0x00000040#define ANEG_CFG_RF2 0x00000020#define ANEG_CFG_RF1 0x00000010#define ANEG_CFG_PS2 0x00000001#define ANEG_CFG_PS1 0x00008000#define ANEG_CFG_HD 0x00004000#define ANEG_CFG_FD 0x00002000#define ANEG_CFG_INVAL 0x00001f06};#define ANEG_OK 0#define ANEG_DONE 1#define ANEG_TIMER_ENAB 2#define ANEG_FAILED -1#define ANEG_STATE_SETTLE_TIME 10000static int tg3_fiber_aneg_smachine(struct tg3 *tp, struct tg3_fiber_aneginfo *ap){ unsigned long delta; uint32_t rx_cfg_reg; int ret; if (ap->state == ANEG_STATE_UNKNOWN) { ap->rxconfig = 0; ap->link_time = 0; ap->cur_time = 0; ap->ability_match_cfg = 0; ap->ability_match_count = 0; ap->ability_match = 0; ap->idle_match = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -