diff options
Diffstat (limited to 'drivers/net/ethernet/atheros')
24 files changed, 6630 insertions, 1860 deletions
diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig index 1ed886d421f..58ad37c733b 100644 --- a/drivers/net/ethernet/atheros/Kconfig +++ b/drivers/net/ethernet/atheros/Kconfig @@ -22,7 +22,6 @@ config ATL2 tristate "Atheros L2 Fast Ethernet support" depends on PCI select CRC32 - select NET_CORE select MII ---help--- This driver supports the Atheros L2 fast ethernet adapter. @@ -34,7 +33,6 @@ config ATL1 tristate "Atheros/Attansic L1 Gigabit Ethernet support" depends on PCI select CRC32 - select NET_CORE select MII ---help--- This driver supports the Atheros/Attansic L1 gigabit ethernet @@ -44,10 +42,9 @@ config ATL1 will be called atl1. config ATL1E - tristate "Atheros L1E Gigabit Ethernet support (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + tristate "Atheros L1E Gigabit Ethernet support" + depends on PCI select CRC32 - select NET_CORE select MII ---help--- This driver supports the Atheros L1E gigabit ethernet adapter. @@ -56,10 +53,9 @@ config ATL1E will be called atl1e. config ATL1C - tristate "Atheros L1C Gigabit Ethernet support (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + tristate "Atheros L1C Gigabit Ethernet support" + depends on PCI select CRC32 - select NET_CORE select MII ---help--- This driver supports the Atheros L1C gigabit ethernet adapter. @@ -67,4 +63,21 @@ config ATL1C To compile this driver as a module, choose M here. The module will be called atl1c. +config ALX + tristate "Qualcomm Atheros AR816x/AR817x support" + depends on PCI + select CRC32 + select MDIO + help + This driver supports the Qualcomm Atheros L1F ethernet adapter, + i.e. the following chipsets: + + 1969:1091 - AR8161 Gigabit Ethernet + 1969:1090 - AR8162 Fast Ethernet + 1969:10A1 - AR8171 Gigabit Ethernet + 1969:10A0 - AR8172 Fast Ethernet + + To compile this driver as a module, choose M here. The module + will be called alx. + endif # NET_VENDOR_ATHEROS diff --git a/drivers/net/ethernet/atheros/Makefile b/drivers/net/ethernet/atheros/Makefile index e7e76fb576f..5cf1c65bbce 100644 --- a/drivers/net/ethernet/atheros/Makefile +++ b/drivers/net/ethernet/atheros/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_ATL1) += atlx/ obj-$(CONFIG_ATL2) += atlx/ obj-$(CONFIG_ATL1E) += atl1e/ obj-$(CONFIG_ATL1C) += atl1c/ +obj-$(CONFIG_ALX) += alx/ diff --git a/drivers/net/ethernet/atheros/alx/Makefile b/drivers/net/ethernet/atheros/alx/Makefile new file mode 100644 index 00000000000..5901fa407d5 --- /dev/null +++ b/drivers/net/ethernet/atheros/alx/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_ALX) += alx.o +alx-objs := main.o ethtool.o hw.o +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h new file mode 100644 index 00000000000..8fc93c5f6ab --- /dev/null +++ b/drivers/net/ethernet/atheros/alx/alx.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net> + * + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _ALX_H_ +#define _ALX_H_ + +#include <linux/types.h> +#include <linux/etherdevice.h> +#include <linux/dma-mapping.h> +#include <linux/spinlock.h> +#include "hw.h" + +#define ALX_WATCHDOG_TIME (5 * HZ) + +struct alx_buffer { + struct sk_buff *skb; + DEFINE_DMA_UNMAP_ADDR(dma); + DEFINE_DMA_UNMAP_LEN(size); +}; + +struct alx_rx_queue { + struct alx_rrd *rrd; + dma_addr_t rrd_dma; + + struct alx_rfd *rfd; + dma_addr_t rfd_dma; + + struct alx_buffer *bufs; + + u16 write_idx, read_idx; + u16 rrd_read_idx; +}; +#define ALX_RX_ALLOC_THRESH 32 + +struct alx_tx_queue { + struct alx_txd *tpd; + dma_addr_t tpd_dma; + struct alx_buffer *bufs; + u16 write_idx, read_idx; +}; + +#define ALX_DEFAULT_TX_WORK 128 + +enum alx_device_quirks { + ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG = BIT(0), +}; + +struct alx_priv { + struct net_device *dev; + + struct alx_hw hw; + + /* all descriptor memory */ + struct { + dma_addr_t dma; + void *virt; + unsigned int size; + } descmem; + + /* protect int_mask updates */ + spinlock_t irq_lock; + u32 int_mask; + + unsigned int tx_ringsz; + unsigned int rx_ringsz; + unsigned int rxbuf_size; + + struct napi_struct napi; + struct alx_tx_queue txq; + struct alx_rx_queue rxq; + + struct work_struct link_check_wk; + struct work_struct reset_wk; + + u16 msg_enable; + + bool msi; + + /* protects hw.stats */ + spinlock_t stats_lock; +}; + +extern const struct ethtool_ops alx_ethtool_ops; +extern const char alx_drv_name[]; + +#endif diff --git a/drivers/net/ethernet/atheros/alx/ethtool.c b/drivers/net/ethernet/atheros/alx/ethtool.c new file mode 100644 index 00000000000..08e22df2a30 --- /dev/null +++ b/drivers/net/ethernet/atheros/alx/ethtool.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net> + * + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/pci.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/mdio.h> +#include <linux/interrupt.h> +#include <asm/byteorder.h> + +#include "alx.h" +#include "reg.h" +#include "hw.h" + +/* The order of these strings must match the order of the fields in + * struct alx_hw_stats + * See hw.h + */ +static const char alx_gstrings_stats[][ETH_GSTRING_LEN] = { + "rx_packets", + "rx_bcast_packets", + "rx_mcast_packets", + "rx_pause_packets", + "rx_ctrl_packets", + "rx_fcs_errors", + "rx_length_errors", + "rx_bytes", + "rx_runt_packets", + "rx_fragments", + "rx_64B_or_less_packets", + "rx_65B_to_127B_packets", + "rx_128B_to_255B_packets", + "rx_256B_to_511B_packets", + "rx_512B_to_1023B_packets", + "rx_1024B_to_1518B_packets", + "rx_1519B_to_mtu_packets", + "rx_oversize_packets", + "rx_rxf_ov_drop_packets", + "rx_rrd_ov_drop_packets", + "rx_align_errors", + "rx_bcast_bytes", + "rx_mcast_bytes", + "rx_address_errors", + "tx_packets", + "tx_bcast_packets", + "tx_mcast_packets", + "tx_pause_packets", + "tx_exc_defer_packets", + "tx_ctrl_packets", + "tx_defer_packets", + "tx_bytes", + "tx_64B_or_less_packets", + "tx_65B_to_127B_packets", + "tx_128B_to_255B_packets", + "tx_256B_to_511B_packets", + "tx_512B_to_1023B_packets", + "tx_1024B_to_1518B_packets", + "tx_1519B_to_mtu_packets", + "tx_single_collision", + "tx_multiple_collisions", + "tx_late_collision", + "tx_abort_collision", + "tx_underrun", + "tx_trd_eop", + "tx_length_errors", + "tx_trunc_packets", + "tx_bcast_bytes", + "tx_mcast_bytes", + "tx_update", +}; + +#define ALX_NUM_STATS ARRAY_SIZE(alx_gstrings_stats) + + +static u32 alx_get_supported_speeds(struct alx_hw *hw) +{ + u32 supported = SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full; + + if (alx_hw_giga(hw)) + supported |= SUPPORTED_1000baseT_Full; + + BUILD_BUG_ON(SUPPORTED_10baseT_Half != ADVERTISED_10baseT_Half); + BUILD_BUG_ON(SUPPORTED_10baseT_Full != ADVERTISED_10baseT_Full); + BUILD_BUG_ON(SUPPORTED_100baseT_Half != ADVERTISED_100baseT_Half); + BUILD_BUG_ON(SUPPORTED_100baseT_Full != ADVERTISED_100baseT_Full); + BUILD_BUG_ON(SUPPORTED_1000baseT_Full != ADVERTISED_1000baseT_Full); + + return supported; +} + +static int alx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_hw *hw = &alx->hw; + + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_TP | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause; + if (alx_hw_giga(hw)) + ecmd->supported |= SUPPORTED_1000baseT_Full; + ecmd->supported |= alx_get_supported_speeds(hw); + + ecmd->advertising = ADVERTISED_TP; + if (hw->adv_cfg & ADVERTISED_Autoneg) + ecmd->advertising |= hw->adv_cfg; + + ecmd->port = PORT_TP; + ecmd->phy_address = 0; + + if (hw->adv_cfg & ADVERTISED_Autoneg) + ecmd->autoneg = AUTONEG_ENABLE; + else + ecmd->autoneg = AUTONEG_DISABLE; + ecmd->transceiver = XCVR_INTERNAL; + + if (hw->flowctrl & ALX_FC_ANEG && hw->adv_cfg & ADVERTISED_Autoneg) { + if (hw->flowctrl & ALX_FC_RX) { + ecmd->advertising |= ADVERTISED_Pause; + + if (!(hw->flowctrl & ALX_FC_TX)) + ecmd->advertising |= ADVERTISED_Asym_Pause; + } else if (hw->flowctrl & ALX_FC_TX) { + ecmd->advertising |= ADVERTISED_Asym_Pause; + } + } + + ethtool_cmd_speed_set(ecmd, hw->link_speed); + ecmd->duplex = hw->duplex; + + return 0; +} + +static int alx_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_hw *hw = &alx->hw; + u32 adv_cfg; + + ASSERT_RTNL(); + + if (ecmd->autoneg == AUTONEG_ENABLE) { + if (ecmd->advertising & ~alx_get_supported_speeds(hw)) + return -EINVAL; + adv_cfg = ecmd->advertising | ADVERTISED_Autoneg; + } else { + adv_cfg = alx_speed_to_ethadv(ethtool_cmd_speed(ecmd), + ecmd->duplex); + + if (!adv_cfg || adv_cfg == ADVERTISED_1000baseT_Full) + return -EINVAL; + } + + hw->adv_cfg = adv_cfg; + return alx_setup_speed_duplex(hw, adv_cfg, hw->flowctrl); +} + +static void alx_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_hw *hw = &alx->hw; + + pause->autoneg = !!(hw->flowctrl & ALX_FC_ANEG && + hw->adv_cfg & ADVERTISED_Autoneg); + pause->tx_pause = !!(hw->flowctrl & ALX_FC_TX); + pause->rx_pause = !!(hw->flowctrl & ALX_FC_RX); +} + + +static int alx_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_hw *hw = &alx->hw; + int err = 0; + bool reconfig_phy = false; + u8 fc = 0; + + if (pause->tx_pause) + fc |= ALX_FC_TX; + if (pause->rx_pause) + fc |= ALX_FC_RX; + if (pause->autoneg) + fc |= ALX_FC_ANEG; + + ASSERT_RTNL(); + + /* restart auto-neg for auto-mode */ + if (hw->adv_cfg & ADVERTISED_Autoneg) { + if (!((fc ^ hw->flowctrl) & ALX_FC_ANEG)) + reconfig_phy = true; + if (fc & hw->flowctrl & ALX_FC_ANEG && + (fc ^ hw->flowctrl) & (ALX_FC_RX | ALX_FC_TX)) + reconfig_phy = true; + } + + if (reconfig_phy) { + err = alx_setup_speed_duplex(hw, hw->adv_cfg, fc); + if (err) + return err; + } + + /* flow control on mac */ + if ((fc ^ hw->flowctrl) & (ALX_FC_RX | ALX_FC_TX)) + alx_cfg_mac_flowcontrol(hw, fc); + + hw->flowctrl = fc; + + return 0; +} + +static u32 alx_get_msglevel(struct net_device *netdev) +{ + struct alx_priv *alx = netdev_priv(netdev); + + return alx->msg_enable; +} + +static void alx_set_msglevel(struct net_device *netdev, u32 data) +{ + struct alx_priv *alx = netdev_priv(netdev); + + alx->msg_enable = data; +} + +static void alx_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *estats, u64 *data) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_hw *hw = &alx->hw; + + spin_lock(&alx->stats_lock); + + alx_update_hw_stats(hw); + BUILD_BUG_ON(sizeof(hw->stats) - offsetof(struct alx_hw_stats, rx_ok) < + ALX_NUM_STATS * sizeof(u64)); + memcpy(data, &hw->stats.rx_ok, ALX_NUM_STATS * sizeof(u64)); + + spin_unlock(&alx->stats_lock); +} + +static void alx_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(buf, &alx_gstrings_stats, sizeof(alx_gstrings_stats)); + break; + default: + WARN_ON(1); + break; + } +} + +static int alx_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ALX_NUM_STATS; + default: + return -EINVAL; + } +} + +const struct ethtool_ops alx_ethtool_ops = { + .get_settings = alx_get_settings, + .set_settings = alx_set_settings, + .get_pauseparam = alx_get_pauseparam, + .set_pauseparam = alx_set_pauseparam, + .get_msglevel = alx_get_msglevel, + .set_msglevel = alx_set_msglevel, + .get_link = ethtool_op_get_link, + .get_strings = alx_get_strings, + .get_sset_count = alx_get_sset_count, + .get_ethtool_stats = alx_get_ethtool_stats, +}; diff --git a/drivers/net/ethernet/atheros/alx/hw.c b/drivers/net/ethernet/atheros/alx/hw.c new file mode 100644 index 00000000000..7712f068f6d --- /dev/null +++ b/drivers/net/ethernet/atheros/alx/hw.c @@ -0,0 +1,1110 @@ +/* + * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net> + * + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <linux/etherdevice.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/mdio.h> +#include "reg.h" +#include "hw.h" + +static inline bool alx_is_rev_a(u8 rev) +{ + return rev == ALX_REV_A0 || rev == ALX_REV_A1; +} + +static int alx_wait_mdio_idle(struct alx_hw *hw) +{ + u32 val; + int i; + + for (i = 0; i < ALX_MDIO_MAX_AC_TO; i++) { + val = alx_read_mem32(hw, ALX_MDIO); + if (!(val & ALX_MDIO_BUSY)) + return 0; + udelay(10); + } + + return -ETIMEDOUT; +} + +static int alx_read_phy_core(struct alx_hw *hw, bool ext, u8 dev, + u16 reg, u16 *phy_data) +{ + u32 val, clk_sel; + int err; + + *phy_data = 0; + + /* use slow clock when it's in hibernation status */ + clk_sel = hw->link_speed != SPEED_UNKNOWN ? + ALX_MDIO_CLK_SEL_25MD4 : + ALX_MDIO_CLK_SEL_25MD128; + + if (ext) { + val = dev << ALX_MDIO_EXTN_DEVAD_SHIFT | + reg << ALX_MDIO_EXTN_REG_SHIFT; + alx_write_mem32(hw, ALX_MDIO_EXTN, val); + + val = ALX_MDIO_SPRES_PRMBL | ALX_MDIO_START | + ALX_MDIO_MODE_EXT | ALX_MDIO_OP_READ | + clk_sel << ALX_MDIO_CLK_SEL_SHIFT; + } else { + val = ALX_MDIO_SPRES_PRMBL | + clk_sel << ALX_MDIO_CLK_SEL_SHIFT | + reg << ALX_MDIO_REG_SHIFT | + ALX_MDIO_START | ALX_MDIO_OP_READ; + } + alx_write_mem32(hw, ALX_MDIO, val); + + err = alx_wait_mdio_idle(hw); + if (err) + return err; + val = alx_read_mem32(hw, ALX_MDIO); + *phy_data = ALX_GET_FIELD(val, ALX_MDIO_DATA); + return 0; +} + +static int alx_write_phy_core(struct alx_hw *hw, bool ext, u8 dev, + u16 reg, u16 phy_data) +{ + u32 val, clk_sel; + + /* use slow clock when it's in hibernation status */ + clk_sel = hw->link_speed != SPEED_UNKNOWN ? + ALX_MDIO_CLK_SEL_25MD4 : + ALX_MDIO_CLK_SEL_25MD128; + + if (ext) { + val = dev << ALX_MDIO_EXTN_DEVAD_SHIFT | + reg << ALX_MDIO_EXTN_REG_SHIFT; + alx_write_mem32(hw, ALX_MDIO_EXTN, val); + + val = ALX_MDIO_SPRES_PRMBL | + clk_sel << ALX_MDIO_CLK_SEL_SHIFT | + phy_data << ALX_MDIO_DATA_SHIFT | + ALX_MDIO_START | ALX_MDIO_MODE_EXT; + } else { + val = ALX_MDIO_SPRES_PRMBL | + clk_sel << ALX_MDIO_CLK_SEL_SHIFT | + reg << ALX_MDIO_REG_SHIFT | + phy_data << ALX_MDIO_DATA_SHIFT | + ALX_MDIO_START; + } + alx_write_mem32(hw, ALX_MDIO, val); + + return alx_wait_mdio_idle(hw); +} + +static int __alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data) +{ + return alx_read_phy_core(hw, false, 0, reg, phy_data); +} + +static int __alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data) +{ + return alx_write_phy_core(hw, false, 0, reg, phy_data); +} + +static int __alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata) +{ + return alx_read_phy_core(hw, true, dev, reg, pdata); +} + +static int __alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data) +{ + return alx_write_phy_core(hw, true, dev, reg, data); +} + +static int __alx_read_phy_dbg(struct alx_hw *hw, u16 reg, u16 *pdata) +{ + int err; + + err = __alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, reg); + if (err) + return err; + + return __alx_read_phy_reg(hw, ALX_MII_DBG_DATA, pdata); +} + +static int __alx_write_phy_dbg(struct alx_hw *hw, u16 reg, u16 data) +{ + int err; + + err = __alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, reg); + if (err) + return err; + + return __alx_write_phy_reg(hw, ALX_MII_DBG_DATA, data); +} + +int alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data) +{ + int err; + + spin_lock(&hw->mdio_lock); + err = __alx_read_phy_reg(hw, reg, phy_data); + spin_unlock(&hw->mdio_lock); + + return err; +} + +int alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data) +{ + int err; + + spin_lock(&hw->mdio_lock); + err = __alx_write_phy_reg(hw, reg, phy_data); + spin_unlock(&hw->mdio_lock); + + return err; +} + +int alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata) +{ + int err; + + spin_lock(&hw->mdio_lock); + err = __alx_read_phy_ext(hw, dev, reg, pdata); + spin_unlock(&hw->mdio_lock); + + return err; +} + +int alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data) +{ + int err; + + spin_lock(&hw->mdio_lock); + err = __alx_write_phy_ext(hw, dev, reg, data); + spin_unlock(&hw->mdio_lock); + + return err; +} + +static int alx_read_phy_dbg(struct alx_hw *hw, u16 reg, u16 *pdata) +{ + int err; + + spin_lock(&hw->mdio_lock); + err = __alx_read_phy_dbg(hw, reg, pdata); + spin_unlock(&hw->mdio_lock); + + return err; +} + +static int alx_write_phy_dbg(struct alx_hw *hw, u16 reg, u16 data) +{ + int err; + + spin_lock(&hw->mdio_lock); + err = __alx_write_phy_dbg(hw, reg, data); + spin_unlock(&hw->mdio_lock); + + return err; +} + +static u16 alx_get_phy_config(struct alx_hw *hw) +{ + u32 val; + u16 phy_val; + + val = alx_read_mem32(hw, ALX_PHY_CTRL); + /* phy in reset */ + if ((val & ALX_PHY_CTRL_DSPRST_OUT) == 0) + return ALX_DRV_PHY_UNKNOWN; + + val = alx_read_mem32(hw, ALX_DRV); + val = ALX_GET_FIELD(val, ALX_DRV_PHY); + if (ALX_DRV_PHY_UNKNOWN == val) + return ALX_DRV_PHY_UNKNOWN; + + alx_read_phy_reg(hw, ALX_MII_DBG_ADDR, &phy_val); + if (ALX_PHY_INITED == phy_val) + return val; + + return ALX_DRV_PHY_UNKNOWN; +} + +static bool alx_wait_reg(struct alx_hw *hw, u32 reg, u32 wait, u32 *val) +{ + u32 read; + int i; + + for (i = 0; i < ALX_SLD_MAX_TO; i++) { + read = alx_read_mem32(hw, reg); + if ((read & wait) == 0) { + if (val) + *val = read; + return true; + } + mdelay(1); + } + + return false; +} + +static bool alx_read_macaddr(struct alx_hw *hw, u8 *addr) +{ + u32 mac0, mac1; + + mac0 = alx_read_mem32(hw, ALX_STAD0); + mac1 = alx_read_mem32(hw, ALX_STAD1); + + /* addr should be big-endian */ + put_unaligned(cpu_to_be32(mac0), (__be32 *)(addr + 2)); + put_unaligned(cpu_to_be16(mac1), (__be16 *)addr); + + return is_valid_ether_addr(addr); +} + +int alx_get_perm_macaddr(struct alx_hw *hw, u8 *addr) +{ + u32 val; + + /* try to get it from register first */ + if (alx_read_macaddr(hw, addr)) + return 0; + + /* try to load from efuse */ + if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_STAT | ALX_SLD_START, &val)) + return -EIO; + alx_write_mem32(hw, ALX_SLD, val | ALX_SLD_START); + if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_START, NULL)) + return -EIO; + if (alx_read_macaddr(hw, addr)) + return 0; + + /* try to load from flash/eeprom (if present) */ + val = alx_read_mem32(hw, ALX_EFLD); + if (val & (ALX_EFLD_F_EXIST | ALX_EFLD_E_EXIST)) { + if (!alx_wait_reg(hw, ALX_EFLD, + ALX_EFLD_STAT | ALX_EFLD_START, &val)) + return -EIO; + alx_write_mem32(hw, ALX_EFLD, val | ALX_EFLD_START); + if (!alx_wait_reg(hw, ALX_EFLD, ALX_EFLD_START, NULL)) + return -EIO; + if (alx_read_macaddr(hw, addr)) + return 0; + } + + return -EIO; +} + +void alx_set_macaddr(struct alx_hw *hw, const u8 *addr) +{ + u32 val; + + /* for example: 00-0B-6A-F6-00-DC * STAD0=6AF600DC, STAD1=000B */ + val = be32_to_cpu(get_unaligned((__be32 *)(addr + 2))); + alx_write_mem32(hw, ALX_STAD0, val); + val = be16_to_cpu(get_unaligned((__be16 *)addr)); + alx_write_mem32(hw, ALX_STAD1, val); +} + +static void alx_reset_osc(struct alx_hw *hw, u8 rev) +{ + u32 val, val2; + + /* clear Internal OSC settings, switching OSC by hw itself */ + val = alx_read_mem32(hw, ALX_MISC3); + alx_write_mem32(hw, ALX_MISC3, + (val & ~ALX_MISC3_25M_BY_SW) | + ALX_MISC3_25M_NOTO_INTNL); + + /* 25M clk from chipset may be unstable 1s after de-assert of + * PERST, driver need re-calibrate before enter Sleep for WoL + */ + val = alx_read_mem32(hw, ALX_MISC); + if (rev >= ALX_REV_B0) { + /* restore over current protection def-val, + * this val could be reset by MAC-RST + */ + ALX_SET_FIELD(val, ALX_MISC_PSW_OCP, ALX_MISC_PSW_OCP_DEF); + /* a 0->1 change will update the internal val of osc */ + val &= ~ALX_MISC_INTNLOSC_OPEN; + alx_write_mem32(hw, ALX_MISC, val); + alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN); + /* hw will automatically dis OSC after cab. */ + val2 = alx_read_mem32(hw, ALX_MSIC2); + val2 &= ~ALX_MSIC2_CALB_START; + alx_write_mem32(hw, ALX_MSIC2, val2); + alx_write_mem32(hw, ALX_MSIC2, val2 | ALX_MSIC2_CALB_START); + } else { + val &= ~ALX_MISC_INTNLOSC_OPEN; + /* disable isolate for rev A devices */ + if (alx_is_rev_a(rev)) + val &= ~ALX_MISC_ISO_EN; + + alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN); + alx_write_mem32(hw, ALX_MISC, val); + } + + udelay(20); +} + +static int alx_stop_mac(struct alx_hw *hw) +{ + u32 rxq, txq, val; + u16 i; + + rxq = alx_read_mem32(hw, ALX_RXQ0); + alx_write_mem32(hw, ALX_RXQ0, rxq & ~ALX_RXQ0_EN); + txq = alx_read_mem32(hw, ALX_TXQ0); + alx_write_mem32(hw, ALX_TXQ0, txq & ~ALX_TXQ0_EN); + + udelay(40); + + hw->rx_ctrl &= ~(ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_TX_EN); + alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); + + for (i = 0; i < ALX_DMA_MAC_RST_TO; i++) { + val = alx_read_mem32(hw, ALX_MAC_STS); + if (!(val & ALX_MAC_STS_IDLE)) + return 0; + udelay(10); + } + + return -ETIMEDOUT; +} + +int alx_reset_mac(struct alx_hw *hw) +{ + u32 val, pmctrl; + int i, ret; + u8 rev; + bool a_cr; + + pmctrl = 0; + rev = alx_hw_revision(hw); + a_cr = alx_is_rev_a(rev) && alx_hw_with_cr(hw); + + /* disable all interrupts, RXQ/TXQ */ + alx_write_mem32(hw, ALX_MSIX_MASK, 0xFFFFFFFF); + alx_write_mem32(hw, ALX_IMR, 0); + alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS); + + ret = alx_stop_mac(hw); + if (ret) + return ret; + + /* mac reset workaroud */ + alx_write_mem32(hw, ALX_RFD_PIDX, 1); + + /* dis l0s/l1 before mac reset */ + if (a_cr) { + pmctrl = alx_read_mem32(hw, ALX_PMCTRL); + if (pmctrl & (ALX_PMCTRL_L1_EN | ALX_PMCTRL_L0S_EN)) + alx_write_mem32(hw, ALX_PMCTRL, + pmctrl & ~(ALX_PMCTRL_L1_EN | + ALX_PMCTRL_L0S_EN)); + } + + /* reset whole mac safely */ + val = alx_read_mem32(hw, ALX_MASTER); + alx_write_mem32(hw, ALX_MASTER, + val | ALX_MASTER_DMA_MAC_RST | ALX_MASTER_OOB_DIS); + + /* make sure it's real idle */ + udelay(10); + for (i = 0; i < ALX_DMA_MAC_RST_TO; i++) { + val = alx_read_mem32(hw, ALX_RFD_PIDX); + if (val == 0) + break; + udelay(10); + } + for (; i < ALX_DMA_MAC_RST_TO; i++) { + val = alx_read_mem32(hw, ALX_MASTER); + if ((val & ALX_MASTER_DMA_MAC_RST) == 0) + break; + udelay(10); + } + if (i == ALX_DMA_MAC_RST_TO) + return -EIO; + udelay(10); + + if (a_cr) { + alx_write_mem32(hw, ALX_MASTER, val | ALX_MASTER_PCLKSEL_SRDS); + /* restore l0s / l1 */ + if (pmctrl & (ALX_PMCTRL_L1_EN | ALX_PMCTRL_L0S_EN)) + alx_write_mem32(hw, ALX_PMCTRL, pmctrl); + } + + alx_reset_osc(hw, rev); + + /* clear Internal OSC settings, switching OSC by hw itself, + * disable isolate for rev A devices + */ + val = alx_read_mem32(hw, ALX_MISC3); + alx_write_mem32(hw, ALX_MISC3, + (val & ~ALX_MISC3_25M_BY_SW) | + ALX_MISC3_25M_NOTO_INTNL); + val = alx_read_mem32(hw, ALX_MISC); + val &= ~ALX_MISC_INTNLOSC_OPEN; + if (alx_is_rev_a(rev)) + val &= ~ALX_MISC_ISO_EN; + alx_write_mem32(hw, ALX_MISC, val); + udelay(20); + + /* driver control speed/duplex, hash-alg */ + alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); + + val = alx_read_mem32(hw, ALX_SERDES); + alx_write_mem32(hw, ALX_SERDES, + val | ALX_SERDES_MACCLK_SLWDWN | + ALX_SERDES_PHYCLK_SLWDWN); + + return 0; +} + +void alx_reset_phy(struct alx_hw *hw) +{ + int i; + u32 val; + u16 phy_val; + + /* (DSP)reset PHY core */ + val = alx_read_mem32(hw, ALX_PHY_CTRL); + val &= ~(ALX_PHY_CTRL_DSPRST_OUT | ALX_PHY_CTRL_IDDQ | + ALX_PHY_CTRL_GATE_25M | ALX_PHY_CTRL_POWER_DOWN | + ALX_PHY_CTRL_CLS); + val |= ALX_PHY_CTRL_RST_ANALOG; + + val |= (ALX_PHY_CTRL_HIB_PULSE | ALX_PHY_CTRL_HIB_EN); + alx_write_mem32(hw, ALX_PHY_CTRL, val); + udelay(10); + alx_write_mem32(hw, ALX_PHY_CTRL, val | ALX_PHY_CTRL_DSPRST_OUT); + + for (i = 0; i < ALX_PHY_CTRL_DSPRST_TO; i++) + udelay(10); + + /* phy power saving & hib */ + alx_write_phy_dbg(hw, ALX_MIIDBG_LEGCYPS, ALX_LEGCYPS_DEF); + alx_write_phy_dbg(hw, ALX_MIIDBG_SYSMODCTRL, + ALX_SYSMODCTRL_IECHOADJ_DEF); + alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_VDRVBIAS, + ALX_VDRVBIAS_DEF); + + /* EEE advertisement */ + val = alx_read_mem32(hw, ALX_LPI_CTRL); + alx_write_mem32(hw, ALX_LPI_CTRL, val & ~ALX_LPI_CTRL_EN); + alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_LOCAL_EEEADV, 0); + + /* phy power saving */ + alx_write_phy_dbg(hw, ALX_MIIDBG_TST10BTCFG, ALX_TST10BTCFG_DEF); + alx_write_phy_dbg(hw, ALX_MIIDBG_SRDSYSMOD, ALX_SRDSYSMOD_DEF); + alx_write_phy_dbg(hw, ALX_MIIDBG_TST100BTCFG, ALX_TST100BTCFG_DEF); + alx_write_phy_dbg(hw, ALX_MIIDBG_ANACTRL, ALX_ANACTRL_DEF); + alx_read_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, &phy_val); + alx_write_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, + phy_val & ~ALX_GREENCFG2_GATE_DFSE_EN); + /* rtl8139c, 120m issue */ + alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_NLP78, + ALX_MIIEXT_NLP78_120M_DEF); + alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_S3DIG10, + ALX_MIIEXT_S3DIG10_DEF); + + if (hw->lnk_patch) { + /* Turn off half amplitude */ + alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL3, + &phy_val); + alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL3, + phy_val | ALX_CLDCTRL3_BP_CABLE1TH_DET_GT); + /* Turn off Green feature */ + alx_read_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, &phy_val); + alx_write_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, + phy_val | ALX_GREENCFG2_BP_GREEN); + /* Turn off half Bias */ + alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL5, + &phy_val); + alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL5, + phy_val | ALX_CLDCTRL5_BP_VD_HLFBIAS); + } + + /* set phy interrupt mask */ + alx_write_phy_reg(hw, ALX_MII_IER, ALX_IER_LINK_UP | ALX_IER_LINK_DOWN); +} + +#define ALX_PCI_CMD (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO) + +void alx_reset_pcie(struct alx_hw *hw) +{ + u8 rev = alx_hw_revision(hw); + u32 val; + u16 val16; + + /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */ + pci_read_config_word(hw->pdev, PCI_COMMAND, &val16); + if (!(val16 & ALX_PCI_CMD) || (val16 & PCI_COMMAND_INTX_DISABLE)) { + val16 = (val16 | ALX_PCI_CMD) & ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(hw->pdev, PCI_COMMAND, val16); + } + + /* clear WoL setting/status */ + val = alx_read_mem32(hw, ALX_WOL0); + alx_write_mem32(hw, ALX_WOL0, 0); + + val = alx_read_mem32(hw, ALX_PDLL_TRNS1); + alx_write_mem32(hw, ALX_PDLL_TRNS1, val & ~ALX_PDLL_TRNS1_D3PLLOFF_EN); + + /* mask some pcie error bits */ + val = alx_read_mem32(hw, ALX_UE_SVRT); + val &= ~(ALX_UE_SVRT_DLPROTERR | ALX_UE_SVRT_FCPROTERR); + alx_write_mem32(hw, ALX_UE_SVRT, val); + + /* wol 25M & pclk */ + val = alx_read_mem32(hw, ALX_MASTER); + if (alx_is_rev_a(rev) && alx_hw_with_cr(hw)) { + if ((val & ALX_MASTER_WAKEN_25M) == 0 || + (val & ALX_MASTER_PCLKSEL_SRDS) == 0) + alx_write_mem32(hw, ALX_MASTER, + val | ALX_MASTER_PCLKSEL_SRDS | + ALX_MASTER_WAKEN_25M); + } else { + if ((val & ALX_MASTER_WAKEN_25M) == 0 || + (val & ALX_MASTER_PCLKSEL_SRDS) != 0) + alx_write_mem32(hw, ALX_MASTER, + (val & ~ALX_MASTER_PCLKSEL_SRDS) | + ALX_MASTER_WAKEN_25M); + } + + /* ASPM setting */ + alx_enable_aspm(hw, true, true); + + udelay(10); +} + +void alx_start_mac(struct alx_hw *hw) +{ + u32 mac, txq, rxq; + + rxq = alx_read_mem32(hw, ALX_RXQ0); + alx_write_mem32(hw, ALX_RXQ0, rxq | ALX_RXQ0_EN); + txq = alx_read_mem32(hw, ALX_TXQ0); + alx_write_mem32(hw, ALX_TXQ0, txq | ALX_TXQ0_EN); + + mac = hw->rx_ctrl; + if (hw->duplex == DUPLEX_FULL) + mac |= ALX_MAC_CTRL_FULLD; + else + mac &= ~ALX_MAC_CTRL_FULLD; + ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED, + hw->link_speed == SPEED_1000 ? ALX_MAC_CTRL_SPEED_1000 : + ALX_MAC_CTRL_SPEED_10_100); + mac |= ALX_MAC_CTRL_TX_EN | ALX_MAC_CTRL_RX_EN; + hw->rx_ctrl = mac; + alx_write_mem32(hw, ALX_MAC_CTRL, mac); +} + +void alx_cfg_mac_flowcontrol(struct alx_hw *hw, u8 fc) +{ + if (fc & ALX_FC_RX) + hw->rx_ctrl |= ALX_MAC_CTRL_RXFC_EN; + else + hw->rx_ctrl &= ~ALX_MAC_CTRL_RXFC_EN; + + if (fc & ALX_FC_TX) + hw->rx_ctrl |= ALX_MAC_CTRL_TXFC_EN; + else + hw->rx_ctrl &= ~ALX_MAC_CTRL_TXFC_EN; + + alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); +} + +void alx_enable_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en) +{ + u32 pmctrl; + u8 rev = alx_hw_revision(hw); + + pmctrl = alx_read_mem32(hw, ALX_PMCTRL); + + ALX_SET_FIELD(pmctrl, ALX_PMCTRL_LCKDET_TIMER, + ALX_PMCTRL_LCKDET_TIMER_DEF); + pmctrl |= ALX_PMCTRL_RCVR_WT_1US | + ALX_PMCTRL_L1_CLKSW_EN | + ALX_PMCTRL_L1_SRDSRX_PWD; + ALX_SET_FIELD(pmctrl, ALX_PMCTRL_L1REQ_TO, ALX_PMCTRL_L1REG_TO_DEF); + ALX_SET_FIELD(pmctrl, ALX_PMCTRL_L1_TIMER, ALX_PMCTRL_L1_TIMER_16US); + pmctrl &= ~(ALX_PMCTRL_L1_SRDS_EN | + ALX_PMCTRL_L1_SRDSPLL_EN | + ALX_PMCTRL_L1_BUFSRX_EN | + ALX_PMCTRL_SADLY_EN | + ALX_PMCTRL_HOTRST_WTEN| + ALX_PMCTRL_L0S_EN | + ALX_PMCTRL_L1_EN | + ALX_PMCTRL_ASPM_FCEN | + ALX_PMCTRL_TXL1_AFTER_L0S | + ALX_PMCTRL_RXL1_AFTER_L0S); + if (alx_is_rev_a(rev) && alx_hw_with_cr(hw)) + pmctrl |= ALX_PMCTRL_L1_SRDS_EN | ALX_PMCTRL_L1_SRDSPLL_EN; + + if (l0s_en) + pmctrl |= (ALX_PMCTRL_L0S_EN | ALX_PMCTRL_ASPM_FCEN); + if (l1_en) + pmctrl |= (ALX_PMCTRL_L1_EN | ALX_PMCTRL_ASPM_FCEN); + + alx_write_mem32(hw, ALX_PMCTRL, pmctrl); +} + + +static u32 ethadv_to_hw_cfg(struct alx_hw *hw, u32 ethadv_cfg) +{ + u32 cfg = 0; + + if (ethadv_cfg & ADVERTISED_Autoneg) { + cfg |= ALX_DRV_PHY_AUTO; + if (ethadv_cfg & ADVERTISED_10baseT_Half) + cfg |= ALX_DRV_PHY_10; + if (ethadv_cfg & ADVERTISED_10baseT_Full) + cfg |= ALX_DRV_PHY_10 | ALX_DRV_PHY_DUPLEX; + if (ethadv_cfg & ADVERTISED_100baseT_Half) + cfg |= ALX_DRV_PHY_100; + if (ethadv_cfg & ADVERTISED_100baseT_Full) + cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX; + if (ethadv_cfg & ADVERTISED_1000baseT_Half) + cfg |= ALX_DRV_PHY_1000; + if (ethadv_cfg & ADVERTISED_1000baseT_Full) + cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX; + if (ethadv_cfg & ADVERTISED_Pause) + cfg |= ADVERTISE_PAUSE_CAP; + if (ethadv_cfg & ADVERTISED_Asym_Pause) + cfg |= ADVERTISE_PAUSE_ASYM; + } else { + switch (ethadv_cfg) { + case ADVERTISED_10baseT_Half: + cfg |= ALX_DRV_PHY_10; + break; + case ADVERTISED_100baseT_Half: + cfg |= ALX_DRV_PHY_100; + break; + case ADVERTISED_10baseT_Full: + cfg |= ALX_DRV_PHY_10 | ALX_DRV_PHY_DUPLEX; + break; + case ADVERTISED_100baseT_Full: + cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX; + break; + } + } + + return cfg; +} + +int alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl) +{ + u16 adv, giga, cr; + u32 val; + int err = 0; + + alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, 0); + val = alx_read_mem32(hw, ALX_DRV); + ALX_SET_FIELD(val, ALX_DRV_PHY, 0); + + if (ethadv & ADVERTISED_Autoneg) { + adv = ADVERTISE_CSMA; + adv |= ethtool_adv_to_mii_adv_t(ethadv); + + if (flowctrl & ALX_FC_ANEG) { + if (flowctrl & ALX_FC_RX) { + adv |= ADVERTISED_Pause; + if (!(flowctrl & ALX_FC_TX)) + adv |= ADVERTISED_Asym_Pause; + } else if (flowctrl & ALX_FC_TX) { + adv |= ADVERTISED_Asym_Pause; + } + } + giga = 0; + if (alx_hw_giga(hw)) + giga = ethtool_adv_to_mii_ctrl1000_t(ethadv); + + cr = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART; + + if (alx_write_phy_reg(hw, MII_ADVERTISE, adv) || + alx_write_phy_reg(hw, MII_CTRL1000, giga) || + alx_write_phy_reg(hw, MII_BMCR, cr)) + err = -EBUSY; + } else { + cr = BMCR_RESET; + if (ethadv == ADVERTISED_100baseT_Half || + ethadv == ADVERTISED_100baseT_Full) + cr |= BMCR_SPEED100; + if (ethadv == ADVERTISED_10baseT_Full || + ethadv == ADVERTISED_100baseT_Full) + cr |= BMCR_FULLDPLX; + + err = alx_write_phy_reg(hw, MII_BMCR, cr); + } + + if (!err) { + alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, ALX_PHY_INITED); + val |= ethadv_to_hw_cfg(hw, ethadv); + } + + alx_write_mem32(hw, ALX_DRV, val); + + return err; +} + + +void alx_post_phy_link(struct alx_hw *hw) +{ + u16 phy_val, len, agc; + u8 revid = alx_hw_revision(hw); + bool adj_th = revid == ALX_REV_B0; + + if (revid != ALX_REV_B0 && !alx_is_rev_a(revid)) + return; + + /* 1000BT/AZ, wrong cable length */ + if (hw->link_speed != SPEED_UNKNOWN) { + alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL6, + &phy_val); + len = ALX_GET_FIELD(phy_val, ALX_CLDCTRL6_CAB_LEN); + alx_read_phy_dbg(hw, ALX_MIIDBG_AGC, &phy_val); + agc = ALX_GET_FIELD(phy_val, ALX_AGC_2_VGA); + + if ((hw->link_speed == SPEED_1000 && + (len > ALX_CLDCTRL6_CAB_LEN_SHORT1G || + (len == 0 && agc > ALX_AGC_LONG1G_LIMT))) || + (hw->link_speed == SPEED_100 && + (len > ALX_CLDCTRL6_CAB_LEN_SHORT100M || + (len == 0 && agc > ALX_AGC_LONG100M_LIMT)))) { + alx_write_phy_dbg(hw, ALX_MIIDBG_AZ_ANADECT, + ALX_AZ_ANADECT_LONG); + alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE, + &phy_val); + alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE, + phy_val | ALX_AFE_10BT_100M_TH); + } else { + alx_write_phy_dbg(hw, ALX_MIIDBG_AZ_ANADECT, + ALX_AZ_ANADECT_DEF); + alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, + ALX_MIIEXT_AFE, &phy_val); + alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE, + phy_val & ~ALX_AFE_10BT_100M_TH); + } + + /* threshold adjust */ + if (adj_th && hw->lnk_patch) { + if (hw->link_speed == SPEED_100) { + alx_write_phy_dbg(hw, ALX_MIIDBG_MSE16DB, + ALX_MSE16DB_UP); + } else if (hw->link_speed == SPEED_1000) { + /* + * Giga link threshold, raise the tolerance of + * noise 50% + */ + alx_read_phy_dbg(hw, ALX_MIIDBG_MSE20DB, + &phy_val); + ALX_SET_FIELD(phy_val, ALX_MSE20DB_TH, + ALX_MSE20DB_TH_HI); + alx_write_phy_dbg(hw, ALX_MIIDBG_MSE20DB, + phy_val); + } + } + } else { + alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE, + &phy_val); + alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE, + phy_val & ~ALX_AFE_10BT_100M_TH); + + if (adj_th && hw->lnk_patch) { + alx_write_phy_dbg(hw, ALX_MIIDBG_MSE16DB, + ALX_MSE16DB_DOWN); + alx_read_phy_dbg(hw, ALX_MIIDBG_MSE20DB, &phy_val); + ALX_SET_FIELD(phy_val, ALX_MSE20DB_TH, + ALX_MSE20DB_TH_DEF); + alx_write_phy_dbg(hw, ALX_MIIDBG_MSE20DB, phy_val); + } + } +} + +bool alx_phy_configured(struct alx_hw *hw) +{ + u32 cfg, hw_cfg; + + cfg = ethadv_to_hw_cfg(hw, hw->adv_cfg); + cfg = ALX_GET_FIELD(cfg, ALX_DRV_PHY); + hw_cfg = alx_get_phy_config(hw); + + if (hw_cfg == ALX_DRV_PHY_UNKNOWN) + return false; + + return cfg == hw_cfg; +} + +int alx_read_phy_link(struct alx_hw *hw) +{ + struct pci_dev *pdev = hw->pdev; + u16 bmsr, giga; + int err; + + err = alx_read_phy_reg(hw, MII_BMSR, &bmsr); + if (err) + return err; + + err = alx_read_phy_reg(hw, MII_BMSR, &bmsr); + if (err) + return err; + + if (!(bmsr & BMSR_LSTATUS)) { + hw->link_speed = SPEED_UNKNOWN; + hw->duplex = DUPLEX_UNKNOWN; + return 0; + } + + /* speed/duplex result is saved in PHY Specific Status Register */ + err = alx_read_phy_reg(hw, ALX_MII_GIGA_PSSR, &giga); + if (err) + return err; + + if (!(giga & ALX_GIGA_PSSR_SPD_DPLX_RESOLVED)) + goto wrong_speed; + + switch (giga & ALX_GIGA_PSSR_SPEED) { + case ALX_GIGA_PSSR_1000MBS: + hw->link_speed = SPEED_1000; + break; + case ALX_GIGA_PSSR_100MBS: + hw->link_speed = SPEED_100; + break; + case ALX_GIGA_PSSR_10MBS: + hw->link_speed = SPEED_10; + break; + default: + goto wrong_speed; + } + + hw->duplex = (giga & ALX_GIGA_PSSR_DPLX) ? DUPLEX_FULL : DUPLEX_HALF; + return 0; + +wrong_speed: + dev_err(&pdev->dev, "invalid PHY speed/duplex: 0x%x\n", giga); + return -EINVAL; +} + +int alx_clear_phy_intr(struct alx_hw *hw) +{ + u16 isr; + + /* clear interrupt status by reading it */ + return alx_read_phy_reg(hw, ALX_MII_ISR, &isr); +} + +void alx_disable_rss(struct alx_hw *hw) +{ + u32 ctrl = alx_read_mem32(hw, ALX_RXQ0); + + ctrl &= ~ALX_RXQ0_RSS_HASH_EN; + alx_write_mem32(hw, ALX_RXQ0, ctrl); +} + +void alx_configure_basic(struct alx_hw *hw) +{ + u32 val, raw_mtu, max_payload; + u16 val16; + u8 chip_rev = alx_hw_revision(hw); + + alx_set_macaddr(hw, hw->mac_addr); + + alx_write_mem32(hw, ALX_CLK_GATE, ALX_CLK_GATE_ALL); + + /* idle timeout to switch clk_125M */ + if (chip_rev >= ALX_REV_B0) + alx_write_mem32(hw, ALX_IDLE_DECISN_TIMER, + ALX_IDLE_DECISN_TIMER_DEF); + + alx_write_mem32(hw, ALX_SMB_TIMER, hw->smb_timer * 500UL); + + val = alx_read_mem32(hw, ALX_MASTER); + val |= ALX_MASTER_IRQMOD2_EN | + ALX_MASTER_IRQMOD1_EN | + ALX_MASTER_SYSALVTIMER_EN; + alx_write_mem32(hw, ALX_MASTER, val); + alx_write_mem32(hw, ALX_IRQ_MODU_TIMER, + (hw->imt >> 1) << ALX_IRQ_MODU_TIMER1_SHIFT); + /* intr re-trig timeout */ + alx_write_mem32(hw, ALX_INT_RETRIG, ALX_INT_RETRIG_TO); + /* tpd threshold to trig int */ + alx_write_mem32(hw, ALX_TINT_TPD_THRSHLD, hw->ith_tpd); + alx_write_mem32(hw, ALX_TINT_TIMER, hw->imt); + + raw_mtu = hw->mtu + ETH_HLEN; + alx_write_mem32(hw, ALX_MTU, raw_mtu + 8); + if (raw_mtu > ALX_MTU_JUMBO_TH) + hw->rx_ctrl &= ~ALX_MAC_CTRL_FAST_PAUSE; + + if ((raw_mtu + 8) < ALX_TXQ1_JUMBO_TSO_TH) + val = (raw_mtu + 8 + 7) >> 3; + else + val = ALX_TXQ1_JUMBO_TSO_TH >> 3; + alx_write_mem32(hw, ALX_TXQ1, val | ALX_TXQ1_ERRLGPKT_DROP_EN); + + max_payload = pcie_get_readrq(hw->pdev) >> 8; + /* + * if BIOS had changed the default dma read max length, + * restore it to default value + */ + if (max_payload < ALX_DEV_CTRL_MAXRRS_MIN) + pcie_set_readrq(hw->pdev, 128 << ALX_DEV_CTRL_MAXRRS_MIN); + + val = ALX_TXQ_TPD_BURSTPREF_DEF << ALX_TXQ0_TPD_BURSTPREF_SHIFT | + ALX_TXQ0_MODE_ENHANCE | ALX_TXQ0_LSO_8023_EN | + ALX_TXQ0_SUPT_IPOPT | + ALX_TXQ_TXF_BURST_PREF_DEF << ALX_TXQ0_TXF_BURST_PREF_SHIFT; + alx_write_mem32(hw, ALX_TXQ0, val); + val = ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q1_NUMPREF_SHIFT | + ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q2_NUMPREF_SHIFT | + ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q3_NUMPREF_SHIFT | + ALX_HQTPD_BURST_EN; + alx_write_mem32(hw, ALX_HQTPD, val); + + /* rxq, flow control */ + val = alx_read_mem32(hw, ALX_SRAM5); + val = ALX_GET_FIELD(val, ALX_SRAM_RXF_LEN) << 3; + if (val > ALX_SRAM_RXF_LEN_8K) { + val16 = ALX_MTU_STD_ALGN >> 3; + val = (val - ALX_RXQ2_RXF_FLOW_CTRL_RSVD) >> 3; + } else { + val16 = ALX_MTU_STD_ALGN >> 3; + val = (val - ALX_MTU_STD_ALGN) >> 3; + } + alx_write_mem32(hw, ALX_RXQ2, + val16 << ALX_RXQ2_RXF_XOFF_THRESH_SHIFT | + val << ALX_RXQ2_RXF_XON_THRESH_SHIFT); + val = ALX_RXQ0_NUM_RFD_PREF_DEF << ALX_RXQ0_NUM_RFD_PREF_SHIFT | + ALX_RXQ0_RSS_MODE_DIS << ALX_RXQ0_RSS_MODE_SHIFT | + ALX_RXQ0_IDT_TBL_SIZE_DEF << ALX_RXQ0_IDT_TBL_SIZE_SHIFT | + ALX_RXQ0_RSS_HSTYP_ALL | ALX_RXQ0_RSS_HASH_EN | + ALX_RXQ0_IPV6_PARSE_EN; + + if (alx_hw_giga(hw)) + ALX_SET_FIELD(val, ALX_RXQ0_ASPM_THRESH, + ALX_RXQ0_ASPM_THRESH_100M); + + alx_write_mem32(hw, ALX_RXQ0, val); + + val = alx_read_mem32(hw, ALX_DMA); + val = ALX_DMA_RORDER_MODE_OUT << ALX_DMA_RORDER_MODE_SHIFT | + ALX_DMA_RREQ_PRI_DATA | + max_payload << ALX_DMA_RREQ_BLEN_SHIFT | + ALX_DMA_WDLY_CNT_DEF << ALX_DMA_WDLY_CNT_SHIFT | + ALX_DMA_RDLY_CNT_DEF << ALX_DMA_RDLY_CNT_SHIFT | + (hw->dma_chnl - 1) << ALX_DMA_RCHNL_SEL_SHIFT; + alx_write_mem32(hw, ALX_DMA, val); + + /* default multi-tx-q weights */ + val = ALX_WRR_PRI_RESTRICT_NONE << ALX_WRR_PRI_SHIFT | + 4 << ALX_WRR_PRI0_SHIFT | + 4 << ALX_WRR_PRI1_SHIFT | + 4 << ALX_WRR_PRI2_SHIFT | + 4 << ALX_WRR_PRI3_SHIFT; + alx_write_mem32(hw, ALX_WRR, val); +} + +bool alx_get_phy_info(struct alx_hw *hw) +{ + u16 devs1, devs2; + + if (alx_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id[0]) || + alx_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id[1])) + return false; + + /* since we haven't PMA/PMD status2 register, we can't + * use mdio45_probe function for prtad and mmds. + * use fixed MMD3 to get mmds. + */ + if (alx_read_phy_ext(hw, 3, MDIO_DEVS1, &devs1) || + alx_read_phy_ext(hw, 3, MDIO_DEVS2, &devs2)) + return false; + hw->mdio.mmds = devs1 | devs2 << 16; + + return true; +} + +void alx_update_hw_stats(struct alx_hw *hw) +{ + /* RX stats */ + hw->stats.rx_ok += alx_read_mem32(hw, ALX_MIB_RX_OK); + hw->stats.rx_bcast += alx_read_mem32(hw, ALX_MIB_RX_BCAST); + hw->stats.rx_mcast += alx_read_mem32(hw, ALX_MIB_RX_MCAST); + hw->stats.rx_pause += alx_read_mem32(hw, ALX_MIB_RX_PAUSE); + hw->stats.rx_ctrl += alx_read_mem32(hw, ALX_MIB_RX_CTRL); + hw->stats.rx_fcs_err += alx_read_mem32(hw, ALX_MIB_RX_FCS_ERR); + hw->stats.rx_len_err += alx_read_mem32(hw, ALX_MIB_RX_LEN_ERR); + hw->stats.rx_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_BYTE_CNT); + hw->stats.rx_runt += alx_read_mem32(hw, ALX_MIB_RX_RUNT); + hw->stats.rx_frag += alx_read_mem32(hw, ALX_MIB_RX_FRAG); + hw->stats.rx_sz_64B += alx_read_mem32(hw, ALX_MIB_RX_SZ_64B); + hw->stats.rx_sz_127B += alx_read_mem32(hw, ALX_MIB_RX_SZ_127B); + hw->stats.rx_sz_255B += alx_read_mem32(hw, ALX_MIB_RX_SZ_255B); + hw->stats.rx_sz_511B += alx_read_mem32(hw, ALX_MIB_RX_SZ_511B); + hw->stats.rx_sz_1023B += alx_read_mem32(hw, ALX_MIB_RX_SZ_1023B); + hw->stats.rx_sz_1518B += alx_read_mem32(hw, ALX_MIB_RX_SZ_1518B); + hw->stats.rx_sz_max += alx_read_mem32(hw, ALX_MIB_RX_SZ_MAX); + hw->stats.rx_ov_sz += alx_read_mem32(hw, ALX_MIB_RX_OV_SZ); + hw->stats.rx_ov_rxf += alx_read_mem32(hw, ALX_MIB_RX_OV_RXF); + hw->stats.rx_ov_rrd += alx_read_mem32(hw, ALX_MIB_RX_OV_RRD); + hw->stats.rx_align_err += alx_read_mem32(hw, ALX_MIB_RX_ALIGN_ERR); + hw->stats.rx_bc_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_BCCNT); + hw->stats.rx_mc_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_MCCNT); + hw->stats.rx_err_addr += alx_read_mem32(hw, ALX_MIB_RX_ERRADDR); + + /* TX stats */ + hw->stats.tx_ok += alx_read_mem32(hw, ALX_MIB_TX_OK); + hw->stats.tx_bcast += alx_read_mem32(hw, ALX_MIB_TX_BCAST); + hw->stats.tx_mcast += alx_read_mem32(hw, ALX_MIB_TX_MCAST); + hw->stats.tx_pause += alx_read_mem32(hw, ALX_MIB_TX_PAUSE); + hw->stats.tx_exc_defer += alx_read_mem32(hw, ALX_MIB_TX_EXC_DEFER); + hw->stats.tx_ctrl += alx_read_mem32(hw, ALX_MIB_TX_CTRL); + hw->stats.tx_defer += alx_read_mem32(hw, ALX_MIB_TX_DEFER); + hw->stats.tx_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_BYTE_CNT); + hw->stats.tx_sz_64B += alx_read_mem32(hw, ALX_MIB_TX_SZ_64B); + hw->stats.tx_sz_127B += alx_read_mem32(hw, ALX_MIB_TX_SZ_127B); + hw->stats.tx_sz_255B += alx_read_mem32(hw, ALX_MIB_TX_SZ_255B); + hw->stats.tx_sz_511B += alx_read_mem32(hw, ALX_MIB_TX_SZ_511B); + hw->stats.tx_sz_1023B += alx_read_mem32(hw, ALX_MIB_TX_SZ_1023B); + hw->stats.tx_sz_1518B += alx_read_mem32(hw, ALX_MIB_TX_SZ_1518B); + hw->stats.tx_sz_max += alx_read_mem32(hw, ALX_MIB_TX_SZ_MAX); + hw->stats.tx_single_col += alx_read_mem32(hw, ALX_MIB_TX_SINGLE_COL); + hw->stats.tx_multi_col += alx_read_mem32(hw, ALX_MIB_TX_MULTI_COL); + hw->stats.tx_late_col += alx_read_mem32(hw, ALX_MIB_TX_LATE_COL); + hw->stats.tx_abort_col += alx_read_mem32(hw, ALX_MIB_TX_ABORT_COL); + hw->stats.tx_underrun += alx_read_mem32(hw, ALX_MIB_TX_UNDERRUN); + hw->stats.tx_trd_eop += alx_read_mem32(hw, ALX_MIB_TX_TRD_EOP); + hw->stats.tx_len_err += alx_read_mem32(hw, ALX_MIB_TX_LEN_ERR); + hw->stats.tx_trunc += alx_read_mem32(hw, ALX_MIB_TX_TRUNC); + hw->stats.tx_bc_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_BCCNT); + hw->stats.tx_mc_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_MCCNT); + + hw->stats.update += alx_read_mem32(hw, ALX_MIB_UPDATE); +} diff --git a/drivers/net/ethernet/atheros/alx/hw.h b/drivers/net/ethernet/atheros/alx/hw.h new file mode 100644 index 00000000000..15548802d6f --- /dev/null +++ b/drivers/net/ethernet/atheros/alx/hw.h @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net> + * + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ALX_HW_H_ +#define ALX_HW_H_ +#include <linux/types.h> +#include <linux/mdio.h> +#include <linux/pci.h> +#include "reg.h" + +/* Transmit Packet Descriptor, contains 4 32-bit words. + * + * 31 16 0 + * +----------------+----------------+ + * | vlan-tag | buf length | + * +----------------+----------------+ + * | Word 1 | + * +----------------+----------------+ + * | Word 2: buf addr lo | + * +----------------+----------------+ + * | Word 3: buf addr hi | + * +----------------+----------------+ + * + * Word 2 and 3 combine to form a 64-bit buffer address + * + * Word 1 has three forms, depending on the state of bit 8/12/13: + * if bit8 =='1', the definition is just for custom checksum offload. + * if bit8 == '0' && bit12 == '1' && bit13 == '1', the *FIRST* descriptor + * for the skb is special for LSO V2, Word 2 become total skb length , + * Word 3 is meaningless. + * other condition, the definition is for general skb or ip/tcp/udp + * checksum or LSO(TSO) offload. + * + * Here is the depiction: + * + * 0-+ 0-+ + * 1 | 1 | + * 2 | 2 | + * 3 | Payload offset 3 | L4 header offset + * 4 | (7:0) 4 | (7:0) + * 5 | 5 | + * 6 | 6 | + * 7-+ 7-+ + * 8 Custom csum enable = 1 8 Custom csum enable = 0 + * 9 General IPv4 checksum 9 General IPv4 checksum + * 10 General TCP checksum 10 General TCP checksum + * 11 General UDP checksum 11 General UDP checksum + * 12 Large Send Segment enable 12 Large Send Segment enable + * 13 Large Send Segment type 13 Large Send Segment type + * 14 VLAN tagged 14 VLAN tagged + * 15 Insert VLAN tag 15 Insert VLAN tag + * 16 IPv4 packet 16 IPv4 packet + * 17 Ethernet frame type 17 Ethernet frame type + * 18-+ 18-+ + * 19 | 19 | + * 20 | 20 | + * 21 | Custom csum offset 21 | + * 22 | (25:18) 22 | + * 23 | 23 | MSS (30:18) + * 24 | 24 | + * 25-+ 25 | + * 26-+ 26 | + * 27 | 27 | + * 28 | Reserved 28 | + * 29 | 29 | + * 30-+ 30-+ + * 31 End of packet 31 End of packet + */ +struct alx_txd { + __le16 len; + __le16 vlan_tag; + __le32 word1; + union { + __le64 addr; + struct { + __le32 pkt_len; + __le32 resvd; + } l; + } adrl; +} __packed; + +/* tpd word 1 */ +#define TPD_CXSUMSTART_MASK 0x00FF +#define TPD_CXSUMSTART_SHIFT 0 +#define TPD_L4HDROFFSET_MASK 0x00FF +#define TPD_L4HDROFFSET_SHIFT 0 +#define TPD_CXSUM_EN_MASK 0x0001 +#define TPD_CXSUM_EN_SHIFT 8 +#define TPD_IP_XSUM_MASK 0x0001 +#define TPD_IP_XSUM_SHIFT 9 +#define TPD_TCP_XSUM_MASK 0x0001 +#define TPD_TCP_XSUM_SHIFT 10 +#define TPD_UDP_XSUM_MASK 0x0001 +#define TPD_UDP_XSUM_SHIFT 11 +#define TPD_LSO_EN_MASK 0x0001 +#define TPD_LSO_EN_SHIFT 12 +#define TPD_LSO_V2_MASK 0x0001 +#define TPD_LSO_V2_SHIFT 13 +#define TPD_VLTAGGED_MASK 0x0001 +#define TPD_VLTAGGED_SHIFT 14 +#define TPD_INS_VLTAG_MASK 0x0001 +#define TPD_INS_VLTAG_SHIFT 15 +#define TPD_IPV4_MASK 0x0001 +#define TPD_IPV4_SHIFT 16 +#define TPD_ETHTYPE_MASK 0x0001 +#define TPD_ETHTYPE_SHIFT 17 +#define TPD_CXSUMOFFSET_MASK 0x00FF +#define TPD_CXSUMOFFSET_SHIFT 18 +#define TPD_MSS_MASK 0x1FFF +#define TPD_MSS_SHIFT 18 +#define TPD_EOP_MASK 0x0001 +#define TPD_EOP_SHIFT 31 + +#define DESC_GET(_x, _name) ((_x) >> _name##SHIFT & _name##MASK) + +/* Receive Free Descriptor */ +struct alx_rfd { + __le64 addr; /* data buffer address, length is + * declared in register --- every + * buffer has the same size + */ +} __packed; + +/* Receive Return Descriptor, contains 4 32-bit words. + * + * 31 16 0 + * +----------------+----------------+ + * | Word 0 | + * +----------------+----------------+ + * | Word 1: RSS Hash value | + * +----------------+----------------+ + * | Word 2 | + * +----------------+----------------+ + * | Word 3 | + * +----------------+----------------+ + * + * Word 0 depiction & Word 2 depiction: + * + * 0--+ 0--+ + * 1 | 1 | + * 2 | 2 | + * 3 | 3 | + * 4 | 4 | + * 5 | 5 | + * 6 | 6 | + * 7 | IP payload checksum 7 | VLAN tag + * 8 | (15:0) 8 | (15:0) + * 9 | 9 | + * 10 | 10 | + * 11 | 11 | + * 12 | 12 | + * 13 | 13 | + * 14 | 14 | + * 15-+ 15-+ + * 16-+ 16-+ + * 17 | Number of RFDs 17 | + * 18 | (19:16) 18 | + * 19-+ 19 | Protocol ID + * 20-+ 20 | (23:16) + * 21 | 21 | + * 22 | 22 | + * 23 | 23-+ + * 24 | 24 | Reserved + * 25 | Start index of RFD-ring 25-+ + * 26 | (31:20) 26 | RSS Q-num (27:25) + * 27 | 27-+ + * 28 | 28-+ + * 29 | 29 | RSS Hash algorithm + * 30 | 30 | (31:28) + * 31-+ 31-+ + * + * Word 3 depiction: + * + * 0--+ + * 1 | + * 2 | + * 3 | + * 4 | + * 5 | + * 6 | + * 7 | Packet length (include FCS) + * 8 | (13:0) + * 9 | + * 10 | + * 11 | + * 12 | + * 13-+ + * 14 L4 Header checksum error + * 15 IPv4 checksum error + * 16 VLAN tagged + * 17-+ + * 18 | Protocol ID (19:17) + * 19-+ + * 20 Receive error summary + * 21 FCS(CRC) error + * 22 Frame alignment error + * 23 Truncated packet + * 24 Runt packet + * 25 Incomplete packet due to insufficient rx-desc + * 26 Broadcast packet + * 27 Multicast packet + * 28 Ethernet type (EII or 802.3) + * 29 FIFO overflow + * 30 Length error (for 802.3, length field mismatch with actual len) + * 31 Updated, indicate to driver that this RRD is refreshed. + */ +struct alx_rrd { + __le32 word0; + __le32 rss_hash; + __le32 word2; + __le32 word3; +} __packed; + +/* rrd word 0 */ +#define RRD_XSUM_MASK 0xFFFF +#define RRD_XSUM_SHIFT 0 +#define RRD_NOR_MASK 0x000F +#define RRD_NOR_SHIFT 16 +#define RRD_SI_MASK 0x0FFF +#define RRD_SI_SHIFT 20 + +/* rrd word 2 */ +#define RRD_VLTAG_MASK 0xFFFF +#define RRD_VLTAG_SHIFT 0 +#define RRD_PID_MASK 0x00FF +#define RRD_PID_SHIFT 16 +/* non-ip packet */ +#define RRD_PID_NONIP 0 +/* ipv4(only) */ +#define RRD_PID_IPV4 1 +/* tcp/ipv6 */ +#define RRD_PID_IPV6TCP 2 +/* tcp/ipv4 */ +#define RRD_PID_IPV4TCP 3 +/* udp/ipv6 */ +#define RRD_PID_IPV6UDP 4 +/* udp/ipv4 */ +#define RRD_PID_IPV4UDP 5 +/* ipv6(only) */ +#define RRD_PID_IPV6 6 +/* LLDP packet */ +#define RRD_PID_LLDP 7 +/* 1588 packet */ +#define RRD_PID_1588 8 +#define RRD_RSSQ_MASK 0x0007 +#define RRD_RSSQ_SHIFT 25 +#define RRD_RSSALG_MASK 0x000F +#define RRD_RSSALG_SHIFT 28 +#define RRD_RSSALG_TCPV6 0x1 +#define RRD_RSSALG_IPV6 0x2 +#define RRD_RSSALG_TCPV4 0x4 +#define RRD_RSSALG_IPV4 0x8 + +/* rrd word 3 */ +#define RRD_PKTLEN_MASK 0x3FFF +#define RRD_PKTLEN_SHIFT 0 +#define RRD_ERR_L4_MASK 0x0001 +#define RRD_ERR_L4_SHIFT 14 +#define RRD_ERR_IPV4_MASK 0x0001 +#define RRD_ERR_IPV4_SHIFT 15 +#define RRD_VLTAGGED_MASK 0x0001 +#define RRD_VLTAGGED_SHIFT 16 +#define RRD_OLD_PID_MASK 0x0007 +#define RRD_OLD_PID_SHIFT 17 +#define RRD_ERR_RES_MASK 0x0001 +#define RRD_ERR_RES_SHIFT 20 +#define RRD_ERR_FCS_MASK 0x0001 +#define RRD_ERR_FCS_SHIFT 21 +#define RRD_ERR_FAE_MASK 0x0001 +#define RRD_ERR_FAE_SHIFT 22 +#define RRD_ERR_TRUNC_MASK 0x0001 +#define RRD_ERR_TRUNC_SHIFT 23 +#define RRD_ERR_RUNT_MASK 0x0001 +#define RRD_ERR_RUNT_SHIFT 24 +#define RRD_ERR_ICMP_MASK 0x0001 +#define RRD_ERR_ICMP_SHIFT 25 +#define RRD_BCAST_MASK 0x0001 +#define RRD_BCAST_SHIFT 26 +#define RRD_MCAST_MASK 0x0001 +#define RRD_MCAST_SHIFT 27 +#define RRD_ETHTYPE_MASK 0x0001 +#define RRD_ETHTYPE_SHIFT 28 +#define RRD_ERR_FIFOV_MASK 0x0001 +#define RRD_ERR_FIFOV_SHIFT 29 +#define RRD_ERR_LEN_MASK 0x0001 +#define RRD_ERR_LEN_SHIFT 30 +#define RRD_UPDATED_MASK 0x0001 +#define RRD_UPDATED_SHIFT 31 + + +#define ALX_MAX_SETUP_LNK_CYCLE 50 + +/* for FlowControl */ +#define ALX_FC_RX 0x01 +#define ALX_FC_TX 0x02 +#define ALX_FC_ANEG 0x04 + +/* for sleep control */ +#define ALX_SLEEP_WOL_PHY 0x00000001 +#define ALX_SLEEP_WOL_MAGIC 0x00000002 +#define ALX_SLEEP_CIFS 0x00000004 +#define ALX_SLEEP_ACTIVE (ALX_SLEEP_WOL_PHY | \ + ALX_SLEEP_WOL_MAGIC | \ + ALX_SLEEP_CIFS) + +/* for RSS hash type */ +#define ALX_RSS_HASH_TYPE_IPV4 0x1 +#define ALX_RSS_HASH_TYPE_IPV4_TCP 0x2 +#define ALX_RSS_HASH_TYPE_IPV6 0x4 +#define ALX_RSS_HASH_TYPE_IPV6_TCP 0x8 +#define ALX_RSS_HASH_TYPE_ALL (ALX_RSS_HASH_TYPE_IPV4 | \ + ALX_RSS_HASH_TYPE_IPV4_TCP | \ + ALX_RSS_HASH_TYPE_IPV6 | \ + ALX_RSS_HASH_TYPE_IPV6_TCP) +#define ALX_DEF_RXBUF_SIZE 1536 +#define ALX_MAX_JUMBO_PKT_SIZE (9*1024) +#define ALX_MAX_TSO_PKT_SIZE (7*1024) +#define ALX_MAX_FRAME_SIZE ALX_MAX_JUMBO_PKT_SIZE +#define ALX_MIN_FRAME_SIZE 68 +#define ALX_RAW_MTU(_mtu) (_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN) + +#define ALX_MAX_RX_QUEUES 8 +#define ALX_MAX_TX_QUEUES 4 +#define ALX_MAX_HANDLED_INTRS 5 + +#define ALX_ISR_MISC (ALX_ISR_PCIE_LNKDOWN | \ + ALX_ISR_DMAW | \ + ALX_ISR_DMAR | \ + ALX_ISR_SMB | \ + ALX_ISR_MANU | \ + ALX_ISR_TIMER) + +#define ALX_ISR_FATAL (ALX_ISR_PCIE_LNKDOWN | \ + ALX_ISR_DMAW | ALX_ISR_DMAR) + +#define ALX_ISR_ALERT (ALX_ISR_RXF_OV | \ + ALX_ISR_TXF_UR | \ + ALX_ISR_RFD_UR) + +#define ALX_ISR_ALL_QUEUES (ALX_ISR_TX_Q0 | \ + ALX_ISR_TX_Q1 | \ + ALX_ISR_TX_Q2 | \ + ALX_ISR_TX_Q3 | \ + ALX_ISR_RX_Q0 | \ + ALX_ISR_RX_Q1 | \ + ALX_ISR_RX_Q2 | \ + ALX_ISR_RX_Q3 | \ + ALX_ISR_RX_Q4 | \ + ALX_ISR_RX_Q5 | \ + ALX_ISR_RX_Q6 | \ + ALX_ISR_RX_Q7) + +/* Statistics counters collected by the MAC + * + * The order of the fields must match the strings in alx_gstrings_stats + * All stats fields should be u64 + * See ethtool.c + */ +struct alx_hw_stats { + /* rx */ + u64 rx_ok; /* good RX packets */ + u64 rx_bcast; /* good RX broadcast packets */ + u64 rx_mcast; /* good RX multicast packets */ + u64 rx_pause; /* RX pause frames */ + u64 rx_ctrl; /* RX control packets other than pause frames */ + u64 rx_fcs_err; /* RX packets with bad FCS */ + u64 rx_len_err; /* RX packets with length != actual size */ + u64 rx_byte_cnt; /* good bytes received. FCS is NOT included */ + u64 rx_runt; /* RX packets < 64 bytes with good FCS */ + u64 rx_frag; /* RX packets < 64 bytes with bad FCS */ + u64 rx_sz_64B; /* 64 byte RX packets */ + u64 rx_sz_127B; /* 65-127 byte RX packets */ + u64 rx_sz_255B; /* 128-255 byte RX packets */ + u64 rx_sz_511B; /* 256-511 byte RX packets */ + u64 rx_sz_1023B; /* 512-1023 byte RX packets */ + u64 rx_sz_1518B; /* 1024-1518 byte RX packets */ + u64 rx_sz_max; /* 1519 byte to MTU RX packets */ + u64 rx_ov_sz; /* truncated RX packets, size > MTU */ + u64 rx_ov_rxf; /* frames dropped due to RX FIFO overflow */ + u64 rx_ov_rrd; /* frames dropped due to RRD overflow */ + u64 rx_align_err; /* alignment errors */ + u64 rx_bc_byte_cnt; /* RX broadcast bytes, excluding FCS */ + u64 rx_mc_byte_cnt; /* RX multicast bytes, excluding FCS */ + u64 rx_err_addr; /* packets dropped due to address filtering */ + + /* tx */ + u64 tx_ok; /* good TX packets */ + u64 tx_bcast; /* good TX broadcast packets */ + u64 tx_mcast; /* good TX multicast packets */ + u64 tx_pause; /* TX pause frames */ + u64 tx_exc_defer; /* TX packets deferred excessively */ + u64 tx_ctrl; /* TX control frames, excluding pause frames */ + u64 tx_defer; /* TX packets deferred */ + u64 tx_byte_cnt; /* bytes transmitted, FCS is NOT included */ + u64 tx_sz_64B; /* 64 byte TX packets */ + u64 tx_sz_127B; /* 65-127 byte TX packets */ + u64 tx_sz_255B; /* 128-255 byte TX packets */ + u64 tx_sz_511B; /* 256-511 byte TX packets */ + u64 tx_sz_1023B; /* 512-1023 byte TX packets */ + u64 tx_sz_1518B; /* 1024-1518 byte TX packets */ + u64 tx_sz_max; /* 1519 byte to MTU TX packets */ + u64 tx_single_col; /* packets TX after a single collision */ + u64 tx_multi_col; /* packets TX after multiple collisions */ + u64 tx_late_col; /* TX packets with late collisions */ + u64 tx_abort_col; /* TX packets aborted w/excessive collisions */ + u64 tx_underrun; /* TX packets aborted due to TX FIFO underrun + * or TRD FIFO underrun + */ + u64 tx_trd_eop; /* reads beyond the EOP into the next frame + * when TRD was not written timely + */ + u64 tx_len_err; /* TX packets where length != actual size */ + u64 tx_trunc; /* TX packets truncated due to size > MTU */ + u64 tx_bc_byte_cnt; /* broadcast bytes transmitted, excluding FCS */ + u64 tx_mc_byte_cnt; /* multicast bytes transmitted, excluding FCS */ + u64 update; +}; + + +/* maximum interrupt vectors for msix */ +#define ALX_MAX_MSIX_INTRS 16 + +#define ALX_GET_FIELD(_data, _field) \ + (((_data) >> _field ## _SHIFT) & _field ## _MASK) + +#define ALX_SET_FIELD(_data, _field, _value) do { \ + (_data) &= ~(_field ## _MASK << _field ## _SHIFT); \ + (_data) |= ((_value) & _field ## _MASK) << _field ## _SHIFT;\ + } while (0) + +struct alx_hw { + struct pci_dev *pdev; + u8 __iomem *hw_addr; + + /* current & permanent mac addr */ + u8 mac_addr[ETH_ALEN]; + u8 perm_addr[ETH_ALEN]; + + u16 mtu; + u16 imt; + u8 dma_chnl; + u8 max_dma_chnl; + /* tpd threshold to trig INT */ + u32 ith_tpd; + u32 rx_ctrl; + u32 mc_hash[2]; + + u32 smb_timer; + /* SPEED_* + DUPLEX_*, SPEED_UNKNOWN if link is down */ + int link_speed; + u8 duplex; + + /* auto-neg advertisement or force mode config */ + u8 flowctrl; + u32 adv_cfg; + + spinlock_t mdio_lock; + struct mdio_if_info mdio; + u16 phy_id[2]; + + /* PHY link patch flag */ + bool lnk_patch; + + /* cumulated stats from the hardware (registers are cleared on read) */ + struct alx_hw_stats stats; +}; + +static inline int alx_hw_revision(struct alx_hw *hw) +{ + return hw->pdev->revision >> ALX_PCI_REVID_SHIFT; +} + +static inline bool alx_hw_with_cr(struct alx_hw *hw) +{ + return hw->pdev->revision & 1; +} + +static inline bool alx_hw_giga(struct alx_hw *hw) +{ + return hw->pdev->device & 1; +} + +static inline void alx_write_mem8(struct alx_hw *hw, u32 reg, u8 val) +{ + writeb(val, hw->hw_addr + reg); +} + +static inline void alx_write_mem16(struct alx_hw *hw, u32 reg, u16 val) +{ + writew(val, hw->hw_addr + reg); +} + +static inline u16 alx_read_mem16(struct alx_hw *hw, u32 reg) +{ + return readw(hw->hw_addr + reg); +} + +static inline void alx_write_mem32(struct alx_hw *hw, u32 reg, u32 val) +{ + writel(val, hw->hw_addr + reg); +} + +static inline u32 alx_read_mem32(struct alx_hw *hw, u32 reg) +{ + return readl(hw->hw_addr + reg); +} + +static inline void alx_post_write(struct alx_hw *hw) +{ + readl(hw->hw_addr); +} + +int alx_get_perm_macaddr(struct alx_hw *hw, u8 *addr); +void alx_reset_phy(struct alx_hw *hw); +void alx_reset_pcie(struct alx_hw *hw); +void alx_enable_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en); +int alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl); +void alx_post_phy_link(struct alx_hw *hw); +int alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data); +int alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data); +int alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata); +int alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data); +int alx_read_phy_link(struct alx_hw *hw); +int alx_clear_phy_intr(struct alx_hw *hw); +void alx_cfg_mac_flowcontrol(struct alx_hw *hw, u8 fc); +void alx_start_mac(struct alx_hw *hw); +int alx_reset_mac(struct alx_hw *hw); +void alx_set_macaddr(struct alx_hw *hw, const u8 *addr); +bool alx_phy_configured(struct alx_hw *hw); +void alx_configure_basic(struct alx_hw *hw); +void alx_disable_rss(struct alx_hw *hw); +bool alx_get_phy_info(struct alx_hw *hw); +void alx_update_hw_stats(struct alx_hw *hw); + +static inline u32 alx_speed_to_ethadv(int speed, u8 duplex) +{ + if (speed == SPEED_1000 && duplex == DUPLEX_FULL) + return ADVERTISED_1000baseT_Full; + if (speed == SPEED_100 && duplex == DUPLEX_FULL) + return ADVERTISED_100baseT_Full; + if (speed == SPEED_100 && duplex== DUPLEX_HALF) + return ADVERTISED_100baseT_Half; + if (speed == SPEED_10 && duplex == DUPLEX_FULL) + return ADVERTISED_10baseT_Full; + if (speed == SPEED_10 && duplex == DUPLEX_HALF) + return ADVERTISED_10baseT_Half; + return 0; +} + +#endif diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c new file mode 100644 index 00000000000..49faa97a30c --- /dev/null +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -0,0 +1,1557 @@ +/* + * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net> + * + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/if_vlan.h> +#include <linux/mdio.h> +#include <linux/aer.h> +#include <linux/bitops.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <net/ip6_checksum.h> +#include <linux/crc32.h> +#include "alx.h" +#include "hw.h" +#include "reg.h" + +const char alx_drv_name[] = "alx"; + + +static void alx_free_txbuf(struct alx_priv *alx, int entry) +{ + struct alx_buffer *txb = &alx->txq.bufs[entry]; + + if (dma_unmap_len(txb, size)) { + dma_unmap_single(&alx->hw.pdev->dev, + dma_unmap_addr(txb, dma), + dma_unmap_len(txb, size), + DMA_TO_DEVICE); + dma_unmap_len_set(txb, size, 0); + } + + if (txb->skb) { + dev_kfree_skb_any(txb->skb); + txb->skb = NULL; + } +} + +static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) +{ + struct alx_rx_queue *rxq = &alx->rxq; + struct sk_buff *skb; + struct alx_buffer *cur_buf; + dma_addr_t dma; + u16 cur, next, count = 0; + + next = cur = rxq->write_idx; + if (++next == alx->rx_ringsz) + next = 0; + cur_buf = &rxq->bufs[cur]; + + while (!cur_buf->skb && next != rxq->read_idx) { + struct alx_rfd *rfd = &rxq->rfd[cur]; + + skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size, gfp); + if (!skb) + break; + dma = dma_map_single(&alx->hw.pdev->dev, + skb->data, alx->rxbuf_size, + DMA_FROM_DEVICE); + if (dma_mapping_error(&alx->hw.pdev->dev, dma)) { + dev_kfree_skb(skb); + break; + } + + /* Unfortunately, RX descriptor buffers must be 4-byte + * aligned, so we can't use IP alignment. + */ + if (WARN_ON(dma & 3)) { + dev_kfree_skb(skb); + break; + } + + cur_buf->skb = skb; + dma_unmap_len_set(cur_buf, size, alx->rxbuf_size); + dma_unmap_addr_set(cur_buf, dma, dma); + rfd->addr = cpu_to_le64(dma); + + cur = next; + if (++next == alx->rx_ringsz) + next = 0; + cur_buf = &rxq->bufs[cur]; + count++; + } + + if (count) { + /* flush all updates before updating hardware */ + wmb(); + rxq->write_idx = cur; + alx_write_mem16(&alx->hw, ALX_RFD_PIDX, cur); + } + + return count; +} + +static inline int alx_tpd_avail(struct alx_priv *alx) +{ + struct alx_tx_queue *txq = &alx->txq; + + if (txq->write_idx >= txq->read_idx) + return alx->tx_ringsz + txq->read_idx - txq->write_idx - 1; + return txq->read_idx - txq->write_idx - 1; +} + +static bool alx_clean_tx_irq(struct alx_priv *alx) +{ + struct alx_tx_queue *txq = &alx->txq; + u16 hw_read_idx, sw_read_idx; + unsigned int total_bytes = 0, total_packets = 0; + int budget = ALX_DEFAULT_TX_WORK; + + sw_read_idx = txq->read_idx; + hw_read_idx = alx_read_mem16(&alx->hw, ALX_TPD_PRI0_CIDX); + + if (sw_read_idx != hw_read_idx) { + while (sw_read_idx != hw_read_idx && budget > 0) { + struct sk_buff *skb; + + skb = txq->bufs[sw_read_idx].skb; + if (skb) { + total_bytes += skb->len; + total_packets++; + budget--; + } + + alx_free_txbuf(alx, sw_read_idx); + + if (++sw_read_idx == alx->tx_ringsz) + sw_read_idx = 0; + } + txq->read_idx = sw_read_idx; + + netdev_completed_queue(alx->dev, total_packets, total_bytes); + } + + if (netif_queue_stopped(alx->dev) && netif_carrier_ok(alx->dev) && + alx_tpd_avail(alx) > alx->tx_ringsz/4) + netif_wake_queue(alx->dev); + + return sw_read_idx == hw_read_idx; +} + +static void alx_schedule_link_check(struct alx_priv *alx) +{ + schedule_work(&alx->link_check_wk); +} + +static void alx_schedule_reset(struct alx_priv *alx) +{ + schedule_work(&alx->reset_wk); +} + +static bool alx_clean_rx_irq(struct alx_priv *alx, int budget) +{ + struct alx_rx_queue *rxq = &alx->rxq; + struct alx_rrd *rrd; + struct alx_buffer *rxb; + struct sk_buff *skb; + u16 length, rfd_cleaned = 0; + + while (budget > 0) { + rrd = &rxq->rrd[rxq->rrd_read_idx]; + if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT))) + break; + rrd->word3 &= ~cpu_to_le32(1 << RRD_UPDATED_SHIFT); + + if (ALX_GET_FIELD(le32_to_cpu(rrd->word0), + RRD_SI) != rxq->read_idx || + ALX_GET_FIELD(le32_to_cpu(rrd->word0), + RRD_NOR) != 1) { + alx_schedule_reset(alx); + return 0; + } + + rxb = &rxq->bufs[rxq->read_idx]; + dma_unmap_single(&alx->hw.pdev->dev, + dma_unmap_addr(rxb, dma), + dma_unmap_len(rxb, size), + DMA_FROM_DEVICE); + dma_unmap_len_set(rxb, size, 0); + skb = rxb->skb; + rxb->skb = NULL; + + if (rrd->word3 & cpu_to_le32(1 << RRD_ERR_RES_SHIFT) || + rrd->word3 & cpu_to_le32(1 << RRD_ERR_LEN_SHIFT)) { + rrd->word3 = 0; + dev_kfree_skb_any(skb); + goto next_pkt; + } + + length = ALX_GET_FIELD(le32_to_cpu(rrd->word3), + RRD_PKTLEN) - ETH_FCS_LEN; + skb_put(skb, length); + skb->protocol = eth_type_trans(skb, alx->dev); + + skb_checksum_none_assert(skb); + if (alx->dev->features & NETIF_F_RXCSUM && + !(rrd->word3 & (cpu_to_le32(1 << RRD_ERR_L4_SHIFT) | + cpu_to_le32(1 << RRD_ERR_IPV4_SHIFT)))) { + switch (ALX_GET_FIELD(le32_to_cpu(rrd->word2), + RRD_PID)) { + case RRD_PID_IPV6UDP: + case RRD_PID_IPV4UDP: + case RRD_PID_IPV4TCP: + case RRD_PID_IPV6TCP: + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + } + } + + napi_gro_receive(&alx->napi, skb); + budget--; + +next_pkt: + if (++rxq->read_idx == alx->rx_ringsz) + rxq->read_idx = 0; + if (++rxq->rrd_read_idx == alx->rx_ringsz) + rxq->rrd_read_idx = 0; + + if (++rfd_cleaned > ALX_RX_ALLOC_THRESH) + rfd_cleaned -= alx_refill_rx_ring(alx, GFP_ATOMIC); + } + + if (rfd_cleaned) + alx_refill_rx_ring(alx, GFP_ATOMIC); + + return budget > 0; +} + +static int alx_poll(struct napi_struct *napi, int budget) +{ + struct alx_priv *alx = container_of(napi, struct alx_priv, napi); + struct alx_hw *hw = &alx->hw; + bool complete = true; + unsigned long flags; + + complete = alx_clean_tx_irq(alx) && + alx_clean_rx_irq(alx, budget); + + if (!complete) + return 1; + + napi_complete(&alx->napi); + + /* enable interrupt */ + spin_lock_irqsave(&alx->irq_lock, flags); + alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0; + alx_write_mem32(hw, ALX_IMR, alx->int_mask); + spin_unlock_irqrestore(&alx->irq_lock, flags); + + alx_post_write(hw); + + return 0; +} + +static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr) +{ + struct alx_hw *hw = &alx->hw; + bool write_int_mask = false; + + spin_lock(&alx->irq_lock); + + /* ACK interrupt */ + alx_write_mem32(hw, ALX_ISR, intr | ALX_ISR_DIS); + intr &= alx->int_mask; + + if (intr & ALX_ISR_FATAL) { + netif_warn(alx, hw, alx->dev, + "fatal interrupt 0x%x, resetting\n", intr); + alx_schedule_reset(alx); + goto out; + } + + if (intr & ALX_ISR_ALERT) + netdev_warn(alx->dev, "alert interrupt: 0x%x\n", intr); + + if (intr & ALX_ISR_PHY) { + /* suppress PHY interrupt, because the source + * is from PHY internal. only the internal status + * is cleared, the interrupt status could be cleared. + */ + alx->int_mask &= ~ALX_ISR_PHY; + write_int_mask = true; + alx_schedule_link_check(alx); + } + + if (intr & (ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0)) { + napi_schedule(&alx->napi); + /* mask rx/tx interrupt, enable them when napi complete */ + alx->int_mask &= ~ALX_ISR_ALL_QUEUES; + write_int_mask = true; + } + + if (write_int_mask) + alx_write_mem32(hw, ALX_IMR, alx->int_mask); + + alx_write_mem32(hw, ALX_ISR, 0); + + out: + spin_unlock(&alx->irq_lock); + return IRQ_HANDLED; +} + +static irqreturn_t alx_intr_msi(int irq, void *data) +{ + struct alx_priv *alx = data; + + return alx_intr_handle(alx, alx_read_mem32(&alx->hw, ALX_ISR)); +} + +static irqreturn_t alx_intr_legacy(int irq, void *data) +{ + struct alx_priv *alx = data; + struct alx_hw *hw = &alx->hw; + u32 intr; + + intr = alx_read_mem32(hw, ALX_ISR); + + if (intr & ALX_ISR_DIS || !(intr & alx->int_mask)) + return IRQ_NONE; + + return alx_intr_handle(alx, intr); +} + +static void alx_init_ring_ptrs(struct alx_priv *alx) +{ + struct alx_hw *hw = &alx->hw; + u32 addr_hi = ((u64)alx->descmem.dma) >> 32; + + alx->rxq.read_idx = 0; + alx->rxq.write_idx = 0; + alx->rxq.rrd_read_idx = 0; + alx_write_mem32(hw, ALX_RX_BASE_ADDR_HI, addr_hi); + alx_write_mem32(hw, ALX_RRD_ADDR_LO, alx->rxq.rrd_dma); + alx_write_mem32(hw, ALX_RRD_RING_SZ, alx->rx_ringsz); + alx_write_mem32(hw, ALX_RFD_ADDR_LO, alx->rxq.rfd_dma); + alx_write_mem32(hw, ALX_RFD_RING_SZ, alx->rx_ringsz); + alx_write_mem32(hw, ALX_RFD_BUF_SZ, alx->rxbuf_size); + + alx->txq.read_idx = 0; + alx->txq.write_idx = 0; + alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi); + alx_write_mem32(hw, ALX_TPD_PRI0_ADDR_LO, alx->txq.tpd_dma); + alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz); + + /* load these pointers into the chip */ + alx_write_mem32(hw, ALX_SRAM9, ALX_SRAM_LOAD_PTR); +} + +static void alx_free_txring_buf(struct alx_priv *alx) +{ + struct alx_tx_queue *txq = &alx->txq; + int i; + + if (!txq->bufs) + return; + + for (i = 0; i < alx->tx_ringsz; i++) + alx_free_txbuf(alx, i); + + memset(txq->bufs, 0, alx->tx_ringsz * sizeof(struct alx_buffer)); + memset(txq->tpd, 0, alx->tx_ringsz * sizeof(struct alx_txd)); + txq->write_idx = 0; + txq->read_idx = 0; + + netdev_reset_queue(alx->dev); +} + +static void alx_free_rxring_buf(struct alx_priv *alx) +{ + struct alx_rx_queue *rxq = &alx->rxq; + struct alx_buffer *cur_buf; + u16 i; + + if (rxq == NULL) + return; + + for (i = 0; i < alx->rx_ringsz; i++) { + cur_buf = rxq->bufs + i; + if (cur_buf->skb) { + dma_unmap_single(&alx->hw.pdev->dev, + dma_unmap_addr(cur_buf, dma), + dma_unmap_len(cur_buf, size), + DMA_FROM_DEVICE); + dev_kfree_skb(cur_buf->skb); + cur_buf->skb = NULL; + dma_unmap_len_set(cur_buf, size, 0); + dma_unmap_addr_set(cur_buf, dma, 0); + } + } + + rxq->write_idx = 0; + rxq->read_idx = 0; + rxq->rrd_read_idx = 0; +} + +static void alx_free_buffers(struct alx_priv *alx) +{ + alx_free_txring_buf(alx); + alx_free_rxring_buf(alx); +} + +static int alx_reinit_rings(struct alx_priv *alx) +{ + alx_free_buffers(alx); + + alx_init_ring_ptrs(alx); + + if (!alx_refill_rx_ring(alx, GFP_KERNEL)) + return -ENOMEM; + + return 0; +} + +static void alx_add_mc_addr(struct alx_hw *hw, const u8 *addr, u32 *mc_hash) +{ + u32 crc32, bit, reg; + + crc32 = ether_crc(ETH_ALEN, addr); + reg = (crc32 >> 31) & 0x1; + bit = (crc32 >> 26) & 0x1F; + + mc_hash[reg] |= BIT(bit); +} + +static void __alx_set_rx_mode(struct net_device *netdev) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_hw *hw = &alx->hw; + struct netdev_hw_addr *ha; + u32 mc_hash[2] = {}; + + if (!(netdev->flags & IFF_ALLMULTI)) { + netdev_for_each_mc_addr(ha, netdev) + alx_add_mc_addr(hw, ha->addr, mc_hash); + + alx_write_mem32(hw, ALX_HASH_TBL0, mc_hash[0]); + alx_write_mem32(hw, ALX_HASH_TBL1, mc_hash[1]); + } + + hw->rx_ctrl &= ~(ALX_MAC_CTRL_MULTIALL_EN | ALX_MAC_CTRL_PROMISC_EN); + if (netdev->flags & IFF_PROMISC) + hw->rx_ctrl |= ALX_MAC_CTRL_PROMISC_EN; + if (netdev->flags & IFF_ALLMULTI) + hw->rx_ctrl |= ALX_MAC_CTRL_MULTIALL_EN; + + alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); +} + +static void alx_set_rx_mode(struct net_device *netdev) +{ + __alx_set_rx_mode(netdev); +} + +static int alx_set_mac_address(struct net_device *netdev, void *data) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_hw *hw = &alx->hw; + struct sockaddr *addr = data; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + if (netdev->addr_assign_type & NET_ADDR_RANDOM) + netdev->addr_assign_type ^= NET_ADDR_RANDOM; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(hw->mac_addr, addr->sa_data, netdev->addr_len); + alx_set_macaddr(hw, hw->mac_addr); + + return 0; +} + +static int alx_alloc_descriptors(struct alx_priv *alx) +{ + alx->txq.bufs = kcalloc(alx->tx_ringsz, + sizeof(struct alx_buffer), + GFP_KERNEL); + if (!alx->txq.bufs) + return -ENOMEM; + + alx->rxq.bufs = kcalloc(alx->rx_ringsz, + sizeof(struct alx_buffer), + GFP_KERNEL); + if (!alx->rxq.bufs) + goto out_free; + + /* physical tx/rx ring descriptors + * + * Allocate them as a single chunk because they must not cross a + * 4G boundary (hardware has a single register for high 32 bits + * of addresses only) + */ + alx->descmem.size = sizeof(struct alx_txd) * alx->tx_ringsz + + sizeof(struct alx_rrd) * alx->rx_ringsz + + sizeof(struct alx_rfd) * alx->rx_ringsz; + alx->descmem.virt = dma_zalloc_coherent(&alx->hw.pdev->dev, + alx->descmem.size, + &alx->descmem.dma, + GFP_KERNEL); + if (!alx->descmem.virt) + goto out_free; + + alx->txq.tpd = alx->descmem.virt; + alx->txq.tpd_dma = alx->descmem.dma; + + /* alignment requirement for next block */ + BUILD_BUG_ON(sizeof(struct alx_txd) % 8); + + alx->rxq.rrd = + (void *)((u8 *)alx->descmem.virt + + sizeof(struct alx_txd) * alx->tx_ringsz); + alx->rxq.rrd_dma = alx->descmem.dma + + sizeof(struct alx_txd) * alx->tx_ringsz; + + /* alignment requirement for next block */ + BUILD_BUG_ON(sizeof(struct alx_rrd) % 8); + + alx->rxq.rfd = + (void *)((u8 *)alx->descmem.virt + + sizeof(struct alx_txd) * alx->tx_ringsz + + sizeof(struct alx_rrd) * alx->rx_ringsz); + alx->rxq.rfd_dma = alx->descmem.dma + + sizeof(struct alx_txd) * alx->tx_ringsz + + sizeof(struct alx_rrd) * alx->rx_ringsz; + + return 0; +out_free: + kfree(alx->txq.bufs); + kfree(alx->rxq.bufs); + return -ENOMEM; +} + +static int alx_alloc_rings(struct alx_priv *alx) +{ + int err; + + err = alx_alloc_descriptors(alx); + if (err) + return err; + + alx->int_mask &= ~ALX_ISR_ALL_QUEUES; + alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0; + alx->tx_ringsz = alx->tx_ringsz; + + netif_napi_add(alx->dev, &alx->napi, alx_poll, 64); + + alx_reinit_rings(alx); + return 0; +} + +static void alx_free_rings(struct alx_priv *alx) +{ + netif_napi_del(&alx->napi); + alx_free_buffers(alx); + + kfree(alx->txq.bufs); + kfree(alx->rxq.bufs); + + dma_free_coherent(&alx->hw.pdev->dev, + alx->descmem.size, + alx->descmem.virt, + alx->descmem.dma); +} + +static void alx_config_vector_mapping(struct alx_priv *alx) +{ + struct alx_hw *hw = &alx->hw; + + alx_write_mem32(hw, ALX_MSI_MAP_TBL1, 0); + alx_write_mem32(hw, ALX_MSI_MAP_TBL2, 0); + alx_write_mem32(hw, ALX_MSI_ID_MAP, 0); +} + +static void alx_irq_enable(struct alx_priv *alx) +{ + struct alx_hw *hw = &alx->hw; + + /* level-1 interrupt switch */ + alx_write_mem32(hw, ALX_ISR, 0); + alx_write_mem32(hw, ALX_IMR, alx->int_mask); + alx_post_write(hw); +} + +static void alx_irq_disable(struct alx_priv *alx) +{ + struct alx_hw *hw = &alx->hw; + + alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS); + alx_write_mem32(hw, ALX_IMR, 0); + alx_post_write(hw); + + synchronize_irq(alx->hw.pdev->irq); +} + +static int alx_request_irq(struct alx_priv *alx) +{ + struct pci_dev *pdev = alx->hw.pdev; + struct alx_hw *hw = &alx->hw; + int err; + u32 msi_ctrl; + + msi_ctrl = (hw->imt >> 1) << ALX_MSI_RETRANS_TM_SHIFT; + + if (!pci_enable_msi(alx->hw.pdev)) { + alx->msi = true; + + alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, + msi_ctrl | ALX_MSI_MASK_SEL_LINE); + err = request_irq(pdev->irq, alx_intr_msi, 0, + alx->dev->name, alx); + if (!err) + goto out; + /* fall back to legacy interrupt */ + pci_disable_msi(alx->hw.pdev); + } + + alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, 0); + err = request_irq(pdev->irq, alx_intr_legacy, IRQF_SHARED, + alx->dev->name, alx); +out: + if (!err) + alx_config_vector_mapping(alx); + return err; +} + +static void alx_free_irq(struct alx_priv *alx) +{ + struct pci_dev *pdev = alx->hw.pdev; + + free_irq(pdev->irq, alx); + + if (alx->msi) { + pci_disable_msi(alx->hw.pdev); + alx->msi = false; + } +} + +static int alx_identify_hw(struct alx_priv *alx) +{ + struct alx_hw *hw = &alx->hw; + int rev = alx_hw_revision(hw); + + if (rev > ALX_REV_C0) + return -EINVAL; + + hw->max_dma_chnl = rev >= ALX_REV_B0 ? 4 : 2; + + return 0; +} + +static int alx_init_sw(struct alx_priv *alx) +{ + struct pci_dev *pdev = alx->hw.pdev; + struct alx_hw *hw = &alx->hw; + int err; + + err = alx_identify_hw(alx); + if (err) { + dev_err(&pdev->dev, "unrecognized chip, aborting\n"); + return err; + } + + alx->hw.lnk_patch = + pdev->device == ALX_DEV_ID_AR8161 && + pdev->subsystem_vendor == PCI_VENDOR_ID_ATTANSIC && + pdev->subsystem_device == 0x0091 && + pdev->revision == 0; + + hw->smb_timer = 400; + hw->mtu = alx->dev->mtu; + alx->rxbuf_size = ALIGN(ALX_RAW_MTU(hw->mtu), 8); + alx->tx_ringsz = 256; + alx->rx_ringsz = 512; + hw->imt = 200; + alx->int_mask = ALX_ISR_MISC; + hw->dma_chnl = hw->max_dma_chnl; + hw->ith_tpd = alx->tx_ringsz / 3; + hw->link_speed = SPEED_UNKNOWN; + hw->duplex = DUPLEX_UNKNOWN; + hw->adv_cfg = ADVERTISED_Autoneg | + ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_1000baseT_Full; + hw->flowctrl = ALX_FC_ANEG | ALX_FC_RX | ALX_FC_TX; + + hw->rx_ctrl = ALX_MAC_CTRL_WOLSPED_SWEN | + ALX_MAC_CTRL_MHASH_ALG_HI5B | + ALX_MAC_CTRL_BRD_EN | + ALX_MAC_CTRL_PCRCE | + ALX_MAC_CTRL_CRCE | + ALX_MAC_CTRL_RXFC_EN | + ALX_MAC_CTRL_TXFC_EN | + 7 << ALX_MAC_CTRL_PRMBLEN_SHIFT; + + return err; +} + + +static netdev_features_t alx_fix_features(struct net_device *netdev, + netdev_features_t features) +{ + if (netdev->mtu > ALX_MAX_TSO_PKT_SIZE) + features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + + return features; +} + +static void alx_netif_stop(struct alx_priv *alx) +{ + alx->dev->trans_start = jiffies; + if (netif_carrier_ok(alx->dev)) { + netif_carrier_off(alx->dev); + netif_tx_disable(alx->dev); + napi_disable(&alx->napi); + } +} + +static void alx_halt(struct alx_priv *alx) +{ + struct alx_hw *hw = &alx->hw; + + alx_netif_stop(alx); + hw->link_speed = SPEED_UNKNOWN; + hw->duplex = DUPLEX_UNKNOWN; + + alx_reset_mac(hw); + + /* disable l0s/l1 */ + alx_enable_aspm(hw, false, false); + alx_irq_disable(alx); + alx_free_buffers(alx); +} + +static void alx_configure(struct alx_priv *alx) +{ + struct alx_hw *hw = &alx->hw; + + alx_configure_basic(hw); + alx_disable_rss(hw); + __alx_set_rx_mode(alx->dev); + + alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); +} + +static void alx_activate(struct alx_priv *alx) +{ + /* hardware setting lost, restore it */ + alx_reinit_rings(alx); + alx_configure(alx); + + /* clear old interrupts */ + alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS); + + alx_irq_enable(alx); + + alx_schedule_link_check(alx); +} + +static void alx_reinit(struct alx_priv *alx) +{ + ASSERT_RTNL(); + + alx_halt(alx); + alx_activate(alx); +} + +static int alx_change_mtu(struct net_device *netdev, int mtu) +{ + struct alx_priv *alx = netdev_priv(netdev); + int max_frame = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; + + if ((max_frame < ALX_MIN_FRAME_SIZE) || + (max_frame > ALX_MAX_FRAME_SIZE)) + return -EINVAL; + + if (netdev->mtu == mtu) + return 0; + + netdev->mtu = mtu; + alx->hw.mtu = mtu; + alx->rxbuf_size = mtu > ALX_DEF_RXBUF_SIZE ? + ALIGN(max_frame, 8) : ALX_DEF_RXBUF_SIZE; + netdev_update_features(netdev); + if (netif_running(netdev)) + alx_reinit(alx); + return 0; +} + +static void alx_netif_start(struct alx_priv *alx) +{ + netif_tx_wake_all_queues(alx->dev); + napi_enable(&alx->napi); + netif_carrier_on(alx->dev); +} + +static int __alx_open(struct alx_priv *alx, bool resume) +{ + int err; + + if (!resume) + netif_carrier_off(alx->dev); + + err = alx_alloc_rings(alx); + if (err) + return err; + + alx_configure(alx); + + err = alx_request_irq(alx); + if (err) + goto out_free_rings; + + /* clear old interrupts */ + alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS); + + alx_irq_enable(alx); + + if (!resume) + netif_tx_start_all_queues(alx->dev); + + alx_schedule_link_check(alx); + return 0; + +out_free_rings: + alx_free_rings(alx); + return err; +} + +static void __alx_stop(struct alx_priv *alx) +{ + alx_halt(alx); + alx_free_irq(alx); + alx_free_rings(alx); +} + +static const char *alx_speed_desc(struct alx_hw *hw) +{ + switch (alx_speed_to_ethadv(hw->link_speed, hw->duplex)) { + case ADVERTISED_1000baseT_Full: + return "1 Gbps Full"; + case ADVERTISED_100baseT_Full: + return "100 Mbps Full"; + case ADVERTISED_100baseT_Half: + return "100 Mbps Half"; + case ADVERTISED_10baseT_Full: + return "10 Mbps Full"; + case ADVERTISED_10baseT_Half: + return "10 Mbps Half"; + default: + return "Unknown speed"; + } +} + +static void alx_check_link(struct alx_priv *alx) +{ + struct alx_hw *hw = &alx->hw; + unsigned long flags; + int old_speed; + u8 old_duplex; + int err; + + /* clear PHY internal interrupt status, otherwise the main + * interrupt status will be asserted forever + */ + alx_clear_phy_intr(hw); + + old_speed = hw->link_speed; + old_duplex = hw->duplex; + err = alx_read_phy_link(hw); + if (err < 0) + goto reset; + + spin_lock_irqsave(&alx->irq_lock, flags); + alx->int_mask |= ALX_ISR_PHY; + alx_write_mem32(hw, ALX_IMR, alx->int_mask); + spin_unlock_irqrestore(&alx->irq_lock, flags); + + if (old_speed == hw->link_speed) + return; + + if (hw->link_speed != SPEED_UNKNOWN) { + netif_info(alx, link, alx->dev, + "NIC Up: %s\n", alx_speed_desc(hw)); + alx_post_phy_link(hw); + alx_enable_aspm(hw, true, true); + alx_start_mac(hw); + + if (old_speed == SPEED_UNKNOWN) + alx_netif_start(alx); + } else { + /* link is now down */ + alx_netif_stop(alx); + netif_info(alx, link, alx->dev, "Link Down\n"); + err = alx_reset_mac(hw); + if (err) + goto reset; + alx_irq_disable(alx); + + /* MAC reset causes all HW settings to be lost, restore all */ + err = alx_reinit_rings(alx); + if (err) + goto reset; + alx_configure(alx); + alx_enable_aspm(hw, false, true); + alx_post_phy_link(hw); + alx_irq_enable(alx); + } + + return; + +reset: + alx_schedule_reset(alx); +} + +static int alx_open(struct net_device *netdev) +{ + return __alx_open(netdev_priv(netdev), false); +} + +static int alx_stop(struct net_device *netdev) +{ + __alx_stop(netdev_priv(netdev)); + return 0; +} + +static void alx_link_check(struct work_struct *work) +{ + struct alx_priv *alx; + + alx = container_of(work, struct alx_priv, link_check_wk); + + rtnl_lock(); + alx_check_link(alx); + rtnl_unlock(); +} + +static void alx_reset(struct work_struct *work) +{ + struct alx_priv *alx = container_of(work, struct alx_priv, reset_wk); + + rtnl_lock(); + alx_reinit(alx); + rtnl_unlock(); +} + +static int alx_tx_csum(struct sk_buff *skb, struct alx_txd *first) +{ + u8 cso, css; + + if (skb->ip_summed != CHECKSUM_PARTIAL) + return 0; + + cso = skb_checksum_start_offset(skb); + if (cso & 1) + return -EINVAL; + + css = cso + skb->csum_offset; + first->word1 |= cpu_to_le32((cso >> 1) << TPD_CXSUMSTART_SHIFT); + first->word1 |= cpu_to_le32((css >> 1) << TPD_CXSUMOFFSET_SHIFT); + first->word1 |= cpu_to_le32(1 << TPD_CXSUM_EN_SHIFT); + + return 0; +} + +static int alx_map_tx_skb(struct alx_priv *alx, struct sk_buff *skb) +{ + struct alx_tx_queue *txq = &alx->txq; + struct alx_txd *tpd, *first_tpd; + dma_addr_t dma; + int maplen, f, first_idx = txq->write_idx; + + first_tpd = &txq->tpd[txq->write_idx]; + tpd = first_tpd; + + maplen = skb_headlen(skb); + dma = dma_map_single(&alx->hw.pdev->dev, skb->data, maplen, + DMA_TO_DEVICE); + if (dma_mapping_error(&alx->hw.pdev->dev, dma)) + goto err_dma; + + dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen); + dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma); + + tpd->adrl.addr = cpu_to_le64(dma); + tpd->len = cpu_to_le16(maplen); + + for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[f]; + + if (++txq->write_idx == alx->tx_ringsz) + txq->write_idx = 0; + tpd = &txq->tpd[txq->write_idx]; + + tpd->word1 = first_tpd->word1; + + maplen = skb_frag_size(frag); + dma = skb_frag_dma_map(&alx->hw.pdev->dev, frag, 0, + maplen, DMA_TO_DEVICE); + if (dma_mapping_error(&alx->hw.pdev->dev, dma)) + goto err_dma; + dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen); + dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma); + + tpd->adrl.addr = cpu_to_le64(dma); + tpd->len = cpu_to_le16(maplen); + } + + /* last TPD, set EOP flag and store skb */ + tpd->word1 |= cpu_to_le32(1 << TPD_EOP_SHIFT); + txq->bufs[txq->write_idx].skb = skb; + + if (++txq->write_idx == alx->tx_ringsz) + txq->write_idx = 0; + + return 0; + +err_dma: + f = first_idx; + while (f != txq->write_idx) { + alx_free_txbuf(alx, f); + if (++f == alx->tx_ringsz) + f = 0; + } + return -ENOMEM; +} + +static netdev_tx_t alx_start_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_tx_queue *txq = &alx->txq; + struct alx_txd *first; + int tpdreq = skb_shinfo(skb)->nr_frags + 1; + + if (alx_tpd_avail(alx) < tpdreq) { + netif_stop_queue(alx->dev); + goto drop; + } + + first = &txq->tpd[txq->write_idx]; + memset(first, 0, sizeof(*first)); + + if (alx_tx_csum(skb, first)) + goto drop; + + if (alx_map_tx_skb(alx, skb) < 0) + goto drop; + + netdev_sent_queue(alx->dev, skb->len); + + /* flush updates before updating hardware */ + wmb(); + alx_write_mem16(&alx->hw, ALX_TPD_PRI0_PIDX, txq->write_idx); + + if (alx_tpd_avail(alx) < alx->tx_ringsz/8) + netif_stop_queue(alx->dev); + + return NETDEV_TX_OK; + +drop: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +static void alx_tx_timeout(struct net_device *dev) +{ + struct alx_priv *alx = netdev_priv(dev); + + alx_schedule_reset(alx); +} + +static int alx_mdio_read(struct net_device *netdev, + int prtad, int devad, u16 addr) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_hw *hw = &alx->hw; + u16 val; + int err; + + if (prtad != hw->mdio.prtad) + return -EINVAL; + + if (devad == MDIO_DEVAD_NONE) + err = alx_read_phy_reg(hw, addr, &val); + else + err = alx_read_phy_ext(hw, devad, addr, &val); + + if (err) + return err; + return val; +} + +static int alx_mdio_write(struct net_device *netdev, + int prtad, int devad, u16 addr, u16 val) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_hw *hw = &alx->hw; + + if (prtad != hw->mdio.prtad) + return -EINVAL; + + if (devad == MDIO_DEVAD_NONE) + return alx_write_phy_reg(hw, addr, val); + + return alx_write_phy_ext(hw, devad, addr, val); +} + +static int alx_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct alx_priv *alx = netdev_priv(netdev); + + if (!netif_running(netdev)) + return -EAGAIN; + + return mdio_mii_ioctl(&alx->hw.mdio, if_mii(ifr), cmd); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void alx_poll_controller(struct net_device *netdev) +{ + struct alx_priv *alx = netdev_priv(netdev); + + if (alx->msi) + alx_intr_msi(0, alx); + else + alx_intr_legacy(0, alx); +} +#endif + +static struct rtnl_link_stats64 *alx_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *net_stats) +{ + struct alx_priv *alx = netdev_priv(dev); + struct alx_hw_stats *hw_stats = &alx->hw.stats; + + spin_lock(&alx->stats_lock); + + alx_update_hw_stats(&alx->hw); + + net_stats->tx_bytes = hw_stats->tx_byte_cnt; + net_stats->rx_bytes = hw_stats->rx_byte_cnt; + net_stats->multicast = hw_stats->rx_mcast; + net_stats->collisions = hw_stats->tx_single_col + + hw_stats->tx_multi_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_ov_sz + + hw_stats->rx_ov_rrd + + hw_stats->rx_align_err + + hw_stats->rx_ov_rxf; + + net_stats->rx_fifo_errors = hw_stats->rx_ov_rxf; + 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_dropped = hw_stats->rx_ov_rrd; + + 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_aborted_errors = hw_stats->tx_abort_col; + net_stats->tx_fifo_errors = hw_stats->tx_underrun; + net_stats->tx_window_errors = hw_stats->tx_late_col; + + net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors; + net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors; + + spin_unlock(&alx->stats_lock); + + return net_stats; +} + +static const struct net_device_ops alx_netdev_ops = { + .ndo_open = alx_open, + .ndo_stop = alx_stop, + .ndo_start_xmit = alx_start_xmit, + .ndo_get_stats64 = alx_get_stats64, + .ndo_set_rx_mode = alx_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = alx_set_mac_address, + .ndo_change_mtu = alx_change_mtu, + .ndo_do_ioctl = alx_ioctl, + .ndo_tx_timeout = alx_tx_timeout, + .ndo_fix_features = alx_fix_features, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = alx_poll_controller, +#endif +}; + +static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct alx_priv *alx; + struct alx_hw *hw; + bool phy_configured; + int bars, err; + + err = pci_enable_device_mem(pdev); + if (err) + return err; + + /* The alx chip can DMA to 64-bit addresses, but it uses a single + * shared register for the high 32 bits, so only a single, aligned, + * 4 GB physical address range can be used for descriptors. + */ + if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { + dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n"); + } else { + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, "No usable DMA config, aborting\n"); + goto out_pci_disable; + } + } + + bars = pci_select_bars(pdev, IORESOURCE_MEM); + err = pci_request_selected_regions(pdev, bars, alx_drv_name); + if (err) { + dev_err(&pdev->dev, + "pci_request_selected_regions failed(bars:%d)\n", bars); + goto out_pci_disable; + } + + pci_enable_pcie_error_reporting(pdev); + pci_set_master(pdev); + + if (!pdev->pm_cap) { + dev_err(&pdev->dev, + "Can't find power management capability, aborting\n"); + err = -EIO; + goto out_pci_release; + } + + netdev = alloc_etherdev(sizeof(*alx)); + if (!netdev) { + err = -ENOMEM; + goto out_pci_release; + } + + SET_NETDEV_DEV(netdev, &pdev->dev); + alx = netdev_priv(netdev); + spin_lock_init(&alx->hw.mdio_lock); + spin_lock_init(&alx->irq_lock); + spin_lock_init(&alx->stats_lock); + alx->dev = netdev; + alx->hw.pdev = pdev; + alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP | + NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR | NETIF_MSG_WOL; + hw = &alx->hw; + pci_set_drvdata(pdev, alx); + + hw->hw_addr = pci_ioremap_bar(pdev, 0); + if (!hw->hw_addr) { + dev_err(&pdev->dev, "cannot map device registers\n"); + err = -EIO; + goto out_free_netdev; + } + + netdev->netdev_ops = &alx_netdev_ops; + netdev->ethtool_ops = &alx_ethtool_ops; + netdev->irq = pdev->irq; + netdev->watchdog_timeo = ALX_WATCHDOG_TIME; + + if (ent->driver_data & ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG) + pdev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; + + err = alx_init_sw(alx); + if (err) { + dev_err(&pdev->dev, "net device private data init failed\n"); + goto out_unmap; + } + + alx_reset_pcie(hw); + + phy_configured = alx_phy_configured(hw); + + if (!phy_configured) + alx_reset_phy(hw); + + err = alx_reset_mac(hw); + if (err) { + dev_err(&pdev->dev, "MAC Reset failed, error = %d\n", err); + goto out_unmap; + } + + /* setup link to put it in a known good starting state */ + if (!phy_configured) { + err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl); + if (err) { + dev_err(&pdev->dev, + "failed to configure PHY speed/duplex (err=%d)\n", + err); + goto out_unmap; + } + } + + netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + + if (alx_get_perm_macaddr(hw, hw->perm_addr)) { + dev_warn(&pdev->dev, + "Invalid permanent address programmed, using random one\n"); + eth_hw_addr_random(netdev); + memcpy(hw->perm_addr, netdev->dev_addr, netdev->addr_len); + } + + memcpy(hw->mac_addr, hw->perm_addr, ETH_ALEN); + memcpy(netdev->dev_addr, hw->mac_addr, ETH_ALEN); + memcpy(netdev->perm_addr, hw->perm_addr, ETH_ALEN); + + hw->mdio.prtad = 0; + hw->mdio.mmds = 0; + hw->mdio.dev = netdev; + hw->mdio.mode_support = MDIO_SUPPORTS_C45 | + MDIO_SUPPORTS_C22 | + MDIO_EMULATE_C22; + hw->mdio.mdio_read = alx_mdio_read; + hw->mdio.mdio_write = alx_mdio_write; + + if (!alx_get_phy_info(hw)) { + dev_err(&pdev->dev, "failed to identify PHY\n"); + err = -EIO; + goto out_unmap; + } + + INIT_WORK(&alx->link_check_wk, alx_link_check); + INIT_WORK(&alx->reset_wk, alx_reset); + netif_carrier_off(netdev); + + err = register_netdev(netdev); + if (err) { + dev_err(&pdev->dev, "register netdevice failed\n"); + goto out_unmap; + } + + netdev_info(netdev, + "Qualcomm Atheros AR816x/AR817x Ethernet [%pM]\n", + netdev->dev_addr); + + return 0; + +out_unmap: + iounmap(hw->hw_addr); +out_free_netdev: + free_netdev(netdev); +out_pci_release: + pci_release_selected_regions(pdev, bars); +out_pci_disable: + pci_disable_device(pdev); + return err; +} + +static void alx_remove(struct pci_dev *pdev) +{ + struct alx_priv *alx = pci_get_drvdata(pdev); + struct alx_hw *hw = &alx->hw; + + cancel_work_sync(&alx->link_check_wk); + cancel_work_sync(&alx->reset_wk); + + /* restore permanent mac address */ + alx_set_macaddr(hw, hw->perm_addr); + + unregister_netdev(alx->dev); + iounmap(hw->hw_addr); + pci_release_selected_regions(pdev, + pci_select_bars(pdev, IORESOURCE_MEM)); + + pci_disable_pcie_error_reporting(pdev); + pci_disable_device(pdev); + + free_netdev(alx->dev); +} + +#ifdef CONFIG_PM_SLEEP +static int alx_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct alx_priv *alx = pci_get_drvdata(pdev); + + if (!netif_running(alx->dev)) + return 0; + netif_device_detach(alx->dev); + __alx_stop(alx); + return 0; +} + +static int alx_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct alx_priv *alx = pci_get_drvdata(pdev); + struct alx_hw *hw = &alx->hw; + + alx_reset_phy(hw); + + if (!netif_running(alx->dev)) + return 0; + netif_device_attach(alx->dev); + return __alx_open(alx, true); +} + +static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume); +#define ALX_PM_OPS (&alx_pm_ops) +#else +#define ALX_PM_OPS NULL +#endif + + +static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct alx_priv *alx = pci_get_drvdata(pdev); + struct net_device *netdev = alx->dev; + pci_ers_result_t rc = PCI_ERS_RESULT_NEED_RESET; + + dev_info(&pdev->dev, "pci error detected\n"); + + rtnl_lock(); + + if (netif_running(netdev)) { + netif_device_detach(netdev); + alx_halt(alx); + } + + if (state == pci_channel_io_perm_failure) + rc = PCI_ERS_RESULT_DISCONNECT; + else + pci_disable_device(pdev); + + rtnl_unlock(); + + return rc; +} + +static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev) +{ + struct alx_priv *alx = pci_get_drvdata(pdev); + struct alx_hw *hw = &alx->hw; + pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; + + dev_info(&pdev->dev, "pci error slot reset\n"); + + rtnl_lock(); + + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, "Failed to re-enable PCI device after reset\n"); + goto out; + } + + pci_set_master(pdev); + + alx_reset_pcie(hw); + if (!alx_reset_mac(hw)) + rc = PCI_ERS_RESULT_RECOVERED; +out: + pci_cleanup_aer_uncorrect_error_status(pdev); + + rtnl_unlock(); + + return rc; +} + +static void alx_pci_error_resume(struct pci_dev *pdev) +{ + struct alx_priv *alx = pci_get_drvdata(pdev); + struct net_device *netdev = alx->dev; + + dev_info(&pdev->dev, "pci error resume\n"); + + rtnl_lock(); + + if (netif_running(netdev)) { + alx_activate(alx); + netif_device_attach(netdev); + } + + rtnl_unlock(); +} + +static const struct pci_error_handlers alx_err_handlers = { + .error_detected = alx_pci_error_detected, + .slot_reset = alx_pci_error_slot_reset, + .resume = alx_pci_error_resume, +}; + +static DEFINE_PCI_DEVICE_TABLE(alx_pci_tbl) = { + { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8161), + .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, + { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200), + .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, + { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162), + .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, + { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) }, + { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8172) }, + {} +}; + +static struct pci_driver alx_driver = { + .name = alx_drv_name, + .id_table = alx_pci_tbl, + .probe = alx_probe, + .remove = alx_remove, + .err_handler = &alx_err_handlers, + .driver.pm = ALX_PM_OPS, +}; + +module_pci_driver(alx_driver); +MODULE_DEVICE_TABLE(pci, alx_pci_tbl); +MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); +MODULE_AUTHOR("Qualcomm Corporation, <nic-devel@qualcomm.com>"); +MODULE_DESCRIPTION( + "Qualcomm Atheros(R) AR816x/AR817x PCI-E Ethernet Network Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/atheros/alx/reg.h b/drivers/net/ethernet/atheros/alx/reg.h new file mode 100644 index 00000000000..af006b44b2a --- /dev/null +++ b/drivers/net/ethernet/atheros/alx/reg.h @@ -0,0 +1,854 @@ +/* + * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net> + * + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ALX_REG_H +#define ALX_REG_H + +#define ALX_DEV_ID_AR8161 0x1091 +#define ALX_DEV_ID_E2200 0xe091 +#define ALX_DEV_ID_AR8162 0x1090 +#define ALX_DEV_ID_AR8171 0x10A1 +#define ALX_DEV_ID_AR8172 0x10A0 + +/* rev definition, + * bit(0): with xD support + * bit(1): with Card Reader function + * bit(7:2): real revision + */ +#define ALX_PCI_REVID_SHIFT 3 +#define ALX_REV_A0 0 +#define ALX_REV_A1 1 +#define ALX_REV_B0 2 +#define ALX_REV_C0 3 + +#define ALX_DEV_CTRL 0x0060 +#define ALX_DEV_CTRL_MAXRRS_MIN 2 + +#define ALX_MSIX_MASK 0x0090 + +#define ALX_UE_SVRT 0x010C +#define ALX_UE_SVRT_FCPROTERR BIT(13) +#define ALX_UE_SVRT_DLPROTERR BIT(4) + +/* eeprom & flash load register */ +#define ALX_EFLD 0x0204 +#define ALX_EFLD_F_EXIST BIT(10) +#define ALX_EFLD_E_EXIST BIT(9) +#define ALX_EFLD_STAT BIT(5) +#define ALX_EFLD_START BIT(0) + +/* eFuse load register */ +#define ALX_SLD 0x0218 +#define ALX_SLD_STAT BIT(12) +#define ALX_SLD_START BIT(11) +#define ALX_SLD_MAX_TO 100 + +#define ALX_PDLL_TRNS1 0x1104 +#define ALX_PDLL_TRNS1_D3PLLOFF_EN BIT(11) + +#define ALX_PMCTRL 0x12F8 +#define ALX_PMCTRL_HOTRST_WTEN BIT(31) +/* bit30: L0s/L1 controlled by MAC based on throughput(setting in 15A0) */ +#define ALX_PMCTRL_ASPM_FCEN BIT(30) +#define ALX_PMCTRL_SADLY_EN BIT(29) +#define ALX_PMCTRL_LCKDET_TIMER_MASK 0xF +#define ALX_PMCTRL_LCKDET_TIMER_SHIFT 24 +#define ALX_PMCTRL_LCKDET_TIMER_DEF 0xC +/* bit[23:20] if pm_request_l1 time > @, then enter L0s not L1 */ +#define ALX_PMCTRL_L1REQ_TO_MASK 0xF +#define ALX_PMCTRL_L1REQ_TO_SHIFT 20 +#define ALX_PMCTRL_L1REG_TO_DEF 0xF +#define ALX_PMCTRL_TXL1_AFTER_L0S BIT(19) +#define ALX_PMCTRL_L1_TIMER_MASK 0x7 +#define ALX_PMCTRL_L1_TIMER_SHIFT 16 +#define ALX_PMCTRL_L1_TIMER_16US 4 +#define ALX_PMCTRL_RCVR_WT_1US BIT(15) +/* bit13: enable pcie clk switch in L1 state */ +#define ALX_PMCTRL_L1_CLKSW_EN BIT(13) +#define ALX_PMCTRL_L0S_EN BIT(12) +#define ALX_PMCTRL_RXL1_AFTER_L0S BIT(11) +#define ALX_PMCTRL_L1_BUFSRX_EN BIT(7) +/* bit6: power down serdes RX */ +#define ALX_PMCTRL_L1_SRDSRX_PWD BIT(6) +#define ALX_PMCTRL_L1_SRDSPLL_EN BIT(5) +#define ALX_PMCTRL_L1_SRDS_EN BIT(4) +#define ALX_PMCTRL_L1_EN BIT(3) + +/*******************************************************/ +/* following registers are mapped only to memory space */ +/*******************************************************/ + +#define ALX_MASTER 0x1400 +/* bit12: 1:alwys select pclk from serdes, not sw to 25M */ +#define ALX_MASTER_PCLKSEL_SRDS BIT(12) +/* bit11: irq moduration for rx */ +#define ALX_MASTER_IRQMOD2_EN BIT(11) +/* bit10: irq moduration for tx/rx */ +#define ALX_MASTER_IRQMOD1_EN BIT(10) +#define ALX_MASTER_SYSALVTIMER_EN BIT(7) +#define ALX_MASTER_OOB_DIS BIT(6) +/* bit5: wakeup without pcie clk */ +#define ALX_MASTER_WAKEN_25M BIT(5) +/* bit0: MAC & DMA reset */ +#define ALX_MASTER_DMA_MAC_RST BIT(0) +#define ALX_DMA_MAC_RST_TO 50 + +#define ALX_IRQ_MODU_TIMER 0x1408 +#define ALX_IRQ_MODU_TIMER1_MASK 0xFFFF +#define ALX_IRQ_MODU_TIMER1_SHIFT 0 + +#define ALX_PHY_CTRL 0x140C +#define ALX_PHY_CTRL_100AB_EN BIT(17) +/* bit14: affect MAC & PHY, go to low power sts */ +#define ALX_PHY_CTRL_POWER_DOWN BIT(14) +/* bit13: 1:pll always ON, 0:can switch in lpw */ +#define ALX_PHY_CTRL_PLL_ON BIT(13) +#define ALX_PHY_CTRL_RST_ANALOG BIT(12) +#define ALX_PHY_CTRL_HIB_PULSE BIT(11) +#define ALX_PHY_CTRL_HIB_EN BIT(10) +#define ALX_PHY_CTRL_IDDQ BIT(7) +#define ALX_PHY_CTRL_GATE_25M BIT(5) +#define ALX_PHY_CTRL_LED_MODE BIT(2) +/* bit0: out of dsp RST state */ +#define ALX_PHY_CTRL_DSPRST_OUT BIT(0) +#define ALX_PHY_CTRL_DSPRST_TO 80 +#define ALX_PHY_CTRL_CLS (ALX_PHY_CTRL_LED_MODE | \ + ALX_PHY_CTRL_100AB_EN | \ + ALX_PHY_CTRL_PLL_ON) + +#define ALX_MAC_STS 0x1410 +#define ALX_MAC_STS_TXQ_BUSY BIT(3) +#define ALX_MAC_STS_RXQ_BUSY BIT(2) +#define ALX_MAC_STS_TXMAC_BUSY BIT(1) +#define ALX_MAC_STS_RXMAC_BUSY BIT(0) +#define ALX_MAC_STS_IDLE (ALX_MAC_STS_TXQ_BUSY | \ + ALX_MAC_STS_RXQ_BUSY | \ + ALX_MAC_STS_TXMAC_BUSY | \ + ALX_MAC_STS_RXMAC_BUSY) + +#define ALX_MDIO 0x1414 +#define ALX_MDIO_MODE_EXT BIT(30) +#define ALX_MDIO_BUSY BIT(27) +#define ALX_MDIO_CLK_SEL_MASK 0x7 +#define ALX_MDIO_CLK_SEL_SHIFT 24 +#define ALX_MDIO_CLK_SEL_25MD4 0 +#define ALX_MDIO_CLK_SEL_25MD128 7 +#define ALX_MDIO_START BIT(23) +#define ALX_MDIO_SPRES_PRMBL BIT(22) +/* bit21: 1:read,0:write */ +#define ALX_MDIO_OP_READ BIT(21) +#define ALX_MDIO_REG_MASK 0x1F +#define ALX_MDIO_REG_SHIFT 16 +#define ALX_MDIO_DATA_MASK 0xFFFF +#define ALX_MDIO_DATA_SHIFT 0 +#define ALX_MDIO_MAX_AC_TO 120 + +#define ALX_MDIO_EXTN 0x1448 +#define ALX_MDIO_EXTN_DEVAD_MASK 0x1F +#define ALX_MDIO_EXTN_DEVAD_SHIFT 16 +#define ALX_MDIO_EXTN_REG_MASK 0xFFFF +#define ALX_MDIO_EXTN_REG_SHIFT 0 + +#define ALX_SERDES 0x1424 +#define ALX_SERDES_PHYCLK_SLWDWN BIT(18) +#define ALX_SERDES_MACCLK_SLWDWN BIT(17) + +#define ALX_LPI_CTRL 0x1440 +#define ALX_LPI_CTRL_EN BIT(0) + +/* for B0+, bit[13..] for C0+ */ +#define ALX_HRTBT_EXT_CTRL 0x1AD0 +#define L1F_HRTBT_EXT_CTRL_PERIOD_HIGH_MASK 0x3F +#define L1F_HRTBT_EXT_CTRL_PERIOD_HIGH_SHIFT 24 +#define L1F_HRTBT_EXT_CTRL_SWOI_STARTUP_PKT_EN BIT(23) +#define L1F_HRTBT_EXT_CTRL_IOAC_2_FRAGMENTED BIT(22) +#define L1F_HRTBT_EXT_CTRL_IOAC_1_FRAGMENTED BIT(21) +#define L1F_HRTBT_EXT_CTRL_IOAC_1_KEEPALIVE_EN BIT(20) +#define L1F_HRTBT_EXT_CTRL_IOAC_1_HAS_VLAN BIT(19) +#define L1F_HRTBT_EXT_CTRL_IOAC_1_IS_8023 BIT(18) +#define L1F_HRTBT_EXT_CTRL_IOAC_1_IS_IPV6 BIT(17) +#define L1F_HRTBT_EXT_CTRL_IOAC_2_KEEPALIVE_EN BIT(16) +#define L1F_HRTBT_EXT_CTRL_IOAC_2_HAS_VLAN BIT(15) +#define L1F_HRTBT_EXT_CTRL_IOAC_2_IS_8023 BIT(14) +#define L1F_HRTBT_EXT_CTRL_IOAC_2_IS_IPV6 BIT(13) +#define ALX_HRTBT_EXT_CTRL_NS_EN BIT(12) +#define ALX_HRTBT_EXT_CTRL_FRAG_LEN_MASK 0xFF +#define ALX_HRTBT_EXT_CTRL_FRAG_LEN_SHIFT 4 +#define ALX_HRTBT_EXT_CTRL_IS_8023 BIT(3) +#define ALX_HRTBT_EXT_CTRL_IS_IPV6 BIT(2) +#define ALX_HRTBT_EXT_CTRL_WAKEUP_EN BIT(1) +#define ALX_HRTBT_EXT_CTRL_ARP_EN BIT(0) + +#define ALX_HRTBT_REM_IPV4_ADDR 0x1AD4 +#define ALX_HRTBT_HOST_IPV4_ADDR 0x1478 +#define ALX_HRTBT_REM_IPV6_ADDR3 0x1AD8 +#define ALX_HRTBT_REM_IPV6_ADDR2 0x1ADC +#define ALX_HRTBT_REM_IPV6_ADDR1 0x1AE0 +#define ALX_HRTBT_REM_IPV6_ADDR0 0x1AE4 + +/* 1B8C ~ 1B94 for C0+ */ +#define ALX_SWOI_ACER_CTRL 0x1B8C +#define ALX_SWOI_ORIG_ACK_NAK_EN BIT(20) +#define ALX_SWOI_ORIG_ACK_NAK_PKT_LEN_MASK 0XFF +#define ALX_SWOI_ORIG_ACK_NAK_PKT_LEN_SHIFT 12 +#define ALX_SWOI_ORIG_ACK_ADDR_MASK 0XFFF +#define ALX_SWOI_ORIG_ACK_ADDR_SHIFT 0 + +#define ALX_SWOI_IOAC_CTRL_2 0x1B90 +#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_FRAG_LEN_MASK 0xFF +#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_FRAG_LEN_SHIFT 24 +#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_PKT_LEN_MASK 0xFFF +#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_PKT_LEN_SHIFT 12 +#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_HDR_ADDR_MASK 0xFFF +#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_HDR_ADDR_SHIFT 0 + +#define ALX_SWOI_IOAC_CTRL_3 0x1B94 +#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_FRAG_LEN_MASK 0xFF +#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_FRAG_LEN_SHIFT 24 +#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_PKT_LEN_MASK 0xFFF +#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_PKT_LEN_SHIFT 12 +#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_HDR_ADDR_MASK 0xFFF +#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_HDR_ADDR_SHIFT 0 + +/* for B0 */ +#define ALX_IDLE_DECISN_TIMER 0x1474 +/* 1ms */ +#define ALX_IDLE_DECISN_TIMER_DEF 0x400 + +#define ALX_MAC_CTRL 0x1480 +#define ALX_MAC_CTRL_FAST_PAUSE BIT(31) +#define ALX_MAC_CTRL_WOLSPED_SWEN BIT(30) +/* bit29: 1:legacy(hi5b), 0:marvl(lo5b)*/ +#define ALX_MAC_CTRL_MHASH_ALG_HI5B BIT(29) +#define ALX_MAC_CTRL_BRD_EN BIT(26) +#define ALX_MAC_CTRL_MULTIALL_EN BIT(25) +#define ALX_MAC_CTRL_SPEED_MASK 0x3 +#define ALX_MAC_CTRL_SPEED_SHIFT 20 +#define ALX_MAC_CTRL_SPEED_10_100 1 +#define ALX_MAC_CTRL_SPEED_1000 2 +#define ALX_MAC_CTRL_PROMISC_EN BIT(15) +#define ALX_MAC_CTRL_VLANSTRIP BIT(14) +#define ALX_MAC_CTRL_PRMBLEN_MASK 0xF +#define ALX_MAC_CTRL_PRMBLEN_SHIFT 10 +#define ALX_MAC_CTRL_PCRCE BIT(7) +#define ALX_MAC_CTRL_CRCE BIT(6) +#define ALX_MAC_CTRL_FULLD BIT(5) +#define ALX_MAC_CTRL_RXFC_EN BIT(3) +#define ALX_MAC_CTRL_TXFC_EN BIT(2) +#define ALX_MAC_CTRL_RX_EN BIT(1) +#define ALX_MAC_CTRL_TX_EN BIT(0) + +#define ALX_STAD0 0x1488 +#define ALX_STAD1 0x148C + +#define ALX_HASH_TBL0 0x1490 +#define ALX_HASH_TBL1 0x1494 + +#define ALX_MTU 0x149C +#define ALX_MTU_JUMBO_TH 1514 +#define ALX_MTU_STD_ALGN 1536 + +#define ALX_SRAM5 0x1524 +#define ALX_SRAM_RXF_LEN_MASK 0xFFF +#define ALX_SRAM_RXF_LEN_SHIFT 0 +#define ALX_SRAM_RXF_LEN_8K (8*1024) + +#define ALX_SRAM9 0x1534 +#define ALX_SRAM_LOAD_PTR BIT(0) + +#define ALX_RX_BASE_ADDR_HI 0x1540 + +#define ALX_TX_BASE_ADDR_HI 0x1544 + +#define ALX_RFD_ADDR_LO 0x1550 +#define ALX_RFD_RING_SZ 0x1560 +#define ALX_RFD_BUF_SZ 0x1564 + +#define ALX_RRD_ADDR_LO 0x1568 +#define ALX_RRD_RING_SZ 0x1578 + +/* pri3: highest, pri0: lowest */ +#define ALX_TPD_PRI3_ADDR_LO 0x14E4 +#define ALX_TPD_PRI2_ADDR_LO 0x14E0 +#define ALX_TPD_PRI1_ADDR_LO 0x157C +#define ALX_TPD_PRI0_ADDR_LO 0x1580 + +/* producer index is 16bit */ +#define ALX_TPD_PRI3_PIDX 0x1618 +#define ALX_TPD_PRI2_PIDX 0x161A +#define ALX_TPD_PRI1_PIDX 0x15F0 +#define ALX_TPD_PRI0_PIDX 0x15F2 + +/* consumer index is 16bit */ +#define ALX_TPD_PRI3_CIDX 0x161C +#define ALX_TPD_PRI2_CIDX 0x161E +#define ALX_TPD_PRI1_CIDX 0x15F4 +#define ALX_TPD_PRI0_CIDX 0x15F6 + +#define ALX_TPD_RING_SZ 0x1584 + +#define ALX_TXQ0 0x1590 +#define ALX_TXQ0_TXF_BURST_PREF_MASK 0xFFFF +#define ALX_TXQ0_TXF_BURST_PREF_SHIFT 16 +#define ALX_TXQ_TXF_BURST_PREF_DEF 0x200 +#define ALX_TXQ0_LSO_8023_EN BIT(7) +#define ALX_TXQ0_MODE_ENHANCE BIT(6) +#define ALX_TXQ0_EN BIT(5) +#define ALX_TXQ0_SUPT_IPOPT BIT(4) +#define ALX_TXQ0_TPD_BURSTPREF_MASK 0xF +#define ALX_TXQ0_TPD_BURSTPREF_SHIFT 0 +#define ALX_TXQ_TPD_BURSTPREF_DEF 5 + +#define ALX_TXQ1 0x1594 +/* bit11: drop large packet, len > (rfd buf) */ +#define ALX_TXQ1_ERRLGPKT_DROP_EN BIT(11) +#define ALX_TXQ1_JUMBO_TSO_TH (7*1024) + +#define ALX_RXQ0 0x15A0 +#define ALX_RXQ0_EN BIT(31) +#define ALX_RXQ0_RSS_HASH_EN BIT(29) +#define ALX_RXQ0_RSS_MODE_MASK 0x3 +#define ALX_RXQ0_RSS_MODE_SHIFT 26 +#define ALX_RXQ0_RSS_MODE_DIS 0 +#define ALX_RXQ0_RSS_MODE_MQMI 3 +#define ALX_RXQ0_NUM_RFD_PREF_MASK 0x3F +#define ALX_RXQ0_NUM_RFD_PREF_SHIFT 20 +#define ALX_RXQ0_NUM_RFD_PREF_DEF 8 +#define ALX_RXQ0_IDT_TBL_SIZE_MASK 0x1FF +#define ALX_RXQ0_IDT_TBL_SIZE_SHIFT 8 +#define ALX_RXQ0_IDT_TBL_SIZE_DEF 0x100 +#define ALX_RXQ0_IDT_TBL_SIZE_NORMAL 128 +#define ALX_RXQ0_IPV6_PARSE_EN BIT(7) +#define ALX_RXQ0_RSS_HSTYP_MASK 0xF +#define ALX_RXQ0_RSS_HSTYP_SHIFT 2 +#define ALX_RXQ0_RSS_HSTYP_IPV6_TCP_EN BIT(5) +#define ALX_RXQ0_RSS_HSTYP_IPV6_EN BIT(4) +#define ALX_RXQ0_RSS_HSTYP_IPV4_TCP_EN BIT(3) +#define ALX_RXQ0_RSS_HSTYP_IPV4_EN BIT(2) +#define ALX_RXQ0_RSS_HSTYP_ALL (ALX_RXQ0_RSS_HSTYP_IPV6_TCP_EN | \ + ALX_RXQ0_RSS_HSTYP_IPV4_TCP_EN | \ + ALX_RXQ0_RSS_HSTYP_IPV6_EN | \ + ALX_RXQ0_RSS_HSTYP_IPV4_EN) +#define ALX_RXQ0_ASPM_THRESH_MASK 0x3 +#define ALX_RXQ0_ASPM_THRESH_SHIFT 0 +#define ALX_RXQ0_ASPM_THRESH_100M 3 + +#define ALX_RXQ2 0x15A8 +#define ALX_RXQ2_RXF_XOFF_THRESH_MASK 0xFFF +#define ALX_RXQ2_RXF_XOFF_THRESH_SHIFT 16 +#define ALX_RXQ2_RXF_XON_THRESH_MASK 0xFFF +#define ALX_RXQ2_RXF_XON_THRESH_SHIFT 0 +/* Size = tx-packet(1522) + IPG(12) + SOF(8) + 64(Pause) + IPG(12) + SOF(8) + + * rx-packet(1522) + delay-of-link(64) + * = 3212. + */ +#define ALX_RXQ2_RXF_FLOW_CTRL_RSVD 3212 + +#define ALX_DMA 0x15C0 +#define ALX_DMA_RCHNL_SEL_MASK 0x3 +#define ALX_DMA_RCHNL_SEL_SHIFT 26 +#define ALX_DMA_WDLY_CNT_MASK 0xF +#define ALX_DMA_WDLY_CNT_SHIFT 16 +#define ALX_DMA_WDLY_CNT_DEF 4 +#define ALX_DMA_RDLY_CNT_MASK 0x1F +#define ALX_DMA_RDLY_CNT_SHIFT 11 +#define ALX_DMA_RDLY_CNT_DEF 15 +/* bit10: 0:tpd with pri, 1: data */ +#define ALX_DMA_RREQ_PRI_DATA BIT(10) +#define ALX_DMA_RREQ_BLEN_MASK 0x7 +#define ALX_DMA_RREQ_BLEN_SHIFT 4 +#define ALX_DMA_RORDER_MODE_MASK 0x7 +#define ALX_DMA_RORDER_MODE_SHIFT 0 +#define ALX_DMA_RORDER_MODE_OUT 4 + +#define ALX_WOL0 0x14A0 +#define ALX_WOL0_PME_LINK BIT(5) +#define ALX_WOL0_LINK_EN BIT(4) +#define ALX_WOL0_PME_MAGIC_EN BIT(3) +#define ALX_WOL0_MAGIC_EN BIT(2) + +#define ALX_RFD_PIDX 0x15E0 + +#define ALX_RFD_CIDX 0x15F8 + +/* MIB */ +#define ALX_MIB_BASE 0x1700 + +#define ALX_MIB_RX_OK (ALX_MIB_BASE + 0) +#define ALX_MIB_RX_BCAST (ALX_MIB_BASE + 4) +#define ALX_MIB_RX_MCAST (ALX_MIB_BASE + 8) +#define ALX_MIB_RX_PAUSE (ALX_MIB_BASE + 12) +#define ALX_MIB_RX_CTRL (ALX_MIB_BASE + 16) +#define ALX_MIB_RX_FCS_ERR (ALX_MIB_BASE + 20) +#define ALX_MIB_RX_LEN_ERR (ALX_MIB_BASE + 24) +#define ALX_MIB_RX_BYTE_CNT (ALX_MIB_BASE + 28) +#define ALX_MIB_RX_RUNT (ALX_MIB_BASE + 32) +#define ALX_MIB_RX_FRAG (ALX_MIB_BASE + 36) +#define ALX_MIB_RX_SZ_64B (ALX_MIB_BASE + 40) +#define ALX_MIB_RX_SZ_127B (ALX_MIB_BASE + 44) +#define ALX_MIB_RX_SZ_255B (ALX_MIB_BASE + 48) +#define ALX_MIB_RX_SZ_511B (ALX_MIB_BASE + 52) +#define ALX_MIB_RX_SZ_1023B (ALX_MIB_BASE + 56) +#define ALX_MIB_RX_SZ_1518B (ALX_MIB_BASE + 60) +#define ALX_MIB_RX_SZ_MAX (ALX_MIB_BASE + 64) +#define ALX_MIB_RX_OV_SZ (ALX_MIB_BASE + 68) +#define ALX_MIB_RX_OV_RXF (ALX_MIB_BASE + 72) +#define ALX_MIB_RX_OV_RRD (ALX_MIB_BASE + 76) +#define ALX_MIB_RX_ALIGN_ERR (ALX_MIB_BASE + 80) +#define ALX_MIB_RX_BCCNT (ALX_MIB_BASE + 84) +#define ALX_MIB_RX_MCCNT (ALX_MIB_BASE + 88) +#define ALX_MIB_RX_ERRADDR (ALX_MIB_BASE + 92) + +#define ALX_MIB_TX_OK (ALX_MIB_BASE + 96) +#define ALX_MIB_TX_BCAST (ALX_MIB_BASE + 100) +#define ALX_MIB_TX_MCAST (ALX_MIB_BASE + 104) +#define ALX_MIB_TX_PAUSE (ALX_MIB_BASE + 108) +#define ALX_MIB_TX_EXC_DEFER (ALX_MIB_BASE + 112) +#define ALX_MIB_TX_CTRL (ALX_MIB_BASE + 116) +#define ALX_MIB_TX_DEFER (ALX_MIB_BASE + 120) +#define ALX_MIB_TX_BYTE_CNT (ALX_MIB_BASE + 124) +#define ALX_MIB_TX_SZ_64B (ALX_MIB_BASE + 128) +#define ALX_MIB_TX_SZ_127B (ALX_MIB_BASE + 132) +#define ALX_MIB_TX_SZ_255B (ALX_MIB_BASE + 136) +#define ALX_MIB_TX_SZ_511B (ALX_MIB_BASE + 140) +#define ALX_MIB_TX_SZ_1023B (ALX_MIB_BASE + 144) +#define ALX_MIB_TX_SZ_1518B (ALX_MIB_BASE + 148) +#define ALX_MIB_TX_SZ_MAX (ALX_MIB_BASE + 152) +#define ALX_MIB_TX_SINGLE_COL (ALX_MIB_BASE + 156) +#define ALX_MIB_TX_MULTI_COL (ALX_MIB_BASE + 160) +#define ALX_MIB_TX_LATE_COL (ALX_MIB_BASE + 164) +#define ALX_MIB_TX_ABORT_COL (ALX_MIB_BASE + 168) +#define ALX_MIB_TX_UNDERRUN (ALX_MIB_BASE + 172) +#define ALX_MIB_TX_TRD_EOP (ALX_MIB_BASE + 176) +#define ALX_MIB_TX_LEN_ERR (ALX_MIB_BASE + 180) +#define ALX_MIB_TX_TRUNC (ALX_MIB_BASE + 184) +#define ALX_MIB_TX_BCCNT (ALX_MIB_BASE + 188) +#define ALX_MIB_TX_MCCNT (ALX_MIB_BASE + 192) +#define ALX_MIB_UPDATE (ALX_MIB_BASE + 196) + + +#define ALX_ISR 0x1600 +#define ALX_ISR_DIS BIT(31) +#define ALX_ISR_RX_Q7 BIT(30) +#define ALX_ISR_RX_Q6 BIT(29) +#define ALX_ISR_RX_Q5 BIT(28) +#define ALX_ISR_RX_Q4 BIT(27) +#define ALX_ISR_PCIE_LNKDOWN BIT(26) +#define ALX_ISR_RX_Q3 BIT(19) +#define ALX_ISR_RX_Q2 BIT(18) +#define ALX_ISR_RX_Q1 BIT(17) +#define ALX_ISR_RX_Q0 BIT(16) +#define ALX_ISR_TX_Q0 BIT(15) +#define ALX_ISR_PHY BIT(12) +#define ALX_ISR_DMAW BIT(10) +#define ALX_ISR_DMAR BIT(9) +#define ALX_ISR_TXF_UR BIT(8) +#define ALX_ISR_TX_Q3 BIT(7) +#define ALX_ISR_TX_Q2 BIT(6) +#define ALX_ISR_TX_Q1 BIT(5) +#define ALX_ISR_RFD_UR BIT(4) +#define ALX_ISR_RXF_OV BIT(3) +#define ALX_ISR_MANU BIT(2) +#define ALX_ISR_TIMER BIT(1) +#define ALX_ISR_SMB BIT(0) + +#define ALX_IMR 0x1604 + +/* re-send assert msg if SW no response */ +#define ALX_INT_RETRIG 0x1608 +/* 40ms */ +#define ALX_INT_RETRIG_TO 20000 + +#define ALX_SMB_TIMER 0x15C4 + +#define ALX_TINT_TPD_THRSHLD 0x15C8 + +#define ALX_TINT_TIMER 0x15CC + +#define ALX_CLK_GATE 0x1814 +#define ALX_CLK_GATE_RXMAC BIT(5) +#define ALX_CLK_GATE_TXMAC BIT(4) +#define ALX_CLK_GATE_RXQ BIT(3) +#define ALX_CLK_GATE_TXQ BIT(2) +#define ALX_CLK_GATE_DMAR BIT(1) +#define ALX_CLK_GATE_DMAW BIT(0) +#define ALX_CLK_GATE_ALL (ALX_CLK_GATE_RXMAC | \ + ALX_CLK_GATE_TXMAC | \ + ALX_CLK_GATE_RXQ | \ + ALX_CLK_GATE_TXQ | \ + ALX_CLK_GATE_DMAR | \ + ALX_CLK_GATE_DMAW) + +/* interop between drivers */ +#define ALX_DRV 0x1804 +#define ALX_DRV_PHY_AUTO BIT(28) +#define ALX_DRV_PHY_1000 BIT(27) +#define ALX_DRV_PHY_100 BIT(26) +#define ALX_DRV_PHY_10 BIT(25) +#define ALX_DRV_PHY_DUPLEX BIT(24) +/* bit23: adv Pause */ +#define ALX_DRV_PHY_PAUSE BIT(23) +/* bit22: adv Asym Pause */ +#define ALX_DRV_PHY_MASK 0xFF +#define ALX_DRV_PHY_SHIFT 21 +#define ALX_DRV_PHY_UNKNOWN 0 + +/* flag of phy inited */ +#define ALX_PHY_INITED 0x003F + +/* reg 1830 ~ 186C for C0+, 16 bit map patterns and wake packet detection */ +#define ALX_WOL_CTRL2 0x1830 +#define ALX_WOL_CTRL2_DATA_STORE BIT(3) +#define ALX_WOL_CTRL2_PTRN_EVT BIT(2) +#define ALX_WOL_CTRL2_PME_PTRN_EN BIT(1) +#define ALX_WOL_CTRL2_PTRN_EN BIT(0) + +#define ALX_WOL_CTRL3 0x1834 +#define ALX_WOL_CTRL3_PTRN_ADDR_MASK 0xFFFFF +#define ALX_WOL_CTRL3_PTRN_ADDR_SHIFT 0 + +#define ALX_WOL_CTRL4 0x1838 +#define ALX_WOL_CTRL4_PT15_MATCH BIT(31) +#define ALX_WOL_CTRL4_PT14_MATCH BIT(30) +#define ALX_WOL_CTRL4_PT13_MATCH BIT(29) +#define ALX_WOL_CTRL4_PT12_MATCH BIT(28) +#define ALX_WOL_CTRL4_PT11_MATCH BIT(27) +#define ALX_WOL_CTRL4_PT10_MATCH BIT(26) +#define ALX_WOL_CTRL4_PT9_MATCH BIT(25) +#define ALX_WOL_CTRL4_PT8_MATCH BIT(24) +#define ALX_WOL_CTRL4_PT7_MATCH BIT(23) +#define ALX_WOL_CTRL4_PT6_MATCH BIT(22) +#define ALX_WOL_CTRL4_PT5_MATCH BIT(21) +#define ALX_WOL_CTRL4_PT4_MATCH BIT(20) +#define ALX_WOL_CTRL4_PT3_MATCH BIT(19) +#define ALX_WOL_CTRL4_PT2_MATCH BIT(18) +#define ALX_WOL_CTRL4_PT1_MATCH BIT(17) +#define ALX_WOL_CTRL4_PT0_MATCH BIT(16) +#define ALX_WOL_CTRL4_PT15_EN BIT(15) +#define ALX_WOL_CTRL4_PT14_EN BIT(14) +#define ALX_WOL_CTRL4_PT13_EN BIT(13) +#define ALX_WOL_CTRL4_PT12_EN BIT(12) +#define ALX_WOL_CTRL4_PT11_EN BIT(11) +#define ALX_WOL_CTRL4_PT10_EN BIT(10) +#define ALX_WOL_CTRL4_PT9_EN BIT(9) +#define ALX_WOL_CTRL4_PT8_EN BIT(8) +#define ALX_WOL_CTRL4_PT7_EN BIT(7) +#define ALX_WOL_CTRL4_PT6_EN BIT(6) +#define ALX_WOL_CTRL4_PT5_EN BIT(5) +#define ALX_WOL_CTRL4_PT4_EN BIT(4) +#define ALX_WOL_CTRL4_PT3_EN BIT(3) +#define ALX_WOL_CTRL4_PT2_EN BIT(2) +#define ALX_WOL_CTRL4_PT1_EN BIT(1) +#define ALX_WOL_CTRL4_PT0_EN BIT(0) + +#define ALX_WOL_CTRL5 0x183C +#define ALX_WOL_CTRL5_PT3_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT3_LEN_SHIFT 24 +#define ALX_WOL_CTRL5_PT2_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT2_LEN_SHIFT 16 +#define ALX_WOL_CTRL5_PT1_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT1_LEN_SHIFT 8 +#define ALX_WOL_CTRL5_PT0_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT0_LEN_SHIFT 0 + +#define ALX_WOL_CTRL6 0x1840 +#define ALX_WOL_CTRL5_PT7_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT7_LEN_SHIFT 24 +#define ALX_WOL_CTRL5_PT6_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT6_LEN_SHIFT 16 +#define ALX_WOL_CTRL5_PT5_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT5_LEN_SHIFT 8 +#define ALX_WOL_CTRL5_PT4_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT4_LEN_SHIFT 0 + +#define ALX_WOL_CTRL7 0x1844 +#define ALX_WOL_CTRL5_PT11_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT11_LEN_SHIFT 24 +#define ALX_WOL_CTRL5_PT10_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT10_LEN_SHIFT 16 +#define ALX_WOL_CTRL5_PT9_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT9_LEN_SHIFT 8 +#define ALX_WOL_CTRL5_PT8_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT8_LEN_SHIFT 0 + +#define ALX_WOL_CTRL8 0x1848 +#define ALX_WOL_CTRL5_PT15_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT15_LEN_SHIFT 24 +#define ALX_WOL_CTRL5_PT14_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT14_LEN_SHIFT 16 +#define ALX_WOL_CTRL5_PT13_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT13_LEN_SHIFT 8 +#define ALX_WOL_CTRL5_PT12_LEN_MASK 0xFF +#define ALX_WOL_CTRL5_PT12_LEN_SHIFT 0 + +#define ALX_ACER_FIXED_PTN0 0x1850 +#define ALX_ACER_FIXED_PTN0_MASK 0xFFFFFFFF +#define ALX_ACER_FIXED_PTN0_SHIFT 0 + +#define ALX_ACER_FIXED_PTN1 0x1854 +#define ALX_ACER_FIXED_PTN1_MASK 0xFFFF +#define ALX_ACER_FIXED_PTN1_SHIFT 0 + +#define ALX_ACER_RANDOM_NUM0 0x1858 +#define ALX_ACER_RANDOM_NUM0_MASK 0xFFFFFFFF +#define ALX_ACER_RANDOM_NUM0_SHIFT 0 + +#define ALX_ACER_RANDOM_NUM1 0x185C +#define ALX_ACER_RANDOM_NUM1_MASK 0xFFFFFFFF +#define ALX_ACER_RANDOM_NUM1_SHIFT 0 + +#define ALX_ACER_RANDOM_NUM2 0x1860 +#define ALX_ACER_RANDOM_NUM2_MASK 0xFFFFFFFF +#define ALX_ACER_RANDOM_NUM2_SHIFT 0 + +#define ALX_ACER_RANDOM_NUM3 0x1864 +#define ALX_ACER_RANDOM_NUM3_MASK 0xFFFFFFFF +#define ALX_ACER_RANDOM_NUM3_SHIFT 0 + +#define ALX_ACER_MAGIC 0x1868 +#define ALX_ACER_MAGIC_EN BIT(31) +#define ALX_ACER_MAGIC_PME_EN BIT(30) +#define ALX_ACER_MAGIC_MATCH BIT(29) +#define ALX_ACER_MAGIC_FF_CHECK BIT(10) +#define ALX_ACER_MAGIC_RAN_LEN_MASK 0x1F +#define ALX_ACER_MAGIC_RAN_LEN_SHIFT 5 +#define ALX_ACER_MAGIC_FIX_LEN_MASK 0x1F +#define ALX_ACER_MAGIC_FIX_LEN_SHIFT 0 + +#define ALX_ACER_TIMER 0x186C +#define ALX_ACER_TIMER_EN BIT(31) +#define ALX_ACER_TIMER_PME_EN BIT(30) +#define ALX_ACER_TIMER_MATCH BIT(29) +#define ALX_ACER_TIMER_THRES_MASK 0x1FFFF +#define ALX_ACER_TIMER_THRES_SHIFT 0 +#define ALX_ACER_TIMER_THRES_DEF 1 + +/* RSS definitions */ +#define ALX_RSS_KEY0 0x14B0 +#define ALX_RSS_KEY1 0x14B4 +#define ALX_RSS_KEY2 0x14B8 +#define ALX_RSS_KEY3 0x14BC +#define ALX_RSS_KEY4 0x14C0 +#define ALX_RSS_KEY5 0x14C4 +#define ALX_RSS_KEY6 0x14C8 +#define ALX_RSS_KEY7 0x14CC +#define ALX_RSS_KEY8 0x14D0 +#define ALX_RSS_KEY9 0x14D4 + +#define ALX_RSS_IDT_TBL0 0x1B00 + +#define ALX_MSI_MAP_TBL1 0x15D0 +#define ALX_MSI_MAP_TBL1_TXQ1_SHIFT 20 +#define ALX_MSI_MAP_TBL1_TXQ0_SHIFT 16 +#define ALX_MSI_MAP_TBL1_RXQ3_SHIFT 12 +#define ALX_MSI_MAP_TBL1_RXQ2_SHIFT 8 +#define ALX_MSI_MAP_TBL1_RXQ1_SHIFT 4 +#define ALX_MSI_MAP_TBL1_RXQ0_SHIFT 0 + +#define ALX_MSI_MAP_TBL2 0x15D8 +#define ALX_MSI_MAP_TBL2_TXQ3_SHIFT 20 +#define ALX_MSI_MAP_TBL2_TXQ2_SHIFT 16 +#define ALX_MSI_MAP_TBL2_RXQ7_SHIFT 12 +#define ALX_MSI_MAP_TBL2_RXQ6_SHIFT 8 +#define ALX_MSI_MAP_TBL2_RXQ5_SHIFT 4 +#define ALX_MSI_MAP_TBL2_RXQ4_SHIFT 0 + +#define ALX_MSI_ID_MAP 0x15D4 + +#define ALX_MSI_RETRANS_TIMER 0x1920 +/* bit16: 1:line,0:standard */ +#define ALX_MSI_MASK_SEL_LINE BIT(16) +#define ALX_MSI_RETRANS_TM_MASK 0xFFFF +#define ALX_MSI_RETRANS_TM_SHIFT 0 + +/* CR DMA ctrl */ + +/* TX QoS */ +#define ALX_WRR 0x1938 +#define ALX_WRR_PRI_MASK 0x3 +#define ALX_WRR_PRI_SHIFT 29 +#define ALX_WRR_PRI_RESTRICT_NONE 3 +#define ALX_WRR_PRI3_MASK 0x1F +#define ALX_WRR_PRI3_SHIFT 24 +#define ALX_WRR_PRI2_MASK 0x1F +#define ALX_WRR_PRI2_SHIFT 16 +#define ALX_WRR_PRI1_MASK 0x1F +#define ALX_WRR_PRI1_SHIFT 8 +#define ALX_WRR_PRI0_MASK 0x1F +#define ALX_WRR_PRI0_SHIFT 0 + +#define ALX_HQTPD 0x193C +#define ALX_HQTPD_BURST_EN BIT(31) +#define ALX_HQTPD_Q3_NUMPREF_MASK 0xF +#define ALX_HQTPD_Q3_NUMPREF_SHIFT 8 +#define ALX_HQTPD_Q2_NUMPREF_MASK 0xF +#define ALX_HQTPD_Q2_NUMPREF_SHIFT 4 +#define ALX_HQTPD_Q1_NUMPREF_MASK 0xF +#define ALX_HQTPD_Q1_NUMPREF_SHIFT 0 + +#define ALX_MISC 0x19C0 +#define ALX_MISC_PSW_OCP_MASK 0x7 +#define ALX_MISC_PSW_OCP_SHIFT 21 +#define ALX_MISC_PSW_OCP_DEF 0x7 +#define ALX_MISC_ISO_EN BIT(12) +#define ALX_MISC_INTNLOSC_OPEN BIT(3) + +#define ALX_MSIC2 0x19C8 +#define ALX_MSIC2_CALB_START BIT(0) + +#define ALX_MISC3 0x19CC +/* bit1: 1:Software control 25M */ +#define ALX_MISC3_25M_BY_SW BIT(1) +/* bit0: 25M switch to intnl OSC */ +#define ALX_MISC3_25M_NOTO_INTNL BIT(0) + +/* MSIX tbl in memory space */ +#define ALX_MSIX_ENTRY_BASE 0x2000 + +/********************* PHY regs definition ***************************/ + +/* PHY Specific Status Register */ +#define ALX_MII_GIGA_PSSR 0x11 +#define ALX_GIGA_PSSR_SPD_DPLX_RESOLVED 0x0800 +#define ALX_GIGA_PSSR_DPLX 0x2000 +#define ALX_GIGA_PSSR_SPEED 0xC000 +#define ALX_GIGA_PSSR_10MBS 0x0000 +#define ALX_GIGA_PSSR_100MBS 0x4000 +#define ALX_GIGA_PSSR_1000MBS 0x8000 + +/* PHY Interrupt Enable Register */ +#define ALX_MII_IER 0x12 +#define ALX_IER_LINK_UP 0x0400 +#define ALX_IER_LINK_DOWN 0x0800 + +/* PHY Interrupt Status Register */ +#define ALX_MII_ISR 0x13 + +#define ALX_MII_DBG_ADDR 0x1D +#define ALX_MII_DBG_DATA 0x1E + +/***************************** debug port *************************************/ + +#define ALX_MIIDBG_ANACTRL 0x00 +#define ALX_ANACTRL_DEF 0x02EF + +#define ALX_MIIDBG_SYSMODCTRL 0x04 +/* en half bias */ +#define ALX_SYSMODCTRL_IECHOADJ_DEF 0xBB8B + +#define ALX_MIIDBG_SRDSYSMOD 0x05 +#define ALX_SRDSYSMOD_DEEMP_EN 0x0040 +#define ALX_SRDSYSMOD_DEF 0x2C46 + +#define ALX_MIIDBG_HIBNEG 0x0B +#define ALX_HIBNEG_PSHIB_EN 0x8000 +#define ALX_HIBNEG_HIB_PSE 0x1000 +#define ALX_HIBNEG_DEF 0xBC40 +#define ALX_HIBNEG_NOHIB (ALX_HIBNEG_DEF & \ + ~(ALX_HIBNEG_PSHIB_EN | ALX_HIBNEG_HIB_PSE)) + +#define ALX_MIIDBG_TST10BTCFG 0x12 +#define ALX_TST10BTCFG_DEF 0x4C04 + +#define ALX_MIIDBG_AZ_ANADECT 0x15 +#define ALX_AZ_ANADECT_DEF 0x3220 +#define ALX_AZ_ANADECT_LONG 0x3210 + +#define ALX_MIIDBG_MSE16DB 0x18 +#define ALX_MSE16DB_UP 0x05EA +#define ALX_MSE16DB_DOWN 0x02EA + +#define ALX_MIIDBG_MSE20DB 0x1C +#define ALX_MSE20DB_TH_MASK 0x7F +#define ALX_MSE20DB_TH_SHIFT 2 +#define ALX_MSE20DB_TH_DEF 0x2E +#define ALX_MSE20DB_TH_HI 0x54 + +#define ALX_MIIDBG_AGC 0x23 +#define ALX_AGC_2_VGA_MASK 0x3FU +#define ALX_AGC_2_VGA_SHIFT 8 +#define ALX_AGC_LONG1G_LIMT 40 +#define ALX_AGC_LONG100M_LIMT 44 + +#define ALX_MIIDBG_LEGCYPS 0x29 +#define ALX_LEGCYPS_EN 0x8000 +#define ALX_LEGCYPS_DEF 0x129D + +#define ALX_MIIDBG_TST100BTCFG 0x36 +#define ALX_TST100BTCFG_DEF 0xE12C + +#define ALX_MIIDBG_GREENCFG 0x3B +#define ALX_GREENCFG_DEF 0x7078 + +#define ALX_MIIDBG_GREENCFG2 0x3D +#define ALX_GREENCFG2_BP_GREEN 0x8000 +#define ALX_GREENCFG2_GATE_DFSE_EN 0x0080 + +/******* dev 3 *********/ +#define ALX_MIIEXT_PCS 3 + +#define ALX_MIIEXT_CLDCTRL3 0x8003 +#define ALX_CLDCTRL3_BP_CABLE1TH_DET_GT 0x8000 + +#define ALX_MIIEXT_CLDCTRL5 0x8005 +#define ALX_CLDCTRL5_BP_VD_HLFBIAS 0x4000 + +#define ALX_MIIEXT_CLDCTRL6 0x8006 +#define ALX_CLDCTRL6_CAB_LEN_MASK 0xFF +#define ALX_CLDCTRL6_CAB_LEN_SHIFT 0 +#define ALX_CLDCTRL6_CAB_LEN_SHORT1G 116 +#define ALX_CLDCTRL6_CAB_LEN_SHORT100M 152 + +#define ALX_MIIEXT_VDRVBIAS 0x8062 +#define ALX_VDRVBIAS_DEF 0x3 + +/********* dev 7 **********/ +#define ALX_MIIEXT_ANEG 7 + +#define ALX_MIIEXT_LOCAL_EEEADV 0x3C +#define ALX_LOCAL_EEEADV_1000BT 0x0004 +#define ALX_LOCAL_EEEADV_100BT 0x0002 + +#define ALX_MIIEXT_AFE 0x801A +#define ALX_AFE_10BT_100M_TH 0x0040 + +#define ALX_MIIEXT_S3DIG10 0x8023 +/* bit0: 1:bypass 10BT rx fifo, 0:original 10BT rx */ +#define ALX_MIIEXT_S3DIG10_SL 0x0001 +#define ALX_MIIEXT_S3DIG10_DEF 0 + +#define ALX_MIIEXT_NLP78 0x8027 +#define ALX_MIIEXT_NLP78_120M_DEF 0x8A05 + +#endif diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h index ca70e16b6e2..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> @@ -74,8 +73,6 @@ #define AT_RX_BUF_SIZE (ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN) #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 #define AT_DEF_RECEIVE_QUEUE 1 @@ -100,7 +97,7 @@ #define ATL1C_ASPM_L0s_ENABLE 0x0001 #define ATL1C_ASPM_L1_ENABLE 0x0002 -#define AT_REGS_LEN (75 * sizeof(u32)) +#define AT_REGS_LEN (74 * sizeof(u32)) #define AT_EEPROM_LEN 512 #define ATL1C_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i])) @@ -297,20 +294,6 @@ enum atl1c_dma_req_block { atl1c_dma_req_4096 = 5 }; -enum atl1c_rss_mode { - atl1c_rss_mode_disable = 0, - atl1c_rss_sig_que = 1, - atl1c_rss_mul_que_sig_int = 2, - atl1c_rss_mul_que_mul_int = 4, -}; - -enum atl1c_rss_type { - atl1c_rss_disable = 0, - atl1c_rss_ipv4 = 1, - atl1c_rss_ipv4_tcp = 2, - atl1c_rss_ipv6 = 4, - atl1c_rss_ipv6_tcp = 8 -}; enum atl1c_nic_type { athr_l1c = 0, @@ -388,7 +371,6 @@ struct atl1c_hw { enum atl1c_dma_order dma_order; enum atl1c_dma_rcb rcb_value; enum atl1c_dma_req_block dmar_block; - enum atl1c_dma_req_block dmaw_block; u16 device_id; u16 vendor_id; @@ -399,8 +381,6 @@ struct atl1c_hw { u16 phy_id2; u32 intr_mask; - u8 dmaw_dly_cnt; - u8 dmar_dly_cnt; u8 preamble_len; u16 max_frame_size; @@ -440,10 +420,6 @@ struct atl1c_hw { #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 */ - u16 cmb_tx_timer; u32 smb_timer; u16 rrd_thresh; /* Threshold of number of RRD produced to trigger @@ -451,9 +427,6 @@ struct atl1c_hw { u16 tpd_thresh; u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. */ u8 rfd_burst; - enum atl1c_rss_type rss_type; - enum atl1c_rss_mode rss_mode; - u8 rss_hash_bits; u32 base_cpu; u32 indirect_tab; u8 mac_addr[ETH_ALEN]; @@ -462,12 +435,12 @@ struct atl1c_hw { bool phy_configured; bool re_autoneg; bool emi_ca; + bool msi_lnkpatch; /* link patch for specific platforms */ }; /* * atl1c_ring_header represents a single, contiguous block of DMA space - * mapped for the three descriptor rings (tpd, rfd, rrd) and the two - * message blocks (cmb, smb) described below + * mapped for the three descriptor rings (tpd, rfd, rrd) described below */ struct atl1c_ring_header { void *desc; /* virtual address */ @@ -541,21 +514,14 @@ struct atl1c_rrd_ring { u16 next_to_clean; }; -struct atl1c_cmb { - void *cmb; - dma_addr_t dma; -}; - -struct atl1c_smb { - void *smb; - dma_addr_t dma; -}; - /* board specific private data structure */ 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 */ @@ -586,11 +552,8 @@ struct atl1c_adapter { /* All Descriptor memory */ struct atl1c_ring_header ring_header; struct atl1c_tpd_ring tpd_ring[AT_MAX_TRANSMIT_QUEUE]; - struct atl1c_rfd_ring rfd_ring[AT_MAX_RECEIVE_QUEUE]; - struct atl1c_rrd_ring rrd_ring[AT_MAX_RECEIVE_QUEUE]; - struct atl1c_cmb cmb; - struct atl1c_smb smb; - int num_rx_queues; + struct atl1c_rfd_ring rfd_ring; + struct atl1c_rrd_ring rrd_ring; u32 bd_number; /* board number;*/ }; @@ -618,8 +581,14 @@ struct atl1c_adapter { #define AT_WRITE_REGW(a, reg, value) (\ writew((value), ((a)->hw_addr + reg))) -#define AT_READ_REGW(a, reg) (\ - readw((a)->hw_addr + reg)) +#define AT_READ_REGW(a, reg, pdata) do { \ + if (unlikely((a)->hibernate)) { \ + readw((a)->hw_addr + reg); \ + *(u16 *)pdata = readw((a)->hw_addr + reg); \ + } else { \ + *(u16 *)pdata = readw((a)->hw_addr + reg); \ + } \ + } while (0) #define AT_WRITE_REG_ARRAY(a, reg, offset, value) ( \ writel((value), (((a)->hw_addr + reg) + ((offset) << 2)))) @@ -630,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 0a9326aa58b..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; @@ -141,8 +141,7 @@ static void atl1c_get_regs(struct net_device *netdev, memset(p, 0, AT_REGS_LEN); - regs->version = 0; - AT_READ_REG(hw, REG_VPD_CAP, p++); + regs->version = 1; AT_READ_REG(hw, REG_PM_CTRL, p++); AT_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL, p++); AT_READ_REG(hw, REG_TWSI_CTRL, p++); @@ -154,7 +153,7 @@ static void atl1c_get_regs(struct net_device *netdev, AT_READ_REG(hw, REG_LINK_CTRL, p++); AT_READ_REG(hw, REG_IDLE_STATUS, p++); AT_READ_REG(hw, REG_MDIO_CTRL, p++); - AT_READ_REG(hw, REG_SERDES_LOCK, p++); + AT_READ_REG(hw, REG_SERDES, p++); AT_READ_REG(hw, REG_MAC_CTRL, p++); AT_READ_REG(hw, REG_MAC_IPG_IFG, p++); AT_READ_REG(hw, REG_MAC_STA_ADDR, p++); @@ -167,9 +166,9 @@ static void atl1c_get_regs(struct net_device *netdev, AT_READ_REG(hw, REG_WOL_CTRL, p++); atl1c_read_phy_reg(hw, MII_BMCR, &phy_data); - regs_buff[73] = (u32) phy_data; + regs_buff[AT_REGS_LEN/sizeof(u32) - 2] = (u32) phy_data; atl1c_read_phy_reg(hw, MII_BMSR, &phy_data); - regs_buff[74] = (u32) phy_data; + regs_buff[AT_REGS_LEN/sizeof(u32) - 1] = (u32) phy_data; } static int atl1c_get_eeprom_len(struct net_device *netdev) @@ -306,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 23f2ab0f2fa..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,10 +199,10 @@ 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 0; + return err; } /* @@ -278,33 +256,158 @@ void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value) } /* - * Reads the value from a PHY register - * hw - Struct containing variables accessed by shared code - * reg_addr - address of the PHY register to read + * wait mdio module be idle + * return true: idle + * false: still busy */ -int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data) +bool atl1c_wait_mdio_idle(struct atl1c_hw *hw) { u32 val; int i; - val = ((u32)(reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | - MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | - MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; + for (i = 0; i < MDIO_MAX_AC_TO; i++) { + AT_READ_REG(hw, REG_MDIO_CTRL, &val); + if (!(val & (MDIO_CTRL_BUSY | MDIO_CTRL_START))) + break; + udelay(10); + } + + return i != MDIO_MAX_AC_TO; +} + +void atl1c_stop_phy_polling(struct atl1c_hw *hw) +{ + if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION)) + return; + + AT_WRITE_REG(hw, REG_MDIO_CTRL, 0); + atl1c_wait_mdio_idle(hw); +} + +void atl1c_start_phy_polling(struct atl1c_hw *hw, u16 clk_sel) +{ + u32 val; + + if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION)) + return; + val = MDIO_CTRL_SPRES_PRMBL | + FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | + FIELDX(MDIO_CTRL_REG, 1) | + MDIO_CTRL_START | + MDIO_CTRL_OP_READ; + AT_WRITE_REG(hw, REG_MDIO_CTRL, val); + atl1c_wait_mdio_idle(hw); + val |= MDIO_CTRL_AP_EN; + val &= ~MDIO_CTRL_START; AT_WRITE_REG(hw, REG_MDIO_CTRL, val); + udelay(30); +} - for (i = 0; i < MDIO_WAIT_TIMES; i++) { - udelay(2); - AT_READ_REG(hw, REG_MDIO_CTRL, &val); - if (!(val & (MDIO_START | MDIO_BUSY))) - break; + +/* + * atl1c_read_phy_core + * core funtion to read register in PHY via MDIO control regsiter. + * ext: extension register (see IEEE 802.3) + * dev: device address (see IEEE 802.3 DEVAD, PRTAD is fixed to 0) + * reg: reg to read + */ +int atl1c_read_phy_core(struct atl1c_hw *hw, bool ext, u8 dev, + u16 reg, u16 *phy_data) +{ + u32 val; + u16 clk_sel = MDIO_CTRL_CLK_25_4; + + atl1c_stop_phy_polling(hw); + + *phy_data = 0; + + /* only l2c_b2 & l1d_2 could use slow clock */ + if ((hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) && + hw->hibernate) + clk_sel = MDIO_CTRL_CLK_25_128; + if (ext) { + val = FIELDX(MDIO_EXTN_DEVAD, dev) | FIELDX(MDIO_EXTN_REG, reg); + AT_WRITE_REG(hw, REG_MDIO_EXTN, val); + val = MDIO_CTRL_SPRES_PRMBL | + FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | + MDIO_CTRL_START | + MDIO_CTRL_MODE_EXT | + MDIO_CTRL_OP_READ; + } else { + val = MDIO_CTRL_SPRES_PRMBL | + FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | + FIELDX(MDIO_CTRL_REG, reg) | + MDIO_CTRL_START | + MDIO_CTRL_OP_READ; } - if (!(val & (MDIO_START | MDIO_BUSY))) { - *phy_data = (u16)val; - return 0; + AT_WRITE_REG(hw, REG_MDIO_CTRL, val); + + if (!atl1c_wait_mdio_idle(hw)) + return -1; + + AT_READ_REG(hw, REG_MDIO_CTRL, &val); + *phy_data = (u16)FIELD_GETX(val, MDIO_CTRL_DATA); + + atl1c_start_phy_polling(hw, clk_sel); + + return 0; +} + +/* + * atl1c_write_phy_core + * core funtion to write to register in PHY via MDIO control regsiter. + * ext: extension register (see IEEE 802.3) + * dev: device address (see IEEE 802.3 DEVAD, PRTAD is fixed to 0) + * reg: reg to write + */ +int atl1c_write_phy_core(struct atl1c_hw *hw, bool ext, u8 dev, + u16 reg, u16 phy_data) +{ + u32 val; + u16 clk_sel = MDIO_CTRL_CLK_25_4; + + atl1c_stop_phy_polling(hw); + + + /* only l2c_b2 & l1d_2 could use slow clock */ + if ((hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) && + hw->hibernate) + clk_sel = MDIO_CTRL_CLK_25_128; + + if (ext) { + val = FIELDX(MDIO_EXTN_DEVAD, dev) | FIELDX(MDIO_EXTN_REG, reg); + AT_WRITE_REG(hw, REG_MDIO_EXTN, val); + val = MDIO_CTRL_SPRES_PRMBL | + FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | + FIELDX(MDIO_CTRL_DATA, phy_data) | + MDIO_CTRL_START | + MDIO_CTRL_MODE_EXT; + } else { + val = MDIO_CTRL_SPRES_PRMBL | + FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | + FIELDX(MDIO_CTRL_DATA, phy_data) | + FIELDX(MDIO_CTRL_REG, reg) | + MDIO_CTRL_START; } + AT_WRITE_REG(hw, REG_MDIO_CTRL, val); - return -1; + if (!atl1c_wait_mdio_idle(hw)) + return -1; + + atl1c_start_phy_polling(hw, clk_sel); + + return 0; +} + +/* + * Reads the value from a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to read + */ +int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data) +{ + return atl1c_read_phy_core(hw, false, 0, reg_addr, phy_data); } /* @@ -315,27 +418,47 @@ int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data) */ int atl1c_write_phy_reg(struct atl1c_hw *hw, u32 reg_addr, u16 phy_data) { - int i; - u32 val; + return atl1c_write_phy_core(hw, false, 0, reg_addr, phy_data); +} - val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT | - (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT | - MDIO_SUP_PREAMBLE | MDIO_START | - MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; +/* read from PHY extension register */ +int atl1c_read_phy_ext(struct atl1c_hw *hw, u8 dev_addr, + u16 reg_addr, u16 *phy_data) +{ + return atl1c_read_phy_core(hw, true, dev_addr, reg_addr, phy_data); +} - AT_WRITE_REG(hw, REG_MDIO_CTRL, val); +/* write to PHY extension register */ +int atl1c_write_phy_ext(struct atl1c_hw *hw, u8 dev_addr, + u16 reg_addr, u16 phy_data) +{ + return atl1c_write_phy_core(hw, true, dev_addr, reg_addr, phy_data); +} - for (i = 0; i < MDIO_WAIT_TIMES; i++) { - udelay(2); - AT_READ_REG(hw, REG_MDIO_CTRL, &val); - if (!(val & (MDIO_START | MDIO_BUSY))) - break; - } +int atl1c_read_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data) +{ + int err; - if (!(val & (MDIO_START | MDIO_BUSY))) - return 0; + err = atl1c_write_phy_reg(hw, MII_DBG_ADDR, reg_addr); + if (unlikely(err)) + return err; + else + err = atl1c_read_phy_reg(hw, MII_DBG_DATA, phy_data); - return -1; + return err; +} + +int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data) +{ + int err; + + err = atl1c_write_phy_reg(hw, MII_DBG_ADDR, reg_addr); + if (unlikely(err)) + return err; + else + err = atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data); + + return err; } /* @@ -380,125 +503,106 @@ static int atl1c_phy_setup_adv(struct atl1c_hw *hw) void atl1c_phy_disable(struct atl1c_hw *hw) { - AT_WRITE_REGW(hw, REG_GPHY_CTRL, - GPHY_CTRL_PW_WOL_DIS | GPHY_CTRL_EXT_RESET); + atl1c_power_saving(hw, 0); } -static void atl1c_phy_magic_data(struct atl1c_hw *hw) -{ - u16 data; - - data = ANA_LOOP_SEL_10BT | ANA_EN_MASK_TB | ANA_EN_10BT_IDLE | - ((1 & ANA_INTERVAL_SEL_TIMER_MASK) << - ANA_INTERVAL_SEL_TIMER_SHIFT); - - atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_18); - atl1c_write_phy_reg(hw, MII_DBG_DATA, data); - - data = (2 & ANA_SERDES_CDR_BW_MASK) | ANA_MS_PAD_DBG | - ANA_SERDES_EN_DEEM | ANA_SERDES_SEL_HSP | ANA_SERDES_EN_PLL | - ANA_SERDES_EN_LCKDT; - - atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_5); - atl1c_write_phy_reg(hw, MII_DBG_DATA, data); - - data = (44 & ANA_LONG_CABLE_TH_100_MASK) | - ((33 & ANA_SHORT_CABLE_TH_100_MASK) << - ANA_SHORT_CABLE_TH_100_SHIFT) | ANA_BP_BAD_LINK_ACCUM | - ANA_BP_SMALL_BW; - - atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_54); - atl1c_write_phy_reg(hw, MII_DBG_DATA, data); - - data = (11 & ANA_IECHO_ADJ_MASK) | ((11 & ANA_IECHO_ADJ_MASK) << - ANA_IECHO_ADJ_2_SHIFT) | ((8 & ANA_IECHO_ADJ_MASK) << - ANA_IECHO_ADJ_1_SHIFT) | ((8 & ANA_IECHO_ADJ_MASK) << - ANA_IECHO_ADJ_0_SHIFT); - - atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_4); - atl1c_write_phy_reg(hw, MII_DBG_DATA, data); - - data = ANA_RESTART_CAL | ((7 & ANA_MANUL_SWICH_ON_MASK) << - ANA_MANUL_SWICH_ON_SHIFT) | ANA_MAN_ENABLE | - ANA_SEL_HSP | ANA_EN_HB | ANA_OEN_125M; - - atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_0); - atl1c_write_phy_reg(hw, MII_DBG_DATA, data); - - if (hw->ctrl_flags & ATL1C_HIB_DISABLE) { - atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_41); - if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0) - return; - data &= ~ANA_TOP_PS_EN; - atl1c_write_phy_reg(hw, MII_DBG_DATA, data); - - atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_11); - if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0) - return; - data &= ~ANA_PS_HIB_EN; - atl1c_write_phy_reg(hw, MII_DBG_DATA, data); - } -} 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; + u32 phy_ctrl_data, lpi_ctrl; int err; - if (hw->ctrl_flags & ATL1C_HIB_DISABLE) - phy_ctrl_data &= ~GPHY_CTRL_HIB_EN; - + /* reset PHY core */ + AT_READ_REG(hw, REG_GPHY_CTRL, &phy_ctrl_data); + phy_ctrl_data &= ~(GPHY_CTRL_EXT_RESET | GPHY_CTRL_PHY_IDDQ | + GPHY_CTRL_GATE_25M_EN | GPHY_CTRL_PWDOWN_HW | GPHY_CTRL_CLS); + phy_ctrl_data |= GPHY_CTRL_SEL_ANA_RST; + if (!(hw->ctrl_flags & ATL1C_HIB_DISABLE)) + phy_ctrl_data |= (GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE); + else + phy_ctrl_data &= ~(GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE); AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data); AT_WRITE_FLUSH(hw); - msleep(40); - phy_ctrl_data |= GPHY_CTRL_EXT_RESET; - AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data); + udelay(10); + AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data | GPHY_CTRL_EXT_RESET); AT_WRITE_FLUSH(hw); - msleep(10); + udelay(10 * GPHY_CTRL_EXT_RST_TO); /* delay 800us */ + /* switch clock */ 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); + atl1c_read_phy_dbg(hw, MIIDBG_CFGLPSPD, &phy_data); + atl1c_write_phy_dbg(hw, MIIDBG_CFGLPSPD, + phy_data & ~CFGLPSPD_RSTCNT_CLK125SW); } - 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, 0x3B); - atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data); - atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7); - msleep(20); + /* tx-half amplitude issue fix */ + if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) { + atl1c_read_phy_dbg(hw, MIIDBG_CABLE1TH_DET, &phy_data); + phy_data |= CABLE1TH_DET_EN; + atl1c_write_phy_dbg(hw, MIIDBG_CABLE1TH_DET, phy_data); } - if (hw->nic_type == athr_l1d) { - atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29); - atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x929D); + + /* clear bit3 of dbgport 3B to lower voltage */ + if (!(hw->ctrl_flags & ATL1C_HIB_DISABLE)) { + if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) { + 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); + } + /* power saving config */ + phy_data = + hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2 ? + L1D_LEGCYPS_DEF : L1C_LEGCYPS_DEF; + atl1c_write_phy_dbg(hw, MIIDBG_LEGCYPS, phy_data); + /* hib */ + atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL, + SYSMODCTRL_IECHOADJ_DEF); + } else { + /* disable pws */ + atl1c_read_phy_dbg(hw, MIIDBG_LEGCYPS, &phy_data); + atl1c_write_phy_dbg(hw, MIIDBG_LEGCYPS, + phy_data & ~LEGCYPS_EN); + /* disable hibernate */ + atl1c_read_phy_dbg(hw, MIIDBG_HIBNEG, &phy_data); + atl1c_write_phy_dbg(hw, MIIDBG_HIBNEG, + phy_data & HIBNEG_PSHIB_EN); } - if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b2 - || hw->nic_type == athr_l2c) { - atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29); - atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD); + /* disable AZ(EEE) by default */ + if (hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2 || + hw->nic_type == athr_l2c_b2) { + AT_READ_REG(hw, REG_LPI_CTRL, &lpi_ctrl); + AT_WRITE_REG(hw, REG_LPI_CTRL, lpi_ctrl & ~LPI_CTRL_EN); + atl1c_write_phy_ext(hw, MIIEXT_ANEG, MIIEXT_LOCAL_EEEADV, 0); + atl1c_write_phy_ext(hw, MIIEXT_PCS, MIIEXT_CLDCTRL3, + L2CB_CLDCTRL3); } - err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data); + + /* other debug port to set */ + atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, ANACTRL_DEF); + atl1c_write_phy_dbg(hw, MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF); + atl1c_write_phy_dbg(hw, MIIDBG_TST10BTCFG, TST10BTCFG_DEF); + /* UNH-IOL test issue, set bit7 */ + atl1c_write_phy_dbg(hw, MIIDBG_TST100BTCFG, + TST100BTCFG_DEF | TST100BTCFG_LITCH_EN); + + /* set phy interrupt mask */ + phy_data = IER_LINK_UP | IER_LINK_DOWN; + err = atl1c_write_phy_reg(hw, MII_IER, phy_data); if (err) { if (netif_msg_hw(adapter)) dev_err(&pdev->dev, "Error enable PHY linkChange Interrupt\n"); return err; } - if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION)) - atl1c_phy_magic_data(hw); return 0; } 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; @@ -589,9 +693,10 @@ 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) +/* 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; @@ -660,3 +765,101 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw) return atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data); } + +int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc) +{ + struct atl1c_adapter *adapter = hw->adapter; + struct pci_dev *pdev = adapter->pdev; + u32 master_ctrl, mac_ctrl, phy_ctrl; + u32 wol_ctrl, speed; + u16 phy_data; + + wol_ctrl = 0; + speed = adapter->link_speed == SPEED_1000 ? + MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100; + + AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl); + AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl); + AT_READ_REG(hw, REG_GPHY_CTRL, &phy_ctrl); + + master_ctrl &= ~MASTER_CTRL_CLK_SEL_DIS; + mac_ctrl = FIELD_SETX(mac_ctrl, MAC_CTRL_SPEED, speed); + mac_ctrl &= ~(MAC_CTRL_DUPLX | MAC_CTRL_RX_EN | MAC_CTRL_TX_EN); + if (adapter->link_duplex == FULL_DUPLEX) + mac_ctrl |= MAC_CTRL_DUPLX; + phy_ctrl &= ~(GPHY_CTRL_EXT_RESET | GPHY_CTRL_CLS); + phy_ctrl |= GPHY_CTRL_SEL_ANA_RST | GPHY_CTRL_HIB_PULSE | + GPHY_CTRL_HIB_EN; + if (!wufc) { /* without WoL */ + master_ctrl |= MASTER_CTRL_CLK_SEL_DIS; + phy_ctrl |= GPHY_CTRL_PHY_IDDQ | GPHY_CTRL_PWDOWN_HW; + AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl); + AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl); + AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl); + AT_WRITE_REG(hw, REG_WOL_CTRL, 0); + hw->phy_configured = false; /* re-init PHY when resume */ + return 0; + } + phy_ctrl |= GPHY_CTRL_EXT_RESET; + if (wufc & AT_WUFC_MAG) { + mac_ctrl |= MAC_CTRL_RX_EN | MAC_CTRL_BC_EN; + wol_ctrl |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN; + if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V11) + wol_ctrl |= WOL_PATTERN_EN | WOL_PATTERN_PME_EN; + } + 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 failed.\n", + atl1c_driver_name); + } + } + /* clear PHY interrupt */ + atl1c_read_phy_reg(hw, MII_ISR, &phy_data); + + dev_dbg(&pdev->dev, "%s: suspend MAC=%x,MASTER=%x,PHY=0x%x,WOL=%x\n", + atl1c_driver_name, mac_ctrl, master_ctrl, phy_ctrl, wol_ctrl); + AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl); + AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl); + AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl); + AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl); + + 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 655fc6c4a8a..21d8c4dbdbe 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h @@ -25,12 +25,18 @@ #include <linux/types.h> #include <linux/mii.h> +#define FIELD_GETX(_x, _name) ((_x) >> (_name##_SHIFT) & (_name##_MASK)) +#define FIELD_SETX(_x, _name, _v) \ +(((_x) & ~((_name##_MASK) << (_name##_SHIFT))) |\ +(((_v) & (_name##_MASK)) << (_name##_SHIFT))) +#define FIELDX(_name, _v) (((_v) & (_name##_MASK)) << (_name##_SHIFT)) + struct atl1c_adapter; 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); @@ -42,46 +48,49 @@ 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); +int atl1c_phy_to_ps_link(struct atl1c_hw *hw); +int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc); +bool atl1c_wait_mdio_idle(struct atl1c_hw *hw); +void atl1c_stop_phy_polling(struct atl1c_hw *hw); +void atl1c_start_phy_polling(struct atl1c_hw *hw, u16 clk_sel); +int atl1c_read_phy_core(struct atl1c_hw *hw, bool ext, u8 dev, + u16 reg, u16 *phy_data); +int atl1c_write_phy_core(struct atl1c_hw *hw, bool ext, u8 dev, + u16 reg, u16 phy_data); +int atl1c_read_phy_ext(struct atl1c_hw *hw, u8 dev_addr, + u16 reg_addr, u16 *phy_data); +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 +#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 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 #define DEVICE_CAP_MAX_PAYLOAD_MASK 0x7 #define DEVICE_CAP_MAX_PAYLOAD_SHIFT 0 -#define REG_DEVICE_CTRL 0x60 -#define DEVICE_CTRL_MAX_PAYLOAD_MASK 0x7 -#define DEVICE_CTRL_MAX_PAYLOAD_SHIFT 5 -#define DEVICE_CTRL_MAX_RREQ_SZ_MASK 0x7 -#define DEVICE_CTRL_MAX_RREQ_SZ_SHIFT 12 +#define DEVICE_CTRL_MAXRRS_MIN 2 #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 -#define VPD_CAP_ID_SHIFT 0 -#define VPD_CAP_NEXT_PTR_MASK 0xFF -#define VPD_CAP_NEXT_PTR_SHIFT 8 -#define VPD_CAP_VPD_ADDR_MASK 0x7FFF -#define VPD_CAP_VPD_ADDR_SHIFT 16 -#define VPD_CAP_VPD_FLAG 0x80000000 - -#define REG_VPD_DATA 0x70 - -#define REG_PCIE_UC_SEVERITY 0x10C -#define PCIE_UC_SERVRITY_TRN 0x00000001 -#define PCIE_UC_SERVRITY_DLP 0x00000010 -#define PCIE_UC_SERVRITY_PSN_TLP 0x00001000 -#define PCIE_UC_SERVRITY_FCP 0x00002000 -#define PCIE_UC_SERVRITY_CPL_TO 0x00004000 -#define PCIE_UC_SERVRITY_CA 0x00008000 -#define PCIE_UC_SERVRITY_UC 0x00010000 -#define PCIE_UC_SERVRITY_ROV 0x00020000 -#define PCIE_UC_SERVRITY_MLFP 0x00040000 -#define PCIE_UC_SERVRITY_ECRC 0x00080000 -#define PCIE_UC_SERVRITY_UR 0x00100000 +#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 */ @@ -90,25 +99,17 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #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 @@ -118,16 +119,23 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #define PCIE_DEV_MISC_SERDES_SEL_DIN 0x10 #define REG_PCIE_PHYMISC 0x1000 -#define PCIE_PHYMISC_FORCE_RCV_DET 0x4 +#define PCIE_PHYMISC_FORCE_RCV_DET BIT(2) +#define PCIE_PHYMISC_NFTS_MASK 0xFFUL +#define PCIE_PHYMISC_NFTS_SHIFT 16 #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 PCIE_PHYMISC2_L0S_TH_MASK 0x3UL +#define PCIE_PHYMISC2_L0S_TH_SHIFT 18 +#define L2CB1_PCIE_PHYMISC2_L0S_TH 3 +#define PCIE_PHYMISC2_CDR_BW_MASK 0x3UL +#define PCIE_PHYMISC2_CDR_BW_SHIFT 16 +#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) #define REG_EEPROM_CTRL 0x12C0 #define EEPROM_CTRL_DATA_HI_MASK 0xFFFF @@ -140,56 +148,81 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #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_SDES_EN 0x00000001 -#define PM_CTRL_RBER_EN 0x00000002 -#define PM_CTRL_CLK_REQ_EN 0x00000004 -#define PM_CTRL_ASPM_L1_EN 0x00000008 -#define PM_CTRL_SERDES_L1_EN 0x00000010 -#define PM_CTRL_SERDES_PLL_L1_EN 0x00000020 -#define PM_CTRL_SERDES_PD_EX_L1 0x00000040 -#define PM_CTRL_SERDES_BUDS_RX_L1_EN 0x00000080 -#define PM_CTRL_L0S_ENTRY_TIMER_MASK 0xF -#define PM_CTRL_L0S_ENTRY_TIMER_SHIFT 8 -#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_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 0xF +#define PM_CTRL_HOTRST BIT(31) +#define PM_CTRL_MAC_ASPM_CHK BIT(30) /* L0s/L1 dis by MAC based on + * thrghput(setting in 15A0) */ +#define PM_CTRL_SA_DLY_EN BIT(29) +#define PM_CTRL_L0S_BUFSRX_EN BIT(28) +#define PM_CTRL_LCKDET_TIMER_MASK 0xFUL #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 PM_CTRL_LCKDET_TIMER_DEF 0xC +#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 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 +#define L1D_PMCTRL_L1_ENTRY_TM_DIS 0 +#define L1D_PMCTRL_L1_ENTRY_TM_2US 1 +#define L1D_PMCTRL_L1_ENTRY_TM_4US 2 +#define L1D_PMCTRL_L1_ENTRY_TM_8US 3 +#define L1D_PMCTRL_L1_ENTRY_TM_16US 4 +#define L1D_PMCTRL_L1_ENTRY_TM_24US 5 +#define L1D_PMCTRL_L1_ENTRY_TM_32US 6 +#define L1D_PMCTRL_L1_ENTRY_TM_63US 7 +#define PM_CTRL_L1_ENTRY_TIMER_MASK 0xFUL /* l1C 4bits */ +#define PM_CTRL_L1_ENTRY_TIMER_SHIFT 16 +#define L2CB1_PM_CTRL_L1_ENTRY_TM 7 +#define L1C_PM_CTRL_L1_ENTRY_TM 0xF +#define PM_CTRL_RCVR_WT_TIMER BIT(15) /* 1:1us, 0:2ms */ +#define PM_CTRL_CLK_PWM_VER1_1 BIT(14) /* 0:1.0a,1:1.1 */ +#define PM_CTRL_CLK_SWH_L1 BIT(13) /* en pcie clk sw in L1 */ +#define PM_CTRL_ASPM_L0S_EN BIT(12) +#define PM_CTRL_RXL1_AFTER_L0S BIT(11) /* l1dv2.0+ */ +#define L1D_PMCTRL_L0S_TIMER_MASK 7UL /* l1d2.0+, 3bits*/ +#define L1D_PMCTRL_L0S_TIMER_SHIFT 8 +#define PM_CTRL_L0S_ENTRY_TIMER_MASK 0xFUL /* l1c, 4bits */ +#define PM_CTRL_L0S_ENTRY_TIMER_SHIFT 8 +#define PM_CTRL_SERDES_BUFS_RX_L1_EN BIT(7) +#define PM_CTRL_SERDES_PD_EX_L1 BIT(6) /* power down serdes rx */ +#define PM_CTRL_SERDES_PLL_L1_EN BIT(5) +#define PM_CTRL_SERDES_L1_EN BIT(4) +#define PM_CTRL_ASPM_L1_EN BIT(3) +#define PM_CTRL_CLK_REQ_EN BIT(2) +#define PM_CTRL_RBER_EN BIT(1) +#define PM_CTRL_SPRSDWER_EN BIT(0) #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 -#define MASTER_CTRL_RX_ITIMER_EN 0x800 -#define MASTER_CTRL_CLK_SEL_DIS 0x1000 -#define MASTER_CTRL_CLK_SWH_MODE 0x2000 -#define MASTER_CTRL_INT_RDCLR 0x4000 -#define MASTER_CTRL_REV_NUM_SHIFT 16 -#define MASTER_CTRL_REV_NUM_MASK 0xff -#define MASTER_CTRL_DEV_ID_SHIFT 24 -#define MASTER_CTRL_DEV_ID_MASK 0x7f -#define MASTER_CTRL_OTP_SEL 0x80000000 +#define MASTER_CTRL_OTP_SEL BIT(31) +#define MASTER_DEV_NUM_MASK 0x7FUL +#define MASTER_DEV_NUM_SHIFT 24 +#define MASTER_REV_NUM_MASK 0xFFUL +#define MASTER_REV_NUM_SHIFT 16 +#define MASTER_CTRL_INT_RDCLR BIT(14) +#define MASTER_CTRL_CLK_SEL_DIS BIT(12) /* 1:alwys sel pclk from + * serdes, not sw to 25M */ +#define MASTER_CTRL_RX_ITIMER_EN BIT(11) /* IRQ MODURATION FOR RX */ +#define MASTER_CTRL_TX_ITIMER_EN BIT(10) /* MODURATION FOR TX/RX */ +#define MASTER_CTRL_MANU_INT BIT(9) /* SOFT MANUAL INT */ +#define MASTER_CTRL_MANUTIMER_EN BIT(8) +#define MASTER_CTRL_SA_TIMER_EN BIT(7) /* SYS ALIVE TIMER EN */ +#define MASTER_CTRL_OOB_DIS BIT(6) /* OUT OF BOX DIS */ +#define MASTER_CTRL_WAKEN_25M BIT(5) /* WAKE WO. PCIE CLK */ +#define MASTER_CTRL_BERT_START BIT(4) +#define MASTER_PCIE_TSTMOD_MASK 3UL +#define MASTER_PCIE_TSTMOD_SHIFT 2 +#define MASTER_PCIE_RST BIT(1) +#define MASTER_CTRL_SOFT_RST BIT(0) /* RST MAC & DMA */ +#define DMA_MAC_RST_TO 50 /* Timer Initial Value Register */ #define REG_MANUAL_TIMER_INIT 0x1404 @@ -201,87 +234,85 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #define IRQ_MODRT_RX_TIMER_SHIFT 16 #define REG_GPHY_CTRL 0x140C -#define GPHY_CTRL_EXT_RESET 0x1 -#define GPHY_CTRL_RTL_MODE 0x2 -#define GPHY_CTRL_LED_MODE 0x4 -#define GPHY_CTRL_ANEG_NOW 0x8 -#define GPHY_CTRL_REV_ANEG 0x10 -#define GPHY_CTRL_GATE_25M_EN 0x20 -#define GPHY_CTRL_LPW_EXIT 0x40 -#define GPHY_CTRL_PHY_IDDQ 0x80 -#define GPHY_CTRL_PHY_IDDQ_DIS 0x100 -#define GPHY_CTRL_GIGA_DIS 0x200 -#define GPHY_CTRL_HIB_EN 0x400 -#define GPHY_CTRL_HIB_PULSE 0x800 -#define GPHY_CTRL_SEL_ANA_RST 0x1000 -#define GPHY_CTRL_PHY_PLL_ON 0x2000 -#define GPHY_CTRL_PWDOWN_HW 0x4000 -#define GPHY_CTRL_PHY_PLL_BYPASS 0x8000 - -#define GPHY_CTRL_DEFAULT ( \ - GPHY_CTRL_SEL_ANA_RST |\ - GPHY_CTRL_HIB_PULSE |\ - GPHY_CTRL_HIB_EN) - -#define GPHY_CTRL_PW_WOL_DIS ( \ - GPHY_CTRL_SEL_ANA_RST |\ - GPHY_CTRL_HIB_PULSE |\ - GPHY_CTRL_HIB_EN |\ - 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) +#define GPHY_CTRL_ADDR_MASK 0x1FUL +#define GPHY_CTRL_ADDR_SHIFT 19 +#define GPHY_CTRL_BP_VLTGSW BIT(18) +#define GPHY_CTRL_100AB_EN BIT(17) +#define GPHY_CTRL_10AB_EN BIT(16) +#define GPHY_CTRL_PHY_PLL_BYPASS BIT(15) +#define GPHY_CTRL_PWDOWN_HW BIT(14) /* affect MAC&PHY, to low pw */ +#define GPHY_CTRL_PHY_PLL_ON BIT(13) /* 1:pll always on, 0:can sw */ +#define GPHY_CTRL_SEL_ANA_RST BIT(12) +#define GPHY_CTRL_HIB_PULSE BIT(11) +#define GPHY_CTRL_HIB_EN BIT(10) +#define GPHY_CTRL_GIGA_DIS BIT(9) +#define GPHY_CTRL_PHY_IDDQ_DIS BIT(8) /* pw on RST */ +#define GPHY_CTRL_PHY_IDDQ BIT(7) /* bit8 affect bit7 while rb */ +#define GPHY_CTRL_LPW_EXIT BIT(6) +#define GPHY_CTRL_GATE_25M_EN BIT(5) +#define GPHY_CTRL_REV_ANEG BIT(4) +#define GPHY_CTRL_ANEG_NOW BIT(3) +#define GPHY_CTRL_LED_MODE BIT(2) +#define GPHY_CTRL_RTL_MODE BIT(1) +#define GPHY_CTRL_EXT_RESET BIT(0) /* 1:out of DSP RST status */ +#define GPHY_CTRL_EXT_RST_TO 80 /* 800us atmost */ +#define GPHY_CTRL_CLS (\ + GPHY_CTRL_LED_MODE |\ + GPHY_CTRL_100AB_EN |\ + GPHY_CTRL_PHY_PLL_ON) + /* Block IDLE Status Register */ -#define REG_IDLE_STATUS 0x1410 -#define IDLE_STATUS_MASK 0x00FF -#define IDLE_STATUS_RXMAC_NO_IDLE 0x1 -#define IDLE_STATUS_TXMAC_NO_IDLE 0x2 -#define IDLE_STATUS_RXQ_NO_IDLE 0x4 -#define IDLE_STATUS_TXQ_NO_IDLE 0x8 -#define IDLE_STATUS_DMAR_NO_IDLE 0x10 -#define IDLE_STATUS_DMAW_NO_IDLE 0x20 -#define IDLE_STATUS_SMB_NO_IDLE 0x40 -#define IDLE_STATUS_CMB_NO_IDLE 0x80 +#define REG_IDLE_STATUS 0x1410 +#define IDLE_STATUS_SFORCE_MASK 0xFUL +#define IDLE_STATUS_SFORCE_SHIFT 14 +#define IDLE_STATUS_CALIB_DONE BIT(13) +#define IDLE_STATUS_CALIB_RES_MASK 0x1FUL +#define IDLE_STATUS_CALIB_RES_SHIFT 8 +#define IDLE_STATUS_CALIBERR_MASK 0xFUL +#define IDLE_STATUS_CALIBERR_SHIFT 4 +#define IDLE_STATUS_TXQ_BUSY BIT(3) +#define IDLE_STATUS_RXQ_BUSY BIT(2) +#define IDLE_STATUS_TXMAC_BUSY BIT(1) +#define IDLE_STATUS_RXMAC_BUSY BIT(0) +#define IDLE_STATUS_MASK (\ + IDLE_STATUS_TXQ_BUSY |\ + IDLE_STATUS_RXQ_BUSY |\ + IDLE_STATUS_TXMAC_BUSY |\ + IDLE_STATUS_RXMAC_BUSY) /* MDIO Control Register */ #define REG_MDIO_CTRL 0x1414 -#define MDIO_DATA_MASK 0xffff /* On MDIO write, the 16-bit - * control data to write to PHY - * MII management register */ -#define MDIO_DATA_SHIFT 0 /* On MDIO read, the 16-bit - * status data that was read - * from the PHY MII management register */ -#define MDIO_REG_ADDR_MASK 0x1f /* MDIO register address */ -#define MDIO_REG_ADDR_SHIFT 16 -#define MDIO_RW 0x200000 /* 1: read, 0: write */ -#define MDIO_SUP_PREAMBLE 0x400000 /* Suppress preamble */ -#define MDIO_START 0x800000 /* Write 1 to initiate the MDIO - * master. And this bit is self - * cleared after one cycle */ -#define MDIO_CLK_SEL_SHIFT 24 -#define MDIO_CLK_25_4 0 -#define MDIO_CLK_25_6 2 -#define MDIO_CLK_25_8 3 -#define MDIO_CLK_25_10 4 -#define MDIO_CLK_25_14 5 -#define MDIO_CLK_25_20 6 -#define MDIO_CLK_25_28 7 -#define MDIO_BUSY 0x8000000 -#define MDIO_AP_EN 0x10000000 -#define MDIO_WAIT_TIMES 10 - -/* MII PHY Status Register */ -#define REG_PHY_STATUS 0x1418 -#define PHY_GENERAL_STATUS_MASK 0xFFFF -#define PHY_STATUS_RECV_ENABLE 0x0001 -#define PHY_OE_PWSP_STATUS_MASK 0x07FF -#define PHY_OE_PWSP_STATUS_SHIFT 16 -#define PHY_STATUS_LPW_STATE 0x80000000 +#define MDIO_CTRL_MODE_EXT BIT(30) +#define MDIO_CTRL_POST_READ BIT(29) +#define MDIO_CTRL_AP_EN BIT(28) +#define MDIO_CTRL_BUSY BIT(27) +#define MDIO_CTRL_CLK_SEL_MASK 0x7UL +#define MDIO_CTRL_CLK_SEL_SHIFT 24 +#define MDIO_CTRL_CLK_25_4 0 /* 25MHz divide 4 */ +#define MDIO_CTRL_CLK_25_6 2 +#define MDIO_CTRL_CLK_25_8 3 +#define MDIO_CTRL_CLK_25_10 4 +#define MDIO_CTRL_CLK_25_32 5 +#define MDIO_CTRL_CLK_25_64 6 +#define MDIO_CTRL_CLK_25_128 7 +#define MDIO_CTRL_START BIT(23) +#define MDIO_CTRL_SPRES_PRMBL BIT(22) +#define MDIO_CTRL_OP_READ BIT(21) /* 1:read, 0:write */ +#define MDIO_CTRL_REG_MASK 0x1FUL +#define MDIO_CTRL_REG_SHIFT 16 +#define MDIO_CTRL_DATA_MASK 0xFFFFUL +#define MDIO_CTRL_DATA_SHIFT 0 +#define MDIO_MAX_AC_TO 120 /* 1.2ms timeout for slow clk */ + +/* for extension reg access */ +#define REG_MDIO_EXTN 0x1448 +#define MDIO_EXTN_PORTAD_MASK 0x1FUL +#define MDIO_EXTN_PORTAD_SHIFT 21 +#define MDIO_EXTN_DEVAD_MASK 0x1FUL +#define MDIO_EXTN_DEVAD_SHIFT 16 +#define MDIO_EXTN_REG_MASK 0xFFFFUL +#define MDIO_EXTN_REG_SHIFT 0 + /* BIST Control and Status Register0 (for the Packet Memory) */ #define REG_BIST0_CTRL 0x141c #define BIST0_NOW 0x1 @@ -299,50 +330,81 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #define BIST1_FUSE_FLAG 0x4 /* SerDes Lock Detect Control and Status Register */ -#define REG_SERDES_LOCK 0x1424 -#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 +#define REG_SERDES 0x1424 +#define SERDES_PHY_CLK_SLOWDOWN BIT(18) +#define SERDES_MAC_CLK_SLOWDOWN BIT(17) +#define SERDES_SELFB_PLL_MASK 0x3UL +#define SERDES_SELFB_PLL_SHIFT 14 +#define SERDES_PHYCLK_SEL_GTX BIT(13) /* 1:gtx_clk, 0:25M */ +#define SERDES_PCIECLK_SEL_SRDS BIT(12) /* 1:serdes,0:25M */ +#define SERDES_BUFS_RX_EN BIT(11) +#define SERDES_PD_RX BIT(10) +#define SERDES_PLL_EN BIT(9) +#define SERDES_EN BIT(8) +#define SERDES_SELFB_PLL_SEL_CSR BIT(6) /* 0:state-machine,1:csr */ +#define SERDES_SELFB_PLL_CSR_MASK 0x3UL +#define SERDES_SELFB_PLL_CSR_SHIFT 4 +#define SERDES_SELFB_PLL_CSR_4 3 /* 4-12% OV-CLK */ +#define SERDES_SELFB_PLL_CSR_0 2 /* 0-4% OV-CLK */ +#define SERDES_SELFB_PLL_CSR_12 1 /* 12-18% OV-CLK */ +#define SERDES_SELFB_PLL_CSR_18 0 /* 18-25% OV-CLK */ +#define SERDES_VCO_SLOW BIT(3) +#define SERDES_VCO_FAST BIT(2) +#define SERDES_LOCK_DETECT_EN BIT(1) +#define SERDES_LOCK_DETECT BIT(0) + +#define REG_LPI_DECISN_TIMER 0x143C +#define L2CB_LPI_DESISN_TIMER 0x7D00 + +#define REG_LPI_CTRL 0x1440 +#define LPI_CTRL_CHK_DA BIT(31) +#define LPI_CTRL_ENH_TO_MASK 0x1FFFUL +#define LPI_CTRL_ENH_TO_SHIFT 12 +#define LPI_CTRL_ENH_TH_MASK 0x1FUL +#define LPI_CTRL_ENH_TH_SHIFT 6 +#define LPI_CTRL_ENH_EN BIT(5) +#define LPI_CTRL_CHK_RX BIT(4) +#define LPI_CTRL_CHK_STATE BIT(3) +#define LPI_CTRL_GMII BIT(2) +#define LPI_CTRL_TO_PHY BIT(1) +#define LPI_CTRL_EN BIT(0) + +#define REG_LPI_WAIT 0x1444 +#define LPI_WAIT_TIMER_MASK 0xFFFFUL +#define LPI_WAIT_TIMER_SHIFT 0 /* MAC Control Register */ #define REG_MAC_CTRL 0x1480 -#define MAC_CTRL_TX_EN 0x1 -#define MAC_CTRL_RX_EN 0x2 -#define MAC_CTRL_TX_FLOW 0x4 -#define MAC_CTRL_RX_FLOW 0x8 -#define MAC_CTRL_LOOPBACK 0x10 -#define MAC_CTRL_DUPLX 0x20 -#define MAC_CTRL_ADD_CRC 0x40 -#define MAC_CTRL_PAD 0x80 -#define MAC_CTRL_LENCHK 0x100 -#define MAC_CTRL_HUGE_EN 0x200 -#define MAC_CTRL_PRMLEN_SHIFT 10 -#define MAC_CTRL_PRMLEN_MASK 0xf -#define MAC_CTRL_RMV_VLAN 0x4000 -#define MAC_CTRL_PROMIS_EN 0x8000 -#define MAC_CTRL_TX_PAUSE 0x10000 -#define MAC_CTRL_SCNT 0x20000 -#define MAC_CTRL_SRST_TX 0x40000 -#define MAC_CTRL_TX_SIMURST 0x80000 -#define MAC_CTRL_SPEED_SHIFT 20 -#define MAC_CTRL_SPEED_MASK 0x3 -#define MAC_CTRL_DBG_TX_BKPRESURE 0x400000 -#define MAC_CTRL_TX_HUGE 0x800000 -#define MAC_CTRL_RX_CHKSUM_EN 0x1000000 -#define MAC_CTRL_MC_ALL_EN 0x2000000 -#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 +#define MAC_CTRL_SPEED_MODE_SW BIT(30) /* 0:phy,1:sw */ +#define MAC_CTRL_HASH_ALG_CRC32 BIT(29) /* 1:legacy,0:lw_5b */ +#define MAC_CTRL_SINGLE_PAUSE_EN BIT(28) +#define MAC_CTRL_DBG BIT(27) +#define MAC_CTRL_BC_EN BIT(26) +#define MAC_CTRL_MC_ALL_EN BIT(25) +#define MAC_CTRL_RX_CHKSUM_EN BIT(24) +#define MAC_CTRL_TX_HUGE BIT(23) +#define MAC_CTRL_DBG_TX_BKPRESURE BIT(22) +#define MAC_CTRL_SPEED_MASK 3UL +#define MAC_CTRL_SPEED_SHIFT 20 +#define MAC_CTRL_SPEED_10_100 1 +#define MAC_CTRL_SPEED_1000 2 +#define MAC_CTRL_TX_SIMURST BIT(19) +#define MAC_CTRL_SCNT BIT(17) +#define MAC_CTRL_TX_PAUSE BIT(16) +#define MAC_CTRL_PROMIS_EN BIT(15) +#define MAC_CTRL_RMV_VLAN BIT(14) +#define MAC_CTRL_PRMLEN_MASK 0xFUL +#define MAC_CTRL_PRMLEN_SHIFT 10 +#define MAC_CTRL_HUGE_EN BIT(9) +#define MAC_CTRL_LENCHK BIT(8) +#define MAC_CTRL_PAD BIT(7) +#define MAC_CTRL_ADD_CRC BIT(6) +#define MAC_CTRL_DUPLX BIT(5) +#define MAC_CTRL_LOOPBACK BIT(4) +#define MAC_CTRL_RX_FLOW BIT(3) +#define MAC_CTRL_TX_FLOW BIT(2) +#define MAC_CTRL_RX_EN BIT(1) +#define MAC_CTRL_TX_EN BIT(0) /* MAC IPG/IFG Control Register */ #define REG_MAC_IPG_IFG 0x1484 @@ -386,34 +448,53 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); /* Wake-On-Lan control register */ #define REG_WOL_CTRL 0x14a0 -#define WOL_PATTERN_EN 0x00000001 -#define WOL_PATTERN_PME_EN 0x00000002 -#define WOL_MAGIC_EN 0x00000004 -#define WOL_MAGIC_PME_EN 0x00000008 -#define WOL_LINK_CHG_EN 0x00000010 -#define WOL_LINK_CHG_PME_EN 0x00000020 -#define WOL_PATTERN_ST 0x00000100 -#define WOL_MAGIC_ST 0x00000200 -#define WOL_LINKCHG_ST 0x00000400 -#define WOL_CLK_SWITCH_EN 0x00008000 -#define WOL_PT0_EN 0x00010000 -#define WOL_PT1_EN 0x00020000 -#define WOL_PT2_EN 0x00040000 -#define WOL_PT3_EN 0x00080000 -#define WOL_PT4_EN 0x00100000 -#define WOL_PT5_EN 0x00200000 -#define WOL_PT6_EN 0x00400000 +#define WOL_PT7_MATCH BIT(31) +#define WOL_PT6_MATCH BIT(30) +#define WOL_PT5_MATCH BIT(29) +#define WOL_PT4_MATCH BIT(28) +#define WOL_PT3_MATCH BIT(27) +#define WOL_PT2_MATCH BIT(26) +#define WOL_PT1_MATCH BIT(25) +#define WOL_PT0_MATCH BIT(24) +#define WOL_PT7_EN BIT(23) +#define WOL_PT6_EN BIT(22) +#define WOL_PT5_EN BIT(21) +#define WOL_PT4_EN BIT(20) +#define WOL_PT3_EN BIT(19) +#define WOL_PT2_EN BIT(18) +#define WOL_PT1_EN BIT(17) +#define WOL_PT0_EN BIT(16) +#define WOL_LNKCHG_ST BIT(10) +#define WOL_MAGIC_ST BIT(9) +#define WOL_PATTERN_ST BIT(8) +#define WOL_OOB_EN BIT(6) +#define WOL_LINK_CHG_PME_EN BIT(5) +#define WOL_LINK_CHG_EN BIT(4) +#define WOL_MAGIC_PME_EN BIT(3) +#define WOL_MAGIC_EN BIT(2) +#define WOL_PATTERN_PME_EN BIT(1) +#define WOL_PATTERN_EN BIT(0) /* WOL Length ( 2 DWORD ) */ -#define REG_WOL_PATTERN_LEN 0x14a4 -#define WOL_PT_LEN_MASK 0x7f -#define WOL_PT0_LEN_SHIFT 0 -#define WOL_PT1_LEN_SHIFT 8 -#define WOL_PT2_LEN_SHIFT 16 -#define WOL_PT3_LEN_SHIFT 24 -#define WOL_PT4_LEN_SHIFT 0 -#define WOL_PT5_LEN_SHIFT 8 -#define WOL_PT6_LEN_SHIFT 16 +#define REG_WOL_PTLEN1 0x14A4 +#define WOL_PTLEN1_3_MASK 0xFFUL +#define WOL_PTLEN1_3_SHIFT 24 +#define WOL_PTLEN1_2_MASK 0xFFUL +#define WOL_PTLEN1_2_SHIFT 16 +#define WOL_PTLEN1_1_MASK 0xFFUL +#define WOL_PTLEN1_1_SHIFT 8 +#define WOL_PTLEN1_0_MASK 0xFFUL +#define WOL_PTLEN1_0_SHIFT 0 + +#define REG_WOL_PTLEN2 0x14A8 +#define WOL_PTLEN2_7_MASK 0xFFUL +#define WOL_PTLEN2_7_SHIFT 24 +#define WOL_PTLEN2_6_MASK 0xFFUL +#define WOL_PTLEN2_6_SHIFT 16 +#define WOL_PTLEN2_5_MASK 0xFFUL +#define WOL_PTLEN2_5_SHIFT 8 +#define WOL_PTLEN2_4_MASK 0xFFUL +#define WOL_PTLEN2_4_SHIFT 0 /* Internal SRAM Partition Register */ #define RFDX_HEAD_ADDR_MASK 0x03FF @@ -458,66 +539,50 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); */ #define REG_RX_BASE_ADDR_HI 0x1540 #define REG_TX_BASE_ADDR_HI 0x1544 -#define REG_SMB_BASE_ADDR_HI 0x1548 -#define REG_SMB_BASE_ADDR_LO 0x154C #define REG_RFD0_HEAD_ADDR_LO 0x1550 -#define REG_RFD1_HEAD_ADDR_LO 0x1554 -#define REG_RFD2_HEAD_ADDR_LO 0x1558 -#define REG_RFD3_HEAD_ADDR_LO 0x155C #define REG_RFD_RING_SIZE 0x1560 #define RFD_RING_SIZE_MASK 0x0FFF #define REG_RX_BUF_SIZE 0x1564 #define RX_BUF_SIZE_MASK 0xFFFF #define REG_RRD0_HEAD_ADDR_LO 0x1568 -#define REG_RRD1_HEAD_ADDR_LO 0x156C -#define REG_RRD2_HEAD_ADDR_LO 0x1570 -#define REG_RRD3_HEAD_ADDR_LO 0x1574 #define REG_RRD_RING_SIZE 0x1578 #define RRD_RING_SIZE_MASK 0x0FFF -#define REG_HTPD_HEAD_ADDR_LO 0x157C -#define REG_NTPD_HEAD_ADDR_LO 0x1580 +#define REG_TPD_PRI1_ADDR_LO 0x157C +#define REG_TPD_PRI0_ADDR_LO 0x1580 #define REG_TPD_RING_SIZE 0x1584 #define TPD_RING_SIZE_MASK 0xFFFF -#define REG_CMB_BASE_ADDR_LO 0x1588 - -/* RSS about */ -#define REG_RSS_KEY0 0x14B0 -#define REG_RSS_KEY1 0x14B4 -#define REG_RSS_KEY2 0x14B8 -#define REG_RSS_KEY3 0x14BC -#define REG_RSS_KEY4 0x14C0 -#define REG_RSS_KEY5 0x14C4 -#define REG_RSS_KEY6 0x14C8 -#define REG_RSS_KEY7 0x14CC -#define REG_RSS_KEY8 0x14D0 -#define REG_RSS_KEY9 0x14D4 -#define REG_IDT_TABLE0 0x14E0 -#define REG_IDT_TABLE1 0x14E4 -#define REG_IDT_TABLE2 0x14E8 -#define REG_IDT_TABLE3 0x14EC -#define REG_IDT_TABLE4 0x14F0 -#define REG_IDT_TABLE5 0x14F4 -#define REG_IDT_TABLE6 0x14F8 -#define REG_IDT_TABLE7 0x14FC -#define REG_IDT_TABLE REG_IDT_TABLE0 -#define REG_RSS_HASH_VALUE 0x15B0 -#define REG_RSS_HASH_FLAG 0x15B4 -#define REG_BASE_CPU_NUMBER 0x15B8 /* TXQ Control Register */ -#define REG_TXQ_CTRL 0x1590 -#define TXQ_NUM_TPD_BURST_MASK 0xF -#define TXQ_NUM_TPD_BURST_SHIFT 0 -#define TXQ_CTRL_IP_OPTION_EN 0x10 -#define TXQ_CTRL_EN 0x20 -#define TXQ_CTRL_ENH_MODE 0x40 -#define TXQ_CTRL_LS_8023_EN 0x80 -#define TXQ_TXF_BURST_NUM_SHIFT 16 -#define TXQ_TXF_BURST_NUM_MASK 0xFFFF +#define REG_TXQ_CTRL 0x1590 +#define TXQ_TXF_BURST_NUM_MASK 0xFFFFUL +#define TXQ_TXF_BURST_NUM_SHIFT 16 +#define L1C_TXQ_TXF_BURST_PREF 0x200 +#define L2CB_TXQ_TXF_BURST_PREF 0x40 +#define TXQ_CTRL_PEDING_CLR BIT(8) +#define TXQ_CTRL_LS_8023_EN BIT(7) +#define TXQ_CTRL_ENH_MODE BIT(6) +#define TXQ_CTRL_EN BIT(5) +#define TXQ_CTRL_IP_OPTION_EN BIT(4) +#define TXQ_NUM_TPD_BURST_MASK 0xFUL +#define TXQ_NUM_TPD_BURST_SHIFT 0 +#define TXQ_NUM_TPD_BURST_DEF 5 +#define TXQ_CFGV (\ + FIELDX(TXQ_NUM_TPD_BURST, TXQ_NUM_TPD_BURST_DEF) |\ + TXQ_CTRL_ENH_MODE |\ + TXQ_CTRL_LS_8023_EN |\ + TXQ_CTRL_IP_OPTION_EN) +#define L1C_TXQ_CFGV (\ + TXQ_CFGV |\ + FIELDX(TXQ_TXF_BURST_NUM, L1C_TXQ_TXF_BURST_PREF)) +#define L2CB_TXQ_CFGV (\ + TXQ_CFGV |\ + FIELDX(TXQ_TXF_BURST_NUM, L2CB_TXQ_TXF_BURST_PREF)) + /* Jumbo packet Threshold for task offload */ #define REG_TX_TSO_OFFLOAD_THRESH 0x1594 /* In 8-bytes */ #define TX_TSO_OFFLOAD_THRESH_MASK 0x07FF +#define MAX_TSO_FRAME_SIZE (7*1024) #define REG_TXF_WATER_MARK 0x1598 /* In 8-bytes */ #define TXF_WATER_MARK_MASK 0x0FFF @@ -537,26 +602,21 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #define ASPM_THRUPUT_LIMIT_NO 0x00 #define ASPM_THRUPUT_LIMIT_1M 0x01 #define ASPM_THRUPUT_LIMIT_10M 0x02 -#define ASPM_THRUPUT_LIMIT_100M 0x04 -#define RXQ1_CTRL_EN 0x10 -#define RXQ2_CTRL_EN 0x20 -#define RXQ3_CTRL_EN 0x40 -#define IPV6_CHKSUM_CTRL_EN 0x80 -#define RSS_HASH_BITS_MASK 0x00FF -#define RSS_HASH_BITS_SHIFT 8 -#define RSS_HASH_IPV4 0x10000 -#define RSS_HASH_IPV4_TCP 0x20000 -#define RSS_HASH_IPV6 0x40000 -#define RSS_HASH_IPV6_TCP 0x80000 +#define ASPM_THRUPUT_LIMIT_100M 0x03 +#define IPV6_CHKSUM_CTRL_EN BIT(7) #define RXQ_RFD_BURST_NUM_MASK 0x003F #define RXQ_RFD_BURST_NUM_SHIFT 20 -#define RSS_MODE_MASK 0x0003 +#define RXQ_NUM_RFD_PREF_DEF 8 +#define RSS_MODE_MASK 3UL #define RSS_MODE_SHIFT 26 -#define RSS_NIP_QUEUE_SEL_MASK 0x1 -#define RSS_NIP_QUEUE_SEL_SHIFT 28 -#define RRS_HASH_CTRL_EN 0x20000000 -#define RX_CUT_THRU_EN 0x40000000 -#define RXQ_CTRL_EN 0x80000000 +#define RSS_MODE_DIS 0 +#define RSS_MODE_SQSI 1 +#define RSS_MODE_MQSI 2 +#define RSS_MODE_MQMI 3 +#define RSS_NIP_QUEUE_SEL BIT(28) /* 0:q0, 1:table */ +#define RRS_HASH_CTRL_EN BIT(29) +#define RX_CUT_THRU_EN BIT(30) +#define RXQ_CTRL_EN BIT(31) #define REG_RFD_FREE_THRESH 0x15A4 #define RFD_FREE_THRESH_MASK 0x003F @@ -577,57 +637,45 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #define RXD_DMA_DOWN_TIMER_SHIFT 16 /* DMA Engine Control Register */ -#define REG_DMA_CTRL 0x15C0 -#define DMA_CTRL_DMAR_IN_ORDER 0x1 -#define DMA_CTRL_DMAR_ENH_ORDER 0x2 -#define DMA_CTRL_DMAR_OUT_ORDER 0x4 -#define DMA_CTRL_RCB_VALUE 0x8 -#define DMA_CTRL_DMAR_BURST_LEN_MASK 0x0007 -#define DMA_CTRL_DMAR_BURST_LEN_SHIFT 4 -#define DMA_CTRL_DMAW_BURST_LEN_MASK 0x0007 -#define DMA_CTRL_DMAW_BURST_LEN_SHIFT 7 -#define DMA_CTRL_DMAR_REQ_PRI 0x400 -#define DMA_CTRL_DMAR_DLY_CNT_MASK 0x001F -#define DMA_CTRL_DMAR_DLY_CNT_SHIFT 11 -#define DMA_CTRL_DMAW_DLY_CNT_MASK 0x000F -#define DMA_CTRL_DMAW_DLY_CNT_SHIFT 16 -#define DMA_CTRL_CMB_EN 0x100000 -#define DMA_CTRL_SMB_EN 0x200000 -#define DMA_CTRL_CMB_NOW 0x400000 -#define MAC_CTRL_SMB_DIS 0x1000000 -#define DMA_CTRL_SMB_NOW 0x80000000 - -/* CMB/SMB Control Register */ +#define REG_DMA_CTRL 0x15C0 +#define DMA_CTRL_SMB_NOW BIT(31) +#define DMA_CTRL_WPEND_CLR BIT(30) +#define DMA_CTRL_RPEND_CLR BIT(29) +#define DMA_CTRL_WDLY_CNT_MASK 0xFUL +#define DMA_CTRL_WDLY_CNT_SHIFT 16 +#define DMA_CTRL_WDLY_CNT_DEF 4 +#define DMA_CTRL_RDLY_CNT_MASK 0x1FUL +#define DMA_CTRL_RDLY_CNT_SHIFT 11 +#define DMA_CTRL_RDLY_CNT_DEF 15 +#define DMA_CTRL_RREQ_PRI_DATA BIT(10) /* 0:tpd, 1:data */ +#define DMA_CTRL_WREQ_BLEN_MASK 7UL +#define DMA_CTRL_WREQ_BLEN_SHIFT 7 +#define DMA_CTRL_RREQ_BLEN_MASK 7UL +#define DMA_CTRL_RREQ_BLEN_SHIFT 4 +#define L1C_CTRL_DMA_RCB_LEN128 BIT(3) /* 0:64bytes,1:128bytes */ +#define DMA_CTRL_RORDER_MODE_MASK 7UL +#define DMA_CTRL_RORDER_MODE_SHIFT 0 +#define DMA_CTRL_RORDER_MODE_OUT 4 +#define DMA_CTRL_RORDER_MODE_ENHANCE 2 +#define DMA_CTRL_RORDER_MODE_IN 1 + +/* INT-triggle/SMB Control Register */ #define REG_SMB_STAT_TIMER 0x15C4 /* 2us resolution */ #define SMB_STAT_TIMER_MASK 0xFFFFFF -#define REG_CMB_TPD_THRESH 0x15C8 -#define CMB_TPD_THRESH_MASK 0xFFFF -#define REG_CMB_TX_TIMER 0x15CC /* 2us resolution */ -#define CMB_TX_TIMER_MASK 0xFFFF +#define REG_TINT_TPD_THRESH 0x15C8 /* tpd th to trig intrrupt */ /* Mail box */ #define MB_RFDX_PROD_IDX_MASK 0xFFFF #define REG_MB_RFD0_PROD_IDX 0x15E0 -#define REG_MB_RFD1_PROD_IDX 0x15E4 -#define REG_MB_RFD2_PROD_IDX 0x15E8 -#define REG_MB_RFD3_PROD_IDX 0x15EC - -#define MB_PRIO_PROD_IDX_MASK 0xFFFF -#define REG_MB_PRIO_PROD_IDX 0x15F0 -#define MB_HTPD_PROD_IDX_SHIFT 0 -#define MB_NTPD_PROD_IDX_SHIFT 16 -#define MB_PRIO_CONS_IDX_MASK 0xFFFF -#define REG_MB_PRIO_CONS_IDX 0x15F4 -#define MB_HTPD_CONS_IDX_SHIFT 0 -#define MB_NTPD_CONS_IDX_SHIFT 16 +#define REG_TPD_PRI1_PIDX 0x15F0 /* 16bit,hi-tpd producer idx */ +#define REG_TPD_PRI0_PIDX 0x15F2 /* 16bit,lo-tpd producer idx */ +#define REG_TPD_PRI1_CIDX 0x15F4 /* 16bit,hi-tpd consumer idx */ +#define REG_TPD_PRI0_CIDX 0x15F6 /* 16bit,lo-tpd consumer idx */ #define REG_MB_RFD01_CONS_IDX 0x15F8 #define MB_RFD0_CONS_IDX_MASK 0x0000FFFF #define MB_RFD1_CONS_IDX_MASK 0xFFFF0000 -#define REG_MB_RFD23_CONS_IDX 0x15FC -#define MB_RFD2_CONS_IDX_MASK 0x0000FFFF -#define MB_RFD3_CONS_IDX_MASK 0xFFFF0000 /* Interrupt Status Register */ #define REG_ISR 0x1600 @@ -705,13 +753,6 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #define REG_INT_RETRIG_TIMER 0x1608 #define INT_RETRIG_TIMER_MASK 0xFFFF -#define REG_HDS_CTRL 0x160C -#define HDS_CTRL_EN 0x0001 -#define HDS_CTRL_BACKFILLSIZE_SHIFT 8 -#define HDS_CTRL_BACKFILLSIZE_MASK 0x0FFF -#define HDS_CTRL_MAX_HDRSIZE_SHIFT 20 -#define HDS_CTRL_MAC_HDRSIZE_MASK 0x0FFF - #define REG_MAC_RX_STATUS_BIN 0x1700 #define REG_MAC_RX_STATUS_END 0x175c #define REG_MAC_TX_STATUS_BIN 0x1760 @@ -796,73 +837,188 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #define MII_DBG_ADDR 0x1D #define MII_DBG_DATA 0x1E -#define MII_ANA_CTRL_0 0x0 -#define ANA_RESTART_CAL 0x0001 -#define ANA_MANUL_SWICH_ON_SHIFT 0x1 -#define ANA_MANUL_SWICH_ON_MASK 0xF -#define ANA_MAN_ENABLE 0x0020 -#define ANA_SEL_HSP 0x0040 -#define ANA_EN_HB 0x0080 -#define ANA_EN_HBIAS 0x0100 -#define ANA_OEN_125M 0x0200 -#define ANA_EN_LCKDT 0x0400 -#define ANA_LCKDT_PHY 0x0800 -#define ANA_AFE_MODE 0x1000 -#define ANA_VCO_SLOW 0x2000 -#define ANA_VCO_FAST 0x4000 -#define ANA_SEL_CLK125M_DSP 0x8000 - -#define MII_ANA_CTRL_4 0x4 -#define ANA_IECHO_ADJ_MASK 0xF -#define ANA_IECHO_ADJ_3_SHIFT 0 -#define ANA_IECHO_ADJ_2_SHIFT 4 -#define ANA_IECHO_ADJ_1_SHIFT 8 -#define ANA_IECHO_ADJ_0_SHIFT 12 - -#define MII_ANA_CTRL_5 0x5 -#define ANA_SERDES_CDR_BW_SHIFT 0 -#define ANA_SERDES_CDR_BW_MASK 0x3 -#define ANA_MS_PAD_DBG 0x0004 -#define ANA_SPEEDUP_DBG 0x0008 -#define ANA_SERDES_TH_LOS_SHIFT 4 -#define ANA_SERDES_TH_LOS_MASK 0x3 -#define ANA_SERDES_EN_DEEM 0x0040 -#define ANA_SERDES_TXELECIDLE 0x0080 -#define ANA_SERDES_BEACON 0x0100 -#define ANA_SERDES_HALFTXDR 0x0200 -#define ANA_SERDES_SEL_HSP 0x0400 -#define ANA_SERDES_EN_PLL 0x0800 -#define ANA_SERDES_EN 0x1000 -#define ANA_SERDES_EN_LCKDT 0x2000 - -#define MII_ANA_CTRL_11 0xB -#define ANA_PS_HIB_EN 0x8000 - -#define MII_ANA_CTRL_18 0x12 -#define ANA_TEST_MODE_10BT_01SHIFT 0 -#define ANA_TEST_MODE_10BT_01MASK 0x3 -#define ANA_LOOP_SEL_10BT 0x0004 -#define ANA_RGMII_MODE_SW 0x0008 -#define ANA_EN_LONGECABLE 0x0010 -#define ANA_TEST_MODE_10BT_2 0x0020 -#define ANA_EN_10BT_IDLE 0x0400 -#define ANA_EN_MASK_TB 0x0800 -#define ANA_TRIGGER_SEL_TIMER_SHIFT 12 -#define ANA_TRIGGER_SEL_TIMER_MASK 0x3 -#define ANA_INTERVAL_SEL_TIMER_SHIFT 14 -#define ANA_INTERVAL_SEL_TIMER_MASK 0x3 - -#define MII_ANA_CTRL_41 0x29 -#define ANA_TOP_PS_EN 0x8000 - -#define MII_ANA_CTRL_54 0x36 -#define ANA_LONG_CABLE_TH_100_SHIFT 0 -#define ANA_LONG_CABLE_TH_100_MASK 0x3F -#define ANA_DESERVED 0x0040 -#define ANA_EN_LIT_CH 0x0080 -#define ANA_SHORT_CABLE_TH_100_SHIFT 8 -#define ANA_SHORT_CABLE_TH_100_MASK 0x3F -#define ANA_BP_BAD_LINK_ACCUM 0x4000 -#define ANA_BP_SMALL_BW 0x8000 +/***************************** debug port *************************************/ + +#define MIIDBG_ANACTRL 0x00 +#define ANACTRL_CLK125M_DELAY_EN 0x8000 +#define ANACTRL_VCO_FAST 0x4000 +#define ANACTRL_VCO_SLOW 0x2000 +#define ANACTRL_AFE_MODE_EN 0x1000 +#define ANACTRL_LCKDET_PHY 0x800 +#define ANACTRL_LCKDET_EN 0x400 +#define ANACTRL_OEN_125M 0x200 +#define ANACTRL_HBIAS_EN 0x100 +#define ANACTRL_HB_EN 0x80 +#define ANACTRL_SEL_HSP 0x40 +#define ANACTRL_CLASSA_EN 0x20 +#define ANACTRL_MANUSWON_SWR_MASK 3U +#define ANACTRL_MANUSWON_SWR_SHIFT 2 +#define ANACTRL_MANUSWON_SWR_2V 0 +#define ANACTRL_MANUSWON_SWR_1P9V 1 +#define ANACTRL_MANUSWON_SWR_1P8V 2 +#define ANACTRL_MANUSWON_SWR_1P7V 3 +#define ANACTRL_MANUSWON_BW3_4M 0x2 +#define ANACTRL_RESTART_CAL 0x1 +#define ANACTRL_DEF 0x02EF + +#define MIIDBG_SYSMODCTRL 0x04 +#define SYSMODCTRL_IECHOADJ_PFMH_PHY 0x8000 +#define SYSMODCTRL_IECHOADJ_BIASGEN 0x4000 +#define SYSMODCTRL_IECHOADJ_PFML_PHY 0x2000 +#define SYSMODCTRL_IECHOADJ_PS_MASK 3U +#define SYSMODCTRL_IECHOADJ_PS_SHIFT 10 +#define SYSMODCTRL_IECHOADJ_PS_40 3 +#define SYSMODCTRL_IECHOADJ_PS_20 2 +#define SYSMODCTRL_IECHOADJ_PS_0 1 +#define SYSMODCTRL_IECHOADJ_10BT_100MV 0x40 /* 1:100mv, 0:200mv */ +#define SYSMODCTRL_IECHOADJ_HLFAP_MASK 3U +#define SYSMODCTRL_IECHOADJ_HLFAP_SHIFT 4 +#define SYSMODCTRL_IECHOADJ_VDFULBW 0x8 +#define SYSMODCTRL_IECHOADJ_VDBIASHLF 0x4 +#define SYSMODCTRL_IECHOADJ_VDAMPHLF 0x2 +#define SYSMODCTRL_IECHOADJ_VDLANSW 0x1 +#define SYSMODCTRL_IECHOADJ_DEF 0x88BB /* ???? */ + +/* for l1d & l2cb */ +#define SYSMODCTRL_IECHOADJ_CUR_ADD 0x8000 +#define SYSMODCTRL_IECHOADJ_CUR_MASK 7U +#define SYSMODCTRL_IECHOADJ_CUR_SHIFT 12 +#define SYSMODCTRL_IECHOADJ_VOL_MASK 0xFU +#define SYSMODCTRL_IECHOADJ_VOL_SHIFT 8 +#define SYSMODCTRL_IECHOADJ_VOL_17ALL 3 +#define SYSMODCTRL_IECHOADJ_VOL_100M15 1 +#define SYSMODCTRL_IECHOADJ_VOL_10M17 0 +#define SYSMODCTRL_IECHOADJ_BIAS1_MASK 0xFU +#define SYSMODCTRL_IECHOADJ_BIAS1_SHIFT 4 +#define SYSMODCTRL_IECHOADJ_BIAS2_MASK 0xFU +#define SYSMODCTRL_IECHOADJ_BIAS2_SHIFT 0 +#define L1D_SYSMODCTRL_IECHOADJ_DEF 0x4FBB + +#define MIIDBG_SRDSYSMOD 0x05 +#define SRDSYSMOD_LCKDET_EN 0x2000 +#define SRDSYSMOD_PLL_EN 0x800 +#define SRDSYSMOD_SEL_HSP 0x400 +#define SRDSYSMOD_HLFTXDR 0x200 +#define SRDSYSMOD_TXCLK_DELAY_EN 0x100 +#define SRDSYSMOD_TXELECIDLE 0x80 +#define SRDSYSMOD_DEEMP_EN 0x40 +#define SRDSYSMOD_MS_PAD 0x4 +#define SRDSYSMOD_CDR_ADC_VLTG 0x2 +#define SRDSYSMOD_CDR_DAC_1MA 0x1 +#define SRDSYSMOD_DEF 0x2C46 + +#define MIIDBG_CFGLPSPD 0x0A +#define CFGLPSPD_RSTCNT_MASK 3U +#define CFGLPSPD_RSTCNT_SHIFT 14 +#define CFGLPSPD_RSTCNT_CLK125SW 0x2000 + +#define MIIDBG_HIBNEG 0x0B +#define HIBNEG_PSHIB_EN 0x8000 +#define HIBNEG_WAKE_BOTH 0x4000 +#define HIBNEG_ONOFF_ANACHG_SUDEN 0x2000 +#define HIBNEG_HIB_PULSE 0x1000 +#define HIBNEG_GATE_25M_EN 0x800 +#define HIBNEG_RST_80U 0x400 +#define HIBNEG_RST_TIMER_MASK 3U +#define HIBNEG_RST_TIMER_SHIFT 8 +#define HIBNEG_GTX_CLK_DELAY_MASK 3U +#define HIBNEG_GTX_CLK_DELAY_SHIFT 5 +#define HIBNEG_BYPSS_BRKTIMER 0x10 +#define HIBNEG_DEF 0xBC40 + +#define MIIDBG_TST10BTCFG 0x12 +#define TST10BTCFG_INTV_TIMER_MASK 3U +#define TST10BTCFG_INTV_TIMER_SHIFT 14 +#define TST10BTCFG_TRIGER_TIMER_MASK 3U +#define TST10BTCFG_TRIGER_TIMER_SHIFT 12 +#define TST10BTCFG_DIV_MAN_MLT3_EN 0x800 +#define TST10BTCFG_OFF_DAC_IDLE 0x400 +#define TST10BTCFG_LPBK_DEEP 0x4 /* 1:deep,0:shallow */ +#define TST10BTCFG_DEF 0x4C04 + +#define MIIDBG_AZ_ANADECT 0x15 +#define AZ_ANADECT_10BTRX_TH 0x8000 +#define AZ_ANADECT_BOTH_01CHNL 0x4000 +#define AZ_ANADECT_INTV_MASK 0x3FU +#define AZ_ANADECT_INTV_SHIFT 8 +#define AZ_ANADECT_THRESH_MASK 0xFU +#define AZ_ANADECT_THRESH_SHIFT 4 +#define AZ_ANADECT_CHNL_MASK 0xFU +#define AZ_ANADECT_CHNL_SHIFT 0 +#define AZ_ANADECT_DEF 0x3220 +#define AZ_ANADECT_LONG 0xb210 + +#define MIIDBG_MSE16DB 0x18 /* l1d */ +#define L1D_MSE16DB_UP 0x05EA +#define L1D_MSE16DB_DOWN 0x02EA + +#define MIIDBG_LEGCYPS 0x29 +#define LEGCYPS_EN 0x8000 +#define LEGCYPS_DAC_AMP1000_MASK 7U +#define LEGCYPS_DAC_AMP1000_SHIFT 12 +#define LEGCYPS_DAC_AMP100_MASK 7U +#define LEGCYPS_DAC_AMP100_SHIFT 9 +#define LEGCYPS_DAC_AMP10_MASK 7U +#define LEGCYPS_DAC_AMP10_SHIFT 6 +#define LEGCYPS_UNPLUG_TIMER_MASK 7U +#define LEGCYPS_UNPLUG_TIMER_SHIFT 3 +#define LEGCYPS_UNPLUG_DECT_EN 0x4 +#define LEGCYPS_ECNC_PS_EN 0x1 +#define L1D_LEGCYPS_DEF 0x129D +#define L1C_LEGCYPS_DEF 0x36DD + +#define MIIDBG_TST100BTCFG 0x36 +#define TST100BTCFG_NORMAL_BW_EN 0x8000 +#define TST100BTCFG_BADLNK_BYPASS 0x4000 +#define TST100BTCFG_SHORTCABL_TH_MASK 0x3FU +#define TST100BTCFG_SHORTCABL_TH_SHIFT 8 +#define TST100BTCFG_LITCH_EN 0x80 +#define TST100BTCFG_VLT_SW 0x40 +#define TST100BTCFG_LONGCABL_TH_MASK 0x3FU +#define TST100BTCFG_LONGCABL_TH_SHIFT 0 +#define TST100BTCFG_DEF 0xE12C + +#define MIIDBG_VOLT_CTRL 0x3B /* only for l2cb 1 & 2 */ +#define VOLT_CTRL_CABLE1TH_MASK 0x1FFU +#define VOLT_CTRL_CABLE1TH_SHIFT 7 +#define VOLT_CTRL_AMPCTRL_MASK 3U +#define VOLT_CTRL_AMPCTRL_SHIFT 5 +#define VOLT_CTRL_SW_BYPASS 0x10 +#define VOLT_CTRL_SWLOWEST 0x8 +#define VOLT_CTRL_DACAMP10_MASK 7U +#define VOLT_CTRL_DACAMP10_SHIFT 0 + +#define MIIDBG_CABLE1TH_DET 0x3E +#define CABLE1TH_DET_EN 0x8000 + + +/******* dev 3 *********/ +#define MIIEXT_PCS 3 + +#define MIIEXT_CLDCTRL3 0x8003 +#define CLDCTRL3_BP_CABLE1TH_DET_GT 0x8000 +#define CLDCTRL3_AZ_DISAMP 0x1000 +#define L2CB_CLDCTRL3 0x4D19 +#define L1D_CLDCTRL3 0xDD19 + +#define MIIEXT_CLDCTRL6 0x8006 +#define CLDCTRL6_CAB_LEN_MASK 0x1FFU +#define CLDCTRL6_CAB_LEN_SHIFT 0 +#define CLDCTRL6_CAB_LEN_SHORT 0x50 + +/********* dev 7 **********/ +#define MIIEXT_ANEG 7 + +#define MIIEXT_LOCAL_EEEADV 0x3C +#define LOCAL_EEEADV_1000BT 0x4 +#define LOCAL_EEEADV_100BT 0x2 + +#define MIIEXT_REMOTE_EEEADV 0x3D +#define REMOTE_EEEADV_1000BT 0x4 +#define REMOTE_EEEADV_100BT 0x2 + +#define MIIEXT_EEE_ANEG 0x8000 +#define EEE_ANEG_1000M 0x4 +#define EEE_ANEG_100M 0x2 #endif /*_ATL1C_HW_H_*/ diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index b8591246eb4..e11bf18fbbd 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -21,17 +21,9 @@ #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; -#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 PCI_DEVICE_ID_ATHEROS_L1D_2_0 0x1083 /* AR8151 v2.0 Gigabit 1000 */ -#define L2CB_V10 0xc0 -#define L2CB_V11 0xc1 /* * atl1c_pci_tbl - PCI Device ID Table @@ -54,70 +46,72 @@ static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = { }; MODULE_DEVICE_TABLE(pci, atl1c_pci_tbl); -MODULE_AUTHOR("Jie Yang <jie.yang@atheros.com>"); -MODULE_DESCRIPTION("Atheros 1000M Ethernet Network Driver"); +MODULE_AUTHOR("Jie Yang"); +MODULE_AUTHOR("Qualcomm Atheros Inc., <nic-devel@qualcomm.com>"); +MODULE_DESCRIPTION("Qualcom Atheros 100/1000M Ethernet Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(ATL1C_DRV_VERSION); static int atl1c_stop_mac(struct atl1c_hw *hw); -static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw); -static void atl1c_enable_tx_ctrl(struct atl1c_hw *hw); static void atl1c_disable_l0s_l1(struct atl1c_hw *hw); -static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup); -static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter); -static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que, +static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed); +static void atl1c_start_mac(struct atl1c_adapter *adapter); +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, }; -static const u16 atl1c_rfd_prod_idx_regs[AT_MAX_RECEIVE_QUEUE] = -{ - REG_MB_RFD0_PROD_IDX, - REG_MB_RFD1_PROD_IDX, - REG_MB_RFD2_PROD_IDX, - REG_MB_RFD3_PROD_IDX -}; - -static const u16 atl1c_rfd_addr_lo_regs[AT_MAX_RECEIVE_QUEUE] = -{ - REG_RFD0_HEAD_ADDR_LO, - REG_RFD1_HEAD_ADDR_LO, - REG_RFD2_HEAD_ADDR_LO, - REG_RFD3_HEAD_ADDR_LO -}; - -static const u16 atl1c_rrd_addr_lo_regs[AT_MAX_RECEIVE_QUEUE] = -{ - REG_RRD0_HEAD_ADDR_LO, - REG_RRD1_HEAD_ADDR_LO, - REG_RRD2_HEAD_ADDR_LO, - REG_RRD3_HEAD_ADDR_LO -}; static const u32 atl1c_default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP; static void atl1c_pcie_patch(struct atl1c_hw *hw) { - u32 data; + u32 mst_data, data; - AT_READ_REG(hw, REG_PCIE_PHYMISC, &data); - data |= PCIE_PHYMISC_FORCE_RCV_DET; - AT_WRITE_REG(hw, REG_PCIE_PHYMISC, data); + /* pclk sel could switch to 25M */ + AT_READ_REG(hw, REG_MASTER_CTRL, &mst_data); + mst_data &= ~MASTER_CTRL_CLK_SEL_DIS; + AT_WRITE_REG(hw, REG_MASTER_CTRL, mst_data); + /* WoL/PCIE related settings */ + if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) { + AT_READ_REG(hw, REG_PCIE_PHYMISC, &data); + data |= PCIE_PHYMISC_FORCE_RCV_DET; + AT_WRITE_REG(hw, REG_PCIE_PHYMISC, data); + } else { /* new dev set bit5 of MASTER */ + if (!(mst_data & MASTER_CTRL_WAKEN_25M)) + AT_WRITE_REG(hw, REG_MASTER_CTRL, + mst_data | MASTER_CTRL_WAKEN_25M); + } + /* aspm/PCIE setting only for l2cb 1.0 */ if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10) { AT_READ_REG(hw, REG_PCIE_PHYMISC2, &data); - - data &= ~(PCIE_PHYMISC2_SERDES_CDR_MASK << - PCIE_PHYMISC2_SERDES_CDR_SHIFT); - data |= 3 << PCIE_PHYMISC2_SERDES_CDR_SHIFT; - data &= ~(PCIE_PHYMISC2_SERDES_TH_MASK << - PCIE_PHYMISC2_SERDES_TH_SHIFT); - data |= 3 << PCIE_PHYMISC2_SERDES_TH_SHIFT; + data = FIELD_SETX(data, PCIE_PHYMISC2_CDR_BW, + L2CB1_PCIE_PHYMISC2_CDR_BW); + data = FIELD_SETX(data, PCIE_PHYMISC2_L0S_TH, + L2CB1_PCIE_PHYMISC2_L0S_TH); AT_WRITE_REG(hw, REG_PCIE_PHYMISC2, data); + /* extend L1 sync timer */ + AT_READ_REG(hw, REG_LINK_CTRL, &data); + data |= LINK_CTRL_EXT_SYNC; + AT_WRITE_REG(hw, REG_LINK_CTRL, data); + } + /* l2cb 1.x & l1d 1.x */ + if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d) { + AT_READ_REG(hw, REG_PM_CTRL, &data); + data |= PM_CTRL_L0S_BUFSRX_EN; + AT_WRITE_REG(hw, REG_PM_CTRL, data); + /* clear vendor msg */ + AT_READ_REG(hw, REG_DMA_DBG, &data); + AT_WRITE_REG(hw, REG_DMA_DBG, data & ~DMA_DBG_VENDOR_MSG); } } @@ -130,6 +124,7 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag) u32 data; u32 pci_cmd; struct pci_dev *pdev = hw->adapter->pdev; + int pos; AT_READ_REG(hw, PCI_COMMAND, &pci_cmd); pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; @@ -142,14 +137,25 @@ 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 */ - AT_READ_REG(hw, REG_PCIE_UC_SEVERITY, &data); - data &= ~PCIE_UC_SERVRITY_DLP; - data &= ~PCIE_UC_SERVRITY_FCP; - AT_WRITE_REG(hw, REG_PCIE_UC_SEVERITY, data); + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); + 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 */ + pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, + PCI_EXP_DEVSTA_NFED | + PCI_EXP_DEVSTA_FED | + PCI_EXP_DEVSTA_CED | + PCI_EXP_DEVSTA_URD); AT_READ_REG(hw, REG_LTSSM_ID_CTRL, &data); data &= ~LTSSM_ID_EN_WRO; @@ -158,16 +164,11 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag) atl1c_pcie_patch(hw); if (flag & ATL1C_PCIE_L0S_L1_DISABLE) atl1c_disable_l0s_l1(hw); - if (flag & ATL1C_PCIE_PHY_RESET) - AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT); - else - AT_WRITE_REG(hw, REG_GPHY_CTRL, - GPHY_CTRL_DEFAULT | GPHY_CTRL_EXT_RESET); msleep(5); } -/* +/** * atl1c_irq_enable - Enable default interrupt generation settings * @adapter: board private structure */ @@ -180,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 */ @@ -193,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 */ @@ -207,21 +208,21 @@ static inline void atl1c_irq_reset(struct atl1c_adapter *adapter) * atl1c_wait_until_idle - wait up to AT_HW_MAX_IDLE_DELAY reads * of the idle status register until the device is actually idle */ -static u32 atl1c_wait_until_idle(struct atl1c_hw *hw) +static u32 atl1c_wait_until_idle(struct atl1c_hw *hw, u32 modu_ctrl) { int timeout; u32 data; for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { AT_READ_REG(hw, REG_IDLE_STATUS, &data); - if ((data & IDLE_STATUS_MASK) == 0) + if ((data & modu_ctrl) == 0) return 0; msleep(1); } return data; } -/* +/** * atl1c_phy_config - Timer Call-back * @data: pointer to netdev cast into an unsigned long */ @@ -261,15 +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"); - atl1c_set_aspm(hw, false); - netif_carrier_off(netdev); - netif_stop_queue(netdev); - atl1c_phy_reset(hw); - atl1c_phy_init(&adapter->hw); + dev_warn(&pdev->dev, "reset mac failed\n"); + atl1c_set_aspm(hw, SPEED_0); + atl1c_post_phy_linkchg(hw, SPEED_0); + atl1c_reset_dma_ring(adapter); + atl1c_configure(adapter); } else { /* Link Up */ hw->hibernate = false; @@ -283,10 +284,9 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) adapter->link_duplex != duplex) { adapter->link_speed = speed; adapter->link_duplex = duplex; - atl1c_set_aspm(hw, true); - atl1c_enable_tx_ctrl(hw); - atl1c_enable_rx_ctrl(hw); - atl1c_setup_mac_ctrl(adapter); + atl1c_set_aspm(hw, speed); + atl1c_post_phy_linkchg(hw, speed); + atl1c_start_mac(adapter); if (netif_msg_link(adapter)) dev_info(&pdev->dev, "%s: %s NIC Link is Up<%d Mbps %s>\n", @@ -337,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); @@ -345,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); + } } @@ -356,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 */ @@ -369,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 * @@ -413,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 { @@ -448,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 @@ -469,7 +475,7 @@ 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); - atl1c_hw_set_mac_addr(&adapter->hw); + atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr); return 0; } @@ -477,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, @@ -490,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); @@ -506,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 @@ -522,11 +533,16 @@ static int atl1c_set_features(struct net_device *netdev, static int atl1c_change_mtu(struct net_device *netdev, int new_mtu) { struct atl1c_adapter *adapter = netdev_priv(netdev); + struct atl1c_hw *hw = &adapter->hw; int old_mtu = netdev->mtu; int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; - if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) || - (max_frame > MAX_JUMBO_FRAME_SIZE)) { + /* Fast Ethernet controller doesn't support jumbo packet */ + if (((hw->nic_type == athr_l2c || + hw->nic_type == athr_l2c_b || + hw->nic_type == athr_l2c_b2) && new_mtu > ETH_DATA_LEN) || + max_frame < ETH_ZLEN + ETH_FCS_LEN || + max_frame > MAX_JUMBO_FRAME_SIZE) { if (netif_msg_link(adapter)) dev_warn(&adapter->pdev->dev, "invalid MTU setting\n"); return -EINVAL; @@ -542,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; } @@ -562,7 +570,7 @@ static int atl1c_mdio_read(struct net_device *netdev, int phy_id, int reg_num) struct atl1c_adapter *adapter = netdev_priv(netdev); u16 result; - atl1c_read_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, &result); + atl1c_read_phy_reg(&adapter->hw, reg_num, &result); return result; } @@ -571,15 +579,9 @@ static void atl1c_mdio_write(struct net_device *netdev, int phy_id, { struct atl1c_adapter *adapter = netdev_priv(netdev); - atl1c_write_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, val); + 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) { @@ -630,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) { @@ -648,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; } @@ -686,21 +682,15 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw) static int atl1c_setup_mac_funcs(struct atl1c_hw *hw) { - u32 phy_status_data; u32 link_ctrl_data; atl1c_set_mac_type(hw); - AT_READ_REG(hw, REG_PHY_STATUS, &phy_status_data); AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data); hw->ctrl_flags = ATL1C_INTR_MODRT_ENABLE | ATL1C_TXQ_MODE_ENHANCE; - if (link_ctrl_data & LINK_CTRL_L0S_EN) - 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; + hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT | + ATL1C_ASPM_L1_SUPPORT; hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON; if (hw->nic_type == athr_l1c || @@ -709,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 * @@ -717,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; @@ -728,15 +781,14 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) device_set_wakeup_enable(&pdev->dev, false); adapter->link_speed = SPEED_0; adapter->link_duplex = FULL_DUPLEX; - adapter->num_rx_queues = AT_DEF_RECEIVE_QUEUE; adapter->tpd_ring[0].count = 1024; - adapter->rfd_ring[0].count = 512; + adapter->rfd_ring.count = 512; hw->vendor_id = pdev->vendor; 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; @@ -745,26 +797,18 @@ 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; hw->max_frame_size = adapter->netdev->mtu; - if (adapter->num_rx_queues < 2) { - hw->rss_type = atl1c_rss_disable; - hw->rss_mode = atl1c_rss_mode_disable; - } else { - hw->rss_type = atl1c_rss_ipv4; - hw->rss_mode = atl1c_rss_mul_que_mul_int; - hw->rss_hash_bits = 16; - } hw->autoneg_advertised = ADVERTISED_Autoneg; hw->indirect_tab = 0xE4E4E4E4; hw->base_cpu = 0; hw->ict = 50000; /* 100ms */ hw->smb_timer = 200000; /* 400ms */ - hw->cmb_tpd = 4; - hw->cmb_tx_timer = 1; /* 2 us */ hw->rx_imt = 200; hw->tx_imt = 1000; @@ -772,9 +816,6 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) hw->rfd_burst = 8; hw->dma_order = atl1c_dma_ord_out; hw->dmar_block = atl1c_dma_req_1024; - hw->dmaw_block = atl1c_dma_req_1024; - hw->dmar_dly_cnt = 15; - hw->dmaw_dly_cnt = 4; if (atl1c_alloc_queues(adapter)) { dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); @@ -791,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) @@ -809,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 */ @@ -834,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 */ @@ -844,30 +881,28 @@ 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 */ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter) { - struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring; - struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring; + struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring; struct atl1c_buffer *buffer_info; struct pci_dev *pdev = adapter->pdev; - int i, j; + int j; - for (i = 0; i < adapter->num_rx_queues; i++) { - for (j = 0; j < rfd_ring[i].count; j++) { - buffer_info = &rfd_ring[i].buffer_info[j]; - atl1c_clean_buffer(pdev, buffer_info, 0); - } - /* zero out the descriptor ring */ - memset(rfd_ring[i].desc, 0, rfd_ring[i].size); - rfd_ring[i].next_to_clean = 0; - rfd_ring[i].next_to_use = 0; - rrd_ring[i].next_to_use = 0; - rrd_ring[i].next_to_clean = 0; + for (j = 0; j < rfd_ring->count; j++) { + buffer_info = &rfd_ring->buffer_info[j]; + atl1c_clean_buffer(pdev, buffer_info); } + /* zero out the descriptor ring */ + memset(rfd_ring->desc, 0, rfd_ring->size); + rfd_ring->next_to_clean = 0; + rfd_ring->next_to_use = 0; + rrd_ring->next_to_use = 0; + rrd_ring->next_to_clean = 0; } /* @@ -876,8 +911,8 @@ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter) static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter) { struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring; - struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring; - struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring; + struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring; struct atl1c_buffer *buffer_info; int i, j; @@ -889,19 +924,17 @@ static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter) ATL1C_SET_BUFFER_STATE(&buffer_info[i], ATL1C_BUFFER_FREE); } - for (i = 0; i < adapter->num_rx_queues; i++) { - rfd_ring[i].next_to_use = 0; - rfd_ring[i].next_to_clean = 0; - rrd_ring[i].next_to_use = 0; - rrd_ring[i].next_to_clean = 0; - for (j = 0; j < rfd_ring[i].count; j++) { - buffer_info = &rfd_ring[i].buffer_info[j]; - ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE); - } + rfd_ring->next_to_use = 0; + rfd_ring->next_to_clean = 0; + rrd_ring->next_to_use = 0; + rrd_ring->next_to_clean = 0; + for (j = 0; j < rfd_ring->count; j++) { + buffer_info = &rfd_ring->buffer_info[j]; + ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE); } } -/* +/** * atl1c_free_ring_resources - Free Tx / RX descriptor Resources * @adapter: board private structure * @@ -922,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 * @@ -934,45 +971,38 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring; - struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring; - struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring; + struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring; struct atl1c_ring_header *ring_header = &adapter->ring_header; - int num_rx_queues = adapter->num_rx_queues; int size; int i; int count = 0; int rx_desc_count = 0; u32 offset = 0; - rrd_ring[0].count = rfd_ring[0].count; + rrd_ring->count = rfd_ring->count; for (i = 1; i < AT_MAX_TRANSMIT_QUEUE; i++) tpd_ring[i].count = tpd_ring[0].count; - for (i = 1; i < adapter->num_rx_queues; i++) - rfd_ring[i].count = rrd_ring[i].count = rfd_ring[0].count; - /* 2 tpd queue, one high priority queue, * another normal priority queue */ size = sizeof(struct atl1c_buffer) * (tpd_ring->count * 2 + - rfd_ring->count * num_rx_queues); + 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; } - for (i = 0; i < num_rx_queues; i++) { - rfd_ring[i].buffer_info = - (struct atl1c_buffer *) (tpd_ring->buffer_info + count); - count += rfd_ring[i].count; - rx_desc_count += rfd_ring[i].count; - } + rfd_ring->buffer_info = + (tpd_ring->buffer_info + count); + count += rfd_ring->count; + rx_desc_count += rfd_ring->count; + /* * real ring DMA buffer * each ring/block may need up to 8 bytes for alignment, hence the @@ -982,8 +1012,7 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) sizeof(struct atl1c_tpd_desc) * tpd_ring->count * 2 + sizeof(struct atl1c_rx_free_desc) * rx_desc_count + sizeof(struct atl1c_recv_ret_status) * rx_desc_count + - sizeof(struct atl1c_hw_stats) + - 8 * 4 + 8 * 2 * num_rx_queues; + 8 * 4; ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, &ring_header->dma); @@ -1004,25 +1033,18 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) offset += roundup(tpd_ring[i].size, 8); } /* init RFD ring */ - for (i = 0; i < num_rx_queues; i++) { - rfd_ring[i].dma = ring_header->dma + offset; - rfd_ring[i].desc = (u8 *) ring_header->desc + offset; - rfd_ring[i].size = sizeof(struct atl1c_rx_free_desc) * - rfd_ring[i].count; - offset += roundup(rfd_ring[i].size, 8); - } + rfd_ring->dma = ring_header->dma + offset; + rfd_ring->desc = (u8 *) ring_header->desc + offset; + rfd_ring->size = sizeof(struct atl1c_rx_free_desc) * rfd_ring->count; + offset += roundup(rfd_ring->size, 8); /* init RRD ring */ - for (i = 0; i < num_rx_queues; i++) { - rrd_ring[i].dma = ring_header->dma + offset; - rrd_ring[i].desc = (u8 *) ring_header->desc + offset; - rrd_ring[i].size = sizeof(struct atl1c_recv_ret_status) * - rrd_ring[i].count; - offset += roundup(rrd_ring[i].size, 8); - } + rrd_ring->dma = ring_header->dma + offset; + rrd_ring->desc = (u8 *) ring_header->desc + offset; + rrd_ring->size = sizeof(struct atl1c_recv_ret_status) * + rrd_ring->count; + offset += roundup(rrd_ring->size, 8); - adapter->smb.dma = ring_header->dma + offset; - adapter->smb.smb = (u8 *)ring_header->desc + offset; return 0; err_nomem: @@ -1033,26 +1055,20 @@ err_nomem: static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) { struct atl1c_hw *hw = &adapter->hw; - struct atl1c_rfd_ring *rfd_ring = (struct atl1c_rfd_ring *) - adapter->rfd_ring; - struct atl1c_rrd_ring *rrd_ring = (struct atl1c_rrd_ring *) - adapter->rrd_ring; + struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring; struct atl1c_tpd_ring *tpd_ring = (struct atl1c_tpd_ring *) adapter->tpd_ring; - struct atl1c_cmb *cmb = (struct atl1c_cmb *) &adapter->cmb; - struct atl1c_smb *smb = (struct atl1c_smb *) &adapter->smb; - int i; - u32 data; /* TPD */ AT_WRITE_REG(hw, REG_TX_BASE_ADDR_HI, (u32)((tpd_ring[atl1c_trans_normal].dma & AT_DMA_HI_ADDR_MASK) >> 32)); /* just enable normal priority TX queue */ - AT_WRITE_REG(hw, REG_NTPD_HEAD_ADDR_LO, + AT_WRITE_REG(hw, REG_TPD_PRI0_ADDR_LO, (u32)(tpd_ring[atl1c_trans_normal].dma & AT_DMA_LO_ADDR_MASK)); - AT_WRITE_REG(hw, REG_HTPD_HEAD_ADDR_LO, + AT_WRITE_REG(hw, REG_TPD_PRI1_ADDR_LO, (u32)(tpd_ring[atl1c_trans_high].dma & AT_DMA_LO_ADDR_MASK)); AT_WRITE_REG(hw, REG_TPD_RING_SIZE, @@ -1061,31 +1077,21 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) /* RFD */ AT_WRITE_REG(hw, REG_RX_BASE_ADDR_HI, - (u32)((rfd_ring[0].dma & AT_DMA_HI_ADDR_MASK) >> 32)); - for (i = 0; i < adapter->num_rx_queues; i++) - AT_WRITE_REG(hw, atl1c_rfd_addr_lo_regs[i], - (u32)(rfd_ring[i].dma & AT_DMA_LO_ADDR_MASK)); + (u32)((rfd_ring->dma & AT_DMA_HI_ADDR_MASK) >> 32)); + AT_WRITE_REG(hw, REG_RFD0_HEAD_ADDR_LO, + (u32)(rfd_ring->dma & AT_DMA_LO_ADDR_MASK)); AT_WRITE_REG(hw, REG_RFD_RING_SIZE, - rfd_ring[0].count & RFD_RING_SIZE_MASK); + rfd_ring->count & RFD_RING_SIZE_MASK); AT_WRITE_REG(hw, REG_RX_BUF_SIZE, adapter->rx_buffer_len & RX_BUF_SIZE_MASK); /* RRD */ - for (i = 0; i < adapter->num_rx_queues; i++) - AT_WRITE_REG(hw, atl1c_rrd_addr_lo_regs[i], - (u32)(rrd_ring[i].dma & AT_DMA_LO_ADDR_MASK)); + AT_WRITE_REG(hw, REG_RRD0_HEAD_ADDR_LO, + (u32)(rrd_ring->dma & AT_DMA_LO_ADDR_MASK)); AT_WRITE_REG(hw, REG_RRD_RING_SIZE, - (rrd_ring[0].count & RRD_RING_SIZE_MASK)); - - /* CMB */ - AT_WRITE_REG(hw, REG_CMB_BASE_ADDR_LO, cmb->dma & AT_DMA_LO_ADDR_MASK); + (rrd_ring->count & RRD_RING_SIZE_MASK)); - /* SMB */ - AT_WRITE_REG(hw, REG_SMB_BASE_ADDR_HI, - (u32)((smb->dma & AT_DMA_HI_ADDR_MASK) >> 32)); - AT_WRITE_REG(hw, REG_SMB_BASE_ADDR_LO, - (u32)(smb->dma & AT_DMA_LO_ADDR_MASK)); if (hw->nic_type == athr_l2c_b) { AT_WRITE_REG(hw, REG_SRAM_RXF_LEN, 0x02a0L); AT_WRITE_REG(hw, REG_SRAM_TXF_LEN, 0x0100L); @@ -1096,13 +1102,6 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) AT_WRITE_REG(hw, REG_TXF_WATER_MARK, 0); /* TX watermark, to enter l1 state.*/ AT_WRITE_REG(hw, REG_RXD_DMA_CTRL, 0); /* RXD threshold.*/ } - if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d_2) { - /* Power Saving for L2c_B */ - AT_READ_REG(hw, REG_SERDES_LOCK, &data); - data |= SERDES_MAC_CLK_SLOWDOWN; - data |= SERDES_PYH_CLK_SLOWDOWN; - AT_WRITE_REG(hw, REG_SERDES_LOCK, data); - } /* Load all of base address above */ AT_WRITE_REG(hw, REG_LOAD_PTR, 1); } @@ -1110,32 +1109,26 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) static void atl1c_configure_tx(struct atl1c_adapter *adapter) { struct atl1c_hw *hw = &adapter->hw; - u32 dev_ctrl_data; - u32 max_pay_load; + int max_pay_load; u16 tx_offload_thresh; u32 txq_ctrl_data; - u32 max_pay_load_data; - tx_offload_thresh = MAX_TX_OFFLOAD_THRESH; + tx_offload_thresh = MAX_TSO_FRAME_SIZE; AT_WRITE_REG(hw, REG_TX_TSO_OFFLOAD_THRESH, (tx_offload_thresh >> 3) & TX_TSO_OFFLOAD_THRESH_MASK); - AT_READ_REG(hw, REG_DEVICE_CTRL, &dev_ctrl_data); - max_pay_load = (dev_ctrl_data >> DEVICE_CTRL_MAX_PAYLOAD_SHIFT) & - DEVICE_CTRL_MAX_PAYLOAD_MASK; - hw->dmaw_block = min_t(u32, max_pay_load, hw->dmaw_block); - max_pay_load = (dev_ctrl_data >> DEVICE_CTRL_MAX_RREQ_SZ_SHIFT) & - DEVICE_CTRL_MAX_RREQ_SZ_MASK; + max_pay_load = pcie_get_readrq(adapter->pdev) >> 8; hw->dmar_block = min_t(u32, max_pay_load, hw->dmar_block); - - txq_ctrl_data = (hw->tpd_burst & TXQ_NUM_TPD_BURST_MASK) << - TXQ_NUM_TPD_BURST_SHIFT; - if (hw->ctrl_flags & ATL1C_TXQ_MODE_ENHANCE) - txq_ctrl_data |= TXQ_CTRL_ENH_MODE; - max_pay_load_data = (atl1c_pay_load_size[hw->dmar_block] & - TXQ_TXF_BURST_NUM_MASK) << TXQ_TXF_BURST_NUM_SHIFT; - if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) - max_pay_load_data >>= 1; - txq_ctrl_data |= max_pay_load_data; + /* + * if BIOS had changed the dam-read-max-length to an invalid value, + * restore it to default value + */ + if (hw->dmar_block < DEVICE_CTRL_MAXRRS_MIN) { + pcie_set_readrq(adapter->pdev, 128 << DEVICE_CTRL_MAXRRS_MIN); + hw->dmar_block = DEVICE_CTRL_MAXRRS_MIN; + } + txq_ctrl_data = + hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2 ? + L2CB_TXQ_CFGV : L1C_TXQ_CFGV; AT_WRITE_REG(hw, REG_TXQ_CTRL, txq_ctrl_data); } @@ -1150,34 +1143,13 @@ static void atl1c_configure_rx(struct atl1c_adapter *adapter) if (hw->ctrl_flags & ATL1C_RX_IPV6_CHKSUM) rxq_ctrl_data |= IPV6_CHKSUM_CTRL_EN; - if (hw->rss_type == atl1c_rss_ipv4) - rxq_ctrl_data |= RSS_HASH_IPV4; - if (hw->rss_type == atl1c_rss_ipv4_tcp) - rxq_ctrl_data |= RSS_HASH_IPV4_TCP; - if (hw->rss_type == atl1c_rss_ipv6) - rxq_ctrl_data |= RSS_HASH_IPV6; - if (hw->rss_type == atl1c_rss_ipv6_tcp) - rxq_ctrl_data |= RSS_HASH_IPV6_TCP; - if (hw->rss_type != atl1c_rss_disable) - rxq_ctrl_data |= RRS_HASH_CTRL_EN; - - rxq_ctrl_data |= (hw->rss_mode & RSS_MODE_MASK) << - RSS_MODE_SHIFT; - rxq_ctrl_data |= (hw->rss_hash_bits & RSS_HASH_BITS_MASK) << - RSS_HASH_BITS_SHIFT; - if (hw->ctrl_flags & ATL1C_ASPM_CTRL_MON) - rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_1M & - ASPM_THRUPUT_LIMIT_MASK) << ASPM_THRUPUT_LIMIT_SHIFT; - - AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data); -} -static void atl1c_configure_rss(struct atl1c_adapter *adapter) -{ - struct atl1c_hw *hw = &adapter->hw; + /* aspm for gigabit */ + if (hw->nic_type != athr_l1d_2 && (hw->device_id & 1) != 0) + rxq_ctrl_data = FIELD_SETX(rxq_ctrl_data, ASPM_THRUPUT_LIMIT, + ASPM_THRUPUT_LIMIT_100M); - AT_WRITE_REG(hw, REG_IDT_TABLE, hw->indirect_tab); - AT_WRITE_REG(hw, REG_BASE_CPU_NUMBER, hw->base_cpu); + AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data); } static void atl1c_configure_dma(struct atl1c_adapter *adapter) @@ -1185,36 +1157,11 @@ static void atl1c_configure_dma(struct atl1c_adapter *adapter) struct atl1c_hw *hw = &adapter->hw; u32 dma_ctrl_data; - dma_ctrl_data = DMA_CTRL_DMAR_REQ_PRI; - if (hw->ctrl_flags & ATL1C_CMB_ENABLE) - dma_ctrl_data |= DMA_CTRL_CMB_EN; - if (hw->ctrl_flags & ATL1C_SMB_ENABLE) - dma_ctrl_data |= DMA_CTRL_SMB_EN; - else - dma_ctrl_data |= MAC_CTRL_SMB_DIS; - - switch (hw->dma_order) { - case atl1c_dma_ord_in: - dma_ctrl_data |= DMA_CTRL_DMAR_IN_ORDER; - break; - case atl1c_dma_ord_enh: - dma_ctrl_data |= DMA_CTRL_DMAR_ENH_ORDER; - break; - case atl1c_dma_ord_out: - dma_ctrl_data |= DMA_CTRL_DMAR_OUT_ORDER; - break; - default: - break; - } - - dma_ctrl_data |= (((u32)hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) - << DMA_CTRL_DMAR_BURST_LEN_SHIFT; - dma_ctrl_data |= (((u32)hw->dmaw_block) & DMA_CTRL_DMAW_BURST_LEN_MASK) - << DMA_CTRL_DMAW_BURST_LEN_SHIFT; - dma_ctrl_data |= (((u32)hw->dmar_dly_cnt) & DMA_CTRL_DMAR_DLY_CNT_MASK) - << DMA_CTRL_DMAR_DLY_CNT_SHIFT; - dma_ctrl_data |= (((u32)hw->dmaw_dly_cnt) & DMA_CTRL_DMAW_DLY_CNT_MASK) - << DMA_CTRL_DMAW_DLY_CNT_SHIFT; + dma_ctrl_data = FIELDX(DMA_CTRL_RORDER_MODE, DMA_CTRL_RORDER_MODE_OUT) | + DMA_CTRL_RREQ_PRI_DATA | + FIELDX(DMA_CTRL_RREQ_BLEN, hw->dmar_block) | + FIELDX(DMA_CTRL_WDLY_CNT, DMA_CTRL_WDLY_CNT_DEF) | + FIELDX(DMA_CTRL_RDLY_CNT, DMA_CTRL_RDLY_CNT_DEF); AT_WRITE_REG(hw, REG_DMA_CTRL, dma_ctrl_data); } @@ -1229,52 +1176,53 @@ static int atl1c_stop_mac(struct atl1c_hw *hw) u32 data; AT_READ_REG(hw, REG_RXQ_CTRL, &data); - data &= ~(RXQ1_CTRL_EN | RXQ2_CTRL_EN | - RXQ3_CTRL_EN | RXQ_CTRL_EN); + data &= ~RXQ_CTRL_EN; AT_WRITE_REG(hw, REG_RXQ_CTRL, data); AT_READ_REG(hw, REG_TXQ_CTRL, &data); data &= ~TXQ_CTRL_EN; - AT_WRITE_REG(hw, REG_TWSI_CTRL, data); + AT_WRITE_REG(hw, REG_TXQ_CTRL, data); - atl1c_wait_until_idle(hw); + atl1c_wait_until_idle(hw, IDLE_STATUS_RXQ_BUSY | IDLE_STATUS_TXQ_BUSY); AT_READ_REG(hw, REG_MAC_CTRL, &data); data &= ~(MAC_CTRL_TX_EN | MAC_CTRL_RX_EN); AT_WRITE_REG(hw, REG_MAC_CTRL, data); - return (int)atl1c_wait_until_idle(hw); -} - -static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw) -{ - u32 data; - - AT_READ_REG(hw, REG_RXQ_CTRL, &data); - switch (hw->adapter->num_rx_queues) { - case 4: - data |= (RXQ3_CTRL_EN | RXQ2_CTRL_EN | RXQ1_CTRL_EN); - break; - case 3: - data |= (RXQ2_CTRL_EN | RXQ1_CTRL_EN); - break; - case 2: - data |= RXQ1_CTRL_EN; - break; - default: - break; - } - data |= RXQ_CTRL_EN; - AT_WRITE_REG(hw, REG_RXQ_CTRL, data); + return (int)atl1c_wait_until_idle(hw, + IDLE_STATUS_TXMAC_BUSY | IDLE_STATUS_RXMAC_BUSY); } -static void atl1c_enable_tx_ctrl(struct atl1c_hw *hw) +static void atl1c_start_mac(struct atl1c_adapter *adapter) { - u32 data; + struct atl1c_hw *hw = &adapter->hw; + u32 mac, txq, rxq; + + hw->mac_duplex = adapter->link_duplex == FULL_DUPLEX ? true : false; + hw->mac_speed = adapter->link_speed == SPEED_1000 ? + atl1c_mac_speed_1000 : atl1c_mac_speed_10_100; + + AT_READ_REG(hw, REG_TXQ_CTRL, &txq); + AT_READ_REG(hw, REG_RXQ_CTRL, &rxq); + AT_READ_REG(hw, REG_MAC_CTRL, &mac); + + txq |= TXQ_CTRL_EN; + rxq |= RXQ_CTRL_EN; + mac |= MAC_CTRL_TX_EN | MAC_CTRL_TX_FLOW | + MAC_CTRL_RX_EN | MAC_CTRL_RX_FLOW | + MAC_CTRL_ADD_CRC | MAC_CTRL_PAD | + MAC_CTRL_BC_EN | MAC_CTRL_SINGLE_PAUSE_EN | + MAC_CTRL_HASH_ALG_CRC32; + if (hw->mac_duplex) + mac |= MAC_CTRL_DUPLX; + else + mac &= ~MAC_CTRL_DUPLX; + mac = FIELD_SETX(mac, MAC_CTRL_SPEED, hw->mac_speed); + mac = FIELD_SETX(mac, MAC_CTRL_PRMLEN, hw->preamble_len); - AT_READ_REG(hw, REG_TXQ_CTRL, &data); - data |= TXQ_CTRL_EN; - AT_WRITE_REG(hw, REG_TXQ_CTRL, data); + AT_WRITE_REG(hw, REG_TXQ_CTRL, txq); + AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq); + AT_WRITE_REG(hw, REG_MAC_CTRL, mac); } /* @@ -1284,12 +1232,9 @@ static void atl1c_enable_tx_ctrl(struct atl1c_hw *hw) */ 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 master_ctrl_data = 0; - - AT_WRITE_REG(hw, REG_IMR, 0); - AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT); + u32 ctrl_data = 0; atl1c_stop_mac(hw); /* @@ -1298,194 +1243,148 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) * the current PCI configuration. The global reset bit is self- * clearing, and should clear within a microsecond. */ - AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data); - master_ctrl_data |= MASTER_CTRL_OOB_DIS_OFF; - AT_WRITE_REGW(hw, REG_MASTER_CTRL, ((master_ctrl_data | MASTER_CTRL_SOFT_RST) - & 0xFFFF)); + AT_READ_REG(hw, REG_MASTER_CTRL, &ctrl_data); + ctrl_data |= MASTER_CTRL_OOB_DIS; + AT_WRITE_REG(hw, REG_MASTER_CTRL, ctrl_data | MASTER_CTRL_SOFT_RST); AT_WRITE_FLUSH(hw); msleep(10); /* Wait at least 10ms for All module to be Idle */ - if (atl1c_wait_until_idle(hw)) { + if (atl1c_wait_until_idle(hw, IDLE_STATUS_MASK)) { dev_err(&pdev->dev, "MAC state machine can't be idle since" " disabled for 10ms second\n"); return -1; } + AT_WRITE_REG(hw, REG_MASTER_CTRL, ctrl_data); + + /* driver control speed/duplex */ + AT_READ_REG(hw, REG_MAC_CTRL, &ctrl_data); + AT_WRITE_REG(hw, REG_MAC_CTRL, ctrl_data | MAC_CTRL_SPEED_MODE_SW); + + /* clk switch setting */ + AT_READ_REG(hw, REG_SERDES, &ctrl_data); + switch (hw->nic_type) { + case athr_l2c_b: + ctrl_data &= ~(SERDES_PHY_CLK_SLOWDOWN | + SERDES_MAC_CLK_SLOWDOWN); + AT_WRITE_REG(hw, REG_SERDES, ctrl_data); + break; + case athr_l2c_b2: + case athr_l1d_2: + ctrl_data |= SERDES_PHY_CLK_SLOWDOWN | SERDES_MAC_CLK_SLOWDOWN; + AT_WRITE_REG(hw, REG_SERDES, ctrl_data); + break; + default: + break; + } + return 0; } static void atl1c_disable_l0s_l1(struct atl1c_hw *hw) { - u32 pm_ctrl_data; + u16 ctrl_flags = hw->ctrl_flags; - AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data); - pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK << - PM_CTRL_L1_ENTRY_TIMER_SHIFT); - pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1; - pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; - pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; - pm_ctrl_data &= ~PM_CTRL_MAC_ASPM_CHK; - pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1; - - pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN; - pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN; - pm_ctrl_data |= PM_CTRL_SERDES_L1_EN; - AT_WRITE_REG(hw, REG_PM_CTRL, pm_ctrl_data); + hw->ctrl_flags &= ~(ATL1C_ASPM_L0S_SUPPORT | ATL1C_ASPM_L1_SUPPORT); + atl1c_set_aspm(hw, SPEED_0); + hw->ctrl_flags = ctrl_flags; } /* * Set ASPM state. * Enable/disable L0s/L1 depend on link state. */ -static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup) +static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed) { u32 pm_ctrl_data; - u32 link_ctrl_data; - u32 link_l1_timer = 0xF; + u32 link_l1_timer; 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_ASPM_L1_EN | + PM_CTRL_ASPM_L0S_EN | + PM_CTRL_MAC_ASPM_CHK); + /* L1 timer */ + if (hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) { + pm_ctrl_data &= ~PMCTRL_TXL1_AFTER_L0S; + link_l1_timer = + link_speed == SPEED_1000 || link_speed == SPEED_100 ? + L1D_PMCTRL_L1_ENTRY_TM_16US : 1; + pm_ctrl_data = FIELD_SETX(pm_ctrl_data, + L1D_PMCTRL_L1_ENTRY_TM, link_l1_timer); + } else { + link_l1_timer = hw->nic_type == athr_l2c_b ? + L2CB1_PM_CTRL_L1_ENTRY_TM : L1C_PM_CTRL_L1_ENTRY_TM; + if (link_speed != SPEED_1000 && link_speed != SPEED_100) + link_l1_timer = 1; + pm_ctrl_data = FIELD_SETX(pm_ctrl_data, + PM_CTRL_L1_ENTRY_TIMER, link_l1_timer); + } - 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 |= AT_LCKDET_TIMER << PM_CTRL_LCKDET_TIMER_SHIFT; + /* L0S/L1 enable */ + 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; + /* l2cb & l1d & l2cb2 & l1d2 */ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d || - hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) { - 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_RCVR_WT_TIMER; - pm_ctrl_data &= ~(PM_CTRL_PM_REQ_TIMER_MASK << - PM_CTRL_PM_REQ_TIMER_SHIFT); - pm_ctrl_data |= AT_ASPM_L1_TIMER << - PM_CTRL_PM_REQ_TIMER_SHIFT; - 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; - } - pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK; - if (linkup) { - 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 || hw->nic_type == athr_l1d_2) { - 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_l2c_b) - link_l1_timer = 7; - else if (hw->nic_type == athr_l2c_b2 || - hw->nic_type == athr_l1d_2) - link_l1_timer = 4; - pm_ctrl_data |= link_l1_timer << - 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; + hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) { + pm_ctrl_data = FIELD_SETX(pm_ctrl_data, + PM_CTRL_PM_REQ_TIMER, PM_CTRL_PM_REQ_TO_DEF); + pm_ctrl_data |= PM_CTRL_RCVR_WT_TIMER | + PM_CTRL_SERDES_PD_EX_L1 | + PM_CTRL_CLK_SWH_L1; + pm_ctrl_data &= ~(PM_CTRL_SERDES_L1_EN | + PM_CTRL_SERDES_PLL_L1_EN | + PM_CTRL_SERDES_BUFS_RX_L1_EN | + PM_CTRL_SA_DLY_EN | + PM_CTRL_HOTRST); + /* disable l0s if link down or l2cb */ + if (link_speed == SPEED_0 || hw->nic_type == athr_l2c_b) pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; - pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; - + } else { /* l1c */ + pm_ctrl_data = + FIELD_SETX(pm_ctrl_data, PM_CTRL_L1_ENTRY_TIMER, 0); + if (link_speed != SPEED_0) { + pm_ctrl_data |= PM_CTRL_SERDES_L1_EN | + PM_CTRL_SERDES_PLL_L1_EN | + PM_CTRL_SERDES_BUFS_RX_L1_EN; + pm_ctrl_data &= ~(PM_CTRL_SERDES_PD_EX_L1 | + PM_CTRL_CLK_SWH_L1 | + PM_CTRL_ASPM_L0S_EN | + PM_CTRL_ASPM_L1_EN); + } else { /* link down */ + pm_ctrl_data |= PM_CTRL_CLK_SWH_L1; + pm_ctrl_data &= ~(PM_CTRL_SERDES_L1_EN | + PM_CTRL_SERDES_PLL_L1_EN | + PM_CTRL_SERDES_BUFS_RX_L1_EN | + PM_CTRL_ASPM_L0S_EN); } - } else { - pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN; - pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; - pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN; - pm_ctrl_data |= PM_CTRL_CLK_SWH_L1; - - if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT) - pm_ctrl_data |= PM_CTRL_ASPM_L1_EN; - else - pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; } AT_WRITE_REG(hw, REG_PM_CTRL, pm_ctrl_data); return; } -static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter) -{ - struct atl1c_hw *hw = &adapter->hw; - struct net_device *netdev = adapter->netdev; - u32 mac_ctrl_data; - - mac_ctrl_data = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN; - mac_ctrl_data |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); - - if (adapter->link_duplex == FULL_DUPLEX) { - hw->mac_duplex = true; - mac_ctrl_data |= MAC_CTRL_DUPLX; - } - - if (adapter->link_speed == SPEED_1000) - hw->mac_speed = atl1c_mac_speed_1000; - else - hw->mac_speed = atl1c_mac_speed_10_100; - - mac_ctrl_data |= (hw->mac_speed & MAC_CTRL_SPEED_MASK) << - MAC_CTRL_SPEED_SHIFT; - - mac_ctrl_data |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); - mac_ctrl_data |= ((hw->preamble_len & MAC_CTRL_PRMLEN_MASK) << - MAC_CTRL_PRMLEN_SHIFT); - - __atl1c_vlan_mode(netdev->features, &mac_ctrl_data); - - mac_ctrl_data |= MAC_CTRL_BC_EN; - if (netdev->flags & IFF_PROMISC) - mac_ctrl_data |= MAC_CTRL_PROMIS_EN; - if (netdev->flags & IFF_ALLMULTI) - 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 || - hw->nic_type == athr_l1d_2) { - 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); -} - -/* +/** * 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; u32 intr_modrt_data; u32 data; + AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data); + master_ctrl_data &= ~(MASTER_CTRL_TX_ITIMER_EN | + MASTER_CTRL_RX_ITIMER_EN | + MASTER_CTRL_INT_RDCLR); /* clear interrupt status */ AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF); /* Clear any WOL status */ @@ -1524,30 +1423,39 @@ static int atl1c_configure(struct atl1c_adapter *adapter) master_ctrl_data |= MASTER_CTRL_SA_TIMER_EN; AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data); - if (hw->ctrl_flags & ATL1C_CMB_ENABLE) { - AT_WRITE_REG(hw, REG_CMB_TPD_THRESH, - hw->cmb_tpd & CMB_TPD_THRESH_MASK); - AT_WRITE_REG(hw, REG_CMB_TX_TIMER, - hw->cmb_tx_timer & CMB_TX_TIMER_MASK); - } + AT_WRITE_REG(hw, REG_SMB_STAT_TIMER, + hw->smb_timer & SMB_STAT_TIMER_MASK); - if (hw->ctrl_flags & ATL1C_SMB_ENABLE) - AT_WRITE_REG(hw, REG_SMB_STAT_TIMER, - hw->smb_timer & SMB_STAT_TIMER_MASK); /* set MTU */ AT_WRITE_REG(hw, REG_MTU, hw->max_frame_size + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); - /* HDS, disable */ - AT_WRITE_REG(hw, REG_HDS_CTRL, 0); atl1c_configure_tx(adapter); atl1c_configure_rx(adapter); - atl1c_configure_rss(adapter); atl1c_configure_dma(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; @@ -1574,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 * @@ -1588,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; } @@ -1628,26 +1545,20 @@ 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); u16 hw_next_to_clean; - u16 shift; - u32 data; + u16 reg; - if (type == atl1c_trans_high) - shift = MB_HTPD_CONS_IDX_SHIFT; - else - shift = MB_NTPD_CONS_IDX_SHIFT; + reg = type == atl1c_trans_high ? REG_TPD_PRI1_CIDX : REG_TPD_PRI0_CIDX; - AT_READ_REG(&adapter->hw, REG_MB_PRIO_CONS_IDX, &data); - hw_next_to_clean = (data >> shift) & MB_PRIO_PROD_IDX_MASK; + AT_READ_REGW(&adapter->hw, reg, &hw_next_to_clean); 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); @@ -1661,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) { @@ -1710,7 +1620,7 @@ static irqreturn_t atl1c_intr(int irq, void *data) "atl1c hardware error (status = 0x%x)\n", status & ISR_ERROR); /* reset MAC */ - adapter->work_event |= ATL1C_WORK_EVENT_RESET; + set_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event); schedule_work(&adapter->common_task); return IRQ_HANDLED; } @@ -1745,9 +1655,38 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter, skb_checksum_none_assert(skb); } -static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid) +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[ringid]; + struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; struct pci_dev *pdev = adapter->pdev; struct atl1c_buffer *buffer_info, *next_info; struct sk_buff *skb; @@ -1755,6 +1694,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid 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) @@ -1765,7 +1705,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid while (next_info->flags & ATL1C_BUFFER_FREE) { rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use); - skb = dev_alloc_skb(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"); @@ -1781,9 +1721,18 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid 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); @@ -1799,7 +1748,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid /* TODO: update mailbox here */ wmb(); rfd_ring->next_to_use = rfd_next_to_use; - AT_WRITE_REG(&adapter->hw, atl1c_rfd_prod_idx_regs[ringid], + AT_WRITE_REG(&adapter->hw, REG_MB_RFD0_PROD_IDX, rfd_ring->next_to_use & MB_RFDX_PROD_IDX_MASK); } @@ -1838,7 +1787,7 @@ static void atl1c_clean_rfd(struct atl1c_rfd_ring *rfd_ring, rfd_ring->next_to_clean = rfd_index; } -static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que, +static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, int *work_done, int work_to_do) { u16 rfd_num, rfd_index; @@ -1846,8 +1795,8 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que, u16 length; struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; - struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring[que]; - struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring[que]; + struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring; struct sk_buff *skb; struct atl1c_recv_ret_status *rrs; struct atl1c_buffer *buffer_info; @@ -1905,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); @@ -1913,12 +1862,11 @@ rrs_checked: count++; } if (count) - atl1c_alloc_rx_buffer(adapter, que); + 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) { @@ -1930,7 +1878,7 @@ static int atl1c_clean(struct napi_struct *napi, int budget) if (!netif_carrier_ok(adapter->netdev)) goto quit_polling; /* just enable one RXQ */ - atl1c_clean_rx_irq(adapter, 0, &work_done, budget); + atl1c_clean_rx_irq(adapter, &work_done, budget); if (work_done < budget) { quit_polling: @@ -2025,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) { @@ -2119,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) { @@ -2144,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); @@ -2166,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); @@ -2187,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); @@ -2199,29 +2179,23 @@ 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, struct atl1c_tpd_desc *tpd, enum atl1c_trans_queue type) { struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type]; - u32 prod_data; + u16 reg; - AT_READ_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, &prod_data); - switch (type) { - case atl1c_trans_high: - prod_data &= 0xFFFF0000; - prod_data |= tpd_ring->next_to_use & 0xFFFF; - break; - case atl1c_trans_normal: - prod_data &= 0x0000FFFF; - prod_data |= (tpd_ring->next_to_use & 0xFFFF) << 16; - break; - default: - break; - } - wmb(); - AT_WRITE_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, prod_data); + reg = type == atl1c_trans_high ? REG_TPD_PRI1_PIDX : REG_TPD_PRI0_PIDX; + AT_WRITE_REGW(&adapter->hw, reg, tpd_ring->next_to_use); } static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, @@ -2244,10 +2218,6 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, dev_info(&adapter->pdev->dev, "tx locked\n"); return NETDEV_TX_LOCKED; } - if (skb->mark == 0x01) - type = atl1c_trans_high; - else - type = atl1c_trans_normal; if (atl1c_tpd_avail(adapter, type) < tpd_req) { /* no enough descriptor, just stop queue */ @@ -2278,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; } @@ -2310,8 +2288,7 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter) "Unable to allocate MSI interrupt Error: %d\n", err); adapter->have_msi = false; - } else - netdev->irq = pdev->irq; + } if (!adapter->have_msi) flags |= IRQF_SHARED; @@ -2331,44 +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; - int i; netif_carrier_off(netdev); - atl1c_init_ring_ptrs(adapter); - atl1c_set_multi(netdev); - atl1c_restore_vlan(adapter); - - for (i = 0; i < adapter->num_rx_queues; i++) { - num = atl1c_alloc_rx_buffer(adapter, i); - 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; } @@ -2386,18 +2357,18 @@ static void atl1c_down(struct atl1c_adapter *adapter) napi_disable(&adapter->napi); atl1c_irq_disable(adapter); atl1c_free_irq(adapter); + /* disable ASPM if device inactive */ + atl1c_disable_l0s_l1(&adapter->hw); /* reset MAC to disable all RX/TX */ atl1c_reset_mac(&adapter->hw); msleep(1); 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 * @@ -2427,13 +2398,6 @@ static int atl1c_open(struct net_device *netdev) if (unlikely(err)) goto err_up; - if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) { - u32 phy_data; - - AT_READ_REG(&adapter->hw, REG_MDIO_CTRL, &phy_data); - phy_data |= MDIO_AP_EN; - AT_WRITE_REG(&adapter->hw, REG_MDIO_CTRL, phy_data); - } return 0; err_up: @@ -2443,7 +2407,7 @@ err_up: return err; } -/* +/** * atl1c_close - Disables a network interface * @netdev: network interface device structure * @@ -2459,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; @@ -2470,10 +2436,6 @@ static int atl1c_suspend(struct device *dev) struct net_device *netdev = pci_get_drvdata(pdev); struct atl1c_adapter *adapter = netdev_priv(netdev); struct atl1c_hw *hw = &adapter->hw; - u32 mac_ctrl_data = 0; - u32 master_ctrl_data = 0; - u32 wol_ctrl_data = 0; - u16 mii_intr_status_data = 0; u32 wufc = adapter->wol; atl1c_disable_l0s_l1(hw); @@ -2484,75 +2446,10 @@ static int atl1c_suspend(struct device *dev) netif_device_detach(netdev); if (wufc) - if (atl1c_phy_power_saving(hw) != 0) + if (atl1c_phy_to_ps_link(hw) != 0) dev_dbg(&pdev->dev, "phy power saving failed"); - AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data); - AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl_data); - - master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS; - mac_ctrl_data &= ~(MAC_CTRL_PRMLEN_MASK << MAC_CTRL_PRMLEN_SHIFT); - mac_ctrl_data |= (((u32)adapter->hw.preamble_len & - MAC_CTRL_PRMLEN_MASK) << - MAC_CTRL_PRMLEN_SHIFT); - mac_ctrl_data &= ~(MAC_CTRL_SPEED_MASK << MAC_CTRL_SPEED_SHIFT); - mac_ctrl_data &= ~MAC_CTRL_DUPLX; - - if (wufc) { - mac_ctrl_data |= MAC_CTRL_RX_EN; - if (adapter->link_speed == SPEED_1000 || - adapter->link_speed == SPEED_0) { - mac_ctrl_data |= atl1c_mac_speed_1000 << - MAC_CTRL_SPEED_SHIFT; - mac_ctrl_data |= MAC_CTRL_DUPLX; - } else - mac_ctrl_data |= atl1c_mac_speed_10_100 << - MAC_CTRL_SPEED_SHIFT; - - if (adapter->link_duplex == DUPLEX_FULL) - mac_ctrl_data |= MAC_CTRL_DUPLX; - - /* turn on magic packet wol */ - if (wufc & AT_WUFC_MAG) - wol_ctrl_data |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN; - - if (wufc & AT_WUFC_LNKC) { - wol_ctrl_data |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN; - /* only link up can wake up */ - if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) { - dev_dbg(&pdev->dev, "%s: read write phy " - "register failed.\n", - atl1c_driver_name); - } - } - /* clear phy interrupt */ - atl1c_read_phy_reg(hw, MII_ISR, &mii_intr_status_data); - /* Config MAC Ctrl register */ - __atl1c_vlan_mode(netdev->features, &mac_ctrl_data); - - /* magic packet maybe Broadcast&multicast&Unicast frame */ - if (wufc & AT_WUFC_MAG) - mac_ctrl_data |= MAC_CTRL_BC_EN; - - dev_dbg(&pdev->dev, - "%s: suspend MAC=0x%x\n", - atl1c_driver_name, mac_ctrl_data); - AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data); - AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data); - AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); - - AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT | - GPHY_CTRL_EXT_RESET); - } else { - AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_POWER_SAVING); - master_ctrl_data |= MASTER_CTRL_CLK_SEL_DIS; - mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT; - mac_ctrl_data |= MAC_CTRL_DUPLX; - AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data); - AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); - AT_WRITE_REG(hw, REG_WOL_CTRL, 0); - hw->phy_configured = false; /* re-init PHY when resume */ - } + atl1c_power_saving(hw, wufc); return 0; } @@ -2565,8 +2462,7 @@ static int atl1c_resume(struct device *dev) struct atl1c_adapter *adapter = netdev_priv(netdev); AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0); - atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE | - ATL1C_PCIE_PHY_RESET); + atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE); atl1c_phy_reset(&adapter->hw); atl1c_reset_mac(&adapter->hw); @@ -2619,23 +2515,22 @@ static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev) SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); - netdev->irq = pdev->irq; netdev->netdev_ops = &atl1c_netdev_ops; netdev->watchdog_timeo = AT_TX_WATCHDOG; 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 @@ -2646,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; @@ -2689,7 +2583,6 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, netdev = alloc_etherdev(sizeof(struct atl1c_adapter)); if (netdev == NULL) { err = -ENOMEM; - dev_err(&pdev->dev, "etherdev alloc failed\n"); goto err_alloc_etherdev; } @@ -2710,14 +2603,13 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "cannot map device registers\n"); goto err_ioremap; } - netdev->base_addr = (unsigned long)adapter->hw.hw_addr; /* init mii data */ adapter->mii.dev = netdev; adapter->mii.mdio_read = atl1c_mdio_read; adapter->mii.mdio_write = atl1c_mdio_write; adapter->mii.phy_id_mask = 0x1f; - adapter->mii.reg_num_mask = MDIO_REG_ADDR_MASK; + adapter->mii.reg_num_mask = MDIO_CTRL_REG_MASK; netif_napi_add(netdev, &adapter->napi, atl1c_clean, 64); setup_timer(&adapter->phy_config_timer, atl1c_phy_config, (unsigned long)adapter); @@ -2727,8 +2619,7 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "net device private data init failed\n"); goto err_sw_init; } - atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE | - ATL1C_PCIE_PHY_RESET); + atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE); /* Init GPHY as early as possible due to power saving issue */ atl1c_phy_reset(&adapter->hw); @@ -2746,18 +2637,16 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, err = -EIO; goto err_reset; } - if (atl1c_read_mac_addr(&adapter->hw) != 0) { - err = -EIO; - dev_err(&pdev->dev, "get mac address failed\n"); - goto err_eeprom; + 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; } 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); @@ -2774,7 +2663,6 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, err_reset: err_register: err_sw_init: -err_eeprom: iounmap(adapter->hw.hw_addr); err_init_netdev: err_ioremap: @@ -2787,7 +2675,7 @@ err_dma: return err; } -/* +/** * atl1c_remove - Device Removal Routine * @pdev: PCI device information struct * @@ -2796,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); @@ -2811,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 @@ -2839,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 * @@ -2867,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 * @@ -2892,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, @@ -2904,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); diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e.h b/drivers/net/ethernet/atheros/atl1e/atl1e.h index 829b5ad71d0..0212dac7e23 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e.h +++ b/drivers/net/ethernet/atheros/atl1e/atl1e.h @@ -23,7 +23,6 @@ #ifndef _ATL1E_H_ #define _ATL1E_H_ -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/types.h> #include <linux/errno.h> @@ -186,7 +185,7 @@ struct atl1e_tpd_desc { /* how about 0x2000 */ #define MAX_TX_BUF_LEN 0x2000 #define MAX_TX_BUF_SHIFT 13 -/*#define MAX_TX_BUF_LEN 0x3000 */ +#define MAX_TSO_SEG_SIZE 0x3c00 /* rrs word 1 bit 0:31 */ #define RRS_RX_CSUM_MASK 0xFFFF @@ -438,7 +437,6 @@ struct atl1e_adapter { struct atl1e_hw hw; struct atl1e_hw_stats hw_stats; - bool have_msi; u32 wol; u16 link_speed; u16 link_duplex; @@ -500,10 +498,10 @@ struct atl1e_adapter { extern char atl1e_driver_name[]; extern char atl1e_driver_version[]; -extern void atl1e_check_options(struct atl1e_adapter *adapter); -extern int atl1e_up(struct atl1e_adapter *adapter); -extern void atl1e_down(struct atl1e_adapter *adapter); -extern void atl1e_reinit_locked(struct atl1e_adapter *adapter); -extern s32 atl1e_reset_hw(struct atl1e_hw *hw); -extern void atl1e_set_ethtool_ops(struct net_device *netdev); +void atl1e_check_options(struct atl1e_adapter *adapter); +int atl1e_up(struct atl1e_adapter *adapter); +void atl1e_down(struct atl1e_adapter *adapter); +void atl1e_reinit_locked(struct atl1e_adapter *adapter); +s32 atl1e_reset_hw(struct atl1e_hw *hw); +void atl1e_set_ethtool_ops(struct net_device *netdev); #endif /* _ATL1_E_H_ */ diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c b/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c index 6e61f9f9ebb..1be072f4afc 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c @@ -57,8 +57,8 @@ static int atl1e_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; @@ -268,7 +268,7 @@ static int atl1e_set_eeprom(struct net_device *netdev, if (eeprom_buff == NULL) return -ENOMEM; - ptr = (u32 *)eeprom_buff; + ptr = eeprom_buff; if (eeprom->offset & 3) { /* need read/modify/write of first changed EEPROM word */ @@ -388,5 +388,5 @@ static const struct ethtool_ops atl1e_ethtool_ops = { void atl1e_set_ethtool_ops(struct net_device *netdev) { - SET_ETHTOOL_OPS(netdev, &atl1e_ethtool_ops); + netdev->ethtool_ops = &atl1e_ethtool_ops; } diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c index c915c087381..4345332533a 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c @@ -89,7 +89,7 @@ static const u16 atl1e_pay_load_size[] = { 128, 256, 512, 1024, 2048, 4096, }; -/* +/** * atl1e_irq_enable - Enable default interrupt generation settings * @adapter: board private structure */ @@ -102,7 +102,7 @@ static inline void atl1e_irq_enable(struct atl1e_adapter *adapter) } } -/* +/** * atl1e_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure */ @@ -114,7 +114,7 @@ static inline void atl1e_irq_disable(struct atl1e_adapter *adapter) synchronize_irq(adapter->pdev->irq); } -/* +/** * atl1e_irq_reset - reset interrupt confiure on the NIC * @adapter: board private structure */ @@ -126,7 +126,7 @@ static inline void atl1e_irq_reset(struct atl1e_adapter *adapter) AT_WRITE_FLUSH(&adapter->hw); } -/* +/** * atl1e_phy_config - Timer Call-back * @data: pointer to netdev cast into an unsigned long */ @@ -210,7 +210,7 @@ static int atl1e_check_link(struct atl1e_adapter *adapter) return 0; } -/* +/** * atl1e_link_chg_task - deal with link change event Out of interrupt context * @netdev: network interface device structure */ @@ -259,7 +259,7 @@ static void atl1e_cancel_work(struct atl1e_adapter *adapter) cancel_work_sync(&adapter->link_chg_task); } -/* +/** * atl1e_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure */ @@ -271,7 +271,7 @@ static void atl1e_tx_timeout(struct net_device *netdev) schedule_work(&adapter->reset_task); } -/* +/** * atl1e_set_multi - Multicast and Promiscuous mode set * @netdev: network interface device structure * @@ -313,9 +313,37 @@ static void atl1e_set_multi(struct net_device *netdev) } } +static void __atl1e_rx_mode(netdev_features_t features, u32 *mac_ctrl_data) +{ + + if (features & NETIF_F_RXALL) { + /* enable RX of ALL frames */ + *mac_ctrl_data |= MAC_CTRL_DBG; + } else { + /* disable RX of ALL frames */ + *mac_ctrl_data &= ~MAC_CTRL_DBG; + } +} + +static void atl1e_rx_mode(struct net_device *netdev, + netdev_features_t features) +{ + struct atl1e_adapter *adapter = netdev_priv(netdev); + u32 mac_ctrl_data = 0; + + netdev_dbg(adapter->netdev, "%s\n", __func__); + + atl1e_irq_disable(adapter); + mac_ctrl_data = AT_READ_REG(&adapter->hw, REG_MAC_CTRL); + __atl1e_rx_mode(features, &mac_ctrl_data); + AT_WRITE_REG(&adapter->hw, REG_MAC_CTRL, mac_ctrl_data); + atl1e_irq_enable(adapter); +} + + static void __atl1e_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 { @@ -345,7 +373,7 @@ static void atl1e_restore_vlan(struct atl1e_adapter *adapter) atl1e_vlan_mode(adapter->netdev, adapter->netdev->features); } -/* +/** * atl1e_set_mac - Change the Ethernet Address of the NIC * @netdev: network interface device structure * @p: pointer to an address structure @@ -378,10 +406,10 @@ static netdev_features_t atl1e_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; return features; } @@ -391,13 +419,17 @@ static int atl1e_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) atl1e_vlan_mode(netdev, features); + if (changed & NETIF_F_RXALL) + atl1e_rx_mode(netdev, features); + + return 0; } -/* +/** * atl1e_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure * @new_mtu: new value for maximum frame size @@ -449,12 +481,6 @@ static void atl1e_mdio_write(struct net_device *netdev, int phy_id, atl1e_write_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, val); } -/* - * atl1e_mii_ioctl - - * @netdev: - * @ifreq: - * @cmd: - */ static int atl1e_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { @@ -505,12 +531,6 @@ out: } -/* - * atl1e_ioctl - - * @netdev: - * @ifreq: - * @cmd: - */ static int atl1e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { switch (cmd) { @@ -541,17 +561,17 @@ static void atl1e_setup_pcicmd(struct pci_dev *pdev) msleep(1); } -/* +/** * atl1e_alloc_queues - Allocate memory for all rings * @adapter: board private structure to initialize * */ -static int __devinit atl1e_alloc_queues(struct atl1e_adapter *adapter) +static int atl1e_alloc_queues(struct atl1e_adapter *adapter) { return 0; } -/* +/** * atl1e_sw_init - Initialize general software structures (struct atl1e_adapter) * @adapter: board private structure to initialize * @@ -559,7 +579,7 @@ static int __devinit atl1e_alloc_queues(struct atl1e_adapter *adapter) * Fields are initialized based on PCI device information and * OS network device settings (MTU size). */ -static int __devinit atl1e_sw_init(struct atl1e_adapter *adapter) +static int atl1e_sw_init(struct atl1e_adapter *adapter) { struct atl1e_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; @@ -635,14 +655,13 @@ static int __devinit atl1e_sw_init(struct atl1e_adapter *adapter) return 0; } -/* +/** * atl1e_clean_tx_ring - Free Tx-skb * @adapter: board private structure */ static void atl1e_clean_tx_ring(struct atl1e_adapter *adapter) { - struct atl1e_tx_ring *tx_ring = (struct atl1e_tx_ring *) - &adapter->tx_ring; + struct atl1e_tx_ring *tx_ring = &adapter->tx_ring; struct atl1e_tx_buffer *tx_buffer = NULL; struct pci_dev *pdev = adapter->pdev; u16 index, ring_count; @@ -679,14 +698,14 @@ static void atl1e_clean_tx_ring(struct atl1e_adapter *adapter) ring_count); } -/* +/** * atl1e_clean_rx_ring - Free rx-reservation skbs * @adapter: board private structure */ static void atl1e_clean_rx_ring(struct atl1e_adapter *adapter) { struct atl1e_rx_ring *rx_ring = - (struct atl1e_rx_ring *)&adapter->rx_ring; + &adapter->rx_ring; struct atl1e_rx_page_desc *rx_page_desc = rx_ring->rx_page_desc; u16 i, j; @@ -762,7 +781,7 @@ static void atl1e_init_ring_ptrs(struct atl1e_adapter *adapter) } } -/* +/** * atl1e_free_ring_resources - Free Tx / RX descriptor Resources * @adapter: board private structure * @@ -787,7 +806,7 @@ static void atl1e_free_ring_resources(struct atl1e_adapter *adapter) } } -/* +/** * atl1e_setup_mem_resources - allocate Tx / RX descriptor resources * @adapter: board private structure * @@ -832,8 +851,6 @@ static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter) size = sizeof(struct atl1e_tx_buffer) * (tx_ring->count); tx_ring->tx_buffer = kzalloc(size, GFP_KERNEL); if (tx_ring->tx_buffer == NULL) { - netdev_err(adapter->netdev, "kzalloc failed, size = D%d\n", - size); err = -ENOMEM; goto failed; } @@ -884,14 +901,12 @@ failed: return err; } -static inline void atl1e_configure_des_ring(const struct atl1e_adapter *adapter) +static inline void atl1e_configure_des_ring(struct atl1e_adapter *adapter) { - struct atl1e_hw *hw = (struct atl1e_hw *)&adapter->hw; - struct atl1e_rx_ring *rx_ring = - (struct atl1e_rx_ring *)&adapter->rx_ring; - struct atl1e_tx_ring *tx_ring = - (struct atl1e_tx_ring *)&adapter->tx_ring; + struct atl1e_hw *hw = &adapter->hw; + struct atl1e_rx_ring *rx_ring = &adapter->rx_ring; + struct atl1e_tx_ring *tx_ring = &adapter->tx_ring; struct atl1e_rx_page_desc *rx_page_desc = NULL; int i, j; @@ -932,7 +947,7 @@ static inline void atl1e_configure_des_ring(const struct atl1e_adapter *adapter) static inline void atl1e_configure_tx(struct atl1e_adapter *adapter) { - struct atl1e_hw *hw = (struct atl1e_hw *)&adapter->hw; + struct atl1e_hw *hw = &adapter->hw; u32 dev_ctrl_data = 0; u32 max_pay_load = 0; u32 jumbo_thresh = 0; @@ -975,7 +990,7 @@ static inline void atl1e_configure_tx(struct atl1e_adapter *adapter) static inline void atl1e_configure_rx(struct atl1e_adapter *adapter) { - struct atl1e_hw *hw = (struct atl1e_hw *)&adapter->hw; + struct atl1e_hw *hw = &adapter->hw; u32 rxf_len = 0; u32 rxf_low = 0; u32 rxf_high = 0; @@ -1074,11 +1089,12 @@ static void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter) value |= MAC_CTRL_PROMIS_EN; if (netdev->flags & IFF_ALLMULTI) value |= MAC_CTRL_MC_ALL_EN; - + if (netdev->features & NETIF_F_RXALL) + value |= MAC_CTRL_DBG; AT_WRITE_REG(hw, REG_MAC_CTRL, value); } -/* +/** * atl1e_configure - Configure Transmit&Receive Unit after Reset * @adapter: board private structure * @@ -1148,7 +1164,7 @@ static int atl1e_configure(struct atl1e_adapter *adapter) return 0; } -/* +/** * atl1e_get_stats - Get System Network Statistics * @netdev: network interface device structure * @@ -1161,32 +1177,40 @@ static struct net_device_stats *atl1e_get_stats(struct net_device *netdev) struct atl1e_hw_stats *hw_stats = &adapter->hw_stats; struct net_device_stats *net_stats = &netdev->stats; - 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; + 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_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; 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; } @@ -1224,8 +1248,7 @@ static inline void atl1e_clear_phy_int(struct atl1e_adapter *adapter) static bool atl1e_clean_tx_irq(struct atl1e_adapter *adapter) { - struct atl1e_tx_ring *tx_ring = (struct atl1e_tx_ring *) - &adapter->tx_ring; + struct atl1e_tx_ring *tx_ring = &adapter->tx_ring; struct atl1e_tx_buffer *tx_buffer = NULL; u16 hw_next_to_clean = AT_READ_REGW(&adapter->hw, REG_TPD_CONS_IDX); u16 next_to_clean = atomic_read(&tx_ring->next_to_clean); @@ -1261,11 +1284,10 @@ static bool atl1e_clean_tx_irq(struct atl1e_adapter *adapter) return true; } -/* +/** * atl1e_intr - Interrupt Handler * @irq: interrupt number * @data: pointer to a network interface device structure - * @pt_regs: CPU registers structure */ static irqreturn_t atl1e_intr(int irq, void *data) { @@ -1384,15 +1406,14 @@ static struct atl1e_rx_page *atl1e_get_rx_page(struct atl1e_adapter *adapter, (struct atl1e_rx_page_desc *) adapter->rx_ring.rx_page_desc; u8 rx_using = rx_page_desc[que].rx_using; - return (struct atl1e_rx_page *)&(rx_page_desc[que].rx_page[rx_using]); + return &(rx_page_desc[que].rx_page[rx_using]); } static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, int *work_done, int work_to_do) { struct net_device *netdev = adapter->netdev; - struct atl1e_rx_ring *rx_ring = (struct atl1e_rx_ring *) - &adapter->rx_ring; + struct atl1e_rx_ring *rx_ring = &adapter->rx_ring; struct atl1e_rx_page_desc *rx_page_desc = (struct atl1e_rx_page_desc *) rx_ring->rx_page_desc; struct sk_buff *skb = NULL; @@ -1425,7 +1446,8 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, rx_page_desc[que].rx_nxseq++; /* error packet */ - if (prrs->pkt_flag & RRS_IS_ERR_FRAME) { + if ((prrs->pkt_flag & RRS_IS_ERR_FRAME) && + !(netdev->features & NETIF_F_RXALL)) { if (prrs->err_flag & (RRS_ERR_BAD_CRC | RRS_ERR_DRIBBLE | RRS_ERR_CODE | RRS_ERR_TRUNC)) { @@ -1438,13 +1460,14 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, } packet_size = ((prrs->word1 >> RRS_PKT_SIZE_SHIFT) & - RRS_PKT_SIZE_MASK) - 4; /* CRC */ + RRS_PKT_SIZE_MASK); + if (likely(!(netdev->features & NETIF_F_RXFCS))) + packet_size -= 4; /* CRC */ + skb = netdev_alloc_skb_ip_align(netdev, packet_size); - if (skb == NULL) { - netdev_warn(netdev, - "Memory squeeze, deferring packet\n"); + if (skb == NULL) goto skip_pkt; - } + memcpy(skb->data, (u8 *)(prrs + 1), packet_size); skb_put(skb, packet_size); skb->protocol = eth_type_trans(skb, netdev); @@ -1457,7 +1480,7 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, netdev_dbg(netdev, "RXD VLAN TAG<RRD>=0x%04x\n", prrs->vtag); - __vlan_hwaccel_put_tag(skb, vlan_tag); + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag); } netif_receive_skb(skb); @@ -1494,9 +1517,8 @@ fatal_err: schedule_work(&adapter->reset_task); } -/* +/** * atl1e_clean - NAPI Rx polling callback - * @adapter: board private structure */ static int atl1e_clean(struct napi_struct *napi, int budget) { @@ -1576,7 +1598,7 @@ static struct atl1e_tpd_desc *atl1e_get_tpd(struct atl1e_adapter *adapter) tx_ring->next_to_use = 0; memset(&tx_ring->desc[next_to_use], 0, sizeof(struct atl1e_tpd_desc)); - return (struct atl1e_tpd_desc *)&tx_ring->desc[next_to_use]; + return &tx_ring->desc[next_to_use]; } static struct atl1e_tx_buffer * @@ -1619,17 +1641,17 @@ static u16 atl1e_cal_tdp_req(const struct sk_buff *skb) static int atl1e_tso_csum(struct atl1e_adapter *adapter, struct sk_buff *skb, struct atl1e_tpd_desc *tpd) { + 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) { @@ -1688,8 +1710,8 @@ check_sum: return 0; } -static void atl1e_tx_map(struct atl1e_adapter *adapter, - struct sk_buff *skb, struct atl1e_tpd_desc *tpd) +static int atl1e_tx_map(struct atl1e_adapter *adapter, + struct sk_buff *skb, struct atl1e_tpd_desc *tpd) { struct atl1e_tpd_desc *use_tpd = NULL; struct atl1e_tx_buffer *tx_buffer = NULL; @@ -1700,6 +1722,8 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter, u16 nr_frags; u16 f; int segment; + int ring_start = adapter->tx_ring.next_to_use; + int ring_end; nr_frags = skb_shinfo(skb)->nr_frags; segment = (tpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK; @@ -1712,6 +1736,9 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter, tx_buffer->length = map_len; tx_buffer->dma = pci_map_single(adapter->pdev, skb->data, hdr_len, PCI_DMA_TODEVICE); + if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) + return -ENOSPC; + ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_SINGLE); mapped_len += map_len; use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma); @@ -1738,6 +1765,22 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter, tx_buffer->dma = pci_map_single(adapter->pdev, skb->data + mapped_len, map_len, PCI_DMA_TODEVICE); + + if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) { + /* We need to unwind the mappings we've done */ + ring_end = adapter->tx_ring.next_to_use; + adapter->tx_ring.next_to_use = ring_start; + while (adapter->tx_ring.next_to_use != ring_end) { + tpd = atl1e_get_tpd(adapter); + tx_buffer = atl1e_get_tx_buffer(adapter, tpd); + pci_unmap_single(adapter->pdev, tx_buffer->dma, + tx_buffer->length, PCI_DMA_TODEVICE); + } + /* Reset the tx rings next pointer */ + adapter->tx_ring.next_to_use = ring_start; + return -ENOSPC; + } + ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_SINGLE); mapped_len += map_len; use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma); @@ -1773,6 +1816,23 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter, (i * MAX_TX_BUF_LEN), tx_buffer->length, DMA_TO_DEVICE); + + if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) { + /* We need to unwind the mappings we've done */ + ring_end = adapter->tx_ring.next_to_use; + adapter->tx_ring.next_to_use = ring_start; + while (adapter->tx_ring.next_to_use != ring_end) { + tpd = atl1e_get_tpd(adapter); + tx_buffer = atl1e_get_tx_buffer(adapter, tpd); + dma_unmap_page(&adapter->pdev->dev, tx_buffer->dma, + tx_buffer->length, DMA_TO_DEVICE); + } + + /* Reset the ring next to use pointer */ + adapter->tx_ring.next_to_use = ring_start; + return -ENOSPC; + } + ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_PAGE); use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma); use_tpd->word2 = (use_tpd->word2 & (~TPD_BUFLEN_MASK)) | @@ -1790,6 +1850,7 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter, /* The last buffer info contain the skb address, so it will be free after unmap */ tx_buffer->skb = skb; + return 0; } static void atl1e_tx_queue(struct atl1e_adapter *adapter, u16 count, @@ -1857,10 +1918,15 @@ static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb, return NETDEV_TX_OK; } - atl1e_tx_map(adapter, skb, tpd); + if (atl1e_tx_map(adapter, skb, tpd)) { + dev_kfree_skb_any(skb); + goto out; + } + atl1e_tx_queue(adapter, tpd_req, tpd); netdev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ +out: spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_OK; } @@ -1870,40 +1936,22 @@ static void atl1e_free_irq(struct atl1e_adapter *adapter) struct net_device *netdev = adapter->netdev; free_irq(adapter->pdev->irq, netdev); - - if (adapter->have_msi) - pci_disable_msi(adapter->pdev); } static int atl1e_request_irq(struct atl1e_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; - int flags = 0; int err = 0; - adapter->have_msi = true; - err = pci_enable_msi(adapter->pdev); - if (err) { - netdev_dbg(adapter->netdev, - "Unable to allocate MSI interrupt Error: %d\n", err); - adapter->have_msi = false; - } else - netdev->irq = pdev->irq; - - - if (!adapter->have_msi) - flags |= IRQF_SHARED; - err = request_irq(adapter->pdev->irq, atl1e_intr, flags, - netdev->name, netdev); + err = request_irq(pdev->irq, atl1e_intr, IRQF_SHARED, netdev->name, + netdev); if (err) { netdev_dbg(adapter->netdev, "Unable to allocate interrupt Error: %d\n", err); - if (adapter->have_msi) - pci_disable_msi(adapter->pdev); return err; } - netdev_dbg(adapter->netdev, "atl1e_request_irq OK\n"); + netdev_dbg(netdev, "atl1e_request_irq OK\n"); return err; } @@ -1964,7 +2012,7 @@ void atl1e_down(struct atl1e_adapter *adapter) atl1e_clean_rx_ring(adapter); } -/* +/** * atl1e_open - Called when a network interface is made active * @netdev: network interface device structure * @@ -2010,7 +2058,7 @@ err_req_irq: return err; } -/* +/** * atl1e_close - Disables a network interface * @netdev: network interface device structure * @@ -2064,8 +2112,8 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state) if (wufc) { /* get link status */ - atl1e_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data); - atl1e_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data); + atl1e_read_phy_reg(hw, MII_BMSR, &mii_bmsr_data); + atl1e_read_phy_reg(hw, MII_BMSR, &mii_bmsr_data); mii_advertise_data = ADVERTISE_10HALF; @@ -2089,7 +2137,7 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state) for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) { msleep(100); atl1e_read_phy_reg(hw, MII_BMSR, - (u16 *)&mii_bmsr_data); + &mii_bmsr_data); if (mii_bmsr_data & BMSR_LSTATUS) break; } @@ -2233,21 +2281,21 @@ static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev) SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); - netdev->irq = pdev->irq; netdev->netdev_ops = &atl1e_netdev_ops; netdev->watchdog_timeo = AT_TX_WATCHDOG; atl1e_set_ethtool_ops(netdev); netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO | - NETIF_F_HW_VLAN_RX; + NETIF_F_HW_VLAN_CTAG_RX; netdev->features = netdev->hw_features | NETIF_F_LLTX | - NETIF_F_HW_VLAN_TX; - + NETIF_F_HW_VLAN_CTAG_TX; + /* not enabled by default */ + netdev->hw_features |= NETIF_F_RXALL | NETIF_F_RXFCS; return 0; } -/* +/** * atl1e_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in atl1e_pci_tbl @@ -2258,8 +2306,7 @@ static int atl1e_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 atl1e_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct atl1e_adapter *adapter = NULL; @@ -2300,7 +2347,6 @@ static int __devinit atl1e_probe(struct pci_dev *pdev, netdev = alloc_etherdev(sizeof(struct atl1e_adapter)); if (netdev == NULL) { err = -ENOMEM; - dev_err(&pdev->dev, "etherdev alloc failed\n"); goto err_alloc_etherdev; } @@ -2320,7 +2366,6 @@ static int __devinit atl1e_probe(struct pci_dev *pdev, netdev_err(netdev, "cannot map device registers\n"); goto err_ioremap; } - netdev->base_addr = (unsigned long)adapter->hw.hw_addr; /* init mii data */ adapter->mii.dev = netdev; @@ -2368,11 +2413,11 @@ static int __devinit atl1e_probe(struct pci_dev *pdev, } memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); - memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); netdev_dbg(netdev, "mac address : %pM\n", adapter->hw.mac_addr); INIT_WORK(&adapter->reset_task, atl1e_reset_task); INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task); + netif_set_gso_max_size(netdev, MAX_TSO_SEG_SIZE); err = register_netdev(netdev); if (err) { netdev_err(netdev, "register netdevice failed\n"); @@ -2391,7 +2436,7 @@ err_reset: err_register: err_sw_init: err_eeprom: - iounmap(adapter->hw.hw_addr); + pci_iounmap(pdev, adapter->hw.hw_addr); err_init_netdev: err_ioremap: free_netdev(netdev); @@ -2403,7 +2448,7 @@ err_dma: return err; } -/* +/** * atl1e_remove - Device Removal Routine * @pdev: PCI device information struct * @@ -2412,7 +2457,7 @@ err_dma: * Hot-Plug event, or because the driver is going to be removed from * memory. */ -static void __devexit atl1e_remove(struct pci_dev *pdev) +static void atl1e_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct atl1e_adapter *adapter = netdev_priv(netdev); @@ -2429,13 +2474,13 @@ static void __devexit atl1e_remove(struct pci_dev *pdev) unregister_netdev(netdev); atl1e_free_ring_resources(adapter); atl1e_force_ps(&adapter->hw); - iounmap(adapter->hw.hw_addr); + pci_iounmap(pdev, adapter->hw.hw_addr); pci_release_regions(pdev); free_netdev(netdev); pci_disable_device(pdev); } -/* +/** * atl1e_io_error_detected - called when PCI error is detected * @pdev: Pointer to PCI device * @state: The current pci connection state @@ -2463,7 +2508,7 @@ atl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_NEED_RESET; } -/* +/** * atl1e_io_slot_reset - called after the pci bus has been reset. * @pdev: Pointer to PCI device * @@ -2490,7 +2535,7 @@ static pci_ers_result_t atl1e_io_slot_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_RECOVERED; } -/* +/** * atl1e_io_resume - called when traffic can start flowing again. * @pdev: Pointer to PCI device * @@ -2514,7 +2559,7 @@ static void atl1e_io_resume(struct pci_dev *pdev) netif_device_attach(netdev); } -static struct pci_error_handlers atl1e_err_handler = { +static const struct pci_error_handlers atl1e_err_handler = { .error_detected = atl1e_io_error_detected, .slot_reset = atl1e_io_slot_reset, .resume = atl1e_io_resume, @@ -2524,7 +2569,7 @@ static struct pci_driver atl1e_driver = { .name = atl1e_driver_name, .id_table = atl1e_pci_tbl, .probe = atl1e_probe, - .remove = __devexit_p(atl1e_remove), + .remove = atl1e_remove, /* Power Management Hooks */ #ifdef CONFIG_PM .suspend = atl1e_suspend, @@ -2534,27 +2579,4 @@ static struct pci_driver atl1e_driver = { .err_handler = &atl1e_err_handler }; -/* - * atl1e_init_module - Driver Registration Routine - * - * atl1e_init_module is the first routine called when the driver is - * loaded. All it does is register with the PCI subsystem. - */ -static int __init atl1e_init_module(void) -{ - return pci_register_driver(&atl1e_driver); -} - -/* - * atl1e_exit_module - Driver Exit Cleanup Routine - * - * atl1e_exit_module is called just before the driver is removed - * from memory. - */ -static void __exit atl1e_exit_module(void) -{ - pci_unregister_driver(&atl1e_driver); -} - -module_init(atl1e_init_module); -module_exit(atl1e_exit_module); +module_pci_driver(atl1e_driver); diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_param.c b/drivers/net/ethernet/atheros/atl1e/atl1e_param.c index 0ce60b6e7ef..fa314282c9a 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_param.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_param.c @@ -40,7 +40,7 @@ #define ATL1E_PARAM_INIT { [0 ... ATL1E_MAX_NIC] = OPTION_UNSET } #define ATL1E_PARAM(x, desc) \ - static int __devinitdata x[ATL1E_MAX_NIC + 1] = ATL1E_PARAM_INIT; \ + static int x[ATL1E_MAX_NIC + 1] = ATL1E_PARAM_INIT; \ static unsigned int num_##x; \ module_param_array_named(x, x, int, &num_##x, 0); \ MODULE_PARM_DESC(x, desc); @@ -116,7 +116,8 @@ struct atl1e_option { } arg; }; -static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, struct atl1e_adapter *adapter) +static int atl1e_validate_option(int *value, struct atl1e_option *opt, + struct atl1e_adapter *adapter) { if (*value == OPTION_UNSET) { *value = opt->def; @@ -168,7 +169,7 @@ static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, return -1; } -/* +/** * atl1e_check_options - Range Checking for Command Line Parameters * @adapter: board private structure * @@ -177,7 +178,7 @@ static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, * value exists, a default value is used. The final value is stored * in a variable in the adapter structure. */ -void __devinit atl1e_check_options(struct atl1e_adapter *adapter) +void atl1e_check_options(struct atl1e_adapter *adapter) { int bd = adapter->bd_number; diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c index 9bd20497664..b460db7919a 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.c +++ b/drivers/net/ethernet/atheros/atlx/atl1.c @@ -113,7 +113,7 @@ static const struct ethtool_ops atl1_ethtool_ops; * * Default Value: 100 (200us) */ -static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; +static int int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; static unsigned int num_int_mod_timer; module_param_array_named(int_mod_timer, int_mod_timer, int, &num_int_mod_timer, 0); @@ -143,8 +143,8 @@ struct atl1_option { } arg; }; -static int __devinit atl1_validate_option(int *value, struct atl1_option *opt, - struct pci_dev *pdev) +static int atl1_validate_option(int *value, struct atl1_option *opt, + struct pci_dev *pdev) { if (*value == OPTION_UNSET) { *value = opt->def; @@ -195,7 +195,7 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt, return -1; } -/* +/** * atl1_check_options - Range Checking for Command Line Parameters * @adapter: board private structure * @@ -204,7 +204,7 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt, * value exists, a default value is used. The final value is stored * in a variable in the adapter structure. */ -static void __devinit atl1_check_options(struct atl1_adapter *adapter) +static void atl1_check_options(struct atl1_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; int bd = adapter->bd_number; @@ -266,7 +266,7 @@ static s32 atl1_reset_hw(struct atl1_hw *hw) * interrupts & Clear any pending interrupt events */ /* - * iowrite32(0, hw->hw_addr + REG_IMR); + * atlx_irq_disable(adapter); * iowrite32(0xffffffff, hw->hw_addr + REG_ISR); */ @@ -534,14 +534,17 @@ static int atl1_get_permanent_address(struct atl1_hw *hw) */ static s32 atl1_read_mac_addr(struct atl1_hw *hw) { + s32 ret = 0; u16 i; - if (atl1_get_permanent_address(hw)) - random_ether_addr(hw->perm_mac_addr); + if (atl1_get_permanent_address(hw)) { + eth_random_addr(hw->perm_mac_addr); + ret = 1; + } for (i = 0; i < ETH_ALEN; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; - return 0; + return ret; } /* @@ -934,7 +937,7 @@ static void atl1_set_mac_addr(struct atl1_hw *hw) iowrite32(value, (hw->hw_addr + REG_MAC_STA_ADDR) + (1 << 2)); } -/* +/** * atl1_sw_init - Initialize general software structures (struct atl1_adapter) * @adapter: board private structure to initialize * @@ -942,7 +945,7 @@ static void atl1_set_mac_addr(struct atl1_hw *hw) * Fields are initialized based on PCI device information and * OS network device settings (MTU size). */ -static int __devinit atl1_sw_init(struct atl1_adapter *adapter) +static int atl1_sw_init(struct atl1_adapter *adapter) { struct atl1_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; @@ -1011,12 +1014,6 @@ static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, atl1_write_phy_reg(&adapter->hw, reg_num, val); } -/* - * atl1_mii_ioctl - - * @netdev: - * @ifreq: - * @cmd: - */ static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { struct atl1_adapter *adapter = netdev_priv(netdev); @@ -1033,7 +1030,7 @@ static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) return retval; } -/* +/** * atl1_setup_mem_resources - allocate Tx / RX descriptor resources * @adapter: board private structure * @@ -1058,7 +1055,7 @@ static s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) goto err_nomem; } rfd_ring->buffer_info = - (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count); + (tpd_ring->buffer_info + tpd_ring->count); /* * real ring DMA buffer @@ -1144,7 +1141,7 @@ static void atl1_init_ring_ptrs(struct atl1_adapter *adapter) atomic_set(&rrd_ring->next_to_clean, 0); } -/* +/** * atl1_clean_rx_ring - Free RFD Buffers * @adapter: board private structure */ @@ -1184,7 +1181,7 @@ static void atl1_clean_rx_ring(struct atl1_adapter *adapter) atomic_set(&rrd_ring->next_to_clean, 0); } -/* +/** * atl1_clean_tx_ring - Free Tx Buffers * @adapter: board private structure */ @@ -1224,7 +1221,7 @@ static void atl1_clean_tx_ring(struct atl1_adapter *adapter) atomic_set(&tpd_ring->next_to_clean, 0); } -/* +/** * atl1_free_ring_resources - Free Tx / RX descriptor Resources * @adapter: board private structure * @@ -1467,7 +1464,7 @@ static void set_flow_ctrl_new(struct atl1_hw *hw) iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH); } -/* +/** * atl1_configure - Configure Transmit&Receive Unit after Reset * @adapter: board private structure * @@ -1681,33 +1678,42 @@ static void atl1_inc_smb(struct atl1_adapter *adapter) struct net_device *netdev = adapter->netdev; struct stats_msg_block *smb = adapter->smb.smb; + u64 new_rx_errors = smb->rx_frag + + smb->rx_fcs_err + + smb->rx_len_err + + smb->rx_sz_ov + + smb->rx_rxf_ov + + smb->rx_rrd_ov + + smb->rx_align_err; + u64 new_tx_errors = smb->tx_late_col + + smb->tx_abort_col + + smb->tx_underrun + + smb->tx_trunc; + /* Fill out the OS statistics structure */ - adapter->soft_stats.rx_packets += smb->rx_ok; - adapter->soft_stats.tx_packets += smb->tx_ok; + adapter->soft_stats.rx_packets += smb->rx_ok + new_rx_errors; + adapter->soft_stats.tx_packets += smb->tx_ok + new_tx_errors; adapter->soft_stats.rx_bytes += smb->rx_byte_cnt; adapter->soft_stats.tx_bytes += smb->tx_byte_cnt; adapter->soft_stats.multicast += smb->rx_mcast; - adapter->soft_stats.collisions += (smb->tx_1_col + smb->tx_2_col * 2 + - smb->tx_late_col + smb->tx_abort_col * adapter->hw.max_retry); + adapter->soft_stats.collisions += smb->tx_1_col + + smb->tx_2_col + + smb->tx_late_col + + smb->tx_abort_col; /* Rx Errors */ - adapter->soft_stats.rx_errors += (smb->rx_frag + smb->rx_fcs_err + - smb->rx_len_err + smb->rx_sz_ov + smb->rx_rxf_ov + - smb->rx_rrd_ov + smb->rx_align_err); + adapter->soft_stats.rx_errors += new_rx_errors; adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov; adapter->soft_stats.rx_length_errors += smb->rx_len_err; adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err; adapter->soft_stats.rx_frame_errors += smb->rx_align_err; - adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov + - smb->rx_rxf_ov); adapter->soft_stats.rx_pause += smb->rx_pause; adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov; adapter->soft_stats.rx_trunc += smb->rx_sz_ov; /* Tx Errors */ - adapter->soft_stats.tx_errors += (smb->tx_late_col + - smb->tx_abort_col + smb->tx_underrun + smb->tx_trunc); + adapter->soft_stats.tx_errors += new_tx_errors; adapter->soft_stats.tx_fifo_errors += smb->tx_underrun; adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col; adapter->soft_stats.tx_window_errors += smb->tx_late_col; @@ -1721,23 +1727,18 @@ static void atl1_inc_smb(struct atl1_adapter *adapter) adapter->soft_stats.tx_trunc += smb->tx_trunc; adapter->soft_stats.tx_pause += smb->tx_pause; - netdev->stats.rx_packets = adapter->soft_stats.rx_packets; - netdev->stats.tx_packets = adapter->soft_stats.tx_packets; netdev->stats.rx_bytes = adapter->soft_stats.rx_bytes; netdev->stats.tx_bytes = adapter->soft_stats.tx_bytes; netdev->stats.multicast = adapter->soft_stats.multicast; netdev->stats.collisions = adapter->soft_stats.collisions; netdev->stats.rx_errors = adapter->soft_stats.rx_errors; - netdev->stats.rx_over_errors = - adapter->soft_stats.rx_missed_errors; netdev->stats.rx_length_errors = adapter->soft_stats.rx_length_errors; netdev->stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; netdev->stats.rx_frame_errors = adapter->soft_stats.rx_frame_errors; netdev->stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; - netdev->stats.rx_missed_errors = - adapter->soft_stats.rx_missed_errors; + netdev->stats.rx_dropped = adapter->soft_stats.rx_rrd_ov; netdev->stats.tx_errors = adapter->soft_stats.tx_errors; netdev->stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; netdev->stats.tx_aborted_errors = @@ -1746,6 +1747,9 @@ static void atl1_inc_smb(struct atl1_adapter *adapter) adapter->soft_stats.tx_window_errors; netdev->stats.tx_carrier_errors = adapter->soft_stats.tx_carrier_errors; + + netdev->stats.rx_packets = adapter->soft_stats.rx_packets; + netdev->stats.tx_packets = adapter->soft_stats.tx_packets; } static void atl1_update_mailbox(struct atl1_adapter *adapter) @@ -1841,7 +1845,7 @@ static void atl1_rx_checksum(struct atl1_adapter *adapter, } } -/* +/** * atl1_alloc_rx_buffers - Replace used receive buffers * @adapter: address of board private structure */ @@ -1875,7 +1879,7 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) adapter->rx_buffer_len); if (unlikely(!skb)) { /* Better luck next round */ - adapter->netdev->stats.rx_dropped++; + adapter->soft_stats.rx_dropped++; break; } @@ -1914,7 +1918,7 @@ next: return num_alloc; } -static void atl1_intr_rx(struct atl1_adapter *adapter) +static int atl1_intr_rx(struct atl1_adapter *adapter, int budget) { int i, count; u16 length; @@ -1930,7 +1934,7 @@ static void atl1_intr_rx(struct atl1_adapter *adapter) rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean); - while (1) { + while (count < budget) { rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean); i = 1; if (likely(rrd->xsz.valid)) { /* packet valid */ @@ -2027,9 +2031,9 @@ rrd_ok: ((rrd->vlan_tag & 7) << 13) | ((rrd->vlan_tag & 8) << 9); - __vlan_hwaccel_put_tag(skb, vlan_tag); + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag); } - netif_rx(skb); + netif_receive_skb(skb); /* let protocol layer free skb */ buffer_info->skb = NULL; @@ -2062,14 +2066,17 @@ rrd_ok: iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX); spin_unlock(&adapter->mb_lock); } + + return count; } -static void atl1_intr_tx(struct atl1_adapter *adapter) +static int atl1_intr_tx(struct atl1_adapter *adapter) { struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; struct atl1_buffer *buffer_info; u16 sw_tpd_next_to_clean; u16 cmb_tpd_next_to_clean; + int count = 0; sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean); cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx); @@ -2089,12 +2096,16 @@ static void atl1_intr_tx(struct atl1_adapter *adapter) if (++sw_tpd_next_to_clean == tpd_ring->count) sw_tpd_next_to_clean = 0; + + count++; } atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean); if (netif_queue_stopped(adapter->netdev) && netif_carrier_ok(adapter->netdev)) netif_wake_queue(adapter->netdev); + + return count; } static u16 atl1_tpd_avail(struct atl1_tpd_ring *tpd_ring) @@ -2107,18 +2118,17 @@ static u16 atl1_tpd_avail(struct atl1_tpd_ring *tpd_ring) } static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb, - struct tx_packet_desc *ptpd) + struct tx_packet_desc *ptpd) { u8 hdr_len, ip_off; u32 real_len; - int err; if (skb_shinfo(skb)->gso_size) { - 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; if (skb->protocol == htons(ETH_P_IP)) { struct iphdr *iph = ip_hdr(skb); @@ -2164,7 +2174,7 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb, return 3; } } - return false; + return 0; } static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb, @@ -2436,88 +2446,126 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb, return NETDEV_TX_OK; } -/* +static int atl1_rings_clean(struct napi_struct *napi, int budget) +{ + struct atl1_adapter *adapter = container_of(napi, struct atl1_adapter, napi); + int work_done = atl1_intr_rx(adapter, budget); + + if (atl1_intr_tx(adapter)) + work_done = budget; + + /* Let's come again to process some more packets */ + if (work_done >= budget) + return work_done; + + napi_complete(napi); + /* re-enable Interrupt */ + if (likely(adapter->int_enabled)) + atlx_imr_set(adapter, IMR_NORMAL_MASK); + return work_done; +} + +static inline int atl1_sched_rings_clean(struct atl1_adapter* adapter) +{ + if (!napi_schedule_prep(&adapter->napi)) + /* It is possible in case even the RX/TX ints are disabled via IMR + * register the ISR bits are set anyway (but do not produce IRQ). + * To handle such situation the napi functions used to check is + * something scheduled or not. + */ + return 0; + + __napi_schedule(&adapter->napi); + + /* + * Disable RX/TX ints via IMR register if it is + * allowed. NAPI handler must reenable them in same + * way. + */ + if (!adapter->int_enabled) + return 1; + + atlx_imr_set(adapter, IMR_NORXTX_MASK); + return 1; +} + +/** * atl1_intr - Interrupt Handler * @irq: interrupt number * @data: pointer to a network interface device structure - * @pt_regs: CPU registers structure */ static irqreturn_t atl1_intr(int irq, void *data) { struct atl1_adapter *adapter = netdev_priv(data); u32 status; - int max_ints = 10; status = adapter->cmb.cmb->int_stats; if (!status) return IRQ_NONE; - do { - /* clear CMB interrupt status at once */ - adapter->cmb.cmb->int_stats = 0; - - if (status & ISR_GPHY) /* clear phy status */ - atlx_clear_phy_int(adapter); + /* clear CMB interrupt status at once, + * but leave rx/tx interrupt status in case it should be dropped + * only if rx/tx processing queued. In other case interrupt + * can be lost. + */ + adapter->cmb.cmb->int_stats = status & (ISR_CMB_TX | ISR_CMB_RX); - /* clear ISR status, and Enable CMB DMA/Disable Interrupt */ - iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR); + if (status & ISR_GPHY) /* clear phy status */ + atlx_clear_phy_int(adapter); - /* check if SMB intr */ - if (status & ISR_SMB) - atl1_inc_smb(adapter); + /* clear ISR status, and Enable CMB DMA/Disable Interrupt */ + iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR); - /* check if PCIE PHY Link down */ - if (status & ISR_PHY_LINKDOWN) { - if (netif_msg_intr(adapter)) - dev_printk(KERN_DEBUG, &adapter->pdev->dev, - "pcie phy link down %x\n", status); - if (netif_running(adapter->netdev)) { /* reset MAC */ - iowrite32(0, adapter->hw.hw_addr + REG_IMR); - schedule_work(&adapter->pcie_dma_to_rst_task); - return IRQ_HANDLED; - } - } + /* check if SMB intr */ + if (status & ISR_SMB) + atl1_inc_smb(adapter); - /* check if DMA read/write error ? */ - if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { - if (netif_msg_intr(adapter)) - dev_printk(KERN_DEBUG, &adapter->pdev->dev, - "pcie DMA r/w error (status = 0x%x)\n", - status); - iowrite32(0, adapter->hw.hw_addr + REG_IMR); - schedule_work(&adapter->pcie_dma_to_rst_task); + /* check if PCIE PHY Link down */ + if (status & ISR_PHY_LINKDOWN) { + if (netif_msg_intr(adapter)) + dev_printk(KERN_DEBUG, &adapter->pdev->dev, + "pcie phy link down %x\n", status); + if (netif_running(adapter->netdev)) { /* reset MAC */ + atlx_irq_disable(adapter); + schedule_work(&adapter->reset_dev_task); return IRQ_HANDLED; } + } - /* link event */ - if (status & ISR_GPHY) { - adapter->soft_stats.tx_carrier_errors++; - atl1_check_for_link(adapter); - } + /* check if DMA read/write error ? */ + if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { + if (netif_msg_intr(adapter)) + dev_printk(KERN_DEBUG, &adapter->pdev->dev, + "pcie DMA r/w error (status = 0x%x)\n", + status); + atlx_irq_disable(adapter); + schedule_work(&adapter->reset_dev_task); + return IRQ_HANDLED; + } - /* transmit event */ - if (status & ISR_CMB_TX) - atl1_intr_tx(adapter); - - /* rx exception */ - if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN | - ISR_RRD_OV | ISR_HOST_RFD_UNRUN | - ISR_HOST_RRD_OV | ISR_CMB_RX))) { - if (status & (ISR_RXF_OV | ISR_RFD_UNRUN | - ISR_RRD_OV | ISR_HOST_RFD_UNRUN | - ISR_HOST_RRD_OV)) - if (netif_msg_intr(adapter)) - dev_printk(KERN_DEBUG, - &adapter->pdev->dev, - "rx exception, ISR = 0x%x\n", - status); - atl1_intr_rx(adapter); - } + /* link event */ + if (status & ISR_GPHY) { + adapter->soft_stats.tx_carrier_errors++; + atl1_check_for_link(adapter); + } - if (--max_ints < 0) - break; + /* transmit or receive event */ + if (status & (ISR_CMB_TX | ISR_CMB_RX) && + atl1_sched_rings_clean(adapter)) + adapter->cmb.cmb->int_stats = adapter->cmb.cmb->int_stats & + ~(ISR_CMB_TX | ISR_CMB_RX); - } while ((status = adapter->cmb.cmb->int_stats)); + /* rx exception */ + if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN | + ISR_RRD_OV | ISR_HOST_RFD_UNRUN | + ISR_HOST_RRD_OV))) { + if (netif_msg_intr(adapter)) + dev_printk(KERN_DEBUG, + &adapter->pdev->dev, + "rx exception, ISR = 0x%x\n", + status); + atl1_sched_rings_clean(adapter); + } /* re-enable Interrupt */ iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR); @@ -2525,7 +2573,7 @@ static irqreturn_t atl1_intr(int irq, void *data) } -/* +/** * atl1_phy_config - Timer Call-back * @data: pointer to netdev cast into an unsigned long */ @@ -2596,6 +2644,7 @@ static s32 atl1_up(struct atl1_adapter *adapter) if (unlikely(err)) goto err_up; + napi_enable(&adapter->napi); atlx_irq_enable(adapter); atl1_check_link(adapter); netif_start_queue(netdev); @@ -2612,6 +2661,7 @@ static void atl1_down(struct atl1_adapter *adapter) { struct net_device *netdev = adapter->netdev; + napi_disable(&adapter->napi); netif_stop_queue(netdev); del_timer_sync(&adapter->phy_config_timer); adapter->phy_timer_pending = false; @@ -2630,10 +2680,10 @@ static void atl1_down(struct atl1_adapter *adapter) atl1_clean_rx_ring(adapter); } -static void atl1_tx_timeout_task(struct work_struct *work) +static void atl1_reset_dev_task(struct work_struct *work) { struct atl1_adapter *adapter = - container_of(work, struct atl1_adapter, tx_timeout_task); + container_of(work, struct atl1_adapter, reset_dev_task); struct net_device *netdev = adapter->netdev; netif_device_detach(netdev); @@ -2642,7 +2692,7 @@ static void atl1_tx_timeout_task(struct work_struct *work) netif_device_attach(netdev); } -/* +/** * atl1_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure * @new_mtu: new value for maximum frame size @@ -2676,7 +2726,7 @@ static int atl1_change_mtu(struct net_device *netdev, int new_mtu) return 0; } -/* +/** * atl1_open - Called when a network interface is made active * @netdev: network interface device structure * @@ -2711,7 +2761,7 @@ err_up: return err; } -/* +/** * atl1_close - Disables a network interface * @netdev: network interface device structure * @@ -2730,7 +2780,7 @@ static int atl1_close(struct net_device *netdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int atl1_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -2832,23 +2882,18 @@ static int atl1_resume(struct device *dev) return 0; } +#endif static SIMPLE_DEV_PM_OPS(atl1_pm_ops, atl1_suspend, atl1_resume); -#define ATL1_PM_OPS (&atl1_pm_ops) - -#else - -static int atl1_suspend(struct device *dev) { return 0; } - -#define ATL1_PM_OPS NULL -#endif static void atl1_shutdown(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct atl1_adapter *adapter = netdev_priv(netdev); +#ifdef CONFIG_PM_SLEEP atl1_suspend(&pdev->dev); +#endif pci_wake_from_d3(pdev, adapter->wol); pci_set_power_state(pdev, PCI_D3hot); } @@ -2879,7 +2924,7 @@ static const struct net_device_ops atl1_netdev_ops = { #endif }; -/* +/** * atl1_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in atl1_pci_tbl @@ -2890,8 +2935,7 @@ static const struct net_device_ops atl1_netdev_ops = { * The OS initialization, configuring of the adapter private structure, * and a hardware reset occur. */ -static int __devinit atl1_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int atl1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct atl1_adapter *adapter; @@ -2968,6 +3012,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev, netdev->netdev_ops = &atl1_netdev_ops; netdev->watchdog_timeo = 5 * HZ; + netif_napi_add(netdev, &adapter->napi, atl1_rings_clean, 64); netdev->ethtool_ops = &atl1_ethtool_ops; adapter->bd_number = cards_found; @@ -2979,10 +3024,10 @@ static int __devinit atl1_probe(struct pci_dev *pdev, netdev->features = NETIF_F_HW_CSUM; netdev->features |= NETIF_F_SG; - netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); + netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); netdev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_TSO | - NETIF_F_HW_VLAN_RX; + NETIF_F_HW_VLAN_CTAG_RX; /* is this valid? see atl1_setup_mac_ctrl() */ netdev->features |= NETIF_F_RXCSUM; @@ -3007,7 +3052,10 @@ static int __devinit atl1_probe(struct pci_dev *pdev, } /* copy the MAC address out of the EEPROM */ - atl1_read_mac_addr(&adapter->hw); + if (atl1_read_mac_addr(&adapter->hw)) { + /* mark random mac */ + netdev->addr_assign_type = NET_ADDR_RANDOM; + } memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); if (!is_valid_ether_addr(netdev->dev_addr)) { @@ -3032,12 +3080,10 @@ static int __devinit atl1_probe(struct pci_dev *pdev, (unsigned long)adapter); adapter->phy_timer_pending = false; - INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task); + INIT_WORK(&adapter->reset_dev_task, atl1_reset_dev_task); INIT_WORK(&adapter->link_chg_task, atlx_link_chg_task); - INIT_WORK(&adapter->pcie_dma_to_rst_task, atl1_tx_timeout_task); - err = register_netdev(netdev); if (err) goto err_common; @@ -3058,7 +3104,7 @@ err_request_regions: return err; } -/* +/** * atl1_remove - Device Removal Routine * @pdev: PCI device information struct * @@ -3067,7 +3113,7 @@ err_request_regions: * Hot-Plug event, or because the driver is going to be removed from * memory. */ -static void __devexit atl1_remove(struct pci_dev *pdev) +static void atl1_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct atl1_adapter *adapter; @@ -3082,7 +3128,8 @@ static void __devexit atl1_remove(struct pci_dev *pdev) * from the BIOS during POST. If we've been messing with the MAC * address, we need to save the permanent one. */ - if (memcmp(adapter->hw.mac_addr, adapter->hw.perm_mac_addr, ETH_ALEN)) { + if (!ether_addr_equal_unaligned(adapter->hw.mac_addr, + adapter->hw.perm_mac_addr)) { memcpy(adapter->hw.mac_addr, adapter->hw.perm_mac_addr, ETH_ALEN); atl1_set_mac_addr(&adapter->hw); @@ -3100,36 +3147,11 @@ static struct pci_driver atl1_driver = { .name = ATLX_DRIVER_NAME, .id_table = atl1_pci_tbl, .probe = atl1_probe, - .remove = __devexit_p(atl1_remove), + .remove = atl1_remove, .shutdown = atl1_shutdown, - .driver.pm = ATL1_PM_OPS, + .driver.pm = &atl1_pm_ops, }; -/* - * atl1_exit_module - Driver Exit Cleanup Routine - * - * atl1_exit_module is called just before the driver is removed - * from memory. - */ -static void __exit atl1_exit_module(void) -{ - pci_unregister_driver(&atl1_driver); -} - -/* - * atl1_init_module - Driver Registration Routine - * - * atl1_init_module is the first routine called when the driver is - * loaded. All it does is register with the PCI subsystem. - */ -static int __init atl1_init_module(void) -{ - return pci_register_driver(&atl1_driver); -} - -module_init(atl1_init_module); -module_exit(atl1_exit_module); - struct atl1_stats { char stat_string[ETH_GSTRING_LEN]; int sizeof_stat; @@ -3236,8 +3258,8 @@ static int atl1_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; } if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || hw->media_type == MEDIA_TYPE_1000M_FULL) @@ -3665,3 +3687,5 @@ static const struct ethtool_ops atl1_ethtool_ops = { .get_ethtool_stats = atl1_get_ethtool_stats, .get_sset_count = atl1_get_sset_count, }; + +module_pci_driver(atl1_driver); diff --git a/drivers/net/ethernet/atheros/atlx/atl1.h b/drivers/net/ethernet/atheros/atlx/atl1.h index 109d6da8be9..34a58cd846a 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.h +++ b/drivers/net/ethernet/atheros/atlx/atl1.h @@ -275,13 +275,17 @@ static u32 atl1_check_link(struct atl1_adapter *adapter); #define ISR_DIS_SMB 0x20000000 #define ISR_DIS_DMA 0x40000000 -/* Normal Interrupt mask */ -#define IMR_NORMAL_MASK (\ +/* Normal Interrupt mask without RX/TX enabled */ +#define IMR_NORXTX_MASK (\ ISR_SMB |\ ISR_GPHY |\ ISR_PHY_LINKDOWN|\ ISR_DMAR_TO_RST |\ - ISR_DMAW_TO_RST |\ + ISR_DMAW_TO_RST) + +/* Normal Interrupt mask */ +#define IMR_NORMAL_MASK (\ + IMR_NORXTX_MASK |\ ISR_CMB_TX |\ ISR_CMB_RX) @@ -662,6 +666,7 @@ struct atl1_sft_stats { u64 rx_errors; u64 rx_length_errors; u64 rx_crc_errors; + u64 rx_dropped; u64 rx_frame_errors; u64 rx_fifo_errors; u64 rx_missed_errors; @@ -758,9 +763,9 @@ struct atl1_adapter { u16 link_speed; u16 link_duplex; spinlock_t lock; - struct work_struct tx_timeout_task; + struct napi_struct napi; + struct work_struct reset_dev_task; struct work_struct link_chg_task; - struct work_struct pcie_dma_to_rst_task; struct timer_list phy_config_timer; bool phy_timer_pending; @@ -782,6 +787,12 @@ struct atl1_adapter { u16 ict; /* interrupt clear timer (2us resolution */ struct mii_if_info mii; /* MII interface info */ + /* + * Use this value to check is napi handler allowed to + * enable ints or not + */ + bool int_enabled; + u32 bd_number; /* board number */ bool pci_using_64; struct atl1_hw hw; diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index 071f4c85896..6746bd71714 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -55,6 +55,7 @@ static const char atl2_driver_name[] = "atl2"; static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver"; static const char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation."; static const char atl2_driver_version[] = ATL2_DRV_VERSION; +static const struct ethtool_ops atl2_ethtool_ops; MODULE_AUTHOR("Atheros Corporation <xiong.huang@atheros.com>, Chris Snook <csnook@redhat.com>"); MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver"); @@ -71,11 +72,9 @@ static DEFINE_PCI_DEVICE_TABLE(atl2_pci_tbl) = { }; MODULE_DEVICE_TABLE(pci, atl2_pci_tbl); -static void atl2_set_ethtool_ops(struct net_device *netdev); - static void atl2_check_options(struct atl2_adapter *adapter); -/* +/** * atl2_sw_init - Initialize general software structures (struct atl2_adapter) * @adapter: board private structure to initialize * @@ -83,7 +82,7 @@ static void atl2_check_options(struct atl2_adapter *adapter); * Fields are initialized based on PCI device information and * OS network device settings (MTU size). */ -static int __devinit atl2_sw_init(struct atl2_adapter *adapter) +static int atl2_sw_init(struct atl2_adapter *adapter) { struct atl2_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; @@ -123,7 +122,7 @@ static int __devinit atl2_sw_init(struct atl2_adapter *adapter) return 0; } -/* +/** * atl2_set_multi - Multicast and Promiscuous mode set * @netdev: network interface device structure * @@ -177,7 +176,7 @@ static void init_ring_ptrs(struct atl2_adapter *adapter) adapter->txs_next_clear = 0; } -/* +/** * atl2_configure - Configure Transmit&Receive Unit after Reset * @adapter: board private structure * @@ -283,7 +282,7 @@ static int atl2_configure(struct atl2_adapter *adapter) return value; } -/* +/** * atl2_setup_ring_resources - allocate Tx / RX descriptor resources * @adapter: board private structure * @@ -340,7 +339,7 @@ static s32 atl2_setup_ring_resources(struct atl2_adapter *adapter) return 0; } -/* +/** * atl2_irq_enable - Enable default interrupt generation settings * @adapter: board private structure */ @@ -350,7 +349,7 @@ static inline void atl2_irq_enable(struct atl2_adapter *adapter) ATL2_WRITE_FLUSH(&adapter->hw); } -/* +/** * atl2_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure */ @@ -363,7 +362,7 @@ static inline void atl2_irq_disable(struct atl2_adapter *adapter) static void __atl2_vlan_mode(netdev_features_t features, u32 *ctrl) { - if (features & NETIF_F_HW_VLAN_RX) { + if (features & NETIF_F_HW_VLAN_CTAG_RX) { /* enable VLAN tag insert/strip */ *ctrl |= MAC_CTRL_RMV_VLAN; } else { @@ -399,10 +398,10 @@ static netdev_features_t atl2_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; return features; } @@ -412,7 +411,7 @@ static int atl2_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) atl2_vlan_mode(netdev, features); return 0; @@ -437,9 +436,6 @@ static void atl2_intr_rx(struct atl2_adapter *adapter) /* alloc new buffer */ skb = netdev_alloc_skb_ip_align(netdev, rx_size); if (NULL == skb) { - printk(KERN_WARNING - "%s: Mem squeeze, deferring packet.\n", - netdev->name); /* * Check that some rx space is free. If not, * free one and mark stats->rx_dropped++. @@ -455,7 +451,7 @@ static void atl2_intr_rx(struct atl2_adapter *adapter) ((rxd->status.vtag&7) << 13) | ((rxd->status.vtag&8) << 9); - __vlan_hwaccel_put_tag(skb, vlan_tag); + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag); } netif_rx(skb); netdev->stats.rx_bytes += rx_size; @@ -599,11 +595,10 @@ static inline void atl2_clear_phy_int(struct atl2_adapter *adapter) spin_unlock(&adapter->stats_lock); } -/* +/** * atl2_intr - Interrupt Handler * @irq: interrupt number * @data: pointer to a network interface device structure - * @pt_regs: CPU registers structure */ static irqreturn_t atl2_intr(int irq, void *data) { @@ -679,7 +674,7 @@ static int atl2_request_irq(struct atl2_adapter *adapter) netdev); } -/* +/** * atl2_free_ring_resources - Free Tx / RX descriptor Resources * @adapter: board private structure * @@ -692,7 +687,7 @@ static void atl2_free_ring_resources(struct atl2_adapter *adapter) adapter->ring_dma); } -/* +/** * atl2_open - Called when a network interface is made active * @netdev: network interface device structure * @@ -798,7 +793,7 @@ static void atl2_free_irq(struct atl2_adapter *adapter) #endif } -/* +/** * atl2_close - Disables a network interface * @netdev: network interface device structure * @@ -891,7 +886,7 @@ static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb, skb->len-copy_len); offset = ((u32)(skb->len-copy_len + 3) & ~3); } -#ifdef NETIF_F_HW_VLAN_TX +#ifdef NETIF_F_HW_VLAN_CTAG_TX if (vlan_tx_tag_present(skb)) { u16 vlan_tag = vlan_tx_tag_get(skb); vlan_tag = (vlan_tag << 4) | @@ -918,7 +913,7 @@ static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb, return NETDEV_TX_OK; } -/* +/** * atl2_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure * @new_mtu: new value for maximum frame size @@ -943,7 +938,7 @@ static int atl2_change_mtu(struct net_device *netdev, int new_mtu) return 0; } -/* +/** * atl2_set_mac - Change the Ethernet Address of the NIC * @netdev: network interface device structure * @p: pointer to an address structure @@ -969,12 +964,6 @@ static int atl2_set_mac(struct net_device *netdev, void *p) return 0; } -/* - * atl2_mii_ioctl - - * @netdev: - * @ifreq: - * @cmd: - */ static int atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { struct atl2_adapter *adapter = netdev_priv(netdev); @@ -1011,12 +1000,6 @@ static int atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) return 0; } -/* - * atl2_ioctl - - * @netdev: - * @ifreq: - * @cmd: - */ static int atl2_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { switch (cmd) { @@ -1033,7 +1016,7 @@ static int atl2_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } } -/* +/** * atl2_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure */ @@ -1045,7 +1028,7 @@ static void atl2_tx_timeout(struct net_device *netdev) schedule_work(&adapter->reset_task); } -/* +/** * atl2_watchdog - Timer Call-back * @data: pointer to netdev cast into an unsigned long */ @@ -1070,7 +1053,7 @@ static void atl2_watchdog(unsigned long data) } } -/* +/** * atl2_phy_config - Timer Call-back * @data: pointer to netdev cast into an unsigned long */ @@ -1274,9 +1257,8 @@ static int atl2_check_link(struct atl2_adapter *adapter) return 0; } -/* +/** * atl2_link_chg_task - deal with link change event Out of interrupt context - * @netdev: network interface device structure */ static void atl2_link_chg_task(struct work_struct *work) { @@ -1341,7 +1323,7 @@ static const struct net_device_ops atl2_netdev_ops = { #endif }; -/* +/** * atl2_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in atl2_pci_tbl @@ -1352,8 +1334,7 @@ static const struct net_device_ops atl2_netdev_ops = { * The OS initialization, configuring of the adapter private structure, * and a hardware reset occur. */ -static int __devinit atl2_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct atl2_adapter *adapter; @@ -1415,7 +1396,7 @@ static int __devinit atl2_probe(struct pci_dev *pdev, atl2_setup_pcicmd(pdev); netdev->netdev_ops = &atl2_netdev_ops; - atl2_set_ethtool_ops(netdev); + netdev->ethtool_ops = &atl2_ethtool_ops; netdev->watchdog_timeo = 5 * HZ; strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); @@ -1431,8 +1412,8 @@ static int __devinit atl2_probe(struct pci_dev *pdev, err = -EIO; - netdev->hw_features = NETIF_F_SG | NETIF_F_HW_VLAN_RX; - netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); + netdev->hw_features = NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_RX; + netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); /* Init PHY as early as possible due to power saving issue */ atl2_phy_init(&adapter->hw); @@ -1448,14 +1429,7 @@ static int __devinit atl2_probe(struct pci_dev *pdev, /* copy the MAC address out of the EEPROM */ atl2_read_mac_addr(&adapter->hw); memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); -/* FIXME: do we still need this? */ -#ifdef ETHTOOL_GPERMADDR - memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); - - if (!is_valid_ether_addr(netdev->perm_addr)) { -#else if (!is_valid_ether_addr(netdev->dev_addr)) { -#endif err = -EIO; goto err_eeprom; } @@ -1501,7 +1475,7 @@ err_dma: return err; } -/* +/** * atl2_remove - Device Removal Routine * @pdev: PCI device information struct * @@ -1512,7 +1486,7 @@ err_dma: */ /* FIXME: write the original MAC address back in case it was changed from a * BIOS-set value, as in atl1 -- CHS */ -static void __devexit atl2_remove(struct pci_dev *pdev) +static void atl2_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct atl2_adapter *adapter = netdev_priv(netdev); @@ -1719,7 +1693,7 @@ static struct pci_driver atl2_driver = { .name = atl2_driver_name, .id_table = atl2_pci_tbl, .probe = atl2_probe, - .remove = __devexit_p(atl2_remove), + .remove = atl2_remove, /* Power Management Hooks */ .suspend = atl2_suspend, #ifdef CONFIG_PM @@ -1728,7 +1702,7 @@ static struct pci_driver atl2_driver = { .shutdown = atl2_shutdown, }; -/* +/** * atl2_init_module - Driver Registration Routine * * atl2_init_module is the first routine called when the driver is @@ -1743,7 +1717,7 @@ static int __init atl2_init_module(void) } module_init(atl2_init_module); -/* +/** * atl2_exit_module - Driver Exit Cleanup Routine * * atl2_exit_module is called just before the driver is removed @@ -1795,8 +1769,8 @@ static int atl2_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; @@ -2130,11 +2104,6 @@ static const struct ethtool_ops atl2_ethtool_ops = { .set_eeprom = atl2_set_eeprom, }; -static void atl2_set_ethtool_ops(struct net_device *netdev) -{ - SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops); -} - #define LBYTESWAP(a) ((((a) & 0x00ff00ff) << 8) | \ (((a) & 0xff00ff00) >> 8)) #define LONGSWAP(a) ((LBYTESWAP(a) << 16) | (LBYTESWAP(a) >> 16)) @@ -2258,7 +2227,7 @@ static int get_permanent_address(struct atl2_hw *hw) u32 Addr[2]; u32 i, Control; u16 Register; - u8 EthAddr[NODE_ADDRESS_SIZE]; + u8 EthAddr[ETH_ALEN]; bool KeyValid; if (is_valid_ether_addr(hw->perm_mac_addr)) @@ -2299,7 +2268,7 @@ static int get_permanent_address(struct atl2_hw *hw) *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *) &Addr[1]); if (is_valid_ether_addr(EthAddr)) { - memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); + memcpy(hw->perm_mac_addr, EthAddr, ETH_ALEN); return 0; } return 1; @@ -2334,7 +2303,7 @@ static int get_permanent_address(struct atl2_hw *hw) *(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]); *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *)&Addr[1]); if (is_valid_ether_addr(EthAddr)) { - memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); + memcpy(hw->perm_mac_addr, EthAddr, ETH_ALEN); return 0; } /* maybe MAC-address is from BIOS */ @@ -2344,7 +2313,7 @@ static int get_permanent_address(struct atl2_hw *hw) *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *) &Addr[1]); if (is_valid_ether_addr(EthAddr)) { - memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); + memcpy(hw->perm_mac_addr, EthAddr, ETH_ALEN); return 0; } @@ -2358,11 +2327,9 @@ static int get_permanent_address(struct atl2_hw *hw) */ static s32 atl2_read_mac_addr(struct atl2_hw *hw) { - u16 i; - if (get_permanent_address(hw)) { /* for test */ - /* FIXME: shouldn't we use random_ether_addr() here? */ + /* FIXME: shouldn't we use eth_random_addr() here? */ hw->perm_mac_addr[0] = 0x00; hw->perm_mac_addr[1] = 0x13; hw->perm_mac_addr[2] = 0x74; @@ -2371,8 +2338,7 @@ static s32 atl2_read_mac_addr(struct atl2_hw *hw) hw->perm_mac_addr[5] = 0x38; } - for (i = 0; i < NODE_ADDRESS_SIZE; i++) - hw->mac_addr[i] = hw->perm_mac_addr[i]; + memcpy(hw->mac_addr, hw->perm_mac_addr, ETH_ALEN); return 0; } @@ -2862,12 +2828,12 @@ static void atl2_force_ps(struct atl2_hw *hw) */ #define ATL2_PARAM(X, desc) \ - static const int __devinitdata X[ATL2_MAX_NIC + 1] = ATL2_PARAM_INIT; \ + static const int X[ATL2_MAX_NIC + 1] = ATL2_PARAM_INIT; \ MODULE_PARM(X, "1-" __MODULE_STRING(ATL2_MAX_NIC) "i"); \ MODULE_PARM_DESC(X, desc); #else #define ATL2_PARAM(X, desc) \ - static int __devinitdata X[ATL2_MAX_NIC+1] = ATL2_PARAM_INIT; \ + static int X[ATL2_MAX_NIC+1] = ATL2_PARAM_INIT; \ static unsigned int num_##X; \ module_param_array_named(X, X, int, &num_##X, 0); \ MODULE_PARM_DESC(X, desc); @@ -2951,7 +2917,7 @@ struct atl2_option { } arg; }; -static int __devinit atl2_validate_option(int *value, struct atl2_option *opt) +static int atl2_validate_option(int *value, struct atl2_option *opt) { int i; struct atl2_opt_list *ent; @@ -3000,7 +2966,7 @@ static int __devinit atl2_validate_option(int *value, struct atl2_option *opt) return -1; } -/* +/** * atl2_check_options - Range Checking for Command Line Parameters * @adapter: board private structure * @@ -3009,7 +2975,7 @@ static int __devinit atl2_validate_option(int *value, struct atl2_option *opt) * value exists, a default value is used. The final value is stored * in a variable in the adapter structure. */ -static void __devinit atl2_check_options(struct atl2_adapter *adapter) +static void atl2_check_options(struct atl2_adapter *adapter) { int val; struct atl2_option opt; diff --git a/drivers/net/ethernet/atheros/atlx/atl2.h b/drivers/net/ethernet/atheros/atlx/atl2.h index bf9016ebdd9..2f27d4c4c3a 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.h +++ b/drivers/net/ethernet/atheros/atlx/atl2.h @@ -42,12 +42,11 @@ #include "atlx.h" #ifdef ETHTOOL_OPS_COMPAT -extern int ethtool_ioctl(struct ifreq *ifr); +int ethtool_ioctl(struct ifreq *ifr); #endif #define PCI_COMMAND_REGISTER PCI_COMMAND #define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE -#define ETH_ADDR_LEN ETH_ALEN #define ATL2_WRITE_REG(a, reg, value) (iowrite32((value), \ ((a)->hw_addr + (reg)))) @@ -429,8 +428,8 @@ struct atl2_hw { u8 flash_vendor; u8 dma_fairness; - u8 mac_addr[NODE_ADDRESS_SIZE]; - u8 perm_mac_addr[NODE_ADDRESS_SIZE]; + u8 mac_addr[ETH_ALEN]; + u8 perm_mac_addr[ETH_ALEN]; /* FIXME */ /* bool phy_preamble_sup; */ diff --git a/drivers/net/ethernet/atheros/atlx/atlx.c b/drivers/net/ethernet/atheros/atlx/atlx.c index 8ff7411094d..46a622cceee 100644 --- a/drivers/net/ethernet/atheros/atlx/atlx.c +++ b/drivers/net/ethernet/atheros/atlx/atlx.c @@ -64,7 +64,7 @@ static int atlx_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } } -/* +/** * atlx_set_mac - Change the Ethernet Address of the NIC * @netdev: network interface device structure * @p: pointer to an address structure @@ -114,7 +114,7 @@ static void atlx_check_for_link(struct atlx_adapter *adapter) schedule_work(&adapter->link_chg_task); } -/* +/** * atlx_set_multi - Multicast and Promiscuous mode set * @netdev: network interface device structure * @@ -154,24 +154,31 @@ static void atlx_set_multi(struct net_device *netdev) } } -/* +static inline void atlx_imr_set(struct atlx_adapter *adapter, + unsigned int imr) +{ + iowrite32(imr, adapter->hw.hw_addr + REG_IMR); + ioread32(adapter->hw.hw_addr + REG_IMR); +} + +/** * atlx_irq_enable - Enable default interrupt generation settings * @adapter: board private structure */ static void atlx_irq_enable(struct atlx_adapter *adapter) { - iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR); - ioread32(adapter->hw.hw_addr + REG_IMR); + atlx_imr_set(adapter, IMR_NORMAL_MASK); + adapter->int_enabled = true; } -/* +/** * atlx_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure */ static void atlx_irq_disable(struct atlx_adapter *adapter) { - iowrite32(0, adapter->hw.hw_addr + REG_IMR); - ioread32(adapter->hw.hw_addr + REG_IMR); + adapter->int_enabled = false; + atlx_imr_set(adapter, 0); synchronize_irq(adapter->pdev->irq); } @@ -185,7 +192,7 @@ static void atlx_clear_phy_int(struct atlx_adapter *adapter) spin_unlock_irqrestore(&adapter->lock, flags); } -/* +/** * atlx_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure */ @@ -193,7 +200,7 @@ static void atlx_tx_timeout(struct net_device *netdev) { struct atlx_adapter *adapter = netdev_priv(netdev); /* Do the reset outside of interrupt context */ - schedule_work(&adapter->tx_timeout_task); + schedule_work(&adapter->reset_dev_task); } /* @@ -213,7 +220,7 @@ static void atlx_link_chg_task(struct work_struct *work) static void __atlx_vlan_mode(netdev_features_t features, u32 *ctrl) { - if (features & NETIF_F_HW_VLAN_RX) { + if (features & NETIF_F_HW_VLAN_CTAG_RX) { /* enable VLAN tag insert/strip */ *ctrl |= MAC_CTRL_RMV_VLAN; } else { @@ -250,10 +257,10 @@ static netdev_features_t atlx_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; return features; } @@ -263,7 +270,7 @@ static int atlx_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) atlx_vlan_mode(netdev, features); return 0; diff --git a/drivers/net/ethernet/atheros/atlx/atlx.h b/drivers/net/ethernet/atheros/atlx/atlx.h index 14054b75aa6..448f5dcc02e 100644 --- a/drivers/net/ethernet/atheros/atlx/atlx.h +++ b/drivers/net/ethernet/atheros/atlx/atlx.h @@ -484,7 +484,6 @@ /* For checksumming, the sum of all words in the EEPROM should equal 0xBABA */ #define EEPROM_SUM 0xBABA -#define NODE_ADDRESS_SIZE 6 struct atlx_spi_flash_dev { const char *manu_name; /* manufacturer id */ |
