2012-08-09

From: Cloud Ren

This driver support two new ethernet chipsets:

1969:1091 - AR8161 Gigabit Ethernet

1969:1090 - AR8162 Fast Ethernet

Qualcomm Atheros(QCA) is commiting to fix all bugs found on this driver.

This driver is also permissively licensed thereby enabling developers of

other OSes to cherry pick this driver to port to their OS.

Test including build/install/uninstall/dhcp/ping/iperf/wol/reboot/etc.

is passed on the supported chipsets.

This driver and patch also have addressed all sparse and checkpatch

warnings.

Signed-off-by: Cloud Ren

Signed-off-by: Xiong Huang

Signed-off-by: Hao-Ran Liu(Joseph Liu)

Signed-off-by: Joe Perches

Tested-by: David Liu

Signed-off-by: Luis R. Rodriguez

---

MAINTAINERS | 11 +

drivers/net/ethernet/atheros/Kconfig | 38 +-

drivers/net/ethernet/atheros/Makefile | 1 +

drivers/net/ethernet/atheros/alx/Makefile | 7 +

drivers/net/ethernet/atheros/alx/alx.h | 746 +++++

drivers/net/ethernet/atheros/alx/alx_abs.c | 1055 +++++++

drivers/net/ethernet/atheros/alx/alx_cifs.c | 307 ++

drivers/net/ethernet/atheros/alx/alx_cifs.h | 69 +

drivers/net/ethernet/atheros/alx/alx_dfs.c | 878 ++++++

drivers/net/ethernet/atheros/alx/alx_dfs.h | 182 ++

drivers/net/ethernet/atheros/alx/alx_ethtool.c | 337 +++

drivers/net/ethernet/atheros/alx/alx_hw.c | 1042 +++++++

drivers/net/ethernet/atheros/alx/alx_hw.h | 2132 +++++++++++++

drivers/net/ethernet/atheros/alx/alx_hwcom.h | 128 +

drivers/net/ethernet/atheros/alx/alx_main.c | 3830 ++++++++++++++++++++++++

drivers/net/ethernet/atheros/alx/alx_sw.h | 478 +++

16 files changed, 11238 insertions(+), 3 deletions(-)

create mode 100644 drivers/net/ethernet/atheros/alx/Makefile

create mode 100644 drivers/net/ethernet/atheros/alx/alx.h

create mode 100644 drivers/net/ethernet/atheros/alx/alx_abs.c

create mode 100644 drivers/net/ethernet/atheros/alx/alx_cifs.c

create mode 100644 drivers/net/ethernet/atheros/alx/alx_cifs.h

create mode 100644 drivers/net/ethernet/atheros/alx/alx_dfs.c

create mode 100644 drivers/net/ethernet/atheros/alx/alx_dfs.h

create mode 100644 drivers/net/ethernet/atheros/alx/alx_ethtool.c

create mode 100644 drivers/net/ethernet/atheros/alx/alx_hw.c

create mode 100644 drivers/net/ethernet/atheros/alx/alx_hw.h

create mode 100644 drivers/net/ethernet/atheros/alx/alx_hwcom.h

create mode 100644 drivers/net/ethernet/atheros/alx/alx_main.c

create mode 100644 drivers/net/ethernet/atheros/alx/alx_sw.h

diff --git a/MAINTAINERS b/MAINTAINERS

index 1b71f6c..eb12e1b 100644

--- a/MAINTAINERS

+++ b/MAINTAINERS

@@ -1290,6 +1290,17 @@ W: http://atl1.sourceforge.net

S: Maintained

F: drivers/net/ethernet/atheros/

+ALX ETHERNET DRIVERS

+M: Cloud Ren

+M: Stevent Li

+M: Wu Ken

+M: David Liu

+L: netdev@vger.kernel.org

+L: nic-devel@qualcomm.com

+W: http://www.linuxfoundation.org/collaborate/workgroups/networking/alx

+S: Supported

+F: drivers/net/ethernet/atheros/alx/

+

ATM

M: Chas Williams

L: linux-atm-general@lists.sourceforge.net (moderated for non-subscribers)

diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig

index 1ed886d..8dfd634 100644

--- a/drivers/net/ethernet/atheros/Kconfig

+++ b/drivers/net/ethernet/atheros/Kconfig

@@ -56,15 +56,47 @@ config ATL1E

will be called atl1e.

config ATL1C

- tristate "Atheros L1C Gigabit Ethernet support (EXPERIMENTAL)"

- depends on PCI && EXPERIMENTAL

+ tristate "Atheros L1C/L1D Gigabit Ethernet support"

+ depends on PCI

select CRC32

select NET_CORE

select MII

---help---

- This driver supports the Atheros L1C gigabit ethernet adapter.

+ This driver supports the Atheros L1C/L1D ethernet adapter.

+ This driver supports following chipsets:

+

+ 1969:1063 - AR8131 Gigabit Ethernet

+ 1969:1062 - AR8132 Fast Ethernet (10/100 Mbit/s)

+ 1969:2062 - AR8152 v2.0 Fast Ethernet

+ 1969:2060 - AR8152 v1.1 Fast Ethernet

+ 1969:1073 - AR8151 v1.0 Gigabit Ethernet

+ 1969:1083 - AR8151 v2.0 Gigabit Ethernet

To compile this driver as a module, choose M here. The module

will be called atl1c.

+config ALX

+ tristate "Qualcomm Atheros L1F Gigabit Ethernet support"

+ depends on PCI

+ select CRC32

+ select NET_CORE

+ select MII

+ ---help---

+ This driver supports the Qualcomm Atheros L1F ethernet adapter.

+ This driver supports following chipsets:

+

+ 1969:1091 - AR8161 Gigabit Ethernet

+ 1969:1090 - AR8162 Fast Ethernet

+

+ To compile this driver as a module, choose M here. The module

+ will be called alx.

+

+config ALX_DEBUGFS

+ bool "Qualcomm Atheros debugging interface"

+ depends on ALX && DEBUG_FS

+ ---help---

+ This option adds ability to debug and test L1F. It can

+ support Qualcomm Atheros tools, including diagnostic, memcfg

+ and SWOI.

+

endif # NET_VENDOR_ATHEROS

diff --git a/drivers/net/ethernet/atheros/Makefile b/drivers/net/ethernet/atheros/Makefile

index e7e76fb..5cf1c65 100644

--- a/drivers/net/ethernet/atheros/Makefile

+++ b/drivers/net/ethernet/atheros/Makefile

@@ -6,3 +6,4 @@ obj-$(CONFIG_ATL1) += atlx/

obj-$(CONFIG_ATL2) += atlx/

obj-$(CONFIG_ATL1E) += atl1e/

obj-$(CONFIG_ATL1C) += atl1c/

+obj-$(CONFIG_ALX) += alx/

diff --git a/drivers/net/ethernet/atheros/alx/Makefile b/drivers/net/ethernet/atheros/alx/Makefile

new file mode 100644

index 0000000..66acb3f

--- /dev/null

+++ b/drivers/net/ethernet/atheros/alx/Makefile

@@ -0,0 +1,7 @@

+obj-$(CONFIG_ALX) += alx.o

+alx-objs := alx_main.o alx_ethtool.o alx_abs.o alx_hw.o

+ifdef CONFIG_ALX_DEBUGFS

+alx-objs += alx_dfs.o

+alx-objs += alx_cifs.o

+endif

+ccflags-y += -D__CHECK_ENDIAN__

diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h

new file mode 100644

index 0000000..69709e7

--- /dev/null

+++ b/drivers/net/ethernet/atheros/alx/alx.h

@@ -0,0 +1,746 @@

+/*

+ * Copyright (c) 2012 Qualcomm Atheros, Inc.

+ *

+ * Permission to use, copy, modify, and/or distribute this software for any

+ * purpose with or without fee is hereby granted, provided that the above

+ * copyright notice and this permission notice appear in all copies.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES

+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR

+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES

+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN

+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF

+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

+ */

+

+#ifndef _ALX_H_

+#define _ALX_H_

+

+#include

+

+#include "alx_sw.h"

+#include "alx_dfs.h"

+

+/*

+ * Definition to enable some features

+ */

+#undef CONFIG_ALX_MSIX

+#undef CONFIG_ALX_MSI

+#undef CONFIG_ALX_MTQ

+#undef CONFIG_ALX_MRQ

+#undef CONFIG_ALX_RSS

+/* #define CONFIG_ALX_MSIX */

+#define CONFIG_ALX_MSI

+#define CONFIG_ALX_MTQ

+#define CONFIG_ALX_MRQ

+#ifdef CONFIG_ALX_MRQ

+#define CONFIG_ALX_RSS

+#endif

+

+#define ALX_MSG_DEFAULT 0

+

+/* Logging functions and macros */

+#define alx_err(adpt, fmt, ...) \

