Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f574b35 authored by Jie Yang's avatar Jie Yang Committed by David S. Miller
Browse files

atl1c: Add AR8151 v2 support and change L0s/L1 routine



Add AR8151 v2.0 Gigabit 1000 support
Change jumbo frame size to 6K
Update L0s/L1 rountine
        when link speed is 100M or 1G, set L1 link timer to 4 for l1d_2 and l2c_b2
        set L1 link timer to 7 for l2c_b, set L1 link timer to 0xF for others.
Update atl1c_suspend routine
	just refactory the function, add atl1c_phy_power_saving routine,
	when Wake On Lan enable, this func will be called to save power,
	it will reautoneg PHY to 10/100M speed depend on the link
	partners link capability.
Update atl1c_configure_des_ring
        do not use l2c_b default SRAM configuration.

Signed-off-by: default avatarJie Yang <Jie.Yang@atheros.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent aac4dddc
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -73,7 +73,8 @@
#define FULL_DUPLEX        2

#define AT_RX_BUF_SIZE		(ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)
#define MAX_JUMBO_FRAME_SIZE 	(9*1024)
#define MAX_JUMBO_FRAME_SIZE	(6*1024)
#define MAX_TSO_FRAME_SIZE      (7*1024)
#define MAX_TX_OFFLOAD_THRESH	(9*1024)

#define AT_MAX_RECEIVE_QUEUE    4
@@ -87,10 +88,11 @@
#define AT_MAX_INT_WORK		5
#define AT_TWSI_EEPROM_TIMEOUT 	100
#define AT_HW_MAX_IDLE_DELAY 	10
#define AT_SUSPEND_LINK_TIMEOUT 28
#define AT_SUSPEND_LINK_TIMEOUT 100

#define AT_ASPM_L0S_TIMER	6
#define AT_ASPM_L1_TIMER	12
#define AT_LCKDET_TIMER		12

#define ATL1C_PCIE_L0S_L1_DISABLE 	0x01
#define ATL1C_PCIE_PHY_RESET		0x02
@@ -316,6 +318,7 @@ enum atl1c_nic_type {
	athr_l2c_b,
	athr_l2c_b2,
	athr_l1d,
	athr_l1d_2,
};

enum atl1c_trans_queue {
@@ -392,6 +395,8 @@ struct atl1c_hw {
	u16 subsystem_id;
	u16 subsystem_vendor_id;
	u8 revision_id;
	u16 phy_id1;
	u16 phy_id2;

	u32 intr_mask;
	u8 dmaw_dly_cnt;
+92 −15
Original line number Diff line number Diff line
@@ -37,6 +37,9 @@ int atl1c_check_eeprom_exist(struct atl1c_hw *hw)
	if (data & TWSI_DEBUG_DEV_EXIST)
		return 1;

	AT_READ_REG(hw, REG_MASTER_CTRL, &data);
	if (data & MASTER_CTRL_OTP_SEL)
		return 1;
	return 0;
}

@@ -69,6 +72,8 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
	u32 i;
	u32 otp_ctrl_data;
	u32 twsi_ctrl_data;
	u32 ltssm_ctrl_data;
	u32 wol_data;
	u8  eth_addr[ETH_ALEN];
	u16 phy_data;
	bool raise_vol = false;
@@ -104,6 +109,15 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
			udelay(20);
			raise_vol = true;
		}
		/* close open bit of ReadOnly*/
		AT_READ_REG(hw, REG_LTSSM_ID_CTRL, &ltssm_ctrl_data);
		ltssm_ctrl_data &= ~LTSSM_ID_EN_WRO;
		AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, ltssm_ctrl_data);

		/* clear any WOL settings */
		AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
		AT_READ_REG(hw, REG_WOL_CTRL, &wol_data);


		AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
		twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
