diff options
Diffstat (limited to 'drivers/net/ethernet/atheros/atl1c')
| -rw-r--r-- | drivers/net/ethernet/atheros/atl1c/atl1c.h | 11 | ||||
| -rw-r--r-- | drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c | 6 | ||||
| -rw-r--r-- | drivers/net/ethernet/atheros/atl1c/atl1c_hw.c | 153 | ||||
| -rw-r--r-- | drivers/net/ethernet/atheros/atl1c/atl1c_hw.h | 40 | ||||
| -rw-r--r-- | drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 491 |
5 files changed, 432 insertions, 269 deletions
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h index acc2956df90..b9203d92893 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c.h +++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h @@ -22,7 +22,6 @@ #ifndef _ATL1C_H_ #define _ATL1C_H_ -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/types.h> #include <linux/errno.h> @@ -436,6 +435,7 @@ struct atl1c_hw { bool phy_configured; bool re_autoneg; bool emi_ca; + bool msi_lnkpatch; /* link patch for specific platforms */ }; /* @@ -519,6 +519,9 @@ struct atl1c_adapter { struct net_device *netdev; struct pci_dev *pdev; struct napi_struct napi; + struct page *rx_page; + unsigned int rx_page_offset; + unsigned int rx_frag_size; struct atl1c_hw hw; struct atl1c_hw_stats hw_stats; struct mii_if_info mii; /* MII interface info */ @@ -596,7 +599,7 @@ struct atl1c_adapter { extern char atl1c_driver_name[]; extern char atl1c_driver_version[]; -extern void atl1c_reinit_locked(struct atl1c_adapter *adapter); -extern s32 atl1c_reset_hw(struct atl1c_hw *hw); -extern void atl1c_set_ethtool_ops(struct net_device *netdev); +void atl1c_reinit_locked(struct atl1c_adapter *adapter); +s32 atl1c_reset_hw(struct atl1c_hw *hw); +void atl1c_set_ethtool_ops(struct net_device *netdev); #endif /* _ATL1C_H_ */ diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c b/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c index 859ea844ba0..48694c239d5 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c @@ -56,8 +56,8 @@ static int atl1c_get_settings(struct net_device *netdev, else ecmd->duplex = DUPLEX_HALF; } else { - ethtool_cmd_speed_set(ecmd, -1); - ecmd->duplex = -1; + ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN); + ecmd->duplex = DUPLEX_UNKNOWN; } ecmd->autoneg = AUTONEG_ENABLE; @@ -305,5 +305,5 @@ static const struct ethtool_ops atl1c_ethtool_ops = { void atl1c_set_ethtool_ops(struct net_device *netdev) { - SET_ETHTOOL_OPS(netdev, &atl1c_ethtool_ops); + netdev->ethtool_ops = &atl1c_ethtool_ops; } diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c index 07f017f59b3..1cda49a28f7 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c @@ -43,7 +43,7 @@ int atl1c_check_eeprom_exist(struct atl1c_hw *hw) return 0; } -void atl1c_hw_set_mac_addr(struct atl1c_hw *hw) +void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr) { u32 value; /* @@ -51,35 +51,48 @@ void atl1c_hw_set_mac_addr(struct atl1c_hw *hw) * 0: 6AF600DC 1: 000B * low dword */ - value = (((u32)hw->mac_addr[2]) << 24) | - (((u32)hw->mac_addr[3]) << 16) | - (((u32)hw->mac_addr[4]) << 8) | - (((u32)hw->mac_addr[5])) ; + value = mac_addr[2] << 24 | + mac_addr[3] << 16 | + mac_addr[4] << 8 | + mac_addr[5]; AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value); /* hight dword */ - value = (((u32)hw->mac_addr[0]) << 8) | - (((u32)hw->mac_addr[1])) ; + value = mac_addr[0] << 8 | + mac_addr[1]; AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value); } +/* read mac address from hardware register */ +static bool atl1c_read_current_addr(struct atl1c_hw *hw, u8 *eth_addr) +{ + u32 addr[2]; + + AT_READ_REG(hw, REG_MAC_STA_ADDR, &addr[0]); + AT_READ_REG(hw, REG_MAC_STA_ADDR + 4, &addr[1]); + + *(u32 *) ð_addr[2] = htonl(addr[0]); + *(u16 *) ð_addr[0] = htons((u16)addr[1]); + + return is_valid_ether_addr(eth_addr); +} + /* * atl1c_get_permanent_address * return 0 if get valid mac address, */ static int atl1c_get_permanent_address(struct atl1c_hw *hw) { - u32 addr[2]; 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; + /* MAC-address from BIOS is the 1st priority */ + if (atl1c_read_current_addr(hw, hw->perm_mac_addr)) + return 0; + /* init */ - addr[0] = addr[1] = 0; AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data); if (atl1c_check_eeprom_exist(hw)) { if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) { @@ -91,33 +104,17 @@ static int atl1c_get_permanent_address(struct atl1c_hw *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); + /* raise voltage temporally for l2cb */ + if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) { + atl1c_read_phy_dbg(hw, MIIDBG_ANACTRL, &phy_data); + phy_data &= ~ANACTRL_HB_EN; + atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, phy_data); + atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data); + phy_data |= VOLT_CTRL_SWLOWEST; + atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data); udelay(20); raise_vol = true; } - /* close open bit of ReadOnly*/ - AT_READ_REG(hw, REG_LTSSM_ID_CTRL, <ssm_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; @@ -138,44 +135,25 @@ static int atl1c_get_permanent_address(struct atl1c_hw *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_2) { - 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); - } + atl1c_read_phy_dbg(hw, MIIDBG_ANACTRL, &phy_data); + phy_data |= ANACTRL_HB_EN; + atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, phy_data); + atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data); + phy_data &= ~VOLT_CTRL_SWLOWEST; + atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data); + udelay(20); } - /* maybe MAC-address is from BIOS */ - AT_READ_REG(hw, REG_MAC_STA_ADDR, &addr[0]); - AT_READ_REG(hw, REG_MAC_STA_ADDR + 4, &addr[1]); - *(u32 *) ð_addr[2] = swab32(addr[0]); - *(u16 *) ð_addr[0] = swab16(*(u16 *)&addr[1]); - - if (is_valid_ether_addr(eth_addr)) { - memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + if (atl1c_read_current_addr(hw, hw->perm_mac_addr)) return 0; - } -out: return -1; } bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value) { int i; - int ret = false; + bool ret = false; u32 otp_ctrl_data; u32 control; u32 data; @@ -221,7 +199,7 @@ int atl1c_read_mac_addr(struct atl1c_hw *hw) err = atl1c_get_permanent_address(hw); if (err) - random_ether_addr(hw->perm_mac_addr); + eth_random_addr(hw->perm_mac_addr); memcpy(hw->mac_addr, hw->perm_mac_addr, sizeof(hw->perm_mac_addr)); return err; @@ -624,7 +602,7 @@ int atl1c_phy_reset(struct atl1c_hw *hw) int atl1c_phy_init(struct atl1c_hw *hw) { - struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; + struct atl1c_adapter *adapter = hw->adapter; struct pci_dev *pdev = adapter->pdev; int ret_val; u16 mii_bmcr_data = BMCR_RESET; @@ -718,7 +696,7 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex) /* select one link mode to get lower power consumption */ int atl1c_phy_to_ps_link(struct atl1c_hw *hw) { - struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; + struct atl1c_adapter *adapter = hw->adapter; struct pci_dev *pdev = adapter->pdev; int ret = 0; u16 autoneg_advertised = ADVERTISED_10baseT_Half; @@ -790,7 +768,7 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw) int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc) { - struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; + struct atl1c_adapter *adapter = hw->adapter; struct pci_dev *pdev = adapter->pdev; u32 master_ctrl, mac_ctrl, phy_ctrl; u32 wol_ctrl, speed; @@ -832,7 +810,7 @@ int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc) if (wufc & AT_WUFC_LNKC) { wol_ctrl |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN; if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) { - dev_dbg(&pdev->dev, "%s: write phy MII_IER faild.\n", + dev_dbg(&pdev->dev, "%s: write phy MII_IER failed.\n", atl1c_driver_name); } } @@ -848,3 +826,40 @@ int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc) return 0; } + + +/* configure phy after Link change Event */ +void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed) +{ + u16 phy_val; + bool adj_thresh = false; + + if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2 || + hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2) + adj_thresh = true; + + if (link_speed != SPEED_0) { /* link up */ + /* az with brcm, half-amp */ + if (hw->nic_type == athr_l1d_2) { + atl1c_read_phy_ext(hw, MIIEXT_PCS, MIIEXT_CLDCTRL6, + &phy_val); + phy_val = FIELD_GETX(phy_val, CLDCTRL6_CAB_LEN); + phy_val = phy_val > CLDCTRL6_CAB_LEN_SHORT ? + AZ_ANADECT_LONG : AZ_ANADECT_DEF; + atl1c_write_phy_dbg(hw, MIIDBG_AZ_ANADECT, phy_val); + } + /* threshold adjust */ + if (adj_thresh && link_speed == SPEED_100 && hw->msi_lnkpatch) { + atl1c_write_phy_dbg(hw, MIIDBG_MSE16DB, L1D_MSE16DB_UP); + atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL, + L1D_SYSMODCTRL_IECHOADJ_DEF); + } + } else { /* link down */ + if (adj_thresh && hw->msi_lnkpatch) { + atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL, + SYSMODCTRL_IECHOADJ_DEF); + atl1c_write_phy_dbg(hw, MIIDBG_MSE16DB, + L1D_MSE16DB_DOWN); + } + } +} diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h index 0adb3413133..21d8c4dbdbe 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h @@ -36,7 +36,7 @@ struct atl1c_hw; /* function prototype */ void atl1c_phy_disable(struct atl1c_hw *hw); -void atl1c_hw_set_mac_addr(struct atl1c_hw *hw); +void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr); int atl1c_phy_reset(struct atl1c_hw *hw); int atl1c_read_mac_addr(struct atl1c_hw *hw); int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex); @@ -63,6 +63,7 @@ int atl1c_write_phy_ext(struct atl1c_hw *hw, u8 dev_addr, u16 reg_addr, u16 phy_data); int atl1c_read_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data); int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data); +void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed); /* hw-ids */ #define PCI_DEVICE_ID_ATTANSIC_L2C 0x1062 @@ -73,6 +74,8 @@ int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data); #define PCI_DEVICE_ID_ATHEROS_L1D_2_0 0x1083 /* AR8151 v2.0 Gigabit 1000 */ #define L2CB_V10 0xc0 #define L2CB_V11 0xc1 +#define L2CB_V20 0xc0 +#define L2CB_V21 0xc1 /* register definition */ #define REG_DEVICE_CAP 0x5C @@ -86,6 +89,9 @@ int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data); #define LINK_CTRL_L1_EN 0x02 #define LINK_CTRL_EXT_SYNC 0x80 +#define REG_PCIE_IND_ACC_ADDR 0x80 +#define REG_PCIE_IND_ACC_DATA 0x84 + #define REG_DEV_SERIALNUM_CTRL 0x200 #define REG_DEV_MAC_SEL_MASK 0x0 /* 0:EUI; 1:MAC */ #define REG_DEV_MAC_SEL_SHIFT 0 @@ -93,25 +99,17 @@ int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data); #define REG_DEV_SERIAL_NUM_EN_SHIFT 1 #define REG_TWSI_CTRL 0x218 +#define TWSI_CTLR_FREQ_MASK 0x3UL +#define TWSI_CTRL_FREQ_SHIFT 24 +#define TWSI_CTRL_FREQ_100K 0 +#define TWSI_CTRL_FREQ_200K 1 +#define TWSI_CTRL_FREQ_300K 2 +#define TWSI_CTRL_FREQ_400K 3 +#define TWSI_CTRL_LD_EXIST BIT(23) +#define TWSI_CTRL_HW_LDSTAT BIT(12) /* 0:finish,1:in progress */ +#define TWSI_CTRL_SW_LDSTART BIT(11) #define TWSI_CTRL_LD_OFFSET_MASK 0xFF #define TWSI_CTRL_LD_OFFSET_SHIFT 0 -#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7 -#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8 -#define TWSI_CTRL_SW_LDSTART 0x800 -#define TWSI_CTRL_HW_LDSTART 0x1000 -#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F -#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15 -#define TWSI_CTRL_LD_EXIST 0x400000 -#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3 -#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23 -#define TWSI_CTRL_FREQ_SEL_100K 0 -#define TWSI_CTRL_FREQ_SEL_200K 1 -#define TWSI_CTRL_FREQ_SEL_300K 2 -#define TWSI_CTRL_FREQ_SEL_400K 3 -#define TWSI_CTRL_SMB_SLV_ADDR -#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3 -#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24 - #define REG_PCIE_DEV_MISC_CTRL 0x21C #define PCIE_DEV_MISC_EXT_PIPE 0x2 @@ -134,7 +132,7 @@ int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data); #define L2CB1_PCIE_PHYMISC2_CDR_BW 3 #define REG_TWSI_DEBUG 0x1108 -#define TWSI_DEBUG_DEV_EXIST 0x20000000 +#define TWSI_DEBUG_DEV_EXIST BIT(29) #define REG_DMA_DBG 0x1114 #define DMA_DBG_VENDOR_MSG BIT(0) @@ -150,7 +148,7 @@ int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data); #define REG_EEPROM_DATA_LO 0x12C4 #define REG_OTP_CTRL 0x12F0 -#define OTP_CTRL_CLK_EN 0x0002 +#define OTP_CTRL_CLK_EN BIT(1) #define REG_PM_CTRL 0x12F8 #define PM_CTRL_HOTRST BIT(31) @@ -164,7 +162,7 @@ int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data); #define PM_CTRL_PM_REQ_TIMER_MASK 0xFUL #define PM_CTRL_PM_REQ_TIMER_SHIFT 20 /* pm_request_l1 time > @ * ->L0s not L1 */ -#define PM_CTRL_PM_REQ_TO_DEF 0xC +#define PM_CTRL_PM_REQ_TO_DEF 0xF #define PMCTRL_TXL1_AFTER_L0S BIT(19) /* l1dv2.0+ */ #define L1D_PMCTRL_L1_ENTRY_TM_MASK 7UL /* l1dv2.0+, 3bits */ #define L1D_PMCTRL_L1_ENTRY_TM_SHIFT 16 diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 25b7b009849..e11bf18fbbd 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -21,7 +21,7 @@ #include "atl1c.h" -#define ATL1C_DRV_VERSION "1.0.1.0-NAPI" +#define ATL1C_DRV_VERSION "1.0.1.1-NAPI" char atl1c_driver_name[] = "atl1c"; char atl1c_driver_version[] = ATL1C_DRV_VERSION; @@ -60,6 +60,10 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, int *work_done, int work_to_do); static int atl1c_up(struct atl1c_adapter *adapter); static void atl1c_down(struct atl1c_adapter *adapter); +static int atl1c_reset_mac(struct atl1c_hw *hw); +static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter); +static int atl1c_configure(struct atl1c_adapter *adapter); +static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter); static const u16 atl1c_pay_load_size[] = { 128, 256, 512, 1024, 2048, 4096, @@ -133,16 +137,21 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag) */ pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); + /* wol sts read-clear */ + AT_READ_REG(hw, REG_WOL_CTRL, &data); + AT_WRITE_REG(hw, REG_WOL_CTRL, 0); /* * Mask some pcie error bits */ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); - pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, &data); - data &= ~(PCI_ERR_UNC_DLP | PCI_ERR_UNC_FCP); - pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, data); + if (pos) { + pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, &data); + data &= ~(PCI_ERR_UNC_DLP | PCI_ERR_UNC_FCP); + pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, data); + } /* clear error status */ - pci_write_config_word(pdev, pci_pcie_cap(pdev) + PCI_EXP_DEVSTA, + pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_NFED | PCI_EXP_DEVSTA_FED | PCI_EXP_DEVSTA_CED | @@ -159,7 +168,7 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag) msleep(5); } -/* +/** * atl1c_irq_enable - Enable default interrupt generation settings * @adapter: board private structure */ @@ -172,7 +181,7 @@ static inline void atl1c_irq_enable(struct atl1c_adapter *adapter) } } -/* +/** * atl1c_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure */ @@ -185,7 +194,7 @@ static inline void atl1c_irq_disable(struct atl1c_adapter *adapter) synchronize_irq(adapter->pdev->irq); } -/* +/** * atl1c_irq_reset - reset interrupt confiure on the NIC * @adapter: board private structure */ @@ -213,7 +222,7 @@ static u32 atl1c_wait_until_idle(struct atl1c_hw *hw, u32 modu_ctrl) return data; } -/* +/** * atl1c_phy_config - Timer Call-back * @data: pointer to netdev cast into an unsigned long */ @@ -253,13 +262,15 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) if ((phy_data & BMSR_LSTATUS) == 0) { /* link down */ + netif_carrier_off(netdev); hw->hibernate = true; - if (atl1c_stop_mac(hw) != 0) + if (atl1c_reset_mac(hw) != 0) if (netif_msg_hw(adapter)) - dev_warn(&pdev->dev, "stop mac failed\n"); + dev_warn(&pdev->dev, "reset mac failed\n"); atl1c_set_aspm(hw, SPEED_0); - netif_carrier_off(netdev); - netif_stop_queue(netdev); + atl1c_post_phy_linkchg(hw, SPEED_0); + atl1c_reset_dma_ring(adapter); + atl1c_configure(adapter); } else { /* Link Up */ hw->hibernate = false; @@ -274,6 +285,7 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) adapter->link_speed = speed; adapter->link_duplex = duplex; atl1c_set_aspm(hw, speed); + atl1c_post_phy_linkchg(hw, speed); atl1c_start_mac(adapter); if (netif_msg_link(adapter)) dev_info(&pdev->dev, @@ -325,6 +337,9 @@ static void atl1c_common_task(struct work_struct *work) adapter = container_of(work, struct atl1c_adapter, common_task); netdev = adapter->netdev; + if (test_bit(__AT_DOWN, &adapter->flags)) + return; + if (test_and_clear_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event)) { netif_device_detach(netdev); atl1c_down(adapter); @@ -333,8 +348,11 @@ static void atl1c_common_task(struct work_struct *work) } if (test_and_clear_bit(ATL1C_WORK_EVENT_LINK_CHANGE, - &adapter->work_event)) + &adapter->work_event)) { + atl1c_irq_disable(adapter); atl1c_check_link_status(adapter); + atl1c_irq_enable(adapter); + } } @@ -344,7 +362,7 @@ static void atl1c_del_timer(struct atl1c_adapter *adapter) } -/* +/** * atl1c_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure */ @@ -357,7 +375,7 @@ static void atl1c_tx_timeout(struct net_device *netdev) schedule_work(&adapter->common_task); } -/* +/** * atl1c_set_multi - Multicast and Promiscuous mode set * @netdev: network interface device structure * @@ -401,7 +419,7 @@ static void atl1c_set_multi(struct net_device *netdev) static void __atl1c_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data) { - if (features & NETIF_F_HW_VLAN_RX) { + if (features & NETIF_F_HW_VLAN_CTAG_RX) { /* enable VLAN tag insert/strip */ *mac_ctrl_data |= MAC_CTRL_RMV_VLAN; } else { @@ -436,7 +454,7 @@ static void atl1c_restore_vlan(struct atl1c_adapter *adapter) atl1c_vlan_mode(adapter->netdev, adapter->netdev->features); } -/* +/** * atl1c_set_mac - Change the Ethernet Address of the NIC * @netdev: network interface device structure * @p: pointer to an address structure @@ -456,9 +474,8 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p) memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); - netdev->addr_assign_type &= ~NET_ADDR_RANDOM; - atl1c_hw_set_mac_addr(&adapter->hw); + atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr); return 0; } @@ -466,10 +483,15 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p) static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter, struct net_device *dev) { + unsigned int head_size; int mtu = dev->mtu; adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ? roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE; + + head_size = SKB_DATA_ALIGN(adapter->rx_buffer_len + NET_SKB_PAD) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + adapter->rx_frag_size = roundup_pow_of_two(head_size); } static netdev_features_t atl1c_fix_features(struct net_device *netdev, @@ -479,10 +501,10 @@ static netdev_features_t atl1c_fix_features(struct net_device *netdev, * Since there is no support for separate rx/tx vlan accel * enable/disable make sure tx flag is always in same state as rx. */ - if (features & NETIF_F_HW_VLAN_RX) - features |= NETIF_F_HW_VLAN_TX; + if (features & NETIF_F_HW_VLAN_CTAG_RX) + features |= NETIF_F_HW_VLAN_CTAG_TX; else - features &= ~NETIF_F_HW_VLAN_TX; + features &= ~NETIF_F_HW_VLAN_CTAG_TX; if (netdev->mtu > MAX_TSO_FRAME_SIZE) features &= ~(NETIF_F_TSO | NETIF_F_TSO6); @@ -495,13 +517,13 @@ static int atl1c_set_features(struct net_device *netdev, { netdev_features_t changed = netdev->features ^ features; - if (changed & NETIF_F_HW_VLAN_RX) + if (changed & NETIF_F_HW_VLAN_CTAG_RX) atl1c_vlan_mode(netdev, features); return 0; } -/* +/** * atl1c_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure * @new_mtu: new value for maximum frame size @@ -536,14 +558,6 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu) netdev_update_features(netdev); atl1c_up(adapter); clear_bit(__AT_RESETTING, &adapter->flags); - if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) { - u32 phy_data; - - AT_READ_REG(&adapter->hw, 0x1414, &phy_data); - phy_data |= 0x10000000; - AT_WRITE_REG(&adapter->hw, 0x1414, phy_data); - } - } return 0; } @@ -568,12 +582,6 @@ static void atl1c_mdio_write(struct net_device *netdev, int phy_id, atl1c_write_phy_reg(&adapter->hw, reg_num, val); } -/* - * atl1c_mii_ioctl - - * @netdev: - * @ifreq: - * @cmd: - */ static int atl1c_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { @@ -624,12 +632,6 @@ out: return retval; } -/* - * atl1c_ioctl - - * @netdev: - * @ifreq: - * @cmd: - */ static int atl1c_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { switch (cmd) { @@ -642,12 +644,12 @@ static int atl1c_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } } -/* +/** * atl1c_alloc_queues - Allocate memory for all rings * @adapter: board private structure to initialize * */ -static int __devinit atl1c_alloc_queues(struct atl1c_adapter *adapter) +static int atl1c_alloc_queues(struct atl1c_adapter *adapter) { return 0; } @@ -697,7 +699,70 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw) hw->link_cap_flags |= ATL1C_LINK_CAP_1000M; return 0; } -/* + +struct atl1c_platform_patch { + u16 pci_did; + u8 pci_revid; + u16 subsystem_vid; + u16 subsystem_did; + u32 patch_flag; +#define ATL1C_LINK_PATCH 0x1 +}; +static const struct atl1c_platform_patch plats[] = { +{0x2060, 0xC1, 0x1019, 0x8152, 0x1}, +{0x2060, 0xC1, 0x1019, 0x2060, 0x1}, +{0x2060, 0xC1, 0x1019, 0xE000, 0x1}, +{0x2062, 0xC0, 0x1019, 0x8152, 0x1}, +{0x2062, 0xC0, 0x1019, 0x2062, 0x1}, +{0x2062, 0xC0, 0x1458, 0xE000, 0x1}, +{0x2062, 0xC1, 0x1019, 0x8152, 0x1}, +{0x2062, 0xC1, 0x1019, 0x2062, 0x1}, +{0x2062, 0xC1, 0x1458, 0xE000, 0x1}, +{0x2062, 0xC1, 0x1565, 0x2802, 0x1}, +{0x2062, 0xC1, 0x1565, 0x2801, 0x1}, +{0x1073, 0xC0, 0x1019, 0x8151, 0x1}, +{0x1073, 0xC0, 0x1019, 0x1073, 0x1}, +{0x1073, 0xC0, 0x1458, 0xE000, 0x1}, +{0x1083, 0xC0, 0x1458, 0xE000, 0x1}, +{0x1083, 0xC0, 0x1019, 0x8151, 0x1}, +{0x1083, 0xC0, 0x1019, 0x1083, 0x1}, +{0x1083, 0xC0, 0x1462, 0x7680, 0x1}, +{0x1083, 0xC0, 0x1565, 0x2803, 0x1}, +{0}, +}; + +static void atl1c_patch_assign(struct atl1c_hw *hw) +{ + struct pci_dev *pdev = hw->adapter->pdev; + u32 misc_ctrl; + int i = 0; + + hw->msi_lnkpatch = false; + + while (plats[i].pci_did != 0) { + if (plats[i].pci_did == hw->device_id && + plats[i].pci_revid == hw->revision_id && + plats[i].subsystem_vid == hw->subsystem_vendor_id && + plats[i].subsystem_did == hw->subsystem_id) { + if (plats[i].patch_flag & ATL1C_LINK_PATCH) + hw->msi_lnkpatch = true; + } + i++; + } + + if (hw->device_id == PCI_DEVICE_ID_ATHEROS_L2C_B2 && + hw->revision_id == L2CB_V21) { + /* config acess mode */ + pci_write_config_dword(pdev, REG_PCIE_IND_ACC_ADDR, + REG_PCIE_DEV_MISC_CTRL); + pci_read_config_dword(pdev, REG_PCIE_IND_ACC_DATA, &misc_ctrl); + misc_ctrl &= ~0x100; + pci_write_config_dword(pdev, REG_PCIE_IND_ACC_ADDR, + REG_PCIE_DEV_MISC_CTRL); + pci_write_config_dword(pdev, REG_PCIE_IND_ACC_DATA, misc_ctrl); + } +} +/** * atl1c_sw_init - Initialize general software structures (struct atl1c_adapter) * @adapter: board private structure to initialize * @@ -705,7 +770,7 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw) * Fields are initialized based on PCI device information and * OS network device settings (MTU size). */ -static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) +static int atl1c_sw_init(struct atl1c_adapter *adapter) { struct atl1c_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; @@ -723,7 +788,7 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) hw->device_id = pdev->device; hw->subsystem_vendor_id = pdev->subsystem_vendor; hw->subsystem_id = pdev->subsystem_device; - AT_READ_REG(hw, PCI_CLASS_REVISION, &revision); + pci_read_config_dword(pdev, PCI_CLASS_REVISION, &revision); hw->revision_id = revision & 0xFF; /* before link up, we assume hibernate is true */ hw->hibernate = true; @@ -732,6 +797,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) dev_err(&pdev->dev, "set mac function pointers failed\n"); return -1; } + atl1c_patch_assign(hw); + hw->intr_mask = IMR_NORMAL_MASK; hw->phy_configured = false; hw->preamble_len = 7; @@ -765,7 +832,7 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) } static inline void atl1c_clean_buffer(struct pci_dev *pdev, - struct atl1c_buffer *buffer_info, int in_irq) + struct atl1c_buffer *buffer_info) { u16 pci_driection; if (buffer_info->flags & ATL1C_BUFFER_FREE) @@ -783,17 +850,13 @@ static inline void atl1c_clean_buffer(struct pci_dev *pdev, pci_unmap_page(pdev, buffer_info->dma, buffer_info->length, pci_driection); } - if (buffer_info->skb) { - if (in_irq) - dev_kfree_skb_irq(buffer_info->skb); - else - dev_kfree_skb(buffer_info->skb); - } + if (buffer_info->skb) + dev_consume_skb_any(buffer_info->skb); buffer_info->dma = 0; buffer_info->skb = NULL; ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE); } -/* +/** * atl1c_clean_tx_ring - Free Tx-skb * @adapter: board private structure */ @@ -808,7 +871,7 @@ static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter, ring_count = tpd_ring->count; for (index = 0; index < ring_count; index++) { buffer_info = &tpd_ring->buffer_info[index]; - atl1c_clean_buffer(pdev, buffer_info, 0); + atl1c_clean_buffer(pdev, buffer_info); } /* Zero out Tx-buffers */ @@ -818,7 +881,7 @@ static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter, tpd_ring->next_to_use = 0; } -/* +/** * atl1c_clean_rx_ring - Free rx-reservation skbs * @adapter: board private structure */ @@ -832,7 +895,7 @@ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter) for (j = 0; j < rfd_ring->count; j++) { buffer_info = &rfd_ring->buffer_info[j]; - atl1c_clean_buffer(pdev, buffer_info, 0); + atl1c_clean_buffer(pdev, buffer_info); } /* zero out the descriptor ring */ memset(rfd_ring->desc, 0, rfd_ring->size); @@ -871,7 +934,7 @@ static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter) } } -/* +/** * atl1c_free_ring_resources - Free Tx / RX descriptor Resources * @adapter: board private structure * @@ -892,9 +955,13 @@ static void atl1c_free_ring_resources(struct atl1c_adapter *adapter) kfree(adapter->tpd_ring[0].buffer_info); adapter->tpd_ring[0].buffer_info = NULL; } + if (adapter->rx_page) { + put_page(adapter->rx_page); + adapter->rx_page = NULL; + } } -/* +/** * atl1c_setup_mem_resources - allocate Tx / RX descriptor resources * @adapter: board private structure * @@ -922,19 +989,17 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) size = sizeof(struct atl1c_buffer) * (tpd_ring->count * 2 + rfd_ring->count); tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL); - if (unlikely(!tpd_ring->buffer_info)) { - dev_err(&pdev->dev, "kzalloc failed, size = %d\n", - size); + if (unlikely(!tpd_ring->buffer_info)) goto err_nomem; - } + for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) { tpd_ring[i].buffer_info = - (struct atl1c_buffer *) (tpd_ring->buffer_info + count); + (tpd_ring->buffer_info + count); count += tpd_ring[i].count; } rfd_ring->buffer_info = - (struct atl1c_buffer *) (tpd_ring->buffer_info + count); + (tpd_ring->buffer_info + count); count += rfd_ring->count; rx_desc_count += rfd_ring->count; @@ -1167,13 +1232,10 @@ static void atl1c_start_mac(struct atl1c_adapter *adapter) */ static int atl1c_reset_mac(struct atl1c_hw *hw) { - struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; + struct atl1c_adapter *adapter = hw->adapter; struct pci_dev *pdev = adapter->pdev; u32 ctrl_data = 0; - AT_WRITE_REG(hw, REG_IMR, 0); - AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT); - atl1c_stop_mac(hw); /* * Issue Soft Reset to the MAC. This will reset the chip's @@ -1261,7 +1323,7 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed) } /* L0S/L1 enable */ - if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT) + if ((hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT) && link_speed != SPEED_0) pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN | PM_CTRL_MAC_ASPM_CHK; if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT) pm_ctrl_data |= PM_CTRL_ASPM_L1_EN | PM_CTRL_MAC_ASPM_CHK; @@ -1306,13 +1368,13 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed) return; } -/* +/** * atl1c_configure - Configure Transmit&Receive Unit after Reset * @adapter: board private structure * * Configure the Tx /Rx unit of the MAC after a reset. */ -static int atl1c_configure(struct atl1c_adapter *adapter) +static int atl1c_configure_mac(struct atl1c_adapter *adapter) { struct atl1c_hw *hw = &adapter->hw; u32 master_ctrl_data = 0; @@ -1375,6 +1437,25 @@ static int atl1c_configure(struct atl1c_adapter *adapter) return 0; } +static int atl1c_configure(struct atl1c_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int num; + + atl1c_init_ring_ptrs(adapter); + atl1c_set_multi(netdev); + atl1c_restore_vlan(adapter); + + num = atl1c_alloc_rx_buffer(adapter); + if (unlikely(num == 0)) + return -ENOMEM; + + if (atl1c_configure_mac(adapter)) + return -EIO; + + return 0; +} + static void atl1c_update_hw_stats(struct atl1c_adapter *adapter) { u16 hw_reg_addr = 0; @@ -1401,7 +1482,7 @@ static void atl1c_update_hw_stats(struct atl1c_adapter *adapter) } } -/* +/** * atl1c_get_stats - Get System Network Statistics * @netdev: network interface device structure * @@ -1415,31 +1496,40 @@ static struct net_device_stats *atl1c_get_stats(struct net_device *netdev) struct net_device_stats *net_stats = &netdev->stats; atl1c_update_hw_stats(adapter); - net_stats->rx_packets = hw_stats->rx_ok; - net_stats->tx_packets = hw_stats->tx_ok; net_stats->rx_bytes = hw_stats->rx_byte_cnt; net_stats->tx_bytes = hw_stats->tx_byte_cnt; net_stats->multicast = hw_stats->rx_mcast; net_stats->collisions = hw_stats->tx_1_col + - hw_stats->tx_2_col * 2 + - hw_stats->tx_late_col + hw_stats->tx_abort_col; - net_stats->rx_errors = hw_stats->rx_frag + hw_stats->rx_fcs_err + - hw_stats->rx_len_err + hw_stats->rx_sz_ov + - hw_stats->rx_rrd_ov + hw_stats->rx_align_err; + hw_stats->tx_2_col + + hw_stats->tx_late_col + + hw_stats->tx_abort_col; + + net_stats->rx_errors = hw_stats->rx_frag + + hw_stats->rx_fcs_err + + hw_stats->rx_len_err + + hw_stats->rx_sz_ov + + hw_stats->rx_rrd_ov + + hw_stats->rx_align_err + + hw_stats->rx_rxf_ov; + net_stats->rx_fifo_errors = hw_stats->rx_rxf_ov; net_stats->rx_length_errors = hw_stats->rx_len_err; net_stats->rx_crc_errors = hw_stats->rx_fcs_err; net_stats->rx_frame_errors = hw_stats->rx_align_err; - net_stats->rx_over_errors = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov; + net_stats->rx_dropped = hw_stats->rx_rrd_ov; - net_stats->rx_missed_errors = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov; + net_stats->tx_errors = hw_stats->tx_late_col + + hw_stats->tx_abort_col + + hw_stats->tx_underrun + + hw_stats->tx_trunc; - net_stats->tx_errors = hw_stats->tx_late_col + hw_stats->tx_abort_col + - hw_stats->tx_underrun + hw_stats->tx_trunc; net_stats->tx_fifo_errors = hw_stats->tx_underrun; net_stats->tx_aborted_errors = hw_stats->tx_abort_col; net_stats->tx_window_errors = hw_stats->tx_late_col; + net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors; + net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors; + return net_stats; } @@ -1455,8 +1545,7 @@ static inline void atl1c_clear_phy_int(struct atl1c_adapter *adapter) static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter, enum atl1c_trans_queue type) { - struct atl1c_tpd_ring *tpd_ring = (struct atl1c_tpd_ring *) - &adapter->tpd_ring[type]; + struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type]; struct atl1c_buffer *buffer_info; struct pci_dev *pdev = adapter->pdev; u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean); @@ -1469,7 +1558,7 @@ static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter, while (next_to_clean != hw_next_to_clean) { buffer_info = &tpd_ring->buffer_info[next_to_clean]; - atl1c_clean_buffer(pdev, buffer_info, 1); + atl1c_clean_buffer(pdev, buffer_info); if (++next_to_clean == tpd_ring->count) next_to_clean = 0; atomic_set(&tpd_ring->next_to_clean, next_to_clean); @@ -1483,11 +1572,10 @@ static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter, return true; } -/* +/** * atl1c_intr - Interrupt Handler * @irq: interrupt number * @data: pointer to a network interface device structure - * @pt_regs: CPU registers structure */ static irqreturn_t atl1c_intr(int irq, void *data) { @@ -1567,6 +1655,35 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter, skb_checksum_none_assert(skb); } +static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter) +{ + struct sk_buff *skb; + struct page *page; + + if (adapter->rx_frag_size > PAGE_SIZE) + return netdev_alloc_skb(adapter->netdev, + adapter->rx_buffer_len); + + page = adapter->rx_page; + if (!page) { + adapter->rx_page = page = alloc_page(GFP_ATOMIC); + if (unlikely(!page)) + return NULL; + adapter->rx_page_offset = 0; + } + + skb = build_skb(page_address(page) + adapter->rx_page_offset, + adapter->rx_frag_size); + if (likely(skb)) { + adapter->rx_page_offset += adapter->rx_frag_size; + if (adapter->rx_page_offset >= PAGE_SIZE) + adapter->rx_page = NULL; + else + get_page(page); + } + return skb; +} + static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) { struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; @@ -1577,6 +1694,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) u16 num_alloc = 0; u16 rfd_next_to_use, next_next; struct atl1c_rx_free_desc *rfd_desc; + dma_addr_t mapping; next_next = rfd_next_to_use = rfd_ring->next_to_use; if (++next_next == rfd_ring->count) @@ -1587,7 +1705,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) while (next_info->flags & ATL1C_BUFFER_FREE) { rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use); - skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len); + skb = atl1c_alloc_skb(adapter); if (unlikely(!skb)) { if (netif_msg_rx_err(adapter)) dev_warn(&pdev->dev, "alloc rx buffer failed\n"); @@ -1603,9 +1721,18 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); buffer_info->skb = skb; buffer_info->length = adapter->rx_buffer_len; - buffer_info->dma = pci_map_single(pdev, vir_addr, + mapping = pci_map_single(pdev, vir_addr, buffer_info->length, PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(pdev, mapping))) { + dev_kfree_skb(skb); + buffer_info->skb = NULL; + buffer_info->length = 0; + ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE); + netif_warn(adapter, rx_err, adapter->netdev, "RX pci_map_single failed"); + break; + } + buffer_info->dma = mapping; ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, ATL1C_PCIMAP_FROMDEVICE); rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma); @@ -1727,7 +1854,7 @@ rrs_checked: AT_TAG_TO_VLAN(rrs->vlan_tag, vlan); vlan = le16_to_cpu(vlan); - __vlan_hwaccel_put_tag(skb, vlan); + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan); } netif_receive_skb(skb); @@ -1738,9 +1865,8 @@ rrs_checked: atl1c_alloc_rx_buffer(adapter); } -/* +/** * atl1c_clean - NAPI Rx polling callback - * @adapter: board private structure */ static int atl1c_clean(struct napi_struct *napi, int budget) { @@ -1847,17 +1973,17 @@ static int atl1c_tso_csum(struct atl1c_adapter *adapter, enum atl1c_trans_queue type) { struct pci_dev *pdev = adapter->pdev; + unsigned short offload_type; u8 hdr_len; u32 real_len; - unsigned short offload_type; - int err; if (skb_is_gso(skb)) { - if (skb_header_cloned(skb)) { - err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); - if (unlikely(err)) - return -1; - } + int err; + + err = skb_cow_head(skb, 0); + if (err < 0) + return err; + offload_type = skb_shinfo(skb)->gso_type; if (offload_type & SKB_GSO_TCPV4) { @@ -1941,7 +2067,29 @@ check_sum: return 0; } -static void atl1c_tx_map(struct atl1c_adapter *adapter, +static void atl1c_tx_rollback(struct atl1c_adapter *adpt, + struct atl1c_tpd_desc *first_tpd, + enum atl1c_trans_queue type) +{ + struct atl1c_tpd_ring *tpd_ring = &adpt->tpd_ring[type]; + struct atl1c_buffer *buffer_info; + struct atl1c_tpd_desc *tpd; + u16 first_index, index; + + first_index = first_tpd - (struct atl1c_tpd_desc *)tpd_ring->desc; + index = first_index; + while (index != tpd_ring->next_to_use) { + tpd = ATL1C_TPD_DESC(tpd_ring, index); + buffer_info = &tpd_ring->buffer_info[index]; + atl1c_clean_buffer(adpt->pdev, buffer_info); + memset(tpd, 0, sizeof(struct atl1c_tpd_desc)); + if (++index == tpd_ring->count) + index = 0; + } + tpd_ring->next_to_use = first_index; +} + +static int atl1c_tx_map(struct atl1c_adapter *adapter, struct sk_buff *skb, struct atl1c_tpd_desc *tpd, enum atl1c_trans_queue type) { @@ -1966,6 +2114,9 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, buffer_info->length = map_len; buffer_info->dma = pci_map_single(adapter->pdev, skb->data, hdr_len, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(adapter->pdev, + buffer_info->dma))) + goto err_dma; ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, ATL1C_PCIMAP_TODEVICE); @@ -1988,6 +2139,10 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, buffer_info->dma = pci_map_single(adapter->pdev, skb->data + mapped_len, buffer_info->length, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(adapter->pdev, + buffer_info->dma))) + goto err_dma; + ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, ATL1C_PCIMAP_TODEVICE); @@ -2009,6 +2164,9 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, frag, 0, buffer_info->length, DMA_TO_DEVICE); + if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) + goto err_dma; + ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_PAGE, ATL1C_PCIMAP_TODEVICE); @@ -2021,6 +2179,13 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, /* The last buffer info contain the skb address, so it will be free after unmap */ buffer_info->skb = skb; + + return 0; + +err_dma: + buffer_info->dma = 0; + buffer_info->length = 0; + return -1; } static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb, @@ -2083,10 +2248,18 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, if (skb_network_offset(skb) != ETH_HLEN) tpd->word1 |= 1 << TPD_ETH_TYPE_SHIFT; /* Ethernet frame */ - atl1c_tx_map(adapter, skb, tpd, type); - atl1c_tx_queue(adapter, skb, tpd, type); + if (atl1c_tx_map(adapter, skb, tpd, type) < 0) { + netif_info(adapter, tx_done, adapter->netdev, + "tx-skb droppted due to dma error\n"); + /* roll back tpd/buffer */ + atl1c_tx_rollback(adapter, tpd, type); + spin_unlock_irqrestore(&adapter->tx_lock, flags); + dev_kfree_skb_any(skb); + } else { + atl1c_tx_queue(adapter, skb, tpd, type); + spin_unlock_irqrestore(&adapter->tx_lock, flags); + } - spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_OK; } @@ -2135,41 +2308,38 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter) return err; } + +static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter) +{ + /* release tx-pending skbs and reset tx/rx ring index */ + atl1c_clean_tx_ring(adapter, atl1c_trans_normal); + atl1c_clean_tx_ring(adapter, atl1c_trans_high); + atl1c_clean_rx_ring(adapter); +} + static int atl1c_up(struct atl1c_adapter *adapter) { struct net_device *netdev = adapter->netdev; - int num; int err; netif_carrier_off(netdev); - atl1c_init_ring_ptrs(adapter); - atl1c_set_multi(netdev); - atl1c_restore_vlan(adapter); - - num = atl1c_alloc_rx_buffer(adapter); - if (unlikely(num == 0)) { - err = -ENOMEM; - goto err_alloc_rx; - } - if (atl1c_configure(adapter)) { - err = -EIO; + err = atl1c_configure(adapter); + if (unlikely(err)) goto err_up; - } err = atl1c_request_irq(adapter); if (unlikely(err)) goto err_up; + atl1c_check_link_status(adapter); clear_bit(__AT_DOWN, &adapter->flags); napi_enable(&adapter->napi); atl1c_irq_enable(adapter); - atl1c_check_link_status(adapter); netif_start_queue(netdev); return err; err_up: -err_alloc_rx: atl1c_clean_rx_ring(adapter); return err; } @@ -2195,12 +2365,10 @@ static void atl1c_down(struct atl1c_adapter *adapter) adapter->link_speed = SPEED_0; adapter->link_duplex = -1; - atl1c_clean_tx_ring(adapter, atl1c_trans_normal); - atl1c_clean_tx_ring(adapter, atl1c_trans_high); - atl1c_clean_rx_ring(adapter); + atl1c_reset_dma_ring(adapter); } -/* +/** * atl1c_open - Called when a network interface is made active * @netdev: network interface device structure * @@ -2239,7 +2407,7 @@ err_up: return err; } -/* +/** * atl1c_close - Disables a network interface * @netdev: network interface device structure * @@ -2255,6 +2423,8 @@ static int atl1c_close(struct net_device *netdev) struct atl1c_adapter *adapter = netdev_priv(netdev); WARN_ON(test_bit(__AT_RESETTING, &adapter->flags)); + set_bit(__AT_DOWN, &adapter->flags); + cancel_work_sync(&adapter->common_task); atl1c_down(adapter); atl1c_free_ring_resources(adapter); return 0; @@ -2350,17 +2520,17 @@ static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev) atl1c_set_ethtool_ops(netdev); /* TODO: add when ready */ - netdev->hw_features = NETIF_F_SG | - NETIF_F_HW_CSUM | - NETIF_F_HW_VLAN_RX | - NETIF_F_TSO | + netdev->hw_features = NETIF_F_SG | + NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_TSO | NETIF_F_TSO6; - netdev->features = netdev->hw_features | - NETIF_F_HW_VLAN_TX; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_CTAG_TX; return 0; } -/* +/** * atl1c_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in atl1c_pci_tbl @@ -2371,8 +2541,7 @@ static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev) * The OS initialization, configuring of the adapter private structure, * and a hardware reset occur. */ -static int __devinit atl1c_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct atl1c_adapter *adapter; @@ -2470,15 +2639,14 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, } if (atl1c_read_mac_addr(&adapter->hw)) { /* got a random MAC address, set NET_ADDR_RANDOM to netdev */ - netdev->addr_assign_type |= NET_ADDR_RANDOM; + netdev->addr_assign_type = NET_ADDR_RANDOM; } memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); - memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); if (netif_msg_probe(adapter)) dev_dbg(&pdev->dev, "mac address : %pM\n", adapter->hw.mac_addr); - atl1c_hw_set_mac_addr(&adapter->hw); + atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr); INIT_WORK(&adapter->common_task, atl1c_common_task); adapter->work_event = 0; err = register_netdev(netdev); @@ -2507,7 +2675,7 @@ err_dma: return err; } -/* +/** * atl1c_remove - Device Removal Routine * @pdev: PCI device information struct * @@ -2516,12 +2684,14 @@ err_dma: * Hot-Plug event, or because the driver is going to be removed from * memory. */ -static void __devexit atl1c_remove(struct pci_dev *pdev) +static void atl1c_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct atl1c_adapter *adapter = netdev_priv(netdev); unregister_netdev(netdev); + /* restore permanent address */ + atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.perm_mac_addr); atl1c_phy_disable(&adapter->hw); iounmap(adapter->hw.hw_addr); @@ -2531,7 +2701,7 @@ static void __devexit atl1c_remove(struct pci_dev *pdev) free_netdev(netdev); } -/* +/** * atl1c_io_error_detected - called when PCI error is detected * @pdev: Pointer to PCI device * @state: The current pci connection state @@ -2559,7 +2729,7 @@ static pci_ers_result_t atl1c_io_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_NEED_RESET; } -/* +/** * atl1c_io_slot_reset - called after the pci bus has been reset. * @pdev: Pointer to PCI device * @@ -2587,7 +2757,7 @@ static pci_ers_result_t atl1c_io_slot_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_RECOVERED; } -/* +/** * atl1c_io_resume - called when traffic can start flowing again. * @pdev: Pointer to PCI device * @@ -2612,7 +2782,7 @@ static void atl1c_io_resume(struct pci_dev *pdev) netif_device_attach(netdev); } -static struct pci_error_handlers atl1c_err_handler = { +static const struct pci_error_handlers atl1c_err_handler = { .error_detected = atl1c_io_error_detected, .slot_reset = atl1c_io_slot_reset, .resume = atl1c_io_resume, @@ -2624,33 +2794,10 @@ static struct pci_driver atl1c_driver = { .name = atl1c_driver_name, .id_table = atl1c_pci_tbl, .probe = atl1c_probe, - .remove = __devexit_p(atl1c_remove), + .remove = atl1c_remove, .shutdown = atl1c_shutdown, .err_handler = &atl1c_err_handler, .driver.pm = &atl1c_pm_ops, }; -/* - * atl1c_init_module - Driver Registration Routine - * - * atl1c_init_module is the first routine called when the driver is - * loaded. All it does is register with the PCI subsystem. - */ -static int __init atl1c_init_module(void) -{ - return pci_register_driver(&atl1c_driver); -} - -/* - * atl1c_exit_module - Driver Exit Cleanup Routine - * - * atl1c_exit_module is called just before the driver is removed - * from memory. - */ -static void __exit atl1c_exit_module(void) -{ - pci_unregister_driver(&atl1c_driver); -} - -module_init(atl1c_init_module); -module_exit(atl1c_exit_module); +module_pci_driver(atl1c_driver); |