+ netdev_err(adpt->netdev, fmt, ##__VA_ARGS__)

+

+#define ALX_VLAN_TO_TAG(_vlan, _tag) \

+ do { \

+ _tag = ((((_vlan) >> 8) & 0xFF) | (((_vlan) & 0xFF)
> 8) & 0xFF) | (((_tag) & 0xFF)
"

+#endif

+};

+

+union alx_hw_rrdesc {

+ /* dword flat format */

+ struct {

+ __le32 dw0;

+ __le32 dw1;

+ __le32 dw2;

+ __le32 dw3;

+ } dfmt;

+

+ /* qword flat format */

+ struct {

+ __le64 qw0;

+ __le64 qw1;

+ } qfmt;

+};

+

+/*

+ * XXX: we should not use this guy, best to just

+ * do all le32_to_cpu() conversions on the spot.

+ */

+union alx_sw_rrdesc {

+ struct alx_sw_rrdes_general genr;

+

+ /* dword flat format */

+ struct {

+ u32 dw0;

+ u32 dw1;

+ u32 dw2;

+ u32 dw3;

+ } dfmt;

+

+ /* qword flat format */

+ struct {

+ u64 qw0;

+ u64 qw1;

+ } qfmt;

+};

+

+/*

+ * RFD : definition

+ */

+

+/* general parameter format of rfd */

+struct alx_sw_rfdes_general {

+ u64 addr;

+};

+

+union alx_hw_rfdesc {

+ /* dword flat format */

+ struct {

+ __le32 dw0;

+ __le32 dw1;

+ } dfmt;

+

+ /* qword flat format */

+ struct {

+ __le64 qw0;

+ } qfmt;

+};

+

+/*

+ * XXX: we should not use this guy, best to just

+ * do all le32_to_cpu() conversions on the spot.

+ */

+union alx_sw_rfdesc {

+ struct alx_sw_rfdes_general genr;

+

+ /* dword flat format */

+ struct {

+ u32 dw0;

+ u32 dw1;

+ } dfmt;

+

+ /* qword flat format */

+ struct {

+ u64 qw0;

+ } qfmt;

+};

+

+/*

+ * TPD : definition

+ */

+

+/* general parameter format of tpd */

+struct alx_sw_tpdes_general {

+#if defined(__LITTLE_ENDIAN_BITFIELD)

+ /* dword 0 */

+ u32 buffer_len:16; /* include 4-byte CRC */

+ u32 vlan_tag:16;

+ /* dword 1 */

+ u32 l4hdr_offset:8; /* l4 header offset to the 1st byte of packet */

+ u32 c_csum:1;

+ u32 ip_csum:1;

+ u32 tcp_csum:1;

+ u32 udp_csum:1;

+ u32 lso:1;

+ u32 lso_v2:1;

+ u32 vtagged:1; /* vlan-id tagged already */

+ u32 instag:1; /* insert vlan tag */

+

+ u32 ipv4:1; /* ipv4 packet */

+ u32 type:1; /* type of packet (ethernet_ii(0) or snap(1)) */

+ u32 reserve:12;

+ u32 epad:1; /* even byte padding when this packet */

+ u32 last_frag:1; /* last fragment(buffer) of the packet */

+

+ u64 addr;

+#elif defined(__BIG_ENDIAN_BITFIELD)

+ /* dword 0 */

+ u32 vlan_tag:16;

+ u32 buffer_len:16;

+ /* dword 1 */

+ u32 last_frag:1;

+ u32 epad:1;

+ u32 reserve:12;

+ u32 type:1;

+ u32 ipv4:1;

+ u32 instag:1;

+ u32 vtagged:1;

+ u32 lso_v2:1;

+ u32 lso:1;

+ u32 udp_csum:1;

+ u32 tcp_csum:1;

+ u32 ip_csum:1;

+ u32 c_csum:1;

+ u32 l4hdr_offset:8;

+

+ u64 addr;

+#else

+#error "Please fix
"

+#endif

+};

+

+/* custom checksum parameter format of tpd */

+struct alx_sw_tpdes_checksum {

+#if defined(__LITTLE_ENDIAN_BITFIELD)

+ /* dword 0 */

+ u32 buffer_len:16;

+ u32 vlan_tag:16;

+ /* dword 1 */

+ u32 payld_offset:8; /* payload offset to the 1st byte of packet */

+ u32 c_csum:1; /* do custom checksum offload */

+ u32 ip_csum:1; /* do ip(v4) header checksum offload */

+ u32 tcp_csum:1; /* do tcp checksum offload, both ipv4 and ipv6 */

+ u32 udp_csum:1; /* do udp checksum offlaod, both ipv4 and ipv6 */

+ u32 lso:1;

+ u32 lso_v2:1;

+ u32 vtagged:1; /* vlan-id tagged already */

+ u32 instag:1; /* insert vlan tag */

+ u32 ipv4:1; /* ipv4 packet */

+ u32 type:1; /* type of packet (ethernet_ii(0) or snap(1)) */

+ u32 cxsum_offset:8; /* checksum offset to the 1st byte of packet */

+ u32 reserve:4;

+ u32 epad:1; /* even byte padding when this packet */

+ u32 last_frag:1; /* last fragment(buffer) of the packet */

+

+ u64 addr;

+#elif defined(__BIG_ENDIAN_BITFIELD)

+ /* dword 0 */

+ u32 vlan_tag:16;

+ u32 buffer_len:16;

+ /* dword 1 */

+ u32 last_frag:1;

+ u32 epad:1;

+ u32 reserve:4;

+ u32 cxsum_offset:8;

+ u32 type:1;

+ u32 ipv4:1;

+ u32 instag:1;

+ u32 vtagged:1;

+ u32 lso_v2:1;

+ u32 lso:1;

+ u32 udp_csum:1;

+ u32 tcp_csum:1;

+ u32 ip_csum:1;

+ u32 c_csum:1;

+ u32 payld_offset:8;

+

+ u64 addr;

+#else

+#error "Please fix
"

+#endif

+};

+

+

+/* tcp large send format (v1/v2) of tpd */

+struct alx_sw_tpdes_tso {

+#if defined(__LITTLE_ENDIAN_BITFIELD)

+ /* dword 0 */

+ u32 buffer_len:16; /* include 4-byte CRC */

+ u32 vlan_tag:16;

+ /* dword 1 */

+ u32 tcphdr_offset:8; /* tcp hdr offset to the 1st byte of packet */

+ u32 c_csum:1;

+ u32 ip_csum:1;

+ u32 tcp_csum:1;

+ u32 udp_csum:1;

+ u32 lso:1; /* do tcp large send (ipv4 only) */

+ u32 lso_v2:1; /* must be 0 in this format */

+ u32 vtagged:1; /* vlan-id tagged already */

+ u32 instag:1; /* insert vlan tag */

+ u32 ipv4:1; /* ipv4 packet */

+ u32 type:1; /* type of packet (ethernet_ii(1) or snap(0)) */

+ u32 mss:13; /* mss if do tcp large send */

+ u32 last_frag:1; /* last fragment(buffer) of the packet */

+

+ u32 pkt_len; /* packet length in ext tpd */

+ u32 reserve;

+#elif defined(__BIG_ENDIAN_BITFIELD)

+ /* dword 0 */

+ u32 vlan_tag:16;

+ u32 buffer_len:16;

+ /* dword 1 */

+ u32 last_frag:1;

+ u32 mss:13;

+ u32 type:1;

+ u32 ipv4:1;

+ u32 instag:1;

+ u32 vtagged:1;

+ u32 lso_v2:1;

+ u32 lso:1;

+ u32 udp_csum:1;

+ u32 tcp_csum:1;

+ u32 ip_csum:1;

+ u32 c_csum:1;

+ u32 tcphdr_offset:8;

+

+ u32 pkt_len;

+ u32 reserve;

+#else

+#error "Please fix
"

+#endif

+};

+

+union alx_hw_tpdesc {

+ /* dword flat format */

+ struct {

+ __le32 dw0;

+ __le32 dw1;

+ __le32 dw2;

+ __le32 dw3;

+ } dfmt;

+

+ /* qword flat format */

+ struct {

+ __le64 qw0;

+ __le64 qw1;

+ } qfmt;

+};

+

+/*

+ * XXX: we should not use this guy, best to just

+ * do all le32_to_cpu() conversions on the spot.

+ */

+union alx_sw_tpdesc {

+ struct alx_sw_tpdes_general genr;

+ struct alx_sw_tpdes_checksum csum;

+ struct alx_sw_tpdes_tso tso;

+

+ /* dword flat format */

+ struct {

+ u32 dw0;

+ u32 dw1;

+ u32 dw2;

+ u32 dw3;

+ } dfmt;

+

+ /* qword flat format */

+ struct {

+ u64 qw0;

+ u64 qw1;

+ } qfmt;

+};

+

+#define ALX_RRD(_que, _i) \

+ (&(((union alx_hw_rrdesc *)(_que)->rrq.rrdesc)[(_i)]))

+#define ALX_RFD(_que, _i) \

+ (&(((union alx_hw_rfdesc *)(_que)->rfq.rfdesc)[(_i)]))

+#define ALX_TPD(_que, _i) \

+ (&(((union alx_hw_tpdesc *)(_que)->tpq.tpdesc)[(_i)]))

+

+

+/*

+ * alx_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 alx_ring_header {

+ void *desc; /* virtual address */

+ dma_addr_t dma; /* physical address*/

+ unsigned int size; /* length in bytes */

+ unsigned int used;

+};

+

+

+/*

+ * alx_buffer is wrapper around a pointer to a socket buffer

+ * so a DMA handle can be stored along with the skb

+ */

+struct alx_buffer {

+ struct sk_buff *skb; /* socket buffer */

+ u16 length; /* rx buffer length */

+ dma_addr_t dma;

+};

+

+struct alx_sw_buffer {

+ struct sk_buff *skb; /* socket buffer */

+ u32 vlan_tag:16;

+ u32 vlan_flag:1;

+ u32 reserved:15;

+};

+

+/* receive free descriptor (rfd) queue */

+struct alx_rfd_queue {

+ struct alx_buffer *rfbuff;

+ union alx_hw_rfdesc *rfdesc; /* virtual address */

+ dma_addr_t rfdma; /* physical address */

+ u16 size; /* length in bytes */

+ u16 count; /* number of descriptors in the ring */

+ u16 produce_idx; /* it's written to rxque->produce_reg */

+ u16 consume_idx; /* unused*/

+};

+

+/* receive return desciptor (rrd) queue */

+struct alx_rrd_queue {

+ union alx_hw_rrdesc *rrdesc; /* virtual address */

+ dma_addr_t rrdma; /* physical address */

+ u16 size; /* length in bytes */

+ u16 count; /* number of descriptors in the ring */

+ u16 produce_idx; /* unused */

+ u16 consume_idx; /* rxque->consume_reg */

+};

+

+/* software desciptor (swd) queue */

+struct alx_swd_queue {

+ struct alx_sw_buffer *swbuff;

+ u16 count; /* number of descriptors in the ring */

+ u16 produce_idx;

+ u16 consume_idx;

+};

+

+/* rx queue */

+struct alx_rx_queue {

+ struct device *dev; /* device for dma mapping */

+ struct net_device *netdev; /* netdev ring belongs to */

+ struct alx_msix_param *msix;

+ struct alx_rrd_queue rrq;

+ struct alx_rfd_queue rfq;

+ struct alx_swd_queue swq;

+

+ u16 que_idx; /* index in multi rx queues*/

+ u16 max_packets; /* max work per interrupt */

+ u16 produce_reg;

+ u16 consume_reg;

+ u32 flags;

+};

+#define ALX_RX_FLAG_SW_QUE 0x00000001

+#define ALX_RX_FLAG_HW_QUE 0x00000002

+#define CHK_RX_FLAG(_flag) CHK_FLAG(rxque, RX, _flag)

+#define SET_RX_FLAG(_flag) SET_FLAG(rxque, RX, _flag)

+#define CLI_RX_FLAG(_flag) CLI_FLAG(rxque, RX, _flag)

+

+#define GET_RF_BUFFER(_rque, _i) (&((_rque)->rfq.rfbuff[(_i)]))

+#define GET_SW_BUFFER(_rque, _i) (&((_rque)->swq.swbuff[(_i)]))

+

+

+/* transimit packet descriptor (tpd) ring */

+struct alx_tpd_queue {

+ struct alx_buffer *tpbuff;

+ union alx_hw_tpdesc *tpdesc; /* virtual address */

+ dma_addr_t tpdma; /* physical address */

+

+ u16 size; /* length in bytes */

+ u16 count; /* number of descriptors in the ring */

+ u16 produce_idx;

+ u16 consume_idx;

+ u16 last_produce_idx;

+};

+

+/* tx queue */

+struct alx_tx_queue {

+ struct device *dev; /* device for dma mapping */

+ struct net_device *netdev; /* netdev ring belongs to */

+ struct alx_tpd_queue tpq;

+ struct alx_msix_param *msix;

+

+ u16 que_idx; /* needed for multiqueue queue management */

+ u16 max_packets; /* max packets per interrupt */

+ u16 produce_reg;

+ u16 consume_reg;

+};

+#define GET_TP_BUFFER(_tque, _i) (&((_tque)->tpq.tpbuff[(_i)]))

+

+

+/*

+ * definition for array allocations.

+ */

+#define ALX_MAX_MSIX_INTRS 16

+#define ALX_MAX_RX_QUEUES 8

+#define ALX_MAX_TX_QUEUES 4

+

+enum alx_msix_type {

+ alx_msix_type_rx,

+ alx_msix_type_tx,

+ alx_msix_type_other,

+};

+#define ALX_MSIX_TYPE_OTH_TIMER 0

+#define ALX_MSIX_TYPE_OTH_ALERT 1

+#define ALX_MSIX_TYPE_OTH_SMB 2

+#define ALX_MSIX_TYPE_OTH_PHY 3

+

+/* ALX_MAX_MSIX_INTRS of these are allocated,

+ * but we only use one per queue-specific vector.

+ */

+struct alx_msix_param {

+ struct alx_adapter *adpt;

+ unsigned int vec_idx; /* index in HW interrupt vector */

+ char name[IFNAMSIZ + 9];

+

+ /* msix interrupts for queue */

+ u8 rx_map[ALX_MAX_RX_QUEUES];

+ u8 tx_map[ALX_MAX_TX_QUEUES];

+ u8 rx_count; /* Rx ring count assigned to this vector */

+ u8 tx_count; /* Tx ring count assigned to this vector */

+

+ struct napi_struct napi;

+ cpumask_var_t affinity_mask;

+ u32 flags;

+};

+

+#define ALX_MSIX_FLAG_RX0 0x00000001

+#define ALX_MSIX_FLAG_RX1 0x00000002

+#define ALX_MSIX_FLAG_RX2 0x00000004

+#define ALX_MSIX_FLAG_RX3 0x00000008

+#define ALX_MSIX_FLAG_RX4 0x00000010

+#define ALX_MSIX_FLAG_RX5 0x00000020

+#define ALX_MSIX_FLAG_RX6 0x00000040

+#define ALX_MSIX_FLAG_RX7 0x00000080

+#define ALX_MSIX_FLAG_TX0 0x00000100

+#define ALX_MSIX_FLAG_TX1 0x00000200

+#define ALX_MSIX_FLAG_TX2 0x00000400

+#define ALX_MSIX_FLAG_TX3 0x00000800

+#define ALX_MSIX_FLAG_TIMER 0x00001000

+#define ALX_MSIX_FLAG_ALERT 0x00002000

+#define ALX_MSIX_FLAG_SMB 0x00004000

+#define ALX_MSIX_FLAG_PHY 0x00008000

+

+#define ALX_MSIX_FLAG_RXS (\

+ ALX_MSIX_FLAG_RX0 |\

+ ALX_MSIX_FLAG_RX1 |\

+ ALX_MSIX_FLAG_RX2 |\

+ ALX_MSIX_FLAG_RX3 |\

+ ALX_MSIX_FLAG_RX4 |\

+ ALX_MSIX_FLAG_RX5 |\

+ ALX_MSIX_FLAG_RX6 |\

+ ALX_MSIX_FLAG_RX7)

