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 + -
显示快捷键?