sky2.c
来自「linux 内核源代码」· C语言 代码 · 共 2,361 行 · 第 1/5 页
C
2,361 行
if (sky2->flow_mode & FC_RX) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); else sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); } gma_write16(hw, port, GM_GP_CTRL, reg); if (hw->flags & SKY2_HW_GIGABIT) gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000); gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv); gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); /* Setup Phy LED's */ ledctrl = PHY_M_LED_PULS_DUR(PULS_170MS); ledover = 0; switch (hw->chip_id) { case CHIP_ID_YUKON_FE: /* on 88E3082 these bits are at 11..9 (shifted left) */ ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) << 1; ctrl = gm_phy_read(hw, port, PHY_MARV_FE_LED_PAR); /* delete ACT LED control bits */ ctrl &= ~PHY_M_FELP_LED1_MSK; /* change ACT LED control to blink mode */ ctrl |= PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_ACT_BL); gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl); break; case CHIP_ID_YUKON_FE_P: /* Enable Link Partner Next Page */ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); ctrl |= PHY_M_PC_ENA_LIP_NP; /* disable Energy Detect and enable scrambler */ ctrl &= ~(PHY_M_PC_ENA_ENE_DT | PHY_M_PC_DIS_SCRAMB); gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); /* set LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED */ ctrl = PHY_M_FELP_LED2_CTRL(LED_PAR_CTRL_ACT_BL) | PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_LINK) | PHY_M_FELP_LED0_CTRL(LED_PAR_CTRL_SPEED); gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl); break; case CHIP_ID_YUKON_XL: pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); /* select page 3 to access LED control register */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); /* set LED Function Control register */ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ PHY_M_LEDC_INIT_CTRL(7) | /* 10 Mbps */ PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */ PHY_M_LEDC_STA0_CTRL(7))); /* 1000 Mbps */ /* set Polarity Control register */ gm_phy_write(hw, port, PHY_MARV_PHY_STAT, (PHY_M_POLC_LS1_P_MIX(4) | PHY_M_POLC_IS0_P_MIX(4) | PHY_M_POLC_LOS_CTRL(2) | PHY_M_POLC_INIT_CTRL(2) | PHY_M_POLC_STA1_CTRL(2) | PHY_M_POLC_STA0_CTRL(2))); /* restore page register */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); break; case CHIP_ID_YUKON_EC_U: case CHIP_ID_YUKON_EX: pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); /* select page 3 to access LED control register */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); /* set LED Function Control register */ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ PHY_M_LEDC_INIT_CTRL(8) | /* 10 Mbps */ PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */ PHY_M_LEDC_STA0_CTRL(7)));/* 1000 Mbps */ /* set Blink Rate in LED Timer Control Register */ gm_phy_write(hw, port, PHY_MARV_INT_MASK, ledctrl | PHY_M_LED_BLINK_RT(BLINK_84MS)); /* restore page register */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); break; default: /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */ ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL; /* turn off the Rx LED (LED_RX) */ ledover &= ~PHY_M_LED_MO_RX; } if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_U_A1) { /* apply fixes in PHY AFE */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255); /* increase differential signal amplitude in 10BASE-T */ gm_phy_write(hw, port, 0x18, 0xaa99); gm_phy_write(hw, port, 0x17, 0x2011); /* fix for IEEE A/B Symmetry failure in 1000BASE-T */ gm_phy_write(hw, port, 0x18, 0xa204); gm_phy_write(hw, port, 0x17, 0x2002); /* set page register to 0 */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0); } else if (hw->chip_id == CHIP_ID_YUKON_FE_P && hw->chip_rev == CHIP_REV_YU_FE2_A0) { /* apply workaround for integrated resistors calibration */ gm_phy_write(hw, port, PHY_MARV_PAGE_ADDR, 17); gm_phy_write(hw, port, PHY_MARV_PAGE_DATA, 0x3f60); } else if (hw->chip_id != CHIP_ID_YUKON_EX) { /* no effect on Yukon-XL */ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { /* turn on 100 Mbps LED (LED_LINK100) */ ledover |= PHY_M_LED_MO_100; } if (ledover) gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); } /* Enable phy interrupt on auto-negotiation complete (or link up) */ if (sky2->autoneg == AUTONEG_ENABLE) gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); else gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);}static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff){ u32 reg1; static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA }; sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); /* Turn on/off phy power saving */ if (onoff) reg1 &= ~phy_power[port]; else reg1 |= phy_power[port]; if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) reg1 |= coma_mode[port]; sky2_pci_write32(hw, PCI_DEV_REG1, reg1); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); sky2_pci_read32(hw, PCI_DEV_REG1); udelay(100);}/* Force a renegotiation */static void sky2_phy_reinit(struct sky2_port *sky2){ spin_lock_bh(&sky2->phy_lock); sky2_phy_init(sky2->hw, sky2->port); spin_unlock_bh(&sky2->phy_lock);}/* Put device in state to listen for Wake On Lan */static void sky2_wol_init(struct sky2_port *sky2){ struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; enum flow_control save_mode; u16 ctrl; u32 reg1; /* Bring hardware out of reset */ sky2_write16(hw, B0_CTST, CS_RST_CLR); sky2_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR); sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR); sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); /* Force to 10/100 * sky2_reset will re-enable on resume */ save_mode = sky2->flow_mode; ctrl = sky2->advertising; sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); sky2->flow_mode = FC_NONE; sky2_phy_power(hw, port, 1); sky2_phy_reinit(sky2); sky2->flow_mode = save_mode; sky2->advertising = ctrl; /* Set GMAC to no flow control and auto update for speed/duplex */ gma_write16(hw, port, GM_GP_CTRL, GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA| GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS); /* Set WOL address */ memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR), sky2->netdev->dev_addr, ETH_ALEN); /* Turn on appropriate WOL control bits */ sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT); ctrl = 0; if (sky2->wol & WAKE_PHY) ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT; else ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT; if (sky2->wol & WAKE_MAGIC) ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT; else ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;; ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT; sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); /* Turn on legacy PCI-Express PME mode */ reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); reg1 |= PCI_Y2_PME_LEGACY; sky2_pci_write32(hw, PCI_DEV_REG1, reg1); /* block receiver */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);}static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port){ struct net_device *dev = hw->dev[port]; if (dev->mtu <= ETH_DATA_LEN) sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_JUMBO_DIS | TX_STFW_ENA); else if (hw->chip_id != CHIP_ID_YUKON_EC_U) sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA | TX_JUMBO_ENA); else { /* set Tx GMAC FIFO Almost Empty Threshold */ sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), (ECU_JUMBO_WM << 16) | ECU_AE_THR); sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_JUMBO_ENA | TX_STFW_DIS); /* Can't do offload because of lack of store/forward */ dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM); }}static void sky2_mac_init(struct sky2_hw *hw, unsigned port){ struct sky2_port *sky2 = netdev_priv(hw->dev[port]); u16 reg; u32 rx_reg; int i; const u8 *addr = hw->dev[port]->dev_addr; sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR); sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0 && port == 1) { /* WA DEV_472 -- looks like crossed wires on port 2 */ /* clear GMAC 1 Control reset */ sky2_write8(hw, SK_REG(0, GMAC_CTRL), GMC_RST_CLR); do { sky2_write8(hw, SK_REG(1, GMAC_CTRL), GMC_RST_SET); sky2_write8(hw, SK_REG(1, GMAC_CTRL), GMC_RST_CLR); } while (gm_phy_read(hw, 1, PHY_MARV_ID0) != PHY_MARV_ID0_VAL || gm_phy_read(hw, 1, PHY_MARV_ID1) != PHY_MARV_ID1_Y2 || gm_phy_read(hw, 1, PHY_MARV_INT_MASK) != 0); } sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC)); /* Enable Transmit FIFO Underrun */ sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK); spin_lock_bh(&sky2->phy_lock); sky2_phy_init(hw, port); spin_unlock_bh(&sky2->phy_lock); /* MIB clear */ reg = gma_read16(hw, port, GM_PHY_ADDR); gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); for (i = GM_MIB_CNT_BASE; i <= GM_MIB_CNT_END; i += 4) gma_read16(hw, port, i); gma_write16(hw, port, GM_PHY_ADDR, reg); /* transmit control */ gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF)); /* receive control reg: unicast + multicast + no FCS */ gma_write16(hw, port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA); /* transmit flow control */ gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff); /* transmit parameter */ gma_write16(hw, port, GM_TX_PARAM, TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) | TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) | TX_IPG_JAM_DATA(TX_IPG_JAM_DEF) | TX_BACK_OFF_LIM(TX_BOF_LIM_DEF)); /* serial mode register */ reg = DATA_BLIND_VAL(DATA_BLIND_DEF) | GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); if (hw->dev[port]->mtu > ETH_DATA_LEN) reg |= GM_SMOD_JUMBO_ENA; gma_write16(hw, port, GM_SERIAL_MODE, reg); /* virtual address for data */ gma_set_addr(hw, port, GM_SRC_ADDR_2L, addr); /* physical address: used for pause frames */ gma_set_addr(hw, port, GM_SRC_ADDR_1L, addr); /* ignore counter overflows */ gma_write16(hw, port, GM_TX_IRQ_MSK, 0); gma_write16(hw, port, GM_RX_IRQ_MSK, 0); gma_write16(hw, port, GM_TR_IRQ_MSK, 0); /* Configure Rx MAC FIFO */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON; if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_FE_P) rx_reg |= GMF_RX_OVER_ON; sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg); if (hw->chip_id == CHIP_ID_YUKON_XL) { /* Hardware errata - clear flush mask */ sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), 0); } else { /* Flush Rx MAC FIFO on any flow control or error */ sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR); } /* Set threshold to 0xa (64 bytes) + 1 to workaround pause bug */ reg = RX_GMF_FL_THR_DEF + 1; /* Another magic mystery workaround from sk98lin */ if (hw->chip_id == CHIP_ID_YUKON_FE_P && hw->chip_rev == CHIP_REV_YU_FE2_A0) reg = 0x178; sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), reg); /* Configure Tx MAC FIFO */ sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); /* On chips without ram buffer, pause is controled by MAC level */ if (sky2_read8(hw, B2_E_0) == 0) { sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); sky2_set_tx_stfwd(hw, port); } if (hw->chip_id == CHIP_ID_YUKON_FE_P && hw->chip_rev == CHIP_REV_YU_FE2_A0) { /* disable dynamic watermark */ reg = sky2_read16(hw, SK_REG(port, TX_GMF_EA)); reg &= ~TX_DYN_WM_ENA; sky2_write16(hw, SK_REG(port, TX_GMF_EA), reg); }}/* Assign Ram Buffer allocation to queue */static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 space){ u32 end; /* convert from K bytes to qwords used for hw register */ start *= 1024/8; space *= 1024/8; end = start + space - 1; sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR); sky2_write32(hw, RB_ADDR(q, RB_START), start); sky2_write32(hw, RB_ADDR(q, RB_END), end); sky2_write32(hw, RB_ADDR(q, RB_WP), start); sky2_write32(hw, RB_ADDR(q, RB_RP), start); if (q == Q_R1 || q == Q_R2) { u32 tp = space - space/4; /* On receive queue's set the thresholds * give receiver priority when > 3/4 full * send pause when down to 2K */ sky2_write32(hw, RB_ADDR(q, RB_RX_UTHP), tp); sky2_write32(hw, RB_ADDR(q, RB_RX_LTHP), space/2); tp = space - 2048/8; sky2_write32(hw, RB_ADDR(q, RB_RX_UTPP), tp); sky2_write32(hw, RB_ADDR(q, RB_RX_LTPP), space/4); } else { /* Enable store & forward on Tx queue's because * Tx FIFO is only 1K on Yukon */ sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_STFWD); } sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_OP_MD); sky2_read8(hw, RB_ADDR(q, RB_CTRL));}/* Setup Bus Memory Interface */static void sky2_qset(struct sky2_hw *hw, u16 q){ sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_RESET); sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_OPER_INIT); sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_FIFO_OP_ON); sky2_write32(hw, Q_ADDR(q, Q_WM), BMU_WM_DEFAULT);}/* Setup prefetch unit registers. This is the interface between * hardware and driver list elements */static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr, u64 addr, u32 last){ sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_RST_CLR); sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_HI), addr >> 32); sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_LO), (u32) addr); sky2_write16(hw, Y2_QADDR(qaddr, PREF_UNIT_LAST_IDX), last); sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_OP_ON); sky2_read32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL));}static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2){ struct sky2_tx_le *le = sky2->tx_le + sky2->tx_prod; sky2->tx_prod = RING_NEXT(sky2->tx_prod, TX_RING_SIZE); le->ctrl = 0; return le;}static void tx_init(struct sky2_port *sky2){ struct sky2_tx_le *le; sky2->tx_prod = sky2->tx_cons = 0; sky2->tx_tcpsum = 0; sky2->tx_last_mss = 0; le = get_tx_le(sky2);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?