+#define ALX_MSIX_FLAG_TXS (\

+ ALX_MSIX_FLAG_TX0 |\

+ ALX_MSIX_FLAG_TX1 |\

+ ALX_MSIX_FLAG_TX2 |\

+ ALX_MSIX_FLAG_TX3)

+#define ALX_MSIX_FLAG_ALL (\

+ ALX_MSIX_FLAG_RXS |\

+ ALX_MSIX_FLAG_TXS |\

+ ALX_MSIX_FLAG_TIMER |\

+ ALX_MSIX_FLAG_ALERT |\

+ ALX_MSIX_FLAG_SMB |\

+ ALX_MSIX_FLAG_PHY)

+

+#define CHK_MSIX_FLAG(_flag) CHK_FLAG(msix, MSIX, _flag)

+#define SET_MSIX_FLAG(_flag) SET_FLAG(msix, MSIX, _flag)

+#define CLI_MSIX_FLAG(_flag) CLI_FLAG(msix, MSIX, _flag)

+

+/*

+ *board specific private data structure

+ */

+struct alx_adapter {

+ struct net_device *netdev;

+ struct pci_dev *pdev;

+ struct net_device_stats net_stats;

+ bool netdev_registered;

+ u16 bd_number; /* board number;*/

+

+ struct alx_msix_param *msix[ALX_MAX_MSIX_INTRS];

+ struct msix_entry *msix_entries;

+ int num_msix_rxques;

+ int num_msix_txques;

+ int num_msix_noques; /* true count of msix_noques for device */

+ int num_msix_intrs;

+

+ int min_msix_intrs;

+ int max_msix_intrs;

+

+ /* All Descriptor memory */

+ struct alx_ring_header ring_header;

+

+ /* TX */

+ struct alx_tx_queue *tx_queue[ALX_MAX_TX_QUEUES];

+ /* RX */

+ struct alx_rx_queue *rx_queue[ALX_MAX_RX_QUEUES];

+

+ u16 num_txques;

+ u16 num_rxques; /* equal max(num_hw_rxques, num_sw_rxques) */

+ u16 num_hw_rxques;

+ u16 num_sw_rxques;

+ u16 max_rxques;

+ u16 max_txques;

+

+ u16 num_txdescs;

+ u16 num_rxdescs;

+

+ u32 rxbuf_size;

+

+ /* structs defined in alx_hw.h */

+ struct alx_hw hw;

+ struct alx_hw_stats hw_stats;

+

+ u32 *config_space;

+

+ struct work_struct alx_task;

+ struct timer_list alx_timer;

+

+ unsigned long link_jiffies;

+

+ u32 wol;

+ bool cifs;

+ int bars;

+ bool ioport;

+ spinlock_t tx_lock;

+ spinlock_t rx_lock;

+ atomic_t irq_sem;

+

+#ifdef CONFIG_ALX_DEBUGFS

+ struct alx_debugfs_param dfs;

+#endif

+ u16 msg_enable;

+ unsigned long flags;

+};