@@ -119,17 +133,15 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
	}
	/* Disable OTP_CLK */
	if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) {
		if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
		otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
		AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
			AT_WRITE_FLUSH(hw);
		msleep(1);
	}
	}
	if (raise_vol) {
		if (hw->nic_type == athr_l2c_b ||
		    hw->nic_type == athr_l2c_b2 ||
		    hw->nic_type == athr_l1d) {
		    hw->nic_type == athr_l1d ||
		    hw->nic_type == athr_l1d_2) {
			atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
			if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
				goto out;
@@ -456,14 +468,22 @@ int atl1c_phy_reset(struct atl1c_hw *hw)

	if (hw->nic_type == athr_l2c_b ||
	    hw->nic_type == athr_l2c_b2 ||
	    hw->nic_type == athr_l1d) {
	    hw->nic_type == athr_l1d ||
	    hw->nic_type == athr_l1d_2) {
		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
		atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
		atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7);
		msleep(20);
	}

	/*Enable PHY LinkChange Interrupt */
	if (hw->nic_type == athr_l1d) {
		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
		atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x929D);
	}
	if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b2
		|| hw->nic_type == athr_l2c || hw->nic_type == athr_l2c) {
		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
		atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
	}
	err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
	if (err) {
		if (netif_msg_hw(adapter))
@@ -482,11 +502,9 @@ int atl1c_phy_init(struct atl1c_hw *hw)
	struct pci_dev *pdev = adapter->pdev;
	int ret_val;
	u16 mii_bmcr_data = BMCR_RESET;
	u16 phy_id1, phy_id2;

	if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &phy_id1) != 0) ||
		(atl1c_read_phy_reg(hw, MII_PHYSID2, &phy_id2) != 0)) {
			if (netif_msg_link(adapter))
	if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) ||
		(atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) {
		dev_err(&pdev->dev, "Error get phy ID\n");
		return -1;
	}
@@ -572,6 +590,65 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
	return 0;
}

int atl1c_phy_power_saving(struct atl1c_hw *hw)
{
	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
	struct pci_dev *pdev = adapter->pdev;
	int ret = 0;
	u16 autoneg_advertised = ADVERTISED_10baseT_Half;
	u16 save_autoneg_advertised;
	u16 phy_data;
	u16 mii_lpa_data;
	u16 speed = SPEED_0;
	u16 duplex = FULL_DUPLEX;
	int i;

	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
	if (phy_data & BMSR_LSTATUS) {
		atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data);
		if (mii_lpa_data & LPA_10FULL)
			autoneg_advertised = ADVERTISED_10baseT_Full;
		else if (mii_lpa_data & LPA_10HALF)
			autoneg_advertised = ADVERTISED_10baseT_Half;
		else if (mii_lpa_data & LPA_100HALF)
			autoneg_advertised = ADVERTISED_100baseT_Half;
		else if (mii_lpa_data & LPA_100FULL)
			autoneg_advertised = ADVERTISED_100baseT_Full;

		save_autoneg_advertised = hw->autoneg_advertised;
		hw->phy_configured = false;
		hw->autoneg_advertised = autoneg_advertised;
		if (atl1c_restart_autoneg(hw) != 0) {
			dev_dbg(&pdev->dev, "phy autoneg failed\n");
			ret = -1;
		}
		hw->autoneg_advertised = save_autoneg_advertised;

		if (mii_lpa_data) {
			for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
				mdelay(100);
				atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
				atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
				if (phy_data & BMSR_LSTATUS) {
					if (atl1c_get_speed_and_duplex(hw, &speed,
									&duplex) != 0)
						dev_dbg(&pdev->dev,
							"get speed and duplex failed\n");
					break;
				}
			}
		}
	} else {
		speed = SPEED_10;
		duplex = HALF_DUPLEX;
	}
	adapter->link_speed = speed;
	adapter->link_duplex = duplex;

	return ret;
}

int atl1c_restart_autoneg(struct atl1c_hw *hw)
{
	int err = 0;
+46 −3
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value);
int atl1c_phy_init(struct atl1c_hw *hw);
int atl1c_check_eeprom_exist(struct atl1c_hw *hw);
int atl1c_restart_autoneg(struct atl1c_hw *hw);

int atl1c_phy_power_saving(struct atl1c_hw *hw);
/* register definition */
#define REG_DEVICE_CAP              	0x5C
#define DEVICE_CAP_MAX_PAYLOAD_MASK     0x7
@@ -120,6 +120,12 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define REG_PCIE_PHYMISC	    	0x1000
#define PCIE_PHYMISC_FORCE_RCV_DET	0x4

#define REG_PCIE_PHYMISC2		0x1004
#define PCIE_PHYMISC2_SERDES_CDR_MASK	0x3
#define PCIE_PHYMISC2_SERDES_CDR_SHIFT	16
#define PCIE_PHYMISC2_SERDES_TH_MASK	0x3
#define PCIE_PHYMISC2_SERDES_TH_SHIFT	18

#define REG_TWSI_DEBUG			0x1108
#define TWSI_DEBUG_DEV_EXIST		0x20000000

@@ -150,24 +156,28 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define PM_CTRL_ASPM_L0S_EN		0x00001000
#define PM_CTRL_CLK_SWH_L1		0x00002000
#define PM_CTRL_CLK_PWM_VER1_1		0x00004000
#define PM_CTRL_PCIE_RECV		0x00008000
#define PM_CTRL_RCVR_WT_TIMER		0x00008000
#define PM_CTRL_L1_ENTRY_TIMER_MASK	0xF
#define PM_CTRL_L1_ENTRY_TIMER_SHIFT	16
#define PM_CTRL_PM_REQ_TIMER_MASK	0xF
#define PM_CTRL_PM_REQ_TIMER_SHIFT	20
#define PM_CTRL_LCKDET_TIMER_MASK	0x3F
#define PM_CTRL_LCKDET_TIMER_MASK	0xF
#define PM_CTRL_LCKDET_TIMER_SHIFT	24
#define PM_CTRL_EN_BUFS_RX_L0S		0x10000000
#define PM_CTRL_SA_DLY_EN		0x20000000
#define PM_CTRL_MAC_ASPM_CHK		0x40000000
#define PM_CTRL_HOTRST			0x80000000

#define REG_LTSSM_ID_CTRL		0x12FC
#define LTSSM_ID_EN_WRO			0x1000
/* Selene Master Control Register */
#define REG_MASTER_CTRL			0x1400
#define MASTER_CTRL_SOFT_RST            0x1
#define MASTER_CTRL_TEST_MODE_MASK	0x3
#define MASTER_CTRL_TEST_MODE_SHIFT	2
#define MASTER_CTRL_BERT_START		0x10
#define MASTER_CTRL_OOB_DIS_OFF		0x40
#define MASTER_CTRL_SA_TIMER_EN		0x80
#define MASTER_CTRL_MTIMER_EN           0x100
#define MASTER_CTRL_MANUAL_INT          0x200
#define MASTER_CTRL_TX_ITIMER_EN	0x400
@@ -220,6 +230,12 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
		GPHY_CTRL_PWDOWN_HW	|\
		GPHY_CTRL_PHY_IDDQ)

#define GPHY_CTRL_POWER_SAVING (	\
		GPHY_CTRL_SEL_ANA_RST	|\
		GPHY_CTRL_HIB_EN	|\
		GPHY_CTRL_HIB_PULSE	|\
		GPHY_CTRL_PWDOWN_HW	|\
		GPHY_CTRL_PHY_IDDQ)
/* Block IDLE Status Register */
#define REG_IDLE_STATUS  		0x1410
#define IDLE_STATUS_MASK		0x00FF
@@ -287,6 +303,14 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define SERDES_LOCK_DETECT          	0x1  /* SerDes lock detected. This signal
					      * comes from Analog SerDes */
#define SERDES_LOCK_DETECT_EN       	0x2  /* 1: Enable SerDes Lock detect function */
#define SERDES_LOCK_STS_SELFB_PLL_SHIFT 0xE
#define SERDES_LOCK_STS_SELFB_PLL_MASK  0x3
#define SERDES_OVCLK_18_25		0x0
#define SERDES_OVCLK_12_18		0x1
#define SERDES_OVCLK_0_4		0x2
#define SERDES_OVCLK_4_12		0x3
#define SERDES_MAC_CLK_SLOWDOWN		0x20000
#define SERDES_PYH_CLK_SLOWDOWN		0x40000

/* MAC Control Register  */
#define REG_MAC_CTRL         		0x1480
@@ -693,6 +717,21 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define REG_MAC_TX_STATUS_BIN 		0x1760
#define REG_MAC_TX_STATUS_END 		0x17c0

#define REG_CLK_GATING_CTRL		0x1814
#define CLK_GATING_DMAW_EN		0x0001
#define CLK_GATING_DMAR_EN		0x0002
#define CLK_GATING_TXQ_EN		0x0004
#define CLK_GATING_RXQ_EN		0x0008
#define CLK_GATING_TXMAC_EN		0x0010
#define CLK_GATING_RXMAC_EN		0x0020

#define CLK_GATING_EN_ALL	(CLK_GATING_DMAW_EN |\
				 CLK_GATING_DMAR_EN |\
				 CLK_GATING_TXQ_EN  |\
				 CLK_GATING_RXQ_EN  |\
				 CLK_GATING_TXMAC_EN|\
				 CLK_GATING_RXMAC_EN)

/* DEBUG ADDR */
#define REG_DEBUG_DATA0 		0x1900
#define REG_DEBUG_DATA1 		0x1904
@@ -734,6 +773,10 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);

#define MII_PHYSID1			0x02
#define MII_PHYSID2			0x03
#define L1D_MPW_PHYID1			0xD01C  /* V7 */
#define L1D_MPW_PHYID2			0xD01D  /* V1-V6 */
#define L1D_MPW_PHYID3			0xD01E  /* V8 */


/* Autoneg Advertisement Register */
#define MII_ADVERTISE			0x04
+200 −148

File changed.

Preview size limit exceeded, changes collapsed.