diff mbox

atl1c:Atheros L1C Gigabit Ethernet driver

Message ID 1234161271580-git-send-email-jie.yang@atheros.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

jie.yang@atheros.com Feb. 9, 2009, 6:34 a.m. UTC
From: Jie Yang <jie.yang@atheros.com>

Supporting AR8131, and AR8132.

Signed-off-by: Jie Yang <jie.yang@atheros.com>
---

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

David Miller Feb. 9, 2009, 7:18 a.m. UTC | #1
From: <jie.yang@atheros.com>
Date: Mon, 9 Feb 2009 14:34:31 +0800


> +#define PCI_REG_COMMAND	 0x04    /* PCI Command Register */
> +#define CMD_IO_SPACE	 0x0001
> +#define CMD_MEMORY_SPACE 0x0002
> +#define CMD_BUS_MASTER   0x0004

Use definitions in linux/pci_regs.h, instead of inventing
your own.

> +
> +#define BAR_0   0
> +#define BAR_1   1
> +#define BAR_5   5

Likewise.

> +/* Error Codes */
> +#define AT_ERR_EEPROM      1
> +#define AT_ERR_PHY         2
> +#define AT_ERR_CONFIG      3
> +#define AT_ERR_PARAM       4
> +#define AT_ERR_MAC_TYPE    5
> +#define AT_ERR_PHY_TYPE    6
> +#define AT_ERR_PHY_SPEED   7
> +#define AT_ERR_PHY_RES     8
> +#define AT_ERR_TIMEOUT     9

Please do not invent your own error code system, use existing ones.
Otherwise your code is hard for others to understand and review.

> +#define AT_RX_BUF_SIZE		1536

How is this number derived?  Is it ETH_DATA_LEN or ETH_FRAME_LEN
plus some constant or other importnat value?  If so, please
define it as a sum of those descriptive macro values.

> +#define AT_REGS_LEN	75

This definition is really confusing.  It's not the length
of the chip register area, it's the number of registers
the chip has.

Every use in the driver multiplies this value by
"sizeof(u32)".  Just define this macro to "75 * sizeof(u32)"
and update the macro users accordingly.

> +struct atl1c_tpd_desc {
> +	__le16	buffer_len; /* include 4-byte CRC */
> +	u16	vlan_tag;
> +	__le32	word1;
> +	__le64	buffer_addr;
> +};

Is the vlan_tag stored in little or big endian?  I find it
unlikely that it is stored in cpu-endianness, so an
endian typed vlan_tag should be specified here.

The AT_TAG_TO_VLAN() macro will need to be updated to match
whatever endianness this value is stored in.

> +struct atl1c_recv_ret_status {
> +	__le32  word0;
> +	u32	rss_hash;
> +	u16	vlan_tag;
> +	u16	flag;
> +	__le32	word3;
> +};

Well, what endianness are these values stored in?  Cpu endianness?
If not, endian specific types and accessors need to be used here.

> +	u16 autoneg_advertised;
> +#define ADVERTISE_10_HALF               0x0001
> +#define ADVERTISE_10_FULL               0x0002
> +#define ADVERTISE_100_HALF              0x0004
> +#define ADVERTISE_100_FULL              0x0008
> +#define ADVERTISE_1000_HALF             0x0010 /* Not used, just FYI */
> +#define ADVERTISE_1000_FULL             0x0020
> +#define ADVERTISE_DEFAULT (ADVERTISE_10_HALF  |\
> +			   ADVERTISE_10_FULL  |\
> +			   ADVERTISE_100_HALF |\
> +			   ADVERTISE_100_FULL |\
> +			   ADVERTISE_1000_FULL)

Having these self-defined local macros with similar names
as the defines found in linux/mii.h (which also form a bitmask
that fits in 16-bits) is confusing.

Please use the linux/mii.h values here.

> +	if (control & EEPROM_CTRL_RW) {
> +		AT_READ_REG(hw, REG_EEPROM_CTRL, &data);
> +		AT_READ_REG(hw, REG_EEPROM_DATA_LO, p_value);
> +		data = data & 0xFFFF;
> +		*p_value = swab32((data << 16) | (*p_value >> 16));
> +		ret = true;
> +	}

Please make sure the endianness works out properly here,
even on big-endian systems.

I think it's right, but it's worth double checking.

> +#if 0
> +int atl1c_phy_commit(struct atl1c_hw *hw)

Please just elide this code from the driver, you can add
it in when a use is created.

> +static void atl1c_phy_magic_data(struct atl1c_hw *hw)
> +{
> +	u16 data;
> +
> +	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x12);
> +	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x4C04);
> +
> +	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x05);
> +	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x2C46);
> +
> +	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x36);
> +	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xE12C);
> +
> +	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x04);
> +	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x88BB);
> +
> +	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
> +	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x02EF);

No magic constants please, document these MII PHY registers and what
bits and values you are setting into them, using appropriate register
offset and value macros.

I am pretty sure you can find out what these register writes are
doing, and thus be able to document them properly :-)

> +/* register definition */
> +#define REG_PM_CTRLSTAT             	0x44
> +#define PM_CTRLSTAT_PME_EN		0x100

All of these PCI config space registers should either use
the definitions in linux/pci_reg.h or the appropriate
extended PCI config space register probing mechanisms such
as pci_find_capability().

pci_find_capability() is the correct way to find the PM,
VPD, PCI-E etc. extended register areas.


> +			netif_carrier_on(netdev);
> +			netif_wake_queue(netdev);
 ...
> +			netif_carrier_off(netdev);
> +			netif_stop_queue(netdev);

Doing a carrier state change as well as a queue wake/stop is
redundant.  Setting the carrier off is enough to stop packet
flow on transmit to the device.  And likewise setting the
carrier on is enough to (re-)start packet flow for transmit.

> +static int atl1c_clean(struct napi_struct *napi, int budget)
> +{
> +	struct atl1c_adapter *adapter =
> +			container_of(napi, struct atl1c_adapter, napi);
> +	int work_done = 0;
> +	int i;
> +
> +	/* Keep link state information with original netdev */
> +	if (!netif_carrier_ok(adapter->netdev))
> +		goto quit_polling;
> +
> +	for (i = 0; i < adapter->num_rx_queues; i++)
> +		atl1c_clean_rx_irq(adapter, i, &work_done, budget);

This is going to perform very poorly.  You should instantiate
a seperate NAPI instance for each RX queue, and only schedule NAPI
for those specific RX queues which indicate RX packets are available
at interrupt time.

Otherwise having seperate RX queues is pointless, as all of the SMP
locking gains from RX seperation will not be realized.

If it is not possible to implement things this way, either because
it is very difficult or impossible due to the interrupt architecture
of the chip, then please just use one RX queue at this time.  You
can add the RX multi-queue support back later once it is implemented
properly.

> +	netdev->open = &atl1c_open;
> +	netdev->stop = &atl1c_close;
> +	netdev->hard_start_xmit = &atl1c_xmit_frame;
> +	netdev->get_stats = &atl1c_get_stats;
> +	netdev->set_multicast_list = &atl1c_set_multi;
> +	netdev->set_mac_address = &atl1c_set_mac_addr;
> +	netdev->change_mtu = &atl1c_change_mtu;
> +	netdev->do_ioctl = &atl1c_ioctl;
> +	netdev->tx_timeout = &atl1c_tx_timeout;

Please use net_device_ops, the function pointer initialization method
you are using here is deprecated and will be eliminated at some point
in the future.

> +	/* enable device (incl. PCI PM wakeup and hotplug setup) */
> +	err = pci_enable_device(pdev);
> +	if (err) {
> +		dev_err(&pdev->dev, "cannot enable PCI device\n");
> +		return err;
> +	}

Please use pci_enable_device_mem() if only MEM space register
accesses will be used.


> +	/* get user settings */
> +	atl1c_check_options(adapter);

Please do not use module parameters for network device
configuration knobs.

Many of the controls you have specified are supported by
ethtool, and that is the consistent interface we have for
users to make these setting changes.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
J. K. Cliburn Feb. 11, 2009, 1:18 a.m. UTC | #2
Hello Jie,

Net driver stuff goes to Dave Miller now, not Jeff Garzik.

On Mon, 9 Feb 2009 14:34:31 +0800
<jie.yang@atheros.com> wrote:

> From: Jie Yang <jie.yang@atheros.com>
> 
> Supporting AR8131, and AR8132.
> 
> Signed-off-by: Jie Yang <jie.yang@atheros.com>
> ---
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 62bc022..cdb8c46 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -2350,6 +2350,17 @@ config ATL1E
>  	  To compile this driver as a module, choose M here.  The module
>  	  will be called atl1e.
>  
> +config ATL1C
> +	tristate "Atheros L1C Gigabit Ethernet support (EXPERIMENTAL)"
> +	depends on PCI && EXPERIMENTAL
> +	select CRC32
> +	select MII
> +	help
> +	  This driver supports the Atheros L1C gigabit ethernet adapter.
> +
> +	  To compile this driver as a module, choose M here.  The module
> +	  will be called atl1c.
> +
>  config JME
>  	tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
>  	depends on PCI
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index ad87ba7..3f8cb31 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_BONDING) += bonding/
>  obj-$(CONFIG_ATL1) += atlx/
>  obj-$(CONFIG_ATL2) += atlx/
>  obj-$(CONFIG_ATL1E) += atl1e/
> +obj-$(CONFIG_ATL1C) += atl1c/
>  obj-$(CONFIG_GIANFAR) += gianfar_driver.o
>  obj-$(CONFIG_TEHUTI) += tehuti.o
>  obj-$(CONFIG_ENIC) += enic/
> diff --git a/drivers/net/atl1c/Makefile b/drivers/net/atl1c/Makefile
> new file mode 100644
> index 0000000..a2214a6
> --- /dev/null
> +++ b/drivers/net/atl1c/Makefile
> @@ -0,0 +1,2 @@
> +obj-$(CONFIG_ATL1C) += atl1c.o
> +atl1c-objs := atl1c_main.o atl1c_hw.o atl1c_ethtool.o atl1c_param.o
> diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
> new file mode 100644
> index 0000000..118c9a7
> --- /dev/null
> +++ b/drivers/net/atl1c/atl1c.h
> @@ -0,0 +1,643 @@
> +/*
> + * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
> + *
> + * Derived from Intel e1000 driver
> + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
> + * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
> + */
> +
> +#ifndef _ATL1C_H_
> +#define _ATL1C_H_
> +
> +#include <linux/version.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/netdevice.h>
> +#include <linux/etherdevice.h>
> +#include <linux/skbuff.h>
> +#include <linux/ioport.h>
> +#include <linux/slab.h>
> +#include <linux/list.h>
> +#include <linux/delay.h>
> +#include <linux/sched.h>
> +#include <linux/in.h>
> +#include <linux/ip.h>
> +#include <linux/ipv6.h>
> +#include <linux/udp.h>
> +#include <linux/mii.h>
> +#include <linux/io.h>
> +#include <linux/vmalloc.h>
> +#include <linux/pagemap.h>
> +#include <linux/tcp.h>
> +#include <linux/mii.h>
> +#include <linux/ethtool.h>
> +#include <linux/if_vlan.h>
> +#include <linux/workqueue.h>
> +#include <net/checksum.h>
> +#include <net/ip6_checksum.h>
> +
> +#include "atl1c_hw.h"
> +
> +#define PCI_REG_COMMAND	 0x04    /* PCI Command Register */
> +#define CMD_IO_SPACE	 0x0001
> +#define CMD_MEMORY_SPACE 0x0002
> +#define CMD_BUS_MASTER   0x0004
> +
> +#define BAR_0   0
> +#define BAR_1   1
> +#define BAR_5   5
> +
> +/* Wake Up Filter Control */
> +#define AT_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
> +#define AT_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
> +#define AT_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
> +#define AT_WUFC_MC   0x00000008 /* Multicast Wakeup Enable */
> +#define AT_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
> +
> +#define AT_VLAN_TO_TAG(_vlan, _tag)	   \
> +	_tag =  ((((_vlan) >> 8) & 0xF0)  |\
> +		 (((_vlan) & 0xFF) << 8)  |\
> +		 (((_vlan) & 0xF00) >> 8))
> +
> +#define AT_TAG_TO_VLAN(_tag, _vlan) 	 \
> +	_vlan = ((((_tag) >> 8) & 0xF)  |\
> +		(((_tag) & 0xF0) << 8)  |\
> +		(((_tag) & 0xF) >> 8))
> +
> +#define SPEED_0		   0xffff
> +#define HALF_DUPLEX        1
> +#define FULL_DUPLEX        2
> +
> +/* Error Codes */
> +#define AT_ERR_EEPROM      1
> +#define AT_ERR_PHY         2
> +#define AT_ERR_CONFIG      3
> +#define AT_ERR_PARAM       4
> +#define AT_ERR_MAC_TYPE    5
> +#define AT_ERR_PHY_TYPE    6
> +#define AT_ERR_PHY_SPEED   7
> +#define AT_ERR_PHY_RES     8
> +#define AT_ERR_TIMEOUT     9
> +
> +#define AT_RX_BUF_SIZE		1536
> +#define MAX_JUMBO_FRAME_SIZE 	(9*1024)
> +#define MAX_TX_OFFLOAD_THRESH	(9*1024)
> +
> +#define AT_MAX_RECEIVE_QUEUE    4
> +#define AT_DEF_RECEIVE_QUEUE	1
> +#define AT_MAX_TRANSMIT_QUEUE	2
> +
> +#define AT_DMA_HI_ADDR_MASK     0xffffffff00000000ULL
> +#define AT_DMA_LO_ADDR_MASK     0x00000000ffffffffULL
> +
> +#define AT_TX_WATCHDOG  (5 * HZ)
> +#define AT_MAX_INT_WORK		5
> +#define AT_TWSI_EEPROM_TIMEOUT 	100
> +#define AT_HW_MAX_IDLE_DELAY 	10
> +#define AT_SUSPEND_LINK_TIMEOUT 28
> +
> +#define AT_ASPM_L0S_TIMER	6
> +#define AT_ASPM_L1_TIMER	12
> +
> +#define ATL1C_PCIE_L0S_L1_DISABLE 	0x01
> +#define ATL1C_PCIE_PHY_RESET		0x02
> +
> +#define ATL1C_ASPM_L0s_ENABLE		0x0001
> +#define ATL1C_ASPM_L1_ENABLE		0x0002
> +
> +#define AT_REGS_LEN	75
> +#define AT_EEPROM_LEN 	512
> +#define AT_ADV_MASK	(ADVERTISE_10_HALF  |\
> +			 ADVERTISE_10_FULL  |\
> +			 ADVERTISE_100_HALF |\
> +			 ADVERTISE_100_FULL |\
> +			 ADVERTISE_1000_FULL)
> +#define ATL1C_GET_DESC(R, i, type)	(&(((type *)((R)->desc))[i]))
> +#define ATL1C_RFD_DESC(R, i)	ATL1C_GET_DESC(R, i, struct atl1c_rx_free_desc)
> +#define ATL1C_TPD_DESC(R, i)	ATL1C_GET_DESC(R, i, struct atl1c_tpd_desc)
> +#define ATL1C_RRD_DESC(R, i)	ATL1C_GET_DESC(R, i, struct atl1c_recv_ret_status)
> +
> +/* tpd word 1 bit 0:7 General Checksum task offload */
> +#define TPD_L4HDR_OFFSET_MASK	0x00FF
> +#define TPD_L4HDR_OFFSET_SHIFT	0
> +
> +/* tpd word 1 bit 0:7 Large Send task offload (IPv4/IPV6) */
> +#define TPD_TCPHDR_OFFSET_MASK	0x00FF
> +#define TPD_TCPHDR_OFFSET_SHIFT	0
> +
> +/* tpd word 1 bit 0:7 Custom Checksum task offload */
> +#define TPD_PLOADOFFSET_MASK	0x00FF
> +#define TPD_PLOADOFFSET_SHIFT	0
> +
> +/* tpd word 1 bit 8:17 */
> +#define TPD_CCSUM_EN_MASK	0x0001
> +#define TPD_CCSUM_EN_SHIFT	8
> +#define TPD_IP_CSUM_MASK	0x0001
> +#define TPD_IP_CSUM_SHIFT	9
> +#define TPD_TCP_CSUM_MASK	0x0001
> +#define TPD_TCP_CSUM_SHIFT	10
> +#define TPD_UDP_CSUM_MASK	0x0001
> +#define TPD_UDP_CSUM_SHIFT	11
> +#define TPD_LSO_EN_MASK		0x0001	/* TCP Large Send Offload */
> +#define TPD_LSO_EN_SHIFT	12
> +#define TPD_LSO_VER_MASK	0x0001
> +#define TPD_LSO_VER_SHIFT	13 	/* 0 : ipv4; 1 : ipv4/ipv6 */
> +#define TPD_CON_VTAG_MASK	0x0001
> +#define TPD_CON_VTAG_SHIFT	14
> +#define TPD_INS_VTAG_MASK	0x0001
> +#define TPD_INS_VTAG_SHIFT	15
> +#define TPD_IPV4_PACKET_MASK	0x0001  /* valid when LSO VER  is 1 */
> +#define TPD_IPV4_PACKET_SHIFT	16
> +#define TPD_ETH_TYPE_MASK	0x0001
> +#define TPD_ETH_TYPE_SHIFT	17	/* 0 : 802.3 frame; 1 : Ethernet */
> +
> +/* tpd word 18:25 Custom Checksum task offload */
> +#define TPD_CCSUM_OFFSET_MASK	0x00FF
> +#define TPD_CCSUM_OFFSET_SHIFT	18
> +#define TPD_CCSUM_EPAD_MASK	0x0001
> +#define TPD_CCSUM_EPAD_SHIFT	30
> +
> +/* tpd word 18:30 Large Send task offload (IPv4/IPV6) */
> +#define TPD_MSS_MASK            0x1FFF
> +#define TPD_MSS_SHIFT		18
> +
> +#define TPD_EOP_MASK		0x0001
> +#define TPD_EOP_SHIFT		31
> +
> +struct atl1c_tpd_desc {
> +	__le16	buffer_len; /* include 4-byte CRC */
> +	u16	vlan_tag;
> +	__le32	word1;
> +	__le64	buffer_addr;
> +};
> +
> +struct atl1c_tpd_ext_desc {
> +	u32 reservd_0;
> +	__le32 word1;
> +	__le32 pkt_len;
> +	u32 reservd_1;
> +};
> +/* rrs word 0 bit 0:31 */
> +#define RRS_RX_CSUM_MASK	0xFFFF
> +#define RRS_RX_CSUM_SHIFT	0
> +#define RRS_RX_RFD_CNT_MASK	0x000F
> +#define RRS_RX_RFD_CNT_SHIFT	16
> +#define RRS_RX_RFD_INDEX_MASK	0x0FFF
> +#define RRS_RX_RFD_INDEX_SHIFT	20
> +
> +/* rrs flag bit 0:16 */
> +#define RRS_HEAD_LEN_MASK	0x00FF
> +#define RRS_HEAD_LEN_SHIFT	0
> +#define RRS_HDS_TYPE_MASK	0x0003
> +#define RRS_HDS_TYPE_SHIFT	8
> +#define RRS_CPU_NUM_MASK	0x0003
> +#define	RRS_CPU_NUM_SHIFT	10
> +#define RRS_HASH_FLG_MASK	0x000F
> +#define RRS_HASH_FLG_SHIFT	12
> +
> +#define RRS_HDS_TYPE_HEAD	1
> +#define RRS_HDS_TYPE_DATA	2
> +
> +#define RRS_IS_NO_HDS_TYPE(flag) \
> +	(((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == 0)
> +
> +#define RRS_IS_HDS_HEAD(flag) \
> +	(((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \
> +			RRS_HDS_TYPE_HEAD)
> +
> +#define RRS_IS_HDS_DATA(flag) \
> +	(((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \
> +			RRS_HDS_TYPE_DATA)
> +
> +/* rrs word 3 bit 0:31 */
> +#define RRS_PKT_SIZE_MASK	0x3FFF
> +#define RRS_PKT_SIZE_SHIFT	0
> +#define RRS_ERR_L4_CSUM_MASK	0x0001
> +#define RRS_ERR_L4_CSUM_SHIFT	14
> +#define RRS_ERR_IP_CSUM_MASK	0x0001
> +#define RRS_ERR_IP_CSUM_SHIFT	15
> +#define RRS_VLAN_INS_MASK	0x0001
> +#define RRS_VLAN_INS_SHIFT	16
> +#define RRS_PROT_ID_MASK	0x0007
> +#define RRS_PROT_ID_SHIFT	17
> +#define RRS_RX_ERR_SUM_MASK	0x0001
> +#define RRS_RX_ERR_SUM_SHIFT	20
> +#define RRS_RX_ERR_CRC_MASK	0x0001
> +#define RRS_RX_ERR_CRC_SHIFT	21
> +#define RRS_RX_ERR_FAE_MASK	0x0001
> +#define RRS_RX_ERR_FAE_SHIFT	22
> +#define RRS_RX_ERR_TRUNC_MASK	0x0001
> +#define RRS_RX_ERR_TRUNC_SHIFT	23
> +#define RRS_RX_ERR_RUNC_MASK	0x0001
> +#define RRS_RX_ERR_RUNC_SHIFT	24
> +#define RRS_RX_ERR_ICMP_MASK	0x0001
> +#define RRS_RX_ERR_ICMP_SHIFT	25
> +#define RRS_PACKET_BCAST_MASK	0x0001
> +#define RRS_PACKET_BCAST_SHIFT	26
> +#define RRS_PACKET_MCAST_MASK	0x0001
> +#define RRS_PACKET_MCAST_SHIFT	27
> +#define RRS_PACKET_TYPE_MASK	0x0001
> +#define RRS_PACKET_TYPE_SHIFT	28
> +#define RRS_FIFO_FULL_MASK	0x0001
> +#define RRS_FIFO_FULL_SHIFT	29
> +#define RRS_802_3_LEN_ERR_MASK 	0x0001
> +#define RRS_802_3_LEN_ERR_SHIFT 30
> +#define RRS_RXD_UPDATED_MASK	0x0001
> +#define RRS_RXD_UPDATED_SHIFT	31
> +
> +#define RRS_ERR_L4_CSUM         0x00004000
> +#define RRS_ERR_IP_CSUM         0x00008000
> +#define RRS_VLAN_INS            0x00010000
> +#define RRS_RX_ERR_SUM          0x00100000
> +#define RRS_RX_ERR_CRC          0x00200000
> +#define RRS_802_3_LEN_ERR	0x40000000
> +#define RRS_RXD_UPDATED		0x80000000
> +
> +#define RRS_PACKET_TYPE_802_3  	1
> +#define RRS_PACKET_TYPE_ETH	0
> +#define RRS_PACKET_IS_ETH(word) \
> +	(((word) >> RRS_PACKET_TYPE_SHIFT) & RRS_PACKET_TYPE_MASK == \
> +			RRS_PACKET_TYPE_ETH)
> +#define RRS_RXD_IS_VALID(word) \
> +	((((word) >> RRS_RXD_UPDATED_SHIFT) & RRS_RXD_UPDATED_MASK) == 1)
> +
> +#define RRS_PACKET_PROT_IS_IPV4_ONLY(word) \
> +	((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 1)
> +#define RRS_PACKET_PROT_IS_IPV6_ONLY(word) \
> +	((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 6)
> +
> +struct atl1c_recv_ret_status {
> +	__le32  word0;
> +	u32	rss_hash;
> +	u16	vlan_tag;
> +	u16	flag;
> +	__le32	word3;
> +};
> +
> +/* RFD desciptor */
> +struct atl1c_rx_free_desc {
> +	__le64	buffer_addr;
> +};
> +
> +/* DMA Order Settings */
> +enum atl1c_dma_order {
> +	atl1c_dma_ord_in = 1,
> +	atl1c_dma_ord_enh = 2,
> +	atl1c_dma_ord_out = 4
> +};
> +
> +enum atl1c_dma_rcb {
> +	atl1c_rcb_64 = 0,
> +	atl1c_rcb_128 = 1
> +};
> +
> +enum atl1c_mac_speed {
> +	atl1c_mac_speed_0 = 0,
> +	atl1c_mac_speed_10_100 = 1,
> +	atl1c_mac_speed_1000 = 2
> +};
> +
> +enum atl1c_dma_req_block {
> +	atl1c_dma_req_128 = 0,
> +	atl1c_dma_req_256 = 1,
> +	atl1c_dma_req_512 = 2,
> +	atl1c_dma_req_1024 = 3,
> +	atl1c_dma_req_2048 = 4,
> +	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,
> +	athr_l2c = 1,
> +};
> +
> +enum atl1c_trans_queue {
> +	atl1c_trans_normal = 0,
> +	atl1c_trans_high = 1
> +};
> +
> +struct atl1c_hw_stats {
> +	/* rx */
> +	unsigned long rx_ok;		/* The number of good packet received. */
> +	unsigned long rx_bcast;		/* The number of good broadcast packet received. */
> +	unsigned long rx_mcast;		/* The number of good multicast packet received. */
> +	unsigned long rx_pause;		/* The number of Pause packet received. */
> +	unsigned long rx_ctrl;		/* The number of Control packet received other than Pause frame. */
> +	unsigned long rx_fcs_err;	/* The number of packets with bad FCS. */
> +	unsigned long rx_len_err;	/* The number of packets with mismatch of length field and actual size. */
> +	unsigned long rx_byte_cnt;	/* The number of bytes of good packet received. FCS is NOT included. */
> +	unsigned long rx_runt;		/* The number of packets received that are less than 64 byte long and with good FCS. */
> +	unsigned long rx_frag;		/* The number of packets received that are less than 64 byte long and with bad FCS. */
> +	unsigned long rx_sz_64;		/* The number of good and bad packets received that are 64 byte long. */
> +	unsigned long rx_sz_65_127;	/* The number of good and bad packets received that are between 65 and 127-byte long. */
> +	unsigned long rx_sz_128_255;	/* The number of good and bad packets received that are between 128 and 255-byte long. */
> +	unsigned long rx_sz_256_511;	/* The number of good and bad packets received that are between 256 and 511-byte long. */
> +	unsigned long rx_sz_512_1023;	/* The number of good and bad packets received that are between 512 and 1023-byte long. */
> +	unsigned long rx_sz_1024_1518;	/* The number of good and bad packets received that are between 1024 and 1518-byte long. */
> +	unsigned long rx_sz_1519_max;	/* The number of good and bad packets received that are between 1519-byte and MTU. */
> +	unsigned long rx_sz_ov;		/* The number of good and bad packets received that are more than MTU size truncated by Selene. */
> +	unsigned long rx_rxf_ov;	/* The number of frame dropped due to occurrence of RX FIFO overflow. */
> +	unsigned long rx_rrd_ov;	/* The number of frame dropped due to occurrence of RRD overflow. */
> +	unsigned long rx_align_err;	/* Alignment Error */
> +	unsigned long rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */
> +	unsigned long rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */
> +	unsigned long rx_err_addr;	/* The number of packets dropped due to address filtering. */
> +
> +	/* tx */
> +	unsigned long tx_ok;		/* The number of good packet transmitted. */
> +	unsigned long tx_bcast;		/* The number of good broadcast packet transmitted. */
> +	unsigned long tx_mcast;		/* The number of good multicast packet transmitted. */
> +	unsigned long tx_pause;		/* The number of Pause packet transmitted. */
> +	unsigned long tx_exc_defer;	/* The number of packets transmitted with excessive deferral. */
> +	unsigned long tx_ctrl;		/* The number of packets transmitted is a control frame, excluding Pause frame. */
> +	unsigned long tx_defer;		/* The number of packets transmitted that is deferred. */
> +	unsigned long tx_byte_cnt;	/* The number of bytes of data transmitted. FCS is NOT included. */
> +	unsigned long tx_sz_64;		/* The number of good and bad packets transmitted that are 64 byte long. */
> +	unsigned long tx_sz_65_127;	/* The number of good and bad packets transmitted that are between 65 and 127-byte long. */
> +	unsigned long tx_sz_128_255;	/* The number of good and bad packets transmitted that are between 128 and 255-byte long. */
> +	unsigned long tx_sz_256_511;	/* The number of good and bad packets transmitted that are between 256 and 511-byte long. */
> +	unsigned long tx_sz_512_1023;	/* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */
> +	unsigned long tx_sz_1024_1518;	/* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */
> +	unsigned long tx_sz_1519_max;	/* The number of good and bad packets transmitted that are between 1519-byte and MTU. */
> +	unsigned long tx_1_col;		/* The number of packets subsequently transmitted successfully with a single prior collision. */
> +	unsigned long tx_2_col;		/* The number of packets subsequently transmitted successfully with multiple prior collisions. */
> +	unsigned long tx_late_col;	/* The number of packets transmitted with late collisions. */
> +	unsigned long tx_abort_col;	/* The number of transmit packets aborted due to excessive collisions. */
> +	unsigned long tx_underrun;	/* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
> +	unsigned long tx_rd_eop;	/* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */
> +	unsigned long tx_len_err;	/* The number of transmit packets with length field does NOT match the actual frame size. */
> +	unsigned long tx_trunc;		/* The number of transmit packets truncated due to size exceeding MTU. */
> +	unsigned long tx_bcast_byte;	/* The byte count of broadcast packet transmitted, excluding FCS. */
> +	unsigned long tx_mcast_byte;	/* The byte count of multicast packet transmitted, excluding FCS. */
> +};
> +
> +struct atl1c_hw {
> +	u8 __iomem      *hw_addr;            /* inner register address */
> +	struct atl1c_adapter *adapter;
> +	enum atl1c_nic_type  nic_type;
> +	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;
> +	u16 subsystem_id;
> +	u16 subsystem_vendor_id;
> +	u8 revision_id;
> +
> +	u32 intr_mask;
> +	u8 dmaw_dly_cnt;
> +	u8 dmar_dly_cnt;
> +
> +	u8 preamble_len;
> +	u16 max_frame_size;
> +	u16 min_frame_size;
> +
> +	enum atl1c_mac_speed mac_speed;
> +	bool mac_duplex;
> +	bool hibernate;
> +	u16 media_type;
> +#define MEDIA_TYPE_AUTO_SENSOR  0
> +#define MEDIA_TYPE_100M_FULL    1
> +#define MEDIA_TYPE_100M_HALF    2
> +#define MEDIA_TYPE_10M_FULL     3
> +#define MEDIA_TYPE_10M_HALF     4
> +
> +	u16 autoneg_advertised;
> +#define ADVERTISE_10_HALF               0x0001
> +#define ADVERTISE_10_FULL               0x0002
> +#define ADVERTISE_100_HALF              0x0004
> +#define ADVERTISE_100_FULL              0x0008
> +#define ADVERTISE_1000_HALF             0x0010 /* Not used, just FYI */
> +#define ADVERTISE_1000_FULL             0x0020
> +#define ADVERTISE_DEFAULT (ADVERTISE_10_HALF  |\
> +			   ADVERTISE_10_FULL  |\
> +			   ADVERTISE_100_HALF |\
> +			   ADVERTISE_100_FULL |\
> +			   ADVERTISE_1000_FULL)
> +	u16 mii_autoneg_adv_reg;
> +	u16 mii_1000t_ctrl_reg;
> +
> +	u16 tx_imt;	/* TX Interrupt Moderator timer ( 2us resolution) */
> +	u16 rx_imt;	/* RX Interrupt Moderator timer ( 2us resolution) */
> +	u16 ict;        /* Interrupt Clear timer (2us resolution) */
> +	u16 ctrl_flags;
> +#define ATL1C_INTR_CLEAR_ON_READ	0x0001
> +#define ATL1C_INTR_MODRT_ENABLE	 	0x0002
> +#define ATL1C_CMB_ENABLE		0x0004
> +#define ATL1C_SMB_ENABLE		0x0010
> +#define ATL1C_TXQ_MODE_ENHANCE		0x0020
> +#define ATL1C_RX_IPV6_CHKSUM		0x0040
> +#define ATL1C_ASPM_L0S_SUPPORT		0x0080
> +#define ATL1C_ASPM_L1_SUPPORT		0x0100
> +#define ATL1C_ASPM_CTRL_MON		0x0200
> +#define ATL1C_HIB_DISABLE		0x0400
> +#define ATL1C_LINK_CAP_1000M		0x0800
> +#define ATL1C_FPGA_VERSION		0x8000
> +	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
> +			  interrupt request */
> +	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];
> +	u8 perm_mac_addr[ETH_ALEN];
> +
> +	bool phy_configured;
> +	bool re_autoneg;
> +	bool emi_ca;
> +};
> +
> +/*
> + * 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
> + */
> +struct atl1c_ring_header {
> +	void *desc;		/* virtual address */
> +	dma_addr_t dma;		/* physical address*/
> +	unsigned int size;	/* length in bytes */
> +};
> +
> +/*
> + * atl1c_buffer is wrapper around a pointer to a socket buffer
> + * so a DMA handle can be stored along with the skb
> + */
> +struct atl1c_buffer {
> +	struct sk_buff *skb;	/* socket buffer */
> +	u16 length;		/* rx buffer length */
> +	u16 state;		/* state of buffer */
> +#define ATL1_BUFFER_FREE	0
> +#define ATL1_BUFFER_BUSY	1
> +	dma_addr_t dma;
> +};
> +
> +/* transimit packet descriptor (tpd) ring */
> +struct atl1c_tpd_ring {
> +	void *desc;		/* descriptor ring virtual address */
> +	dma_addr_t dma;		/* descriptor ring physical address */
> +	u16 size;		/* descriptor ring length in bytes */
> +	u16 count;		/* number of descriptors in the ring */
> +	u16 next_to_use; 	/* this is protectd by adapter->tx_lock */
> +	atomic_t next_to_clean;
> +	struct atl1c_buffer *buffer_info;
> +};
> +
> +/* receive free descriptor (rfd) ring */
> +struct atl1c_rfd_ring {
> +	void *desc;		/* descriptor ring virtual address */
> +	dma_addr_t dma;		/* descriptor ring physical address */
> +	u16 size;		/* descriptor ring length in bytes */
> +	u16 count;		/* number of descriptors in the ring */
> +	u16 next_to_use;
> +	u16 next_to_clean;
> +	struct atl1c_buffer *buffer_info;
> +};
> +
> +/* receive return desciptor (rrd) ring */
> +struct atl1c_rrd_ring {
> +	void *desc;		/* descriptor ring virtual address */
> +	dma_addr_t dma;		/* descriptor ring physical address */
> +	u16 size;		/* descriptor ring length in bytes */
> +	u16 count;		/* number of descriptors in the ring */
> +	u16 next_to_use;
> +	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 vlan_group   *vlgrp;
> +	struct napi_struct  napi;
> +	struct atl1c_hw        hw;
> +	struct atl1c_hw_stats  hw_stats;
> +	struct net_device_stats net_stats;
> +	struct mii_if_info  mii;    /* MII interface info */
> +	u16 rx_buffer_len;
> +
> +	unsigned long flags;
> +#define __AT_TESTING        0x0001
> +#define __AT_RESETTING      0x0002
> +#define __AT_DOWN           0x0003
> +
> +	bool have_msi;
> +	u32 wol;
> +	u16 link_speed;
> +	u16 link_duplex;
> +
> +	spinlock_t mdio_lock;
> +	spinlock_t tx_lock;
> +	atomic_t irq_sem;
> +
> +	struct work_struct reset_task;
> +	struct work_struct link_chg_task;
> +	struct timer_list watchdog_timer;
> +	struct timer_list phy_config_timer;
> +
> +	/* 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;
> +	u32 bd_number;     /* board number;*/
> +};
> +
> +#define AT_WRITE_REG(a, reg, value) ( \
> +		writel((value), ((a)->hw_addr + reg)))
> +
> +#define AT_WRITE_FLUSH(a) (\
> +		readl((a)->hw_addr))
> +
> +#define AT_READ_REG(a, reg, pdata) do {					\
> +		if (unlikely((a)->hibernate)) {				\
> +			readl((a)->hw_addr + reg);			\
> +			*(u32 *)pdata = readl((a)->hw_addr + reg);	\
> +		} else {						\
> +			*(u32 *)pdata = readl((a)->hw_addr + reg);	\
> +		}							\
> +	} while (0)
> +
> +#define AT_WRITE_REGB(a, reg, value) (\
> +		writeb((value), ((a)->hw_addr + reg)))
> +
> +#define AT_READ_REGB(a, reg) (\
> +		readb((a)->hw_addr + reg))
> +
> +#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_WRITE_REG_ARRAY(a, reg, offset, value) ( \
> +		writel((value), (((a)->hw_addr + reg) + ((offset) << 2))))
> +
> +#define AT_READ_REG_ARRAY(a, reg, offset) ( \
> +		readl(((a)->hw_addr + reg) + ((offset) << 2)))
> +
> +extern char atl1c_driver_name[];
> +extern char atl1c_driver_version[];
> +
> +extern void atl1c_check_options(struct atl1c_adapter *adapter);
> +extern int atl1c_up(struct atl1c_adapter *adapter);
> +extern void atl1c_down(struct atl1c_adapter *adapter);
> +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);
> +#endif /* _ATL1C_H_ */
> diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c
> new file mode 100644
> index 0000000..66a9916
> --- /dev/null
> +++ b/drivers/net/atl1c/atl1c_ethtool.c
> @@ -0,0 +1,379 @@
> +/*
> + * Copyright(c) 2009 - 2009 Atheros Corporation. All rights reserved.
> + *
> + * Derived from Intel e1000 driver
> + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
> + * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
> + *
> + */
> +
> +#include <linux/netdevice.h>
> +#include <linux/ethtool.h>
> +
> +#include "atl1c.h"
> +
> +static int atl1c_get_settings(struct net_device *netdev,
> +			      struct ethtool_cmd *ecmd)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct atl1c_hw *hw = &adapter->hw;
> +
> +	ecmd->supported = (SUPPORTED_10baseT_Half  |
> +			   SUPPORTED_10baseT_Full  |
> +			   SUPPORTED_100baseT_Half |
> +			   SUPPORTED_100baseT_Full |
> +			   SUPPORTED_Autoneg       |
> +			   SUPPORTED_TP);
> +	if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M)
> +		ecmd->supported |= SUPPORTED_1000baseT_Full;
> +
> +	ecmd->advertising = ADVERTISED_TP;
> +
> +	ecmd->advertising |= ADVERTISED_Autoneg;
> +	ecmd->advertising |= hw->autoneg_advertised;
> +
> +	ecmd->port = PORT_TP;
> +	ecmd->phy_address = 0;
> +	ecmd->transceiver = XCVR_INTERNAL;
> +
> +	if (adapter->link_speed != SPEED_0) {
> +		ecmd->speed = adapter->link_speed;
> +		if (adapter->link_duplex == FULL_DUPLEX)
> +			ecmd->duplex = DUPLEX_FULL;
> +		else
> +			ecmd->duplex = DUPLEX_HALF;
> +	} else {
> +		ecmd->speed = -1;
> +		ecmd->duplex = -1;
> +	}
> +
> +	ecmd->autoneg = AUTONEG_ENABLE;
> +	return 0;
> +}
> +
> +static int atl1c_set_settings(struct net_device *netdev,
> +			      struct ethtool_cmd *ecmd)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct atl1c_hw *hw = &adapter->hw;
> +	u16  autoneg_advertised;
> +	while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
> +		msleep(1);
> +
> +	if (ecmd->autoneg == AUTONEG_ENABLE) {
> +		autoneg_advertised = ADVERTISE_DEFAULT;
> +	} else {
> +		if (ecmd->speed == SPEED_1000) {
> +			if (ecmd->duplex != DUPLEX_FULL) {
> +				printk(KERN_WARNING"1000M half is invalid\n");

Consider converting all printks to dev_*...

> +				clear_bit(__AT_RESETTING, &adapter->flags);
> +				return -EINVAL;
> +			}
> +			autoneg_advertised = ADVERTISE_1000_FULL;
> +		} else if (ecmd->speed == SPEED_100) {
> +			if (ecmd->duplex == DUPLEX_FULL)
> +				autoneg_advertised = ADVERTISE_100_FULL;
> +			else
> +				autoneg_advertised = ADVERTISE_100_HALF;
> +		} else {
> +			if (ecmd->duplex == DUPLEX_FULL)
> +				autoneg_advertised = ADVERTISE_10_FULL;
> +			else
> +				autoneg_advertised = ADVERTISE_10_HALF;
> +		}
> +	}
> +
> +	if (hw->autoneg_advertised != autoneg_advertised) {
> +		hw->autoneg_advertised = autoneg_advertised;
> +		if (atl1c_restart_autoneg(hw) != 0) {
> +			printk(KERN_WARNING
> +				"ethtool speed/duplex setting failed\n");
> +			clear_bit(__AT_RESETTING, &adapter->flags);
> +			return -EINVAL;
> +		}
> +	}
> +	clear_bit(__AT_RESETTING, &adapter->flags);
> +	return 0;
> +}
> +
> +static u32 atl1c_get_tx_csum(struct net_device *netdev)
> +{
> +	return (netdev->features & NETIF_F_HW_CSUM) != 0;
> +}
> +
> +static u32 atl1c_get_msglevel(struct net_device *netdev)
> +{
> +#ifdef DBG
> +	return 1;
> +#else
> +	return 0;
> +#endif
> +}
> +
> +static void atl1c_set_msglevel(struct net_device *netdev, u32 data)
> +{
> +}
> +
> +static int atl1c_get_regs_len(struct net_device *netdev)
> +{
> +	return AT_REGS_LEN *sizeof(u32);
> +}
> +
> +static void atl1c_get_regs(struct net_device *netdev,
> +			   struct ethtool_regs *regs, void *p)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct atl1c_hw *hw = &adapter->hw;
> +	u32 *regs_buff = p;
> +	u16 phy_data;
> +
> +	memset(p, 0, (AT_REGS_LEN *sizeof(u32)));
> +
> +	regs->version = 0;
> +	AT_READ_REG(hw, REG_VPD_CAP, 		  p++);
> +	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++);
> +	AT_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL,   p++);
> +	AT_READ_REG(hw, REG_MASTER_CTRL, 	  p++);
> +	AT_READ_REG(hw, REG_MANUAL_TIMER_INIT,    p++);
> +	AT_READ_REG(hw, REG_IRQ_MODRT_TIMER_INIT, p++);
> +	AT_READ_REG(hw, REG_GPHY_CTRL, 		  p++);
> +	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_MAC_CTRL, 		  p++);
> +	AT_READ_REG(hw, REG_MAC_IPG_IFG, 	  p++);
> +	AT_READ_REG(hw, REG_MAC_STA_ADDR, 	  p++);
> +	AT_READ_REG(hw, REG_MAC_STA_ADDR+4, 	  p++);
> +	AT_READ_REG(hw, REG_RX_HASH_TABLE, 	  p++);
> +	AT_READ_REG(hw, REG_RX_HASH_TABLE+4, 	  p++);
> +	AT_READ_REG(hw, REG_RXQ_CTRL, 		  p++);
> +	AT_READ_REG(hw, REG_TXQ_CTRL, 		  p++);
> +	AT_READ_REG(hw, REG_MTU, 		  p++);
> +	AT_READ_REG(hw, REG_WOL_CTRL, 		  p++);
> +
> +	atl1c_read_phy_reg(hw, MII_BMCR, &phy_data);
> +	regs_buff[73] =	(u32) phy_data;
> +	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
> +	regs_buff[74] = (u32) phy_data;
> +}
> +
> +static int atl1c_get_eeprom_len(struct net_device *netdev)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	if (atl1c_check_eeprom_exist(&adapter->hw))
> +		return AT_EEPROM_LEN;
> +	else
> +		return 0;
> +}
> +
> +static int atl1c_get_eeprom(struct net_device *netdev,
> +		struct ethtool_eeprom *eeprom, u8 *bytes)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct atl1c_hw *hw = &adapter->hw;
> +	u32 *eeprom_buff;
> +	int first_dword, last_dword;
> +	int ret_val = 0;
> +	int i;
> +
> +	if (eeprom->len == 0)
> +		return -EINVAL;
> +
> +	if (!atl1c_check_eeprom_exist(hw)) /* not exist */
> +		return -EINVAL;
> +
> +	eeprom->magic = adapter->pdev->vendor |
> +			(adapter->pdev->device << 16);
> +
> +	first_dword = eeprom->offset >> 2;
> +	last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
> +
> +	eeprom_buff = kmalloc(sizeof(u32) *
> +			(last_dword - first_dword + 1), GFP_KERNEL);
> +	if (eeprom_buff == NULL)
> +		return -ENOMEM;
> +
> +	for (i = first_dword; i < last_dword; i++) {
> +		if (!atl1c_read_eeprom(hw, i * 4, &(eeprom_buff[i-first_dword]))) {
> +			kfree(eeprom_buff);
> +			return -EIO;
> +		}
> +	}
> +
> +	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3),
> +			eeprom->len);
> +	kfree(eeprom_buff);
> +
> +	return ret_val;
> +	return 0;
> +}
> +
> +static int atl1c_set_eeprom(struct net_device *netdev,
> +			    struct ethtool_eeprom *eeprom, u8 *bytes)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct atl1c_hw *hw = &adapter->hw;
> +	u32 *eeprom_buff;
> +	u32 *ptr;
> +	int first_dword, last_dword;
> +	int ret_val = 0;
> +	int i;
> +
> +	if (eeprom->len == 0)
> +		return -EOPNOTSUPP;
> +
> +	if (eeprom->magic != (adapter->pdev->vendor |
> +				(adapter->pdev->device << 16)))
> +		return -EINVAL;
> +
> +	first_dword = eeprom->offset >> 2;
> +	last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
> +	eeprom_buff = kmalloc(AT_EEPROM_LEN, GFP_KERNEL);
> +	if (eeprom_buff == NULL)
> +		return -ENOMEM;
> +
> +	ptr = (u32 *)eeprom_buff;
> +
> +	if (eeprom->offset & 3) {
> +		/* need read/modify/write of first changed EEPROM word */
> +		/* only the second byte of the word is being modified */
> +		if (!atl1c_read_eeprom(hw, first_dword * 4, &(eeprom_buff[0]))) {
> +			ret_val = -EIO;
> +			goto out;
> +		}
> +		ptr++;
> +	}
> +	if (((eeprom->offset + eeprom->len) & 3)) {
> +		/* need read/modify/write of last changed EEPROM word */
> +		/* only the first byte of the word is being modified */
> +
> +		if (!atl1c_read_eeprom(hw, last_dword * 4,
> +				&(eeprom_buff[last_dword - first_dword]))) {
> +			ret_val = -EIO;
> +			goto out;
> +		}
> +	}
> +
> +	/* Device's eeprom is always little-endian, word addressable */
> +	memcpy(ptr, bytes, eeprom->len);
> +
> +	for (i = 0; i < last_dword - first_dword + 1; i++) {
> +		if (!atl1c_write_eeprom(hw, ((first_dword + i) * 4),
> +				  eeprom_buff[i])) {
> +			ret_val = -EIO;
> +			goto out;
> +		}
> +	}
> +out:
> +	kfree(eeprom_buff);
> +	return ret_val;
> +	return 0;
> +}
> +
> +static void atl1c_get_drvinfo(struct net_device *netdev,
> +		struct ethtool_drvinfo *drvinfo)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	strncpy(drvinfo->driver,  atl1c_driver_name, 32);
> +	strncpy(drvinfo->version, atl1c_driver_version, 32);
> +	strncpy(drvinfo->fw_version, "L1e", 32);
> +	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
> +	drvinfo->n_stats = 0;
> +	drvinfo->testinfo_len = 0;
> +	drvinfo->regdump_len = atl1c_get_regs_len(netdev);
> +	drvinfo->eedump_len = atl1c_get_eeprom_len(netdev);
> +}
> +
> +static void atl1c_get_wol(struct net_device *netdev,
> +			  struct ethtool_wolinfo *wol)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	wol->supported = WAKE_MAGIC | WAKE_PHY;
> +	wol->wolopts = 0;
> +
> +	if (adapter->wol & AT_WUFC_EX)
> +		wol->wolopts |= WAKE_UCAST;
> +	if (adapter->wol & AT_WUFC_MC)
> +		wol->wolopts |= WAKE_MCAST;
> +	if (adapter->wol & AT_WUFC_BC)
> +		wol->wolopts |= WAKE_BCAST;
> +	if (adapter->wol & AT_WUFC_MAG)
> +		wol->wolopts |= WAKE_MAGIC;
> +	if (adapter->wol & AT_WUFC_LNKC)
> +		wol->wolopts |= WAKE_PHY;
> +
> +	return;
> +}
> +
> +static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
> +			    WAKE_MCAST | WAKE_BCAST | WAKE_MCAST))
> +		return -EOPNOTSUPP;
> +	/* these settings will always override what we currently have */
> +	adapter->wol = 0;
> +
> +	if (wol->wolopts & WAKE_MAGIC)
> +		adapter->wol |= AT_WUFC_MAG;
> +	if (wol->wolopts & WAKE_PHY)
> +		adapter->wol |= AT_WUFC_LNKC;
> +
> +	return 0;
> +}
> +
> +static int atl1c_nway_reset(struct net_device *netdev)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	if (netif_running(netdev))
> +		atl1c_reinit_locked(adapter);
> +	return 0;
> +}
> +
> +static struct ethtool_ops atl1c_ethtool_ops = {
> +	.get_settings           = atl1c_get_settings,
> +	.set_settings           = atl1c_set_settings,
> +	.get_drvinfo            = atl1c_get_drvinfo,
> +	.get_regs_len           = atl1c_get_regs_len,
> +	.get_regs               = atl1c_get_regs,
> +	.get_wol                = atl1c_get_wol,
> +	.set_wol                = atl1c_set_wol,
> +	.get_msglevel           = atl1c_get_msglevel,
> +	.set_msglevel           = atl1c_set_msglevel,
> +	.nway_reset             = atl1c_nway_reset,
> +	.get_link               = ethtool_op_get_link,
> +	.get_eeprom_len         = atl1c_get_eeprom_len,
> +	.get_eeprom             = atl1c_get_eeprom,
> +	.set_eeprom             = atl1c_set_eeprom,
> +	.get_tx_csum            = atl1c_get_tx_csum,
> +	.get_sg                 = ethtool_op_get_sg,
> +	.set_sg                 = ethtool_op_set_sg,
> +#ifdef NETIF_F_TSO
> +	.get_tso                = ethtool_op_get_tso,
> +#endif
> +};
> +
> +void atl1c_set_ethtool_ops(struct net_device *netdev)
> +{
> +	SET_ETHTOOL_OPS(netdev, &atl1c_ethtool_ops);
> +}
> diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
> new file mode 100644
> index 0000000..0d3edbf
> --- /dev/null
> +++ b/drivers/net/atl1c/atl1c_hw.c
> @@ -0,0 +1,547 @@
> +/*
> + * Copyright(c) 2007 Atheros Corporation. All rights reserved.
> + *
> + * Derived from Intel e1000 driver
> + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
> + * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
> + */
> +#include <linux/pci.h>
> +#include <linux/delay.h>
> +#include <linux/mii.h>
> +#include <linux/crc32.h>
> +
> +#include "atl1c.h"
> +
> +/*
> + * check_eeprom_exist
> + * return 1 if eeprom exist
> + */
> +int atl1c_check_eeprom_exist(struct atl1c_hw *hw)
> +{
> +	u32 data;
> +
> +	AT_READ_REG(hw, REG_TWSI_DEBUG, &data);
> +	if (data & TWSI_DEBUG_DEV_EXIST)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +void atl1c_hw_set_mac_addr(struct atl1c_hw *hw)
> +{
> +	u32 value;
> +	/*
> +	 * 00-0B-6A-F6-00-DC
> +	 * 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])) ;
> +	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])) ;
> +	AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value);
> +}
> +
> +/*
> + * 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;
> +	u8  eth_addr[ETH_ALEN];
> +
> +	/* init */
> +	addr[0] = addr[1] = 0;
> +	AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
> +	if (atl1c_check_eeprom_exist(hw)) {
> +		/* Enable OTP CLK */
> +		if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
> +			otp_ctrl_data |= OTP_CTRL_CLK_EN;
> +			AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
> +			msleep(1);
> +		}
> +
> +		AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
> +		twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
> +		AT_WRITE_REG(hw, REG_TWSI_CTRL, twsi_ctrl_data);
> +		for (i = 0; i < AT_TWSI_EEPROM_TIMEOUT; i++) {
> +			msleep(10);
> +			AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
> +			if ((twsi_ctrl_data & TWSI_CTRL_SW_LDSTART) == 0)
> +				break;
> +		}
> +		if (i >= AT_TWSI_EEPROM_TIMEOUT)
> +			return AT_ERR_TIMEOUT;
> +	}
> +	/* Disable OTP_CLK */
> +	if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
> +		otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
> +		AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
> +		msleep(1);
> +	}
> +
> +	/* 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 *) &eth_addr[2] = swab32(addr[0]);
> +	*(u16 *) &eth_addr[0] = swab16(*(u16 *)&addr[1]);
> +
> +	if (is_valid_ether_addr(eth_addr)) {
> +		memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
> +		return 0;
> +	}
> +
> +	return AT_ERR_EEPROM;
> +}
> +
> +bool atl1c_write_eeprom(struct atl1c_hw *hw, u32 offset, u32 value)
> +{
> +	return true;
> +}

Do-nothing function.  Remove?

> +
> +bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value)
> +{
> +	int i;
> +	int ret = false;
> +	u32 otp_ctrl_data;
> +	u32 control;
> +	u32 data;
> +
> +	if (offset & 3)
> +		return ret; /* address do not align */
> +
> +	AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
> +	if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
> +		AT_WRITE_REG(hw, REG_OTP_CTRL,
> +				(otp_ctrl_data | OTP_CTRL_CLK_EN));
> +
> +	AT_WRITE_REG(hw, REG_EEPROM_DATA_LO, 0);
> +	control = (offset & EEPROM_CTRL_ADDR_MASK) << EEPROM_CTRL_ADDR_SHIFT;
> +	AT_WRITE_REG(hw, REG_EEPROM_CTRL, control);
> +
> +	for (i = 0; i < 10; i++) {
> +		udelay(100);
> +		AT_READ_REG(hw, REG_EEPROM_CTRL, &control);
> +		if (control & EEPROM_CTRL_RW)
> +			break;
> +	}
> +	if (control & EEPROM_CTRL_RW) {
> +		AT_READ_REG(hw, REG_EEPROM_CTRL, &data);
> +		AT_READ_REG(hw, REG_EEPROM_DATA_LO, p_value);
> +		data = data & 0xFFFF;
> +		*p_value = swab32((data << 16) | (*p_value >> 16));
> +		ret = true;
> +	}
> +	if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
> +		AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
> +
> +	return ret;
> +}
> +/*
> + * Reads the adapter's MAC address from the EEPROM
> + *
> + * hw - Struct containing variables accessed by shared code
> + */
> +int atl1c_read_mac_addr(struct atl1c_hw *hw)
> +{
> +	int err = 0;
> +
> +	err = atl1c_get_permanent_address(hw);
> +	if (err) {
> +		hw->perm_mac_addr[0] = 0x00;
> +		hw->perm_mac_addr[1] = 0x13;
> +		hw->perm_mac_addr[2] = 0x74;
> +		hw->perm_mac_addr[3] = 0x00;
> +		hw->perm_mac_addr[4] = 0x5c;
> +		hw->perm_mac_addr[5] = 0x38;
> +	}

Better to use random_ether_addr() here.

> +
> +	memcpy(hw->mac_addr, hw->perm_mac_addr, sizeof(hw->perm_mac_addr));
> +	return 0;
> +}
> +
> +/*
> + * atl1c_hash_mc_addr
> + *  purpose
> + *      set hash value for a multicast address
> + *      hash calcu processing :
> + *          1. calcu 32bit CRC for multicast address
> + *          2. reverse crc with MSB to LSB
> + */
> +u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr)
> +{
> +	u32 crc32;
> +	u32 value = 0;
> +	int i;
> +
> +	crc32 = ether_crc_le(6, mc_addr);
> +	for (i = 0; i < 32; i++)
> +		value |= (((crc32 >> i) & 1) << (31 - i));
> +
> +	return value;
> +}
> +
> +/*
> + * Sets the bit in the multicast table corresponding to the hash value.
> + * hw - Struct containing variables accessed by shared code
> + * hash_value - Multicast address hash value
> + */
> +void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value)
> +{
> +	u32 hash_bit, hash_reg;
> +	u32 mta;
> +
> +	/*
> +	 * The HASH Table  is a register array of 2 32-bit registers.
> +	 * It is treated like an array of 64 bits.  We want to set
> +	 * bit BitArray[hash_value]. So we figure out what register
> +	 * the bit is in, read it, OR in the new bit, then write
> +	 * back the new value.  The register is determined by the
> +	 * upper 7 bits of the hash value and the bit within that

Looks like the upper bit, not the upper 7 bits.

> +	 * register are determined by the lower 5 bits of the value.
> +	 */
> +	hash_reg = (hash_value >> 31) & 0x1;
> +	hash_bit = (hash_value >> 26) & 0x1F;
> +
> +	mta = AT_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg);
> +
> +	mta |= (1 << hash_bit);
> +
> +	AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta);
> +}
> +
> +/*
> + * 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)
> +{
> +	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;
> +
> +	AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
> +
> +	wmb();
> +
> +	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;
> +		wmb();
> +	}
> +	if (!(val & (MDIO_START | MDIO_BUSY))) {
> +		*phy_data = (u16)val;
> +		return 0;
> +	}
> +
> +	return AT_ERR_PHY;
> +}
> +
> +/*
> + * Writes a value to a PHY register
> + * hw - Struct containing variables accessed by shared code
> + * reg_addr - address of the PHY register to write
> + * data - data to write to the PHY
> + */
> +int atl1c_write_phy_reg(struct atl1c_hw *hw, u32 reg_addr, u16 phy_data)
> +{
> +	int i;
> +	u32 val;
> +
> +	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;
> +
> +	AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
> +	wmb();
> +
> +	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;
> +		wmb();
> +	}
> +
> +	if (!(val & (MDIO_START | MDIO_BUSY)))
> +		return 0;
> +
> +	return AT_ERR_PHY;
> +}
> +
> +/*
> + * Configures PHY autoneg and flow control advertisement settings
> + *
> + * hw - Struct containing variables accessed by shared code
> + */
> +static int atl1c_phy_setup_adv(struct atl1c_hw *hw)
> +{
> +	u16 mii_adv_data = ADVERTISE_DEFAULT_CAP & ~ADVERTISE_SPEED_MASK;
> +	u16 mii_giga_ctrl_data = GIGA_CR_1000T_DEFAULT_CAP &
> +				~GIGA_CR_1000T_SPEED_MASK;
> +
> +	if (hw->autoneg_advertised & ADVERTISE_10_HALF)
> +		mii_adv_data |= ADVERTISE_10T_HD_CAPS;
> +	if (hw->autoneg_advertised & ADVERTISE_10_FULL)
> +		mii_adv_data |= ADVERTISE_10T_FD_CAPS;
> +	if (hw->autoneg_advertised & ADVERTISE_100_HALF)
> +		mii_adv_data |= ADVERTISE_100TX_HD_CAPS;
> +	if (hw->autoneg_advertised & ADVERTISE_100_FULL)
> +		mii_adv_data |= ADVERTISE_100TX_FD_CAPS;
> +
> +	if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M) {
> +		if (hw->autoneg_advertised & ADVERTISE_1000_HALF)
> +			mii_giga_ctrl_data |= GIGA_CR_1000T_HD_CAPS;
> +		if (hw->autoneg_advertised & ADVERTISE_1000_FULL)
> +			mii_giga_ctrl_data |= GIGA_CR_1000T_FD_CAPS;
> +	}
> +
> +	if (atl1c_write_phy_reg(hw, MII_ADVERTISE, mii_adv_data) != 0 ||
> +	    atl1c_write_phy_reg(hw, MII_GIGA_CR, mii_giga_ctrl_data) != 0)
> +		return AT_ERR_PHY_SPEED;
> +	return 0;
> +}
> +
> +/*
> + * Resets the PHY and make all config validate
> + *
> + * hw - Struct containing variables accessed by shared code
> + *
> + * Sets bit 15 and 12 of the MII control regiser (for F001 bug)
> + */
> +#if 0
> +int atl1c_phy_commit(struct atl1c_hw *hw)
> +{
> +	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
> +	struct pci_dev *pdev = adapter->pdev;
> +	int ret_val;
> +	u16 phy_data;
> +
> +	phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG;
> +
> +	ret_val = atl1c_write_phy_reg(hw, MII_BMCR, phy_data);
> +	if (ret_val) {
> +		u32 val;
> +		int i;
> +		/**************************************
> +		 * pcie serdes link may be down !
> +		 **************************************/
> +		for (i = 0; i < 25; i++) {
> +			msleep(1);
> +			val = AT_READ_REG(hw, REG_MDIO_CTRL);
> +			if (!(val & (MDIO_START | MDIO_BUSY)))
> +				break;
> +		}
> +
> +		if (0 != (val & (MDIO_START | MDIO_BUSY))) {
> +			dev_err(&pdev->dev,
> +				"pcie linkdown at least for 25ms\n");
> +			return ret_val;
> +		}
> +
> +		dev_err(&pdev->dev, "pcie linkup after %d ms\n", i);
> +	}
> +	return 0;
> +}
> +#endif
> +
> +void atl1c_phy_disable(struct atl1c_hw *hw)
> +{
> +	AT_WRITE_REGW(hw, REG_GPHY_CTRL,
> +			GPHY_CTRL_PW_WOL_DIS | GPHY_CTRL_EXT_RESET);
> +}
> +
> +static void atl1c_phy_magic_data(struct atl1c_hw *hw)
> +{
> +	u16 data;
> +
> +	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x12);
> +	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x4C04);
> +
> +	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x05);
> +	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x2C46);
> +
> +	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x36);
> +	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xE12C);
> +
> +	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x04);
> +	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x88BB);
> +
> +	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
> +	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x02EF);
> +
> +	if (hw->ctrl_flags & ATL1C_HIB_DISABLE) {
> +		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
> +		if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0)
> +			return;
> +		data &= 0x7FFF;
> +		atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
> +
> +		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB);
> +		if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0)
> +			return;
> +		data &= 0x7FFF;
> +		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;
> +	u32 phy_ctrl_data = GPHY_CTRL_DEFAULT;
> +	u32 mii_ier_data = IER_LINK_UP | IER_LINK_DOWN;
> +	int err;
> +
> +	if (hw->ctrl_flags & ATL1C_HIB_DISABLE)
> +		phy_ctrl_data &= ~GPHY_CTRL_HIB_EN;
> +
> +	AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data);
> +	msleep(40);
> +	phy_ctrl_data |= GPHY_CTRL_EXT_RESET;
> +	AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data);
> +	msleep(10);
> +
> +	/*Enable PHY LinkChange Interrupt */
> +	err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
> +	if (err) {
> +		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 pci_dev *pdev = adapter->pdev;
> +	int ret_val;
> +	u16 mii_bmcr_data = BMCR_RESET;
> +	u16 phy_id1, phy_id2;
> +
> +	if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &phy_id1) != 0) ||
> +		(atl1c_read_phy_reg(hw, MII_PHYSID2, &phy_id2) != 0)) {
> +		dev_err(&pdev->dev, "Error get phy ID\n");
> +		return -1;
> +	}
> +	switch (hw->media_type) {
> +	case MEDIA_TYPE_AUTO_SENSOR:
> +		ret_val = atl1c_phy_setup_adv(hw);
> +		if (ret_val) {
> +			dev_err(&pdev->dev,
> +				"Error Setting up Auto-Negotiation\n");
> +			return ret_val;
> +		}
> +		mii_bmcr_data |= BMCR_AUTO_NEG_EN | BMCR_RESTART_AUTO_NEG;
> +		break;
> +	case MEDIA_TYPE_100M_FULL:
> +		mii_bmcr_data |= BMCR_SPEED_100 | BMCR_FULL_DUPLEX;
> +		break;
> +	case MEDIA_TYPE_100M_HALF:
> +		mii_bmcr_data |= BMCR_SPEED_100;
> +		break;
> +	case MEDIA_TYPE_10M_FULL:
> +		mii_bmcr_data |= BMCR_SPEED_10 | BMCR_FULL_DUPLEX;
> +		break;
> +	case MEDIA_TYPE_10M_HALF:
> +		mii_bmcr_data |= BMCR_SPEED_10;
> +		break;
> +	default:
> +		dev_err(&pdev->dev, "Wrong Media type %d\n", hw->media_type);
> +		return AT_ERR_PARAM;
> +		break;
> +	}
> +
> +	ret_val = atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data);
> +	if (ret_val)
> +		return ret_val;
> +	hw->phy_configured = true;
> +
> +	return 0;
> +}
> +
> +/*
> + * Detects the current speed and duplex settings of the hardware.
> + *
> + * hw - Struct containing variables accessed by shared code
> + * speed - Speed of the connection
> + * duplex - Duplex setting of the connection
> + */
> +int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
> +{
> +	int err;
> +	u16 phy_data;
> +
> +	/* Read   PHY Specific Status Register (17) */
> +	err = atl1c_read_phy_reg(hw, MII_GIGA_PSSR, &phy_data);
> +	if (err)
> +		return err;
> +
> +	if (!(phy_data & GIGA_PSSR_SPD_DPLX_RESOLVED))
> +		return AT_ERR_PHY_RES;
> +
> +	switch (phy_data & GIGA_PSSR_SPEED) {
> +	case GIGA_PSSR_1000MBS:
> +		*speed = SPEED_1000;
> +		break;
> +	case GIGA_PSSR_100MBS:
> +		*speed = SPEED_100;
> +		break;
> +	case  GIGA_PSSR_10MBS:
> +		*speed = SPEED_10;
> +		break;
> +	default:
> +		return AT_ERR_PHY_SPEED;
> +		break;
> +	}
> +
> +	if (phy_data & GIGA_PSSR_DPLX)
> +		*duplex = FULL_DUPLEX;
> +	else
> +		*duplex = HALF_DUPLEX;
> +
> +	return 0;
> +}
> +
> +int atl1c_restart_autoneg(struct atl1c_hw *hw)
> +{
> +	int err = 0;
> +	u16 mii_bmcr_data = BMCR_RESET;
> +
> +	err = atl1c_phy_setup_adv(hw);
> +	if (err)
> +		return err;
> +	mii_bmcr_data |= BMCR_AUTO_NEG_EN | BMCR_RESTART_AUTO_NEG;
> +
> +	return atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data);
> +}
> diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h
> new file mode 100644
> index 0000000..aa3fdb0
> --- /dev/null
> +++ b/drivers/net/atl1c/atl1c_hw.h
> @@ -0,0 +1,829 @@
> +/*
> + * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
> + *
> + * Derived from Intel e1000 driver
> + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
> + * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
> + */
> +
> +#ifndef _ATL1C_HW_H_
> +#define _ATL1C_HW_H_
> +
> +#include <linux/types.h>
> +#include <linux/mii.h>
> +
> +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);
> +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);
> +u32 atl1c_auto_get_fc(struct atl1c_adapter *adapter, u16 duplex);
> +u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr);
> +void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value);
> +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 atl1c_validate_mdi_setting(struct atl1c_hw *hw);
> +void atl1c_hw_set_mac_addr(struct atl1c_hw *hw);
> +bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value);
> +bool atl1c_write_eeprom(struct atl1c_hw *hw, u32 offset, u32 value);
> +int atl1c_phy_enter_power_saving(struct atl1c_hw *hw);
> +int atl1c_phy_leave_power_saving(struct atl1c_hw *hw);
> +int atl1c_phy_init(struct atl1c_hw *hw);
> +int atl1c_check_eeprom_exist(struct atl1c_hw *hw);
> +void atl1c_force_ps(struct atl1c_hw *hw);
> +int atl1c_restart_autoneg(struct atl1c_hw *hw);

Are all these declarations needed?

> +
> +/* register definition */
> +#define REG_PM_CTRLSTAT             	0x44
> +#define PM_CTRLSTAT_PME_EN		0x100
> +
> +#define REG_PCIE_CAP_LIST           	0x58
> +
> +#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 REG_LINK_CTRL			0x68
> +#define LINK_CTRL_L0S_EN		0x01
> +#define LINK_CTRL_L1_EN			0x02
> +
> +#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_DEV_SERIALNUM_CTRL		0x200
> +#define REG_DEV_MAC_SEL_MASK		0x0 /* 0:EUI; 1:MAC */
> +#define REG_DEV_MAC_SEL_SHIFT		0
> +#define REG_DEV_SERIAL_NUM_EN_MASK	0x1
> +#define REG_DEV_SERIAL_NUM_EN_SHIFT	1
> +
> +#define REG_TWSI_CTRL               	0x218
> +#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
> +#define PCIE_DEV_MISC_RETRY_BUFDIS 	0x1
> +#define PCIE_DEV_MISC_SPIROM_EXIST 	0x4
> +#define PCIE_DEV_MISC_SERDES_ENDIAN    	0x8
> +#define PCIE_DEV_MISC_SERDES_SEL_DIN   	0x10
> +
> +#define REG_PCIE_PHYMISC	    	0x1000
> +#define PCIE_PHYMISC_FORCE_RCV_DET	0x4
> +
> +#define REG_TWSI_DEBUG			0x1108
> +#define TWSI_DEBUG_DEV_EXIST		0x20000000
> +
> +#define REG_EEPROM_CTRL			0x12C0
> +#define EEPROM_CTRL_DATA_HI_MASK	0xFFFF
> +#define EEPROM_CTRL_DATA_HI_SHIFT	0
> +#define EEPROM_CTRL_ADDR_MASK		0x3FF
> +#define EEPROM_CTRL_ADDR_SHIFT		16
> +#define EEPROM_CTRL_ACK			0x40000000
> +#define EEPROM_CTRL_RW			0x80000000
> +
> +#define REG_EEPROM_DATA_LO		0x12C4
> +
> +#define REG_OTP_CTRL			0x12F0
> +#define OTP_CTRL_CLK_EN			0x0002
> +
> +#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_PCIE_RECV		0x00008000
> +#define PM_CTRL_L1_ENTRY_TIMER_MASK	0xF
> +#define PM_CTRL_L1_ENTRY_TIMER_SHIFT	16
> +#define PM_CTRL_PM_REQ_TIMER_MASK	0xF
> +#define PM_CTRL_PM_REQ_TIMER_SHIFT	20
> +#define PM_CTRL_LCKDET_TIMER_MASK	0x3F
> +#define PM_CTRL_LCKDET_TIMER_SHIFT	24
> +#define PM_CTRL_MAC_ASPM_CHK		0x40000000
> +#define PM_CTRL_HOTRST			0x80000000
> +
> +/* 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_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
> +
> +/* Timer Initial Value Register */
> +#define REG_MANUAL_TIMER_INIT       	0x1404
> +
> +/* IRQ ModeratorTimer Initial Value Register */
> +#define REG_IRQ_MODRT_TIMER_INIT     	0x1408
> +#define IRQ_MODRT_TIMER_MASK		0xffff
> +#define IRQ_MODRT_TX_TIMER_SHIFT    	0
> +#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)
> +
> +/* 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
> +
> +/* 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
> +/* BIST Control and Status Register0 (for the Packet Memory) */
> +#define REG_BIST0_CTRL              	0x141c
> +#define BIST0_NOW                   	0x1
> +#define BIST0_SRAM_FAIL             	0x2 /* 1: The SRAM failure is
> +					     * un-repairable  because
> +					     * it has address decoder
> +					     * failure or more than 1 cell
> +					     * stuck-to-x failure */
> +#define BIST0_FUSE_FLAG             	0x4
> +
> +/* BIST Control and Status Register1(for the retry buffer of PCI Express) */
> +#define REG_BIST1_CTRL			0x1420
> +#define BIST1_NOW                   	0x1
> +#define BIST1_SRAM_FAIL             	0x2
> +#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 */
> +
> +/* 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
> +
> +/* MAC IPG/IFG Control Register  */
> +#define REG_MAC_IPG_IFG             	0x1484
> +#define MAC_IPG_IFG_IPGT_SHIFT      	0 	/* Desired back to back
> +						 * inter-packet gap. The
> +						 * default is 96-bit time */
> +#define MAC_IPG_IFG_IPGT_MASK       	0x7f
> +#define MAC_IPG_IFG_MIFG_SHIFT      	8       /* Minimum number of IFG to
> +						 * enforce in between RX frames */
> +#define MAC_IPG_IFG_MIFG_MASK       	0xff  	/* Frame gap below such IFP is dropped */
> +#define MAC_IPG_IFG_IPGR1_SHIFT     	16   	/* 64bit Carrier-Sense window */
> +#define MAC_IPG_IFG_IPGR1_MASK      	0x7f
> +#define MAC_IPG_IFG_IPGR2_SHIFT     	24    	/* 96-bit IPG window */
> +#define MAC_IPG_IFG_IPGR2_MASK      	0x7f
> +
> +/* MAC STATION ADDRESS  */
> +#define REG_MAC_STA_ADDR		0x1488
> +
> +/* Hash table for multicast address */
> +#define REG_RX_HASH_TABLE		0x1490
> +
> +/* MAC Half-Duplex Control Register */
> +#define REG_MAC_HALF_DUPLX_CTRL     	0x1498
> +#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT  0      /* Collision Window */
> +#define MAC_HALF_DUPLX_CTRL_LCOL_MASK   0x3ff
> +#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12
> +#define MAC_HALF_DUPLX_CTRL_RETRY_MASK  0xf
> +#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN  0x10000
> +#define MAC_HALF_DUPLX_CTRL_NO_BACK_C   0x20000
> +#define MAC_HALF_DUPLX_CTRL_NO_BACK_P   0x40000 /* No back-off on backpressure,
> +						 * immediately start the
> +						 * transmission after back pressure */
> +#define MAC_HALF_DUPLX_CTRL_ABEBE        0x80000 /* 1: Alternative Binary Exponential Back-off Enabled */
> +#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT  20      /* Maximum binary exponential number */
> +#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK   0xf
> +#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24      /* IPG to start JAM for collision based flow control in half-duplex */
> +#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK  0xf     /* mode. In unit of 8-bit time */
> +
> +/* Maximum Frame Length Control Register   */
> +#define REG_MTU                     	0x149c
> +
> +/* 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
> +
> +/* 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
> +
> +/* Internal SRAM Partition Register */
> +#define RFDX_HEAD_ADDR_MASK		0x03FF
> +#define RFDX_HARD_ADDR_SHIFT		0
> +#define RFDX_TAIL_ADDR_MASK		0x03FF
> +#define RFDX_TAIL_ADDR_SHIFT            16
> +
> +#define REG_SRAM_RFD0_INFO		0x1500
> +#define REG_SRAM_RFD1_INFO		0x1504
> +#define REG_SRAM_RFD2_INFO		0x1508
> +#define	REG_SRAM_RFD3_INFO		0x150C
> +
> +#define REG_RFD_NIC_LEN			0x1510 /* In 8-bytes */
> +#define RFD_NIC_LEN_MASK		0x03FF
> +
> +#define REG_SRAM_TRD_ADDR           	0x1518
> +#define TPD_HEAD_ADDR_MASK		0x03FF
> +#define TPD_HEAD_ADDR_SHIFT		0
> +#define TPD_TAIL_ADDR_MASK		0x03FF
> +#define TPD_TAIL_ADDR_SHIFT		16
> +
> +#define REG_SRAM_TRD_LEN            	0x151C /* In 8-bytes */
> +#define TPD_NIC_LEN_MASK		0x03FF
> +
> +#define REG_SRAM_RXF_ADDR          	0x1520
> +#define REG_SRAM_RXF_LEN            	0x1524
> +#define REG_SRAM_TXF_ADDR           	0x1528
> +#define REG_SRAM_TXF_LEN            	0x152C
> +#define REG_SRAM_TCPH_ADDR          	0x1530
> +#define REG_SRAM_PKTH_ADDR          	0x1532
> +
> +/*
> + * Load Ptr Register
> + * Software sets this bit after the initialization of the head and tail */
> +#define REG_LOAD_PTR                	0x1534
> +
> +/*
> + * addresses of all descriptors, as well as the following descriptor
> + * control register, which triggers each function block to load the head
> + * pointer to prepare for the operation. This bit is then self-cleared
> + * after one cycle.
> + */
> +#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_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
> +
> +/* Jumbo packet Threshold for task offload */
> +#define REG_TX_TSO_OFFLOAD_THRESH	0x1594 /* In 8-bytes */
> +#define TX_TSO_OFFLOAD_THRESH_MASK	0x07FF
> +
> +#define	REG_TXF_WATER_MARK		0x1598 /* In 8-bytes */
> +#define TXF_WATER_MARK_MASK		0x0FFF
> +#define TXF_LOW_WATER_MARK_SHIFT	0
> +#define TXF_HIGH_WATER_MARK_SHIFT 	16
> +#define TXQ_CTRL_BURST_MODE_EN		0x80000000
> +
> +#define REG_THRUPUT_MON_CTRL		0x159C
> +#define THRUPUT_MON_RATE_MASK		0x3
> +#define THRUPUT_MON_RATE_SHIFT		0
> +#define THRUPUT_MON_EN			0x80
> +
> +/* RXQ Control Register */
> +#define REG_RXQ_CTRL                	0x15A0
> +#define ASPM_THRUPUT_LIMIT_MASK		0x3
> +#define ASPM_THRUPUT_LIMIT_SHIFT	0
> +#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 RXQ_RFD_BURST_NUM_MASK		0x003F
> +#define RXQ_RFD_BURST_NUM_SHIFT		20
> +#define RSS_MODE_MASK			0x0003
> +#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 REG_RFD_FREE_THRESH		0x15A4
> +#define RFD_FREE_THRESH_MASK		0x003F
> +#define RFD_FREE_HI_THRESH_SHIFT	0
> +#define RFD_FREE_LO_THRESH_SHIFT	6
> +
> +/* RXF flow control register */
> +#define REG_RXQ_RXF_PAUSE_THRESH    	0x15A8
> +#define RXQ_RXF_PAUSE_TH_HI_SHIFT       0
> +#define RXQ_RXF_PAUSE_TH_HI_MASK        0x0FFF
> +#define RXQ_RXF_PAUSE_TH_LO_SHIFT       16
> +#define RXQ_RXF_PAUSE_TH_LO_MASK        0x0FFF
> +
> +#define REG_RXD_DMA_CTRL		0x15AC
> +#define RXD_DMA_THRESH_MASK		0x0FFF	/* In 8-bytes */
> +#define RXD_DMA_THRESH_SHIFT		0
> +#define RXD_DMA_DOWN_TIMER_MASK		0xFFFF
> +#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_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
> +
> +/* 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_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
> +#define ISR_SMB				0x00000001
> +#define ISR_TIMER			0x00000002
> +/*
> + * Software manual interrupt, for debug. Set when SW_MAN_INT_EN is set
> + * in Table 51 Selene Master Control Register (Offset 0x1400).
> + */
> +#define ISR_MANUAL         		0x00000004
> +#define ISR_HW_RXF_OV          		0x00000008 /* RXF overflow interrupt */
> +#define ISR_RFD0_UR			0x00000010 /* RFD0 under run */
> +#define ISR_RFD1_UR			0x00000020
> +#define ISR_RFD2_UR			0x00000040
> +#define ISR_RFD3_UR			0x00000080
> +#define ISR_TXF_UR			0x00000100
> +#define ISR_DMAR_TO_RST			0x00000200
> +#define ISR_DMAW_TO_RST			0x00000400
> +#define ISR_TX_CREDIT			0x00000800
> +#define ISR_GPHY			0x00001000
> +/* GPHY low power state interrupt */
> +#define ISR_GPHY_LPW           		0x00002000
> +#define ISR_TXQ_TO_RST			0x00004000
> +#define ISR_TX_PKT			0x00008000
> +#define ISR_RX_PKT_0			0x00010000
> +#define ISR_RX_PKT_1			0x00020000
> +#define ISR_RX_PKT_2			0x00040000
> +#define ISR_RX_PKT_3			0x00080000
> +#define ISR_MAC_RX			0x00100000
> +#define ISR_MAC_TX			0x00200000
> +#define ISR_UR_DETECTED			0x00400000
> +#define ISR_FERR_DETECTED		0x00800000
> +#define ISR_NFERR_DETECTED		0x01000000
> +#define ISR_CERR_DETECTED		0x02000000
> +#define ISR_PHY_LINKDOWN		0x04000000
> +#define ISR_DIS_INT			0x80000000
> +
> +/* Interrupt Mask Register */
> +#define REG_IMR				0x1604
> +
> +#define IMR_NORMAL_MASK		(\
> +		ISR_MANUAL	|\
> +		ISR_HW_RXF_OV	|\
> +		ISR_RFD0_UR	|\
> +		ISR_TXF_UR	|\
> +		ISR_DMAR_TO_RST	|\
> +		ISR_TXQ_TO_RST  |\
> +		ISR_DMAW_TO_RST	|\
> +		ISR_GPHY	|\
> +		ISR_TX_PKT	|\
> +		ISR_RX_PKT_0	|\
> +		ISR_GPHY_LPW    |\
> +		ISR_PHY_LINKDOWN)
> +
> +#define ISR_RX_PKT 	(\
> +	ISR_RX_PKT_0    |\
> +	ISR_RX_PKT_1    |\
> +	ISR_RX_PKT_2    |\
> +	ISR_RX_PKT_3)
> +
> +#define ISR_OVER	(\
> +	ISR_RFD0_UR 	|\
> +	ISR_RFD1_UR	|\
> +	ISR_RFD2_UR	|\
> +	ISR_RFD3_UR	|\
> +	ISR_HW_RXF_OV	|\
> +	ISR_TXF_UR)
> +
> +#define ISR_ERROR	(\
> +	ISR_DMAR_TO_RST	|\
> +	ISR_TXQ_TO_RST  |\
> +	ISR_DMAW_TO_RST	|\
> +	ISR_PHY_LINKDOWN)
> +
> +#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
> +#define REG_MAC_TX_STATUS_END 		0x17c0
> +
> +/* DEBUG ADDR */
> +#define REG_DEBUG_DATA0 		0x1900
> +#define REG_DEBUG_DATA1 		0x1904
> +
> +/* PHY Control Register */
> +#define MII_BMCR			0x00
> +#define BMCR_SPEED_SELECT_MSB		0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
> +#define BMCR_COLL_TEST_ENABLE		0x0080  /* Collision test enable */
> +#define BMCR_FULL_DUPLEX		0x0100  /* FDX =1, half duplex =0 */
> +#define BMCR_RESTART_AUTO_NEG		0x0200  /* Restart auto negotiation */
> +#define BMCR_ISOLATE			0x0400  /* Isolate PHY from MII */
> +#define BMCR_POWER_DOWN			0x0800  /* Power down */
> +#define BMCR_AUTO_NEG_EN		0x1000  /* Auto Neg Enable */
> +#define BMCR_SPEED_SELECT_LSB		0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
> +#define BMCR_LOOPBACK			0x4000  /* 0 = normal, 1 = loopback */
> +#define BMCR_RESET			0x8000  /* 0 = normal, 1 = PHY reset */
> +#define BMCR_SPEED_MASK			0x2040
> +#define BMCR_SPEED_1000			0x0040
> +#define BMCR_SPEED_100			0x2000
> +#define BMCR_SPEED_10			0x0000
> +
> +/* PHY Status Register */
> +#define MII_BMSR			0x01
> +#define BMMSR_EXTENDED_CAPS		0x0001  /* Extended register capabilities */
> +#define BMSR_JABBER_DETECT		0x0002  /* Jabber Detected */
> +#define BMSR_LINK_STATUS		0x0004  /* Link Status 1 = link */
> +#define BMSR_AUTONEG_CAPS		0x0008  /* Auto Neg Capable */
> +#define BMSR_REMOTE_FAULT		0x0010  /* Remote Fault Detect */
> +#define BMSR_AUTONEG_COMPLETE		0x0020  /* Auto Neg Complete */
> +#define BMSR_PREAMBLE_SUPPRESS		0x0040  /* Preamble may be suppressed */
> +#define BMSR_EXTENDED_STATUS		0x0100  /* Ext. status info in Reg 0x0F */
> +#define BMSR_100T2_HD_CAPS		0x0200  /* 100T2 Half Duplex Capable */
> +#define BMSR_100T2_FD_CAPS		0x0400  /* 100T2 Full Duplex Capable */
> +#define BMSR_10T_HD_CAPS		0x0800  /* 10T   Half Duplex Capable */
> +#define BMSR_10T_FD_CAPS		0x1000  /* 10T   Full Duplex Capable */
> +#define BMSR_100X_HD_CAPS		0x2000  /* 100X  Half Duplex Capable */
> +#define BMMII_SR_100X_FD_CAPS		0x4000  /* 100X  Full Duplex Capable */
> +#define BMMII_SR_100T4_CAPS		0x8000  /* 100T4 Capable */
> +
> +#define MII_PHYSID1			0x02
> +#define MII_PHYSID2			0x03
> +
> +/* Autoneg Advertisement Register */
> +#define MII_ADVERTISE			0x04
> +#define ADVERTISE_SELECTOR_FIELD	0x0001  /* indicates IEEE 802.3 CSMA/CD */
> +#define ADVERTISE_10T_HD_CAPS		0x0020  /* 10T   Half Duplex Capable */
> +#define ADVERTISE_10T_FD_CAPS		0x0040  /* 10T   Full Duplex Capable */
> +#define ADVERTISE_100TX_HD_CAPS		0x0080  /* 100TX Half Duplex Capable */
> +#define ADVERTISE_100TX_FD_CAPS		0x0100  /* 100TX Full Duplex Capable */
> +#define ADVERTISE_100T4_CAPS		0x0200  /* 100T4 Capable */
> +#define ADVERTISE_PAUSE			0x0400  /* Pause operation desired */
> +#define ADVERTISE_ASM_DIR		0x0800  /* Asymmetric Pause Direction bit */
> +#define ADVERTISE_REMOTE_FAULT		0x2000  /* Remote Fault detected */
> +#define ADVERTISE_NEXT_PAGE		0x8000  /* Next Page ability supported */
> +#define ADVERTISE_SPEED_MASK		0x01E0
> +#define ADVERTISE_DEFAULT_CAP		0x0DE0
> +
> +#if 0
> +/* Link partner ability register */
> +#define MII_LPA				0x05
> +#define LPA_SLCT			0x001   /* Same as advertise selector  */
> +#define LPA_10HALF			0x002   /* Can do 10mbps half-duplex   */
> +#define LPA_10FULL			0x0040  /* Can do 10mbps full-duplex   */
> +#define LPA_100HALF			0x0080  /* Can do 100mbps half-duplex  */
> +#define LPA_100FULL			0x0100  /* Can do 100mbps full-duplex  */
> +#define LPA_100BASE4			0x0200  /* 100BASE-T4  */
> +#define LPA_PAUSE			0x0400  /* PAUSE */
> +#define LPA_ASYPAUSE			0x0800  /* Asymmetrical PAUSE */
> +#define LPA_RFAULT			0x2000  /* Link partner faulted        */
> +#define LPA_LPACK			0x4000  /* Link partner acked us       */
> +#define LPA_NPAGE			0x8000  /* Next page bit               */
> +#endif

Remove.

> +/* 1000BASE-T Control Register */
> +#define MII_GIGA_CR			0x09
> +#define GIGA_CR_1000T_HD_CAPS		0x0100  /* Advertise 1000T HD capability */
> +#define GIGA_CR_1000T_FD_CAPS		0x0200  /* Advertise 1000T FD capability  */
> +#define GIGA_CR_1000T_REPEATER_DTE	0x0400  /* 1=Repeater/switch device port 0=DTE device */
> +
> +#define GIGA_CR_1000T_MS_VALUE		0x0800  /* 1=Configure PHY as Master 0=Configure PHY as Slave */
> +#define GIGA_CR_1000T_MS_ENABLE		0x1000  /* 1=Master/Slave manual config value 0=Automatic Master/Slave config */
> +#define GIGA_CR_1000T_TEST_MODE_NORMAL	0x0000  /* Normal Operation */
> +#define GIGA_CR_1000T_TEST_MODE_1	0x2000  /* Transmit Waveform test */
> +#define GIGA_CR_1000T_TEST_MODE_2	0x4000  /* Master Transmit Jitter test */
> +#define GIGA_CR_1000T_TEST_MODE_3	0x6000  /* Slave Transmit Jitter test */
> +#define GIGA_CR_1000T_TEST_MODE_4	0x8000	/* Transmitter Distortion test */
> +#define GIGA_CR_1000T_SPEED_MASK	0x0300
> +#define GIGA_CR_1000T_DEFAULT_CAP	0x0300
> +
> +/* PHY Specific Status Register */
> +#define MII_GIGA_PSSR			0x11
> +#define GIGA_PSSR_SPD_DPLX_RESOLVED	0x0800  /* 1=Speed & Duplex resolved */
> +#define GIGA_PSSR_DPLX			0x2000  /* 1=Duplex 0=Half Duplex */
> +#define GIGA_PSSR_SPEED			0xC000  /* Speed, bits 14:15 */
> +#define GIGA_PSSR_10MBS			0x0000  /* 00=10Mbs */
> +#define GIGA_PSSR_100MBS		0x4000  /* 01=100Mbs */
> +#define GIGA_PSSR_1000MBS		0x8000  /* 10=1000Mbs */
> +
> +/* PHY Interrupt Enable Register */
> +#define MII_IER				0x12
> +#define IER_LINK_UP			0x0400
> +#define IER_LINK_DOWN			0x0800
> +
> +/* PHY Interrupt Status Register */
> +#define MII_ISR				0x13
> +#define ISR_LINK_UP			0x0400
> +#define ISR_LINK_DOWN			0x0800
> +
> +/* Cable-Detect-Test Control Register */
> +#define MII_CDTC			0x16
> +#define CDTC_EN_OFF			0   /* sc */
> +#define CDTC_EN_BITS			1
> +#define CDTC_PAIR_OFF			8
> +#define CDTC_PAIR_BIT			2
> +
> +/* Cable-Detect-Test Status Register */
> +#define MII_CDTS			0x1C
> +#define CDTS_STATUS_OFF			8
> +#define CDTS_STATUS_BITS		2
> +#define CDTS_STATUS_NORMAL		0
> +#define CDTS_STATUS_SHORT		1
> +#define CDTS_STATUS_OPEN		2
> +#define CDTS_STATUS_INVALID		3
> +
> +#define MII_DBG_ADDR			0x1D
> +#define MII_DBG_DATA			0x1E
> +
> +#endif /*_ATL1C_HW_H_*/
> diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
> new file mode 100644
> index 0000000..5da217d
> --- /dev/null
> +++ b/drivers/net/atl1c/atl1c_main.c
> @@ -0,0 +1,2804 @@
> +/*
> + * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
> + *
> + * Derived from Intel e1000 driver
> + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
> + * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
> + */
> +
> +#include "atl1c.h"
> +
> +#define DRV_VERSION "1.0.0.1-NAPI"
> +char atl1c_driver_name[] = "ATL1C";

Minor nit, but why uppercase?

> +char atl1c_driver_version[] = DRV_VERSION;
> +#define PCI_DEVICE_ID_ATTANSIC_L2C      0x1062
> +#define PCI_DEVICE_ID_ATTANSIC_L1C      0x1063

The kconfig file indicates support for only the L1C.  Does this driver also support the L2C?  Is the L1C a gigabit device and the L2C a 10/100 device?

> +/*
> + * atl1c_pci_tbl - PCI Device ID Table
> + *
> + * Wildcard entries (PCI_ANY_ID) should come last
> + * Last entry must be all 0s
> + *
> + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
> + *   Class, Class Mask, private data (not used) }
> + */
> +static struct pci_device_id atl1c_pci_tbl[] = {
> +	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)},
> +	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)},
> +	/* required last entry */
> +	{ 0 }
> +};
> +MODULE_DEVICE_TABLE(pci, atl1c_pci_tbl);
> +
> +MODULE_AUTHOR("Jie Yang <jie.yang@atheros.com>");
> +MODULE_DESCRIPTION("Atheros 1000M Ethernet Network Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION(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,
> +		   int *work_done, int work_to_do);

Please reorder the code to eliminate the need for these forward declarations.

> +
> +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
> +};
> +
> +/*
> + * atl1c_init_pcie - init PCIE module
> + */
> +static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag)
> +{
> +	u32 data;
> +	u32 pci_cmd;
> +
> +	AT_READ_REG(hw, PCI_COMMAND, &pci_cmd);
> +	pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
> +	pci_cmd |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
> +		PCI_COMMAND_IO);
> +	AT_WRITE_REG(hw, PCI_COMMAND, pci_cmd);
> +
> +	/*
> +	 * Clear any PowerSaveing Settings
> +	 */
> +	AT_WRITE_REG(hw, REG_PM_CTRLSTAT, 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);
> +
> +	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(1);
> +}
> +
> +/*
> + * atl1c_irq_enable - Enable default interrupt generation settings
> + * @adapter: board private structure
> + */
> +static inline void atl1c_irq_enable(struct atl1c_adapter *adapter)
> +{
> +	if (likely(atomic_dec_and_test(&adapter->irq_sem))) {
> +		AT_WRITE_REG(&adapter->hw, REG_ISR, 0x7FFFFFFF);
> +		AT_WRITE_REG(&adapter->hw, REG_IMR, adapter->hw.intr_mask);
> +		AT_WRITE_FLUSH(&adapter->hw);
> +	}
> +}
> +
> +/*
> + * atl1c_irq_disable - Mask off interrupt generation on the NIC
> + * @adapter: board private structure
> + */
> +static inline void atl1c_irq_disable(struct atl1c_adapter *adapter)
> +{
> +	atomic_inc(&adapter->irq_sem);
> +	AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
> +	AT_WRITE_FLUSH(&adapter->hw);
> +	synchronize_irq(adapter->pdev->irq);
> +}
> +
> +/*
> + * atl1c_irq_reset - reset interrupt confiure on the NIC
> + * @adapter: board private structure
> + */
> +static inline void atl1c_irq_reset(struct atl1c_adapter *adapter)
> +{
> +	atomic_set(&adapter->irq_sem, 1);
> +	atl1c_irq_enable(adapter);
> +}
> +
> +/*
> + * atl1c_phy_config - Timer Call-back
> + * @data: pointer to netdev cast into an unsigned long
> + */
> +static void atl1c_phy_config(unsigned long data)
> +{
> +	struct atl1c_adapter *adapter = (struct atl1c_adapter *) data;
> +	struct atl1c_hw *hw = &adapter->hw;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&adapter->mdio_lock, flags);
> +	atl1c_restart_autoneg(hw);
> +	spin_unlock_irqrestore(&adapter->mdio_lock, flags);
> +}
> +
> +void atl1c_reinit_locked(struct atl1c_adapter *adapter)
> +{
> +
> +	WARN_ON(in_interrupt());
> +	atl1c_down(adapter);
> +	atl1c_up(adapter);
> +	clear_bit(__AT_RESETTING, &adapter->flags);
> +}
> +
> +static void atl1c_reset_task(struct work_struct *work)
> +{
> +	struct atl1c_adapter *adapter;
> +	u32 isr_data;
> +
> +	adapter = container_of(work, struct atl1c_adapter, reset_task);
> +
> +	if (netif_queue_stopped(adapter->netdev) &&
> +			netif_carrier_ok(adapter->netdev)) {
> +		AT_READ_REG(&adapter->hw, REG_ISR, &isr_data);
> +		printk(KERN_EMERG "TX STOPED!\n");
> +		printk(KERN_EMERG "reset hardware!\n");
> +		printk(KERN_EMERG "ISR is %x\n", isr_data);
> +		netif_wake_queue(adapter->netdev);
> +	}
> +}

This function doesn't seem to reset the hardware as the name and comments imply.  It just reads the ISR and wakes the tx queue.

> +
> +static void atl1c_check_link_status(struct atl1c_adapter *adapter)
> +{
> +	struct atl1c_hw *hw = &adapter->hw;
> +	struct net_device *netdev = adapter->netdev;
> +	struct pci_dev    *pdev   = adapter->pdev;
> +	int err = 0;
> +	unsigned long flags;
> +	u16 speed, duplex, phy_data;
> +
> +	spin_lock_irqsave(&adapter->mdio_lock, flags);
> +	/* MII_BMSR must read twise */
> +	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
> +	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
> +	spin_unlock_irqrestore(&adapter->mdio_lock, flags);
> +
> +	if ((phy_data & BMSR_LSTATUS) == 0) {
> +		/* link down */
> +		if (netif_carrier_ok(netdev)) {
> +			hw->hibernate = true;
> +			atl1c_set_aspm(hw, false);
> +			if (atl1c_stop_mac(hw) != 0)
> +				dev_info(&pdev->dev, "stop mac failed\n");
> +		}
> +		netif_carrier_off(netdev);
> +		netif_stop_queue(netdev);
> +	} else {
> +		/* Link Up */
> +		hw->hibernate = false;
> +		spin_lock_irqsave(&adapter->mdio_lock, flags);
> +		err = atl1c_get_speed_and_duplex(hw, &speed, &duplex);
> +		spin_unlock_irqrestore(&adapter->mdio_lock, flags);
> +		if (unlikely(err))
> +			return;
> +		/* link result is our setting */
> +		if (adapter->link_speed != speed ||
> +		    adapter->link_duplex != duplex) {
> +			adapter->link_speed  = speed;
> +			adapter->link_duplex = duplex;
> +			atl1c_enable_tx_ctrl(hw);
> +			atl1c_enable_rx_ctrl(hw);
> +			atl1c_setup_mac_ctrl(adapter);
> +			atl1c_set_aspm(hw, true);
> +			dev_info(&pdev->dev,
> +				"%s: %s NIC Link is Up<%d Mbps %s>\n",
> +				atl1c_driver_name, netdev->name,
> +				adapter->link_speed,
> +				adapter->link_duplex == FULL_DUPLEX ?
> +				"Full Duplex" : "Half Duplex");
> +		}
> +		if (!netif_carrier_ok(netdev)) {
> +			netif_carrier_on(netdev);
> +			netif_wake_queue(netdev);
> +		}
> +	}
> +}
> +
> +/*
> + * atl1c_link_chg_task - deal with link change event Out of interrupt context
> + * @netdev: network interface device structure
> + */
> +static void atl1c_link_chg_task(struct work_struct *work)
> +{
> +	struct atl1c_adapter *adapter;
> +
> +	adapter = container_of(work, struct atl1c_adapter, link_chg_task);
> +	atl1c_check_link_status(adapter);
> +}
> +
> +static void atl1c_link_chg_event(struct atl1c_adapter *adapter)
> +{
> +	struct net_device *netdev = adapter->netdev;
> +	struct pci_dev    *pdev   = adapter->pdev;
> +	u16 phy_data = 0;
> +	u16 link_up = 0;
> +
> +	spin_lock(&adapter->mdio_lock);
> +	atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
> +	atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
> +	spin_unlock(&adapter->mdio_lock);
> +	link_up = phy_data & BMSR_LSTATUS;
> +	/* notify upper layer link down ASAP */
> +	if (!link_up) {
> +		if (netif_carrier_ok(netdev)) {
> +			/* old link state: Up */
> +			netif_carrier_off(netdev);
> +			netif_stop_queue(netdev);
> +			dev_info(&pdev->dev, "%s: %s NIC Link is Down\n",
> +					atl1c_driver_name, netdev->name);
> +			adapter->link_speed = SPEED_0;
> +		}
> +	}
> +	schedule_work(&adapter->link_chg_task);
> +}
> +
> +static void atl1c_del_timer(struct atl1c_adapter *adapter)
> +{
> +	del_timer_sync(&adapter->phy_config_timer);
> +}
> +
> +static void atl1c_cancel_work(struct atl1c_adapter *adapter)
> +{
> +	cancel_work_sync(&adapter->reset_task);
> +	cancel_work_sync(&adapter->link_chg_task);
> +}
> +
> +/*
> + * atl1c_tx_timeout - Respond to a Tx Hang
> + * @netdev: network interface device structure
> + */
> +static void atl1c_tx_timeout(struct net_device *netdev)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	/* Do the reset outside of interrupt context */
> +	schedule_work(&adapter->reset_task);
> +}
> +
> +/*
> + * atl1c_set_multi - Multicast and Promiscuous mode set
> + * @netdev: network interface device structure
> + *
> + * The set_multi entry point is called whenever the multicast address
> + * list or the network interface flags are updated.  This routine is
> + * responsible for configuring the hardware for proper multicast,
> + * promiscuous mode, and all-multi behavior.
> + */
> +static void atl1c_set_multi(struct net_device *netdev)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct atl1c_hw *hw = &adapter->hw;
> +	struct dev_mc_list *mc_ptr;
> +	u32 mac_ctrl_data = 0;
> +	u32 hash_value;
> +
> +	/* Check for Promiscuous and All Multicast modes */
> +	AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl_data);
> +
> +	if (netdev->flags & IFF_PROMISC) {
> +		mac_ctrl_data |= MAC_CTRL_PROMIS_EN;
> +	} else if (netdev->flags & IFF_ALLMULTI) {
> +		mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
> +		mac_ctrl_data &= ~MAC_CTRL_PROMIS_EN;
> +	} else {
> +		mac_ctrl_data &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
> +	}
> +
> +	AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
> +
> +	/* clear the old settings from the multicast hash table */
> +	AT_WRITE_REG(hw, REG_RX_HASH_TABLE, 0);
> +	AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
> +
> +	/* comoute mc addresses' hash value ,and put it into hash table */
> +	for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
> +		hash_value = atl1c_hash_mc_addr(hw, mc_ptr->dmi_addr);
> +		atl1c_hash_set(hw, hash_value);
> +	}
> +}
> +
> +static void atl1c_vlan_rx_register(struct net_device *netdev,
> +				   struct vlan_group *grp)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct pci_dev *pdev = adapter->pdev;
> +	u32 mac_ctrl_data = 0;
> +
> +	dev_dbg(&pdev->dev, "atl1c_vlan_rx_register\n");
> +
> +	atl1c_irq_disable(adapter);
> +
> +	adapter->vlgrp = grp;
> +	AT_READ_REG(&adapter->hw, REG_MAC_CTRL, &mac_ctrl_data);
> +
> +	if (grp) {
> +		/* enable VLAN tag insert/strip */
> +		mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
> +	} else {
> +		/* disable VLAN tag insert/strip */
> +		mac_ctrl_data &= ~MAC_CTRL_RMV_VLAN;
> +	}
> +
> +	AT_WRITE_REG(&adapter->hw, REG_MAC_CTRL, mac_ctrl_data);
> +	atl1c_irq_enable(adapter);
> +}
> +
> +static void atl1c_restore_vlan(struct atl1c_adapter *adapter)
> +{
> +	struct pci_dev *pdev = adapter->pdev;
> +
> +	dev_dbg(&pdev->dev, "atl1c_restore_vlan !");
> +	atl1c_vlan_rx_register(adapter->netdev, adapter->vlgrp);
> +}
> +/*
> + * atl1c_set_mac - Change the Ethernet Address of the NIC
> + * @netdev: network interface device structure
> + * @p: pointer to an address structure
> + *
> + * Returns 0 on success, negative on failure
> + */
> +static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct sockaddr *addr = p;
> +
> +	if (!is_valid_ether_addr(addr->sa_data))
> +		return -EADDRNOTAVAIL;
> +
> +	if (netif_running(netdev))
> +		return -EBUSY;
> +
> +	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);
> +
> +	return 0;
> +}
> +
> +static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
> +				struct net_device *dev)
> +{
> +	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;
> +}
> +/*
> + * atl1c_change_mtu - Change the Maximum Transfer Unit
> + * @netdev: network interface device structure
> + * @new_mtu: new value for maximum frame size
> + *
> + * Returns 0 on success, negative on failure
> + */
> +static int atl1c_change_mtu(struct net_device *netdev, int new_mtu)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	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)) {
> +		dev_warn(&adapter->pdev->dev, "invalid MTU setting\n");
> +		return -EINVAL;
> +	}
> +	/* set MTU */
> +	if (old_mtu != new_mtu && netif_running(netdev)) {
> +		while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
> +			msleep(1);
> +		netdev->mtu = new_mtu;
> +		adapter->hw.max_frame_size = new_mtu;
> +		atl1c_set_rxbufsize(adapter, netdev);
> +		atl1c_down(adapter);
> +		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;
> +}
> +
> +/*
> + *  caller should hold mdio_lock
> + */
> +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);
> +	return result;
> +}
> +
> +static void atl1c_mdio_write(struct net_device *netdev, int phy_id,
> +			     int reg_num, int val)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	atl1c_write_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, val);
> +}
> +
> +/*
> + * atl1c_mii_ioctl -
> + * @netdev:
> + * @ifreq:
> + * @cmd:
> + */
> +static int atl1c_mii_ioctl(struct net_device *netdev,
> +			   struct ifreq *ifr, int cmd)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct pci_dev *pdev = adapter->pdev;
> +	struct mii_ioctl_data *data = if_mii(ifr);
> +	unsigned long flags;
> +	int retval = 0;
> +
> +	if (!netif_running(netdev))
> +		return -EINVAL;
> +
> +	spin_lock_irqsave(&adapter->mdio_lock, flags);
> +	switch (cmd) {
> +	case SIOCGMIIPHY:
> +		data->phy_id = 0;
> +		break;
> +
> +	case SIOCGMIIREG:
> +		if (!capable(CAP_NET_ADMIN)) {
> +			retval = -EPERM;
> +			goto out;
> +		}
> +		if (atl1c_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
> +				    &data->val_out)) {
> +			retval = -EIO;
> +			goto out;
> +		}
> +		break;
> +
> +	case SIOCSMIIREG:
> +		if (!capable(CAP_NET_ADMIN)) {
> +			retval = -EPERM;
> +			goto out;
> +		}
> +		if (data->reg_num & ~(0x1F)) {
> +			retval = -EFAULT;
> +			goto out;
> +		}
> +
> +		dev_dbg(&pdev->dev, "<atl1c_mii_ioctl> write %x %x",
> +				data->reg_num, data->val_in);
> +		if (atl1c_write_phy_reg(&adapter->hw,
> +				     data->reg_num, data->val_in)) {
> +			retval = -EIO;
> +			goto out;
> +		}
> +		break;
> +
> +	default:
> +		retval = -EOPNOTSUPP;
> +		break;
> +	}
> +out:
> +	spin_unlock_irqrestore(&adapter->mdio_lock, flags);
> +	return retval;
> +
> +}
> +
> +/*
> + * atl1c_ioctl -
> + * @netdev:
> + * @ifreq:
> + * @cmd:
> + */
> +static int atl1c_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
> +{
> +	switch (cmd) {
> +	case SIOCGMIIPHY:
> +	case SIOCGMIIREG:
> +	case SIOCSMIIREG:
> +		return atl1c_mii_ioctl(netdev, ifr, cmd);
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
> +/*
> + * atl1c_alloc_queues - Allocate memory for all rings
> + * @adapter: board private structure to initialize
> + *
> + */
> +static int __devinit atl1c_alloc_queues(struct atl1c_adapter *adapter)
> +{
> +	return 0;
> +}
> +
> +static void atl1c_set_mac_type(struct atl1c_hw *hw)
> +{
> +	switch (hw->device_id) {
> +	case PCI_DEVICE_ID_ATTANSIC_L2C:
> +		hw->nic_type = athr_l2c;
> +		break;
> +
> +	case PCI_DEVICE_ID_ATTANSIC_L1C:
> +		hw->nic_type = athr_l1c;
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	return;
> +}
> +
> +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_CLEAR_ON_READ |
> +			 ATL1C_INTR_MODRT_ENABLE  |
> +			 ATL1C_RX_IPV6_CHKSUM	  |
> +			 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 (hw->nic_type == athr_l1c) {
> +		hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
> +		hw->ctrl_flags |= ATL1C_LINK_CAP_1000M;
> +	}
> +	return 0;
> +}
> +/*
> + * atl1c_sw_init - Initialize general software structures (struct atl1c_adapter)
> + * @adapter: board private structure to initialize
> + *
> + * atl1c_sw_init initializes the Adapter private data structure.
> + * 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)
> +{
> +	struct atl1c_hw *hw   = &adapter->hw;
> +	struct pci_dev	*pdev = adapter->pdev;
> +
> +	hw->vendor_id = pdev->vendor;
> +	hw->device_id = pdev->device;
> +	hw->subsystem_vendor_id = pdev->subsystem_vendor;
> +	hw->subsystem_id = pdev->subsystem_device;
> +
> +	/* before link up, we assume hibernate is true */
> +	hw->hibernate = true;
> +	if (atl1c_setup_mac_funcs(hw) != 0) {
> +		dev_err(&pdev->dev, "set mac function pointers failed\n");
> +		return -1;
> +	}
> +	adapter->wol = 0;
> +	adapter->link_speed = SPEED_0;
> +	adapter->link_duplex = FULL_DUPLEX;
> +	adapter->num_rx_queues = AT_DEF_RECEIVE_QUEUE;
> +
> +	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 = ADVERTISE_DEFAULT;
> +	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->tpd_burst = 5;
> +	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");
> +		return -ENOMEM;
> +	}
> +	/* TODO */
> +	atl1c_set_rxbufsize(adapter, adapter->netdev);
> +	atomic_set(&adapter->irq_sem, 1);
> +	spin_lock_init(&adapter->mdio_lock);
> +	spin_lock_init(&adapter->tx_lock);
> +	set_bit(__AT_DOWN, &adapter->flags);
> +
> +	return 0;
> +}
> +
> +/*
> + * atl1c_clean_tx_ring - Free Tx-skb
> + * @adapter: board private structure
> + */
> +static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter,
> +				enum atl1c_trans_queue type)
> +{
> +	struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
> +	struct atl1c_buffer *buffer_info;
> +	struct pci_dev *pdev = adapter->pdev;
> +	u16 index, ring_count;
> +
> +	ring_count = tpd_ring->count;
> +	for (index = 0; index < ring_count; index++) {
> +		buffer_info = &tpd_ring->buffer_info[index];
> +		if (buffer_info->state == ATL1_BUFFER_FREE)
> +			continue;
> +		if (buffer_info->dma)
> +			pci_unmap_single(pdev, buffer_info->dma,
> +					buffer_info->length,
> +					PCI_DMA_TODEVICE);
> +		if (buffer_info->skb)
> +			dev_kfree_skb(buffer_info->skb);
> +		buffer_info->dma = 0;
> +		buffer_info->skb = NULL;
> +		buffer_info->state = ATL1_BUFFER_FREE;
> +	}
> +
> +	/* Zero out Tx-buffers */
> +	memset(tpd_ring->desc, 0, sizeof(struct atl1c_tpd_desc) *
> +				ring_count);
> +	atomic_set(&tpd_ring->next_to_clean, 0);
> +	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_buffer *buffer_info;
> +	struct pci_dev *pdev = adapter->pdev;
> +	int i, 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];
> +			if (buffer_info->state == ATL1_BUFFER_FREE)
> +				continue;
> +			if (buffer_info->dma)
> +				pci_unmap_single(pdev, buffer_info->dma,
> +						buffer_info->length,
> +						PCI_DMA_FROMDEVICE);
> +			if (buffer_info->skb)
> +				dev_kfree_skb(buffer_info->skb);
> +			buffer_info->state = ATL1_BUFFER_FREE;
> +			buffer_info->skb = NULL;
> +		}
> +		/* 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;
> +	}
> +}
> +
> +/*
> + * Read / Write Ptr Initialize:
> + */
> +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_buffer *buffer_info;
> +	int i, j;
> +
> +	for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
> +		tpd_ring[i].next_to_use = 0;
> +		atomic_set(&tpd_ring[i].next_to_clean, 0);
> +		buffer_info = tpd_ring[i].buffer_info;
> +		for (j = 0; j < tpd_ring->count; j++)
> +			buffer_info[i].state = ATL1_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];
> +			buffer_info->state = ATL1_BUFFER_FREE;
> +		}
> +	}
> +}
> +
> +/*
> + * atl1c_free_ring_resources - Free Tx / RX descriptor Resources
> + * @adapter: board private structure
> + *
> + * Free all transmit software resources
> + */
> +static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
> +{
> +	struct pci_dev *pdev = adapter->pdev;
> +
> +	pci_free_consistent(pdev, adapter->ring_header.size,
> +					adapter->ring_header.desc,
> +					adapter->ring_header.dma);
> +	adapter->ring_header.desc = NULL;
> +
> +	/* Note: just free tdp_ring.buffer_info,
> +	*  it contain rfd_ring.buffer_info, do not double free */
> +	if (adapter->tpd_ring[0].buffer_info) {
> +		kfree(adapter->tpd_ring[0].buffer_info);
> +		adapter->tpd_ring[0].buffer_info = NULL;
> +	}
> +}
> +
> +/*
> + * atl1c_setup_mem_resources - allocate Tx / RX descriptor resources
> + * @adapter: board private structure
> + *
> + * Return 0 on success, negative on failure
> + */
> +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_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;
> +	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);
> +	tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
> +	if (unlikely(!tpd_ring->buffer_info)) {
> +		dev_err(&pdev->dev, "kzalloc failed, size = %d\n",
> +			size);
> +		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);
> +		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;
> +	}
> +	/*
> +	 * real ring DMA buffer
> +	 * each ring/block may need up to 8 bytes for alignment, hence the
> +	 * additional bytes tacked onto the end.
> +	 */
> +	ring_header->size = size =
> +		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;
> +
> +	ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
> +				&ring_header->dma);
> +	if (unlikely(!ring_header->desc)) {
> +		dev_err(&pdev->dev, "pci_alloc_consistend failed\n");
> +		goto err_nomem;
> +	}
> +	memset(ring_header->desc, 0, ring_header->size);
> +	/* init TPD ring */
> +
> +	tpd_ring[0].dma = roundup(ring_header->dma, 8);
> +	offset = tpd_ring[0].dma - ring_header->dma;
> +	for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
> +		tpd_ring[i].dma = ring_header->dma + offset;
> +		tpd_ring[i].desc = (u8 *) ring_header->desc + offset;
> +		tpd_ring[i].size =
> +			sizeof(struct atl1c_tpd_desc) * tpd_ring[i].count;
> +		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);
> +	}
> +
> +	/* 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);
> +	}
> +
> +	adapter->smb.dma = ring_header->dma + offset;
> +	adapter->smb.smb = (u8 *)ring_header->desc + offset;
> +	return 0;
> +
> +err_nomem:
> +	kfree(tpd_ring->buffer_info);
> +	return -ENOMEM;
> +}
> +
> +static void atl1c_configure_des_ring(const struct atl1c_adapter *adapter)
> +{
> +	struct atl1c_hw *hw = (struct atl1c_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_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;
> +
> +	/* 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,
> +			(u32)(tpd_ring[atl1c_trans_normal].dma &
> +				AT_DMA_LO_ADDR_MASK));
> +	AT_WRITE_REG(hw, REG_HTPD_HEAD_ADDR_LO,
> +			(u32)(tpd_ring[atl1c_trans_high].dma &
> +				AT_DMA_LO_ADDR_MASK));
> +	AT_WRITE_REG(hw, REG_TPD_RING_SIZE,
> +			(u32)(tpd_ring[0].count & TPD_RING_SIZE_MASK));
> +
> +
> +	/* 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));
> +
> +	AT_WRITE_REG(hw, REG_RFD_RING_SIZE,
> +			rfd_ring[0].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_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);
> +
> +	/* 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));
> +	/* Load all of base address above */
> +	AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
> +
> +	return;
> +}
> +
> +static void atl1c_configure_tx(struct atl1c_adapter *adapter)
> +{
> +	struct atl1c_hw *hw = (struct atl1c_hw *)&adapter->hw;
> +	u32 dev_ctrl_data;
> +	u32 max_pay_load;
> +	u16 tx_offload_thresh;
> +	u32 txq_ctrl_data;
> +	u32 extra_size = 0;     /* Jumbo frame threshold in QWORD unit */
> +
> +	extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
> +	tx_offload_thresh = MAX_TX_OFFLOAD_THRESH;
> +	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(max_pay_load, hw->dmaw_block);
> +	max_pay_load  = (dev_ctrl_data >> DEVICE_CTRL_MAX_RREQ_SZ_SHIFT) &
> +			DEVICE_CTRL_MAX_RREQ_SZ_MASK;
> +	hw->dmar_block = min(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;
> +	txq_ctrl_data |= (atl1c_pay_load_size[hw->dmar_block] &
> +			TXQ_TXF_BURST_NUM_MASK) << TXQ_TXF_BURST_NUM_SHIFT;
> +
> +	AT_WRITE_REG(hw, REG_TXQ_CTRL, txq_ctrl_data);
> +	return;
> +}
> +
> +static void atl1c_configure_rx(struct atl1c_adapter *adapter)
> +{
> +	struct atl1c_hw *hw = (struct atl1c_hw *)&adapter->hw;
> +	u32 rxq_ctrl_data;
> +
> +	rxq_ctrl_data = (hw->rfd_burst & RXQ_RFD_BURST_NUM_MASK) <<
> +			RXQ_RFD_BURST_NUM_SHIFT;
> +
> +	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_100M &
> +			ASPM_THRUPUT_LIMIT_MASK) << ASPM_THRUPUT_LIMIT_SHIFT;
> +
> +	AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data);
> +
> +	return;
> +}
> +
> +static void atl1c_configure_rss(struct atl1c_adapter *adapter)
> +{
> +	struct atl1c_hw *hw = (struct atl1c_hw *)&adapter->hw;
> +
> +	AT_WRITE_REG(hw, REG_IDT_TABLE, hw->indirect_tab);
> +	AT_WRITE_REG(hw, REG_BASE_CPU_NUMBER, hw->base_cpu);
> +
> +	return;
> +}
> +
> +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;
> +
> +	AT_WRITE_REG(hw, REG_DMA_CTRL, dma_ctrl_data);
> +	return;
> +}
> +
> +/*
> + * Stop the mac, transmit and receive units
> + * hw - Struct containing variables accessed by shared code
> + * return : 0  or  idle status (if error)
> + */
> +static int atl1c_stop_mac(struct atl1c_hw *hw)
> +{
> +	u32 data;
> +	int timeout;
> +
> +	AT_READ_REG(hw, REG_RXQ_CTRL, &data);
> +	data &= ~(RXQ1_CTRL_EN | RXQ2_CTRL_EN |
> +		  RXQ3_CTRL_EN | 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);
> +
> +	for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
> +		AT_READ_REG(hw, REG_IDLE_STATUS, &data);
> +		if ((data & (IDLE_STATUS_RXQ_NO_IDLE |
> +			IDLE_STATUS_TXQ_NO_IDLE)) == 0)
> +			break;
> +		msleep(1);
> +	}
> +
> +	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);
> +
> +	for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
> +		AT_READ_REG(hw, REG_IDLE_STATUS, &data);
> +		if ((data & IDLE_STATUS_MASK) == 0)
> +			return 0;
> +		msleep(1);
> +	}
> +	return data;
> +}
> +
> +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);
> +}
> +
> +static void atl1c_enable_tx_ctrl(struct atl1c_hw *hw)
> +{
> +	u32 data;
> +
> +	AT_READ_REG(hw, REG_TXQ_CTRL, &data);
> +	data |= TXQ_CTRL_EN;
> +	AT_WRITE_REG(hw, REG_TXQ_CTRL, data);
> +}
> +
> +/*
> + * Reset the transmit and receive units; mask and clear all interrupts.
> + * hw - Struct containing variables accessed by shared code
> + * return : 0  or  idle status (if error)
> + */
> +static int atl1c_reset_mac(struct atl1c_hw *hw)
> +{
> +	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
> +	struct pci_dev *pdev = adapter->pdev;
> +	u32 idle_status_data = 0;
> +	int timeout = 0;
> +	int ret;
> +
> +	AT_WRITE_REG(hw, REG_IMR, 0);
> +	AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT);
> +
> +	ret = atl1c_stop_mac(hw);
> +	if (ret)
> +		return ret;
> +	/*
> +	 * Issue Soft Reset to the MAC.  This will reset the chip's
> +	 * transmit, receive, DMA.  It will not effect
> +	 * the current PCI configuration.  The global reset bit is self-
> +	 * clearing, and should clear within a microsecond.
> +	 */
> +	AT_WRITE_REGW(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST);
> +	msleep(10);
> +	wmb();
> +	/* Wait at least 10ms for All module to be Idle */
> +	for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
> +		AT_READ_REG(hw, REG_IDLE_STATUS, &idle_status_data);
> +		if ((idle_status_data & IDLE_STATUS_MASK) == 0)
> +			break;
> +		msleep(1);
> +	}
> +	if (timeout >= AT_HW_MAX_IDLE_DELAY) {
> +		dev_err(&pdev->dev,
> +			"MAC state machine cann't be idle since"
> +			" disabled for 10ms second\n");
> +		return AT_ERR_TIMEOUT;
> +	}
> +	return 0;
> +}
> +
> +static void atl1c_disable_l0s_l1(struct atl1c_hw *hw)
> +{
> +	u32 pm_ctrl_data;
> +
> +	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);
> +}
> +
> +/*
> + * Set ASPM state.
> + * Enable/disable L0s/L1 depend on link state.
> + */
> +static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
> +{
> +	u32 pm_ctrl_data;
> +
> +	AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
> +
> +	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_L1_EN;
> +	pm_ctrl_data &=  ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
> +			PM_CTRL_L1_ENTRY_TIMER_SHIFT);
> +
> +	pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
> +
> +	if (linkup) {
> +		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 |= AT_ASPM_L1_TIMER <<
> +				PM_CTRL_L1_ENTRY_TIMER_SHIFT;
> +			pm_ctrl_data |= PM_CTRL_ASPM_L1_EN;
> +		} else
> +			pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
> +
> +		if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
> +			pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
> +		else
> +			pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
> +
> +	} else {
> +		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);
> +
> +	if (adapter->vlgrp)
> +		mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
> +
> +	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;
> +	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)
> +{
> +	struct atl1c_hw *hw = &adapter->hw;
> +	u32 master_ctrl_data = 0;
> +	u32 intr_modrt_data;
> +
> +	/* clear interrupt status */
> +	AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF);
> +	/*  Clear any WOL status */
> +	AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
> +	/* set Interrupt Clear Timer
> +	 * HW will enable self to assert interrupt event to system after
> +	 * waiting x-time for software to notify it accept interrupt.
> +	 */
> +	AT_WRITE_REG(hw, REG_INT_RETRIG_TIMER,
> +		hw->ict & INT_RETRIG_TIMER_MASK);
> +
> +	atl1c_configure_des_ring(adapter);
> +
> +	if (hw->ctrl_flags & ATL1C_INTR_MODRT_ENABLE) {
> +		intr_modrt_data = (hw->tx_imt & IRQ_MODRT_TIMER_MASK) <<
> +					IRQ_MODRT_TX_TIMER_SHIFT;
> +		intr_modrt_data |= (hw->rx_imt & IRQ_MODRT_TIMER_MASK) <<
> +					IRQ_MODRT_RX_TIMER_SHIFT;
> +		AT_WRITE_REG(hw, REG_IRQ_MODRT_TIMER_INIT, intr_modrt_data);
> +		master_ctrl_data |=
> +			MASTER_CTRL_TX_ITIMER_EN | MASTER_CTRL_RX_ITIMER_EN;
> +	}
> +
> +	if (hw->ctrl_flags & ATL1C_INTR_CLEAR_ON_READ)
> +		master_ctrl_data |= MASTER_CTRL_INT_RDCLR;
> +
> +	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);
> +	}
> +
> +	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 void atl1c_update_hw_stats(struct atl1c_adapter *adapter)
> +{
> +	u16 hw_reg_addr = 0;
> +	unsigned long *stats_item = NULL;
> +	u32 data;
> +
> +	/* update rx status */
> +	hw_reg_addr = REG_MAC_RX_STATUS_BIN;
> +	stats_item  = &adapter->hw_stats.rx_ok;
> +	while (hw_reg_addr <= REG_MAC_RX_STATUS_END) {
> +		AT_READ_REG(&adapter->hw, hw_reg_addr, &data);
> +		*stats_item += data;
> +		stats_item++;
> +		hw_reg_addr += 4;
> +	}
> +/* update tx status */
> +	hw_reg_addr = REG_MAC_TX_STATUS_BIN;
> +	stats_item  = &adapter->hw_stats.tx_ok;
> +	while (hw_reg_addr <= REG_MAC_TX_STATUS_END) {
> +		AT_READ_REG(&adapter->hw, hw_reg_addr, &data);
> +		*stats_item += data;
> +		stats_item++;
> +		hw_reg_addr += 4;
> +	}
> +}
> +
> +/*
> + * atl1c_get_stats - Get System Network Statistics
> + * @netdev: network interface device structure
> + *
> + * Returns the address of the device statistics structure.
> + * The statistics are actually updated from the timer callback.
> + */
> +static struct net_device_stats *atl1c_get_stats(struct net_device *netdev)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct atl1c_hw_stats  *hw_stats = &adapter->hw_stats;
> +	struct net_device_stats *net_stats = &adapter->net_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;
> +	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_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_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;
> +
> +	return &adapter->net_stats;
> +}
> +
> +static inline void atl1c_clear_phy_int(struct atl1c_adapter *adapter)
> +{
> +	u16 phy_data;
> +
> +	spin_lock(&adapter->mdio_lock);
> +	atl1c_read_phy_reg(&adapter->hw, MII_ISR, &phy_data);
> +	spin_unlock(&adapter->mdio_lock);
> +}
> +
> +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_buffer *buffer_info;
> +	u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
> +	u16 hw_next_to_clean;
> +	u16 shift;
> +	u32 data;
> +
> +	if (type == atl1c_trans_high)
> +		shift = MB_HTPD_CONS_IDX_SHIFT;
> +	else
> +		shift = MB_NTPD_CONS_IDX_SHIFT;
> +
> +	AT_READ_REG(&adapter->hw, REG_MB_PRIO_CONS_IDX, &data);
> +	hw_next_to_clean = (data >> shift) & MB_PRIO_PROD_IDX_MASK;
> +
> +	while (next_to_clean != hw_next_to_clean) {
> +		buffer_info = &tpd_ring->buffer_info[next_to_clean];
> +		if (buffer_info->state == ATL1_BUFFER_BUSY) {
> +			pci_unmap_page(adapter->pdev, buffer_info->dma,
> +					buffer_info->length, PCI_DMA_TODEVICE);
> +			buffer_info->dma = 0;
> +			if (buffer_info->skb) {
> +				dev_kfree_skb_irq(buffer_info->skb);
> +				buffer_info->skb = NULL;
> +			}
> +			buffer_info->state = ATL1_BUFFER_FREE;
> +		}
> +		if (++next_to_clean == tpd_ring->count)
> +			next_to_clean = 0;
> +		atomic_set(&tpd_ring->next_to_clean, next_to_clean);
> +	}
> +
> +	if (netif_queue_stopped(adapter->netdev) &&
> +			netif_carrier_ok(adapter->netdev)) {
> +		netif_wake_queue(adapter->netdev);
> +	}
> +
> +	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)
> +{
> +	struct net_device *netdev  = data;
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct pci_dev *pdev = adapter->pdev;
> +	struct atl1c_hw *hw = &adapter->hw;
> +	int max_ints = AT_MAX_INT_WORK;
> +	int handled = IRQ_NONE;
> +	u32 status;
> +	u32 reg_data;
> +
> +	do {
> +		AT_READ_REG(hw, REG_ISR, &reg_data);
> +		status = reg_data & hw->intr_mask;
> +
> +		if (status == 0 || (status & ISR_DIS_INT) != 0) {
> +			if (max_ints != AT_MAX_INT_WORK)
> +				handled = IRQ_HANDLED;
> +			break;
> +		}
> +		/* link event */
> +		if (status & ISR_GPHY)
> +			atl1c_clear_phy_int(adapter);
> +		/* Ack ISR */
> +		AT_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT);
> +		if (status & ISR_RX_PKT) {
> +			if (likely(napi_schedule_prep(&adapter->napi))) {
> +				hw->intr_mask &= ~ISR_RX_PKT;
> +				AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
> +				__napi_schedule(&adapter->napi);
> +			}
> +		}
> +		if (status & ISR_TX_PKT)
> +			atl1c_clean_tx_irq(adapter, atl1c_trans_normal);
> +
> +		handled = IRQ_HANDLED;
> +		/* check if PCIE PHY Link down */
> +		if (status & ISR_ERROR) {
> +			dev_err(&pdev->dev,
> +				"atl1c hardware error (status = 0x%x)\n",
> +				status & ISR_ERROR);
> +			/* reset MAC */
> +			hw->intr_mask &= ~ISR_ERROR;
> +			AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
> +			schedule_work(&adapter->reset_task);
> +			break;
> +		}
> +
> +		if (status & ISR_OVER)
> +			dev_err(&pdev->dev,
> +				"TX/RX over flow (status = 0x%x)\n",
> +				status & ISR_OVER);
> +
> +		/* link event */
> +		if (status & (ISR_GPHY | ISR_MANUAL)) {
> +			adapter->net_stats.tx_carrier_errors++;
> +			atl1c_link_chg_event(adapter);
> +			break;
> +		}
> +
> +	} while (--max_ints > 0);
> +	/* re-enable Interrupt*/
> +	AT_WRITE_REG(&adapter->hw, REG_ISR, 0);
> +	return handled;
> +}
> +
> +static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
> +		  struct sk_buff *skb, struct atl1c_recv_ret_status *prrs)
> +{
> +	/*
> +	 * The pid field in RRS in not correct sometimes, so we
> +	 * cannot figure out if the packet is fragmented or not,
> +	 * so we tell the KERNEL CHECKSUM_NONE
> +	 */
> +	skb->ip_summed = CHECKSUM_NONE;
> +
> +	return;
> +}
> +
> +static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid)
> +{
> +	struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring[ringid];
> +	struct pci_dev *pdev = adapter->pdev;
> +	struct atl1c_buffer *buffer_info, *next_info;
> +	struct sk_buff *skb;
> +	void *vir_addr = NULL;
> +	u16 num_alloc = 0;
> +	u16 rfd_next_to_use, next_next;
> +	struct atl1c_rx_free_desc *rfd_desc;
> +
> +	next_next = rfd_next_to_use = rfd_ring->next_to_use;
> +	if (++next_next == rfd_ring->count)
> +		next_next = 0;
> +	buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
> +	next_info = &rfd_ring->buffer_info[next_next];
> +
> +	while (next_info->state == ATL1_BUFFER_FREE) {
> +		rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
> +
> +		skb = dev_alloc_skb(adapter->rx_buffer_len);
> +		if (unlikely(!skb)) {
> +			dev_dbg(&pdev->dev, "alloc rx buffer failed\n");
> +			break;
> +		}
> +
> +		/*
> +		 * Make buffer alignment 2 beyond a 16 byte boundary
> +		 * this will result in a 16 byte aligned IP header after
> +		 * the 14 byte MAC header is removed
> +		 */
> +		vir_addr = skb->data;
> +		buffer_info->state = ATL1_BUFFER_BUSY;
> +		buffer_info->skb = skb;
> +		buffer_info->length = adapter->rx_buffer_len;
> +		buffer_info->dma = pci_map_single(pdev, vir_addr,
> +						buffer_info->length,
> +						PCI_DMA_FROMDEVICE);
> +		rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
> +		rfd_next_to_use = next_next;
> +		if (++next_next == rfd_ring->count)
> +			next_next = 0;
> +		buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
> +		next_info = &rfd_ring->buffer_info[next_next];
> +		num_alloc++;
> +	}
> +
> +	if (num_alloc) {
> +		/* 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],
> +			rfd_ring->next_to_use & MB_RFDX_PROD_IDX_MASK);
> +	}
> +
> +	return num_alloc;
> +}
> +
> +static void atl1c_clean_rrd(struct atl1c_rrd_ring *rrd_ring,
> +			struct	atl1c_recv_ret_status *rrs, u16 num)
> +{
> +	u16 i;
> +	/* the relationship between rrd and rfd is one map one */
> +	for (i = 0; i < num; i++, rrs = ATL1C_RRD_DESC(rrd_ring,
> +					rrd_ring->next_to_clean)) {
> +		rrs->word3 &= ~RRS_RXD_UPDATED;
> +		if (++rrd_ring->next_to_clean == rrd_ring->count)
> +			rrd_ring->next_to_clean = 0;
> +	}
> +	return;
> +}
> +
> +static void atl1c_clean_rfd(struct atl1c_rfd_ring *rfd_ring,
> +	struct atl1c_recv_ret_status *rrs, u16 num)
> +{
> +	u16 i;
> +	u16 rfd_index;
> +	struct atl1c_buffer *buffer_info = rfd_ring->buffer_info;
> +
> +	rfd_index = (rrs->word0 >> RRS_RX_RFD_INDEX_SHIFT) &
> +			RRS_RX_RFD_INDEX_MASK;
> +	for (i = 0; i < num; i++) {
> +		buffer_info[rfd_index].skb = NULL;
> +		buffer_info[rfd_index].state = ATL1_BUFFER_FREE;
> +		if (++rfd_index == rfd_ring->count)
> +			rfd_index = 0;
> +	}
> +	rfd_ring->next_to_clean = rfd_index;
> +
> +	return;
> +}
> +
> +static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que,
> +		   int *work_done, int work_to_do)
> +{
> +	u16 rfd_num, rfd_index;
> +	u16 count = 0;
> +	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 sk_buff *skb;
> +	struct atl1c_recv_ret_status *rrs;
> +	struct atl1c_buffer *buffer_info;
> +
> +	while (1) {
> +		if (*work_done >= work_to_do)
> +			break;
> +		rrs = ATL1C_RRD_DESC(rrd_ring, rrd_ring->next_to_clean);
> +		if (likely(RRS_RXD_IS_VALID(rrs->word3))) {
> +			rfd_num = (rrs->word0 >> RRS_RX_RFD_CNT_SHIFT) &
> +				RRS_RX_RFD_CNT_MASK;
> +			if (unlikely(rfd_num) != 1)
> +				/* TODO support mul rfd*/
> +				printk(KERN_EMERG "Multi rfd not support yet!\n");

"Multiple rfd not supported"

> +			goto rrs_checked;
> +		} else {
> +			break;
> +		}
> +rrs_checked:
> +		atl1c_clean_rrd(rrd_ring, rrs, rfd_num);
> +		if (rrs->word3 & (RRS_RX_ERR_SUM | RRS_802_3_LEN_ERR)) {
> +			atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
> +			printk(KERN_WARNING "wrong packet! rrs word3 is %x\n", rrs->word3);
> +			continue;
> +		}
> +
> +		length = le16_to_cpu((rrs->word3 >> RRS_PKT_SIZE_SHIFT) &
> +				RRS_PKT_SIZE_MASK);
> +		/* Good Receive */
> +		if (likely(rfd_num == 1)) {
> +			rfd_index = (rrs->word0 >> RRS_RX_RFD_INDEX_SHIFT) &
> +					RRS_RX_RFD_INDEX_MASK;
> +			buffer_info = &rfd_ring->buffer_info[rfd_index];
> +			pci_unmap_single(pdev, buffer_info->dma,
> +				buffer_info->length, PCI_DMA_FROMDEVICE);
> +			skb = buffer_info->skb;
> +		} else {
> +			/* TODO */
> +			printk(KERN_EMERG "Multil rfd not support yet!\n");

"Multiple rfd not supported"

> +			break;
> +		}
> +		atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
> +		skb_put(skb, length - ETH_FCS_LEN);
> +		skb->protocol = eth_type_trans(skb, netdev);
> +		skb->dev = netdev;
> +		atl1c_rx_checksum(adapter, skb, rrs);
> +		if (unlikely(adapter->vlgrp) && rrs->word3 & RRS_VLAN_INS) {
> +			u16 vlan;
> +
> +			AT_TAG_TO_VLAN(rrs->vlan_tag, vlan);
> +			vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vlan);
> +		} else
> +			netif_receive_skb(skb);
> +
> +		netdev->last_rx = jiffies;
> +		(*work_done)++;
> +		count++;
> +	}
> +	if (count)
> +		atl1c_alloc_rx_buffer(adapter, que);
> +}
> +
> +/*
> + * atl1c_clean - NAPI Rx polling callback
> + * @adapter: board private structure
> + */
> +static int atl1c_clean(struct napi_struct *napi, int budget)
> +{
> +	struct atl1c_adapter *adapter =
> +			container_of(napi, struct atl1c_adapter, napi);
> +	int work_done = 0;
> +	int i;
> +
> +	/* Keep link state information with original netdev */
> +	if (!netif_carrier_ok(adapter->netdev))
> +		goto quit_polling;
> +
> +	for (i = 0; i < adapter->num_rx_queues; i++)
> +		atl1c_clean_rx_irq(adapter, i, &work_done, budget);
> +
> +	if (work_done < budget) {
> +quit_polling:
> +		napi_complete(napi);
> +		adapter->hw.intr_mask |= ISR_RX_PKT;
> +		AT_WRITE_REG(&adapter->hw, REG_IMR, adapter->hw.intr_mask);
> +	}
> +	return work_done;
> +}
> +
> +#ifdef CONFIG_NET_POLL_CONTROLLER
> +
> +/*
> + * Polling 'interrupt' - used by things like netconsole to send skbs
> + * without having to re-enable interrupts. It's not called while
> + * the interrupt routine is executing.
> + */
> +static void atl1c_netpoll(struct net_device *netdev)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	disable_irq(adapter->pdev->irq);
> +	atl1c_intr(adapter->pdev->irq, netdev);
> +	enable_irq(adapter->pdev->irq);
> +}
> +#endif
> +
> +static inline u16 atl1c_tpd_avail(struct atl1c_adapter *adapter, enum atl1c_trans_queue type)
> +{
> +	struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
> +	u16 next_to_use = 0;
> +	u16 next_to_clean = 0;

Unnecessary initialization.  (Lots of other places, too.)

> +
> +	next_to_clean = atomic_read(&tpd_ring->next_to_clean);
> +	next_to_use   = tpd_ring->next_to_use;
> +
> +	return (u16)(next_to_clean > next_to_use) ?
> +		(next_to_clean - next_to_use - 1) :
> +		(tpd_ring->count + next_to_clean - next_to_use - 1);
> +}
> +
> +/*
> + * get next usable tpd
> + * Note: should call atl1c_tdp_avail to make sure
> + * there is enough tpd to use
> + */
> +static struct atl1c_tpd_desc *atl1c_get_tpd(struct atl1c_adapter *adapter,
> +	enum atl1c_trans_queue type)
> +{
> +	struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
> +	struct atl1c_tpd_desc *tpd_desc;
> +	u16 next_to_use = 0;
> +
> +	next_to_use = tpd_ring->next_to_use;
> +	if (++tpd_ring->next_to_use == tpd_ring->count)
> +		tpd_ring->next_to_use = 0;
> +	tpd_desc = ATL1C_TPD_DESC(tpd_ring, next_to_use);
> +	memset(tpd_desc, 0, sizeof(struct atl1c_tpd_desc));
> +	return	tpd_desc;
> +}
> +
> +static struct atl1c_buffer *
> +atl1c_get_tx_buffer(struct atl1c_adapter *adapter, struct atl1c_tpd_desc *tpd)
> +{
> +	struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring;
> +
> +	return &tpd_ring->buffer_info[tpd -
> +			(struct atl1c_tpd_desc *)tpd_ring->desc];
> +}
> +
> +/* Calculate the transmit packet descript needed*/
> +static u16 atl1c_cal_tpd_req(const struct sk_buff *skb)
> +{
> +	int i = 0;
> +	u16 tpd_req = 1;
> +	u16 proto_hdr_len = 0;
> +
> +	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
> +		tpd_req++;
> +
> +	if (skb_is_gso(skb)) {
> +		proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
> +		if (proto_hdr_len < skb_headlen(skb))
> +			tpd_req++;
> +		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
> +			tpd_req++;
> +	}
> +	return tpd_req;
> +}
> +
> +static int atl1c_tso_csum(struct atl1c_adapter *adapter,
> +			  struct sk_buff *skb,
> +			  struct atl1c_tpd_desc **tpd,
> +			  enum atl1c_trans_queue type)
> +{
> +	struct pci_dev *pdev = adapter->pdev;
> +	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;
> +		}
> +		offload_type = skb_shinfo(skb)->gso_type;
> +
> +		if (offload_type & SKB_GSO_TCPV4) {
> +			real_len = (((unsigned char *)ip_hdr(skb) - skb->data)
> +					+ ntohs(ip_hdr(skb)->tot_len));
> +
> +			if (real_len < skb->len)
> +				pskb_trim(skb, real_len);
> +
> +			hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
> +			if (unlikely(skb->len == hdr_len)) {
> +				/* only xsum need */
> +				dev_warn(&pdev->dev,
> +				      "IPV4 tso with zero data??\n");
> +				goto check_sum;
> +			} else {
> +				ip_hdr(skb)->check = 0;
> +				tcp_hdr(skb)->check = ~csum_tcpudp_magic(
> +							ip_hdr(skb)->saddr,
> +							ip_hdr(skb)->daddr,
> +							0, IPPROTO_TCP, 0);
> +				(*tpd)->word1 |= 1 << TPD_IPV4_PACKET_SHIFT;
> +			}
> +		}
> +
> +		if (offload_type & SKB_GSO_TCPV6) {
> +			struct atl1c_tpd_ext_desc *etpd =
> +				*(struct atl1c_tpd_ext_desc **)(tpd);
> +
> +			memset(etpd, 0, sizeof(struct atl1c_tpd_ext_desc));
> +			*tpd = atl1c_get_tpd(adapter, type);
> +			ipv6_hdr(skb)->payload_len = 0;
> +			/* check payload == 0 byte ? */
> +			hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
> +			if (unlikely(skb->len == hdr_len)) {
> +				/* only xsum need */
> +				dev_warn(&pdev->dev,
> +					"IPV6 tso with zero data??\n");
> +				goto check_sum;
> +			} else
> +				tcp_hdr(skb)->check = ~csum_ipv6_magic(
> +						&ipv6_hdr(skb)->saddr,
> +						&ipv6_hdr(skb)->daddr,
> +						0, IPPROTO_TCP, 0);
> +			etpd->word1 |= 1 << TPD_LSO_EN_SHIFT;
> +			etpd->word1 |= 1 << TPD_LSO_VER_SHIFT;
> +			etpd->pkt_len = cpu_to_le32(skb->len);
> +			(*tpd)->word1 |= 1 << TPD_LSO_VER_SHIFT;
> +		}
> +
> +		(*tpd)->word1 |= 1 << TPD_LSO_EN_SHIFT;
> +		(*tpd)->word1 |= (skb_transport_offset(skb) & TPD_TCPHDR_OFFSET_MASK) <<
> +				TPD_TCPHDR_OFFSET_SHIFT;
> +		(*tpd)->word1 |= (skb_shinfo(skb)->gso_size & TPD_MSS_MASK) <<
> +				TPD_MSS_SHIFT;
> +		return 0;
> +	}
> +
> +check_sum:
> +	if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
> +		u8 css, cso;
> +		cso = skb_transport_offset(skb);
> +
> +		if (unlikely(cso & 0x1)) {
> +			dev_err(&adapter->pdev->dev,
> +			   "pay load offset should not ant event number\n");

s/pay load/payload
s/ant/an

> +			return -1;
> +		} else {
> +			css = cso + skb->csum_offset;
> +
> +			(*tpd)->word1 |= ((cso >> 1) & TPD_PLOADOFFSET_MASK) <<
> +					TPD_PLOADOFFSET_SHIFT;
> +			(*tpd)->word1 |= ((css >> 1) & TPD_CCSUM_OFFSET_MASK) <<
> +					TPD_CCSUM_OFFSET_SHIFT;
> +			(*tpd)->word1 |= 1 << TPD_CCSUM_EN_SHIFT;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static void atl1c_tx_map(struct atl1c_adapter *adapter,
> +		      struct sk_buff *skb, struct atl1c_tpd_desc *tpd,
> +			enum atl1c_trans_queue type)
> +{
> +	struct atl1c_tpd_desc *use_tpd = NULL;
> +	struct atl1c_buffer *buffer_info = NULL;
> +	u16 buf_len = skb->len - skb->data_len;
> +	u16 map_len = 0;
> +	u16 mapped_len = 0;
> +	u16 hdr_len = 0;
> +	u16 nr_frags;
> +	u16 f;
> +	int tso;
> +
> +	nr_frags = skb_shinfo(skb)->nr_frags;
> +	tso = (tpd->word1 >> TPD_LSO_EN_SHIFT) & TPD_LSO_EN_MASK;
> +	if (tso) {
> +		/* TSO */
> +		map_len = hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
> +		use_tpd = tpd;
> +
> +		buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
> +		buffer_info->length = map_len;
> +		buffer_info->dma = pci_map_single(adapter->pdev,
> +					skb->data, hdr_len, PCI_DMA_TODEVICE);
> +		buffer_info->state = ATL1_BUFFER_BUSY;
> +		if (buffer_info->dma == 0) {
> +			printk(KERN_EMERG "buffer_info dma is 0\n");
> +			dump_stack();

BUG_ON?

> +		}
> +		mapped_len += map_len;
> +		use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
> +		use_tpd->buffer_len = cpu_to_le16(buffer_info->length);
> +	}
> +
> +	if (mapped_len < buf_len) {
> +		/* mapped_len == 0, means we should use the first tpd,
> +		   which is given by caller  */
> +		if (mapped_len == 0)
> +			use_tpd = tpd;
> +		else {
> +			use_tpd = atl1c_get_tpd(adapter, type);
> +			memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
> +			use_tpd = atl1c_get_tpd(adapter, type);
> +			memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
> +		}
> +		buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
> +		buffer_info->length = buf_len - mapped_len;
> +		buffer_info->dma =
> +			pci_map_single(adapter->pdev, skb->data + mapped_len,
> +					buffer_info->length, PCI_DMA_TODEVICE);
> +		buffer_info->state = ATL1_BUFFER_BUSY;
> +		if (buffer_info->dma == 0) {
> +			printk(KERN_EMERG "buffer_info dma is 0\n");
> +			dump_stack();

BUG_ON?

> +		}
> +
> +		use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
> +		use_tpd->buffer_len  = cpu_to_le16(buffer_info->length);
> +	}
> +
> +	for (f = 0; f < nr_frags; f++) {
> +		struct skb_frag_struct *frag;
> +
> +		frag = &skb_shinfo(skb)->frags[f];
> +
> +		use_tpd = atl1c_get_tpd(adapter, type);
> +		memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
> +
> +		buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
> +		buffer_info->length = frag->size;
> +		buffer_info->dma =
> +			pci_map_page(adapter->pdev, frag->page,
> +					frag->page_offset,
> +					buffer_info->length,
> +					PCI_DMA_TODEVICE);
> +		buffer_info->state = ATL1_BUFFER_BUSY;
> +		if (buffer_info->dma == 0) {
> +			printk(KERN_EMERG "buffer_info dma is 0\n");
> +			dump_stack();
> +		}

BUG_ON?

> +
> +		use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
> +		use_tpd->buffer_len  = cpu_to_le16(buffer_info->length);
> +	}
> +
> +	/* The last tpd */
> +	use_tpd->word1 |= 1 << TPD_EOP_SHIFT;
> +	/* The last buffer info contain the skb address,
> +	   so it will be free after unmap */
> +	buffer_info->skb = skb;
> +}
> +
> +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;
> +	wmb();
> +	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;
> +	}
> +
> +	AT_WRITE_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, prod_data);
> +}
> +
> +static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	unsigned long flags;
> +	u16 tpd_req = 1;
> +	struct atl1c_tpd_desc *tpd;
> +	enum atl1c_trans_queue type = atl1c_trans_normal;
> +
> +	if (test_bit(__AT_DOWN, &adapter->flags)) {
> +		dev_kfree_skb_any(skb);
> +		return NETDEV_TX_OK;
> +	}
> +
> +	tpd_req = atl1c_cal_tpd_req(skb);
> +	if (!spin_trylock_irqsave(&adapter->tx_lock, flags)) {
> +		printk(KERN_EMERG "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 */
> +		netif_stop_queue(netdev);
> +		spin_unlock_irqrestore(&adapter->tx_lock, flags);
> +		return NETDEV_TX_BUSY;
> +	}
> +
> +	tpd = atl1c_get_tpd(adapter, type);
> +
> +	/* do TSO and check sum */
> +	if (atl1c_tso_csum(adapter, skb, &tpd, type) != 0) {
> +		spin_unlock_irqrestore(&adapter->tx_lock, flags);
> +		dev_kfree_skb_any(skb);
> +		return NETDEV_TX_OK;
> +	}
> +
> +	if (unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) {
> +		u16 vlan = vlan_tx_tag_get(skb);
> +		u16 tag;
> +		AT_VLAN_TO_TAG(vlan, tag);
> +		tpd->word1 |= 1 << TPD_INS_VTAG_SHIFT;
> +		tpd->vlan_tag = tag;
> +	}
> +
> +	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);
> +
> +	netdev->trans_start = jiffies;
> +	spin_unlock_irqrestore(&adapter->tx_lock, flags);
> +	return NETDEV_TX_OK;
> +}
> +
> +static void atl1c_free_irq(struct atl1c_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 atl1c_request_irq(struct atl1c_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) {
> +		dev_dbg(&pdev->dev,
> +			"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, &atl1c_intr, flags,
> +			netdev->name, netdev);
> +	if (err) {
> +		dev_dbg(&pdev->dev,
> +			"Unable to allocate interrupt Error: %d\n", err);
> +		if (adapter->have_msi)
> +			pci_disable_msi(adapter->pdev);
> +		return err;
> +	}
> +	dev_dbg(&pdev->dev, "atl1c_request_irq OK\n");
> +	return err;
> +}
> +
> +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;
> +		goto err_up;
> +	}
> +
> +	err = atl1c_request_irq(adapter);
> +	if (unlikely(err))
> +		goto err_up;
> +
> +	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;
> +}
> +
> +void atl1c_down(struct atl1c_adapter *adapter)
> +{
> +	struct net_device *netdev = adapter->netdev;
> +
> +	atl1c_del_timer(adapter);
> +	atl1c_cancel_work(adapter);
> +
> +	/* signal that we're down so the interrupt handler does not
> +	 * reschedule our watchdog timer */
> +	set_bit(__AT_DOWN, &adapter->flags);
> +	netif_carrier_off(netdev);
> +	netif_stop_queue(netdev);
> +	napi_disable(&adapter->napi);
> +	atl1c_irq_disable(adapter);
> +	atl1c_free_irq(adapter);
> +	AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
> +	/* 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_open - Called when a network interface is made active
> + * @netdev: network interface device structure
> + *
> + * Returns 0 on success, negative value on failure
> + *
> + * The open entry point is called when a network interface is made
> + * active by the system (IFF_UP).  At this point all resources needed
> + * for transmit and receive operations are allocated, the interrupt
> + * handler is registered with the OS, the watchdog timer is started,
> + * and the stack is notified that the interface is ready.
> + */
> +static int atl1c_open(struct net_device *netdev)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	int err;
> +
> +	/* disallow open during test */
> +	if (test_bit(__AT_TESTING, &adapter->flags))
> +		return -EBUSY;
> +
> +	/* allocate rx/tx dma buffer & descriptors */
> +	err = atl1c_setup_ring_resources(adapter);
> +	if (unlikely(err))
> +		return err;
> +
> +	err = atl1c_up(adapter);
> +	if (unlikely(err))
> +		goto err_up;
> +
> +	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);

Please use the defined constant, REG_MDIO_CTRL.

> +	}
> +	return 0;
> +
> +err_up:
> +	atl1c_free_irq(adapter);
> +	atl1c_free_ring_resources(adapter);
> +	atl1c_reset_mac(&adapter->hw);
> +	return err;
> +}
> +
> +/*
> + * atl1c_close - Disables a network interface
> + * @netdev: network interface device structure
> + *
> + * Returns 0, this is not allowed to fail
> + *
> + * The close entry point is called when an interface is de-activated
> + * by the OS.  The hardware is still under the drivers control, but
> + * needs to be disabled.  A global MAC reset is issued to stop the
> + * hardware, and all transmit and receive resources are freed.
> + */
> +static int atl1c_close(struct net_device *netdev)
> +{
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
> +	atl1c_down(adapter);
> +	atl1c_free_ring_resources(adapter);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
> +{
> +	struct net_device *netdev = pci_get_drvdata(pdev);
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +	struct atl1c_hw *hw = &adapter->hw;
> +	u32 ctrl = 0;
> +	u32 mac_ctrl_data = 0;
> +	u32 master_ctrl_data = 0;
> +	u32 wol_ctrl_data = 0;
> +	u32 pm_data;
> +	u16 mii_bmsr_data = 0;
> +	u16 save_autoneg_advertised;
> +	u16 mii_intr_status_data = 0;
> +	u32 wufc = adapter->wol;
> +	u32 i;
> +#ifdef CONFIG_PM
> +	int retval = 0;
> +#endif

Unnecessary ifdef/endif.

> +
> +	if (netif_running(netdev)) {
> +		WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
> +		atl1c_down(adapter);
> +	}
> +	netif_device_detach(netdev);
> +	atl1c_disable_l0s_l1(hw);
> +#ifdef CONFIG_PM
> +	retval = pci_save_state(pdev);
> +	if (retval)
> +		return retval;
> +#endif

Unnecessary ifdef/endif.

> +	if (wufc) {
> +		AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
> +		master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
> +
> +		/* get link status */
> +		atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
> +		atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
> +		save_autoneg_advertised = hw->autoneg_advertised;
> +		hw->autoneg_advertised = ADVERTISE_10_HALF;
> +		if (atl1c_restart_autoneg(hw) != 0)
> +			dev_dbg(&pdev->dev, "phy autoneg failed\n");
> +		hw->phy_configured = false; /* re-init PHY when resume */
> +		hw->autoneg_advertised = save_autoneg_advertised;
> +		/* 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) {
> +			for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
> +				msleep(100);
> +				atl1c_read_phy_reg(hw, MII_BMSR,
> +					(u16 *)&mii_bmsr_data);
> +				if (mii_bmsr_data & BMSR_LSTATUS)
> +					break;
> +			}
> +			if ((mii_bmsr_data & BMSR_LSTATUS) == 0)
> +				dev_dbg(&pdev->dev,
> +					"%s: Link may change"
> +					"when suspend\n",
> +					atl1c_driver_name);
> +			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);
> +				goto wol_dis;
> +			}
> +		}
> +		/* clear phy interrupt */
> +		atl1c_read_phy_reg(hw, MII_ISR, &mii_intr_status_data);
> +		/* Config MAC Ctrl register */
> +		mac_ctrl_data = MAC_CTRL_RX_EN;
> +		/* set to 10/100M halt duplex */
> +		mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
> +		mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
> +				 MAC_CTRL_PRMLEN_MASK) <<
> +				 MAC_CTRL_PRMLEN_SHIFT);
> +
> +		if (adapter->vlgrp)
> +			mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
> +
> +		/* 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);
> +
> +		/* pcie patch */
> +		AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
> +		ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
> +		device_set_wakeup_enable(&pdev->dev, 1);
> +		AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
> +
> +		AT_READ_REG(hw, REG_PM_CTRLSTAT, &pm_data);
> +		pm_data |= PM_CTRLSTAT_PME_EN;
> +		AT_WRITE_REG(hw, REG_PM_CTRLSTAT, pm_data);
> +
> +		pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
> +		goto suspend_exit;
> +	}
> +wol_dis:
> +
> +	/* WOL disabled */
> +	AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
> +
> +	/* pcie patch */
> +	AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
> +	ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
> +	AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
> +
> +	atl1c_phy_disable(hw);
> +	hw->phy_configured = false; /* re-init PHY when resume */
> +
> +	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
> +
> +suspend_exit:
> +
> +	pci_disable_device(pdev);
> +	pci_set_power_state(pdev, pci_choose_state(pdev, state));
> +
> +	return 0;
> +}
> +
> +static int atl1c_resume(struct pci_dev *pdev)
> +{
> +	struct net_device *netdev = pci_get_drvdata(pdev);
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	pci_set_power_state(pdev, PCI_D0);
> +	pci_restore_state(pdev);
> +	pci_enable_wake(pdev, PCI_D3hot, 0);
> +	pci_enable_wake(pdev, PCI_D3cold, 0);
> +
> +	AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
> +
> +	atl1c_phy_reset(&adapter->hw);
> +	atl1c_reset_mac(&adapter->hw);
> +	netif_device_attach(netdev);
> +	if (netif_running(netdev))
> +		atl1c_up(adapter);
> +
> +	return 0;
> +}
> +#endif
> +
> +static void atl1c_shutdown(struct pci_dev *pdev)
> +{
> +	atl1c_suspend(pdev, PMSG_SUSPEND);

I didn't try, but I don't think this will compile without CONFIG_PM.

> +}
> +
> +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->open = &atl1c_open;
> +	netdev->stop = &atl1c_close;
> +	netdev->hard_start_xmit = &atl1c_xmit_frame;
> +	netdev->get_stats = &atl1c_get_stats;
> +	netdev->set_multicast_list = &atl1c_set_multi;
> +	netdev->set_mac_address = &atl1c_set_mac_addr;
> +	netdev->change_mtu = &atl1c_change_mtu;
> +	netdev->do_ioctl = &atl1c_ioctl;
> +	netdev->tx_timeout = &atl1c_tx_timeout;
> +	netdev->watchdog_timeo = AT_TX_WATCHDOG;
> +	netdev->vlan_rx_register = atl1c_vlan_rx_register;
> +#ifdef CONFIG_NET_POLL_CONTROLLER
> +	netdev->poll_controller = atl1c_netpoll;
> +#endif
> +	atl1c_set_ethtool_ops(netdev);
> +
> +	/* TODO: add when ready */
> +	netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
> +			   NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
> +	netdev->features |= NETIF_F_TSO;
> +	netdev->features |= NETIF_F_TSO6;
> +
> +	return 0;
> +}
> +
> +/*
> + * atl1c_probe - Device Initialization Routine
> + * @pdev: PCI device information struct
> + * @ent: entry in atl1c_pci_tbl
> + *
> + * Returns 0 on success, negative on failure
> + *
> + * atl1c_probe initializes an adapter identified by a pci_dev structure.
> + * 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)
> +{
> +	struct net_device *netdev;
> +	struct atl1c_adapter *adapter = NULL;
> +	static int cards_found;
> +
> +	int err = 0;
> +
> +	/* enable device (incl. PCI PM wakeup and hotplug setup) */
> +	err = pci_enable_device(pdev);
> +	if (err) {
> +		dev_err(&pdev->dev, "cannot enable PCI device\n");
> +		return err;
> +	}
> +
> +	/*
> +	 * The atl1c 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 at a time.
> +	 *
> +	 * Supporting 64-bit DMA on this hardware is more trouble than it's
> +	 * worth.  It is far easier to limit to 32-bit DMA than update
> +	 * various kernel subsystems to support the mechanics required by a
> +	 * fixed-high-32-bit system.
> +	 */
> +	if ((pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) ||
> +	    (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) != 0)) {
> +		dev_err(&pdev->dev, "No usable DMA configuration,aborting\n");
> +		goto err_dma;
> +	}
> +
> +	err = pci_request_regions(pdev, atl1c_driver_name);
> +	if (err) {
> +		dev_err(&pdev->dev, "cannot obtain PCI resources\n");
> +		goto err_pci_reg;
> +	}
> +
> +	pci_set_master(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;
> +	}
> +
> +	err = atl1c_init_netdev(netdev, pdev);
> +	if (err) {
> +		dev_err(&pdev->dev, "init netdevice failed\n");
> +		goto err_init_netdev;
> +	}
> +	adapter = netdev_priv(netdev);
> +	adapter->bd_number = cards_found;
> +	adapter->netdev = netdev;
> +	adapter->pdev = pdev;
> +	adapter->hw.adapter = adapter;
> +	adapter->hw.hw_addr = pci_iomap(pdev, BAR_0, 0);
> +	if (!adapter->hw.hw_addr) {
> +		err = -EIO;
> +		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;
> +	netif_napi_add(netdev, &adapter->napi, atl1c_clean, 64);
> +	init_timer(&adapter->phy_config_timer);
> +	adapter->phy_config_timer.function = &atl1c_phy_config;
> +	adapter->phy_config_timer.data = (unsigned long) adapter;
> +
> +	/* get user settings */
> +	atl1c_check_options(adapter);
> +
> +
> +	/* setup the private structure */
> +	err = atl1c_sw_init(adapter);
> +	if (err) {
> +		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);
> +
> +	/* Init GPHY as early as possible due to power saving issue  */
> +	atl1c_phy_reset(&adapter->hw);
> +
> +	err = atl1c_reset_mac(&adapter->hw);
> +	if (err) {
> +		err = -EIO;
> +		goto err_reset;
> +	}
> +
> +
> +	/* reset the controller to
> +	 * put the device in a known good starting state */
> +	err = atl1c_phy_init(&adapter->hw);
> +	if (err) {
> +		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;
> +	}
> +	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
> +	memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
> +	dev_dbg(&pdev->dev, "mac address : %02x-%02x-%02x-%02x-%02x-%02x\n",
> +			adapter->hw.mac_addr[0], adapter->hw.mac_addr[1],
> +			adapter->hw.mac_addr[2], adapter->hw.mac_addr[3],
> +			adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]);
> +
> +	atl1c_hw_set_mac_addr(&adapter->hw);
> +	INIT_WORK(&adapter->reset_task, atl1c_reset_task);
> +	/* FIXME: should remove future ? */
> +	INIT_WORK(&adapter->link_chg_task, atl1c_link_chg_task);
> +	err = register_netdev(netdev);
> +	if (err) {
> +		dev_err(&pdev->dev, "register netdevice failed\n");
> +		goto err_register;
> +	}
> +
> +	cards_found++;
> +
> +	return 0;
> +
> +err_reset:
> +err_register:
> +err_sw_init:
> +err_eeprom:
> +	iounmap(adapter->hw.hw_addr);
> +err_init_netdev:
> +err_ioremap:
> +	free_netdev(netdev);
> +err_alloc_etherdev:
> +	pci_release_regions(pdev);
> +err_pci_reg:
> +err_dma:
> +	pci_disable_device(pdev);
> +	return err;
> +}
> +
> +/*
> + * atl1c_remove - Device Removal Routine
> + * @pdev: PCI device information struct
> + *
> + * atl1c_remove is called by the PCI subsystem to alert the driver
> + * that it should release a PCI device.  The could be caused by a
> + * Hot-Plug event, or because the driver is going to be removed from
> + * memory.
> + */
> +static void __devexit atl1c_remove(struct pci_dev *pdev)
> +{
> +	struct net_device *netdev = pci_get_drvdata(pdev);
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	unregister_netdev(netdev);
> +	atl1c_phy_disable(&adapter->hw);
> +
> +	iounmap(adapter->hw.hw_addr);
> +
> +	pci_release_regions(pdev);
> +	pci_disable_device(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
> + *
> + * This function is called after a PCI bus error affecting
> + * this device has been detected.
> + */
> +static pci_ers_result_t atl1c_io_error_detected(struct pci_dev *pdev,
> +						pci_channel_state_t state)
> +{
> +	struct net_device *netdev = pci_get_drvdata(pdev);
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	netif_device_detach(netdev);
> +
> +	if (netif_running(netdev))
> +		atl1c_down(adapter);
> +
> +	pci_disable_device(pdev);
> +
> +	/* Request a slot slot reset. */
> +	return PCI_ERS_RESULT_NEED_RESET;
> +}
> +
> +/*
> + * atl1c_io_slot_reset - called after the pci bus has been reset.
> + * @pdev: Pointer to PCI device
> + *
> + * Restart the card from scratch, as if from a cold-boot. Implementation
> + * resembles the first-half of the e1000_resume routine.
> + */
> +static pci_ers_result_t atl1c_io_slot_reset(struct pci_dev *pdev)
> +{
> +	struct net_device *netdev = pci_get_drvdata(pdev);
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	if (pci_enable_device(pdev)) {
> +		dev_err(&pdev->dev,
> +		       "ATL1e: Cannot re-enable PCI device after reset.\n");

Remove ATL1e.

> +		return PCI_ERS_RESULT_DISCONNECT;
> +	}
> +	pci_set_master(pdev);
> +
> +	pci_enable_wake(pdev, PCI_D3hot, 0);
> +	pci_enable_wake(pdev, PCI_D3cold, 0);
> +
> +	atl1c_reset_mac(&adapter->hw);
> +
> +	return PCI_ERS_RESULT_RECOVERED;
> +}
> +
> +/*
> + * atl1c_io_resume - called when traffic can start flowing again.
> + * @pdev: Pointer to PCI device
> + *
> + * This callback is called when the error recovery driver tells us that
> + * its OK to resume normal operation. Implementation resembles the
> + * second-half of the atl1c_resume routine.
> + */
> +static void atl1c_io_resume(struct pci_dev *pdev)
> +{
> +	struct net_device *netdev = pci_get_drvdata(pdev);
> +	struct atl1c_adapter *adapter = netdev_priv(netdev);
> +
> +	if (netif_running(netdev)) {
> +		if (atl1c_up(adapter)) {
> +			dev_err(&pdev->dev,
> +			  "ATL1e: can't bring device back up after reset\n");

Remove ATL1e.

> +			return;
> +		}
> +	}
> +
> +	netif_device_attach(netdev);
> +}
> +
> +static struct pci_error_handlers atl1c_err_handler = {
> +	.error_detected = atl1c_io_error_detected,
> +	.slot_reset = atl1c_io_slot_reset,
> +	.resume = atl1c_io_resume,
> +};
> +
> +static struct pci_driver atl1c_driver = {
> +	.name     = atl1c_driver_name,
> +	.id_table = atl1c_pci_tbl,
> +	.probe    = atl1c_probe,
> +	.remove   = __devexit_p(atl1c_remove),
> +	/* Power Managment Hooks */
> +#ifdef CONFIG_PM
> +	.suspend  = atl1c_suspend,
> +	.resume   = atl1c_resume,
> +#endif
> +	.shutdown = atl1c_shutdown,

atl1c_shutdown() calls atl1c_suspend(), which won't be defined without CONFIG_PM.

> +	.err_handler = &atl1c_err_handler
> +};
> +
> +/*
> + * 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);
> diff --git a/drivers/net/atl1c/atl1c_param.c b/drivers/net/atl1c/atl1c_param.c
> new file mode 100644
> index 0000000..722ce94
> --- /dev/null
> +++ b/drivers/net/atl1c/atl1c_param.c
> @@ -0,0 +1,283 @@
> +/*
> + * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
> + *
> + * Derived from Intel e1000 driver
> + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
> + * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
> + */
> +
> +#include <linux/netdevice.h>
> +
> +#include "atl1c.h"
> +
> +/* This is the only thing that needs to be changed to adjust the
> + * maximum number of ports that the driver can manage.
> + */
> +
> +#define ATL1C_MAX_NIC 32
> +
> +#define OPTION_UNSET    -1
> +#define OPTION_DISABLED 0
> +#define OPTION_ENABLED  1
> +
> +/* All parameters are treated the same, as an integer array of values.
> + * This macro just reduces the need to repeat the same declaration code
> + * over and over (plus this helps to avoid typo bugs).
> + */
> +#define ATL1C_PARAM_INIT { [0 ... ATL1C_MAX_NIC] = OPTION_UNSET }
> +
> +#define ATL1C_PARAM(x, desc) \
> +	static int __devinitdata x[ATL1C_MAX_NIC + 1] = ATL1C_PARAM_INIT; \
> +	static int num_##x; \
> +	module_param_array_named(x, x, int, &num_##x, 0); \
> +	MODULE_PARM_DESC(x, desc);
> +
> +/* Transmit Memory count
> + *
> + * Valid Range: 64-2048
> + *
> + * Default Value: 128
> + */
> +#define ATL1C_MIN_TX_DESC_CNT		32
> +#define ATL1C_MAX_TX_DESC_CNT		1024
> +#define ATL1C_DEFAULT_TX_DESC_CNT	1024
> +ATL1C_PARAM(tx_desc_cnt, "Transmit description count");
> +
> +/* Receive Memory Block Count
> + *
> + * Valid Range: 16-512
> + *
> + * Default Value: 128
> + */
> +#define ATL1C_MIN_RX_MEM_SIZE		128
> +#define ATL1C_MAX_RX_MEM_SIZE		1024
> +#define ATL1C_DEFAULT_RX_MEM_SIZE	512
> +ATL1C_PARAM(rx_mem_size, "memory size of rx buffer(KB)");
> +
> +/* User Specified MediaType Override
> + *
> + * Valid Range: 0-5
> + *  - 0    - auto-negotiate at all supported speeds
> + *  - 1    - only link at 100Mbps Full Duplex
> + *  - 2    - only link at 100Mbps Half Duplex
> + *  - 3    - only link at 10Mbps Full Duplex
> + *  - 4    - only link at 10Mbps Half Duplex
> + * Default Value: 0
> + */
> +
> +ATL1C_PARAM(media_type, "MediaType Select");
> +
> +/* Interrupt Moderate Timer in units of 2 us
> + *
> + * Valid Range: 10-65535
> + *
> + * Default Value: 45000(90ms)
> + */
> +#define INT_MOD_DEFAULT_CNT             200 /* 200us */
> +#define INT_MOD_MAX_CNT                 65000
> +#define INT_MOD_MIN_CNT                 50
> +ATL1C_PARAM(int_mod_timer, "Interrupt Moderator Timer");
> +
> +#define AUTONEG_ADV_DEFAULT  0x2F
> +#define AUTONEG_ADV_MASK     0x2F
> +#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
> +
> +#define FLASH_VENDOR_DEFAULT    0
> +#define FLASH_VENDOR_MIN        0
> +#define FLASH_VENDOR_MAX        2
> +
> +struct atl1c_option {
> +	enum { enable_option, range_option, list_option } type;
> +	char *name;
> +	char *err;
> +	int  def;
> +	union {
> +		struct { /* range_option info */
> +			int min;
> +			int max;
> +		} r;
> +		struct { /* list_option info */
> +			int nr;
> +			struct atl1c_opt_list { int i; char *str; } *p;
> +		} l;
> +	} arg;
> +};
> +
> +static int __devinit atl1c_validate_option(int *value, struct atl1c_option *opt, struct pci_dev *pdev)
> +{
> +	if (*value == OPTION_UNSET) {
> +		*value = opt->def;
> +		return 0;
> +	}
> +
> +	switch (opt->type) {
> +	case enable_option:
> +		switch (*value) {
> +		case OPTION_ENABLED:
> +			dev_info(&pdev->dev, "%s Enabled\n", opt->name);
> +			return 0;
> +		case OPTION_DISABLED:
> +			dev_info(&pdev->dev, "%s Disabled\n", opt->name);
> +			return 0;
> +		}
> +		break;
> +	case range_option:
> +		if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
> +			dev_info(&pdev->dev, "%s set to %i\n", opt->name, *value);
> +			return 0;
> +		}
> +		break;
> +	case list_option:{
> +			int i;
> +			struct atl1c_opt_list *ent;
> +
> +			for (i = 0; i < opt->arg.l.nr; i++) {
> +				ent = &opt->arg.l.p[i];
> +				if (*value == ent->i) {
> +					if (ent->str[0] != '\0')
> +						dev_info(&pdev->dev, "%s\n",
> +							ent->str);
> +					return 0;
> +				}
> +			}
> +			break;
> +		}
> +	default:
> +		BUG();
> +	}
> +
> +	dev_info(&pdev->dev, "Invalid %s specified (%i) %s\n",
> +			opt->name, *value, opt->err);
> +	*value = opt->def;
> +	return -1;
> +}
> +
> +/*
> + * atl1c_check_options - Range Checking for Command Line Parameters
> + * @adapter: board private structure
> + *
> + * This routine checks all command line parameters for valid user
> + * input.  If an invalid value is given, or if no user specified
> + * value exists, a default value is used.  The final value is stored
> + * in a variable in the adapter structure.
> + */
> +void __devinit atl1c_check_options(struct atl1c_adapter *adapter)
> +{
> +	struct pci_dev *pdev = adapter->pdev;
> +	int bd = adapter->bd_number;
> +	if (bd >= ATL1C_MAX_NIC) {
> +		dev_notice(&pdev->dev, "no configuration for board #%i\n", bd);
> +		dev_notice(&pdev->dev, "Using defaults for all values\n");
> +	}
> +
> +	{ 		/* Transmit Ring Size */
> +		struct atl1c_option opt = {
> +			.type = range_option,
> +			.name = "Transmit Ddescription Count",
> +			.err  = "using default of "
> +				__MODULE_STRING(ATL1C_DEFAULT_TX_DESC_CNT),
> +			.def  = ATL1C_DEFAULT_TX_DESC_CNT,
> +			.arg  = { .r = { .min = ATL1C_MIN_TX_DESC_CNT,
> +					 .max = ATL1C_MAX_TX_DESC_CNT} }
> +		};
> +		int val;
> +		if (num_tx_desc_cnt > bd) {
> +			val = tx_desc_cnt[bd];
> +			atl1c_validate_option(&val, &opt, pdev);
> +			adapter->tpd_ring[0].count = (u16) val & 0xFFFC;
> +		} else
> +			adapter->tpd_ring[0].count = (u16)opt.def;
> +	}
> +
> +	{ 		/* Receive Memory Block Count */
> +		struct atl1c_option opt = {
> +			.type = range_option,
> +			.name = "Memory size of rx buffer(KB)",
> +			.err  = "using default of "
> +				__MODULE_STRING(ATL1C_DEFAULT_RX_MEM_SIZE),
> +			.def  = ATL1C_DEFAULT_RX_MEM_SIZE,
> +			.arg  = { .r = { .min = ATL1C_MIN_RX_MEM_SIZE,
> +					 .max = ATL1C_MAX_RX_MEM_SIZE} }
> +		};
> +		int val;
> +		if (num_rx_mem_size > bd) {
> +			val = rx_mem_size[bd];
> +			atl1c_validate_option(&val, &opt, pdev);
> +			adapter->rfd_ring[0].count = (u32)val;
> +		} else {
> +			adapter->rfd_ring[0].count = (u32)opt.def;
> +		}
> +	}
> +
> +	{ 		/* Interrupt Moderate Timer */
> +		struct atl1c_option opt = {
> +			.type = range_option,
> +			.name = "Interrupt Moderate TX Timer",
> +			.err  = "using default of "
> +				__MODULE_STRING(INT_MOD_DEFAULT_CNT),
> +			.def  = INT_MOD_DEFAULT_CNT * 5,
> +			.arg  = { .r = { .min = INT_MOD_MIN_CNT,
> +					 .max = INT_MOD_MAX_CNT} }
> +		} ;
> +		int val;
> +		if (num_int_mod_timer > bd) {
> +			val = int_mod_timer[bd];
> +			atl1c_validate_option(&val, &opt, pdev);
> +			adapter->hw.tx_imt = (u16) val;
> +		} else
> +			adapter->hw.tx_imt = (u16)(opt.def);
> +	}
> +	{ 		/* Interrupt Moderate Timer */
> +		struct atl1c_option opt = {
> +			.type = range_option,
> +			.name = "Interrupt Moderate RX Timer",
> +			.err  = "using default of "
> +				__MODULE_STRING(INT_MOD_DEFAULT_CNT),
> +			.def  = INT_MOD_DEFAULT_CNT,
> +			.arg  = { .r = { .min = INT_MOD_MIN_CNT,
> +					 .max = INT_MOD_MAX_CNT} }
> +		} ;
> +		int val;
> +		if (num_int_mod_timer > bd) {
> +			val = int_mod_timer[bd];
> +			atl1c_validate_option(&val, &opt, pdev);
> +			adapter->hw.rx_imt = (u16) val;
> +		} else
> +			adapter->hw.rx_imt = (u16)(opt.def);
> +	}
> +
> +
> +
> +	{ 		/* MediaType */
> +		struct atl1c_option opt = {
> +			.type = range_option,
> +			.name = "Speed/Duplex Selection",
> +			.err  = "using default of "
> +				__MODULE_STRING(MEDIA_TYPE_AUTO_SENSOR),
> +			.def  = MEDIA_TYPE_AUTO_SENSOR,
> +			.arg  = { .r = { .min = MEDIA_TYPE_AUTO_SENSOR,
> +					 .max = MEDIA_TYPE_10M_HALF} }
> +		} ;
> +		int val;
> +		if (num_media_type > bd) {
> +			val = media_type[bd];
> +			atl1c_validate_option(&val, &opt, pdev);
> +			adapter->hw.media_type = (u16) val;
> +		} else
> +			adapter->hw.media_type = (u16)(opt.def);
> +
> +	}
> +}
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 62bc022..cdb8c46 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2350,6 +2350,17 @@  config ATL1E
 	  To compile this driver as a module, choose M here.  The module
 	  will be called atl1e.
 
+config ATL1C
+	tristate "Atheros L1C Gigabit Ethernet support (EXPERIMENTAL)"
+	depends on PCI && EXPERIMENTAL
+	select CRC32
+	select MII
+	help
+	  This driver supports the Atheros L1C gigabit ethernet adapter.
+
+	  To compile this driver as a module, choose M here.  The module
+	  will be called atl1c.
+
 config JME
 	tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
 	depends on PCI
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ad87ba7..3f8cb31 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -17,6 +17,7 @@  obj-$(CONFIG_BONDING) += bonding/
 obj-$(CONFIG_ATL1) += atlx/
 obj-$(CONFIG_ATL2) += atlx/
 obj-$(CONFIG_ATL1E) += atl1e/
+obj-$(CONFIG_ATL1C) += atl1c/
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
 obj-$(CONFIG_TEHUTI) += tehuti.o
 obj-$(CONFIG_ENIC) += enic/
diff --git a/drivers/net/atl1c/Makefile b/drivers/net/atl1c/Makefile
new file mode 100644
index 0000000..a2214a6
--- /dev/null
+++ b/drivers/net/atl1c/Makefile
@@ -0,0 +1,2 @@ 
+obj-$(CONFIG_ATL1C) += atl1c.o
+atl1c-objs := atl1c_main.o atl1c_hw.o atl1c_ethtool.o atl1c_param.o
diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
new file mode 100644
index 0000000..118c9a7
--- /dev/null
+++ b/drivers/net/atl1c/atl1c.h
@@ -0,0 +1,643 @@ 
+/*
+ * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _ATL1C_H_
+#define _ATL1C_H_
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/udp.h>
+#include <linux/mii.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/tcp.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/workqueue.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+
+#include "atl1c_hw.h"
+
+#define PCI_REG_COMMAND	 0x04    /* PCI Command Register */
+#define CMD_IO_SPACE	 0x0001
+#define CMD_MEMORY_SPACE 0x0002
+#define CMD_BUS_MASTER   0x0004
+
+#define BAR_0   0
+#define BAR_1   1
+#define BAR_5   5
+
+/* Wake Up Filter Control */
+#define AT_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define AT_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define AT_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define AT_WUFC_MC   0x00000008 /* Multicast Wakeup Enable */
+#define AT_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+
+#define AT_VLAN_TO_TAG(_vlan, _tag)	   \
+	_tag =  ((((_vlan) >> 8) & 0xF0)  |\
+		 (((_vlan) & 0xFF) << 8)  |\
+		 (((_vlan) & 0xF00) >> 8))
+
+#define AT_TAG_TO_VLAN(_tag, _vlan) 	 \
+	_vlan = ((((_tag) >> 8) & 0xF)  |\
+		(((_tag) & 0xF0) << 8)  |\
+		(((_tag) & 0xF) >> 8))
+
+#define SPEED_0		   0xffff
+#define HALF_DUPLEX        1
+#define FULL_DUPLEX        2
+
+/* Error Codes */
+#define AT_ERR_EEPROM      1
+#define AT_ERR_PHY         2
+#define AT_ERR_CONFIG      3
+#define AT_ERR_PARAM       4
+#define AT_ERR_MAC_TYPE    5
+#define AT_ERR_PHY_TYPE    6
+#define AT_ERR_PHY_SPEED   7
+#define AT_ERR_PHY_RES     8
+#define AT_ERR_TIMEOUT     9
+
+#define AT_RX_BUF_SIZE		1536
+#define MAX_JUMBO_FRAME_SIZE 	(9*1024)
+#define MAX_TX_OFFLOAD_THRESH	(9*1024)
+
+#define AT_MAX_RECEIVE_QUEUE    4
+#define AT_DEF_RECEIVE_QUEUE	1
+#define AT_MAX_TRANSMIT_QUEUE	2
+
+#define AT_DMA_HI_ADDR_MASK     0xffffffff00000000ULL
+#define AT_DMA_LO_ADDR_MASK     0x00000000ffffffffULL
+
+#define AT_TX_WATCHDOG  (5 * HZ)
+#define AT_MAX_INT_WORK		5
+#define AT_TWSI_EEPROM_TIMEOUT 	100
+#define AT_HW_MAX_IDLE_DELAY 	10
+#define AT_SUSPEND_LINK_TIMEOUT 28
+
+#define AT_ASPM_L0S_TIMER	6
+#define AT_ASPM_L1_TIMER	12
+
+#define ATL1C_PCIE_L0S_L1_DISABLE 	0x01
+#define ATL1C_PCIE_PHY_RESET		0x02
+
+#define ATL1C_ASPM_L0s_ENABLE		0x0001
+#define ATL1C_ASPM_L1_ENABLE		0x0002
+
+#define AT_REGS_LEN	75
+#define AT_EEPROM_LEN 	512
+#define AT_ADV_MASK	(ADVERTISE_10_HALF  |\
+			 ADVERTISE_10_FULL  |\
+			 ADVERTISE_100_HALF |\
+			 ADVERTISE_100_FULL |\
+			 ADVERTISE_1000_FULL)
+#define ATL1C_GET_DESC(R, i, type)	(&(((type *)((R)->desc))[i]))
+#define ATL1C_RFD_DESC(R, i)	ATL1C_GET_DESC(R, i, struct atl1c_rx_free_desc)
+#define ATL1C_TPD_DESC(R, i)	ATL1C_GET_DESC(R, i, struct atl1c_tpd_desc)
+#define ATL1C_RRD_DESC(R, i)	ATL1C_GET_DESC(R, i, struct atl1c_recv_ret_status)
+
+/* tpd word 1 bit 0:7 General Checksum task offload */
+#define TPD_L4HDR_OFFSET_MASK	0x00FF
+#define TPD_L4HDR_OFFSET_SHIFT	0
+
+/* tpd word 1 bit 0:7 Large Send task offload (IPv4/IPV6) */
+#define TPD_TCPHDR_OFFSET_MASK	0x00FF
+#define TPD_TCPHDR_OFFSET_SHIFT	0
+
+/* tpd word 1 bit 0:7 Custom Checksum task offload */
+#define TPD_PLOADOFFSET_MASK	0x00FF
+#define TPD_PLOADOFFSET_SHIFT	0
+
+/* tpd word 1 bit 8:17 */
+#define TPD_CCSUM_EN_MASK	0x0001
+#define TPD_CCSUM_EN_SHIFT	8
+#define TPD_IP_CSUM_MASK	0x0001
+#define TPD_IP_CSUM_SHIFT	9
+#define TPD_TCP_CSUM_MASK	0x0001
+#define TPD_TCP_CSUM_SHIFT	10
+#define TPD_UDP_CSUM_MASK	0x0001
+#define TPD_UDP_CSUM_SHIFT	11
+#define TPD_LSO_EN_MASK		0x0001	/* TCP Large Send Offload */
+#define TPD_LSO_EN_SHIFT	12
+#define TPD_LSO_VER_MASK	0x0001
+#define TPD_LSO_VER_SHIFT	13 	/* 0 : ipv4; 1 : ipv4/ipv6 */
+#define TPD_CON_VTAG_MASK	0x0001
+#define TPD_CON_VTAG_SHIFT	14
+#define TPD_INS_VTAG_MASK	0x0001
+#define TPD_INS_VTAG_SHIFT	15
+#define TPD_IPV4_PACKET_MASK	0x0001  /* valid when LSO VER  is 1 */
+#define TPD_IPV4_PACKET_SHIFT	16
+#define TPD_ETH_TYPE_MASK	0x0001
+#define TPD_ETH_TYPE_SHIFT	17	/* 0 : 802.3 frame; 1 : Ethernet */
+
+/* tpd word 18:25 Custom Checksum task offload */
+#define TPD_CCSUM_OFFSET_MASK	0x00FF
+#define TPD_CCSUM_OFFSET_SHIFT	18
+#define TPD_CCSUM_EPAD_MASK	0x0001
+#define TPD_CCSUM_EPAD_SHIFT	30
+
+/* tpd word 18:30 Large Send task offload (IPv4/IPV6) */
+#define TPD_MSS_MASK            0x1FFF
+#define TPD_MSS_SHIFT		18
+
+#define TPD_EOP_MASK		0x0001
+#define TPD_EOP_SHIFT		31
+
+struct atl1c_tpd_desc {
+	__le16	buffer_len; /* include 4-byte CRC */
+	u16	vlan_tag;
+	__le32	word1;
+	__le64	buffer_addr;
+};
+
+struct atl1c_tpd_ext_desc {
+	u32 reservd_0;
+	__le32 word1;
+	__le32 pkt_len;
+	u32 reservd_1;
+};
+/* rrs word 0 bit 0:31 */
+#define RRS_RX_CSUM_MASK	0xFFFF
+#define RRS_RX_CSUM_SHIFT	0
+#define RRS_RX_RFD_CNT_MASK	0x000F
+#define RRS_RX_RFD_CNT_SHIFT	16
+#define RRS_RX_RFD_INDEX_MASK	0x0FFF
+#define RRS_RX_RFD_INDEX_SHIFT	20
+
+/* rrs flag bit 0:16 */
+#define RRS_HEAD_LEN_MASK	0x00FF
+#define RRS_HEAD_LEN_SHIFT	0
+#define RRS_HDS_TYPE_MASK	0x0003
+#define RRS_HDS_TYPE_SHIFT	8
+#define RRS_CPU_NUM_MASK	0x0003
+#define	RRS_CPU_NUM_SHIFT	10
+#define RRS_HASH_FLG_MASK	0x000F
+#define RRS_HASH_FLG_SHIFT	12
+
+#define RRS_HDS_TYPE_HEAD	1
+#define RRS_HDS_TYPE_DATA	2
+
+#define RRS_IS_NO_HDS_TYPE(flag) \
+	(((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == 0)
+
+#define RRS_IS_HDS_HEAD(flag) \
+	(((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \
+			RRS_HDS_TYPE_HEAD)
+
+#define RRS_IS_HDS_DATA(flag) \
+	(((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \
+			RRS_HDS_TYPE_DATA)
+
+/* rrs word 3 bit 0:31 */
+#define RRS_PKT_SIZE_MASK	0x3FFF
+#define RRS_PKT_SIZE_SHIFT	0
+#define RRS_ERR_L4_CSUM_MASK	0x0001
+#define RRS_ERR_L4_CSUM_SHIFT	14
+#define RRS_ERR_IP_CSUM_MASK	0x0001
+#define RRS_ERR_IP_CSUM_SHIFT	15
+#define RRS_VLAN_INS_MASK	0x0001
+#define RRS_VLAN_INS_SHIFT	16
+#define RRS_PROT_ID_MASK	0x0007
+#define RRS_PROT_ID_SHIFT	17
+#define RRS_RX_ERR_SUM_MASK	0x0001
+#define RRS_RX_ERR_SUM_SHIFT	20
+#define RRS_RX_ERR_CRC_MASK	0x0001
+#define RRS_RX_ERR_CRC_SHIFT	21
+#define RRS_RX_ERR_FAE_MASK	0x0001
+#define RRS_RX_ERR_FAE_SHIFT	22
+#define RRS_RX_ERR_TRUNC_MASK	0x0001
+#define RRS_RX_ERR_TRUNC_SHIFT	23
+#define RRS_RX_ERR_RUNC_MASK	0x0001
+#define RRS_RX_ERR_RUNC_SHIFT	24
+#define RRS_RX_ERR_ICMP_MASK	0x0001
+#define RRS_RX_ERR_ICMP_SHIFT	25
+#define RRS_PACKET_BCAST_MASK	0x0001
+#define RRS_PACKET_BCAST_SHIFT	26
+#define RRS_PACKET_MCAST_MASK	0x0001
+#define RRS_PACKET_MCAST_SHIFT	27
+#define RRS_PACKET_TYPE_MASK	0x0001
+#define RRS_PACKET_TYPE_SHIFT	28
+#define RRS_FIFO_FULL_MASK	0x0001
+#define RRS_FIFO_FULL_SHIFT	29
+#define RRS_802_3_LEN_ERR_MASK 	0x0001
+#define RRS_802_3_LEN_ERR_SHIFT 30
+#define RRS_RXD_UPDATED_MASK	0x0001
+#define RRS_RXD_UPDATED_SHIFT	31
+
+#define RRS_ERR_L4_CSUM         0x00004000
+#define RRS_ERR_IP_CSUM         0x00008000
+#define RRS_VLAN_INS            0x00010000
+#define RRS_RX_ERR_SUM          0x00100000
+#define RRS_RX_ERR_CRC          0x00200000
+#define RRS_802_3_LEN_ERR	0x40000000
+#define RRS_RXD_UPDATED		0x80000000
+
+#define RRS_PACKET_TYPE_802_3  	1
+#define RRS_PACKET_TYPE_ETH	0
+#define RRS_PACKET_IS_ETH(word) \
+	(((word) >> RRS_PACKET_TYPE_SHIFT) & RRS_PACKET_TYPE_MASK == \
+			RRS_PACKET_TYPE_ETH)
+#define RRS_RXD_IS_VALID(word) \
+	((((word) >> RRS_RXD_UPDATED_SHIFT) & RRS_RXD_UPDATED_MASK) == 1)
+
+#define RRS_PACKET_PROT_IS_IPV4_ONLY(word) \
+	((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 1)
+#define RRS_PACKET_PROT_IS_IPV6_ONLY(word) \
+	((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 6)
+
+struct atl1c_recv_ret_status {
+	__le32  word0;
+	u32	rss_hash;
+	u16	vlan_tag;
+	u16	flag;
+	__le32	word3;
+};
+
+/* RFD desciptor */
+struct atl1c_rx_free_desc {
+	__le64	buffer_addr;
+};
+
+/* DMA Order Settings */
+enum atl1c_dma_order {
+	atl1c_dma_ord_in = 1,
+	atl1c_dma_ord_enh = 2,
+	atl1c_dma_ord_out = 4
+};
+
+enum atl1c_dma_rcb {
+	atl1c_rcb_64 = 0,
+	atl1c_rcb_128 = 1
+};
+
+enum atl1c_mac_speed {
+	atl1c_mac_speed_0 = 0,
+	atl1c_mac_speed_10_100 = 1,
+	atl1c_mac_speed_1000 = 2
+};
+
+enum atl1c_dma_req_block {
+	atl1c_dma_req_128 = 0,
+	atl1c_dma_req_256 = 1,
+	atl1c_dma_req_512 = 2,
+	atl1c_dma_req_1024 = 3,
+	atl1c_dma_req_2048 = 4,
+	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,
+	athr_l2c = 1,
+};
+
+enum atl1c_trans_queue {
+	atl1c_trans_normal = 0,
+	atl1c_trans_high = 1
+};
+
+struct atl1c_hw_stats {
+	/* rx */
+	unsigned long rx_ok;		/* The number of good packet received. */
+	unsigned long rx_bcast;		/* The number of good broadcast packet received. */
+	unsigned long rx_mcast;		/* The number of good multicast packet received. */
+	unsigned long rx_pause;		/* The number of Pause packet received. */
+	unsigned long rx_ctrl;		/* The number of Control packet received other than Pause frame. */
+	unsigned long rx_fcs_err;	/* The number of packets with bad FCS. */
+	unsigned long rx_len_err;	/* The number of packets with mismatch of length field and actual size. */
+	unsigned long rx_byte_cnt;	/* The number of bytes of good packet received. FCS is NOT included. */
+	unsigned long rx_runt;		/* The number of packets received that are less than 64 byte long and with good FCS. */
+	unsigned long rx_frag;		/* The number of packets received that are less than 64 byte long and with bad FCS. */
+	unsigned long rx_sz_64;		/* The number of good and bad packets received that are 64 byte long. */
+	unsigned long rx_sz_65_127;	/* The number of good and bad packets received that are between 65 and 127-byte long. */
+	unsigned long rx_sz_128_255;	/* The number of good and bad packets received that are between 128 and 255-byte long. */
+	unsigned long rx_sz_256_511;	/* The number of good and bad packets received that are between 256 and 511-byte long. */
+	unsigned long rx_sz_512_1023;	/* The number of good and bad packets received that are between 512 and 1023-byte long. */
+	unsigned long rx_sz_1024_1518;	/* The number of good and bad packets received that are between 1024 and 1518-byte long. */
+	unsigned long rx_sz_1519_max;	/* The number of good and bad packets received that are between 1519-byte and MTU. */
+	unsigned long rx_sz_ov;		/* The number of good and bad packets received that are more than MTU size truncated by Selene. */
+	unsigned long rx_rxf_ov;	/* The number of frame dropped due to occurrence of RX FIFO overflow. */
+	unsigned long rx_rrd_ov;	/* The number of frame dropped due to occurrence of RRD overflow. */
+	unsigned long rx_align_err;	/* Alignment Error */
+	unsigned long rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */
+	unsigned long rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */
+	unsigned long rx_err_addr;	/* The number of packets dropped due to address filtering. */
+
+	/* tx */
+	unsigned long tx_ok;		/* The number of good packet transmitted. */
+	unsigned long tx_bcast;		/* The number of good broadcast packet transmitted. */
+	unsigned long tx_mcast;		/* The number of good multicast packet transmitted. */
+	unsigned long tx_pause;		/* The number of Pause packet transmitted. */
+	unsigned long tx_exc_defer;	/* The number of packets transmitted with excessive deferral. */
+	unsigned long tx_ctrl;		/* The number of packets transmitted is a control frame, excluding Pause frame. */
+	unsigned long tx_defer;		/* The number of packets transmitted that is deferred. */
+	unsigned long tx_byte_cnt;	/* The number of bytes of data transmitted. FCS is NOT included. */
+	unsigned long tx_sz_64;		/* The number of good and bad packets transmitted that are 64 byte long. */
+	unsigned long tx_sz_65_127;	/* The number of good and bad packets transmitted that are between 65 and 127-byte long. */
+	unsigned long tx_sz_128_255;	/* The number of good and bad packets transmitted that are between 128 and 255-byte long. */
+	unsigned long tx_sz_256_511;	/* The number of good and bad packets transmitted that are between 256 and 511-byte long. */
+	unsigned long tx_sz_512_1023;	/* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */
+	unsigned long tx_sz_1024_1518;	/* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */
+	unsigned long tx_sz_1519_max;	/* The number of good and bad packets transmitted that are between 1519-byte and MTU. */
+	unsigned long tx_1_col;		/* The number of packets subsequently transmitted successfully with a single prior collision. */
+	unsigned long tx_2_col;		/* The number of packets subsequently transmitted successfully with multiple prior collisions. */
+	unsigned long tx_late_col;	/* The number of packets transmitted with late collisions. */
+	unsigned long tx_abort_col;	/* The number of transmit packets aborted due to excessive collisions. */
+	unsigned long tx_underrun;	/* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
+	unsigned long tx_rd_eop;	/* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */
+	unsigned long tx_len_err;	/* The number of transmit packets with length field does NOT match the actual frame size. */
+	unsigned long tx_trunc;		/* The number of transmit packets truncated due to size exceeding MTU. */
+	unsigned long tx_bcast_byte;	/* The byte count of broadcast packet transmitted, excluding FCS. */
+	unsigned long tx_mcast_byte;	/* The byte count of multicast packet transmitted, excluding FCS. */
+};
+
+struct atl1c_hw {
+	u8 __iomem      *hw_addr;            /* inner register address */
+	struct atl1c_adapter *adapter;
+	enum atl1c_nic_type  nic_type;
+	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;
+	u16 subsystem_id;
+	u16 subsystem_vendor_id;
+	u8 revision_id;
+
+	u32 intr_mask;
+	u8 dmaw_dly_cnt;
+	u8 dmar_dly_cnt;
+
+	u8 preamble_len;
+	u16 max_frame_size;
+	u16 min_frame_size;
+
+	enum atl1c_mac_speed mac_speed;
+	bool mac_duplex;
+	bool hibernate;
+	u16 media_type;
+#define MEDIA_TYPE_AUTO_SENSOR  0
+#define MEDIA_TYPE_100M_FULL    1
+#define MEDIA_TYPE_100M_HALF    2
+#define MEDIA_TYPE_10M_FULL     3
+#define MEDIA_TYPE_10M_HALF     4
+
+	u16 autoneg_advertised;
+#define ADVERTISE_10_HALF               0x0001
+#define ADVERTISE_10_FULL               0x0002
+#define ADVERTISE_100_HALF              0x0004
+#define ADVERTISE_100_FULL              0x0008
+#define ADVERTISE_1000_HALF             0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL             0x0020
+#define ADVERTISE_DEFAULT (ADVERTISE_10_HALF  |\
+			   ADVERTISE_10_FULL  |\
+			   ADVERTISE_100_HALF |\
+			   ADVERTISE_100_FULL |\
+			   ADVERTISE_1000_FULL)
+	u16 mii_autoneg_adv_reg;
+	u16 mii_1000t_ctrl_reg;
+
+	u16 tx_imt;	/* TX Interrupt Moderator timer ( 2us resolution) */
+	u16 rx_imt;	/* RX Interrupt Moderator timer ( 2us resolution) */
+	u16 ict;        /* Interrupt Clear timer (2us resolution) */
+	u16 ctrl_flags;
+#define ATL1C_INTR_CLEAR_ON_READ	0x0001
+#define ATL1C_INTR_MODRT_ENABLE	 	0x0002
+#define ATL1C_CMB_ENABLE		0x0004
+#define ATL1C_SMB_ENABLE		0x0010
+#define ATL1C_TXQ_MODE_ENHANCE		0x0020
+#define ATL1C_RX_IPV6_CHKSUM		0x0040
+#define ATL1C_ASPM_L0S_SUPPORT		0x0080
+#define ATL1C_ASPM_L1_SUPPORT		0x0100
+#define ATL1C_ASPM_CTRL_MON		0x0200
+#define ATL1C_HIB_DISABLE		0x0400
+#define ATL1C_LINK_CAP_1000M		0x0800
+#define ATL1C_FPGA_VERSION		0x8000
+	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
+			  interrupt request */
+	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];
+	u8 perm_mac_addr[ETH_ALEN];
+
+	bool phy_configured;
+	bool re_autoneg;
+	bool emi_ca;
+};
+
+/*
+ * 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
+ */
+struct atl1c_ring_header {
+	void *desc;		/* virtual address */
+	dma_addr_t dma;		/* physical address*/
+	unsigned int size;	/* length in bytes */
+};
+
+/*
+ * atl1c_buffer is wrapper around a pointer to a socket buffer
+ * so a DMA handle can be stored along with the skb
+ */
+struct atl1c_buffer {
+	struct sk_buff *skb;	/* socket buffer */
+	u16 length;		/* rx buffer length */
+	u16 state;		/* state of buffer */
+#define ATL1_BUFFER_FREE	0
+#define ATL1_BUFFER_BUSY	1
+	dma_addr_t dma;
+};
+
+/* transimit packet descriptor (tpd) ring */
+struct atl1c_tpd_ring {
+	void *desc;		/* descriptor ring virtual address */
+	dma_addr_t dma;		/* descriptor ring physical address */
+	u16 size;		/* descriptor ring length in bytes */
+	u16 count;		/* number of descriptors in the ring */
+	u16 next_to_use; 	/* this is protectd by adapter->tx_lock */
+	atomic_t next_to_clean;
+	struct atl1c_buffer *buffer_info;
+};
+
+/* receive free descriptor (rfd) ring */
+struct atl1c_rfd_ring {
+	void *desc;		/* descriptor ring virtual address */
+	dma_addr_t dma;		/* descriptor ring physical address */
+	u16 size;		/* descriptor ring length in bytes */
+	u16 count;		/* number of descriptors in the ring */
+	u16 next_to_use;
+	u16 next_to_clean;
+	struct atl1c_buffer *buffer_info;
+};
+
+/* receive return desciptor (rrd) ring */
+struct atl1c_rrd_ring {
+	void *desc;		/* descriptor ring virtual address */
+	dma_addr_t dma;		/* descriptor ring physical address */
+	u16 size;		/* descriptor ring length in bytes */
+	u16 count;		/* number of descriptors in the ring */
+	u16 next_to_use;
+	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 vlan_group   *vlgrp;
+	struct napi_struct  napi;
+	struct atl1c_hw        hw;
+	struct atl1c_hw_stats  hw_stats;
+	struct net_device_stats net_stats;
+	struct mii_if_info  mii;    /* MII interface info */
+	u16 rx_buffer_len;
+
+	unsigned long flags;
+#define __AT_TESTING        0x0001
+#define __AT_RESETTING      0x0002
+#define __AT_DOWN           0x0003
+
+	bool have_msi;
+	u32 wol;
+	u16 link_speed;
+	u16 link_duplex;
+
+	spinlock_t mdio_lock;
+	spinlock_t tx_lock;
+	atomic_t irq_sem;
+
+	struct work_struct reset_task;
+	struct work_struct link_chg_task;
+	struct timer_list watchdog_timer;
+	struct timer_list phy_config_timer;
+
+	/* 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;
+	u32 bd_number;     /* board number;*/
+};
+
+#define AT_WRITE_REG(a, reg, value) ( \
+		writel((value), ((a)->hw_addr + reg)))
+
+#define AT_WRITE_FLUSH(a) (\
+		readl((a)->hw_addr))
+
+#define AT_READ_REG(a, reg, pdata) do {					\
+		if (unlikely((a)->hibernate)) {				\
+			readl((a)->hw_addr + reg);			\
+			*(u32 *)pdata = readl((a)->hw_addr + reg);	\
+		} else {						\
+			*(u32 *)pdata = readl((a)->hw_addr + reg);	\
+		}							\
+	} while (0)
+
+#define AT_WRITE_REGB(a, reg, value) (\
+		writeb((value), ((a)->hw_addr + reg)))
+
+#define AT_READ_REGB(a, reg) (\
+		readb((a)->hw_addr + reg))
+
+#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_WRITE_REG_ARRAY(a, reg, offset, value) ( \
+		writel((value), (((a)->hw_addr + reg) + ((offset) << 2))))
+
+#define AT_READ_REG_ARRAY(a, reg, offset) ( \
+		readl(((a)->hw_addr + reg) + ((offset) << 2)))
+
+extern char atl1c_driver_name[];
+extern char atl1c_driver_version[];
+
+extern void atl1c_check_options(struct atl1c_adapter *adapter);
+extern int atl1c_up(struct atl1c_adapter *adapter);
+extern void atl1c_down(struct atl1c_adapter *adapter);
+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);
+#endif /* _ATL1C_H_ */
diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c
new file mode 100644
index 0000000..66a9916
--- /dev/null
+++ b/drivers/net/atl1c/atl1c_ethtool.c
@@ -0,0 +1,379 @@ 
+/*
+ * Copyright(c) 2009 - 2009 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+
+#include "atl1c.h"
+
+static int atl1c_get_settings(struct net_device *netdev,
+			      struct ethtool_cmd *ecmd)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct atl1c_hw *hw = &adapter->hw;
+
+	ecmd->supported = (SUPPORTED_10baseT_Half  |
+			   SUPPORTED_10baseT_Full  |
+			   SUPPORTED_100baseT_Half |
+			   SUPPORTED_100baseT_Full |
+			   SUPPORTED_Autoneg       |
+			   SUPPORTED_TP);
+	if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M)
+		ecmd->supported |= SUPPORTED_1000baseT_Full;
+
+	ecmd->advertising = ADVERTISED_TP;
+
+	ecmd->advertising |= ADVERTISED_Autoneg;
+	ecmd->advertising |= hw->autoneg_advertised;
+
+	ecmd->port = PORT_TP;
+	ecmd->phy_address = 0;
+	ecmd->transceiver = XCVR_INTERNAL;
+
+	if (adapter->link_speed != SPEED_0) {
+		ecmd->speed = adapter->link_speed;
+		if (adapter->link_duplex == FULL_DUPLEX)
+			ecmd->duplex = DUPLEX_FULL;
+		else
+			ecmd->duplex = DUPLEX_HALF;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+
+	ecmd->autoneg = AUTONEG_ENABLE;
+	return 0;
+}
+
+static int atl1c_set_settings(struct net_device *netdev,
+			      struct ethtool_cmd *ecmd)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct atl1c_hw *hw = &adapter->hw;
+	u16  autoneg_advertised;
+	while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
+		msleep(1);
+
+	if (ecmd->autoneg == AUTONEG_ENABLE) {
+		autoneg_advertised = ADVERTISE_DEFAULT;
+	} else {
+		if (ecmd->speed == SPEED_1000) {
+			if (ecmd->duplex != DUPLEX_FULL) {
+				printk(KERN_WARNING"1000M half is invalid\n");
+				clear_bit(__AT_RESETTING, &adapter->flags);
+				return -EINVAL;
+			}
+			autoneg_advertised = ADVERTISE_1000_FULL;
+		} else if (ecmd->speed == SPEED_100) {
+			if (ecmd->duplex == DUPLEX_FULL)
+				autoneg_advertised = ADVERTISE_100_FULL;
+			else
+				autoneg_advertised = ADVERTISE_100_HALF;
+		} else {
+			if (ecmd->duplex == DUPLEX_FULL)
+				autoneg_advertised = ADVERTISE_10_FULL;
+			else
+				autoneg_advertised = ADVERTISE_10_HALF;
+		}
+	}
+
+	if (hw->autoneg_advertised != autoneg_advertised) {
+		hw->autoneg_advertised = autoneg_advertised;
+		if (atl1c_restart_autoneg(hw) != 0) {
+			printk(KERN_WARNING
+				"ethtool speed/duplex setting failed\n");
+			clear_bit(__AT_RESETTING, &adapter->flags);
+			return -EINVAL;
+		}
+	}
+	clear_bit(__AT_RESETTING, &adapter->flags);
+	return 0;
+}
+
+static u32 atl1c_get_tx_csum(struct net_device *netdev)
+{
+	return (netdev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+static u32 atl1c_get_msglevel(struct net_device *netdev)
+{
+#ifdef DBG
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+static void atl1c_set_msglevel(struct net_device *netdev, u32 data)
+{
+}
+
+static int atl1c_get_regs_len(struct net_device *netdev)
+{
+	return AT_REGS_LEN *sizeof(u32);
+}
+
+static void atl1c_get_regs(struct net_device *netdev,
+			   struct ethtool_regs *regs, void *p)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct atl1c_hw *hw = &adapter->hw;
+	u32 *regs_buff = p;
+	u16 phy_data;
+
+	memset(p, 0, (AT_REGS_LEN *sizeof(u32)));
+
+	regs->version = 0;
+	AT_READ_REG(hw, REG_VPD_CAP, 		  p++);
+	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++);
+	AT_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL,   p++);
+	AT_READ_REG(hw, REG_MASTER_CTRL, 	  p++);
+	AT_READ_REG(hw, REG_MANUAL_TIMER_INIT,    p++);
+	AT_READ_REG(hw, REG_IRQ_MODRT_TIMER_INIT, p++);
+	AT_READ_REG(hw, REG_GPHY_CTRL, 		  p++);
+	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_MAC_CTRL, 		  p++);
+	AT_READ_REG(hw, REG_MAC_IPG_IFG, 	  p++);
+	AT_READ_REG(hw, REG_MAC_STA_ADDR, 	  p++);
+	AT_READ_REG(hw, REG_MAC_STA_ADDR+4, 	  p++);
+	AT_READ_REG(hw, REG_RX_HASH_TABLE, 	  p++);
+	AT_READ_REG(hw, REG_RX_HASH_TABLE+4, 	  p++);
+	AT_READ_REG(hw, REG_RXQ_CTRL, 		  p++);
+	AT_READ_REG(hw, REG_TXQ_CTRL, 		  p++);
+	AT_READ_REG(hw, REG_MTU, 		  p++);
+	AT_READ_REG(hw, REG_WOL_CTRL, 		  p++);
+
+	atl1c_read_phy_reg(hw, MII_BMCR, &phy_data);
+	regs_buff[73] =	(u32) phy_data;
+	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+	regs_buff[74] = (u32) phy_data;
+}
+
+static int atl1c_get_eeprom_len(struct net_device *netdev)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	if (atl1c_check_eeprom_exist(&adapter->hw))
+		return AT_EEPROM_LEN;
+	else
+		return 0;
+}
+
+static int atl1c_get_eeprom(struct net_device *netdev,
+		struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct atl1c_hw *hw = &adapter->hw;
+	u32 *eeprom_buff;
+	int first_dword, last_dword;
+	int ret_val = 0;
+	int i;
+
+	if (eeprom->len == 0)
+		return -EINVAL;
+
+	if (!atl1c_check_eeprom_exist(hw)) /* not exist */
+		return -EINVAL;
+
+	eeprom->magic = adapter->pdev->vendor |
+			(adapter->pdev->device << 16);
+
+	first_dword = eeprom->offset >> 2;
+	last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
+
+	eeprom_buff = kmalloc(sizeof(u32) *
+			(last_dword - first_dword + 1), GFP_KERNEL);
+	if (eeprom_buff == NULL)
+		return -ENOMEM;
+
+	for (i = first_dword; i < last_dword; i++) {
+		if (!atl1c_read_eeprom(hw, i * 4, &(eeprom_buff[i-first_dword]))) {
+			kfree(eeprom_buff);
+			return -EIO;
+		}
+	}
+
+	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3),
+			eeprom->len);
+	kfree(eeprom_buff);
+
+	return ret_val;
+	return 0;
+}
+
+static int atl1c_set_eeprom(struct net_device *netdev,
+			    struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct atl1c_hw *hw = &adapter->hw;
+	u32 *eeprom_buff;
+	u32 *ptr;
+	int first_dword, last_dword;
+	int ret_val = 0;
+	int i;
+
+	if (eeprom->len == 0)
+		return -EOPNOTSUPP;
+
+	if (eeprom->magic != (adapter->pdev->vendor |
+				(adapter->pdev->device << 16)))
+		return -EINVAL;
+
+	first_dword = eeprom->offset >> 2;
+	last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
+	eeprom_buff = kmalloc(AT_EEPROM_LEN, GFP_KERNEL);
+	if (eeprom_buff == NULL)
+		return -ENOMEM;
+
+	ptr = (u32 *)eeprom_buff;
+
+	if (eeprom->offset & 3) {
+		/* need read/modify/write of first changed EEPROM word */
+		/* only the second byte of the word is being modified */
+		if (!atl1c_read_eeprom(hw, first_dword * 4, &(eeprom_buff[0]))) {
+			ret_val = -EIO;
+			goto out;
+		}
+		ptr++;
+	}
+	if (((eeprom->offset + eeprom->len) & 3)) {
+		/* need read/modify/write of last changed EEPROM word */
+		/* only the first byte of the word is being modified */
+
+		if (!atl1c_read_eeprom(hw, last_dword * 4,
+				&(eeprom_buff[last_dword - first_dword]))) {
+			ret_val = -EIO;
+			goto out;
+		}
+	}
+
+	/* Device's eeprom is always little-endian, word addressable */
+	memcpy(ptr, bytes, eeprom->len);
+
+	for (i = 0; i < last_dword - first_dword + 1; i++) {
+		if (!atl1c_write_eeprom(hw, ((first_dword + i) * 4),
+				  eeprom_buff[i])) {
+			ret_val = -EIO;
+			goto out;
+		}
+	}
+out:
+	kfree(eeprom_buff);
+	return ret_val;
+	return 0;
+}
+
+static void atl1c_get_drvinfo(struct net_device *netdev,
+		struct ethtool_drvinfo *drvinfo)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	strncpy(drvinfo->driver,  atl1c_driver_name, 32);
+	strncpy(drvinfo->version, atl1c_driver_version, 32);
+	strncpy(drvinfo->fw_version, "L1e", 32);
+	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+	drvinfo->n_stats = 0;
+	drvinfo->testinfo_len = 0;
+	drvinfo->regdump_len = atl1c_get_regs_len(netdev);
+	drvinfo->eedump_len = atl1c_get_eeprom_len(netdev);
+}
+
+static void atl1c_get_wol(struct net_device *netdev,
+			  struct ethtool_wolinfo *wol)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	wol->supported = WAKE_MAGIC | WAKE_PHY;
+	wol->wolopts = 0;
+
+	if (adapter->wol & AT_WUFC_EX)
+		wol->wolopts |= WAKE_UCAST;
+	if (adapter->wol & AT_WUFC_MC)
+		wol->wolopts |= WAKE_MCAST;
+	if (adapter->wol & AT_WUFC_BC)
+		wol->wolopts |= WAKE_BCAST;
+	if (adapter->wol & AT_WUFC_MAG)
+		wol->wolopts |= WAKE_MAGIC;
+	if (adapter->wol & AT_WUFC_LNKC)
+		wol->wolopts |= WAKE_PHY;
+
+	return;
+}
+
+static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
+			    WAKE_MCAST | WAKE_BCAST | WAKE_MCAST))
+		return -EOPNOTSUPP;
+	/* these settings will always override what we currently have */
+	adapter->wol = 0;
+
+	if (wol->wolopts & WAKE_MAGIC)
+		adapter->wol |= AT_WUFC_MAG;
+	if (wol->wolopts & WAKE_PHY)
+		adapter->wol |= AT_WUFC_LNKC;
+
+	return 0;
+}
+
+static int atl1c_nway_reset(struct net_device *netdev)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	if (netif_running(netdev))
+		atl1c_reinit_locked(adapter);
+	return 0;
+}
+
+static struct ethtool_ops atl1c_ethtool_ops = {
+	.get_settings           = atl1c_get_settings,
+	.set_settings           = atl1c_set_settings,
+	.get_drvinfo            = atl1c_get_drvinfo,
+	.get_regs_len           = atl1c_get_regs_len,
+	.get_regs               = atl1c_get_regs,
+	.get_wol                = atl1c_get_wol,
+	.set_wol                = atl1c_set_wol,
+	.get_msglevel           = atl1c_get_msglevel,
+	.set_msglevel           = atl1c_set_msglevel,
+	.nway_reset             = atl1c_nway_reset,
+	.get_link               = ethtool_op_get_link,
+	.get_eeprom_len         = atl1c_get_eeprom_len,
+	.get_eeprom             = atl1c_get_eeprom,
+	.set_eeprom             = atl1c_set_eeprom,
+	.get_tx_csum            = atl1c_get_tx_csum,
+	.get_sg                 = ethtool_op_get_sg,
+	.set_sg                 = ethtool_op_set_sg,
+#ifdef NETIF_F_TSO
+	.get_tso                = ethtool_op_get_tso,
+#endif
+};
+
+void atl1c_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &atl1c_ethtool_ops);
+}
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
new file mode 100644
index 0000000..0d3edbf
--- /dev/null
+++ b/drivers/net/atl1c/atl1c_hw.c
@@ -0,0 +1,547 @@ 
+/*
+ * Copyright(c) 2007 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+
+#include "atl1c.h"
+
+/*
+ * check_eeprom_exist
+ * return 1 if eeprom exist
+ */
+int atl1c_check_eeprom_exist(struct atl1c_hw *hw)
+{
+	u32 data;
+
+	AT_READ_REG(hw, REG_TWSI_DEBUG, &data);
+	if (data & TWSI_DEBUG_DEV_EXIST)
+		return 1;
+
+	return 0;
+}
+
+void atl1c_hw_set_mac_addr(struct atl1c_hw *hw)
+{
+	u32 value;
+	/*
+	 * 00-0B-6A-F6-00-DC
+	 * 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])) ;
+	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])) ;
+	AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value);
+}
+
+/*
+ * 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;
+	u8  eth_addr[ETH_ALEN];
+
+	/* init */
+	addr[0] = addr[1] = 0;
+	AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
+	if (atl1c_check_eeprom_exist(hw)) {
+		/* Enable OTP CLK */
+		if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
+			otp_ctrl_data |= OTP_CTRL_CLK_EN;
+			AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+			msleep(1);
+		}
+
+		AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
+		twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
+		AT_WRITE_REG(hw, REG_TWSI_CTRL, twsi_ctrl_data);
+		for (i = 0; i < AT_TWSI_EEPROM_TIMEOUT; i++) {
+			msleep(10);
+			AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
+			if ((twsi_ctrl_data & TWSI_CTRL_SW_LDSTART) == 0)
+				break;
+		}
+		if (i >= AT_TWSI_EEPROM_TIMEOUT)
+			return AT_ERR_TIMEOUT;
+	}
+	/* Disable OTP_CLK */
+	if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
+		otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
+		AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+		msleep(1);
+	}
+
+	/* 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 *) &eth_addr[2] = swab32(addr[0]);
+	*(u16 *) &eth_addr[0] = swab16(*(u16 *)&addr[1]);
+
+	if (is_valid_ether_addr(eth_addr)) {
+		memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+		return 0;
+	}
+
+	return AT_ERR_EEPROM;
+}
+
+bool atl1c_write_eeprom(struct atl1c_hw *hw, u32 offset, u32 value)
+{
+	return true;
+}
+
+bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value)
+{
+	int i;
+	int ret = false;
+	u32 otp_ctrl_data;
+	u32 control;
+	u32 data;
+
+	if (offset & 3)
+		return ret; /* address do not align */
+
+	AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
+	if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
+		AT_WRITE_REG(hw, REG_OTP_CTRL,
+				(otp_ctrl_data | OTP_CTRL_CLK_EN));
+
+	AT_WRITE_REG(hw, REG_EEPROM_DATA_LO, 0);
+	control = (offset & EEPROM_CTRL_ADDR_MASK) << EEPROM_CTRL_ADDR_SHIFT;
+	AT_WRITE_REG(hw, REG_EEPROM_CTRL, control);
+
+	for (i = 0; i < 10; i++) {
+		udelay(100);
+		AT_READ_REG(hw, REG_EEPROM_CTRL, &control);
+		if (control & EEPROM_CTRL_RW)
+			break;
+	}
+	if (control & EEPROM_CTRL_RW) {
+		AT_READ_REG(hw, REG_EEPROM_CTRL, &data);
+		AT_READ_REG(hw, REG_EEPROM_DATA_LO, p_value);
+		data = data & 0xFFFF;
+		*p_value = swab32((data << 16) | (*p_value >> 16));
+		ret = true;
+	}
+	if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
+		AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+
+	return ret;
+}
+/*
+ * Reads the adapter's MAC address from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ */
+int atl1c_read_mac_addr(struct atl1c_hw *hw)
+{
+	int err = 0;
+
+	err = atl1c_get_permanent_address(hw);
+	if (err) {
+		hw->perm_mac_addr[0] = 0x00;
+		hw->perm_mac_addr[1] = 0x13;
+		hw->perm_mac_addr[2] = 0x74;
+		hw->perm_mac_addr[3] = 0x00;
+		hw->perm_mac_addr[4] = 0x5c;
+		hw->perm_mac_addr[5] = 0x38;
+	}
+
+	memcpy(hw->mac_addr, hw->perm_mac_addr, sizeof(hw->perm_mac_addr));
+	return 0;
+}
+
+/*
+ * atl1c_hash_mc_addr
+ *  purpose
+ *      set hash value for a multicast address
+ *      hash calcu processing :
+ *          1. calcu 32bit CRC for multicast address
+ *          2. reverse crc with MSB to LSB
+ */
+u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr)
+{
+	u32 crc32;
+	u32 value = 0;
+	int i;
+
+	crc32 = ether_crc_le(6, mc_addr);
+	for (i = 0; i < 32; i++)
+		value |= (((crc32 >> i) & 1) << (31 - i));
+
+	return value;
+}
+
+/*
+ * Sets the bit in the multicast table corresponding to the hash value.
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ */
+void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value)
+{
+	u32 hash_bit, hash_reg;
+	u32 mta;
+
+	/*
+	 * The HASH Table  is a register array of 2 32-bit registers.
+	 * It is treated like an array of 64 bits.  We want to set
+	 * bit BitArray[hash_value]. So we figure out what register
+	 * the bit is in, read it, OR in the new bit, then write
+	 * back the new value.  The register is determined by the
+	 * upper 7 bits of the hash value and the bit within that
+	 * register are determined by the lower 5 bits of the value.
+	 */
+	hash_reg = (hash_value >> 31) & 0x1;
+	hash_bit = (hash_value >> 26) & 0x1F;
+
+	mta = AT_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg);
+
+	mta |= (1 << hash_bit);
+
+	AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta);
+}
+
+/*
+ * 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)
+{
+	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;
+
+	AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
+
+	wmb();
+
+	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;
+		wmb();
+	}
+	if (!(val & (MDIO_START | MDIO_BUSY))) {
+		*phy_data = (u16)val;
+		return 0;
+	}
+
+	return AT_ERR_PHY;
+}
+
+/*
+ * Writes a value to a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to write
+ * data - data to write to the PHY
+ */
+int atl1c_write_phy_reg(struct atl1c_hw *hw, u32 reg_addr, u16 phy_data)
+{
+	int i;
+	u32 val;
+
+	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;
+
+	AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
+	wmb();
+
+	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;
+		wmb();
+	}
+
+	if (!(val & (MDIO_START | MDIO_BUSY)))
+		return 0;
+
+	return AT_ERR_PHY;
+}
+
+/*
+ * Configures PHY autoneg and flow control advertisement settings
+ *
+ * hw - Struct containing variables accessed by shared code
+ */
+static int atl1c_phy_setup_adv(struct atl1c_hw *hw)
+{
+	u16 mii_adv_data = ADVERTISE_DEFAULT_CAP & ~ADVERTISE_SPEED_MASK;
+	u16 mii_giga_ctrl_data = GIGA_CR_1000T_DEFAULT_CAP &
+				~GIGA_CR_1000T_SPEED_MASK;
+
+	if (hw->autoneg_advertised & ADVERTISE_10_HALF)
+		mii_adv_data |= ADVERTISE_10T_HD_CAPS;
+	if (hw->autoneg_advertised & ADVERTISE_10_FULL)
+		mii_adv_data |= ADVERTISE_10T_FD_CAPS;
+	if (hw->autoneg_advertised & ADVERTISE_100_HALF)
+		mii_adv_data |= ADVERTISE_100TX_HD_CAPS;
+	if (hw->autoneg_advertised & ADVERTISE_100_FULL)
+		mii_adv_data |= ADVERTISE_100TX_FD_CAPS;
+
+	if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M) {
+		if (hw->autoneg_advertised & ADVERTISE_1000_HALF)
+			mii_giga_ctrl_data |= GIGA_CR_1000T_HD_CAPS;
+		if (hw->autoneg_advertised & ADVERTISE_1000_FULL)
+			mii_giga_ctrl_data |= GIGA_CR_1000T_FD_CAPS;
+	}
+
+	if (atl1c_write_phy_reg(hw, MII_ADVERTISE, mii_adv_data) != 0 ||
+	    atl1c_write_phy_reg(hw, MII_GIGA_CR, mii_giga_ctrl_data) != 0)
+		return AT_ERR_PHY_SPEED;
+	return 0;
+}
+
+/*
+ * Resets the PHY and make all config validate
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets bit 15 and 12 of the MII control regiser (for F001 bug)
+ */
+#if 0
+int atl1c_phy_commit(struct atl1c_hw *hw)
+{
+	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+	struct pci_dev *pdev = adapter->pdev;
+	int ret_val;
+	u16 phy_data;
+
+	phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG;
+
+	ret_val = atl1c_write_phy_reg(hw, MII_BMCR, phy_data);
+	if (ret_val) {
+		u32 val;
+		int i;
+		/**************************************
+		 * pcie serdes link may be down !
+		 **************************************/
+		for (i = 0; i < 25; i++) {
+			msleep(1);
+			val = AT_READ_REG(hw, REG_MDIO_CTRL);
+			if (!(val & (MDIO_START | MDIO_BUSY)))
+				break;
+		}
+
+		if (0 != (val & (MDIO_START | MDIO_BUSY))) {
+			dev_err(&pdev->dev,
+				"pcie linkdown at least for 25ms\n");
+			return ret_val;
+		}
+
+		dev_err(&pdev->dev, "pcie linkup after %d ms\n", i);
+	}
+	return 0;
+}
+#endif
+
+void atl1c_phy_disable(struct atl1c_hw *hw)
+{
+	AT_WRITE_REGW(hw, REG_GPHY_CTRL,
+			GPHY_CTRL_PW_WOL_DIS | GPHY_CTRL_EXT_RESET);
+}
+
+static void atl1c_phy_magic_data(struct atl1c_hw *hw)
+{
+	u16 data;
+
+	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x12);
+	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x4C04);
+
+	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x05);
+	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x2C46);
+
+	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x36);
+	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xE12C);
+
+	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x04);
+	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x88BB);
+
+	atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
+	atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x02EF);
+
+	if (hw->ctrl_flags & ATL1C_HIB_DISABLE) {
+		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+		if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0)
+			return;
+		data &= 0x7FFF;
+		atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
+
+		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB);
+		if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0)
+			return;
+		data &= 0x7FFF;
+		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;
+	u32 phy_ctrl_data = GPHY_CTRL_DEFAULT;
+	u32 mii_ier_data = IER_LINK_UP | IER_LINK_DOWN;
+	int err;
+
+	if (hw->ctrl_flags & ATL1C_HIB_DISABLE)
+		phy_ctrl_data &= ~GPHY_CTRL_HIB_EN;
+
+	AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data);
+	msleep(40);
+	phy_ctrl_data |= GPHY_CTRL_EXT_RESET;
+	AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data);
+	msleep(10);
+
+	/*Enable PHY LinkChange Interrupt */
+	err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
+	if (err) {
+		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 pci_dev *pdev = adapter->pdev;
+	int ret_val;
+	u16 mii_bmcr_data = BMCR_RESET;
+	u16 phy_id1, phy_id2;
+
+	if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &phy_id1) != 0) ||
+		(atl1c_read_phy_reg(hw, MII_PHYSID2, &phy_id2) != 0)) {
+		dev_err(&pdev->dev, "Error get phy ID\n");
+		return -1;
+	}
+	switch (hw->media_type) {
+	case MEDIA_TYPE_AUTO_SENSOR:
+		ret_val = atl1c_phy_setup_adv(hw);
+		if (ret_val) {
+			dev_err(&pdev->dev,
+				"Error Setting up Auto-Negotiation\n");
+			return ret_val;
+		}
+		mii_bmcr_data |= BMCR_AUTO_NEG_EN | BMCR_RESTART_AUTO_NEG;
+		break;
+	case MEDIA_TYPE_100M_FULL:
+		mii_bmcr_data |= BMCR_SPEED_100 | BMCR_FULL_DUPLEX;
+		break;
+	case MEDIA_TYPE_100M_HALF:
+		mii_bmcr_data |= BMCR_SPEED_100;
+		break;
+	case MEDIA_TYPE_10M_FULL:
+		mii_bmcr_data |= BMCR_SPEED_10 | BMCR_FULL_DUPLEX;
+		break;
+	case MEDIA_TYPE_10M_HALF:
+		mii_bmcr_data |= BMCR_SPEED_10;
+		break;
+	default:
+		dev_err(&pdev->dev, "Wrong Media type %d\n", hw->media_type);
+		return AT_ERR_PARAM;
+		break;
+	}
+
+	ret_val = atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data);
+	if (ret_val)
+		return ret_val;
+	hw->phy_configured = true;
+
+	return 0;
+}
+
+/*
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ */
+int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
+{
+	int err;
+	u16 phy_data;
+
+	/* Read   PHY Specific Status Register (17) */
+	err = atl1c_read_phy_reg(hw, MII_GIGA_PSSR, &phy_data);
+	if (err)
+		return err;
+
+	if (!(phy_data & GIGA_PSSR_SPD_DPLX_RESOLVED))
+		return AT_ERR_PHY_RES;
+
+	switch (phy_data & GIGA_PSSR_SPEED) {
+	case GIGA_PSSR_1000MBS:
+		*speed = SPEED_1000;
+		break;
+	case GIGA_PSSR_100MBS:
+		*speed = SPEED_100;
+		break;
+	case  GIGA_PSSR_10MBS:
+		*speed = SPEED_10;
+		break;
+	default:
+		return AT_ERR_PHY_SPEED;
+		break;
+	}
+
+	if (phy_data & GIGA_PSSR_DPLX)
+		*duplex = FULL_DUPLEX;
+	else
+		*duplex = HALF_DUPLEX;
+
+	return 0;
+}
+
+int atl1c_restart_autoneg(struct atl1c_hw *hw)
+{
+	int err = 0;
+	u16 mii_bmcr_data = BMCR_RESET;
+
+	err = atl1c_phy_setup_adv(hw);
+	if (err)
+		return err;
+	mii_bmcr_data |= BMCR_AUTO_NEG_EN | BMCR_RESTART_AUTO_NEG;
+
+	return atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data);
+}
diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h
new file mode 100644
index 0000000..aa3fdb0
--- /dev/null
+++ b/drivers/net/atl1c/atl1c_hw.h
@@ -0,0 +1,829 @@ 
+/*
+ * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _ATL1C_HW_H_
+#define _ATL1C_HW_H_
+
+#include <linux/types.h>
+#include <linux/mii.h>
+
+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);
+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);
+u32 atl1c_auto_get_fc(struct atl1c_adapter *adapter, u16 duplex);
+u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr);
+void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value);
+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 atl1c_validate_mdi_setting(struct atl1c_hw *hw);
+void atl1c_hw_set_mac_addr(struct atl1c_hw *hw);
+bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value);
+bool atl1c_write_eeprom(struct atl1c_hw *hw, u32 offset, u32 value);
+int atl1c_phy_enter_power_saving(struct atl1c_hw *hw);
+int atl1c_phy_leave_power_saving(struct atl1c_hw *hw);
+int atl1c_phy_init(struct atl1c_hw *hw);
+int atl1c_check_eeprom_exist(struct atl1c_hw *hw);
+void atl1c_force_ps(struct atl1c_hw *hw);
+int atl1c_restart_autoneg(struct atl1c_hw *hw);
+
+/* register definition */
+#define REG_PM_CTRLSTAT             	0x44
+#define PM_CTRLSTAT_PME_EN		0x100
+
+#define REG_PCIE_CAP_LIST           	0x58
+
+#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 REG_LINK_CTRL			0x68
+#define LINK_CTRL_L0S_EN		0x01
+#define LINK_CTRL_L1_EN			0x02
+
+#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_DEV_SERIALNUM_CTRL		0x200
+#define REG_DEV_MAC_SEL_MASK		0x0 /* 0:EUI; 1:MAC */
+#define REG_DEV_MAC_SEL_SHIFT		0
+#define REG_DEV_SERIAL_NUM_EN_MASK	0x1
+#define REG_DEV_SERIAL_NUM_EN_SHIFT	1
+
+#define REG_TWSI_CTRL               	0x218
+#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
+#define PCIE_DEV_MISC_RETRY_BUFDIS 	0x1
+#define PCIE_DEV_MISC_SPIROM_EXIST 	0x4
+#define PCIE_DEV_MISC_SERDES_ENDIAN    	0x8
+#define PCIE_DEV_MISC_SERDES_SEL_DIN   	0x10
+
+#define REG_PCIE_PHYMISC	    	0x1000
+#define PCIE_PHYMISC_FORCE_RCV_DET	0x4
+
+#define REG_TWSI_DEBUG			0x1108
+#define TWSI_DEBUG_DEV_EXIST		0x20000000
+
+#define REG_EEPROM_CTRL			0x12C0
+#define EEPROM_CTRL_DATA_HI_MASK	0xFFFF
+#define EEPROM_CTRL_DATA_HI_SHIFT	0
+#define EEPROM_CTRL_ADDR_MASK		0x3FF
+#define EEPROM_CTRL_ADDR_SHIFT		16
+#define EEPROM_CTRL_ACK			0x40000000
+#define EEPROM_CTRL_RW			0x80000000
+
+#define REG_EEPROM_DATA_LO		0x12C4
+
+#define REG_OTP_CTRL			0x12F0
+#define OTP_CTRL_CLK_EN			0x0002
+
+#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_PCIE_RECV		0x00008000
+#define PM_CTRL_L1_ENTRY_TIMER_MASK	0xF
+#define PM_CTRL_L1_ENTRY_TIMER_SHIFT	16
+#define PM_CTRL_PM_REQ_TIMER_MASK	0xF
+#define PM_CTRL_PM_REQ_TIMER_SHIFT	20
+#define PM_CTRL_LCKDET_TIMER_MASK	0x3F
+#define PM_CTRL_LCKDET_TIMER_SHIFT	24
+#define PM_CTRL_MAC_ASPM_CHK		0x40000000
+#define PM_CTRL_HOTRST			0x80000000
+
+/* 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_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
+
+/* Timer Initial Value Register */
+#define REG_MANUAL_TIMER_INIT       	0x1404
+
+/* IRQ ModeratorTimer Initial Value Register */
+#define REG_IRQ_MODRT_TIMER_INIT     	0x1408
+#define IRQ_MODRT_TIMER_MASK		0xffff
+#define IRQ_MODRT_TX_TIMER_SHIFT    	0
+#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)
+
+/* 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
+
+/* 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
+/* BIST Control and Status Register0 (for the Packet Memory) */
+#define REG_BIST0_CTRL              	0x141c
+#define BIST0_NOW                   	0x1
+#define BIST0_SRAM_FAIL             	0x2 /* 1: The SRAM failure is
+					     * un-repairable  because
+					     * it has address decoder
+					     * failure or more than 1 cell
+					     * stuck-to-x failure */
+#define BIST0_FUSE_FLAG             	0x4
+
+/* BIST Control and Status Register1(for the retry buffer of PCI Express) */
+#define REG_BIST1_CTRL			0x1420
+#define BIST1_NOW                   	0x1
+#define BIST1_SRAM_FAIL             	0x2
+#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 */
+
+/* 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
+
+/* MAC IPG/IFG Control Register  */
+#define REG_MAC_IPG_IFG             	0x1484
+#define MAC_IPG_IFG_IPGT_SHIFT      	0 	/* Desired back to back
+						 * inter-packet gap. The
+						 * default is 96-bit time */
+#define MAC_IPG_IFG_IPGT_MASK       	0x7f
+#define MAC_IPG_IFG_MIFG_SHIFT      	8       /* Minimum number of IFG to
+						 * enforce in between RX frames */
+#define MAC_IPG_IFG_MIFG_MASK       	0xff  	/* Frame gap below such IFP is dropped */
+#define MAC_IPG_IFG_IPGR1_SHIFT     	16   	/* 64bit Carrier-Sense window */
+#define MAC_IPG_IFG_IPGR1_MASK      	0x7f
+#define MAC_IPG_IFG_IPGR2_SHIFT     	24    	/* 96-bit IPG window */
+#define MAC_IPG_IFG_IPGR2_MASK      	0x7f
+
+/* MAC STATION ADDRESS  */
+#define REG_MAC_STA_ADDR		0x1488
+
+/* Hash table for multicast address */
+#define REG_RX_HASH_TABLE		0x1490
+
+/* MAC Half-Duplex Control Register */
+#define REG_MAC_HALF_DUPLX_CTRL     	0x1498
+#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT  0      /* Collision Window */
+#define MAC_HALF_DUPLX_CTRL_LCOL_MASK   0x3ff
+#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12
+#define MAC_HALF_DUPLX_CTRL_RETRY_MASK  0xf
+#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN  0x10000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_C   0x20000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_P   0x40000 /* No back-off on backpressure,
+						 * immediately start the
+						 * transmission after back pressure */
+#define MAC_HALF_DUPLX_CTRL_ABEBE        0x80000 /* 1: Alternative Binary Exponential Back-off Enabled */
+#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT  20      /* Maximum binary exponential number */
+#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK   0xf
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24      /* IPG to start JAM for collision based flow control in half-duplex */
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK  0xf     /* mode. In unit of 8-bit time */
+
+/* Maximum Frame Length Control Register   */
+#define REG_MTU                     	0x149c
+
+/* 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
+
+/* 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
+
+/* Internal SRAM Partition Register */
+#define RFDX_HEAD_ADDR_MASK		0x03FF
+#define RFDX_HARD_ADDR_SHIFT		0
+#define RFDX_TAIL_ADDR_MASK		0x03FF
+#define RFDX_TAIL_ADDR_SHIFT            16
+
+#define REG_SRAM_RFD0_INFO		0x1500
+#define REG_SRAM_RFD1_INFO		0x1504
+#define REG_SRAM_RFD2_INFO		0x1508
+#define	REG_SRAM_RFD3_INFO		0x150C
+
+#define REG_RFD_NIC_LEN			0x1510 /* In 8-bytes */
+#define RFD_NIC_LEN_MASK		0x03FF
+
+#define REG_SRAM_TRD_ADDR           	0x1518
+#define TPD_HEAD_ADDR_MASK		0x03FF
+#define TPD_HEAD_ADDR_SHIFT		0
+#define TPD_TAIL_ADDR_MASK		0x03FF
+#define TPD_TAIL_ADDR_SHIFT		16
+
+#define REG_SRAM_TRD_LEN            	0x151C /* In 8-bytes */
+#define TPD_NIC_LEN_MASK		0x03FF
+
+#define REG_SRAM_RXF_ADDR          	0x1520
+#define REG_SRAM_RXF_LEN            	0x1524
+#define REG_SRAM_TXF_ADDR           	0x1528
+#define REG_SRAM_TXF_LEN            	0x152C
+#define REG_SRAM_TCPH_ADDR          	0x1530
+#define REG_SRAM_PKTH_ADDR          	0x1532
+
+/*
+ * Load Ptr Register
+ * Software sets this bit after the initialization of the head and tail */
+#define REG_LOAD_PTR                	0x1534
+
+/*
+ * addresses of all descriptors, as well as the following descriptor
+ * control register, which triggers each function block to load the head
+ * pointer to prepare for the operation. This bit is then self-cleared
+ * after one cycle.
+ */
+#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_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
+
+/* Jumbo packet Threshold for task offload */
+#define REG_TX_TSO_OFFLOAD_THRESH	0x1594 /* In 8-bytes */
+#define TX_TSO_OFFLOAD_THRESH_MASK	0x07FF
+
+#define	REG_TXF_WATER_MARK		0x1598 /* In 8-bytes */
+#define TXF_WATER_MARK_MASK		0x0FFF
+#define TXF_LOW_WATER_MARK_SHIFT	0
+#define TXF_HIGH_WATER_MARK_SHIFT 	16
+#define TXQ_CTRL_BURST_MODE_EN		0x80000000
+
+#define REG_THRUPUT_MON_CTRL		0x159C
+#define THRUPUT_MON_RATE_MASK		0x3
+#define THRUPUT_MON_RATE_SHIFT		0
+#define THRUPUT_MON_EN			0x80
+
+/* RXQ Control Register */
+#define REG_RXQ_CTRL                	0x15A0
+#define ASPM_THRUPUT_LIMIT_MASK		0x3
+#define ASPM_THRUPUT_LIMIT_SHIFT	0
+#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 RXQ_RFD_BURST_NUM_MASK		0x003F
+#define RXQ_RFD_BURST_NUM_SHIFT		20
+#define RSS_MODE_MASK			0x0003
+#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 REG_RFD_FREE_THRESH		0x15A4
+#define RFD_FREE_THRESH_MASK		0x003F
+#define RFD_FREE_HI_THRESH_SHIFT	0
+#define RFD_FREE_LO_THRESH_SHIFT	6
+
+/* RXF flow control register */
+#define REG_RXQ_RXF_PAUSE_THRESH    	0x15A8
+#define RXQ_RXF_PAUSE_TH_HI_SHIFT       0
+#define RXQ_RXF_PAUSE_TH_HI_MASK        0x0FFF
+#define RXQ_RXF_PAUSE_TH_LO_SHIFT       16
+#define RXQ_RXF_PAUSE_TH_LO_MASK        0x0FFF
+
+#define REG_RXD_DMA_CTRL		0x15AC
+#define RXD_DMA_THRESH_MASK		0x0FFF	/* In 8-bytes */
+#define RXD_DMA_THRESH_SHIFT		0
+#define RXD_DMA_DOWN_TIMER_MASK		0xFFFF
+#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_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
+
+/* 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_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
+#define ISR_SMB				0x00000001
+#define ISR_TIMER			0x00000002
+/*
+ * Software manual interrupt, for debug. Set when SW_MAN_INT_EN is set
+ * in Table 51 Selene Master Control Register (Offset 0x1400).
+ */
+#define ISR_MANUAL         		0x00000004
+#define ISR_HW_RXF_OV          		0x00000008 /* RXF overflow interrupt */
+#define ISR_RFD0_UR			0x00000010 /* RFD0 under run */
+#define ISR_RFD1_UR			0x00000020
+#define ISR_RFD2_UR			0x00000040
+#define ISR_RFD3_UR			0x00000080
+#define ISR_TXF_UR			0x00000100
+#define ISR_DMAR_TO_RST			0x00000200
+#define ISR_DMAW_TO_RST			0x00000400
+#define ISR_TX_CREDIT			0x00000800
+#define ISR_GPHY			0x00001000
+/* GPHY low power state interrupt */
+#define ISR_GPHY_LPW           		0x00002000
+#define ISR_TXQ_TO_RST			0x00004000
+#define ISR_TX_PKT			0x00008000
+#define ISR_RX_PKT_0			0x00010000
+#define ISR_RX_PKT_1			0x00020000
+#define ISR_RX_PKT_2			0x00040000
+#define ISR_RX_PKT_3			0x00080000
+#define ISR_MAC_RX			0x00100000
+#define ISR_MAC_TX			0x00200000
+#define ISR_UR_DETECTED			0x00400000
+#define ISR_FERR_DETECTED		0x00800000
+#define ISR_NFERR_DETECTED		0x01000000
+#define ISR_CERR_DETECTED		0x02000000
+#define ISR_PHY_LINKDOWN		0x04000000
+#define ISR_DIS_INT			0x80000000
+
+/* Interrupt Mask Register */
+#define REG_IMR				0x1604
+
+#define IMR_NORMAL_MASK		(\
+		ISR_MANUAL	|\
+		ISR_HW_RXF_OV	|\
+		ISR_RFD0_UR	|\
+		ISR_TXF_UR	|\
+		ISR_DMAR_TO_RST	|\
+		ISR_TXQ_TO_RST  |\
+		ISR_DMAW_TO_RST	|\
+		ISR_GPHY	|\
+		ISR_TX_PKT	|\
+		ISR_RX_PKT_0	|\
+		ISR_GPHY_LPW    |\
+		ISR_PHY_LINKDOWN)
+
+#define ISR_RX_PKT 	(\
+	ISR_RX_PKT_0    |\
+	ISR_RX_PKT_1    |\
+	ISR_RX_PKT_2    |\
+	ISR_RX_PKT_3)
+
+#define ISR_OVER	(\
+	ISR_RFD0_UR 	|\
+	ISR_RFD1_UR	|\
+	ISR_RFD2_UR	|\
+	ISR_RFD3_UR	|\
+	ISR_HW_RXF_OV	|\
+	ISR_TXF_UR)
+
+#define ISR_ERROR	(\
+	ISR_DMAR_TO_RST	|\
+	ISR_TXQ_TO_RST  |\
+	ISR_DMAW_TO_RST	|\
+	ISR_PHY_LINKDOWN)
+
+#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
+#define REG_MAC_TX_STATUS_END 		0x17c0
+
+/* DEBUG ADDR */
+#define REG_DEBUG_DATA0 		0x1900
+#define REG_DEBUG_DATA1 		0x1904
+
+/* PHY Control Register */
+#define MII_BMCR			0x00
+#define BMCR_SPEED_SELECT_MSB		0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define BMCR_COLL_TEST_ENABLE		0x0080  /* Collision test enable */
+#define BMCR_FULL_DUPLEX		0x0100  /* FDX =1, half duplex =0 */
+#define BMCR_RESTART_AUTO_NEG		0x0200  /* Restart auto negotiation */
+#define BMCR_ISOLATE			0x0400  /* Isolate PHY from MII */
+#define BMCR_POWER_DOWN			0x0800  /* Power down */
+#define BMCR_AUTO_NEG_EN		0x1000  /* Auto Neg Enable */
+#define BMCR_SPEED_SELECT_LSB		0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define BMCR_LOOPBACK			0x4000  /* 0 = normal, 1 = loopback */
+#define BMCR_RESET			0x8000  /* 0 = normal, 1 = PHY reset */
+#define BMCR_SPEED_MASK			0x2040
+#define BMCR_SPEED_1000			0x0040
+#define BMCR_SPEED_100			0x2000
+#define BMCR_SPEED_10			0x0000
+
+/* PHY Status Register */
+#define MII_BMSR			0x01
+#define BMMSR_EXTENDED_CAPS		0x0001  /* Extended register capabilities */
+#define BMSR_JABBER_DETECT		0x0002  /* Jabber Detected */
+#define BMSR_LINK_STATUS		0x0004  /* Link Status 1 = link */
+#define BMSR_AUTONEG_CAPS		0x0008  /* Auto Neg Capable */
+#define BMSR_REMOTE_FAULT		0x0010  /* Remote Fault Detect */
+#define BMSR_AUTONEG_COMPLETE		0x0020  /* Auto Neg Complete */
+#define BMSR_PREAMBLE_SUPPRESS		0x0040  /* Preamble may be suppressed */
+#define BMSR_EXTENDED_STATUS		0x0100  /* Ext. status info in Reg 0x0F */
+#define BMSR_100T2_HD_CAPS		0x0200  /* 100T2 Half Duplex Capable */
+#define BMSR_100T2_FD_CAPS		0x0400  /* 100T2 Full Duplex Capable */
+#define BMSR_10T_HD_CAPS		0x0800  /* 10T   Half Duplex Capable */
+#define BMSR_10T_FD_CAPS		0x1000  /* 10T   Full Duplex Capable */
+#define BMSR_100X_HD_CAPS		0x2000  /* 100X  Half Duplex Capable */
+#define BMMII_SR_100X_FD_CAPS		0x4000  /* 100X  Full Duplex Capable */
+#define BMMII_SR_100T4_CAPS		0x8000  /* 100T4 Capable */
+
+#define MII_PHYSID1			0x02
+#define MII_PHYSID2			0x03
+
+/* Autoneg Advertisement Register */
+#define MII_ADVERTISE			0x04
+#define ADVERTISE_SELECTOR_FIELD	0x0001  /* indicates IEEE 802.3 CSMA/CD */
+#define ADVERTISE_10T_HD_CAPS		0x0020  /* 10T   Half Duplex Capable */
+#define ADVERTISE_10T_FD_CAPS		0x0040  /* 10T   Full Duplex Capable */
+#define ADVERTISE_100TX_HD_CAPS		0x0080  /* 100TX Half Duplex Capable */
+#define ADVERTISE_100TX_FD_CAPS		0x0100  /* 100TX Full Duplex Capable */
+#define ADVERTISE_100T4_CAPS		0x0200  /* 100T4 Capable */
+#define ADVERTISE_PAUSE			0x0400  /* Pause operation desired */
+#define ADVERTISE_ASM_DIR		0x0800  /* Asymmetric Pause Direction bit */
+#define ADVERTISE_REMOTE_FAULT		0x2000  /* Remote Fault detected */
+#define ADVERTISE_NEXT_PAGE		0x8000  /* Next Page ability supported */
+#define ADVERTISE_SPEED_MASK		0x01E0
+#define ADVERTISE_DEFAULT_CAP		0x0DE0
+
+#if 0
+/* Link partner ability register */
+#define MII_LPA				0x05
+#define LPA_SLCT			0x001   /* Same as advertise selector  */
+#define LPA_10HALF			0x002   /* Can do 10mbps half-duplex   */
+#define LPA_10FULL			0x0040  /* Can do 10mbps full-duplex   */
+#define LPA_100HALF			0x0080  /* Can do 100mbps half-duplex  */
+#define LPA_100FULL			0x0100  /* Can do 100mbps full-duplex  */
+#define LPA_100BASE4			0x0200  /* 100BASE-T4  */
+#define LPA_PAUSE			0x0400  /* PAUSE */
+#define LPA_ASYPAUSE			0x0800  /* Asymmetrical PAUSE */
+#define LPA_RFAULT			0x2000  /* Link partner faulted        */
+#define LPA_LPACK			0x4000  /* Link partner acked us       */
+#define LPA_NPAGE			0x8000  /* Next page bit               */
+#endif
+/* 1000BASE-T Control Register */
+#define MII_GIGA_CR			0x09
+#define GIGA_CR_1000T_HD_CAPS		0x0100  /* Advertise 1000T HD capability */
+#define GIGA_CR_1000T_FD_CAPS		0x0200  /* Advertise 1000T FD capability  */
+#define GIGA_CR_1000T_REPEATER_DTE	0x0400  /* 1=Repeater/switch device port 0=DTE device */
+
+#define GIGA_CR_1000T_MS_VALUE		0x0800  /* 1=Configure PHY as Master 0=Configure PHY as Slave */
+#define GIGA_CR_1000T_MS_ENABLE		0x1000  /* 1=Master/Slave manual config value 0=Automatic Master/Slave config */
+#define GIGA_CR_1000T_TEST_MODE_NORMAL	0x0000  /* Normal Operation */
+#define GIGA_CR_1000T_TEST_MODE_1	0x2000  /* Transmit Waveform test */
+#define GIGA_CR_1000T_TEST_MODE_2	0x4000  /* Master Transmit Jitter test */
+#define GIGA_CR_1000T_TEST_MODE_3	0x6000  /* Slave Transmit Jitter test */
+#define GIGA_CR_1000T_TEST_MODE_4	0x8000	/* Transmitter Distortion test */
+#define GIGA_CR_1000T_SPEED_MASK	0x0300
+#define GIGA_CR_1000T_DEFAULT_CAP	0x0300
+
+/* PHY Specific Status Register */
+#define MII_GIGA_PSSR			0x11
+#define GIGA_PSSR_SPD_DPLX_RESOLVED	0x0800  /* 1=Speed & Duplex resolved */
+#define GIGA_PSSR_DPLX			0x2000  /* 1=Duplex 0=Half Duplex */
+#define GIGA_PSSR_SPEED			0xC000  /* Speed, bits 14:15 */
+#define GIGA_PSSR_10MBS			0x0000  /* 00=10Mbs */
+#define GIGA_PSSR_100MBS		0x4000  /* 01=100Mbs */
+#define GIGA_PSSR_1000MBS		0x8000  /* 10=1000Mbs */
+
+/* PHY Interrupt Enable Register */
+#define MII_IER				0x12
+#define IER_LINK_UP			0x0400
+#define IER_LINK_DOWN			0x0800
+
+/* PHY Interrupt Status Register */
+#define MII_ISR				0x13
+#define ISR_LINK_UP			0x0400
+#define ISR_LINK_DOWN			0x0800
+
+/* Cable-Detect-Test Control Register */
+#define MII_CDTC			0x16
+#define CDTC_EN_OFF			0   /* sc */
+#define CDTC_EN_BITS			1
+#define CDTC_PAIR_OFF			8
+#define CDTC_PAIR_BIT			2
+
+/* Cable-Detect-Test Status Register */
+#define MII_CDTS			0x1C
+#define CDTS_STATUS_OFF			8
+#define CDTS_STATUS_BITS		2
+#define CDTS_STATUS_NORMAL		0
+#define CDTS_STATUS_SHORT		1
+#define CDTS_STATUS_OPEN		2
+#define CDTS_STATUS_INVALID		3
+
+#define MII_DBG_ADDR			0x1D
+#define MII_DBG_DATA			0x1E
+
+#endif /*_ATL1C_HW_H_*/
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
new file mode 100644
index 0000000..5da217d
--- /dev/null
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -0,0 +1,2804 @@ 
+/*
+ * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "atl1c.h"
+
+#define DRV_VERSION "1.0.0.1-NAPI"
+char atl1c_driver_name[] = "ATL1C";
+char atl1c_driver_version[] = DRV_VERSION;
+#define PCI_DEVICE_ID_ATTANSIC_L2C      0x1062
+#define PCI_DEVICE_ID_ATTANSIC_L1C      0x1063
+/*
+ * atl1c_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ *   Class, Class Mask, private data (not used) }
+ */
+static struct pci_device_id atl1c_pci_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)},
+	/* required last entry */
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, atl1c_pci_tbl);
+
+MODULE_AUTHOR("Jie Yang <jie.yang@atheros.com>");
+MODULE_DESCRIPTION("Atheros 1000M Ethernet Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(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,
+		   int *work_done, int work_to_do);
+
+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
+};
+
+/*
+ * atl1c_init_pcie - init PCIE module
+ */
+static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag)
+{
+	u32 data;
+	u32 pci_cmd;
+
+	AT_READ_REG(hw, PCI_COMMAND, &pci_cmd);
+	pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
+	pci_cmd |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+		PCI_COMMAND_IO);
+	AT_WRITE_REG(hw, PCI_COMMAND, pci_cmd);
+
+	/*
+	 * Clear any PowerSaveing Settings
+	 */
+	AT_WRITE_REG(hw, REG_PM_CTRLSTAT, 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);
+
+	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(1);
+}
+
+/*
+ * atl1c_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ */
+static inline void atl1c_irq_enable(struct atl1c_adapter *adapter)
+{
+	if (likely(atomic_dec_and_test(&adapter->irq_sem))) {
+		AT_WRITE_REG(&adapter->hw, REG_ISR, 0x7FFFFFFF);
+		AT_WRITE_REG(&adapter->hw, REG_IMR, adapter->hw.intr_mask);
+		AT_WRITE_FLUSH(&adapter->hw);
+	}
+}
+
+/*
+ * atl1c_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ */
+static inline void atl1c_irq_disable(struct atl1c_adapter *adapter)
+{
+	atomic_inc(&adapter->irq_sem);
+	AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
+	AT_WRITE_FLUSH(&adapter->hw);
+	synchronize_irq(adapter->pdev->irq);
+}
+
+/*
+ * atl1c_irq_reset - reset interrupt confiure on the NIC
+ * @adapter: board private structure
+ */
+static inline void atl1c_irq_reset(struct atl1c_adapter *adapter)
+{
+	atomic_set(&adapter->irq_sem, 1);
+	atl1c_irq_enable(adapter);
+}
+
+/*
+ * atl1c_phy_config - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1c_phy_config(unsigned long data)
+{
+	struct atl1c_adapter *adapter = (struct atl1c_adapter *) data;
+	struct atl1c_hw *hw = &adapter->hw;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->mdio_lock, flags);
+	atl1c_restart_autoneg(hw);
+	spin_unlock_irqrestore(&adapter->mdio_lock, flags);
+}
+
+void atl1c_reinit_locked(struct atl1c_adapter *adapter)
+{
+
+	WARN_ON(in_interrupt());
+	atl1c_down(adapter);
+	atl1c_up(adapter);
+	clear_bit(__AT_RESETTING, &adapter->flags);
+}
+
+static void atl1c_reset_task(struct work_struct *work)
+{
+	struct atl1c_adapter *adapter;
+	u32 isr_data;
+
+	adapter = container_of(work, struct atl1c_adapter, reset_task);
+
+	if (netif_queue_stopped(adapter->netdev) &&
+			netif_carrier_ok(adapter->netdev)) {
+		AT_READ_REG(&adapter->hw, REG_ISR, &isr_data);
+		printk(KERN_EMERG "TX STOPED!\n");
+		printk(KERN_EMERG "reset hardware!\n");
+		printk(KERN_EMERG "ISR is %x\n", isr_data);
+		netif_wake_queue(adapter->netdev);
+	}
+}
+
+static void atl1c_check_link_status(struct atl1c_adapter *adapter)
+{
+	struct atl1c_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev    *pdev   = adapter->pdev;
+	int err = 0;
+	unsigned long flags;
+	u16 speed, duplex, phy_data;
+
+	spin_lock_irqsave(&adapter->mdio_lock, flags);
+	/* MII_BMSR must read twise */
+	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+	spin_unlock_irqrestore(&adapter->mdio_lock, flags);
+
+	if ((phy_data & BMSR_LSTATUS) == 0) {
+		/* link down */
+		if (netif_carrier_ok(netdev)) {
+			hw->hibernate = true;
+			atl1c_set_aspm(hw, false);
+			if (atl1c_stop_mac(hw) != 0)
+				dev_info(&pdev->dev, "stop mac failed\n");
+		}
+		netif_carrier_off(netdev);
+		netif_stop_queue(netdev);
+	} else {
+		/* Link Up */
+		hw->hibernate = false;
+		spin_lock_irqsave(&adapter->mdio_lock, flags);
+		err = atl1c_get_speed_and_duplex(hw, &speed, &duplex);
+		spin_unlock_irqrestore(&adapter->mdio_lock, flags);
+		if (unlikely(err))
+			return;
+		/* link result is our setting */
+		if (adapter->link_speed != speed ||
+		    adapter->link_duplex != duplex) {
+			adapter->link_speed  = speed;
+			adapter->link_duplex = duplex;
+			atl1c_enable_tx_ctrl(hw);
+			atl1c_enable_rx_ctrl(hw);
+			atl1c_setup_mac_ctrl(adapter);
+			atl1c_set_aspm(hw, true);
+			dev_info(&pdev->dev,
+				"%s: %s NIC Link is Up<%d Mbps %s>\n",
+				atl1c_driver_name, netdev->name,
+				adapter->link_speed,
+				adapter->link_duplex == FULL_DUPLEX ?
+				"Full Duplex" : "Half Duplex");
+		}
+		if (!netif_carrier_ok(netdev)) {
+			netif_carrier_on(netdev);
+			netif_wake_queue(netdev);
+		}
+	}
+}
+
+/*
+ * atl1c_link_chg_task - deal with link change event Out of interrupt context
+ * @netdev: network interface device structure
+ */
+static void atl1c_link_chg_task(struct work_struct *work)
+{
+	struct atl1c_adapter *adapter;
+
+	adapter = container_of(work, struct atl1c_adapter, link_chg_task);
+	atl1c_check_link_status(adapter);
+}
+
+static void atl1c_link_chg_event(struct atl1c_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev    *pdev   = adapter->pdev;
+	u16 phy_data = 0;
+	u16 link_up = 0;
+
+	spin_lock(&adapter->mdio_lock);
+	atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+	atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+	spin_unlock(&adapter->mdio_lock);
+	link_up = phy_data & BMSR_LSTATUS;
+	/* notify upper layer link down ASAP */
+	if (!link_up) {
+		if (netif_carrier_ok(netdev)) {
+			/* old link state: Up */
+			netif_carrier_off(netdev);
+			netif_stop_queue(netdev);
+			dev_info(&pdev->dev, "%s: %s NIC Link is Down\n",
+					atl1c_driver_name, netdev->name);
+			adapter->link_speed = SPEED_0;
+		}
+	}
+	schedule_work(&adapter->link_chg_task);
+}
+
+static void atl1c_del_timer(struct atl1c_adapter *adapter)
+{
+	del_timer_sync(&adapter->phy_config_timer);
+}
+
+static void atl1c_cancel_work(struct atl1c_adapter *adapter)
+{
+	cancel_work_sync(&adapter->reset_task);
+	cancel_work_sync(&adapter->link_chg_task);
+}
+
+/*
+ * atl1c_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ */
+static void atl1c_tx_timeout(struct net_device *netdev)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	/* Do the reset outside of interrupt context */
+	schedule_work(&adapter->reset_task);
+}
+
+/*
+ * atl1c_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ */
+static void atl1c_set_multi(struct net_device *netdev)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct atl1c_hw *hw = &adapter->hw;
+	struct dev_mc_list *mc_ptr;
+	u32 mac_ctrl_data = 0;
+	u32 hash_value;
+
+	/* Check for Promiscuous and All Multicast modes */
+	AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl_data);
+
+	if (netdev->flags & IFF_PROMISC) {
+		mac_ctrl_data |= MAC_CTRL_PROMIS_EN;
+	} else if (netdev->flags & IFF_ALLMULTI) {
+		mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
+		mac_ctrl_data &= ~MAC_CTRL_PROMIS_EN;
+	} else {
+		mac_ctrl_data &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
+	}
+
+	AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
+
+	/* clear the old settings from the multicast hash table */
+	AT_WRITE_REG(hw, REG_RX_HASH_TABLE, 0);
+	AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
+
+	/* comoute mc addresses' hash value ,and put it into hash table */
+	for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+		hash_value = atl1c_hash_mc_addr(hw, mc_ptr->dmi_addr);
+		atl1c_hash_set(hw, hash_value);
+	}
+}
+
+static void atl1c_vlan_rx_register(struct net_device *netdev,
+				   struct vlan_group *grp)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct pci_dev *pdev = adapter->pdev;
+	u32 mac_ctrl_data = 0;
+
+	dev_dbg(&pdev->dev, "atl1c_vlan_rx_register\n");
+
+	atl1c_irq_disable(adapter);
+
+	adapter->vlgrp = grp;
+	AT_READ_REG(&adapter->hw, REG_MAC_CTRL, &mac_ctrl_data);
+
+	if (grp) {
+		/* enable VLAN tag insert/strip */
+		mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
+	} else {
+		/* disable VLAN tag insert/strip */
+		mac_ctrl_data &= ~MAC_CTRL_RMV_VLAN;
+	}
+
+	AT_WRITE_REG(&adapter->hw, REG_MAC_CTRL, mac_ctrl_data);
+	atl1c_irq_enable(adapter);
+}
+
+static void atl1c_restore_vlan(struct atl1c_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	dev_dbg(&pdev->dev, "atl1c_restore_vlan !");
+	atl1c_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+}
+/*
+ * atl1c_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	if (netif_running(netdev))
+		return -EBUSY;
+
+	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);
+
+	return 0;
+}
+
+static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
+				struct net_device *dev)
+{
+	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;
+}
+/*
+ * atl1c_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1c_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	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)) {
+		dev_warn(&adapter->pdev->dev, "invalid MTU setting\n");
+		return -EINVAL;
+	}
+	/* set MTU */
+	if (old_mtu != new_mtu && netif_running(netdev)) {
+		while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
+			msleep(1);
+		netdev->mtu = new_mtu;
+		adapter->hw.max_frame_size = new_mtu;
+		atl1c_set_rxbufsize(adapter, netdev);
+		atl1c_down(adapter);
+		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;
+}
+
+/*
+ *  caller should hold mdio_lock
+ */
+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);
+	return result;
+}
+
+static void atl1c_mdio_write(struct net_device *netdev, int phy_id,
+			     int reg_num, int val)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	atl1c_write_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, val);
+}
+
+/*
+ * atl1c_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1c_mii_ioctl(struct net_device *netdev,
+			   struct ifreq *ifr, int cmd)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct pci_dev *pdev = adapter->pdev;
+	struct mii_ioctl_data *data = if_mii(ifr);
+	unsigned long flags;
+	int retval = 0;
+
+	if (!netif_running(netdev))
+		return -EINVAL;
+
+	spin_lock_irqsave(&adapter->mdio_lock, flags);
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = 0;
+		break;
+
+	case SIOCGMIIREG:
+		if (!capable(CAP_NET_ADMIN)) {
+			retval = -EPERM;
+			goto out;
+		}
+		if (atl1c_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+				    &data->val_out)) {
+			retval = -EIO;
+			goto out;
+		}
+		break;
+
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN)) {
+			retval = -EPERM;
+			goto out;
+		}
+		if (data->reg_num & ~(0x1F)) {
+			retval = -EFAULT;
+			goto out;
+		}
+
+		dev_dbg(&pdev->dev, "<atl1c_mii_ioctl> write %x %x",
+				data->reg_num, data->val_in);
+		if (atl1c_write_phy_reg(&adapter->hw,
+				     data->reg_num, data->val_in)) {
+			retval = -EIO;
+			goto out;
+		}
+		break;
+
+	default:
+		retval = -EOPNOTSUPP;
+		break;
+	}
+out:
+	spin_unlock_irqrestore(&adapter->mdio_lock, flags);
+	return retval;
+
+}
+
+/*
+ * atl1c_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1c_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	switch (cmd) {
+	case SIOCGMIIPHY:
+	case SIOCGMIIREG:
+	case SIOCSMIIREG:
+		return atl1c_mii_ioctl(netdev, ifr, cmd);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/*
+ * atl1c_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ */
+static int __devinit atl1c_alloc_queues(struct atl1c_adapter *adapter)
+{
+	return 0;
+}
+
+static void atl1c_set_mac_type(struct atl1c_hw *hw)
+{
+	switch (hw->device_id) {
+	case PCI_DEVICE_ID_ATTANSIC_L2C:
+		hw->nic_type = athr_l2c;
+		break;
+
+	case PCI_DEVICE_ID_ATTANSIC_L1C:
+		hw->nic_type = athr_l1c;
+		break;
+
+	default:
+		break;
+	}
+
+	return;
+}
+
+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_CLEAR_ON_READ |
+			 ATL1C_INTR_MODRT_ENABLE  |
+			 ATL1C_RX_IPV6_CHKSUM	  |
+			 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 (hw->nic_type == athr_l1c) {
+		hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
+		hw->ctrl_flags |= ATL1C_LINK_CAP_1000M;
+	}
+	return 0;
+}
+/*
+ * atl1c_sw_init - Initialize general software structures (struct atl1c_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * atl1c_sw_init initializes the Adapter private data structure.
+ * 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)
+{
+	struct atl1c_hw *hw   = &adapter->hw;
+	struct pci_dev	*pdev = adapter->pdev;
+
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+	hw->subsystem_vendor_id = pdev->subsystem_vendor;
+	hw->subsystem_id = pdev->subsystem_device;
+
+	/* before link up, we assume hibernate is true */
+	hw->hibernate = true;
+	if (atl1c_setup_mac_funcs(hw) != 0) {
+		dev_err(&pdev->dev, "set mac function pointers failed\n");
+		return -1;
+	}
+	adapter->wol = 0;
+	adapter->link_speed = SPEED_0;
+	adapter->link_duplex = FULL_DUPLEX;
+	adapter->num_rx_queues = AT_DEF_RECEIVE_QUEUE;
+
+	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 = ADVERTISE_DEFAULT;
+	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->tpd_burst = 5;
+	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");
+		return -ENOMEM;
+	}
+	/* TODO */
+	atl1c_set_rxbufsize(adapter, adapter->netdev);
+	atomic_set(&adapter->irq_sem, 1);
+	spin_lock_init(&adapter->mdio_lock);
+	spin_lock_init(&adapter->tx_lock);
+	set_bit(__AT_DOWN, &adapter->flags);
+
+	return 0;
+}
+
+/*
+ * atl1c_clean_tx_ring - Free Tx-skb
+ * @adapter: board private structure
+ */
+static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter,
+				enum atl1c_trans_queue type)
+{
+	struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
+	struct atl1c_buffer *buffer_info;
+	struct pci_dev *pdev = adapter->pdev;
+	u16 index, ring_count;
+
+	ring_count = tpd_ring->count;
+	for (index = 0; index < ring_count; index++) {
+		buffer_info = &tpd_ring->buffer_info[index];
+		if (buffer_info->state == ATL1_BUFFER_FREE)
+			continue;
+		if (buffer_info->dma)
+			pci_unmap_single(pdev, buffer_info->dma,
+					buffer_info->length,
+					PCI_DMA_TODEVICE);
+		if (buffer_info->skb)
+			dev_kfree_skb(buffer_info->skb);
+		buffer_info->dma = 0;
+		buffer_info->skb = NULL;
+		buffer_info->state = ATL1_BUFFER_FREE;
+	}
+
+	/* Zero out Tx-buffers */
+	memset(tpd_ring->desc, 0, sizeof(struct atl1c_tpd_desc) *
+				ring_count);
+	atomic_set(&tpd_ring->next_to_clean, 0);
+	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_buffer *buffer_info;
+	struct pci_dev *pdev = adapter->pdev;
+	int i, 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];
+			if (buffer_info->state == ATL1_BUFFER_FREE)
+				continue;
+			if (buffer_info->dma)
+				pci_unmap_single(pdev, buffer_info->dma,
+						buffer_info->length,
+						PCI_DMA_FROMDEVICE);
+			if (buffer_info->skb)
+				dev_kfree_skb(buffer_info->skb);
+			buffer_info->state = ATL1_BUFFER_FREE;
+			buffer_info->skb = NULL;
+		}
+		/* 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;
+	}
+}
+
+/*
+ * Read / Write Ptr Initialize:
+ */
+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_buffer *buffer_info;
+	int i, j;
+
+	for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
+		tpd_ring[i].next_to_use = 0;
+		atomic_set(&tpd_ring[i].next_to_clean, 0);
+		buffer_info = tpd_ring[i].buffer_info;
+		for (j = 0; j < tpd_ring->count; j++)
+			buffer_info[i].state = ATL1_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];
+			buffer_info->state = ATL1_BUFFER_FREE;
+		}
+	}
+}
+
+/*
+ * atl1c_free_ring_resources - Free Tx / RX descriptor Resources
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	pci_free_consistent(pdev, adapter->ring_header.size,
+					adapter->ring_header.desc,
+					adapter->ring_header.dma);
+	adapter->ring_header.desc = NULL;
+
+	/* Note: just free tdp_ring.buffer_info,
+	*  it contain rfd_ring.buffer_info, do not double free */
+	if (adapter->tpd_ring[0].buffer_info) {
+		kfree(adapter->tpd_ring[0].buffer_info);
+		adapter->tpd_ring[0].buffer_info = NULL;
+	}
+}
+
+/*
+ * atl1c_setup_mem_resources - allocate Tx / RX descriptor resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+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_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;
+	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);
+	tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
+	if (unlikely(!tpd_ring->buffer_info)) {
+		dev_err(&pdev->dev, "kzalloc failed, size = %d\n",
+			size);
+		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);
+		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;
+	}
+	/*
+	 * real ring DMA buffer
+	 * each ring/block may need up to 8 bytes for alignment, hence the
+	 * additional bytes tacked onto the end.
+	 */
+	ring_header->size = size =
+		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;
+
+	ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
+				&ring_header->dma);
+	if (unlikely(!ring_header->desc)) {
+		dev_err(&pdev->dev, "pci_alloc_consistend failed\n");
+		goto err_nomem;
+	}
+	memset(ring_header->desc, 0, ring_header->size);
+	/* init TPD ring */
+
+	tpd_ring[0].dma = roundup(ring_header->dma, 8);
+	offset = tpd_ring[0].dma - ring_header->dma;
+	for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
+		tpd_ring[i].dma = ring_header->dma + offset;
+		tpd_ring[i].desc = (u8 *) ring_header->desc + offset;
+		tpd_ring[i].size =
+			sizeof(struct atl1c_tpd_desc) * tpd_ring[i].count;
+		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);
+	}
+
+	/* 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);
+	}
+
+	adapter->smb.dma = ring_header->dma + offset;
+	adapter->smb.smb = (u8 *)ring_header->desc + offset;
+	return 0;
+
+err_nomem:
+	kfree(tpd_ring->buffer_info);
+	return -ENOMEM;
+}
+
+static void atl1c_configure_des_ring(const struct atl1c_adapter *adapter)
+{
+	struct atl1c_hw *hw = (struct atl1c_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_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;
+
+	/* 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,
+			(u32)(tpd_ring[atl1c_trans_normal].dma &
+				AT_DMA_LO_ADDR_MASK));
+	AT_WRITE_REG(hw, REG_HTPD_HEAD_ADDR_LO,
+			(u32)(tpd_ring[atl1c_trans_high].dma &
+				AT_DMA_LO_ADDR_MASK));
+	AT_WRITE_REG(hw, REG_TPD_RING_SIZE,
+			(u32)(tpd_ring[0].count & TPD_RING_SIZE_MASK));
+
+
+	/* 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));
+
+	AT_WRITE_REG(hw, REG_RFD_RING_SIZE,
+			rfd_ring[0].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_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);
+
+	/* 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));
+	/* Load all of base address above */
+	AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
+
+	return;
+}
+
+static void atl1c_configure_tx(struct atl1c_adapter *adapter)
+{
+	struct atl1c_hw *hw = (struct atl1c_hw *)&adapter->hw;
+	u32 dev_ctrl_data;
+	u32 max_pay_load;
+	u16 tx_offload_thresh;
+	u32 txq_ctrl_data;
+	u32 extra_size = 0;     /* Jumbo frame threshold in QWORD unit */
+
+	extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
+	tx_offload_thresh = MAX_TX_OFFLOAD_THRESH;
+	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(max_pay_load, hw->dmaw_block);
+	max_pay_load  = (dev_ctrl_data >> DEVICE_CTRL_MAX_RREQ_SZ_SHIFT) &
+			DEVICE_CTRL_MAX_RREQ_SZ_MASK;
+	hw->dmar_block = min(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;
+	txq_ctrl_data |= (atl1c_pay_load_size[hw->dmar_block] &
+			TXQ_TXF_BURST_NUM_MASK) << TXQ_TXF_BURST_NUM_SHIFT;
+
+	AT_WRITE_REG(hw, REG_TXQ_CTRL, txq_ctrl_data);
+	return;
+}
+
+static void atl1c_configure_rx(struct atl1c_adapter *adapter)
+{
+	struct atl1c_hw *hw = (struct atl1c_hw *)&adapter->hw;
+	u32 rxq_ctrl_data;
+
+	rxq_ctrl_data = (hw->rfd_burst & RXQ_RFD_BURST_NUM_MASK) <<
+			RXQ_RFD_BURST_NUM_SHIFT;
+
+	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_100M &
+			ASPM_THRUPUT_LIMIT_MASK) << ASPM_THRUPUT_LIMIT_SHIFT;
+
+	AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data);
+
+	return;
+}
+
+static void atl1c_configure_rss(struct atl1c_adapter *adapter)
+{
+	struct atl1c_hw *hw = (struct atl1c_hw *)&adapter->hw;
+
+	AT_WRITE_REG(hw, REG_IDT_TABLE, hw->indirect_tab);
+	AT_WRITE_REG(hw, REG_BASE_CPU_NUMBER, hw->base_cpu);
+
+	return;
+}
+
+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;
+
+	AT_WRITE_REG(hw, REG_DMA_CTRL, dma_ctrl_data);
+	return;
+}
+
+/*
+ * Stop the mac, transmit and receive units
+ * hw - Struct containing variables accessed by shared code
+ * return : 0  or  idle status (if error)
+ */
+static int atl1c_stop_mac(struct atl1c_hw *hw)
+{
+	u32 data;
+	int timeout;
+
+	AT_READ_REG(hw, REG_RXQ_CTRL, &data);
+	data &= ~(RXQ1_CTRL_EN | RXQ2_CTRL_EN |
+		  RXQ3_CTRL_EN | 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);
+
+	for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
+		AT_READ_REG(hw, REG_IDLE_STATUS, &data);
+		if ((data & (IDLE_STATUS_RXQ_NO_IDLE |
+			IDLE_STATUS_TXQ_NO_IDLE)) == 0)
+			break;
+		msleep(1);
+	}
+
+	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);
+
+	for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
+		AT_READ_REG(hw, REG_IDLE_STATUS, &data);
+		if ((data & IDLE_STATUS_MASK) == 0)
+			return 0;
+		msleep(1);
+	}
+	return data;
+}
+
+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);
+}
+
+static void atl1c_enable_tx_ctrl(struct atl1c_hw *hw)
+{
+	u32 data;
+
+	AT_READ_REG(hw, REG_TXQ_CTRL, &data);
+	data |= TXQ_CTRL_EN;
+	AT_WRITE_REG(hw, REG_TXQ_CTRL, data);
+}
+
+/*
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ * hw - Struct containing variables accessed by shared code
+ * return : 0  or  idle status (if error)
+ */
+static int atl1c_reset_mac(struct atl1c_hw *hw)
+{
+	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+	struct pci_dev *pdev = adapter->pdev;
+	u32 idle_status_data = 0;
+	int timeout = 0;
+	int ret;
+
+	AT_WRITE_REG(hw, REG_IMR, 0);
+	AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT);
+
+	ret = atl1c_stop_mac(hw);
+	if (ret)
+		return ret;
+	/*
+	 * Issue Soft Reset to the MAC.  This will reset the chip's
+	 * transmit, receive, DMA.  It will not effect
+	 * the current PCI configuration.  The global reset bit is self-
+	 * clearing, and should clear within a microsecond.
+	 */
+	AT_WRITE_REGW(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST);
+	msleep(10);
+	wmb();
+	/* Wait at least 10ms for All module to be Idle */
+	for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
+		AT_READ_REG(hw, REG_IDLE_STATUS, &idle_status_data);
+		if ((idle_status_data & IDLE_STATUS_MASK) == 0)
+			break;
+		msleep(1);
+	}
+	if (timeout >= AT_HW_MAX_IDLE_DELAY) {
+		dev_err(&pdev->dev,
+			"MAC state machine cann't be idle since"
+			" disabled for 10ms second\n");
+		return AT_ERR_TIMEOUT;
+	}
+	return 0;
+}
+
+static void atl1c_disable_l0s_l1(struct atl1c_hw *hw)
+{
+	u32 pm_ctrl_data;
+
+	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);
+}
+
+/*
+ * Set ASPM state.
+ * Enable/disable L0s/L1 depend on link state.
+ */
+static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
+{
+	u32 pm_ctrl_data;
+
+	AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
+
+	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_L1_EN;
+	pm_ctrl_data &=  ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+			PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+
+	pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
+
+	if (linkup) {
+		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 |= AT_ASPM_L1_TIMER <<
+				PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+			pm_ctrl_data |= PM_CTRL_ASPM_L1_EN;
+		} else
+			pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+
+		if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
+			pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
+		else
+			pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+
+	} else {
+		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);
+
+	if (adapter->vlgrp)
+		mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
+
+	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;
+	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)
+{
+	struct atl1c_hw *hw = &adapter->hw;
+	u32 master_ctrl_data = 0;
+	u32 intr_modrt_data;
+
+	/* clear interrupt status */
+	AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF);
+	/*  Clear any WOL status */
+	AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+	/* set Interrupt Clear Timer
+	 * HW will enable self to assert interrupt event to system after
+	 * waiting x-time for software to notify it accept interrupt.
+	 */
+	AT_WRITE_REG(hw, REG_INT_RETRIG_TIMER,
+		hw->ict & INT_RETRIG_TIMER_MASK);
+
+	atl1c_configure_des_ring(adapter);
+
+	if (hw->ctrl_flags & ATL1C_INTR_MODRT_ENABLE) {
+		intr_modrt_data = (hw->tx_imt & IRQ_MODRT_TIMER_MASK) <<
+					IRQ_MODRT_TX_TIMER_SHIFT;
+		intr_modrt_data |= (hw->rx_imt & IRQ_MODRT_TIMER_MASK) <<
+					IRQ_MODRT_RX_TIMER_SHIFT;
+		AT_WRITE_REG(hw, REG_IRQ_MODRT_TIMER_INIT, intr_modrt_data);
+		master_ctrl_data |=
+			MASTER_CTRL_TX_ITIMER_EN | MASTER_CTRL_RX_ITIMER_EN;
+	}
+
+	if (hw->ctrl_flags & ATL1C_INTR_CLEAR_ON_READ)
+		master_ctrl_data |= MASTER_CTRL_INT_RDCLR;
+
+	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);
+	}
+
+	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 void atl1c_update_hw_stats(struct atl1c_adapter *adapter)
+{
+	u16 hw_reg_addr = 0;
+	unsigned long *stats_item = NULL;
+	u32 data;
+
+	/* update rx status */
+	hw_reg_addr = REG_MAC_RX_STATUS_BIN;
+	stats_item  = &adapter->hw_stats.rx_ok;
+	while (hw_reg_addr <= REG_MAC_RX_STATUS_END) {
+		AT_READ_REG(&adapter->hw, hw_reg_addr, &data);
+		*stats_item += data;
+		stats_item++;
+		hw_reg_addr += 4;
+	}
+/* update tx status */
+	hw_reg_addr = REG_MAC_TX_STATUS_BIN;
+	stats_item  = &adapter->hw_stats.tx_ok;
+	while (hw_reg_addr <= REG_MAC_TX_STATUS_END) {
+		AT_READ_REG(&adapter->hw, hw_reg_addr, &data);
+		*stats_item += data;
+		stats_item++;
+		hw_reg_addr += 4;
+	}
+}
+
+/*
+ * atl1c_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ */
+static struct net_device_stats *atl1c_get_stats(struct net_device *netdev)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct atl1c_hw_stats  *hw_stats = &adapter->hw_stats;
+	struct net_device_stats *net_stats = &adapter->net_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;
+	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_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_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;
+
+	return &adapter->net_stats;
+}
+
+static inline void atl1c_clear_phy_int(struct atl1c_adapter *adapter)
+{
+	u16 phy_data;
+
+	spin_lock(&adapter->mdio_lock);
+	atl1c_read_phy_reg(&adapter->hw, MII_ISR, &phy_data);
+	spin_unlock(&adapter->mdio_lock);
+}
+
+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_buffer *buffer_info;
+	u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+	u16 hw_next_to_clean;
+	u16 shift;
+	u32 data;
+
+	if (type == atl1c_trans_high)
+		shift = MB_HTPD_CONS_IDX_SHIFT;
+	else
+		shift = MB_NTPD_CONS_IDX_SHIFT;
+
+	AT_READ_REG(&adapter->hw, REG_MB_PRIO_CONS_IDX, &data);
+	hw_next_to_clean = (data >> shift) & MB_PRIO_PROD_IDX_MASK;
+
+	while (next_to_clean != hw_next_to_clean) {
+		buffer_info = &tpd_ring->buffer_info[next_to_clean];
+		if (buffer_info->state == ATL1_BUFFER_BUSY) {
+			pci_unmap_page(adapter->pdev, buffer_info->dma,
+					buffer_info->length, PCI_DMA_TODEVICE);
+			buffer_info->dma = 0;
+			if (buffer_info->skb) {
+				dev_kfree_skb_irq(buffer_info->skb);
+				buffer_info->skb = NULL;
+			}
+			buffer_info->state = ATL1_BUFFER_FREE;
+		}
+		if (++next_to_clean == tpd_ring->count)
+			next_to_clean = 0;
+		atomic_set(&tpd_ring->next_to_clean, next_to_clean);
+	}
+
+	if (netif_queue_stopped(adapter->netdev) &&
+			netif_carrier_ok(adapter->netdev)) {
+		netif_wake_queue(adapter->netdev);
+	}
+
+	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)
+{
+	struct net_device *netdev  = data;
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct pci_dev *pdev = adapter->pdev;
+	struct atl1c_hw *hw = &adapter->hw;
+	int max_ints = AT_MAX_INT_WORK;
+	int handled = IRQ_NONE;
+	u32 status;
+	u32 reg_data;
+
+	do {
+		AT_READ_REG(hw, REG_ISR, &reg_data);
+		status = reg_data & hw->intr_mask;
+
+		if (status == 0 || (status & ISR_DIS_INT) != 0) {
+			if (max_ints != AT_MAX_INT_WORK)
+				handled = IRQ_HANDLED;
+			break;
+		}
+		/* link event */
+		if (status & ISR_GPHY)
+			atl1c_clear_phy_int(adapter);
+		/* Ack ISR */
+		AT_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT);
+		if (status & ISR_RX_PKT) {
+			if (likely(napi_schedule_prep(&adapter->napi))) {
+				hw->intr_mask &= ~ISR_RX_PKT;
+				AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
+				__napi_schedule(&adapter->napi);
+			}
+		}
+		if (status & ISR_TX_PKT)
+			atl1c_clean_tx_irq(adapter, atl1c_trans_normal);
+
+		handled = IRQ_HANDLED;
+		/* check if PCIE PHY Link down */
+		if (status & ISR_ERROR) {
+			dev_err(&pdev->dev,
+				"atl1c hardware error (status = 0x%x)\n",
+				status & ISR_ERROR);
+			/* reset MAC */
+			hw->intr_mask &= ~ISR_ERROR;
+			AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
+			schedule_work(&adapter->reset_task);
+			break;
+		}
+
+		if (status & ISR_OVER)
+			dev_err(&pdev->dev,
+				"TX/RX over flow (status = 0x%x)\n",
+				status & ISR_OVER);
+
+		/* link event */
+		if (status & (ISR_GPHY | ISR_MANUAL)) {
+			adapter->net_stats.tx_carrier_errors++;
+			atl1c_link_chg_event(adapter);
+			break;
+		}
+
+	} while (--max_ints > 0);
+	/* re-enable Interrupt*/
+	AT_WRITE_REG(&adapter->hw, REG_ISR, 0);
+	return handled;
+}
+
+static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
+		  struct sk_buff *skb, struct atl1c_recv_ret_status *prrs)
+{
+	/*
+	 * The pid field in RRS in not correct sometimes, so we
+	 * cannot figure out if the packet is fragmented or not,
+	 * so we tell the KERNEL CHECKSUM_NONE
+	 */
+	skb->ip_summed = CHECKSUM_NONE;
+
+	return;
+}
+
+static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid)
+{
+	struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring[ringid];
+	struct pci_dev *pdev = adapter->pdev;
+	struct atl1c_buffer *buffer_info, *next_info;
+	struct sk_buff *skb;
+	void *vir_addr = NULL;
+	u16 num_alloc = 0;
+	u16 rfd_next_to_use, next_next;
+	struct atl1c_rx_free_desc *rfd_desc;
+
+	next_next = rfd_next_to_use = rfd_ring->next_to_use;
+	if (++next_next == rfd_ring->count)
+		next_next = 0;
+	buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+	next_info = &rfd_ring->buffer_info[next_next];
+
+	while (next_info->state == ATL1_BUFFER_FREE) {
+		rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
+
+		skb = dev_alloc_skb(adapter->rx_buffer_len);
+		if (unlikely(!skb)) {
+			dev_dbg(&pdev->dev, "alloc rx buffer failed\n");
+			break;
+		}
+
+		/*
+		 * Make buffer alignment 2 beyond a 16 byte boundary
+		 * this will result in a 16 byte aligned IP header after
+		 * the 14 byte MAC header is removed
+		 */
+		vir_addr = skb->data;
+		buffer_info->state = ATL1_BUFFER_BUSY;
+		buffer_info->skb = skb;
+		buffer_info->length = adapter->rx_buffer_len;
+		buffer_info->dma = pci_map_single(pdev, vir_addr,
+						buffer_info->length,
+						PCI_DMA_FROMDEVICE);
+		rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+		rfd_next_to_use = next_next;
+		if (++next_next == rfd_ring->count)
+			next_next = 0;
+		buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+		next_info = &rfd_ring->buffer_info[next_next];
+		num_alloc++;
+	}
+
+	if (num_alloc) {
+		/* 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],
+			rfd_ring->next_to_use & MB_RFDX_PROD_IDX_MASK);
+	}
+
+	return num_alloc;
+}
+
+static void atl1c_clean_rrd(struct atl1c_rrd_ring *rrd_ring,
+			struct	atl1c_recv_ret_status *rrs, u16 num)
+{
+	u16 i;
+	/* the relationship between rrd and rfd is one map one */
+	for (i = 0; i < num; i++, rrs = ATL1C_RRD_DESC(rrd_ring,
+					rrd_ring->next_to_clean)) {
+		rrs->word3 &= ~RRS_RXD_UPDATED;
+		if (++rrd_ring->next_to_clean == rrd_ring->count)
+			rrd_ring->next_to_clean = 0;
+	}
+	return;
+}
+
+static void atl1c_clean_rfd(struct atl1c_rfd_ring *rfd_ring,
+	struct atl1c_recv_ret_status *rrs, u16 num)
+{
+	u16 i;
+	u16 rfd_index;
+	struct atl1c_buffer *buffer_info = rfd_ring->buffer_info;
+
+	rfd_index = (rrs->word0 >> RRS_RX_RFD_INDEX_SHIFT) &
+			RRS_RX_RFD_INDEX_MASK;
+	for (i = 0; i < num; i++) {
+		buffer_info[rfd_index].skb = NULL;
+		buffer_info[rfd_index].state = ATL1_BUFFER_FREE;
+		if (++rfd_index == rfd_ring->count)
+			rfd_index = 0;
+	}
+	rfd_ring->next_to_clean = rfd_index;
+
+	return;
+}
+
+static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que,
+		   int *work_done, int work_to_do)
+{
+	u16 rfd_num, rfd_index;
+	u16 count = 0;
+	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 sk_buff *skb;
+	struct atl1c_recv_ret_status *rrs;
+	struct atl1c_buffer *buffer_info;
+
+	while (1) {
+		if (*work_done >= work_to_do)
+			break;
+		rrs = ATL1C_RRD_DESC(rrd_ring, rrd_ring->next_to_clean);
+		if (likely(RRS_RXD_IS_VALID(rrs->word3))) {
+			rfd_num = (rrs->word0 >> RRS_RX_RFD_CNT_SHIFT) &
+				RRS_RX_RFD_CNT_MASK;
+			if (unlikely(rfd_num) != 1)
+				/* TODO support mul rfd*/
+				printk(KERN_EMERG "Multi rfd not support yet!\n");
+			goto rrs_checked;
+		} else {
+			break;
+		}
+rrs_checked:
+		atl1c_clean_rrd(rrd_ring, rrs, rfd_num);
+		if (rrs->word3 & (RRS_RX_ERR_SUM | RRS_802_3_LEN_ERR)) {
+			atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
+			printk(KERN_WARNING "wrong packet! rrs word3 is %x\n", rrs->word3);
+			continue;
+		}
+
+		length = le16_to_cpu((rrs->word3 >> RRS_PKT_SIZE_SHIFT) &
+				RRS_PKT_SIZE_MASK);
+		/* Good Receive */
+		if (likely(rfd_num == 1)) {
+			rfd_index = (rrs->word0 >> RRS_RX_RFD_INDEX_SHIFT) &
+					RRS_RX_RFD_INDEX_MASK;
+			buffer_info = &rfd_ring->buffer_info[rfd_index];
+			pci_unmap_single(pdev, buffer_info->dma,
+				buffer_info->length, PCI_DMA_FROMDEVICE);
+			skb = buffer_info->skb;
+		} else {
+			/* TODO */
+			printk(KERN_EMERG "Multil rfd not support yet!\n");
+			break;
+		}
+		atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
+		skb_put(skb, length - ETH_FCS_LEN);
+		skb->protocol = eth_type_trans(skb, netdev);
+		skb->dev = netdev;
+		atl1c_rx_checksum(adapter, skb, rrs);
+		if (unlikely(adapter->vlgrp) && rrs->word3 & RRS_VLAN_INS) {
+			u16 vlan;
+
+			AT_TAG_TO_VLAN(rrs->vlan_tag, vlan);
+			vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vlan);
+		} else
+			netif_receive_skb(skb);
+
+		netdev->last_rx = jiffies;
+		(*work_done)++;
+		count++;
+	}
+	if (count)
+		atl1c_alloc_rx_buffer(adapter, que);
+}
+
+/*
+ * atl1c_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ */
+static int atl1c_clean(struct napi_struct *napi, int budget)
+{
+	struct atl1c_adapter *adapter =
+			container_of(napi, struct atl1c_adapter, napi);
+	int work_done = 0;
+	int i;
+
+	/* Keep link state information with original netdev */
+	if (!netif_carrier_ok(adapter->netdev))
+		goto quit_polling;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		atl1c_clean_rx_irq(adapter, i, &work_done, budget);
+
+	if (work_done < budget) {
+quit_polling:
+		napi_complete(napi);
+		adapter->hw.intr_mask |= ISR_RX_PKT;
+		AT_WRITE_REG(&adapter->hw, REG_IMR, adapter->hw.intr_mask);
+	}
+	return work_done;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void atl1c_netpoll(struct net_device *netdev)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	disable_irq(adapter->pdev->irq);
+	atl1c_intr(adapter->pdev->irq, netdev);
+	enable_irq(adapter->pdev->irq);
+}
+#endif
+
+static inline u16 atl1c_tpd_avail(struct atl1c_adapter *adapter, enum atl1c_trans_queue type)
+{
+	struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
+	u16 next_to_use = 0;
+	u16 next_to_clean = 0;
+
+	next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+	next_to_use   = tpd_ring->next_to_use;
+
+	return (u16)(next_to_clean > next_to_use) ?
+		(next_to_clean - next_to_use - 1) :
+		(tpd_ring->count + next_to_clean - next_to_use - 1);
+}
+
+/*
+ * get next usable tpd
+ * Note: should call atl1c_tdp_avail to make sure
+ * there is enough tpd to use
+ */
+static struct atl1c_tpd_desc *atl1c_get_tpd(struct atl1c_adapter *adapter,
+	enum atl1c_trans_queue type)
+{
+	struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
+	struct atl1c_tpd_desc *tpd_desc;
+	u16 next_to_use = 0;
+
+	next_to_use = tpd_ring->next_to_use;
+	if (++tpd_ring->next_to_use == tpd_ring->count)
+		tpd_ring->next_to_use = 0;
+	tpd_desc = ATL1C_TPD_DESC(tpd_ring, next_to_use);
+	memset(tpd_desc, 0, sizeof(struct atl1c_tpd_desc));
+	return	tpd_desc;
+}
+
+static struct atl1c_buffer *
+atl1c_get_tx_buffer(struct atl1c_adapter *adapter, struct atl1c_tpd_desc *tpd)
+{
+	struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring;
+
+	return &tpd_ring->buffer_info[tpd -
+			(struct atl1c_tpd_desc *)tpd_ring->desc];
+}
+
+/* Calculate the transmit packet descript needed*/
+static u16 atl1c_cal_tpd_req(const struct sk_buff *skb)
+{
+	int i = 0;
+	u16 tpd_req = 1;
+	u16 proto_hdr_len = 0;
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+		tpd_req++;
+
+	if (skb_is_gso(skb)) {
+		proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+		if (proto_hdr_len < skb_headlen(skb))
+			tpd_req++;
+		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+			tpd_req++;
+	}
+	return tpd_req;
+}
+
+static int atl1c_tso_csum(struct atl1c_adapter *adapter,
+			  struct sk_buff *skb,
+			  struct atl1c_tpd_desc **tpd,
+			  enum atl1c_trans_queue type)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	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;
+		}
+		offload_type = skb_shinfo(skb)->gso_type;
+
+		if (offload_type & SKB_GSO_TCPV4) {
+			real_len = (((unsigned char *)ip_hdr(skb) - skb->data)
+					+ ntohs(ip_hdr(skb)->tot_len));
+
+			if (real_len < skb->len)
+				pskb_trim(skb, real_len);
+
+			hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
+			if (unlikely(skb->len == hdr_len)) {
+				/* only xsum need */
+				dev_warn(&pdev->dev,
+				      "IPV4 tso with zero data??\n");
+				goto check_sum;
+			} else {
+				ip_hdr(skb)->check = 0;
+				tcp_hdr(skb)->check = ~csum_tcpudp_magic(
+							ip_hdr(skb)->saddr,
+							ip_hdr(skb)->daddr,
+							0, IPPROTO_TCP, 0);
+				(*tpd)->word1 |= 1 << TPD_IPV4_PACKET_SHIFT;
+			}
+		}
+
+		if (offload_type & SKB_GSO_TCPV6) {
+			struct atl1c_tpd_ext_desc *etpd =
+				*(struct atl1c_tpd_ext_desc **)(tpd);
+
+			memset(etpd, 0, sizeof(struct atl1c_tpd_ext_desc));
+			*tpd = atl1c_get_tpd(adapter, type);
+			ipv6_hdr(skb)->payload_len = 0;
+			/* check payload == 0 byte ? */
+			hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
+			if (unlikely(skb->len == hdr_len)) {
+				/* only xsum need */
+				dev_warn(&pdev->dev,
+					"IPV6 tso with zero data??\n");
+				goto check_sum;
+			} else
+				tcp_hdr(skb)->check = ~csum_ipv6_magic(
+						&ipv6_hdr(skb)->saddr,
+						&ipv6_hdr(skb)->daddr,
+						0, IPPROTO_TCP, 0);
+			etpd->word1 |= 1 << TPD_LSO_EN_SHIFT;
+			etpd->word1 |= 1 << TPD_LSO_VER_SHIFT;
+			etpd->pkt_len = cpu_to_le32(skb->len);
+			(*tpd)->word1 |= 1 << TPD_LSO_VER_SHIFT;
+		}
+
+		(*tpd)->word1 |= 1 << TPD_LSO_EN_SHIFT;
+		(*tpd)->word1 |= (skb_transport_offset(skb) & TPD_TCPHDR_OFFSET_MASK) <<
+				TPD_TCPHDR_OFFSET_SHIFT;
+		(*tpd)->word1 |= (skb_shinfo(skb)->gso_size & TPD_MSS_MASK) <<
+				TPD_MSS_SHIFT;
+		return 0;
+	}
+
+check_sum:
+	if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+		u8 css, cso;
+		cso = skb_transport_offset(skb);
+
+		if (unlikely(cso & 0x1)) {
+			dev_err(&adapter->pdev->dev,
+			   "pay load offset should not ant event number\n");
+			return -1;
+		} else {
+			css = cso + skb->csum_offset;
+
+			(*tpd)->word1 |= ((cso >> 1) & TPD_PLOADOFFSET_MASK) <<
+					TPD_PLOADOFFSET_SHIFT;
+			(*tpd)->word1 |= ((css >> 1) & TPD_CCSUM_OFFSET_MASK) <<
+					TPD_CCSUM_OFFSET_SHIFT;
+			(*tpd)->word1 |= 1 << TPD_CCSUM_EN_SHIFT;
+		}
+	}
+	return 0;
+}
+
+static void atl1c_tx_map(struct atl1c_adapter *adapter,
+		      struct sk_buff *skb, struct atl1c_tpd_desc *tpd,
+			enum atl1c_trans_queue type)
+{
+	struct atl1c_tpd_desc *use_tpd = NULL;
+	struct atl1c_buffer *buffer_info = NULL;
+	u16 buf_len = skb->len - skb->data_len;
+	u16 map_len = 0;
+	u16 mapped_len = 0;
+	u16 hdr_len = 0;
+	u16 nr_frags;
+	u16 f;
+	int tso;
+
+	nr_frags = skb_shinfo(skb)->nr_frags;
+	tso = (tpd->word1 >> TPD_LSO_EN_SHIFT) & TPD_LSO_EN_MASK;
+	if (tso) {
+		/* TSO */
+		map_len = hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+		use_tpd = tpd;
+
+		buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
+		buffer_info->length = map_len;
+		buffer_info->dma = pci_map_single(adapter->pdev,
+					skb->data, hdr_len, PCI_DMA_TODEVICE);
+		buffer_info->state = ATL1_BUFFER_BUSY;
+		if (buffer_info->dma == 0) {
+			printk(KERN_EMERG "buffer_info dma is 0\n");
+			dump_stack();
+		}
+		mapped_len += map_len;
+		use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
+		use_tpd->buffer_len = cpu_to_le16(buffer_info->length);
+	}
+
+	if (mapped_len < buf_len) {
+		/* mapped_len == 0, means we should use the first tpd,
+		   which is given by caller  */
+		if (mapped_len == 0)
+			use_tpd = tpd;
+		else {
+			use_tpd = atl1c_get_tpd(adapter, type);
+			memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
+			use_tpd = atl1c_get_tpd(adapter, type);
+			memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
+		}
+		buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
+		buffer_info->length = buf_len - mapped_len;
+		buffer_info->dma =
+			pci_map_single(adapter->pdev, skb->data + mapped_len,
+					buffer_info->length, PCI_DMA_TODEVICE);
+		buffer_info->state = ATL1_BUFFER_BUSY;
+		if (buffer_info->dma == 0) {
+			printk(KERN_EMERG "buffer_info dma is 0\n");
+			dump_stack();
+		}
+
+		use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
+		use_tpd->buffer_len  = cpu_to_le16(buffer_info->length);
+	}
+
+	for (f = 0; f < nr_frags; f++) {
+		struct skb_frag_struct *frag;
+
+		frag = &skb_shinfo(skb)->frags[f];
+
+		use_tpd = atl1c_get_tpd(adapter, type);
+		memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
+
+		buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
+		buffer_info->length = frag->size;
+		buffer_info->dma =
+			pci_map_page(adapter->pdev, frag->page,
+					frag->page_offset,
+					buffer_info->length,
+					PCI_DMA_TODEVICE);
+		buffer_info->state = ATL1_BUFFER_BUSY;
+		if (buffer_info->dma == 0) {
+			printk(KERN_EMERG "buffer_info dma is 0\n");
+			dump_stack();
+		}
+
+		use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
+		use_tpd->buffer_len  = cpu_to_le16(buffer_info->length);
+	}
+
+	/* The last tpd */
+	use_tpd->word1 |= 1 << TPD_EOP_SHIFT;
+	/* The last buffer info contain the skb address,
+	   so it will be free after unmap */
+	buffer_info->skb = skb;
+}
+
+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;
+	wmb();
+	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;
+	}
+
+	AT_WRITE_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, prod_data);
+}
+
+static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	unsigned long flags;
+	u16 tpd_req = 1;
+	struct atl1c_tpd_desc *tpd;
+	enum atl1c_trans_queue type = atl1c_trans_normal;
+
+	if (test_bit(__AT_DOWN, &adapter->flags)) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	tpd_req = atl1c_cal_tpd_req(skb);
+	if (!spin_trylock_irqsave(&adapter->tx_lock, flags)) {
+		printk(KERN_EMERG "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 */
+		netif_stop_queue(netdev);
+		spin_unlock_irqrestore(&adapter->tx_lock, flags);
+		return NETDEV_TX_BUSY;
+	}
+
+	tpd = atl1c_get_tpd(adapter, type);
+
+	/* do TSO and check sum */
+	if (atl1c_tso_csum(adapter, skb, &tpd, type) != 0) {
+		spin_unlock_irqrestore(&adapter->tx_lock, flags);
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	if (unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) {
+		u16 vlan = vlan_tx_tag_get(skb);
+		u16 tag;
+		AT_VLAN_TO_TAG(vlan, tag);
+		tpd->word1 |= 1 << TPD_INS_VTAG_SHIFT;
+		tpd->vlan_tag = tag;
+	}
+
+	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);
+
+	netdev->trans_start = jiffies;
+	spin_unlock_irqrestore(&adapter->tx_lock, flags);
+	return NETDEV_TX_OK;
+}
+
+static void atl1c_free_irq(struct atl1c_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 atl1c_request_irq(struct atl1c_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) {
+		dev_dbg(&pdev->dev,
+			"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, &atl1c_intr, flags,
+			netdev->name, netdev);
+	if (err) {
+		dev_dbg(&pdev->dev,
+			"Unable to allocate interrupt Error: %d\n", err);
+		if (adapter->have_msi)
+			pci_disable_msi(adapter->pdev);
+		return err;
+	}
+	dev_dbg(&pdev->dev, "atl1c_request_irq OK\n");
+	return err;
+}
+
+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;
+		goto err_up;
+	}
+
+	err = atl1c_request_irq(adapter);
+	if (unlikely(err))
+		goto err_up;
+
+	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;
+}
+
+void atl1c_down(struct atl1c_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	atl1c_del_timer(adapter);
+	atl1c_cancel_work(adapter);
+
+	/* signal that we're down so the interrupt handler does not
+	 * reschedule our watchdog timer */
+	set_bit(__AT_DOWN, &adapter->flags);
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+	napi_disable(&adapter->napi);
+	atl1c_irq_disable(adapter);
+	atl1c_free_irq(adapter);
+	AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
+	/* 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_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ */
+static int atl1c_open(struct net_device *netdev)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	int err;
+
+	/* disallow open during test */
+	if (test_bit(__AT_TESTING, &adapter->flags))
+		return -EBUSY;
+
+	/* allocate rx/tx dma buffer & descriptors */
+	err = atl1c_setup_ring_resources(adapter);
+	if (unlikely(err))
+		return err;
+
+	err = atl1c_up(adapter);
+	if (unlikely(err))
+		goto err_up;
+
+	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;
+
+err_up:
+	atl1c_free_irq(adapter);
+	atl1c_free_ring_resources(adapter);
+	atl1c_reset_mac(&adapter->hw);
+	return err;
+}
+
+/*
+ * atl1c_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ */
+static int atl1c_close(struct net_device *netdev)
+{
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
+	atl1c_down(adapter);
+	atl1c_free_ring_resources(adapter);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+	struct atl1c_hw *hw = &adapter->hw;
+	u32 ctrl = 0;
+	u32 mac_ctrl_data = 0;
+	u32 master_ctrl_data = 0;
+	u32 wol_ctrl_data = 0;
+	u32 pm_data;
+	u16 mii_bmsr_data = 0;
+	u16 save_autoneg_advertised;
+	u16 mii_intr_status_data = 0;
+	u32 wufc = adapter->wol;
+	u32 i;
+#ifdef CONFIG_PM
+	int retval = 0;
+#endif
+
+	if (netif_running(netdev)) {
+		WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
+		atl1c_down(adapter);
+	}
+	netif_device_detach(netdev);
+	atl1c_disable_l0s_l1(hw);
+#ifdef CONFIG_PM
+	retval = pci_save_state(pdev);
+	if (retval)
+		return retval;
+#endif
+	if (wufc) {
+		AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
+		master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
+
+		/* get link status */
+		atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
+		atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
+		save_autoneg_advertised = hw->autoneg_advertised;
+		hw->autoneg_advertised = ADVERTISE_10_HALF;
+		if (atl1c_restart_autoneg(hw) != 0)
+			dev_dbg(&pdev->dev, "phy autoneg failed\n");
+		hw->phy_configured = false; /* re-init PHY when resume */
+		hw->autoneg_advertised = save_autoneg_advertised;
+		/* 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) {
+			for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
+				msleep(100);
+				atl1c_read_phy_reg(hw, MII_BMSR,
+					(u16 *)&mii_bmsr_data);
+				if (mii_bmsr_data & BMSR_LSTATUS)
+					break;
+			}
+			if ((mii_bmsr_data & BMSR_LSTATUS) == 0)
+				dev_dbg(&pdev->dev,
+					"%s: Link may change"
+					"when suspend\n",
+					atl1c_driver_name);
+			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);
+				goto wol_dis;
+			}
+		}
+		/* clear phy interrupt */
+		atl1c_read_phy_reg(hw, MII_ISR, &mii_intr_status_data);
+		/* Config MAC Ctrl register */
+		mac_ctrl_data = MAC_CTRL_RX_EN;
+		/* set to 10/100M halt duplex */
+		mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
+		mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
+				 MAC_CTRL_PRMLEN_MASK) <<
+				 MAC_CTRL_PRMLEN_SHIFT);
+
+		if (adapter->vlgrp)
+			mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
+
+		/* 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);
+
+		/* pcie patch */
+		AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
+		ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+		device_set_wakeup_enable(&pdev->dev, 1);
+		AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+
+		AT_READ_REG(hw, REG_PM_CTRLSTAT, &pm_data);
+		pm_data |= PM_CTRLSTAT_PME_EN;
+		AT_WRITE_REG(hw, REG_PM_CTRLSTAT, pm_data);
+
+		pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+		goto suspend_exit;
+	}
+wol_dis:
+
+	/* WOL disabled */
+	AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+
+	/* pcie patch */
+	AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
+	ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+	AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+
+	atl1c_phy_disable(hw);
+	hw->phy_configured = false; /* re-init PHY when resume */
+
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+
+suspend_exit:
+
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static int atl1c_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
+
+	atl1c_phy_reset(&adapter->hw);
+	atl1c_reset_mac(&adapter->hw);
+	netif_device_attach(netdev);
+	if (netif_running(netdev))
+		atl1c_up(adapter);
+
+	return 0;
+}
+#endif
+
+static void atl1c_shutdown(struct pci_dev *pdev)
+{
+	atl1c_suspend(pdev, PMSG_SUSPEND);
+}
+
+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->open = &atl1c_open;
+	netdev->stop = &atl1c_close;
+	netdev->hard_start_xmit = &atl1c_xmit_frame;
+	netdev->get_stats = &atl1c_get_stats;
+	netdev->set_multicast_list = &atl1c_set_multi;
+	netdev->set_mac_address = &atl1c_set_mac_addr;
+	netdev->change_mtu = &atl1c_change_mtu;
+	netdev->do_ioctl = &atl1c_ioctl;
+	netdev->tx_timeout = &atl1c_tx_timeout;
+	netdev->watchdog_timeo = AT_TX_WATCHDOG;
+	netdev->vlan_rx_register = atl1c_vlan_rx_register;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = atl1c_netpoll;
+#endif
+	atl1c_set_ethtool_ops(netdev);
+
+	/* TODO: add when ready */
+	netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
+			   NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+	netdev->features |= NETIF_F_TSO;
+	netdev->features |= NETIF_F_TSO6;
+
+	return 0;
+}
+
+/*
+ * atl1c_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in atl1c_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * atl1c_probe initializes an adapter identified by a pci_dev structure.
+ * 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)
+{
+	struct net_device *netdev;
+	struct atl1c_adapter *adapter = NULL;
+	static int cards_found;
+
+	int err = 0;
+
+	/* enable device (incl. PCI PM wakeup and hotplug setup) */
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "cannot enable PCI device\n");
+		return err;
+	}
+
+	/*
+	 * The atl1c 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 at a time.
+	 *
+	 * Supporting 64-bit DMA on this hardware is more trouble than it's
+	 * worth.  It is far easier to limit to 32-bit DMA than update
+	 * various kernel subsystems to support the mechanics required by a
+	 * fixed-high-32-bit system.
+	 */
+	if ((pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) ||
+	    (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) != 0)) {
+		dev_err(&pdev->dev, "No usable DMA configuration,aborting\n");
+		goto err_dma;
+	}
+
+	err = pci_request_regions(pdev, atl1c_driver_name);
+	if (err) {
+		dev_err(&pdev->dev, "cannot obtain PCI resources\n");
+		goto err_pci_reg;
+	}
+
+	pci_set_master(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;
+	}
+
+	err = atl1c_init_netdev(netdev, pdev);
+	if (err) {
+		dev_err(&pdev->dev, "init netdevice failed\n");
+		goto err_init_netdev;
+	}
+	adapter = netdev_priv(netdev);
+	adapter->bd_number = cards_found;
+	adapter->netdev = netdev;
+	adapter->pdev = pdev;
+	adapter->hw.adapter = adapter;
+	adapter->hw.hw_addr = pci_iomap(pdev, BAR_0, 0);
+	if (!adapter->hw.hw_addr) {
+		err = -EIO;
+		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;
+	netif_napi_add(netdev, &adapter->napi, atl1c_clean, 64);
+	init_timer(&adapter->phy_config_timer);
+	adapter->phy_config_timer.function = &atl1c_phy_config;
+	adapter->phy_config_timer.data = (unsigned long) adapter;
+
+	/* get user settings */
+	atl1c_check_options(adapter);
+
+
+	/* setup the private structure */
+	err = atl1c_sw_init(adapter);
+	if (err) {
+		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);
+
+	/* Init GPHY as early as possible due to power saving issue  */
+	atl1c_phy_reset(&adapter->hw);
+
+	err = atl1c_reset_mac(&adapter->hw);
+	if (err) {
+		err = -EIO;
+		goto err_reset;
+	}
+
+
+	/* reset the controller to
+	 * put the device in a known good starting state */
+	err = atl1c_phy_init(&adapter->hw);
+	if (err) {
+		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;
+	}
+	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+	memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
+	dev_dbg(&pdev->dev, "mac address : %02x-%02x-%02x-%02x-%02x-%02x\n",
+			adapter->hw.mac_addr[0], adapter->hw.mac_addr[1],
+			adapter->hw.mac_addr[2], adapter->hw.mac_addr[3],
+			adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]);
+
+	atl1c_hw_set_mac_addr(&adapter->hw);
+	INIT_WORK(&adapter->reset_task, atl1c_reset_task);
+	/* FIXME: should remove future ? */
+	INIT_WORK(&adapter->link_chg_task, atl1c_link_chg_task);
+	err = register_netdev(netdev);
+	if (err) {
+		dev_err(&pdev->dev, "register netdevice failed\n");
+		goto err_register;
+	}
+
+	cards_found++;
+
+	return 0;
+
+err_reset:
+err_register:
+err_sw_init:
+err_eeprom:
+	iounmap(adapter->hw.hw_addr);
+err_init_netdev:
+err_ioremap:
+	free_netdev(netdev);
+err_alloc_etherdev:
+	pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+	pci_disable_device(pdev);
+	return err;
+}
+
+/*
+ * atl1c_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * atl1c_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ */
+static void __devexit atl1c_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	unregister_netdev(netdev);
+	atl1c_phy_disable(&adapter->hw);
+
+	iounmap(adapter->hw.hw_addr);
+
+	pci_release_regions(pdev);
+	pci_disable_device(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
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t atl1c_io_error_detected(struct pci_dev *pdev,
+						pci_channel_state_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev))
+		atl1c_down(adapter);
+
+	pci_disable_device(pdev);
+
+	/* Request a slot slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/*
+ * atl1c_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the e1000_resume routine.
+ */
+static pci_ers_result_t atl1c_io_slot_reset(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	if (pci_enable_device(pdev)) {
+		dev_err(&pdev->dev,
+		       "ATL1e: Cannot re-enable PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	atl1c_reset_mac(&adapter->hw);
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/*
+ * atl1c_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the atl1c_resume routine.
+ */
+static void atl1c_io_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+	if (netif_running(netdev)) {
+		if (atl1c_up(adapter)) {
+			dev_err(&pdev->dev,
+			  "ATL1e: can't bring device back up after reset\n");
+			return;
+		}
+	}
+
+	netif_device_attach(netdev);
+}
+
+static struct pci_error_handlers atl1c_err_handler = {
+	.error_detected = atl1c_io_error_detected,
+	.slot_reset = atl1c_io_slot_reset,
+	.resume = atl1c_io_resume,
+};
+
+static struct pci_driver atl1c_driver = {
+	.name     = atl1c_driver_name,
+	.id_table = atl1c_pci_tbl,
+	.probe    = atl1c_probe,
+	.remove   = __devexit_p(atl1c_remove),
+	/* Power Managment Hooks */
+#ifdef CONFIG_PM
+	.suspend  = atl1c_suspend,
+	.resume   = atl1c_resume,
+#endif
+	.shutdown = atl1c_shutdown,
+	.err_handler = &atl1c_err_handler
+};
+
+/*
+ * 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);
diff --git a/drivers/net/atl1c/atl1c_param.c b/drivers/net/atl1c/atl1c_param.c
new file mode 100644
index 0000000..722ce94
--- /dev/null
+++ b/drivers/net/atl1c/atl1c_param.c
@@ -0,0 +1,283 @@ 
+/*
+ * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it 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 program 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, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/netdevice.h>
+
+#include "atl1c.h"
+
+/* This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+
+#define ATL1C_MAX_NIC 32
+
+#define OPTION_UNSET    -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED  1
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+#define ATL1C_PARAM_INIT { [0 ... ATL1C_MAX_NIC] = OPTION_UNSET }
+
+#define ATL1C_PARAM(x, desc) \
+	static int __devinitdata x[ATL1C_MAX_NIC + 1] = ATL1C_PARAM_INIT; \
+	static int num_##x; \
+	module_param_array_named(x, x, int, &num_##x, 0); \
+	MODULE_PARM_DESC(x, desc);
+
+/* Transmit Memory count
+ *
+ * Valid Range: 64-2048
+ *
+ * Default Value: 128
+ */
+#define ATL1C_MIN_TX_DESC_CNT		32
+#define ATL1C_MAX_TX_DESC_CNT		1024
+#define ATL1C_DEFAULT_TX_DESC_CNT	1024
+ATL1C_PARAM(tx_desc_cnt, "Transmit description count");
+
+/* Receive Memory Block Count
+ *
+ * Valid Range: 16-512
+ *
+ * Default Value: 128
+ */
+#define ATL1C_MIN_RX_MEM_SIZE		128
+#define ATL1C_MAX_RX_MEM_SIZE		1024
+#define ATL1C_DEFAULT_RX_MEM_SIZE	512
+ATL1C_PARAM(rx_mem_size, "memory size of rx buffer(KB)");
+
+/* User Specified MediaType Override
+ *
+ * Valid Range: 0-5
+ *  - 0    - auto-negotiate at all supported speeds
+ *  - 1    - only link at 100Mbps Full Duplex
+ *  - 2    - only link at 100Mbps Half Duplex
+ *  - 3    - only link at 10Mbps Full Duplex
+ *  - 4    - only link at 10Mbps Half Duplex
+ * Default Value: 0
+ */
+
+ATL1C_PARAM(media_type, "MediaType Select");
+
+/* Interrupt Moderate Timer in units of 2 us
+ *
+ * Valid Range: 10-65535
+ *
+ * Default Value: 45000(90ms)
+ */
+#define INT_MOD_DEFAULT_CNT             200 /* 200us */
+#define INT_MOD_MAX_CNT                 65000
+#define INT_MOD_MIN_CNT                 50
+ATL1C_PARAM(int_mod_timer, "Interrupt Moderator Timer");
+
+#define AUTONEG_ADV_DEFAULT  0x2F
+#define AUTONEG_ADV_MASK     0x2F
+#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
+
+#define FLASH_VENDOR_DEFAULT    0
+#define FLASH_VENDOR_MIN        0
+#define FLASH_VENDOR_MAX        2
+
+struct atl1c_option {
+	enum { enable_option, range_option, list_option } type;
+	char *name;
+	char *err;
+	int  def;
+	union {
+		struct { /* range_option info */
+			int min;
+			int max;
+		} r;
+		struct { /* list_option info */
+			int nr;
+			struct atl1c_opt_list { int i; char *str; } *p;
+		} l;
+	} arg;
+};
+
+static int __devinit atl1c_validate_option(int *value, struct atl1c_option *opt, struct pci_dev *pdev)
+{
+	if (*value == OPTION_UNSET) {
+		*value = opt->def;
+		return 0;
+	}
+
+	switch (opt->type) {
+	case enable_option:
+		switch (*value) {
+		case OPTION_ENABLED:
+			dev_info(&pdev->dev, "%s Enabled\n", opt->name);
+			return 0;
+		case OPTION_DISABLED:
+			dev_info(&pdev->dev, "%s Disabled\n", opt->name);
+			return 0;
+		}
+		break;
+	case range_option:
+		if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+			dev_info(&pdev->dev, "%s set to %i\n", opt->name, *value);
+			return 0;
+		}
+		break;
+	case list_option:{
+			int i;
+			struct atl1c_opt_list *ent;
+
+			for (i = 0; i < opt->arg.l.nr; i++) {
+				ent = &opt->arg.l.p[i];
+				if (*value == ent->i) {
+					if (ent->str[0] != '\0')
+						dev_info(&pdev->dev, "%s\n",
+							ent->str);
+					return 0;
+				}
+			}
+			break;
+		}
+	default:
+		BUG();
+	}
+
+	dev_info(&pdev->dev, "Invalid %s specified (%i) %s\n",
+			opt->name, *value, opt->err);
+	*value = opt->def;
+	return -1;
+}
+
+/*
+ * atl1c_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input.  If an invalid value is given, or if no user specified
+ * value exists, a default value is used.  The final value is stored
+ * in a variable in the adapter structure.
+ */
+void __devinit atl1c_check_options(struct atl1c_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	int bd = adapter->bd_number;
+	if (bd >= ATL1C_MAX_NIC) {
+		dev_notice(&pdev->dev, "no configuration for board #%i\n", bd);
+		dev_notice(&pdev->dev, "Using defaults for all values\n");
+	}
+
+	{ 		/* Transmit Ring Size */
+		struct atl1c_option opt = {
+			.type = range_option,
+			.name = "Transmit Ddescription Count",
+			.err  = "using default of "
+				__MODULE_STRING(ATL1C_DEFAULT_TX_DESC_CNT),
+			.def  = ATL1C_DEFAULT_TX_DESC_CNT,
+			.arg  = { .r = { .min = ATL1C_MIN_TX_DESC_CNT,
+					 .max = ATL1C_MAX_TX_DESC_CNT} }
+		};
+		int val;
+		if (num_tx_desc_cnt > bd) {
+			val = tx_desc_cnt[bd];
+			atl1c_validate_option(&val, &opt, pdev);
+			adapter->tpd_ring[0].count = (u16) val & 0xFFFC;
+		} else
+			adapter->tpd_ring[0].count = (u16)opt.def;
+	}
+
+	{ 		/* Receive Memory Block Count */
+		struct atl1c_option opt = {
+			.type = range_option,
+			.name = "Memory size of rx buffer(KB)",
+			.err  = "using default of "
+				__MODULE_STRING(ATL1C_DEFAULT_RX_MEM_SIZE),
+			.def  = ATL1C_DEFAULT_RX_MEM_SIZE,
+			.arg  = { .r = { .min = ATL1C_MIN_RX_MEM_SIZE,
+					 .max = ATL1C_MAX_RX_MEM_SIZE} }
+		};
+		int val;
+		if (num_rx_mem_size > bd) {
+			val = rx_mem_size[bd];
+			atl1c_validate_option(&val, &opt, pdev);
+			adapter->rfd_ring[0].count = (u32)val;
+		} else {
+			adapter->rfd_ring[0].count = (u32)opt.def;
+		}
+	}
+
+	{ 		/* Interrupt Moderate Timer */
+		struct atl1c_option opt = {
+			.type = range_option,
+			.name = "Interrupt Moderate TX Timer",
+			.err  = "using default of "
+				__MODULE_STRING(INT_MOD_DEFAULT_CNT),
+			.def  = INT_MOD_DEFAULT_CNT * 5,
+			.arg  = { .r = { .min = INT_MOD_MIN_CNT,
+					 .max = INT_MOD_MAX_CNT} }
+		} ;
+		int val;
+		if (num_int_mod_timer > bd) {
+			val = int_mod_timer[bd];
+			atl1c_validate_option(&val, &opt, pdev);
+			adapter->hw.tx_imt = (u16) val;
+		} else
+			adapter->hw.tx_imt = (u16)(opt.def);
+	}
+	{ 		/* Interrupt Moderate Timer */
+		struct atl1c_option opt = {
+			.type = range_option,
+			.name = "Interrupt Moderate RX Timer",
+			.err  = "using default of "
+				__MODULE_STRING(INT_MOD_DEFAULT_CNT),
+			.def  = INT_MOD_DEFAULT_CNT,
+			.arg  = { .r = { .min = INT_MOD_MIN_CNT,
+					 .max = INT_MOD_MAX_CNT} }
+		} ;
+		int val;
+		if (num_int_mod_timer > bd) {
+			val = int_mod_timer[bd];
+			atl1c_validate_option(&val, &opt, pdev);
+			adapter->hw.rx_imt = (u16) val;
+		} else
+			adapter->hw.rx_imt = (u16)(opt.def);
+	}
+
+
+
+	{ 		/* MediaType */
+		struct atl1c_option opt = {
+			.type = range_option,
+			.name = "Speed/Duplex Selection",
+			.err  = "using default of "
+				__MODULE_STRING(MEDIA_TYPE_AUTO_SENSOR),
+			.def  = MEDIA_TYPE_AUTO_SENSOR,
+			.arg  = { .r = { .min = MEDIA_TYPE_AUTO_SENSOR,
+					 .max = MEDIA_TYPE_10M_HALF} }
+		} ;
+		int val;
+		if (num_media_type > bd) {
+			val = media_type[bd];
+			atl1c_validate_option(&val, &opt, pdev);
+			adapter->hw.media_type = (u16) val;
+		} else
+			adapter->hw.media_type = (u16)(opt.def);
+
+	}
+}