📄 tg3.c
字号:
ap->ack_match = 0; } ap->cur_time++; if (tr32(MAC_STATUS) & MAC_STATUS_RCVD_CFG) { rx_cfg_reg = tr32(MAC_RX_AUTO_NEG); if (rx_cfg_reg != ap->ability_match_cfg) { ap->ability_match_cfg = rx_cfg_reg; ap->ability_match = 0; ap->ability_match_count = 0; } else { if (++ap->ability_match_count > 1) { ap->ability_match = 1; ap->ability_match_cfg = rx_cfg_reg; } } if (rx_cfg_reg & ANEG_CFG_ACK) ap->ack_match = 1; else ap->ack_match = 0; ap->idle_match = 0; } else { ap->idle_match = 1; ap->ability_match_cfg = 0; ap->ability_match_count = 0; ap->ability_match = 0; ap->ack_match = 0; rx_cfg_reg = 0; } ap->rxconfig = rx_cfg_reg; ret = ANEG_OK; switch(ap->state) { case ANEG_STATE_UNKNOWN: if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN)) ap->state = ANEG_STATE_AN_ENABLE; /* fallthru */ case ANEG_STATE_AN_ENABLE: ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX); if (ap->flags & MR_AN_ENABLE) { 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; ap->ack_match = 0; ap->state = ANEG_STATE_RESTART_INIT; } else { ap->state = ANEG_STATE_DISABLE_LINK_OK; } break; case ANEG_STATE_RESTART_INIT: ap->link_time = ap->cur_time; ap->flags &= ~(MR_NP_LOADED); ap->txconfig = 0; tw32(MAC_TX_AUTO_NEG, 0); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; tw32_carefully(MAC_MODE, tp->mac_mode); ret = ANEG_TIMER_ENAB; ap->state = ANEG_STATE_RESTART; /* fallthru */ case ANEG_STATE_RESTART: delta = ap->cur_time - ap->link_time; if (delta > ANEG_STATE_SETTLE_TIME) { ap->state = ANEG_STATE_ABILITY_DETECT_INIT; } else { ret = ANEG_TIMER_ENAB; } break; case ANEG_STATE_DISABLE_LINK_OK: ret = ANEG_DONE; break; case ANEG_STATE_ABILITY_DETECT_INIT: ap->flags &= ~(MR_TOGGLE_TX); ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1); tw32(MAC_TX_AUTO_NEG, ap->txconfig); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; tw32_carefully(MAC_MODE, tp->mac_mode); ap->state = ANEG_STATE_ABILITY_DETECT; break; case ANEG_STATE_ABILITY_DETECT: if (ap->ability_match != 0 && ap->rxconfig != 0) { ap->state = ANEG_STATE_ACK_DETECT_INIT; } break; case ANEG_STATE_ACK_DETECT_INIT: ap->txconfig |= ANEG_CFG_ACK; tw32(MAC_TX_AUTO_NEG, ap->txconfig); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; tw32_carefully(MAC_MODE, tp->mac_mode); ap->state = ANEG_STATE_ACK_DETECT; /* fallthru */ case ANEG_STATE_ACK_DETECT: if (ap->ack_match != 0) { if ((ap->rxconfig & ~ANEG_CFG_ACK) == (ap->ability_match_cfg & ~ANEG_CFG_ACK)) { ap->state = ANEG_STATE_COMPLETE_ACK_INIT; } else { ap->state = ANEG_STATE_AN_ENABLE; } } else if (ap->ability_match != 0 && ap->rxconfig == 0) { ap->state = ANEG_STATE_AN_ENABLE; } break; case ANEG_STATE_COMPLETE_ACK_INIT: if (ap->rxconfig & ANEG_CFG_INVAL) { ret = ANEG_FAILED; break; } ap->flags &= ~(MR_LP_ADV_FULL_DUPLEX | MR_LP_ADV_HALF_DUPLEX | MR_LP_ADV_SYM_PAUSE | MR_LP_ADV_ASYM_PAUSE | MR_LP_ADV_REMOTE_FAULT1 | MR_LP_ADV_REMOTE_FAULT2 | MR_LP_ADV_NEXT_PAGE | MR_TOGGLE_RX | MR_NP_RX); if (ap->rxconfig & ANEG_CFG_FD) ap->flags |= MR_LP_ADV_FULL_DUPLEX; if (ap->rxconfig & ANEG_CFG_HD) ap->flags |= MR_LP_ADV_HALF_DUPLEX; if (ap->rxconfig & ANEG_CFG_PS1) ap->flags |= MR_LP_ADV_SYM_PAUSE; if (ap->rxconfig & ANEG_CFG_PS2) ap->flags |= MR_LP_ADV_ASYM_PAUSE; if (ap->rxconfig & ANEG_CFG_RF1) ap->flags |= MR_LP_ADV_REMOTE_FAULT1; if (ap->rxconfig & ANEG_CFG_RF2) ap->flags |= MR_LP_ADV_REMOTE_FAULT2; if (ap->rxconfig & ANEG_CFG_NP) ap->flags |= MR_LP_ADV_NEXT_PAGE; ap->link_time = ap->cur_time; ap->flags ^= (MR_TOGGLE_TX); if (ap->rxconfig & 0x0008) ap->flags |= MR_TOGGLE_RX; if (ap->rxconfig & ANEG_CFG_NP) ap->flags |= MR_NP_RX; ap->flags |= MR_PAGE_RX; ap->state = ANEG_STATE_COMPLETE_ACK; ret = ANEG_TIMER_ENAB; break; case ANEG_STATE_COMPLETE_ACK: if (ap->ability_match != 0 && ap->rxconfig == 0) { ap->state = ANEG_STATE_AN_ENABLE; break; } delta = ap->cur_time - ap->link_time; if (delta > ANEG_STATE_SETTLE_TIME) { if (!(ap->flags & (MR_LP_ADV_NEXT_PAGE))) { ap->state = ANEG_STATE_IDLE_DETECT_INIT; } else { if ((ap->txconfig & ANEG_CFG_NP) == 0 && !(ap->flags & MR_NP_RX)) { ap->state = ANEG_STATE_IDLE_DETECT_INIT; } else { ret = ANEG_FAILED; } } } break; case ANEG_STATE_IDLE_DETECT_INIT: ap->link_time = ap->cur_time; tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; tw32_carefully(MAC_MODE, tp->mac_mode); ap->state = ANEG_STATE_IDLE_DETECT; ret = ANEG_TIMER_ENAB; break; case ANEG_STATE_IDLE_DETECT: if (ap->ability_match != 0 && ap->rxconfig == 0) { ap->state = ANEG_STATE_AN_ENABLE; break; } delta = ap->cur_time - ap->link_time; if (delta > ANEG_STATE_SETTLE_TIME) { /* XXX another gem from the Broadcom driver :( */ ap->state = ANEG_STATE_LINK_OK; } break; case ANEG_STATE_LINK_OK: ap->flags |= (MR_AN_COMPLETE | MR_LINK_OK); ret = ANEG_DONE; break; case ANEG_STATE_NEXT_PAGE_WAIT_INIT: /* ??? unimplemented */ break; case ANEG_STATE_NEXT_PAGE_WAIT: /* ??? unimplemented */ break; default: ret = ANEG_FAILED; break; }; return ret;}static int tg3_setup_fiber_phy(struct tg3 *tp){ uint32_t orig_pause_cfg; uint16_t orig_active_speed; uint8_t orig_active_duplex; int current_link_up; int i; orig_pause_cfg = (tp->tg3_flags & (TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE)); orig_active_speed = tp->link_config.active_speed; orig_active_duplex = tp->link_config.active_duplex; tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; tw32_carefully(MAC_MODE, tp->mac_mode); /* Reset when initting first time or we have a link. */ if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) || (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) { /* Set PLL lock range. */ tg3_writephy(tp, 0x16, 0x8007); /* SW reset */ tg3_writephy(tp, MII_BMCR, BMCR_RESET); /* Wait for reset to complete. */ mdelay(5); /* Config mode; select PMA/Ch 1 regs. */ tg3_writephy(tp, 0x10, 0x8411); /* Enable auto-lock and comdet, select txclk for tx. */ tg3_writephy(tp, 0x11, 0x0a10); tg3_writephy(tp, 0x18, 0x00a0); tg3_writephy(tp, 0x16, 0x41ff); /* Assert and deassert POR. */ tg3_writephy(tp, 0x13, 0x0400); udelay(40); tg3_writephy(tp, 0x13, 0x0000); tg3_writephy(tp, 0x11, 0x0a50); udelay(40); tg3_writephy(tp, 0x11, 0x0a10); /* Wait for signal to stabilize */ mdelay(150); /* Deselect the channel register so we can read the PHYID * later. */ tg3_writephy(tp, 0x10, 0x8011); } /* Disable link change interrupt. */ tw32_carefully(MAC_EVENT, 0); current_link_up = 0; if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) { if (!(tp->tg3_flags & TG3_FLAG_GOT_SERDES_FLOWCTL)) { struct tg3_fiber_aneginfo aninfo; int status = ANEG_FAILED; unsigned int tick; uint32_t tmp; memset(&aninfo, 0, sizeof(aninfo)); aninfo.flags |= (MR_AN_ENABLE); tw32(MAC_TX_AUTO_NEG, 0); tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; tw32_carefully(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); aninfo.state = ANEG_STATE_UNKNOWN; aninfo.cur_time = 0; tick = 0; while (++tick < 195000) { status = tg3_fiber_aneg_smachine(tp, &aninfo); if (status == ANEG_DONE || status == ANEG_FAILED) break; udelay(1); } tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; tw32_carefully(MAC_MODE, tp->mac_mode); if (status == ANEG_DONE && (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK | MR_LP_ADV_FULL_DUPLEX))) { uint32_t local_adv, remote_adv; local_adv = ADVERTISE_PAUSE_CAP; remote_adv = 0; if (aninfo.flags & MR_LP_ADV_SYM_PAUSE) remote_adv |= LPA_PAUSE_CAP; if (aninfo.flags & MR_LP_ADV_ASYM_PAUSE) remote_adv |= LPA_PAUSE_ASYM; tg3_setup_flow_control(tp, local_adv, remote_adv); tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; current_link_up = 1; } for (i = 0; i < 60; i++) { udelay(20); tw32_carefully(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)) == 0) break; } if (current_link_up == 0 && (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) { current_link_up = 1; } } else { /* Forcing 1000FD link up. */ current_link_up = 1; } } tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; tw32_carefully(MAC_MODE, tp->mac_mode); tp->hw_status->status = (SD_STATUS_UPDATED | (tp->hw_status->status & ~SD_STATUS_LINK_CHG)); for (i = 0; i < 100; i++) { udelay(20); tw32_carefully(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)) == 0) break; } if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) current_link_up = 0; if (current_link_up == 1) { tp->link_config.active_speed = SPEED_1000; tp->link_config.active_duplex = DUPLEX_FULL; } else { tp->link_config.active_speed = SPEED_INVALID; tp->link_config.active_duplex = DUPLEX_INVALID; } if (current_link_up != tp->carrier_ok) { tp->carrier_ok = current_link_up; tg3_link_report(tp); } else { uint32_t now_pause_cfg = tp->tg3_flags & (TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); if (orig_pause_cfg != now_pause_cfg || orig_active_speed != tp->link_config.active_speed || orig_active_duplex != tp->link_config.active_duplex) tg3_link_report(tp); } if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) { tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY); if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) { tw32_carefully(MAC_MODE, tp->mac_mode); } } return 0;}#else#define tg3_setup_fiber_phy(TP) (-EINVAL)#endif /* SUPPORT_FIBER_PHY */static int tg3_setup_phy(struct tg3 *tp){ int err; if (tp->phy_id == PHY_ID_SERDES) { err = tg3_setup_fiber_phy(tp); } else { err = tg3_setup_copper_phy(tp); } if (tp->link_config.active_speed == SPEED_1000 && tp->link_config.active_duplex == DUPLEX_HALF) tw32(MAC_TX_LENGTHS, ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | (6 << TX_LENGTHS_IPG_SHIFT) | (0xff << TX_LENGTHS_SLOT_TIME_SHIFT))); else tw32(MAC_TX_LENGTHS, ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | (6 << TX_LENGTHS_IPG_SHIFT) | (32 << TX_LENGTHS_SLOT_TIME_SHIFT))); return err;}#define MAX_WAIT_CNT 1000/* To stop a block, clear the enable bit and poll till it * clears. */static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, uint32_t enable_bit){ unsigned int i; uint32_t val; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { switch(ofs) { case RCVLSC_MODE: case DMAC_MODE: case MBFREE_MODE: case BUFMGR_MODE: case MEMARB_MODE: /* We can't enable/disable these bits of the * 5705, just say success. */ return 0; default: break; } } val = tr32(ofs); val &= ~enable_bit; tw32(ofs, val); tr32(ofs); for (i = 0; i < MAX_WAIT_CNT; i++) { udelay(100); val = tr32(ofs); if ((val & enable_bit) == 0) break; } if (i == MAX_WAIT_CNT) { printf("tg3_stop_block timed out, ofs=%lx enable_bit=%x\n", ofs, enable_bit); return -ENODEV; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -