From 496c185c9495629ef1c65387cb2594578393cfe0 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Tue, 16 Feb 2010 15:16:45 -0800 Subject: [PATCH] atl1c: Add support for Atheros AR8152 and AR8152 AR8151 is a Gigabit Ethernet device. AR8152 devices are Fast Ethernet devices, there are two revisions, a 1.0 and a 2.0 revision. This has been tested against these devices: Driver Model-name vendor:device Type atl1c AR8131 1969:1063 Gigabit Ethernet atl1c AR8132 1969:1062 Fast Ethernet atl1c AR8151(v1.0) 1969:1073 Gigabit Ethernet atl1c AR8152(v1.1) 1969:2060 Fast Ethernet This device has no hardware available yet so it goes untested, but it should work: atl1c AR8152(v2.0) 1969:2062 Fast Ethernet Signed-off-by: Luis R. Rodriguez Signed-off-by: David S. Miller --- This is in linux-next already. drivers/net/atl1c/atl1c.h | 11 +++- drivers/net/atl1c/atl1c_ethtool.c | 2 +- drivers/net/atl1c/atl1c_hw.c | 83 +++++++++++++++++++++++---- drivers/net/atl1c/atl1c_hw.h | 5 ++ drivers/net/atl1c/atl1c_main.c | 115 +++++++++++++++++++++++++++++++++--- 5 files changed, 191 insertions(+), 25 deletions(-) --- a/drivers/net/atl1c/atl1c.h +++ b/drivers/net/atl1c/atl1c.h @@ -313,6 +313,9 @@ enum atl1c_rss_type { enum atl1c_nic_type { athr_l1c = 0, athr_l2c = 1, + athr_l2c_b, + athr_l2c_b2, + athr_l1d, }; enum atl1c_trans_queue { @@ -426,8 +429,12 @@ struct atl1c_hw { #define ATL1C_ASPM_L1_SUPPORT 0x0100 #define ATL1C_ASPM_CTRL_MON 0x0200 #define ATL1C_HIB_DISABLE 0x0400 -#define ATL1C_LINK_CAP_1000M 0x0800 -#define ATL1C_FPGA_VERSION 0x8000 +#define ATL1C_APS_MODE_ENABLE 0x0800 +#define ATL1C_LINK_EXT_SYNC 0x1000 +#define ATL1C_CLK_GATING_EN 0x2000 +#define ATL1C_FPGA_VERSION 0x8000 + u16 link_cap_flags; +#define ATL1C_LINK_CAP_1000M 0x0001 u16 cmb_tpd; u16 cmb_rrd; u16 cmb_rx_timer; /* 2us resolution */ --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -37,7 +37,7 @@ static int atl1c_get_settings(struct net SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP); - if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M) + if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M) ecmd->supported |= SUPPORTED_1000baseT_Full; ecmd->advertising = ADVERTISED_TP; --- a/drivers/net/atl1c/atl1c_hw.c +++ b/drivers/net/atl1c/atl1c_hw.c @@ -70,17 +70,39 @@ static int atl1c_get_permanent_address(s u32 otp_ctrl_data; u32 twsi_ctrl_data; u8 eth_addr[ETH_ALEN]; + u16 phy_data; + bool raise_vol = false; /* init */ addr[0] = addr[1] = 0; AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data); if (atl1c_check_eeprom_exist(hw)) { - /* Enable OTP CLK */ - 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 (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) { + /* Enable OTP CLK */ + 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 (hw->nic_type == athr_l2c_b || + hw->nic_type == athr_l2c_b2 || + hw->nic_type == athr_l1d) { + atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00); + if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data)) + goto out; + phy_data &= 0xFF7F; + atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data); + + atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B); + if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data)) + goto out; + phy_data |= 0x8; + atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data); + udelay(20); + raise_vol = true; } AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data); @@ -96,11 +118,31 @@ static int atl1c_get_permanent_address(s return -1; } /* Disable OTP_CLK */ - 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 ((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) { + atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00); + if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data)) + goto out; + phy_data |= 0x80; + atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data); + + atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B); + if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data)) + goto out; + phy_data &= 0xFFF7; + atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data); + udelay(20); + } } /* maybe MAC-address is from BIOS */ @@ -114,6 +156,7 @@ static int atl1c_get_permanent_address(s return 0; } +out: return -1; } @@ -307,7 +350,7 @@ static int atl1c_phy_setup_adv(struct at mii_adv_data |= ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL; - if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M) { + if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M) { if (hw->autoneg_advertised & ADVERTISED_1000baseT_Half) mii_giga_ctrl_data |= ADVERTISE_1000HALF; if (hw->autoneg_advertised & ADVERTISED_1000baseT_Full) @@ -389,6 +432,7 @@ int atl1c_phy_reset(struct atl1c_hw *hw) { struct atl1c_adapter *adapter = hw->adapter; struct pci_dev *pdev = adapter->pdev; + u16 phy_data; u32 phy_ctrl_data = GPHY_CTRL_DEFAULT; u32 mii_ier_data = IER_LINK_UP | IER_LINK_DOWN; int err; @@ -404,6 +448,21 @@ int atl1c_phy_reset(struct atl1c_hw *hw) AT_WRITE_FLUSH(hw); msleep(10); + if (hw->nic_type == athr_l2c_b) { + atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x0A); + atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data); + atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xDFFF); + } + + if (hw->nic_type == athr_l2c_b || + hw->nic_type == athr_l2c_b2 || + hw->nic_type == athr_l1d) { + 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 */ err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data); if (err) { --- a/drivers/net/atl1c/atl1c_hw.h +++ b/drivers/net/atl1c/atl1c_hw.h @@ -57,6 +57,7 @@ int atl1c_restart_autoneg(struct atl1c_h #define REG_LINK_CTRL 0x68 #define LINK_CTRL_L0S_EN 0x01 #define LINK_CTRL_L1_EN 0x02 +#define LINK_CTRL_EXT_SYNC 0x80 #define REG_VPD_CAP 0x6C #define VPD_CAP_ID_MASK 0xff @@ -156,6 +157,8 @@ int atl1c_restart_autoneg(struct atl1c_h #define PM_CTRL_PM_REQ_TIMER_SHIFT 20 #define PM_CTRL_LCKDET_TIMER_MASK 0x3F #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 @@ -314,6 +317,8 @@ int atl1c_restart_autoneg(struct atl1c_h #define MAC_CTRL_BC_EN 0x4000000 #define MAC_CTRL_DBG 0x8000000 #define MAC_CTRL_SINGLE_PAUSE_EN 0x10000000 +#define MAC_CTRL_HASH_ALG_CRC32 0x20000000 +#define MAC_CTRL_SPEED_MODE_SW 0x40000000 /* MAC IPG/IFG Control Register */ #define REG_MAC_IPG_IFG 0x1484 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -21,11 +21,18 @@ #include "atl1c.h" -#define ATL1C_DRV_VERSION "1.0.0.1-NAPI" +#define ATL1C_DRV_VERSION "1.0.0.2-NAPI" char atl1c_driver_name[] = "atl1c"; char atl1c_driver_version[] = ATL1C_DRV_VERSION; #define PCI_DEVICE_ID_ATTANSIC_L2C 0x1062 #define PCI_DEVICE_ID_ATTANSIC_L1C 0x1063 +#define PCI_DEVICE_ID_ATHEROS_L2C_B 0x2060 /* AR8152 v1.1 Fast 10/100 */ +#define PCI_DEVICE_ID_ATHEROS_L2C_B2 0x2062 /* AR8152 v2.0 Fast 10/100 */ +#define PCI_DEVICE_ID_ATHEROS_L1D 0x1073 /* AR8151 v1.0 Gigabit 1000 */ + +#define L2CB_V10 0xc0 +#define L2CB_V11 0xc1 + /* * atl1c_pci_tbl - PCI Device ID Table * @@ -38,6 +45,9 @@ char atl1c_driver_version[] = ATL1C_DRV_ static struct pci_device_id atl1c_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)}, {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)}, + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B)}, + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B2)}, + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D)}, /* required last entry */ { 0 } }; @@ -593,11 +603,18 @@ static void atl1c_set_mac_type(struct at case PCI_DEVICE_ID_ATTANSIC_L2C: hw->nic_type = athr_l2c; break; - case PCI_DEVICE_ID_ATTANSIC_L1C: hw->nic_type = athr_l1c; break; - + case PCI_DEVICE_ID_ATHEROS_L2C_B: + hw->nic_type = athr_l2c_b; + break; + case PCI_DEVICE_ID_ATHEROS_L2C_B2: + hw->nic_type = athr_l2c_b2; + break; + case PCI_DEVICE_ID_ATHEROS_L1D: + hw->nic_type = athr_l1d; + break; default: break; } @@ -620,10 +637,13 @@ static int atl1c_setup_mac_funcs(struct hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT; if (link_ctrl_data & LINK_CTRL_L1_EN) hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT; + if (link_ctrl_data & LINK_CTRL_EXT_SYNC) + hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC; - if (hw->nic_type == athr_l1c) { + if (hw->nic_type == athr_l1c || + hw->nic_type == athr_l1d) { hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON; - hw->ctrl_flags |= ATL1C_LINK_CAP_1000M; + hw->link_cap_flags |= ATL1C_LINK_CAP_1000M; } return 0; } @@ -1234,21 +1254,92 @@ static void atl1c_disable_l0s_l1(struct static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup) { u32 pm_ctrl_data; + u32 link_ctrl_data; AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data); - + AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data); pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1; + pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK << PM_CTRL_L1_ENTRY_TIMER_SHIFT); + pm_ctrl_data &= ~(PM_CTRL_LCKDET_TIMER_MASK << + PM_CTRL_LCKDET_TIMER_SHIFT); pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK; + pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; + pm_ctrl_data |= PM_CTRL_RBER_EN; + pm_ctrl_data |= PM_CTRL_SDES_EN; + + if (hw->nic_type == athr_l2c_b || + hw->nic_type == athr_l1d || + hw->nic_type == athr_l2c_b2) { + link_ctrl_data &= ~LINK_CTRL_EXT_SYNC; + if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) { + if (hw->nic_type == athr_l2c_b && + hw->revision_id == L2CB_V10) + link_ctrl_data |= LINK_CTRL_EXT_SYNC; + } + + AT_WRITE_REG(hw, REG_LINK_CTRL, link_ctrl_data); + + pm_ctrl_data |= PM_CTRL_PCIE_RECV; + pm_ctrl_data |= AT_ASPM_L1_TIMER << PM_CTRL_PM_REQ_TIMER_SHIFT; + pm_ctrl_data &= ~PM_CTRL_EN_BUFS_RX_L0S; + pm_ctrl_data &= ~PM_CTRL_SA_DLY_EN; + pm_ctrl_data &= ~PM_CTRL_HOTRST; + pm_ctrl_data |= 1 << PM_CTRL_L1_ENTRY_TIMER_SHIFT; + pm_ctrl_data |= PM_CTRL_SERDES_PD_EX_L1; + } if (linkup) { - pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN; - pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1; + pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; + pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; + if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT) + pm_ctrl_data |= PM_CTRL_ASPM_L1_EN; + if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT) + pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN; + + if (hw->nic_type == athr_l2c_b || + hw->nic_type == athr_l1d || + hw->nic_type == athr_l2c_b2) { + if (hw->nic_type == athr_l2c_b) + if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) + pm_ctrl_data &= PM_CTRL_ASPM_L0S_EN; + pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN; + pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN; + pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN; + pm_ctrl_data |= PM_CTRL_CLK_SWH_L1; + if (hw->adapter->link_speed == SPEED_100 || + hw->adapter->link_speed == SPEED_1000) { + pm_ctrl_data &= + ~(PM_CTRL_L1_ENTRY_TIMER_MASK << + PM_CTRL_L1_ENTRY_TIMER_SHIFT); + if (hw->nic_type == athr_l1d) + pm_ctrl_data |= 0xF << + PM_CTRL_L1_ENTRY_TIMER_SHIFT; + else + pm_ctrl_data |= 7 << + PM_CTRL_L1_ENTRY_TIMER_SHIFT; + } + } else { + pm_ctrl_data |= PM_CTRL_SERDES_L1_EN; + pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN; + pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN; + pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1; + pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; + pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; + } + atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29); + if (hw->adapter->link_speed == SPEED_10) + if (hw->nic_type == athr_l1d) + atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB69D); + else + atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD); + else if (hw->adapter->link_speed == SPEED_100) + atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB2DD); + else + atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x96DD); - pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN; - pm_ctrl_data |= PM_CTRL_SERDES_L1_EN; } else { pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN; pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN; @@ -1302,6 +1393,10 @@ static void atl1c_setup_mac_ctrl(struct mac_ctrl_data |= MAC_CTRL_MC_ALL_EN; mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN; + if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2) { + mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW; + mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32; + } AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); }