+

+#define ALX_ADPT_FLAG_MSI_CAP 0x00000001

+#define ALX_ADPT_FLAG_MSI_EN 0x00000002

+#define ALX_ADPT_FLAG_MSIX_CAP 0x00000004

+#define ALX_ADPT_FLAG_MSIX_EN 0x00000008

+#define ALX_ADPT_FLAG_MRQ_CAP 0x00000010

+#define ALX_ADPT_FLAG_MRQ_EN 0x00000020

+#define ALX_ADPT_FLAG_MTQ_CAP 0x00000040

+#define ALX_ADPT_FLAG_MTQ_EN 0x00000080

+#define ALX_ADPT_FLAG_SRSS_CAP 0x00000100

+#define ALX_ADPT_FLAG_SRSS_EN 0x00000200

+#define ALX_ADPT_FLAG_FIXED_MSIX 0x00000400

+

+#define ALX_ADPT_FLAG_TASK_REINIT_REQ 0x00010000 /* reinit */

+#define ALX_ADPT_FLAG_TASK_LSC_REQ 0x00020000

+

+#define ALX_ADPT_FLAG_STATE_TESTING 0x00100000

+#define ALX_ADPT_FLAG_STATE_RESETTING 0x00200000

+#define ALX_ADPT_FLAG_STATE_DOWN 0x00400000

+#define ALX_ADPT_FLAG_STATE_WATCH_DOG 0x00800000

+#define ALX_ADPT_FLAG_STATE_DIAG_RUNNING 0x01000000

+#define ALX_ADPT_FLAG_STATE_INACTIVE 0x02000000

+

+

+#define CHK_ADPT_FLAG(_flag) CHK_FLAG(adpt, ADPT, _flag)

+#define SET_ADPT_FLAG(_flag) SET_FLAG(adpt, ADPT, _flag)

+#define CLI_ADPT_FLAG(_flag) CLI_FLAG(adpt, ADPT, _flag)

+

+/* default to trying for four seconds */

+#define ALX_TRY_LINK_TIMEOUT (4 * HZ)

+

+

+#define ALX_OPEN_CTRL_IRQ_EN 0x00000001

+#define ALX_OPEN_CTRL_RESET_MAC 0x00000002

+#define ALX_OPEN_CTRL_RESET_PHY 0x00000004

+#define ALX_OPEN_CTRL_RESET_ALL (\

+ ALX_OPEN_CTRL_RESET_MAC |\

+ ALX_OPEN_CTRL_RESET_PHY)

+

+/* needed by alx_ethtool.c */

+extern char alx_drv_name[];

+extern void alx_reinit_locked(struct alx_adapter *adpt);

+extern void alx_set_ethtool_ops(struct net_device *netdev);

+#ifdef ETHTOOL_OPS_COMPAT

+extern int ethtool_ioctl(struct ifreq *ifr);

+#endif

+

+/* needed by alx_dfs.c */

+int alx_validate_mac_addr(u8 *mac_addr);

+bool alx_set_tpdesc(struct alx_tx_queue *txque, union alx_sw_tpdesc *stpd);

+void alx_set_tpdesc_lastfrag(struct alx_tx_queue *txque);

+int alx_open_internal(struct alx_adapter *adpt, u32 ctrl);

+void alx_stop_internal(struct alx_adapter *adpt, u32 ctrl);

+void alx_disable_intr(struct alx_adapter *adpt);

+

+#endif /* _ALX_H_ */

diff --git a/drivers/net/ethernet/atheros/alx/alx_abs.c b/drivers/net/ethernet/atheros/alx/alx_abs.c

new file mode 100644

index 0000000..b039795

--- /dev/null

+++ b/drivers/net/ethernet/atheros/alx/alx_abs.c

@@ -0,0 +1,1055 @@

+/*

+ * Copyright (c) 2012 Qualcomm Atheros, Inc.

+ *

+ * Permission to use, copy, modify, and/or distribute this software for any

+ * purpose with or without fee is hereby granted, provided that the above

+ * copyright notice and this permission notice appear in all copies.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES

+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR

+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES

+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN

+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF

+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

+ */

+

+#include

+#include

+#include

+#include

+

+#include "alx_hw.h"

+

+#define ALF_REV_ID_AR8161_B0 0x10

+

+/* definition for MSIX */

+#define ALF_MSIX_ENTRY_BASE 0x2000

+#define ALF_MSIX_ENTRY_SIZE 16

+#define ALF_MSIX_MSG_LOADDR_OFF 0

+#define ALF_MSIX_MSG_HIADDR_OFF 4

+#define ALF_MSIX_MSG_DATA_OFF 8

+#define ALF_MSIX_MSG_CTRL_OFF 12

+

+#define ALF_MSIX_INDEX_RXQ0 0

+#define ALF_MSIX_INDEX_RXQ1 1

+#define ALF_MSIX_INDEX_RXQ2 2

+#define ALF_MSIX_INDEX_RXQ3 3

+#define ALF_MSIX_INDEX_RXQ4 4

+#define ALF_MSIX_INDEX_RXQ5 5

+#define ALF_MSIX_INDEX_RXQ6 6

+#define ALF_MSIX_INDEX_RXQ7 7

+#define ALF_MSIX_INDEX_TXQ0 8

+#define ALF_MSIX_INDEX_TXQ1 9

+#define ALF_MSIX_INDEX_TXQ2 10

+#define ALF_MSIX_INDEX_TXQ3 11

+#define ALF_MSIX_INDEX_TIMER 12

+#define ALF_MSIX_INDEX_ALERT 13

+#define ALF_MSIX_INDEX_SMB 14

+#define ALF_MSIX_INDEX_PHY 15

+

+

+#define ALF_SRAM_BASE L1F_SRAM0

+#define ALF_SRAM(_i, _type) \

+ (ALF_SRAM_BASE + ((_i) * sizeof(_type)))

+

+#define ALF_MIB_BASE L1F_MIB_BASE

+#define ALF_MIB(_i, _type) \

+ (ALF_MIB_BASE + ((_i) * sizeof(_type)))

+

+/* definition for RSS */

+#define ALF_RSS_KEY_BASE L1F_RSS_KEY0

+#define ALF_RSS_IDT_BASE L1F_RSS_IDT_TBL0

+#define ALF_RSS_KEY(_i, _type) \

+ (ALF_RSS_KEY_BASE + ((_i) * sizeof(_type)))

+#define ALF_RSS_TBL(_i, _type) \

+ (L1F_RSS_IDT_TBL0 + ((_i) * sizeof(_type)))

+

+

+/* NIC */

+int alf_identify_nic(struct alx_hw *hw)

+{

+ u32 drv;

+

+ if (hw->pci_revid
pci_revid) {

+ default:

+ alx_mem_r32(hw, L1F_DRV, &drv);

+ if (drv & LX_DRV_DISABLE)

+ return -EINVAL;

+ break;

+ }

+ return 0;

+}

+

+

+/* PHY */

+int alf_read_phy_reg(struct alx_hw *hw, u16 reg_addr, u16 *phy_data)

+{

+ unsigned long flags;

+ int retval = 0;

+

+ spin_lock_irqsave(&hw->mdio_lock, flags);

+

+ retval = l1f_read_phy(hw, false, ALX_MDIO_DEV_TYPE_NORM, false,

+ reg_addr, phy_data);

+ if (retval)

+ alx_hw_err(hw, "error:%u when read phy reg\n", retval);

+

+ spin_unlock_irqrestore(&hw->mdio_lock, flags);

+ return retval;

+}

+

+

+int alf_write_phy_reg(struct alx_hw *hw, u16 reg_addr, u16 phy_data)

+{

+ unsigned long flags;

+ int retval = 0;

+

+ spin_lock_irqsave(&hw->mdio_lock, flags);

+

+ retval = l1f_write_phy(hw, false, ALX_MDIO_DEV_TYPE_NORM, false,

+ reg_addr, phy_data);

+ if (retval)

+ alx_hw_err(hw, "error;%u, when write phy reg\n", retval);

+

+ spin_unlock_irqrestore(&hw->mdio_lock, flags);

+ return retval;

+}

+

+#ifdef CONFIG_ALX_DEBUGFS

+

+int alf_read_ext_phy_reg(struct alx_hw *hw, u8 type, u16 reg_addr,

+ u16 *phy_data)

+{

+ unsigned long flags;

+ int retval = 0;

+

+ spin_lock_irqsave(&hw->mdio_lock, flags);

+

+ retval = l1f_read_phy(hw, true, type, false, reg_addr, phy_data);

+ if (retval)

+ alx_hw_err(hw, "error:%u, when read ext phy reg\n", retval);

+

+ spin_unlock_irqrestore(&hw->mdio_lock, flags);

+ return retval;

+}

+

+

+int alf_write_ext_phy_reg(struct alx_hw *hw, u8 type, u16 reg_addr,

+ u16 phy_data)

+{

+ unsigned long flags;

+ int retval = 0;

+

+ spin_lock_irqsave(&hw->mdio_lock, flags);

+

+ retval = l1f_write_phy(hw, true, type, false, reg_addr, phy_data);

+ if (retval)

+ alx_hw_err(hw, "error:%u, when write ext phy reg\n", retval);

+

+

+ spin_unlock_irqrestore(&hw->mdio_lock, flags);

+ return retval;

+}

+

+#endif

+

+int alf_init_phy(struct alx_hw *hw)

+{

+ u16 phy_id[2];

+ int retval;

+

+ spin_lock_init(&hw->mdio_lock);

+

+ retval = alf_read_phy_reg(hw, MII_PHYSID1, &phy_id[0]);

+ if (retval)

+ return retval;

+ retval = alf_read_phy_reg(hw, MII_PHYSID2, &phy_id[1]);

+ if (retval)

+ return retval;

+ memcpy(&hw->phy_id, phy_id, sizeof(hw->phy_id));

+

+ hw->autoneg_advertised = LX_LC_ALL;

+

+ return retval;

+}

+

+

+int alf_reset_phy(struct alx_hw *hw)

+{

+ int retval = 0;

+

+ CLI_HW_FLAG(PWSAVE_EN);

+ CLI_HW_FLAG(AZ_EN);

+ CLI_HW_FLAG(PTP_EN);

+

+ if (CHK_HW_FLAG(PWSAVE_CAP))

+ SET_HW_FLAG(PWSAVE_EN);

+

+ if (CHK_HW_FLAG(AZ_CAP))

+ SET_HW_FLAG(AZ_EN);

+

+ if (CHK_HW_FLAG(PTP_CAP))

+ SET_HW_FLAG(PTP_EN);

+

+ alx_hw_info(hw, "reset PHY, pws = %d, az = %d, ptp = %d\n",

+ CHK_HW_FLAG(PWSAVE_EN), CHK_HW_FLAG(AZ_EN),

+ CHK_HW_FLAG(PTP_EN));

+ retval = l1f_reset_phy(hw, CHK_HW_FLAG(PWSAVE_EN), CHK_HW_FLAG(AZ_EN),

+ CHK_HW_FLAG(PTP_EN));

+ if (retval)

+ alx_hw_err(hw, "error when reset phy\n");

+

+ return retval;

+}

+

+

+/* LINK */

+int alf_setup_phy_link(struct alx_hw *hw, u8 speed, bool autoneg,

+ bool fc)

+{

+ int retval = 0;

+

+ if (!CHK_HW_FLAG(GIGA_CAP))

+ speed &= ~(LX_LC_1000F | LX_LC_1000H);

+

+ alx_hw_info(hw, "speed = 0x%x, autoneg = %d\n", speed, autoneg);

+ if (l1f_init_phy_spdfc(hw, autoneg, speed, fc)) {

+ alx_hw_err(hw, "error when init phy speed and fc\n");

+ retval = -EINVAL;

+ }

+

+ return retval;

+}

+

+

+int alf_check_phy_link(struct alx_hw *hw, u8 *speed, bool *link_up)

+{

+ u16 bmsr, giga;

+ int retval;

+

+ alf_read_phy_reg(hw, MII_BMSR, &bmsr);

+ retval = alf_read_phy_reg(hw, MII_BMSR, &bmsr);

+ if (retval)

+ return retval;

+

+ if (!(bmsr & BMSR_LSTATUS)) {

+ *link_up = false;

+ *speed = 0;

+ return retval;

+ }

+ *link_up = true;

+

+ /* Read PHY Specific Status Register (17) */

+ retval = alf_read_phy_reg(hw, L1F_MII_GIGA_PSSR, &giga);

+ if (retval)

+ return retval;

+

+

+ if (!(giga & L1F_GIGA_PSSR_SPD_DPLX_RESOLVED)) {

+ alx_hw_err(hw, "error for speed duplex resolved\n");

+ return -EINVAL;

+ }

+

+ switch (giga & L1F_GIGA_PSSR_SPEED) {

+ case L1F_GIGA_PSSR_1000MBS:

+ if (giga & L1F_GIGA_PSSR_DPLX)

+ *speed = LX_LC_1000F;

+ else

+ alx_hw_err(hw, "1000M half is invalid\n");

+ break;

+ case L1F_GIGA_PSSR_100MBS:

+ if (giga & L1F_GIGA_PSSR_DPLX)

+ *speed = LX_LC_100F;

+ else

+ *speed = LX_LC_100H;

+ break;

+ case L1F_GIGA_PSSR_10MBS:

+ if (giga & L1F_GIGA_PSSR_DPLX)

+ *speed = LX_LC_10F;

+ else

+ *speed = LX_LC_10H;

+ break;

+ default:

+ *speed = 0;

+ retval = -EINVAL;

+ break;

+ }

+ return retval;

+}

+

+int alf_post_phy_link(struct alx_hw *hw, bool az_en, bool link_up, u8 speed)

+{

+ return l1f_post_phy_link(hw, az_en, link_up, speed);

+}

+

+/*

+ * 1. stop_mac

+ * 2. reset mac & dma by reg1400(MASTER)

+ * 3. control speed/duplex, hash-alg

+ * 4. clock switch setting

+ */

+int alf_reset_mac(struct alx_hw *hw)

+{

+ int retval = 0;

+

+ retval = l1f_reset_mac(hw);

+ if (retval)

+ alx_hw_err(hw, "error(%d) when reset mac\n", retval);

+

+ return retval;

+}

+

+

+int alf_start_mac(struct alx_hw *hw)

+{

+ u16 en_ctrl = 0;

+ int retval = 0;

+

+ /* set link speed param */

+ switch (hw->link_speed) {

+ case LX_LC_1000F:

+ en_ctrl |= LX_MACSPEED_1000;

+ /* fall through */

+ case LX_LC_100F:

+ case LX_LC_10F:

+ en_ctrl |= LX_MACDUPLEX_FULL;

+ break;

+ }

+

+ /* set fc param*/

+ switch (hw->cur_fc_mode) {

+ case alx_fc_full:

+ en_ctrl |= LX_FC_RXEN; /* Flow Control RX Enable */

+ en_ctrl |= LX_FC_TXEN; /* Flow Control TX Enable */

+ break;

+ case alx_fc_rx_pause:

+ en_ctrl |= LX_FC_RXEN; /* Flow Control RX Enable */

+ break;

+ case alx_fc_tx_pause:

+ en_ctrl |= LX_FC_TXEN; /* Flow Control TX Enable */

+ break;

+ default:

+ break;

+ }

+

+ if (hw->fc_single_pause)

+ en_ctrl |= LX_SINGLE_PAUSE;

+

+ en_ctrl |= LX_FLT_DIRECT; /* RX Enable; and TX Always Enable */

+ en_ctrl |= LX_ADD_FCS;

+

+ en_ctrl |= hw->flags & ALX_HW_FLAG_LX_MASK;

+

+ if (l1f_enable_mac(hw, true, en_ctrl)) {

+ alx_hw_err(hw, "error when start mac\n");

+ retval = -EINVAL;

+ }

+ return retval;

+}

+

+

+/*

+ * 1. stop RXQ (reg15A0) and TXQ (reg1590)

+ * 2. stop MAC (reg1480)

+ */

+int alf_stop_mac(struct alx_hw *hw)

+{

+ if (l1f_enable_mac(hw, false, 0)) {

+ alx_hw_err(hw, "error when stop mac\n");

+ return -EINVAL;

+ }

+ return 0;

+}

+

+

+int alf_init_mac(struct alx_hw *hw, u16 rxbuf_sz, u16 rx_qnum,

+ u16 rxring_sz, u16 tx_qnum, u16 txring_sz)

+{

+ int retval = 0;

+

+ l1f_init_mac_misc(hw, hw->mac_addr, hw->smb_timer, hw->imt_mod, true);

+

+ retval = l1f_init_mac_rtx_ring_desc(hw, hw->dma.rfdmem_hi[0],

+ hw->dma.rfdmem_lo[0], hw->dma.rrdmem_lo[0],

+ rxring_sz, rxbuf_sz,

+ hw->dma.tpdmem_hi[0], hw->dma.tpdmem_lo,

+ tx_qnum, txring_sz);

+ if (retval) {

+ alx_hw_err(hw, "error(%d) when init mac\n", retval);

+ return retval;

+ }

+

+ /* the mtu equals hw->mtu + length of ether header */

+ l1f_init_mac_rtx_queue(hw, hw->mtu + ALX_ETH_LENGTH_OF_HEADER);

+

+ l1f_init_mac_dma(hw);

+

+ return retval;

+}

+

+

+int alf_reset_pcie(struct alx_hw *hw, bool l0s_en, bool l1_en)

+{

+ int retval = 0;

+

+ if (!CHK_HW_FLAG(L0S_CAP))

+ l0s_en = false;

+

+ if (l0s_en)

+ SET_HW_FLAG(L0S_EN);

+ else

+ CLI_HW_FLAG(L0S_EN);

+

+

+ if (!CHK_HW_FLAG(L1_CAP))

+ l1_en = false;

+

+ if (l1_en)

+ SET_HW_FLAG(L1_EN);

+ else

+ CLI_HW_FLAG(L1_EN);

+

+ if (l1f_reset_pcie(hw, l0s_en, l1_en)) {

+ alx_hw_err(hw, "error when reset pcie\n");

+ retval = -EINVAL;

+ }

+ return retval;

+}

+

+

+int alf_config_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en)

+{

+ int retval = 0;

+

+ if (!CHK_HW_FLAG(L0S_CAP))

+ l0s_en = false;

+

+ if (l0s_en)

+ SET_HW_FLAG(L0S_EN);

+ else

+ CLI_HW_FLAG(L0S_EN);

+

+ if (!CHK_HW_FLAG(L1_CAP))

+ l1_en = false;

+

+ if (l1_en)

+ SET_HW_FLAG(L1_EN);

+ else

+ CLI_HW_FLAG(L1_EN);

+

+ if (l1f_enable_aspm(hw, l0s_en, l1_en, 0)) {

+ alx_hw_err(hw, "error when enable aspm\n");

+ retval = -EINVAL;

+ }

+ return retval;

+}

+

+

+int alf_config_wol(struct alx_hw *hw, u32 wufc)

+{

+ u32 wol;

+ int retval = 0;

+

+ wol = 0;

+ /* turn on magic packet event */

+ if (wufc & ALX_WOL_MAGIC) {

+ wol |= L1F_WOL0_MAGIC_EN | L1F_WOL0_PME_MAGIC_EN;

+ /* magic packet maybe Broadcast&multicast&Unicast frame */

+ /* mac |= MAC_CTRL_BC_EN; */

+ }

+

+ /* turn on link up event */

+ if (wufc & ALX_WOL_PHY) {

+ wol |= L1F_WOL0_LINK_EN | L1F_WOL0_PME_LINK;

+ /* only link up can wake up */

+ retval = alf_write_phy_reg(hw, L1F_MII_IER, L1F_IER_LINK_UP);

+ }

+ alx_mem_w32(hw, L1F_WOL0, wol);

+ return retval;

+}

+

+void alf_update_mac_filter(struct alx_hw *hw)

+{

+ u32 mac;

+ u32 flg_hw_map[] = {

+ ALX_HW_FLAG_BROADCAST_EN, L1F_MAC_CTRL_BRD_EN,

+ ALX_HW_FLAG_VLANSTRIP_EN, L1F_MAC_CTRL_VLANSTRIP,

+ ALX_HW_FLAG_PROMISC_EN, L1F_MAC_CTRL_PROMISC_EN,

+ ALX_HW_FLAG_MULTIALL_EN, L1F_MAC_CTRL_MULTIALL_EN,

+ ALX_HW_FLAG_LOOPBACK_EN, L1F_MAC_CTRL_LPBACK_EN

+ };

+ int i;

+

+

+ alx_mem_r32(hw, L1F_MAC_CTRL, &mac);

+

+ for (i = 0; i
flags & flg_hw_map)

+ mac |= flg_hw_map[i + 1];

+ else

+ mac &= ~flg_hw_map[i + 1];

+ }

+

+ alx_mem_w32(hw, L1F_MAC_CTRL, mac);

+}

+

+

+int alf_config_pow_save(struct alx_hw *hw, u8 speed, bool wol_en,

+ bool tx_en, bool rx_en, bool pws_en)

+{

+ int retval = 0;

+

+ if (l1f_powersaving(hw, speed, wol_en, tx_en, rx_en, pws_en)) {

+ alx_hw_err(hw, "error when set power saving\n");

+ retval = -EINVAL;

+ }

+ return retval;

+}

+

+

+/* RAR, Multicast, VLAN */

+void alf_set_mac_addr(struct alx_hw *hw, u8 *addr)

+{

+ u32 sta;

+

+ /*

+ * for example: 00-0B-6A-F6-00-DC

+ * 0
6AF600DC, 1
000B.

+ */

+

+ /* low dword */

+ sta = addr[2]
> 31) & 0x1;

+ bit = (crc32 >> 26) & 0x1F;

+

+ alx_mem_r32(hw, L1F_HASH_TBL0 + (reg
wrr_mode) {

+ case alx_wrr_mode_none:

+ FIELD_SETL(wrr, L1F_WRR_PRI, L1F_WRR_PRI_RESTRICT_NONE);

+ break;

+ case alx_wrr_mode_high:

+ FIELD_SETL(wrr, L1F_WRR_PRI, L1F_WRR_PRI_RESTRICT_HI);

+ break;

+ case alx_wrr_mode_high2:

+ FIELD_SETL(wrr, L1F_WRR_PRI, L1F_WRR_PRI_RESTRICT_HI2);

+ break;

+ case alx_wrr_mode_all:

+ FIELD_SETL(wrr, L1F_WRR_PRI, L1F_WRR_PRI_RESTRICT_ALL);

+ break;

+ }

+ FIELD_SETL(wrr, L1F_WRR_PRI0, hw->wrr_prio0);

+ FIELD_SETL(wrr, L1F_WRR_PRI1, hw->wrr_prio1);

+ FIELD_SETL(wrr, L1F_WRR_PRI2, hw->wrr_prio2);

+ FIELD_SETL(wrr, L1F_WRR_PRI3, hw->wrr_prio3);

+ alx_mem_w32(hw, L1F_WRR, wrr);

+}

+

+

+int alf_config_msix(struct alx_hw *hw, u16 num_intrs, bool msix_en, bool msi_en)

+{

+ u32 map[2];

+ u32 type;

+ int msix_idx;

+

+ if (!msix_en)

+ goto configure_legacy;

+

+ memset(map, 0, sizeof(map));

+ for (msix_idx = 0; msix_idx
intr_mask);

+ return 0;

+}

+

+

+int alf_disable_legacy_intr(struct alx_hw *hw)

+{

+ alx_mem_w32(hw, L1F_ISR, L1F_ISR_DIS);

+ alx_mem_w32(hw, L1F_IMR, 0);

+ alx_mem_flush(hw);

+ return 0;

+}

+

+

+int alf_enable_msix_intr(struct alx_hw *hw, u8 entry_idx)

+{

+ u32 ctrl_reg;

+

+ ctrl_reg = ALF_MSIX_ENTRY_BASE + (entry_idx * ALF_MSIX_ENTRY_SIZE) +

+ ALF_MSIX_MSG_CTRL_OFF;

+

+ alx_mem_w32(hw, ctrl_reg, 0x0);

+ alx_mem_flush(hw);

+ return 0;

+}

+

+

+int alf_disable_msix_intr(struct alx_hw *hw, u8 entry_idx)

+{

+ u32 ctrl_reg;

+

+ ctrl_reg = ALF_MSIX_ENTRY_BASE + (entry_idx * ALF_MSIX_ENTRY_SIZE) +

+ ALF_MSIX_MSG_CTRL_OFF;

+

+ alx_mem_w32(hw, ctrl_reg, 0x1);

+ alx_mem_flush(hw);

+ return 0;

+}

+

+

+/* RSS */

+int alf_config_rss(struct alx_hw *hw, bool rss_en)

+{

+ int key_len_by_u8 = sizeof(hw->rss_key);

+ int idt_len_by_u32 = sizeof(hw->rss_idt) / sizeof(u32);

+ u32 rxq0;

+ int i;

+

+ /* Fill out hash function keys */

+ for (i = 0; i
rss_key[key_len_by_u8 - i - 1]);

+ }

+

+ /* Fill out redirection table */

+ for (i = 0; i
rss_idt);

+

+ alx_mem_w32(hw, L1F_RSS_BASE_CPU_NUM, hw->rss_base_cpu);

+

+ alx_mem_r32(hw, L1F_RXQ0, &rxq0);

+ if (hw->rss_hstype & ALX_RSS_HSTYP_IPV4_EN)

+ rxq0 |= L1F_RXQ0_RSS_HSTYP_IPV4_EN;

+ else

+ rxq0 &= ~L1F_RXQ0_RSS_HSTYP_IPV4_EN;

+

+ if (hw->rss_hstype & ALX_RSS_HSTYP_TCP4_EN)

+ rxq0 |= L1F_RXQ0_RSS_HSTYP_IPV4_TCP_EN;

+ else

+ rxq0 &= ~L1F_RXQ0_RSS_HSTYP_IPV4_TCP_EN;

+

+ if (hw->rss_hstype & ALX_RSS_HSTYP_IPV6_EN)

+ rxq0 |= L1F_RXQ0_RSS_HSTYP_IPV6_EN;

+ else

+ rxq0 &= ~L1F_RXQ0_RSS_HSTYP_IPV6_EN;

+

+ if (hw->rss_hstype & ALX_RSS_HSTYP_TCP6_EN)

+ rxq0 |= L1F_RXQ0_RSS_HSTYP_IPV6_TCP_EN;

+ else

+ rxq0 &= ~L1F_RXQ0_RSS_HSTYP_IPV6_TCP_EN;

+

+ FIELD_SETL(rxq0, L1F_RXQ0_RSS_MODE, hw->rss_mode);

+ FIELD_SETL(rxq0, L1F_RXQ0_IDT_TBL_SIZE, hw->rss_idt_size);

+

+ if (rss_en)

+ rxq0 |= L1F_RXQ0_RSS_HASH_EN;

+ else

+ rxq0 &= ~L1F_RXQ0_RSS_HASH_EN;

+

+ alx_mem_w32(hw, L1F_RXQ0, rxq0);

+ return 0;

+}

+

+

+/* fc */

+static int alf_get_fc_mode(struct alx_hw *hw, enum alx_fc_mode *mode)

+{

+ u16 bmsr, giga;

+ int i;

+ int retval = 0;

+

+ for (i = 0; i
disable_fc_autoneg) {

+ hw->fc_was_autonegged = false;

+ hw->cur_fc_mode = hw->req_fc_mode;

+ } else {

+ hw->fc_was_autonegged = true;

+ retval = alf_get_fc_mode(hw, &hw->cur_fc_mode);

+ if (retval)

+ return retval;

+ }

+

+ alx_mem_r32(hw, L1F_MAC_CTRL, &mac);

+

+ switch (hw->cur_fc_mode) {

+ case alx_fc_none: /* 0 */

+ mac &= ~(L1F_MAC_CTRL_RXFC_EN | L1F_MAC_CTRL_TXFC_EN);

+ break;

+ case alx_fc_rx_pause: /* 1 */

+ mac &= ~L1F_MAC_CTRL_TXFC_EN;

+ mac |= L1F_MAC_CTRL_RXFC_EN;

+ break;

+ case alx_fc_tx_pause: /* 2 */

+ mac |= L1F_MAC_CTRL_TXFC_EN;

+ mac &= ~L1F_MAC_CTRL_RXFC_EN;

+ break;

+ case alx_fc_full: /* 3 */

+ case alx_fc_default: /* 4 */

+ mac |= (L1F_MAC_CTRL_TXFC_EN | L1F_MAC_CTRL_RXFC_EN);

+ break;

+ default:

+ alx_hw_err(hw, "flow control param set incorrectly\n");

+ return -EINVAL;

+ break;

+ }

+

+ alx_mem_w32(hw, L1F_MAC_CTRL, mac);

+

+ return retval;

+}

+

+

+/* ethtool */

+void alf_get_ethtool_regs(struct alx_hw *hw, void *buff)

+{

+ int i;

+ u32 *val = buff;

+ static const u32 reg[] = {

+ /* 0 */

+ L1F_DEV_CAP, L1F_DEV_CTRL, L1F_LNK_CAP, L1F_LNK_CTRL,

+ L1F_UE_SVRT, L1F_EFLD, L1F_SLD, L1F_PPHY_MISC1,

+ L1F_PPHY_MISC2, L1F_PDLL_TRNS1,

+

+ /* 10 */

+ L1F_TLEXTN_STATS, L1F_EFUSE_CTRL, L1F_EFUSE_DATA, L1F_SPI_OP1,

+ L1F_SPI_OP2, L1F_SPI_OP3, L1F_EF_CTRL, L1F_EF_ADDR,

+ L1F_EF_DATA, L1F_SPI_ID,

+

+ /* 20 */

+ L1F_SPI_CFG_START, L1F_PMCTRL, L1F_LTSSM_CTRL, L1F_MASTER,

+ L1F_MANU_TIMER, L1F_IRQ_MODU_TIMER, L1F_PHY_CTRL, L1F_MAC_STS,

+ L1F_MDIO, L1F_MDIO_EXTN,

+

+ /* 30 */

+ L1F_PHY_STS, L1F_BIST0, L1F_BIST1, L1F_SERDES,

+ L1F_LED_CTRL, L1F_LED_PATN, L1F_LED_PATN2, L1F_SYSALV,

+ L1F_PCIERR_INST, L1F_LPI_DECISN_TIMER,

+

+ /* 40 */

+ L1F_LPI_CTRL, L1F_LPI_WAIT, L1F_HRTBT_VLAN, L1F_HRTBT_CTRL,

+ L1F_RXPARSE, L1F_MAC_CTRL, L1F_GAP, L1F_STAD1,

+ L1F_LED_CTRL, L1F_HASH_TBL0,

+

+ /* 50 */

+ L1F_HASH_TBL1, L1F_HALFD, L1F_DMA, L1F_WOL0,

+ L1F_WOL1, L1F_WOL2, L1F_WRR, L1F_HQTPD,

+ L1F_CPUMAP1, L1F_CPUMAP2,

+

+ /* 60 */

+ L1F_MISC, L1F_RX_BASE_ADDR_HI, L1F_RFD_ADDR_LO, L1F_RFD_RING_SZ,

+ L1F_RFD_BUF_SZ, L1F_RRD_ADDR_LO, L1F_RRD_RING_SZ,

+ L1F_RFD_PIDX, L1F_RFD_CIDX, L1F_RXQ0,

+

+ /* 70 */

+ L1F_RXQ1, L1F_RXQ2, L1F_RXQ3, L1F_TX_BASE_ADDR_HI,

+ L1F_TPD_PRI0_ADDR_LO, L1F_TPD_PRI1_ADDR_LO,

+ L1F_TPD_PRI2_ADDR_LO, L1F_TPD_PRI3_ADDR_LO,

+ L1F_TPD_PRI0_PIDX, L1F_TPD_PRI1_PIDX,

+

+ /* 80 */

+ L1F_TPD_PRI2_PIDX, L1F_TPD_PRI3_PIDX, L1F_TPD_PRI0_CIDX,

+ L1F_TPD_PRI1_CIDX, L1F_TPD_PRI2_CIDX, L1F_TPD_PRI3_CIDX,

+ L1F_TPD_RING_SZ, L1F_TXQ0, L1F_TXQ1, L1F_TXQ2,

+

+ /* 90 */

+ L1F_MSI_MAP_TBL1, L1F_MSI_MAP_TBL2, L1F_MSI_ID_MAP,

+ L1F_MSIX_MASK, L1F_MSIX_PENDING,

+ };

+

+ for (i = 0; i
mac_type == alx_mac_l1f)

+ SET_HW_FLAG(GIGA_CAP);

+

+ /* set flags of alx_phy_info */

+ SET_HW_FLAG(PWSAVE_CAP);

+}

+

+

+/* alc_set_hw_info */

+static void alf_set_hw_infos(struct alx_hw *hw)

+{

+ hw->rxstat_reg = L1F_MIB_RX_OK;

+ hw->rxstat_sz = 0x60;

+ hw->txstat_reg = L1F_MIB_TX_OK;

+ hw->txstat_sz = 0x68;

+

+ hw->rx_prod_reg[0] = L1F_RFD_PIDX;

+ hw->rx_cons_reg[0] = L1F_RFD_CIDX;

+

+ hw->tx_prod_reg[0] = L1F_TPD_PRI0_PIDX;

+ hw->tx_cons_reg[0] = L1F_TPD_PRI0_CIDX;

+ hw->tx_prod_reg[1] = L1F_TPD_PRI1_PIDX;

+ hw->tx_cons_reg[1] = L1F_TPD_PRI1_CIDX;

+ hw->tx_prod_reg[2] = L1F_TPD_PRI2_PIDX;

+ hw->tx_cons_reg[2] = L1F_TPD_PRI2_CIDX;

+ hw->tx_prod_reg[3] = L1F_TPD_PRI3_PIDX;

+ hw->tx_cons_reg[3] = L1F_TPD_PRI3_CIDX;

+

+ hw->hwreg_sz = 0x200;

+ hw->eeprom_sz = 0;

+}

+

+

+/*

+ * alf_init_hw

+ */

+void alf_init_hw(struct alx_hw *hw)

+{

+ alf_set_hw_capabilities(hw);

+ alf_set_hw_infos(hw);

+

+ alx_hw_info(hw, "HW Flags = 0x%x\n", hw->flags);

+}

diff --git a/drivers/net/ethernet/atheros/alx/alx_cifs.c b/drivers/net/ethernet/atheros/alx/alx_cifs.c

new file mode 100644

index 0000000..864747d

--- /dev/null

+++ b/drivers/net/ethernet/atheros/alx/alx_cifs.c

@@ -0,0 +1,307 @@

+/*

+ * Copyright (c) 2012 Qualcomm Atheros, Inc.

+ *

+ * Permission to use, copy, modify, and/or distribute this software for any

+ * purpose with or without fee is hereby granted, provided that the above

+ * copyright notice and this permission notice appear in all copies.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES

+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR

+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES

+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN

+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF

+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

+ */

+

+#include "alx.h"

+#include "alx_hw.h"

+

+/*

+ * Desc: CIFS offload, config the ANNOUNCEMENT message to our adapter.

+ */

+static void alf_setup_cifs(struct alx_hw *hw)

+{

+ u32 ctrl;

+ u32 i;

+ struct alx_swoi *swoi = &hw->swoi_offload;

+

+ if (!swoi->len) {

+ alx_hw_err(hw, "CIFS offload disabled.\n");

+ return;

+ }

+

+ /* Write ANNOUNCEMENT message to SRAM. */

+ for (i = 0; i
len; i += 4) {

+ alx_mem_w32(hw, hw->annce_addr_off + i,

+ *(u32 *) &swoi->msg);

+ }

+

+ ctrl = 0;

+ FIELD_SETL(ctrl, L1F_HRTBT_CTRL_PKTLEN, swoi->len);

+ FIELD_SETL(ctrl, L1F_HRTBT_CTRL_HDRADDR,

+ ((hw->annce_addr_off - PACKET_MAP_ADDR) >> 3));

+ if (swoi->is_vlan)

+ ctrl |= L1F_HRTBT_CTRL_HASVLAN;

+

+ /* The registration packet send period.

+ * 1bit = 2s. nAnncePeriod = (pkt_send_period+1) *2

+ */

+ FIELD_SETL(ctrl, L1F_HRTBT_CTRL_PERIOD, swoi->period / 2 - 1);

+ ctrl |= L1F_HRTBT_CTRL_EN;

+ alx_mem_w32(hw, L1F_HRTBT_CTRL, ctrl);

+ alx_hw_info(hw,

+ "ANNOUNCEMENT message annce_base_addr[0x%08x], len%d, "

+ "%s vlan, Reg%04x-%08x\n",

+ (hw->annce_addr_off - PACKET_MAP_ADDR) >> 3, swoi->len,

+ swoi->is_vlan ? "has" : "no", L1F_HRTBT_CTRL, ctrl);

+

+ hw->annce_addr_off =

+ (hw->annce_addr_off + swoi->len + 0x0F) & 0xFFFFFFF0;

+

+ /* Enable magic because cifs needs it. */

+ alx_mem_r32(hw, L1F_WOL0, &ctrl);

+ ctrl |= (L1F_WOL0_MAGIC_EN | L1F_WOL0_PME_MAGIC_EN);

+

+ alx_mem_w32(hw, L1F_WOL0, ctrl);

+}

+

+

+/*

+ * Desc: CIFS offload, config the ANNOUNCEMENT message to our adapter.

+ */

+static void alf_setup_swoi(struct alx_hw *hw)

+{

+ u32 ctrl;

+ u32 i;

+ struct alx_swoi *swoi = &hw->swoi_offload;

+

+ if (!swoi->len) {

+ alx_hw_err(hw, "SWOI offload disabled.\n");

+ return;

+ }

+

+ /* Write ANNOUNCEMENT message to SRAM. */

+ for (i = 0; i
total_len; i += 4) {

+ alx_mem_w32(hw, hw->annce_addr_off + i,

+ *(u32 *) &swoi->msg);

+ }

+

+ ctrl = 0;

+ FIELD_SETL(ctrl, L1F_HRTBT_CTRL_PKTLEN, swoi->len);

+ FIELD_SETL(ctrl, L1F_HRTBT_CTRL_HDRADDRB0,

+ ((hw->annce_addr_off - PACKET_MAP_ADDR) >> 4));

+ if (swoi->fraged)

+ ctrl |= L1F_HRTBT_CTRL_PKT_FRAG;

+

+ if (swoi->is_vlan)

+ ctrl |= L1F_HRTBT_CTRL_HASVLAN;

+

+ /* The registration packet send period.

+ * 1bit = 2s. nAnncePeriod = (pkt_send_period+1) *2

+ */

+ FIELD_SETL(ctrl, L1F_HRTBT_CTRL_PERIOD, swoi->period / 2 - 1);

+ ctrl |= L1F_HRTBT_CTRL_EN;

+ alx_mem_w32(hw, L1F_HRTBT_CTRL, ctrl);

+ alx_hw_info(hw,

+ "ANNOUNCEMENT message annce_base_addr[0x%08x], len%d, "

+ "%s frag, %s vlan, Reg%04x-%08x\n",

+ (hw->annce_addr_off - PACKET_MAP_ADDR) >> 3, swoi->len,

+ swoi->fraged ? "has" : "no", swoi->is_vlan ? "has" : "no",

+ L1F_HRTBT_CTRL, ctrl);

+

+ ctrl = 0;

+ FIELD_SETL(ctrl, L1F_HRTBT_EXT_CTRL_FRAG_LEN, swoi->frag_len);

+ if (swoi->pkt_is_8023)

+ ctrl |= L1F_HRTBT_EXT_CTRL_IS_8023;

+ if (swoi->pkt_is_ipv6)

+ ctrl |= L1F_HRTBT_EXT_CTRL_IS_IPV6;

+

+ ctrl |= L1F_HRTBT_EXT_CTRL_WAKEUP_EN | (swoi->pkt_is_ipv6 ?

+ L1F_HRTBT_EXT_CTRL_NS_EN :

+ L1F_HRTBT_EXT_CTRL_ARP_EN);

+ alx_mem_w32(hw, L1F_HRTBT_EXT_CTRL, ctrl);

+ alx_mem_r32(hw, L1F_PMOFLD, &ctrl);

+ /* Config host mac address. */

+ alx_mem_r32(hw, L1F_STAD0, &i);

+ alx_mem_w32(hw, L1F_ARP_MAC0, i);

+ /* alx_mem_w32(hw, L1F_1ST_NS_MAC0, i); */

+ alx_mem_w32(hw, L1F_2ND_NS_MAC0, i);

+ alx_mem_r32(hw, L1F_STAD1, &i);

+ alx_mem_w32(hw, L1F_ARP_MAC1, i);

+ /* alx_mem_w32(hw, L1F_1ST_NS_MAC1, i); */

+ alx_mem_w32(hw, L1F_2ND_NS_MAC1, i);

+

+ if (swoi->pkt_is_ipv6) {

+ alx_mem_w32(hw, L1F_HRTBT_REM_IPV6_ADDR3,

+ swoi->svr_ipv6_addr[0]);

+ alx_mem_w32(hw, L1F_HRTBT_REM_IPV6_ADDR2,

+ swoi->svr_ipv6_addr[1]);

+ alx_mem_w32(hw, L1F_HRTBT_REM_IPV6_ADDR1,

+ swoi->svr_ipv6_addr[2]);

+ alx_mem_w32(hw, L1F_HRTBT_REM_IPV6_ADDR0,

+ swoi->svr_ipv6_addr[3]);

+ alx_mem_w32(hw, L1F_2ND_TAR_IPV6_1_3,

+ swoi->host_ipv6_addr[0]);

+ alx_mem_w32(hw, L1F_2ND_TAR_IPV6_1_2,

+ swoi->host_ipv6_addr[1]);

+ alx_mem_w32(hw, L1F_2ND_TAR_IPV6_1_1,

+ swoi->host_ipv6_addr[2]);

+ alx_mem_w32(hw, L1F_2ND_TAR_IPV6_1_0,

+ swoi->host_ipv6_addr[3]);

+ alx_mem_w32(hw, L1F_2ND_SN_IPV6_3, swoi->host_ipv6_addr[0]);

+ alx_mem_w32(hw, L1F_2ND_SN_IPV6_2, swoi->host_ipv6_addr[1]);

+ alx_mem_w32(hw, L1F_2ND_SN_IPV6_1, swoi->host_ipv6_addr

Show more