diff --git a/debian/changelog b/debian/changelog index 321b593c6..04100dba1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,6 +8,9 @@ linux-2.6 (2.6.32-3) UNRELEASED; urgency=high * Input: ALPS - add support for touchpads with 4-directional button * Input: ALPS - add interleaved protocol support (Dell E6x00 series) (Closes: #561589) + + [ Ben Hutchings ] + * sfc: Apply changes from 2.6.33-rc1 adding support for SFC9000 family -- Martin Michlmayr Fri, 18 Dec 2009 15:34:01 +0000 diff --git a/debian/patches/features/all/ethtool-Add-reset-operation.patch b/debian/patches/features/all/ethtool-Add-reset-operation.patch new file mode 100644 index 000000000..c886a6c4f --- /dev/null +++ b/debian/patches/features/all/ethtool-Add-reset-operation.patch @@ -0,0 +1,122 @@ +From d73d3a8cb4723e161589864741d8528d70b350eb Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Mon, 5 Oct 2009 10:59:58 +0000 +Subject: [PATCH] ethtool: Add reset operation + +After updating firmware stored in flash, users may wish to reset the +relevant hardware and start the new firmware immediately. This should +not be completely automatic as it may be disruptive. + +A selective reset may also be useful for debugging or diagnostics. + +This adds a separate reset operation which takes flags indicating the +components to be reset. Drivers are allowed to reset only a subset of +those requested, and must indicate the actual subset. This allows the +use of generic component masks and some future expansion. + +Signed-off-by: Ben Hutchings +Signed-off-by: David S. Miller +--- + include/linux/ethtool.h | 32 ++++++++++++++++++++++++++++++++ + net/core/ethtool.c | 23 +++++++++++++++++++++++ + 2 files changed, 55 insertions(+), 0 deletions(-) + +diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h +index aa0dcb3..eb1a48d 100644 +--- a/include/linux/ethtool.h ++++ b/include/linux/ethtool.h +@@ -498,6 +498,7 @@ struct ethtool_ops { + int (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, void *); + int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); + int (*flash_device)(struct net_device *, struct ethtool_flash *); ++ int (*reset)(struct net_device *, u32 *); + }; + #endif /* __KERNEL__ */ + +@@ -555,6 +556,7 @@ struct ethtool_ops { + #define ETHTOOL_SRXCLSRLDEL 0x00000031 /* Delete RX classification rule */ + #define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */ + #define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ ++#define ETHTOOL_RESET 0x00000034 /* Reset hardware */ + + /* compatibility with older code */ + #define SPARC_ETH_GSET ETHTOOL_GSET +@@ -685,4 +687,34 @@ struct ethtool_ops { + + #define RX_CLS_FLOW_DISC 0xffffffffffffffffULL + ++/* Reset flags */ ++/* The reset() operation must clear the flags for the components which ++ * were actually reset. On successful return, the flags indicate the ++ * components which were not reset, either because they do not exist ++ * in the hardware or because they cannot be reset independently. The ++ * driver must never reset any components that were not requested. ++ */ ++enum ethtool_reset_flags { ++ /* These flags represent components dedicated to the interface ++ * the command is addressed to. Shift any flag left by ++ * ETH_RESET_SHARED_SHIFT to reset a shared component of the ++ * same type. ++ */ ++ ETH_RESET_MGMT = 1 << 0, /* Management processor */ ++ ETH_RESET_IRQ = 1 << 1, /* Interrupt requester */ ++ ETH_RESET_DMA = 1 << 2, /* DMA engine */ ++ ETH_RESET_FILTER = 1 << 3, /* Filtering/flow direction */ ++ ETH_RESET_OFFLOAD = 1 << 4, /* Protocol offload */ ++ ETH_RESET_MAC = 1 << 5, /* Media access controller */ ++ ETH_RESET_PHY = 1 << 6, /* Transceiver/PHY */ ++ ETH_RESET_RAM = 1 << 7, /* RAM shared between ++ * multiple components */ ++ ++ ETH_RESET_DEDICATED = 0x0000ffff, /* All components dedicated to ++ * this interface */ ++ ETH_RESET_ALL = 0xffffffff, /* All components used by this ++ * interface, even if shared */ ++}; ++#define ETH_RESET_SHARED_SHIFT 16 ++ + #endif /* _LINUX_ETHTOOL_H */ +diff --git a/net/core/ethtool.c b/net/core/ethtool.c +index e195108..d8aee58 100644 +--- a/net/core/ethtool.c ++++ b/net/core/ethtool.c +@@ -302,6 +302,26 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) + return ret; + } + ++static int ethtool_reset(struct net_device *dev, char __user *useraddr) ++{ ++ struct ethtool_value reset; ++ int ret; ++ ++ if (!dev->ethtool_ops->reset) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&reset, useraddr, sizeof(reset))) ++ return -EFAULT; ++ ++ ret = dev->ethtool_ops->reset(dev, &reset.data); ++ if (ret) ++ return ret; ++ ++ if (copy_to_user(useraddr, &reset, sizeof(reset))) ++ return -EFAULT; ++ return 0; ++} ++ + static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) + { + struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; +@@ -1089,6 +1109,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) + case ETHTOOL_FLASHDEV: + rc = ethtool_flash_device(dev, useraddr); + break; ++ case ETHTOOL_RESET: ++ rc = ethtool_reset(dev, useraddr); ++ break; + default: + rc = -EOPNOTSUPP; + } +-- +1.6.5.4 + diff --git a/debian/patches/features/all/gro-Change-all-receive-functions-to-return-GRO-result.patch b/debian/patches/features/all/gro-Change-all-receive-functions-to-return-GRO-result.patch new file mode 100644 index 000000000..d140457dc --- /dev/null +++ b/debian/patches/features/all/gro-Change-all-receive-functions-to-return-GRO-result.patch @@ -0,0 +1,242 @@ +From c7c4b3b6e976b95facbb723951bdcd554a3530a4 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Thu, 29 Oct 2009 21:36:53 -0700 +Subject: [PATCH 2/2] gro: Change all receive functions to return GRO result codes + +This will allow drivers to adjust their receive path dynamically +based on whether GRO is being applied successfully. + +Currently all in-tree callers ignore the return values of these +functions and do not need to be changed. + +Signed-off-by: Ben Hutchings +Acked-by: Herbert Xu +Signed-off-by: David S. Miller +--- + include/linux/if_vlan.h | 25 ++++++++++++++----------- + include/linux/netdevice.h | 8 ++++---- + net/8021q/vlan_core.c | 16 +++++++++------- + net/core/dev.c | 38 +++++++++++++++----------------------- + 4 files changed, 42 insertions(+), 45 deletions(-) + +diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h +index 71a4870..153f6b9 100644 +--- a/include/linux/if_vlan.h ++++ b/include/linux/if_vlan.h +@@ -120,10 +120,12 @@ extern u16 vlan_dev_vlan_id(const struct net_device *dev); + extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, + u16 vlan_tci, int polling); + extern int vlan_hwaccel_do_receive(struct sk_buff *skb); +-extern int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, +- unsigned int vlan_tci, struct sk_buff *skb); +-extern int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, +- unsigned int vlan_tci); ++extern gro_result_t ++vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, ++ unsigned int vlan_tci, struct sk_buff *skb); ++extern gro_result_t ++vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, ++ unsigned int vlan_tci); + + #else + static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev) +@@ -150,17 +152,18 @@ static inline int vlan_hwaccel_do_receive(struct sk_buff *skb) + return 0; + } + +-static inline int vlan_gro_receive(struct napi_struct *napi, +- struct vlan_group *grp, +- unsigned int vlan_tci, struct sk_buff *skb) ++static inline gro_result_t ++vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, ++ unsigned int vlan_tci, struct sk_buff *skb) + { +- return NET_RX_DROP; ++ return GRO_DROP; + } + +-static inline int vlan_gro_frags(struct napi_struct *napi, +- struct vlan_group *grp, unsigned int vlan_tci) ++static inline gro_result_t ++vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, ++ unsigned int vlan_tci) + { +- return NET_RX_DROP; ++ return GRO_DROP; + } + #endif + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 6e777ef..193b637 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1483,17 +1483,17 @@ extern int netif_receive_skb(struct sk_buff *skb); + extern void napi_gro_flush(struct napi_struct *napi); + extern gro_result_t dev_gro_receive(struct napi_struct *napi, + struct sk_buff *skb); +-extern int napi_skb_finish(gro_result_t ret, struct sk_buff *skb); +-extern int napi_gro_receive(struct napi_struct *napi, ++extern gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb); ++extern gro_result_t napi_gro_receive(struct napi_struct *napi, + struct sk_buff *skb); + extern void napi_reuse_skb(struct napi_struct *napi, + struct sk_buff *skb); + extern struct sk_buff * napi_get_frags(struct napi_struct *napi); +-extern int napi_frags_finish(struct napi_struct *napi, ++extern gro_result_t napi_frags_finish(struct napi_struct *napi, + struct sk_buff *skb, + gro_result_t ret); + extern struct sk_buff * napi_frags_skb(struct napi_struct *napi); +-extern int napi_gro_frags(struct napi_struct *napi); ++extern gro_result_t napi_gro_frags(struct napi_struct *napi); + + static inline void napi_free_frags(struct napi_struct *napi) + { +diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c +index 47a80d6..8d5ca2a 100644 +--- a/net/8021q/vlan_core.c ++++ b/net/8021q/vlan_core.c +@@ -102,11 +102,12 @@ drop: + return GRO_DROP; + } + +-int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, +- unsigned int vlan_tci, struct sk_buff *skb) ++gro_result_t vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, ++ unsigned int vlan_tci, struct sk_buff *skb) + { + if (netpoll_rx_on(skb)) +- return vlan_hwaccel_receive_skb(skb, grp, vlan_tci); ++ return vlan_hwaccel_receive_skb(skb, grp, vlan_tci) ++ ? GRO_DROP : GRO_NORMAL; + + skb_gro_reset_offset(skb); + +@@ -114,17 +115,18 @@ int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, + } + EXPORT_SYMBOL(vlan_gro_receive); + +-int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, +- unsigned int vlan_tci) ++gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, ++ unsigned int vlan_tci) + { + struct sk_buff *skb = napi_frags_skb(napi); + + if (!skb) +- return NET_RX_DROP; ++ return GRO_DROP; + + if (netpoll_rx_on(skb)) { + skb->protocol = eth_type_trans(skb, skb->dev); +- return vlan_hwaccel_receive_skb(skb, grp, vlan_tci); ++ return vlan_hwaccel_receive_skb(skb, grp, vlan_tci) ++ ? GRO_DROP : GRO_NORMAL; + } + + return napi_frags_finish(napi, skb, +diff --git a/net/core/dev.c b/net/core/dev.c +index 1dc1374..631cc40 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2586,18 +2586,15 @@ __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) + return dev_gro_receive(napi, skb); + } + +-int napi_skb_finish(gro_result_t ret, struct sk_buff *skb) ++gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) + { +- int err = NET_RX_SUCCESS; +- + switch (ret) { + case GRO_NORMAL: +- return netif_receive_skb(skb); ++ if (netif_receive_skb(skb)) ++ ret = GRO_DROP; ++ break; + + case GRO_DROP: +- err = NET_RX_DROP; +- /* fall through */ +- + case GRO_MERGED_FREE: + kfree_skb(skb); + break; +@@ -2607,7 +2604,7 @@ int napi_skb_finish(gro_result_t ret, struct sk_buff *skb) + break; + } + +- return err; ++ return ret; + } + EXPORT_SYMBOL(napi_skb_finish); + +@@ -2627,7 +2624,7 @@ void skb_gro_reset_offset(struct sk_buff *skb) + } + EXPORT_SYMBOL(skb_gro_reset_offset); + +-int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) ++gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) + { + skb_gro_reset_offset(skb); + +@@ -2657,26 +2654,21 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) + } + EXPORT_SYMBOL(napi_get_frags); + +-int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, +- gro_result_t ret) ++gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, ++ gro_result_t ret) + { +- int err = NET_RX_SUCCESS; +- + switch (ret) { + case GRO_NORMAL: + case GRO_HELD: + skb->protocol = eth_type_trans(skb, napi->dev); + +- if (ret == GRO_NORMAL) +- return netif_receive_skb(skb); +- +- skb_gro_pull(skb, -ETH_HLEN); ++ if (ret == GRO_HELD) ++ skb_gro_pull(skb, -ETH_HLEN); ++ else if (netif_receive_skb(skb)) ++ ret = GRO_DROP; + break; + + case GRO_DROP: +- err = NET_RX_DROP; +- /* fall through */ +- + case GRO_MERGED_FREE: + napi_reuse_skb(napi, skb); + break; +@@ -2685,7 +2677,7 @@ int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, + break; + } + +- return err; ++ return ret; + } + EXPORT_SYMBOL(napi_frags_finish); + +@@ -2726,12 +2718,12 @@ out: + } + EXPORT_SYMBOL(napi_frags_skb); + +-int napi_gro_frags(struct napi_struct *napi) ++gro_result_t napi_gro_frags(struct napi_struct *napi) + { + struct sk_buff *skb = napi_frags_skb(napi); + + if (!skb) +- return NET_RX_DROP; ++ return GRO_DROP; + + return napi_frags_finish(napi, skb, __napi_gro_receive(napi, skb)); + } +-- +1.6.5.4 + diff --git a/debian/patches/features/all/gro-Name-the-GRO-result-enumeration-type.patch b/debian/patches/features/all/gro-Name-the-GRO-result-enumeration-type.patch new file mode 100644 index 000000000..1f7d65b04 --- /dev/null +++ b/debian/patches/features/all/gro-Name-the-GRO-result-enumeration-type.patch @@ -0,0 +1,149 @@ +From 5b252f0c2f98df21fadf0f6cf189b87a0b938228 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Thu, 29 Oct 2009 07:17:09 +0000 +Subject: [PATCH 1/2] gro: Name the GRO result enumeration type + +This clarifies which return and parameter types are GRO result codes +and not RX result codes. + +Signed-off-by: Ben Hutchings +Acked-by: Herbert Xu +Signed-off-by: David S. Miller +--- + include/linux/netdevice.h | 10 ++++++---- + net/8021q/vlan_core.c | 5 +++-- + net/core/dev.c | 19 ++++++++++++++----- + 3 files changed, 23 insertions(+), 11 deletions(-) + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index ffc3106..6e777ef 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -348,13 +348,14 @@ enum + NAPI_STATE_NPSVC, /* Netpoll - don't dequeue from poll_list */ + }; + +-enum { ++enum gro_result { + GRO_MERGED, + GRO_MERGED_FREE, + GRO_HELD, + GRO_NORMAL, + GRO_DROP, + }; ++typedef enum gro_result gro_result_t; + + extern void __napi_schedule(struct napi_struct *n); + +@@ -1480,16 +1481,17 @@ extern int netif_rx_ni(struct sk_buff *skb); + #define HAVE_NETIF_RECEIVE_SKB 1 + extern int netif_receive_skb(struct sk_buff *skb); + extern void napi_gro_flush(struct napi_struct *napi); +-extern int dev_gro_receive(struct napi_struct *napi, ++extern gro_result_t dev_gro_receive(struct napi_struct *napi, + struct sk_buff *skb); +-extern int napi_skb_finish(int ret, struct sk_buff *skb); ++extern int napi_skb_finish(gro_result_t ret, struct sk_buff *skb); + extern int napi_gro_receive(struct napi_struct *napi, + struct sk_buff *skb); + extern void napi_reuse_skb(struct napi_struct *napi, + struct sk_buff *skb); + extern struct sk_buff * napi_get_frags(struct napi_struct *napi); + extern int napi_frags_finish(struct napi_struct *napi, +- struct sk_buff *skb, int ret); ++ struct sk_buff *skb, ++ gro_result_t ret); + extern struct sk_buff * napi_frags_skb(struct napi_struct *napi); + extern int napi_gro_frags(struct napi_struct *napi); + +diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c +index 7f7de1a..47a80d6 100644 +--- a/net/8021q/vlan_core.c ++++ b/net/8021q/vlan_core.c +@@ -74,8 +74,9 @@ u16 vlan_dev_vlan_id(const struct net_device *dev) + } + EXPORT_SYMBOL(vlan_dev_vlan_id); + +-static int vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, +- unsigned int vlan_tci, struct sk_buff *skb) ++static gro_result_t ++vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, ++ unsigned int vlan_tci, struct sk_buff *skb) + { + struct sk_buff *p; + +diff --git a/net/core/dev.c b/net/core/dev.c +index 68a1bb6..1dc1374 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2476,7 +2476,7 @@ void napi_gro_flush(struct napi_struct *napi) + } + EXPORT_SYMBOL(napi_gro_flush); + +-int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) ++enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) + { + struct sk_buff **pp = NULL; + struct packet_type *ptype; +@@ -2484,7 +2484,7 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) + struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK]; + int same_flow; + int mac_len; +- int ret; ++ enum gro_result ret; + + if (!(skb->dev->features & NETIF_F_GRO)) + goto normal; +@@ -2568,7 +2568,8 @@ normal: + } + EXPORT_SYMBOL(dev_gro_receive); + +-static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) ++static gro_result_t ++__napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) + { + struct sk_buff *p; + +@@ -2585,7 +2586,7 @@ static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) + return dev_gro_receive(napi, skb); + } + +-int napi_skb_finish(int ret, struct sk_buff *skb) ++int napi_skb_finish(gro_result_t ret, struct sk_buff *skb) + { + int err = NET_RX_SUCCESS; + +@@ -2600,6 +2601,10 @@ int napi_skb_finish(int ret, struct sk_buff *skb) + case GRO_MERGED_FREE: + kfree_skb(skb); + break; ++ ++ case GRO_HELD: ++ case GRO_MERGED: ++ break; + } + + return err; +@@ -2652,7 +2657,8 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) + } + EXPORT_SYMBOL(napi_get_frags); + +-int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) ++int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, ++ gro_result_t ret) + { + int err = NET_RX_SUCCESS; + +@@ -2674,6 +2680,9 @@ int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) + case GRO_MERGED_FREE: + napi_reuse_skb(napi, skb); + break; ++ ++ case GRO_MERGED: ++ break; + } + + return err; +-- +1.6.5.4 + diff --git a/debian/patches/features/all/sfc-2.6.33-rc1.patch b/debian/patches/features/all/sfc-2.6.33-rc1.patch new file mode 100644 index 000000000..bc40014c4 --- /dev/null +++ b/debian/patches/features/all/sfc-2.6.33-rc1.patch @@ -0,0 +1,23088 @@ +diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig +index 260aafa..a65c986 100644 +--- a/drivers/net/sfc/Kconfig ++++ b/drivers/net/sfc/Kconfig +@@ -1,5 +1,5 @@ + config SFC +- tristate "Solarflare Solarstorm SFC4000 support" ++ tristate "Solarflare Solarstorm SFC4000/SFC9000-family support" + depends on PCI && INET + select MDIO + select CRC32 +@@ -7,15 +7,16 @@ config SFC + select I2C_ALGOBIT + help + This driver supports 10-gigabit Ethernet cards based on +- the Solarflare Communications Solarstorm SFC4000 controller. ++ the Solarflare Communications Solarstorm SFC4000 and ++ SFC9000-family controllers. + + To compile this driver as a module, choose M here. The module + will be called sfc. + config SFC_MTD +- bool "Solarflare Solarstorm SFC4000 flash MTD support" ++ bool "Solarflare Solarstorm SFC4000/SFC9000-family MTD support" + depends on SFC && MTD && !(SFC=y && MTD=m) + default y + help +- This exposes the on-board flash memory as an MTD device (e.g. +- /dev/mtd1). This makes it possible to upload new boot code +- to the NIC. ++ This exposes the on-board flash memory as MTD devices (e.g. ++ /dev/mtd1). This makes it possible to upload new firmware ++ to the NIC. +diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile +index b89f9be..1047b19 100644 +--- a/drivers/net/sfc/Makefile ++++ b/drivers/net/sfc/Makefile +@@ -1,6 +1,7 @@ +-sfc-y += efx.o falcon.o tx.o rx.o falcon_gmac.o \ +- falcon_xmac.o selftest.o ethtool.o xfp_phy.o \ +- mdio_10g.o tenxpress.o boards.o sfe4001.o ++sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o \ ++ falcon_gmac.o falcon_xmac.o mcdi_mac.o \ ++ selftest.o ethtool.o qt202x_phy.o mdio_10g.o \ ++ tenxpress.o falcon_boards.o mcdi.o mcdi_phy.o + sfc-$(CONFIG_SFC_MTD) += mtd.o + + obj-$(CONFIG_SFC) += sfc.o +diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h +index d54d84c..098ac2a 100644 +--- a/drivers/net/sfc/bitfield.h ++++ b/drivers/net/sfc/bitfield.h +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -37,6 +37,8 @@ + #define EFX_DWORD_2_WIDTH 32 + #define EFX_DWORD_3_LBN 96 + #define EFX_DWORD_3_WIDTH 32 ++#define EFX_QWORD_0_LBN 0 ++#define EFX_QWORD_0_WIDTH 64 + + /* Specified attribute (e.g. LBN) of the specified field */ + #define EFX_VAL(field, attribute) field ## _ ## attribute +@@ -520,19 +522,6 @@ typedef union efx_oword { + #define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32 + #endif + +-#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \ +- if (falcon_rev(efx) >= FALCON_REV_B0) { \ +- EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \ +- } else { \ +- EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \ +- } \ +-} while (0) +- +-#define EFX_QWORD_FIELD_VER(efx, qword, field) \ +- (falcon_rev(efx) >= FALCON_REV_B0 ? \ +- EFX_QWORD_FIELD((qword), field##_B0) : \ +- EFX_QWORD_FIELD((qword), field##_A1)) +- + /* Used to avoid compiler warnings about shift range exceeding width + * of the data types when dma_addr_t is only 32 bits wide. + */ +diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c +deleted file mode 100644 +index 4a4c74c..0000000 +--- a/drivers/net/sfc/boards.c ++++ /dev/null +@@ -1,328 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2007-2008 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +- +-#include "net_driver.h" +-#include "phy.h" +-#include "boards.h" +-#include "efx.h" +-#include "workarounds.h" +- +-/* Macros for unpacking the board revision */ +-/* The revision info is in host byte order. */ +-#define BOARD_TYPE(_rev) (_rev >> 8) +-#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf) +-#define BOARD_MINOR(_rev) (_rev & 0xf) +- +-/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */ +-#define BLINK_INTERVAL (HZ/2) +- +-static void blink_led_timer(unsigned long context) +-{ +- struct efx_nic *efx = (struct efx_nic *)context; +- struct efx_blinker *bl = &efx->board_info.blinker; +- efx->board_info.set_id_led(efx, bl->state); +- bl->state = !bl->state; +- if (bl->resubmit) +- mod_timer(&bl->timer, jiffies + BLINK_INTERVAL); +-} +- +-static void board_blink(struct efx_nic *efx, bool blink) +-{ +- struct efx_blinker *blinker = &efx->board_info.blinker; +- +- /* The rtnl mutex serialises all ethtool ioctls, so +- * nothing special needs doing here. */ +- if (blink) { +- blinker->resubmit = true; +- blinker->state = false; +- setup_timer(&blinker->timer, blink_led_timer, +- (unsigned long)efx); +- mod_timer(&blinker->timer, jiffies + BLINK_INTERVAL); +- } else { +- blinker->resubmit = false; +- if (blinker->timer.function) +- del_timer_sync(&blinker->timer); +- efx->board_info.init_leds(efx); +- } +-} +- +-/***************************************************************************** +- * Support for LM87 sensor chip used on several boards +- */ +-#define LM87_REG_ALARMS1 0x41 +-#define LM87_REG_ALARMS2 0x42 +-#define LM87_IN_LIMITS(nr, _min, _max) \ +- 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min +-#define LM87_AIN_LIMITS(nr, _min, _max) \ +- 0x3B + (nr), _max, 0x1A + (nr), _min +-#define LM87_TEMP_INT_LIMITS(_min, _max) \ +- 0x39, _max, 0x3A, _min +-#define LM87_TEMP_EXT1_LIMITS(_min, _max) \ +- 0x37, _max, 0x38, _min +- +-#define LM87_ALARM_TEMP_INT 0x10 +-#define LM87_ALARM_TEMP_EXT1 0x20 +- +-#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE) +- +-static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, +- const u8 *reg_values) +-{ +- struct i2c_client *client = i2c_new_device(&efx->i2c_adap, info); +- int rc; +- +- if (!client) +- return -EIO; +- +- while (*reg_values) { +- u8 reg = *reg_values++; +- u8 value = *reg_values++; +- rc = i2c_smbus_write_byte_data(client, reg, value); +- if (rc) +- goto err; +- } +- +- efx->board_info.hwmon_client = client; +- return 0; +- +-err: +- i2c_unregister_device(client); +- return rc; +-} +- +-static void efx_fini_lm87(struct efx_nic *efx) +-{ +- i2c_unregister_device(efx->board_info.hwmon_client); +-} +- +-static int efx_check_lm87(struct efx_nic *efx, unsigned mask) +-{ +- struct i2c_client *client = efx->board_info.hwmon_client; +- s32 alarms1, alarms2; +- +- /* If link is up then do not monitor temperature */ +- if (EFX_WORKAROUND_7884(efx) && efx->link_up) +- return 0; +- +- alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); +- alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); +- if (alarms1 < 0) +- return alarms1; +- if (alarms2 < 0) +- return alarms2; +- alarms1 &= mask; +- alarms2 &= mask >> 8; +- if (alarms1 || alarms2) { +- EFX_ERR(efx, +- "LM87 detected a hardware failure (status %02x:%02x)" +- "%s%s\n", +- alarms1, alarms2, +- (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "", +- (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : ""); +- return -ERANGE; +- } +- +- return 0; +-} +- +-#else /* !CONFIG_SENSORS_LM87 */ +- +-static inline int +-efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, +- const u8 *reg_values) +-{ +- return 0; +-} +-static inline void efx_fini_lm87(struct efx_nic *efx) +-{ +-} +-static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask) +-{ +- return 0; +-} +- +-#endif /* CONFIG_SENSORS_LM87 */ +- +-/***************************************************************************** +- * Support for the SFE4002 +- * +- */ +-static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */ +- +-static const u8 sfe4002_lm87_regs[] = { +- LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ +- LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ +- LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ +- LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */ +- LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ +- LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ +- LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */ +- LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ +- LM87_TEMP_INT_LIMITS(10, 60), /* board */ +- LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ +- 0 +-}; +- +-static struct i2c_board_info sfe4002_hwmon_info = { +- I2C_BOARD_INFO("lm87", 0x2e), +- .platform_data = &sfe4002_lm87_channel, +-}; +- +-/****************************************************************************/ +-/* LED allocations. Note that on rev A0 boards the schematic and the reality +- * differ: red and green are swapped. Below is the fixed (A1) layout (there +- * are only 3 A0 boards in existence, so no real reason to make this +- * conditional). +- */ +-#define SFE4002_FAULT_LED (2) /* Red */ +-#define SFE4002_RX_LED (0) /* Green */ +-#define SFE4002_TX_LED (1) /* Amber */ +- +-static void sfe4002_init_leds(struct efx_nic *efx) +-{ +- /* Set the TX and RX LEDs to reflect status and activity, and the +- * fault LED off */ +- xfp_set_led(efx, SFE4002_TX_LED, +- QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT); +- xfp_set_led(efx, SFE4002_RX_LED, +- QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT); +- xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF); +-} +- +-static void sfe4002_set_id_led(struct efx_nic *efx, bool state) +-{ +- xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON : +- QUAKE_LED_OFF); +-} +- +-static int sfe4002_check_hw(struct efx_nic *efx) +-{ +- /* A0 board rev. 4002s report a temperature fault the whole time +- * (bad sensor) so we mask it out. */ +- unsigned alarm_mask = +- (efx->board_info.major == 0 && efx->board_info.minor == 0) ? +- ~LM87_ALARM_TEMP_EXT1 : ~0; +- +- return efx_check_lm87(efx, alarm_mask); +-} +- +-static int sfe4002_init(struct efx_nic *efx) +-{ +- int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); +- if (rc) +- return rc; +- efx->board_info.monitor = sfe4002_check_hw; +- efx->board_info.init_leds = sfe4002_init_leds; +- efx->board_info.set_id_led = sfe4002_set_id_led; +- efx->board_info.blink = board_blink; +- efx->board_info.fini = efx_fini_lm87; +- return 0; +-} +- +-/***************************************************************************** +- * Support for the SFN4112F +- * +- */ +-static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */ +- +-static const u8 sfn4112f_lm87_regs[] = { +- LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ +- LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ +- LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ +- LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ +- LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ +- LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ +- LM87_TEMP_INT_LIMITS(10, 60), /* board */ +- LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ +- 0 +-}; +- +-static struct i2c_board_info sfn4112f_hwmon_info = { +- I2C_BOARD_INFO("lm87", 0x2e), +- .platform_data = &sfn4112f_lm87_channel, +-}; +- +-#define SFN4112F_ACT_LED 0 +-#define SFN4112F_LINK_LED 1 +- +-static void sfn4112f_init_leds(struct efx_nic *efx) +-{ +- xfp_set_led(efx, SFN4112F_ACT_LED, +- QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT); +- xfp_set_led(efx, SFN4112F_LINK_LED, +- QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT); +-} +- +-static void sfn4112f_set_id_led(struct efx_nic *efx, bool state) +-{ +- xfp_set_led(efx, SFN4112F_LINK_LED, +- state ? QUAKE_LED_ON : QUAKE_LED_OFF); +-} +- +-static int sfn4112f_check_hw(struct efx_nic *efx) +-{ +- /* Mask out unused sensors */ +- return efx_check_lm87(efx, ~0x48); +-} +- +-static int sfn4112f_init(struct efx_nic *efx) +-{ +- int rc = efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs); +- if (rc) +- return rc; +- efx->board_info.monitor = sfn4112f_check_hw; +- efx->board_info.init_leds = sfn4112f_init_leds; +- efx->board_info.set_id_led = sfn4112f_set_id_led; +- efx->board_info.blink = board_blink; +- efx->board_info.fini = efx_fini_lm87; +- return 0; +-} +- +-/* This will get expanded as board-specific details get moved out of the +- * PHY drivers. */ +-struct efx_board_data { +- enum efx_board_type type; +- const char *ref_model; +- const char *gen_type; +- int (*init) (struct efx_nic *nic); +-}; +- +- +-static struct efx_board_data board_data[] = { +- { EFX_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init }, +- { EFX_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init }, +- { EFX_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter", +- sfn4111t_init }, +- { EFX_BOARD_SFN4112F, "SFN4112F", "SFP+ adapter", +- sfn4112f_init }, +-}; +- +-void efx_set_board_info(struct efx_nic *efx, u16 revision_info) +-{ +- struct efx_board_data *data = NULL; +- int i; +- +- efx->board_info.type = BOARD_TYPE(revision_info); +- efx->board_info.major = BOARD_MAJOR(revision_info); +- efx->board_info.minor = BOARD_MINOR(revision_info); +- +- for (i = 0; i < ARRAY_SIZE(board_data); i++) +- if (board_data[i].type == efx->board_info.type) +- data = &board_data[i]; +- +- if (data) { +- EFX_INFO(efx, "board is %s rev %c%d\n", +- (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) +- ? data->ref_model : data->gen_type, +- 'A' + efx->board_info.major, efx->board_info.minor); +- efx->board_info.init = data->init; +- } else { +- EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type); +- } +-} +diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h +deleted file mode 100644 +index 44942de..0000000 +--- a/drivers/net/sfc/boards.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2007-2008 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +- +-#ifndef EFX_BOARDS_H +-#define EFX_BOARDS_H +- +-/* Board IDs (must fit in 8 bits) */ +-enum efx_board_type { +- EFX_BOARD_SFE4001 = 1, +- EFX_BOARD_SFE4002 = 2, +- EFX_BOARD_SFN4111T = 0x51, +- EFX_BOARD_SFN4112F = 0x52, +-}; +- +-extern void efx_set_board_info(struct efx_nic *efx, u16 revision_info); +- +-/* SFE4001 (10GBASE-T) */ +-extern int sfe4001_init(struct efx_nic *efx); +-/* SFN4111T (100/1000/10GBASE-T) */ +-extern int sfn4111t_init(struct efx_nic *efx); +- +-#endif +diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c +index cc4b2f9..f983e3b 100644 +--- a/drivers/net/sfc/efx.c ++++ b/drivers/net/sfc/efx.c +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2005-2008 Solarflare Communications Inc. ++ * Copyright 2005-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -21,12 +21,73 @@ + #include + #include + #include "net_driver.h" +-#include "ethtool.h" +-#include "tx.h" +-#include "rx.h" + #include "efx.h" + #include "mdio_10g.h" +-#include "falcon.h" ++#include "nic.h" ++ ++#include "mcdi.h" ++ ++/************************************************************************** ++ * ++ * Type name strings ++ * ++ ************************************************************************** ++ */ ++ ++/* Loopback mode names (see LOOPBACK_MODE()) */ ++const unsigned int efx_loopback_mode_max = LOOPBACK_MAX; ++const char *efx_loopback_mode_names[] = { ++ [LOOPBACK_NONE] = "NONE", ++ [LOOPBACK_DATA] = "DATAPATH", ++ [LOOPBACK_GMAC] = "GMAC", ++ [LOOPBACK_XGMII] = "XGMII", ++ [LOOPBACK_XGXS] = "XGXS", ++ [LOOPBACK_XAUI] = "XAUI", ++ [LOOPBACK_GMII] = "GMII", ++ [LOOPBACK_SGMII] = "SGMII", ++ [LOOPBACK_XGBR] = "XGBR", ++ [LOOPBACK_XFI] = "XFI", ++ [LOOPBACK_XAUI_FAR] = "XAUI_FAR", ++ [LOOPBACK_GMII_FAR] = "GMII_FAR", ++ [LOOPBACK_SGMII_FAR] = "SGMII_FAR", ++ [LOOPBACK_XFI_FAR] = "XFI_FAR", ++ [LOOPBACK_GPHY] = "GPHY", ++ [LOOPBACK_PHYXS] = "PHYXS", ++ [LOOPBACK_PCS] = "PCS", ++ [LOOPBACK_PMAPMD] = "PMA/PMD", ++ [LOOPBACK_XPORT] = "XPORT", ++ [LOOPBACK_XGMII_WS] = "XGMII_WS", ++ [LOOPBACK_XAUI_WS] = "XAUI_WS", ++ [LOOPBACK_XAUI_WS_FAR] = "XAUI_WS_FAR", ++ [LOOPBACK_XAUI_WS_NEAR] = "XAUI_WS_NEAR", ++ [LOOPBACK_GMII_WS] = "GMII_WS", ++ [LOOPBACK_XFI_WS] = "XFI_WS", ++ [LOOPBACK_XFI_WS_FAR] = "XFI_WS_FAR", ++ [LOOPBACK_PHYXS_WS] = "PHYXS_WS", ++}; ++ ++/* Interrupt mode names (see INT_MODE())) */ ++const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX; ++const char *efx_interrupt_mode_names[] = { ++ [EFX_INT_MODE_MSIX] = "MSI-X", ++ [EFX_INT_MODE_MSI] = "MSI", ++ [EFX_INT_MODE_LEGACY] = "legacy", ++}; ++ ++const unsigned int efx_reset_type_max = RESET_TYPE_MAX; ++const char *efx_reset_type_names[] = { ++ [RESET_TYPE_INVISIBLE] = "INVISIBLE", ++ [RESET_TYPE_ALL] = "ALL", ++ [RESET_TYPE_WORLD] = "WORLD", ++ [RESET_TYPE_DISABLE] = "DISABLE", ++ [RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG", ++ [RESET_TYPE_INT_ERROR] = "INT_ERROR", ++ [RESET_TYPE_RX_RECOVERY] = "RX_RECOVERY", ++ [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH", ++ [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH", ++ [RESET_TYPE_TX_SKIP] = "TX_SKIP", ++ [RESET_TYPE_MC_FAILURE] = "MC_FAILURE", ++}; + + #define EFX_MAX_MTU (9 * 1024) + +@@ -145,7 +206,8 @@ static void efx_fini_channels(struct efx_nic *efx); + + #define EFX_ASSERT_RESET_SERIALISED(efx) \ + do { \ +- if (efx->state == STATE_RUNNING) \ ++ if ((efx->state == STATE_RUNNING) || \ ++ (efx->state == STATE_DISABLED)) \ + ASSERT_RTNL(); \ + } while (0) + +@@ -171,7 +233,7 @@ static int efx_process_channel(struct efx_channel *channel, int rx_quota) + !channel->enabled)) + return 0; + +- rx_packets = falcon_process_eventq(channel, rx_quota); ++ rx_packets = efx_nic_process_eventq(channel, rx_quota); + if (rx_packets == 0) + return 0; + +@@ -203,7 +265,7 @@ static inline void efx_channel_processed(struct efx_channel *channel) + channel->work_pending = false; + smp_wmb(); + +- falcon_eventq_read_ack(channel); ++ efx_nic_eventq_read_ack(channel); + } + + /* NAPI poll handler +@@ -228,26 +290,20 @@ static int efx_poll(struct napi_struct *napi, int budget) + if (channel->used_flags & EFX_USED_BY_RX && + efx->irq_rx_adaptive && + unlikely(++channel->irq_count == 1000)) { +- unsigned old_irq_moderation = channel->irq_moderation; +- + if (unlikely(channel->irq_mod_score < + irq_adapt_low_thresh)) { +- channel->irq_moderation = +- max_t(int, +- channel->irq_moderation - +- FALCON_IRQ_MOD_RESOLUTION, +- FALCON_IRQ_MOD_RESOLUTION); ++ if (channel->irq_moderation > 1) { ++ channel->irq_moderation -= 1; ++ efx->type->push_irq_moderation(channel); ++ } + } else if (unlikely(channel->irq_mod_score > + irq_adapt_high_thresh)) { +- channel->irq_moderation = +- min(channel->irq_moderation + +- FALCON_IRQ_MOD_RESOLUTION, +- efx->irq_rx_moderation); ++ if (channel->irq_moderation < ++ efx->irq_rx_moderation) { ++ channel->irq_moderation += 1; ++ efx->type->push_irq_moderation(channel); ++ } + } +- +- if (channel->irq_moderation != old_irq_moderation) +- falcon_set_int_moderation(channel); +- + channel->irq_count = 0; + channel->irq_mod_score = 0; + } +@@ -280,7 +336,7 @@ void efx_process_channel_now(struct efx_channel *channel) + BUG_ON(!channel->enabled); + + /* Disable interrupts and wait for ISRs to complete */ +- falcon_disable_interrupts(efx); ++ efx_nic_disable_interrupts(efx); + if (efx->legacy_irq) + synchronize_irq(efx->legacy_irq); + if (channel->irq) +@@ -290,14 +346,14 @@ void efx_process_channel_now(struct efx_channel *channel) + napi_disable(&channel->napi_str); + + /* Poll the channel */ +- efx_process_channel(channel, efx->type->evq_size); ++ efx_process_channel(channel, EFX_EVQ_SIZE); + + /* Ack the eventq. This may cause an interrupt to be generated + * when they are reenabled */ + efx_channel_processed(channel); + + napi_enable(&channel->napi_str); +- falcon_enable_interrupts(efx); ++ efx_nic_enable_interrupts(efx); + } + + /* Create event queue +@@ -309,7 +365,7 @@ static int efx_probe_eventq(struct efx_channel *channel) + { + EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel); + +- return falcon_probe_eventq(channel); ++ return efx_nic_probe_eventq(channel); + } + + /* Prepare channel's event queue */ +@@ -319,21 +375,21 @@ static void efx_init_eventq(struct efx_channel *channel) + + channel->eventq_read_ptr = 0; + +- falcon_init_eventq(channel); ++ efx_nic_init_eventq(channel); + } + + static void efx_fini_eventq(struct efx_channel *channel) + { + EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel); + +- falcon_fini_eventq(channel); ++ efx_nic_fini_eventq(channel); + } + + static void efx_remove_eventq(struct efx_channel *channel) + { + EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel); + +- falcon_remove_eventq(channel); ++ efx_nic_remove_eventq(channel); + } + + /************************************************************************** +@@ -499,7 +555,7 @@ static void efx_fini_channels(struct efx_nic *efx) + EFX_ASSERT_RESET_SERIALISED(efx); + BUG_ON(efx->port_enabled); + +- rc = falcon_flush_queues(efx); ++ rc = efx_nic_flush_queues(efx); + if (rc) + EFX_ERR(efx, "failed to flush queues\n"); + else +@@ -547,8 +603,10 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay) + * netif_carrier_on/off) of the link status, and also maintains the + * link status's stop on the port's TX queue. + */ +-static void efx_link_status_changed(struct efx_nic *efx) ++void efx_link_status_changed(struct efx_nic *efx) + { ++ struct efx_link_state *link_state = &efx->link_state; ++ + /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure + * that no events are triggered between unregister_netdev() and the + * driver unloading. A more general condition is that NETDEV_CHANGE +@@ -561,19 +619,19 @@ static void efx_link_status_changed(struct efx_nic *efx) + return; + } + +- if (efx->link_up != netif_carrier_ok(efx->net_dev)) { ++ if (link_state->up != netif_carrier_ok(efx->net_dev)) { + efx->n_link_state_changes++; + +- if (efx->link_up) ++ if (link_state->up) + netif_carrier_on(efx->net_dev); + else + netif_carrier_off(efx->net_dev); + } + + /* Status message for kernel log */ +- if (efx->link_up) { ++ if (link_state->up) { + EFX_INFO(efx, "link up at %uMbps %s-duplex (MTU %d)%s\n", +- efx->link_speed, efx->link_fd ? "full" : "half", ++ link_state->speed, link_state->fd ? "full" : "half", + efx->net_dev->mtu, + (efx->promiscuous ? " [PROMISC]" : "")); + } else { +@@ -582,16 +640,49 @@ static void efx_link_status_changed(struct efx_nic *efx) + + } + ++void efx_link_set_advertising(struct efx_nic *efx, u32 advertising) ++{ ++ efx->link_advertising = advertising; ++ if (advertising) { ++ if (advertising & ADVERTISED_Pause) ++ efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX); ++ else ++ efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX); ++ if (advertising & ADVERTISED_Asym_Pause) ++ efx->wanted_fc ^= EFX_FC_TX; ++ } ++} ++ ++void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type wanted_fc) ++{ ++ efx->wanted_fc = wanted_fc; ++ if (efx->link_advertising) { ++ if (wanted_fc & EFX_FC_RX) ++ efx->link_advertising |= (ADVERTISED_Pause | ++ ADVERTISED_Asym_Pause); ++ else ++ efx->link_advertising &= ~(ADVERTISED_Pause | ++ ADVERTISED_Asym_Pause); ++ if (wanted_fc & EFX_FC_TX) ++ efx->link_advertising ^= ADVERTISED_Asym_Pause; ++ } ++} ++ + static void efx_fini_port(struct efx_nic *efx); + +-/* This call reinitialises the MAC to pick up new PHY settings. The +- * caller must hold the mac_lock */ +-void __efx_reconfigure_port(struct efx_nic *efx) ++/* Push loopback/power/transmit disable settings to the PHY, and reconfigure ++ * the MAC appropriately. All other PHY configuration changes are pushed ++ * through phy_op->set_settings(), and pushed asynchronously to the MAC ++ * through efx_monitor(). ++ * ++ * Callers must hold the mac_lock ++ */ ++int __efx_reconfigure_port(struct efx_nic *efx) + { +- WARN_ON(!mutex_is_locked(&efx->mac_lock)); ++ enum efx_phy_mode phy_mode; ++ int rc; + +- EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n", +- raw_smp_processor_id()); ++ WARN_ON(!mutex_is_locked(&efx->mac_lock)); + + /* Serialise the promiscuous flag with efx_set_multicast_list. */ + if (efx_dev_registered(efx)) { +@@ -599,61 +690,48 @@ void __efx_reconfigure_port(struct efx_nic *efx) + netif_addr_unlock_bh(efx->net_dev); + } + +- falcon_deconfigure_mac_wrapper(efx); +- +- /* Reconfigure the PHY, disabling transmit in mac level loopback. */ ++ /* Disable PHY transmit in mac level loopbacks */ ++ phy_mode = efx->phy_mode; + if (LOOPBACK_INTERNAL(efx)) + efx->phy_mode |= PHY_MODE_TX_DISABLED; + else + efx->phy_mode &= ~PHY_MODE_TX_DISABLED; +- efx->phy_op->reconfigure(efx); + +- if (falcon_switch_mac(efx)) +- goto fail; ++ rc = efx->type->reconfigure_port(efx); + +- efx->mac_op->reconfigure(efx); +- +- /* Inform kernel of loss/gain of carrier */ +- efx_link_status_changed(efx); +- return; ++ if (rc) ++ efx->phy_mode = phy_mode; + +-fail: +- EFX_ERR(efx, "failed to reconfigure MAC\n"); +- efx->port_enabled = false; +- efx_fini_port(efx); ++ return rc; + } + + /* Reinitialise the MAC to pick up new PHY settings, even if the port is + * disabled. */ +-void efx_reconfigure_port(struct efx_nic *efx) ++int efx_reconfigure_port(struct efx_nic *efx) + { ++ int rc; ++ + EFX_ASSERT_RESET_SERIALISED(efx); + + mutex_lock(&efx->mac_lock); +- __efx_reconfigure_port(efx); ++ rc = __efx_reconfigure_port(efx); + mutex_unlock(&efx->mac_lock); +-} +- +-/* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all() +- * we don't efx_reconfigure_port() if the port is disabled. Care is taken +- * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */ +-static void efx_phy_work(struct work_struct *data) +-{ +- struct efx_nic *efx = container_of(data, struct efx_nic, phy_work); + +- mutex_lock(&efx->mac_lock); +- if (efx->port_enabled) +- __efx_reconfigure_port(efx); +- mutex_unlock(&efx->mac_lock); ++ return rc; + } + ++/* Asynchronous work item for changing MAC promiscuity and multicast ++ * hash. Avoid a drain/rx_ingress enable by reconfiguring the current ++ * MAC directly. */ + static void efx_mac_work(struct work_struct *data) + { + struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); + + mutex_lock(&efx->mac_lock); +- if (efx->port_enabled) +- efx->mac_op->irq(efx); ++ if (efx->port_enabled) { ++ efx->type->push_multicast_hash(efx); ++ efx->mac_op->reconfigure(efx); ++ } + mutex_unlock(&efx->mac_lock); + } + +@@ -663,8 +741,8 @@ static int efx_probe_port(struct efx_nic *efx) + + EFX_LOG(efx, "create port\n"); + +- /* Connect up MAC/PHY operations table and read MAC address */ +- rc = falcon_probe_port(efx); ++ /* Connect up MAC/PHY operations table */ ++ rc = efx->type->probe_port(efx); + if (rc) + goto err; + +@@ -699,29 +777,33 @@ static int efx_init_port(struct efx_nic *efx) + + EFX_LOG(efx, "init port\n"); + +- rc = efx->phy_op->init(efx); +- if (rc) +- return rc; + mutex_lock(&efx->mac_lock); +- efx->phy_op->reconfigure(efx); +- rc = falcon_switch_mac(efx); +- mutex_unlock(&efx->mac_lock); ++ ++ rc = efx->phy_op->init(efx); + if (rc) +- goto fail; +- efx->mac_op->reconfigure(efx); ++ goto fail1; + + efx->port_initialized = true; +- efx_stats_enable(efx); ++ ++ /* Reconfigure the MAC before creating dma queues (required for ++ * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */ ++ efx->mac_op->reconfigure(efx); ++ ++ /* Ensure the PHY advertises the correct flow control settings */ ++ rc = efx->phy_op->reconfigure(efx); ++ if (rc) ++ goto fail2; ++ ++ mutex_unlock(&efx->mac_lock); + return 0; + +-fail: ++fail2: + efx->phy_op->fini(efx); ++fail1: ++ mutex_unlock(&efx->mac_lock); + return rc; + } + +-/* Allow efx_reconfigure_port() to be scheduled, and close the window +- * between efx_stop_port and efx_flush_all whereby a previously scheduled +- * efx_phy_work()/efx_mac_work() may have been cancelled */ + static void efx_start_port(struct efx_nic *efx) + { + EFX_LOG(efx, "start port\n"); +@@ -729,15 +811,16 @@ static void efx_start_port(struct efx_nic *efx) + + mutex_lock(&efx->mac_lock); + efx->port_enabled = true; +- __efx_reconfigure_port(efx); +- efx->mac_op->irq(efx); ++ ++ /* efx_mac_work() might have been scheduled after efx_stop_port(), ++ * and then cancelled by efx_flush_all() */ ++ efx->type->push_multicast_hash(efx); ++ efx->mac_op->reconfigure(efx); ++ + mutex_unlock(&efx->mac_lock); + } + +-/* Prevent efx_phy_work, efx_mac_work, and efx_monitor() from executing, +- * and efx_set_multicast_list() from scheduling efx_phy_work. efx_phy_work +- * and efx_mac_work may still be scheduled via NAPI processing until +- * efx_flush_all() is called */ ++/* Prevent efx_mac_work() and efx_monitor() from working */ + static void efx_stop_port(struct efx_nic *efx) + { + EFX_LOG(efx, "stop port\n"); +@@ -760,11 +843,10 @@ static void efx_fini_port(struct efx_nic *efx) + if (!efx->port_initialized) + return; + +- efx_stats_disable(efx); + efx->phy_op->fini(efx); + efx->port_initialized = false; + +- efx->link_up = false; ++ efx->link_state.up = false; + efx_link_status_changed(efx); + } + +@@ -772,7 +854,7 @@ static void efx_remove_port(struct efx_nic *efx) + { + EFX_LOG(efx, "destroying port\n"); + +- falcon_remove_port(efx); ++ efx->type->remove_port(efx); + } + + /************************************************************************** +@@ -824,9 +906,8 @@ static int efx_init_io(struct efx_nic *efx) + goto fail2; + } + +- efx->membase_phys = pci_resource_start(efx->pci_dev, +- efx->type->mem_bar); +- rc = pci_request_region(pci_dev, efx->type->mem_bar, "sfc"); ++ efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR); ++ rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc"); + if (rc) { + EFX_ERR(efx, "request for memory BAR failed\n"); + rc = -EIO; +@@ -835,21 +916,20 @@ static int efx_init_io(struct efx_nic *efx) + efx->membase = ioremap_nocache(efx->membase_phys, + efx->type->mem_map_size); + if (!efx->membase) { +- EFX_ERR(efx, "could not map memory BAR %d at %llx+%x\n", +- efx->type->mem_bar, ++ EFX_ERR(efx, "could not map memory BAR at %llx+%x\n", + (unsigned long long)efx->membase_phys, + efx->type->mem_map_size); + rc = -ENOMEM; + goto fail4; + } +- EFX_LOG(efx, "memory BAR %u at %llx+%x (virtual %p)\n", +- efx->type->mem_bar, (unsigned long long)efx->membase_phys, ++ EFX_LOG(efx, "memory BAR at %llx+%x (virtual %p)\n", ++ (unsigned long long)efx->membase_phys, + efx->type->mem_map_size, efx->membase); + + return 0; + + fail4: +- pci_release_region(efx->pci_dev, efx->type->mem_bar); ++ pci_release_region(efx->pci_dev, EFX_MEM_BAR); + fail3: + efx->membase_phys = 0; + fail2: +@@ -868,7 +948,7 @@ static void efx_fini_io(struct efx_nic *efx) + } + + if (efx->membase_phys) { +- pci_release_region(efx->pci_dev, efx->type->mem_bar); ++ pci_release_region(efx->pci_dev, EFX_MEM_BAR); + efx->membase_phys = 0; + } + +@@ -1011,7 +1091,7 @@ static int efx_probe_nic(struct efx_nic *efx) + EFX_LOG(efx, "creating NIC\n"); + + /* Carry out hardware-type specific initialisation */ +- rc = falcon_probe_nic(efx); ++ rc = efx->type->probe(efx); + if (rc) + return rc; + +@@ -1032,7 +1112,7 @@ static void efx_remove_nic(struct efx_nic *efx) + EFX_LOG(efx, "destroying NIC\n"); + + efx_remove_interrupts(efx); +- falcon_remove_nic(efx); ++ efx->type->remove(efx); + } + + /************************************************************************** +@@ -1112,12 +1192,31 @@ static void efx_start_all(struct efx_nic *efx) + efx_for_each_channel(channel, efx) + efx_start_channel(channel); + +- falcon_enable_interrupts(efx); +- +- /* Start hardware monitor if we're in RUNNING */ +- if (efx->state == STATE_RUNNING) ++ efx_nic_enable_interrupts(efx); ++ ++ /* Switch to event based MCDI completions after enabling interrupts. ++ * If a reset has been scheduled, then we need to stay in polled mode. ++ * Rather than serialising efx_mcdi_mode_event() [which sleeps] and ++ * reset_pending [modified from an atomic context], we instead guarantee ++ * that efx_mcdi_mode_poll() isn't reverted erroneously */ ++ efx_mcdi_mode_event(efx); ++ if (efx->reset_pending != RESET_TYPE_NONE) ++ efx_mcdi_mode_poll(efx); ++ ++ /* Start the hardware monitor if there is one. Otherwise (we're link ++ * event driven), we have to poll the PHY because after an event queue ++ * flush, we could have a missed a link state change */ ++ if (efx->type->monitor != NULL) { + queue_delayed_work(efx->workqueue, &efx->monitor_work, + efx_monitor_interval); ++ } else { ++ mutex_lock(&efx->mac_lock); ++ if (efx->phy_op->poll(efx)) ++ efx_link_status_changed(efx); ++ mutex_unlock(&efx->mac_lock); ++ } ++ ++ efx->type->start_stats(efx); + } + + /* Flush all delayed work. Should only be called when no more delayed work +@@ -1136,8 +1235,6 @@ static void efx_flush_all(struct efx_nic *efx) + + /* Stop scheduled port reconfigurations */ + cancel_work_sync(&efx->mac_work); +- cancel_work_sync(&efx->phy_work); +- + } + + /* Quiesce hardware and software without bringing the link down. +@@ -1155,8 +1252,13 @@ static void efx_stop_all(struct efx_nic *efx) + if (!efx->port_enabled) + return; + ++ efx->type->stop_stats(efx); ++ ++ /* Switch to MCDI polling on Siena before disabling interrupts */ ++ efx_mcdi_mode_poll(efx); ++ + /* Disable interrupts and wait for ISR to complete */ +- falcon_disable_interrupts(efx); ++ efx_nic_disable_interrupts(efx); + if (efx->legacy_irq) + synchronize_irq(efx->legacy_irq); + efx_for_each_channel(channel, efx) { +@@ -1173,15 +1275,9 @@ static void efx_stop_all(struct efx_nic *efx) + * window to loose phy events */ + efx_stop_port(efx); + +- /* Flush efx_phy_work, efx_mac_work, refill_workqueue, monitor_work */ ++ /* Flush efx_mac_work(), refill_workqueue, monitor_work */ + efx_flush_all(efx); + +- /* Isolate the MAC from the TX and RX engines, so that queue +- * flushes will complete in a timely fashion. */ +- falcon_deconfigure_mac_wrapper(efx); +- msleep(10); /* Let the Rx FIFO drain */ +- falcon_drain_tx_fifo(efx); +- + /* Stop the kernel transmit interface late, so the watchdog + * timer isn't ticking over the flush */ + if (efx_dev_registered(efx)) { +@@ -1201,41 +1297,39 @@ static void efx_remove_all(struct efx_nic *efx) + efx_remove_nic(efx); + } + +-/* A convinience function to safely flush all the queues */ +-void efx_flush_queues(struct efx_nic *efx) +-{ +- EFX_ASSERT_RESET_SERIALISED(efx); +- +- efx_stop_all(efx); +- +- efx_fini_channels(efx); +- efx_init_channels(efx); +- +- efx_start_all(efx); +-} +- + /************************************************************************** + * + * Interrupt moderation + * + **************************************************************************/ + ++static unsigned irq_mod_ticks(int usecs, int resolution) ++{ ++ if (usecs <= 0) ++ return 0; /* cannot receive interrupts ahead of time :-) */ ++ if (usecs < resolution) ++ return 1; /* never round down to 0 */ ++ return usecs / resolution; ++} ++ + /* Set interrupt moderation parameters */ + void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, + bool rx_adaptive) + { + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; ++ unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION); ++ unsigned rx_ticks = irq_mod_ticks(rx_usecs, EFX_IRQ_MOD_RESOLUTION); + + EFX_ASSERT_RESET_SERIALISED(efx); + + efx_for_each_tx_queue(tx_queue, efx) +- tx_queue->channel->irq_moderation = tx_usecs; ++ tx_queue->channel->irq_moderation = tx_ticks; + + efx->irq_rx_adaptive = rx_adaptive; +- efx->irq_rx_moderation = rx_usecs; ++ efx->irq_rx_moderation = rx_ticks; + efx_for_each_rx_queue(rx_queue, efx) +- rx_queue->channel->irq_moderation = rx_usecs; ++ rx_queue->channel->irq_moderation = rx_ticks; + } + + /************************************************************************** +@@ -1250,10 +1344,10 @@ static void efx_monitor(struct work_struct *data) + { + struct efx_nic *efx = container_of(data, struct efx_nic, + monitor_work.work); +- int rc; + + EFX_TRACE(efx, "hardware monitor executing on CPU %d\n", + raw_smp_processor_id()); ++ BUG_ON(efx->type->monitor == NULL); + + /* If the mac_lock is already held then it is likely a port + * reconfiguration is already in place, which will likely do +@@ -1262,15 +1356,7 @@ static void efx_monitor(struct work_struct *data) + goto out_requeue; + if (!efx->port_enabled) + goto out_unlock; +- rc = efx->board_info.monitor(efx); +- if (rc) { +- EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", +- (rc == -ERANGE) ? "reported fault" : "failed"); +- efx->phy_mode |= PHY_MODE_LOW_POWER; +- falcon_sim_phy_event(efx); +- } +- efx->phy_op->poll(efx); +- efx->mac_op->poll(efx); ++ efx->type->monitor(efx); + + out_unlock: + mutex_unlock(&efx->mac_lock); +@@ -1374,6 +1460,12 @@ static int efx_net_open(struct net_device *net_dev) + return -EIO; + if (efx->phy_mode & PHY_MODE_SPECIAL) + return -EBUSY; ++ if (efx_mcdi_poll_reboot(efx) && efx_reset(efx, RESET_TYPE_ALL)) ++ return -EIO; ++ ++ /* Notify the kernel of the link state polled during driver load, ++ * before the monitor starts running */ ++ efx_link_status_changed(efx); + + efx_start_all(efx); + return 0; +@@ -1400,20 +1492,6 @@ static int efx_net_stop(struct net_device *net_dev) + return 0; + } + +-void efx_stats_disable(struct efx_nic *efx) +-{ +- spin_lock(&efx->stats_lock); +- ++efx->stats_disable_count; +- spin_unlock(&efx->stats_lock); +-} +- +-void efx_stats_enable(struct efx_nic *efx) +-{ +- spin_lock(&efx->stats_lock); +- --efx->stats_disable_count; +- spin_unlock(&efx->stats_lock); +-} +- + /* Context: process, dev_base_lock or RTNL held, non-blocking. */ + static struct net_device_stats *efx_net_stats(struct net_device *net_dev) + { +@@ -1421,17 +1499,9 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) + struct efx_mac_stats *mac_stats = &efx->mac_stats; + struct net_device_stats *stats = &net_dev->stats; + +- /* Update stats if possible, but do not wait if another thread +- * is updating them or if MAC stats fetches are temporarily +- * disabled; slightly stale stats are acceptable. +- */ +- if (!spin_trylock(&efx->stats_lock)) +- return stats; +- if (!efx->stats_disable_count) { +- efx->mac_op->update_stats(efx); +- falcon_update_nic_stats(efx); +- } +- spin_unlock(&efx->stats_lock); ++ spin_lock_bh(&efx->stats_lock); ++ efx->type->update_stats(efx); ++ spin_unlock_bh(&efx->stats_lock); + + stats->rx_packets = mac_stats->rx_packets; + stats->tx_packets = mac_stats->tx_packets; +@@ -1490,7 +1560,14 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) + EFX_LOG(efx, "changing MTU to %d\n", new_mtu); + + efx_fini_channels(efx); ++ ++ mutex_lock(&efx->mac_lock); ++ /* Reconfigure the MAC before enabling the dma queues so that ++ * the RX buffers don't overflow */ + net_dev->mtu = new_mtu; ++ efx->mac_op->reconfigure(efx); ++ mutex_unlock(&efx->mac_lock); ++ + efx_init_channels(efx); + + efx_start_all(efx); +@@ -1514,7 +1591,9 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) + memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len); + + /* Reconfigure the MAC */ +- efx_reconfigure_port(efx); ++ mutex_lock(&efx->mac_lock); ++ efx->mac_op->reconfigure(efx); ++ mutex_unlock(&efx->mac_lock); + + return 0; + } +@@ -1525,16 +1604,14 @@ static void efx_set_multicast_list(struct net_device *net_dev) + struct efx_nic *efx = netdev_priv(net_dev); + struct dev_mc_list *mc_list = net_dev->mc_list; + union efx_multicast_hash *mc_hash = &efx->multicast_hash; +- bool promiscuous = !!(net_dev->flags & IFF_PROMISC); +- bool changed = (efx->promiscuous != promiscuous); + u32 crc; + int bit; + int i; + +- efx->promiscuous = promiscuous; ++ efx->promiscuous = !!(net_dev->flags & IFF_PROMISC); + + /* Build multicast hash table */ +- if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) { ++ if (efx->promiscuous || (net_dev->flags & IFF_ALLMULTI)) { + memset(mc_hash, 0xff, sizeof(*mc_hash)); + } else { + memset(mc_hash, 0x00, sizeof(*mc_hash)); +@@ -1544,17 +1621,17 @@ static void efx_set_multicast_list(struct net_device *net_dev) + set_bit_le(bit, mc_hash->byte); + mc_list = mc_list->next; + } +- } +- +- if (!efx->port_enabled) +- /* Delay pushing settings until efx_start_port() */ +- return; + +- if (changed) +- queue_work(efx->workqueue, &efx->phy_work); ++ /* Broadcast packets go through the multicast hash filter. ++ * ether_crc_le() of the broadcast address is 0xbe2612ff ++ * so we always add bit 0xff to the mask. ++ */ ++ set_bit_le(0xff, mc_hash->byte); ++ } + +- /* Create and activate new global multicast hash table */ +- falcon_set_multicast_hash(efx); ++ if (efx->port_enabled) ++ queue_work(efx->workqueue, &efx->mac_work); ++ /* Otherwise efx_start_port() will do this */ + } + + static const struct net_device_ops efx_netdev_ops = { +@@ -1683,21 +1760,18 @@ static void efx_unregister_netdev(struct efx_nic *efx) + + /* Tears down the entire software state and most of the hardware state + * before reset. */ +-void efx_reset_down(struct efx_nic *efx, enum reset_type method, +- struct ethtool_cmd *ecmd) ++void efx_reset_down(struct efx_nic *efx, enum reset_type method) + { + EFX_ASSERT_RESET_SERIALISED(efx); + +- efx_stats_disable(efx); + efx_stop_all(efx); + mutex_lock(&efx->mac_lock); + mutex_lock(&efx->spi_lock); + +- efx->phy_op->get_settings(efx, ecmd); +- + efx_fini_channels(efx); + if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) + efx->phy_op->fini(efx); ++ efx->type->fini(efx); + } + + /* This function will always ensure that the locks acquired in +@@ -1705,79 +1779,67 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method, + * that we were unable to reinitialise the hardware, and the + * driver should be disabled. If ok is false, then the rx and tx + * engines are not restarted, pending a RESET_DISABLE. */ +-int efx_reset_up(struct efx_nic *efx, enum reset_type method, +- struct ethtool_cmd *ecmd, bool ok) ++int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) + { + int rc; + + EFX_ASSERT_RESET_SERIALISED(efx); + +- rc = falcon_init_nic(efx); ++ rc = efx->type->init(efx); + if (rc) { + EFX_ERR(efx, "failed to initialise NIC\n"); +- ok = false; ++ goto fail; + } + ++ if (!ok) ++ goto fail; ++ + if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) { +- if (ok) { +- rc = efx->phy_op->init(efx); +- if (rc) +- ok = false; +- } +- if (!ok) +- efx->port_initialized = false; ++ rc = efx->phy_op->init(efx); ++ if (rc) ++ goto fail; ++ if (efx->phy_op->reconfigure(efx)) ++ EFX_ERR(efx, "could not restore PHY settings\n"); + } + +- if (ok) { +- efx_init_channels(efx); ++ efx->mac_op->reconfigure(efx); + +- if (efx->phy_op->set_settings(efx, ecmd)) +- EFX_ERR(efx, "could not restore PHY settings\n"); +- } ++ efx_init_channels(efx); ++ ++ mutex_unlock(&efx->spi_lock); ++ mutex_unlock(&efx->mac_lock); ++ ++ efx_start_all(efx); ++ ++ return 0; ++ ++fail: ++ efx->port_initialized = false; + + mutex_unlock(&efx->spi_lock); + mutex_unlock(&efx->mac_lock); + +- if (ok) { +- efx_start_all(efx); +- efx_stats_enable(efx); +- } + return rc; + } + +-/* Reset the NIC as transparently as possible. Do not reset the PHY +- * Note that the reset may fail, in which case the card will be left +- * in a most-probably-unusable state. ++/* Reset the NIC using the specified method. Note that the reset may ++ * fail, in which case the card will be left in an unusable state. + * +- * This function will sleep. You cannot reset from within an atomic +- * state; use efx_schedule_reset() instead. +- * +- * Grabs the rtnl_lock. ++ * Caller must hold the rtnl_lock. + */ +-static int efx_reset(struct efx_nic *efx) ++int efx_reset(struct efx_nic *efx, enum reset_type method) + { +- struct ethtool_cmd ecmd; +- enum reset_type method = efx->reset_pending; +- int rc = 0; ++ int rc, rc2; ++ bool disabled; + +- /* Serialise with kernel interfaces */ +- rtnl_lock(); ++ EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method)); + +- /* If we're not RUNNING then don't reset. Leave the reset_pending +- * flag set so that efx_pci_probe_main will be retried */ +- if (efx->state != STATE_RUNNING) { +- EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); +- goto out_unlock; +- } ++ efx_reset_down(efx, method); + +- EFX_INFO(efx, "resetting (%d)\n", method); +- +- efx_reset_down(efx, method, &ecmd); +- +- rc = falcon_reset_hw(efx, method); ++ rc = efx->type->reset(efx, method); + if (rc) { + EFX_ERR(efx, "failed to reset hardware\n"); +- goto out_disable; ++ goto out; + } + + /* Allow resets to be rescheduled. */ +@@ -1789,25 +1851,22 @@ static int efx_reset(struct efx_nic *efx) + * can respond to requests. */ + pci_set_master(efx->pci_dev); + ++out: + /* Leave device stopped if necessary */ +- if (method == RESET_TYPE_DISABLE) { +- efx_reset_up(efx, method, &ecmd, false); +- rc = -EIO; +- } else { +- rc = efx_reset_up(efx, method, &ecmd, true); ++ disabled = rc || method == RESET_TYPE_DISABLE; ++ rc2 = efx_reset_up(efx, method, !disabled); ++ if (rc2) { ++ disabled = true; ++ if (!rc) ++ rc = rc2; + } + +-out_disable: +- if (rc) { ++ if (disabled) { + EFX_ERR(efx, "has been disabled\n"); + efx->state = STATE_DISABLED; +- dev_close(efx->net_dev); + } else { + EFX_LOG(efx, "reset complete\n"); + } +- +-out_unlock: +- rtnl_unlock(); + return rc; + } + +@@ -1816,9 +1875,19 @@ out_unlock: + */ + static void efx_reset_work(struct work_struct *data) + { +- struct efx_nic *nic = container_of(data, struct efx_nic, reset_work); ++ struct efx_nic *efx = container_of(data, struct efx_nic, reset_work); ++ ++ /* If we're not RUNNING then don't reset. Leave the reset_pending ++ * flag set so that efx_pci_probe_main will be retried */ ++ if (efx->state != STATE_RUNNING) { ++ EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); ++ return; ++ } + +- efx_reset(nic); ++ rtnl_lock(); ++ if (efx_reset(efx, efx->reset_pending)) ++ dev_close(efx->net_dev); ++ rtnl_unlock(); + } + + void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) +@@ -1843,18 +1912,24 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) + case RESET_TYPE_TX_SKIP: + method = RESET_TYPE_INVISIBLE; + break; ++ case RESET_TYPE_MC_FAILURE: + default: + method = RESET_TYPE_ALL; + break; + } + + if (method != type) +- EFX_LOG(efx, "scheduling reset (%d:%d)\n", type, method); ++ EFX_LOG(efx, "scheduling %s reset for %s\n", ++ RESET_TYPE(method), RESET_TYPE(type)); + else +- EFX_LOG(efx, "scheduling reset (%d)\n", method); ++ EFX_LOG(efx, "scheduling %s reset\n", RESET_TYPE(method)); + + efx->reset_pending = method; + ++ /* efx_process_channel() will no longer read events once a ++ * reset is scheduled. So switch back to poll'd MCDI completions. */ ++ efx_mcdi_mode_poll(efx); ++ + queue_work(reset_workqueue, &efx->reset_work); + } + +@@ -1867,15 +1942,19 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) + /* PCI device ID table */ + static struct pci_device_id efx_pci_table[] __devinitdata = { + {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID), +- .driver_data = (unsigned long) &falcon_a_nic_type}, ++ .driver_data = (unsigned long) &falcon_a1_nic_type}, + {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID), +- .driver_data = (unsigned long) &falcon_b_nic_type}, ++ .driver_data = (unsigned long) &falcon_b0_nic_type}, ++ {PCI_DEVICE(EFX_VENDID_SFC, BETHPAGE_A_P_DEVID), ++ .driver_data = (unsigned long) &siena_a0_nic_type}, ++ {PCI_DEVICE(EFX_VENDID_SFC, SIENA_A_P_DEVID), ++ .driver_data = (unsigned long) &siena_a0_nic_type}, + {0} /* end of list */ + }; + + /************************************************************************** + * +- * Dummy PHY/MAC/Board operations ++ * Dummy PHY/MAC operations + * + * Can be used for some unimplemented operations + * Needed so all function pointers are valid and do not have to be tested +@@ -1887,29 +1966,19 @@ int efx_port_dummy_op_int(struct efx_nic *efx) + return 0; + } + void efx_port_dummy_op_void(struct efx_nic *efx) {} +-void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {} +- +-static struct efx_mac_operations efx_dummy_mac_operations = { +- .reconfigure = efx_port_dummy_op_void, +- .poll = efx_port_dummy_op_void, +- .irq = efx_port_dummy_op_void, +-}; ++void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) ++{ ++} ++bool efx_port_dummy_op_poll(struct efx_nic *efx) ++{ ++ return false; ++} + + static struct efx_phy_operations efx_dummy_phy_operations = { + .init = efx_port_dummy_op_int, +- .reconfigure = efx_port_dummy_op_void, +- .poll = efx_port_dummy_op_void, ++ .reconfigure = efx_port_dummy_op_int, ++ .poll = efx_port_dummy_op_poll, + .fini = efx_port_dummy_op_void, +- .clear_interrupt = efx_port_dummy_op_void, +-}; +- +-static struct efx_board efx_dummy_board_info = { +- .init = efx_port_dummy_op_int, +- .init_leds = efx_port_dummy_op_void, +- .set_id_led = efx_port_dummy_op_blink, +- .monitor = efx_port_dummy_op_int, +- .blink = efx_port_dummy_op_blink, +- .fini = efx_port_dummy_op_void, + }; + + /************************************************************************** +@@ -1932,26 +2001,26 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, + /* Initialise common structures */ + memset(efx, 0, sizeof(*efx)); + spin_lock_init(&efx->biu_lock); +- spin_lock_init(&efx->phy_lock); ++ mutex_init(&efx->mdio_lock); + mutex_init(&efx->spi_lock); ++#ifdef CONFIG_SFC_MTD ++ INIT_LIST_HEAD(&efx->mtd_list); ++#endif + INIT_WORK(&efx->reset_work, efx_reset_work); + INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); + efx->pci_dev = pci_dev; + efx->state = STATE_INIT; + efx->reset_pending = RESET_TYPE_NONE; + strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); +- efx->board_info = efx_dummy_board_info; + + efx->net_dev = net_dev; + efx->rx_checksum_enabled = true; + spin_lock_init(&efx->netif_stop_lock); + spin_lock_init(&efx->stats_lock); +- efx->stats_disable_count = 1; + mutex_init(&efx->mac_lock); +- efx->mac_op = &efx_dummy_mac_operations; ++ efx->mac_op = type->default_mac_ops; + efx->phy_op = &efx_dummy_phy_operations; + efx->mdio.dev = net_dev; +- INIT_WORK(&efx->phy_work, efx_phy_work); + INIT_WORK(&efx->mac_work, efx_mac_work); + atomic_set(&efx->netif_stop_count, 1); + +@@ -1981,17 +2050,9 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, + + efx->type = type; + +- /* Sanity-check NIC type */ +- EFX_BUG_ON_PARANOID(efx->type->txd_ring_mask & +- (efx->type->txd_ring_mask + 1)); +- EFX_BUG_ON_PARANOID(efx->type->rxd_ring_mask & +- (efx->type->rxd_ring_mask + 1)); +- EFX_BUG_ON_PARANOID(efx->type->evq_size & +- (efx->type->evq_size - 1)); + /* As close as we can get to guaranteeing that we don't overflow */ +- EFX_BUG_ON_PARANOID(efx->type->evq_size < +- (efx->type->txd_ring_mask + 1 + +- efx->type->rxd_ring_mask + 1)); ++ BUILD_BUG_ON(EFX_EVQ_SIZE < EFX_TXQ_SIZE + EFX_RXQ_SIZE); ++ + EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS); + + /* Higher numbered interrupt modes are less capable! */ +@@ -2027,19 +2088,10 @@ static void efx_fini_struct(struct efx_nic *efx) + */ + static void efx_pci_remove_main(struct efx_nic *efx) + { +- EFX_ASSERT_RESET_SERIALISED(efx); +- +- /* Skip everything if we never obtained a valid membase */ +- if (!efx->membase) +- return; +- ++ efx_nic_fini_interrupt(efx); + efx_fini_channels(efx); + efx_fini_port(efx); +- +- /* Shutdown the board, then the NIC and board state */ +- efx->board_info.fini(efx); +- falcon_fini_interrupt(efx); +- ++ efx->type->fini(efx); + efx_fini_napi(efx); + efx_remove_all(efx); + } +@@ -2063,9 +2115,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev) + /* Allow any queued efx_resets() to complete */ + rtnl_unlock(); + +- if (efx->membase == NULL) +- goto out; +- + efx_unregister_netdev(efx); + + efx_mtd_remove(efx); +@@ -2078,7 +2127,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev) + + efx_pci_remove_main(efx); + +-out: + efx_fini_io(efx); + EFX_LOG(efx, "shutdown successful\n"); + +@@ -2103,39 +2151,31 @@ static int efx_pci_probe_main(struct efx_nic *efx) + if (rc) + goto fail2; + +- /* Initialise the board */ +- rc = efx->board_info.init(efx); +- if (rc) { +- EFX_ERR(efx, "failed to initialise board\n"); +- goto fail3; +- } +- +- rc = falcon_init_nic(efx); ++ rc = efx->type->init(efx); + if (rc) { + EFX_ERR(efx, "failed to initialise NIC\n"); +- goto fail4; ++ goto fail3; + } + + rc = efx_init_port(efx); + if (rc) { + EFX_ERR(efx, "failed to initialise port\n"); +- goto fail5; ++ goto fail4; + } + + efx_init_channels(efx); + +- rc = falcon_init_interrupt(efx); ++ rc = efx_nic_init_interrupt(efx); + if (rc) +- goto fail6; ++ goto fail5; + + return 0; + +- fail6: ++ fail5: + efx_fini_channels(efx); + efx_fini_port(efx); +- fail5: + fail4: +- efx->board_info.fini(efx); ++ efx->type->fini(efx); + fail3: + efx_fini_napi(efx); + fail2: +@@ -2165,9 +2205,11 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, + net_dev = alloc_etherdev(sizeof(*efx)); + if (!net_dev) + return -ENOMEM; +- net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG | ++ net_dev->features |= (type->offload_features | NETIF_F_SG | + NETIF_F_HIGHDMA | NETIF_F_TSO | + NETIF_F_GRO); ++ if (type->offload_features & NETIF_F_V6_CSUM) ++ net_dev->features |= NETIF_F_TSO6; + /* Mask for features that also apply to VLAN devices */ + net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG | + NETIF_F_HIGHDMA | NETIF_F_TSO); +@@ -2219,18 +2261,19 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, + goto fail4; + } + +- /* Switch to the running state before we expose the device to +- * the OS. This is to ensure that the initial gathering of +- * MAC stats succeeds. */ ++ /* Switch to the running state before we expose the device to the OS, ++ * so that dev_open()|efx_start_all() will actually start the device */ + efx->state = STATE_RUNNING; + +- efx_mtd_probe(efx); /* allowed to fail */ +- + rc = efx_register_netdev(efx); + if (rc) + goto fail5; + + EFX_LOG(efx, "initialisation successful\n"); ++ ++ rtnl_lock(); ++ efx_mtd_probe(efx); /* allowed to fail */ ++ rtnl_unlock(); + return 0; + + fail5: +@@ -2246,11 +2289,107 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, + return rc; + } + ++static int efx_pm_freeze(struct device *dev) ++{ ++ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); ++ ++ efx->state = STATE_FINI; ++ ++ netif_device_detach(efx->net_dev); ++ ++ efx_stop_all(efx); ++ efx_fini_channels(efx); ++ ++ return 0; ++} ++ ++static int efx_pm_thaw(struct device *dev) ++{ ++ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); ++ ++ efx->state = STATE_INIT; ++ ++ efx_init_channels(efx); ++ ++ mutex_lock(&efx->mac_lock); ++ efx->phy_op->reconfigure(efx); ++ mutex_unlock(&efx->mac_lock); ++ ++ efx_start_all(efx); ++ ++ netif_device_attach(efx->net_dev); ++ ++ efx->state = STATE_RUNNING; ++ ++ efx->type->resume_wol(efx); ++ ++ return 0; ++} ++ ++static int efx_pm_poweroff(struct device *dev) ++{ ++ struct pci_dev *pci_dev = to_pci_dev(dev); ++ struct efx_nic *efx = pci_get_drvdata(pci_dev); ++ ++ efx->type->fini(efx); ++ ++ efx->reset_pending = RESET_TYPE_NONE; ++ ++ pci_save_state(pci_dev); ++ return pci_set_power_state(pci_dev, PCI_D3hot); ++} ++ ++/* Used for both resume and restore */ ++static int efx_pm_resume(struct device *dev) ++{ ++ struct pci_dev *pci_dev = to_pci_dev(dev); ++ struct efx_nic *efx = pci_get_drvdata(pci_dev); ++ int rc; ++ ++ rc = pci_set_power_state(pci_dev, PCI_D0); ++ if (rc) ++ return rc; ++ pci_restore_state(pci_dev); ++ rc = pci_enable_device(pci_dev); ++ if (rc) ++ return rc; ++ pci_set_master(efx->pci_dev); ++ rc = efx->type->reset(efx, RESET_TYPE_ALL); ++ if (rc) ++ return rc; ++ rc = efx->type->init(efx); ++ if (rc) ++ return rc; ++ efx_pm_thaw(dev); ++ return 0; ++} ++ ++static int efx_pm_suspend(struct device *dev) ++{ ++ int rc; ++ ++ efx_pm_freeze(dev); ++ rc = efx_pm_poweroff(dev); ++ if (rc) ++ efx_pm_resume(dev); ++ return rc; ++} ++ ++static struct dev_pm_ops efx_pm_ops = { ++ .suspend = efx_pm_suspend, ++ .resume = efx_pm_resume, ++ .freeze = efx_pm_freeze, ++ .thaw = efx_pm_thaw, ++ .poweroff = efx_pm_poweroff, ++ .restore = efx_pm_resume, ++}; ++ + static struct pci_driver efx_pci_driver = { + .name = EFX_DRIVER_NAME, + .id_table = efx_pci_table, + .probe = efx_pci_probe, + .remove = efx_pci_remove, ++ .driver.pm = &efx_pm_ops, + }; + + /************************************************************************** +@@ -2314,8 +2453,8 @@ static void __exit efx_exit_module(void) + module_init(efx_init_module); + module_exit(efx_exit_module); + +-MODULE_AUTHOR("Michael Brown and " +- "Solarflare Communications"); ++MODULE_AUTHOR("Solarflare Communications and " ++ "Michael Brown "); + MODULE_DESCRIPTION("Solarflare Communications network driver"); + MODULE_LICENSE("GPL"); + MODULE_DEVICE_TABLE(pci, efx_pci_table); +diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h +index aecaf62..a615ac0 100644 +--- a/drivers/net/sfc/efx.h ++++ b/drivers/net/sfc/efx.h +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -18,35 +18,64 @@ + #define FALCON_A_P_DEVID 0x0703 + #define FALCON_A_S_DEVID 0x6703 + #define FALCON_B_P_DEVID 0x0710 ++#define BETHPAGE_A_P_DEVID 0x0803 ++#define SIENA_A_P_DEVID 0x0813 ++ ++/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ ++#define EFX_MEM_BAR 2 + + /* TX */ +-extern netdev_tx_t efx_xmit(struct efx_nic *efx, +- struct efx_tx_queue *tx_queue, +- struct sk_buff *skb); ++extern int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); ++extern void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); ++extern void efx_init_tx_queue(struct efx_tx_queue *tx_queue); ++extern void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); ++extern void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); ++extern netdev_tx_t ++efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); ++extern netdev_tx_t ++efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); ++extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); + extern void efx_stop_queue(struct efx_nic *efx); + extern void efx_wake_queue(struct efx_nic *efx); ++#define EFX_TXQ_SIZE 1024 ++#define EFX_TXQ_MASK (EFX_TXQ_SIZE - 1) + + /* RX */ +-extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); ++extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); ++extern void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); ++extern void efx_init_rx_queue(struct efx_rx_queue *rx_queue); ++extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue); ++extern void efx_rx_strategy(struct efx_channel *channel); ++extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue); ++extern void efx_rx_work(struct work_struct *data); ++extern void __efx_rx_packet(struct efx_channel *channel, ++ struct efx_rx_buffer *rx_buf, bool checksummed); + extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, + unsigned int len, bool checksummed, bool discard); + extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay); ++#define EFX_RXQ_SIZE 1024 ++#define EFX_RXQ_MASK (EFX_RXQ_SIZE - 1) + + /* Channels */ + extern void efx_process_channel_now(struct efx_channel *channel); +-extern void efx_flush_queues(struct efx_nic *efx); ++#define EFX_EVQ_SIZE 4096 ++#define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1) + + /* Ports */ +-extern void efx_stats_disable(struct efx_nic *efx); +-extern void efx_stats_enable(struct efx_nic *efx); +-extern void efx_reconfigure_port(struct efx_nic *efx); +-extern void __efx_reconfigure_port(struct efx_nic *efx); ++extern int efx_reconfigure_port(struct efx_nic *efx); ++extern int __efx_reconfigure_port(struct efx_nic *efx); ++ ++/* Ethtool support */ ++extern int efx_ethtool_get_settings(struct net_device *net_dev, ++ struct ethtool_cmd *ecmd); ++extern int efx_ethtool_set_settings(struct net_device *net_dev, ++ struct ethtool_cmd *ecmd); ++extern const struct ethtool_ops efx_ethtool_ops; + + /* Reset handling */ +-extern void efx_reset_down(struct efx_nic *efx, enum reset_type method, +- struct ethtool_cmd *ecmd); +-extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, +- struct ethtool_cmd *ecmd, bool ok); ++extern int efx_reset(struct efx_nic *efx, enum reset_type method); ++extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); ++extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); + + /* Global */ + extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); +@@ -60,7 +89,9 @@ extern void efx_hex_dump(const u8 *, unsigned int, const char *); + /* Dummy PHY ops for PHY drivers */ + extern int efx_port_dummy_op_int(struct efx_nic *efx); + extern void efx_port_dummy_op_void(struct efx_nic *efx); +-extern void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink); ++extern void ++efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); ++extern bool efx_port_dummy_op_poll(struct efx_nic *efx); + + /* MTD */ + #ifdef CONFIG_SFC_MTD +@@ -84,4 +115,8 @@ static inline void efx_schedule_channel(struct efx_channel *channel) + napi_schedule(&channel->napi_str); + } + ++extern void efx_link_status_changed(struct efx_nic *efx); ++extern void efx_link_set_advertising(struct efx_nic *efx, u32); ++extern void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type); ++ + #endif /* EFX_EFX_H */ +diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h +index 60cbc6e..384cfe3 100644 +--- a/drivers/net/sfc/enum.h ++++ b/drivers/net/sfc/enum.h +@@ -1,6 +1,6 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2007-2008 Solarflare Communications Inc. ++ * Copyright 2007-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -13,44 +13,101 @@ + /** + * enum efx_loopback_mode - loopback modes + * @LOOPBACK_NONE: no loopback +- * @LOOPBACK_GMAC: loopback within GMAC at unspecified level +- * @LOOPBACK_XGMII: loopback within XMAC at XGMII level +- * @LOOPBACK_XGXS: loopback within XMAC at XGXS level +- * @LOOPBACK_XAUI: loopback within XMAC at XAUI level ++ * @LOOPBACK_DATA: data path loopback ++ * @LOOPBACK_GMAC: loopback within GMAC ++ * @LOOPBACK_XGMII: loopback after XMAC ++ * @LOOPBACK_XGXS: loopback within BPX after XGXS ++ * @LOOPBACK_XAUI: loopback within BPX before XAUI serdes ++ * @LOOPBACK_GMII: loopback within BPX after GMAC ++ * @LOOPBACK_SGMII: loopback within BPX within SGMII ++ * @LOOPBACK_XGBR: loopback within BPX within XGBR ++ * @LOOPBACK_XFI: loopback within BPX before XFI serdes ++ * @LOOPBACK_XAUI_FAR: loopback within BPX after XAUI serdes ++ * @LOOPBACK_GMII_FAR: loopback within BPX before SGMII ++ * @LOOPBACK_SGMII_FAR: loopback within BPX after SGMII ++ * @LOOPBACK_XFI_FAR: loopback after XFI serdes + * @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level + * @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level + * @LOOPBACK_PCS: loopback within 10G PHY at PCS level + * @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level +- * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!) ++ * @LOOPBACK_XPORT: cross port loopback ++ * @LOOPBACK_XGMII_WS: wireside loopback excluding XMAC ++ * @LOOPBACK_XAUI_WS: wireside loopback within BPX within XAUI serdes ++ * @LOOPBACK_XAUI_WS_FAR: wireside loopback within BPX including XAUI serdes ++ * @LOOPBACK_XAUI_WS_NEAR: wireside loopback within BPX excluding XAUI serdes ++ * @LOOPBACK_GMII_WS: wireside loopback excluding GMAC ++ * @LOOPBACK_XFI_WS: wireside loopback excluding XFI serdes ++ * @LOOPBACK_XFI_WS_FAR: wireside loopback including XFI serdes ++ * @LOOPBACK_PHYXS_WS: wireside loopback within 10G PHY at PHYXS level + */ +-/* Please keep in order and up-to-date w.r.t the following two #defines */ ++/* Please keep up-to-date w.r.t the following two #defines */ + enum efx_loopback_mode { + LOOPBACK_NONE = 0, +- LOOPBACK_GMAC = 1, +- LOOPBACK_XGMII = 2, +- LOOPBACK_XGXS = 3, +- LOOPBACK_XAUI = 4, +- LOOPBACK_GPHY = 5, +- LOOPBACK_PHYXS = 6, +- LOOPBACK_PCS = 7, +- LOOPBACK_PMAPMD = 8, +- LOOPBACK_NETWORK = 9, ++ LOOPBACK_DATA = 1, ++ LOOPBACK_GMAC = 2, ++ LOOPBACK_XGMII = 3, ++ LOOPBACK_XGXS = 4, ++ LOOPBACK_XAUI = 5, ++ LOOPBACK_GMII = 6, ++ LOOPBACK_SGMII = 7, ++ LOOPBACK_XGBR = 8, ++ LOOPBACK_XFI = 9, ++ LOOPBACK_XAUI_FAR = 10, ++ LOOPBACK_GMII_FAR = 11, ++ LOOPBACK_SGMII_FAR = 12, ++ LOOPBACK_XFI_FAR = 13, ++ LOOPBACK_GPHY = 14, ++ LOOPBACK_PHYXS = 15, ++ LOOPBACK_PCS = 16, ++ LOOPBACK_PMAPMD = 17, ++ LOOPBACK_XPORT = 18, ++ LOOPBACK_XGMII_WS = 19, ++ LOOPBACK_XAUI_WS = 20, ++ LOOPBACK_XAUI_WS_FAR = 21, ++ LOOPBACK_XAUI_WS_NEAR = 22, ++ LOOPBACK_GMII_WS = 23, ++ LOOPBACK_XFI_WS = 24, ++ LOOPBACK_XFI_WS_FAR = 25, ++ LOOPBACK_PHYXS_WS = 26, + LOOPBACK_MAX + }; +- + #define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD + +-extern const char *efx_loopback_mode_names[]; +-#define LOOPBACK_MODE_NAME(mode) \ +- STRING_TABLE_LOOKUP(mode, efx_loopback_mode) +-#define LOOPBACK_MODE(efx) \ +- LOOPBACK_MODE_NAME(efx->loopback_mode) +- + /* These loopbacks occur within the controller */ +-#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_GMAC) | \ +- (1 << LOOPBACK_XGMII)| \ +- (1 << LOOPBACK_XGXS) | \ +- (1 << LOOPBACK_XAUI)) ++#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_DATA) | \ ++ (1 << LOOPBACK_GMAC) | \ ++ (1 << LOOPBACK_XGMII)| \ ++ (1 << LOOPBACK_XGXS) | \ ++ (1 << LOOPBACK_XAUI) | \ ++ (1 << LOOPBACK_GMII) | \ ++ (1 << LOOPBACK_SGMII) | \ ++ (1 << LOOPBACK_SGMII) | \ ++ (1 << LOOPBACK_XGBR) | \ ++ (1 << LOOPBACK_XFI) | \ ++ (1 << LOOPBACK_XAUI_FAR) | \ ++ (1 << LOOPBACK_GMII_FAR) | \ ++ (1 << LOOPBACK_SGMII_FAR) | \ ++ (1 << LOOPBACK_XFI_FAR) | \ ++ (1 << LOOPBACK_XGMII_WS) | \ ++ (1 << LOOPBACK_XAUI_WS) | \ ++ (1 << LOOPBACK_XAUI_WS_FAR) | \ ++ (1 << LOOPBACK_XAUI_WS_NEAR) | \ ++ (1 << LOOPBACK_GMII_WS) | \ ++ (1 << LOOPBACK_XFI_WS) | \ ++ (1 << LOOPBACK_XFI_WS_FAR)) ++ ++#define LOOPBACKS_WS ((1 << LOOPBACK_XGMII_WS) | \ ++ (1 << LOOPBACK_XAUI_WS) | \ ++ (1 << LOOPBACK_XAUI_WS_FAR) | \ ++ (1 << LOOPBACK_XAUI_WS_NEAR) | \ ++ (1 << LOOPBACK_GMII_WS) | \ ++ (1 << LOOPBACK_XFI_WS) | \ ++ (1 << LOOPBACK_XFI_WS_FAR) | \ ++ (1 << LOOPBACK_PHYXS_WS)) ++ ++#define LOOPBACKS_EXTERNAL(_efx) \ ++ ((_efx)->loopback_modes & ~LOOPBACKS_INTERNAL & \ ++ ~(1 << LOOPBACK_NONE)) + + #define LOOPBACK_MASK(_efx) \ + (1 << (_efx)->loopback_mode) +@@ -58,6 +115,9 @@ extern const char *efx_loopback_mode_names[]; + #define LOOPBACK_INTERNAL(_efx) \ + (!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx))) + ++#define LOOPBACK_EXTERNAL(_efx) \ ++ (!!(LOOPBACK_MASK(_efx) & LOOPBACKS_EXTERNAL(_efx))) ++ + #define LOOPBACK_CHANGED(_from, _to, _mask) \ + (!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask))) + +@@ -84,6 +144,7 @@ extern const char *efx_loopback_mode_names[]; + * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch + * @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch + * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors ++ * @RESET_TYPE_MC_FAILURE: MC reboot/assertion + */ + enum reset_type { + RESET_TYPE_NONE = -1, +@@ -98,6 +159,7 @@ enum reset_type { + RESET_TYPE_RX_DESC_FETCH, + RESET_TYPE_TX_DESC_FETCH, + RESET_TYPE_TX_SKIP, ++ RESET_TYPE_MC_FAILURE, + RESET_TYPE_MAX, + }; + +diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c +index 45018f2..6c0bbed 100644 +--- a/drivers/net/sfc/ethtool.c ++++ b/drivers/net/sfc/ethtool.c +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -10,30 +10,15 @@ + + #include + #include +-#include + #include + #include "net_driver.h" + #include "workarounds.h" + #include "selftest.h" + #include "efx.h" +-#include "ethtool.h" +-#include "falcon.h" ++#include "nic.h" + #include "spi.h" + #include "mdio_10g.h" + +-const char *efx_loopback_mode_names[] = { +- [LOOPBACK_NONE] = "NONE", +- [LOOPBACK_GMAC] = "GMAC", +- [LOOPBACK_XGMII] = "XGMII", +- [LOOPBACK_XGXS] = "XGXS", +- [LOOPBACK_XAUI] = "XAUI", +- [LOOPBACK_GPHY] = "GPHY", +- [LOOPBACK_PHYXS] = "PHYXS", +- [LOOPBACK_PCS] = "PCS", +- [LOOPBACK_PMAPMD] = "PMA/PMD", +- [LOOPBACK_NETWORK] = "NETWORK", +-}; +- + struct ethtool_string { + char name[ETH_GSTRING_LEN]; + }; +@@ -167,6 +152,7 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err), ++ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc), + }; + +@@ -187,13 +173,15 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) + { + struct efx_nic *efx = netdev_priv(net_dev); + +- efx->board_info.blink(efx, 1); +- set_current_state(TASK_INTERRUPTIBLE); +- if (count) +- schedule_timeout(count * HZ); +- else +- schedule(); +- efx->board_info.blink(efx, 0); ++ do { ++ efx->type->set_id_led(efx, EFX_LED_ON); ++ schedule_timeout_interruptible(HZ / 2); ++ ++ efx->type->set_id_led(efx, EFX_LED_OFF); ++ schedule_timeout_interruptible(HZ / 2); ++ } while (!signal_pending(current) && --count != 0); ++ ++ efx->type->set_id_led(efx, EFX_LED_DEFAULT); + return 0; + } + +@@ -202,6 +190,7 @@ int efx_ethtool_get_settings(struct net_device *net_dev, + struct ethtool_cmd *ecmd) + { + struct efx_nic *efx = netdev_priv(net_dev); ++ struct efx_link_state *link_state = &efx->link_state; + + mutex_lock(&efx->mac_lock); + efx->phy_op->get_settings(efx, ecmd); +@@ -209,6 +198,13 @@ int efx_ethtool_get_settings(struct net_device *net_dev, + + /* Falcon GMAC does not support 1000Mbps HD */ + ecmd->supported &= ~SUPPORTED_1000baseT_Half; ++ /* Both MACs support pause frames (bidirectional and respond-only) */ ++ ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; ++ ++ if (LOOPBACK_INTERNAL(efx)) { ++ ecmd->speed = link_state->speed; ++ ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; ++ } + + return 0; + } +@@ -230,9 +226,6 @@ int efx_ethtool_set_settings(struct net_device *net_dev, + mutex_lock(&efx->mac_lock); + rc = efx->phy_op->set_settings(efx, ecmd); + mutex_unlock(&efx->mac_lock); +- if (!rc) +- efx_reconfigure_port(efx); +- + return rc; + } + +@@ -243,6 +236,9 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev, + + strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver)); + strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); ++ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) ++ siena_print_fwver(efx, info->fw_version, ++ sizeof(info->fw_version)); + strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); + } + +@@ -289,7 +285,7 @@ static void efx_fill_test(unsigned int test_index, + #define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue + #define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue + #define EFX_LOOPBACK_NAME(_mode, _counter) \ +- "loopback.%s." _counter, LOOPBACK_MODE_NAME(mode) ++ "loopback.%s." _counter, STRING_TABLE_LOOKUP(_mode, efx_loopback_mode) + + /** + * efx_fill_loopback_test - fill in a block of loopback self-test entries +@@ -372,9 +368,21 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, + efx_fill_test(n++, strings, data, &tests->registers, + "core", 0, "registers", NULL); + +- for (i = 0; i < efx->phy_op->num_tests; i++) +- efx_fill_test(n++, strings, data, &tests->phy[i], +- "phy", 0, efx->phy_op->test_names[i], NULL); ++ if (efx->phy_op->run_tests != NULL) { ++ EFX_BUG_ON_PARANOID(efx->phy_op->test_name == NULL); ++ ++ for (i = 0; true; ++i) { ++ const char *name; ++ ++ EFX_BUG_ON_PARANOID(i >= EFX_MAX_PHY_TESTS); ++ name = efx->phy_op->test_name(efx, i); ++ if (name == NULL) ++ break; ++ ++ efx_fill_test(n++, strings, data, &tests->phy[i], ++ "phy", 0, name, NULL); ++ } ++ } + + /* Loopback tests */ + for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { +@@ -463,6 +471,36 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, + } + } + ++static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) ++{ ++ struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev); ++ unsigned long features; ++ ++ features = NETIF_F_TSO; ++ if (efx->type->offload_features & NETIF_F_V6_CSUM) ++ features |= NETIF_F_TSO6; ++ ++ if (enable) ++ net_dev->features |= features; ++ else ++ net_dev->features &= ~features; ++ ++ return 0; ++} ++ ++static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) ++{ ++ struct efx_nic *efx = netdev_priv(net_dev); ++ unsigned long features = efx->type->offload_features & NETIF_F_ALL_CSUM; ++ ++ if (enable) ++ net_dev->features |= features; ++ else ++ net_dev->features &= ~features; ++ ++ return 0; ++} ++ + static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable) + { + struct efx_nic *efx = netdev_priv(net_dev); +@@ -537,7 +575,7 @@ static u32 efx_ethtool_get_link(struct net_device *net_dev) + { + struct efx_nic *efx = netdev_priv(net_dev); + +- return efx->link_up; ++ return efx->link_state.up; + } + + static int efx_ethtool_get_eeprom_len(struct net_device *net_dev) +@@ -562,7 +600,8 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev, + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; +- rc = falcon_spi_read(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, ++ rc = falcon_spi_read(efx, spi, ++ eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, + eeprom->len, &len, buf); + mutex_unlock(&efx->spi_lock); + +@@ -585,7 +624,8 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev, + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; +- rc = falcon_spi_write(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, ++ rc = falcon_spi_write(efx, spi, ++ eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, + eeprom->len, &len, buf); + mutex_unlock(&efx->spi_lock); + +@@ -618,6 +658,9 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev, + coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive; + coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation; + ++ coalesce->tx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION; ++ coalesce->rx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION; ++ + return 0; + } + +@@ -656,13 +699,8 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, + } + + efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive); +- +- /* Reset channel to pick up new moderation value. Note that +- * this may change the value of the irq_moderation field +- * (e.g. to allow for hardware timer granularity). +- */ + efx_for_each_channel(channel, efx) +- falcon_set_int_moderation(channel); ++ efx->type->push_irq_moderation(channel); + + return 0; + } +@@ -671,8 +709,12 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, + struct ethtool_pauseparam *pause) + { + struct efx_nic *efx = netdev_priv(net_dev); +- enum efx_fc_type wanted_fc; ++ enum efx_fc_type wanted_fc, old_fc; ++ u32 old_adv; + bool reset; ++ int rc = 0; ++ ++ mutex_lock(&efx->mac_lock); + + wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | + (pause->tx_pause ? EFX_FC_TX : 0) | +@@ -680,14 +722,14 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, + + if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { + EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto out; + } + +- if (!(efx->phy_op->mmds & MDIO_DEVS_AN) && +- (wanted_fc & EFX_FC_AUTO)) { +- EFX_LOG(efx, "PHY does not support flow control " +- "autonegotiation\n"); +- return -EINVAL; ++ if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) { ++ EFX_LOG(efx, "Autonegotiation is disabled\n"); ++ rc = -EINVAL; ++ goto out; + } + + /* TX flow control may automatically turn itself off if the +@@ -697,27 +739,40 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, + * and fix it be cycling transmit flow control on this end. */ + reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX); + if (EFX_WORKAROUND_11482(efx) && reset) { +- if (falcon_rev(efx) >= FALCON_REV_B0) { ++ if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { + /* Recover by resetting the EM block */ +- if (efx->link_up) +- falcon_drain_tx_fifo(efx); ++ falcon_stop_nic_stats(efx); ++ falcon_drain_tx_fifo(efx); ++ efx->mac_op->reconfigure(efx); ++ falcon_start_nic_stats(efx); + } else { + /* Schedule a reset to recover */ + efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); + } + } + +- /* Try to push the pause parameters */ +- mutex_lock(&efx->mac_lock); ++ old_adv = efx->link_advertising; ++ old_fc = efx->wanted_fc; ++ efx_link_set_wanted_fc(efx, wanted_fc); ++ if (efx->link_advertising != old_adv || ++ (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) { ++ rc = efx->phy_op->reconfigure(efx); ++ if (rc) { ++ EFX_ERR(efx, "Unable to advertise requested flow " ++ "control setting\n"); ++ goto out; ++ } ++ } + +- efx->wanted_fc = wanted_fc; +- if (efx->phy_op->mmds & MDIO_DEVS_AN) +- mdio45_ethtool_spauseparam_an(&efx->mdio, pause); +- __efx_reconfigure_port(efx); ++ /* Reconfigure the MAC. The PHY *may* generate a link state change event ++ * if the user just changed the advertised capabilities, but there's no ++ * harm doing this twice */ ++ efx->mac_op->reconfigure(efx); + ++out: + mutex_unlock(&efx->mac_lock); + +- return 0; ++ return rc; + } + + static void efx_ethtool_get_pauseparam(struct net_device *net_dev, +@@ -731,6 +786,50 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, + } + + ++static void efx_ethtool_get_wol(struct net_device *net_dev, ++ struct ethtool_wolinfo *wol) ++{ ++ struct efx_nic *efx = netdev_priv(net_dev); ++ return efx->type->get_wol(efx, wol); ++} ++ ++ ++static int efx_ethtool_set_wol(struct net_device *net_dev, ++ struct ethtool_wolinfo *wol) ++{ ++ struct efx_nic *efx = netdev_priv(net_dev); ++ return efx->type->set_wol(efx, wol->wolopts); ++} ++ ++extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) ++{ ++ struct efx_nic *efx = netdev_priv(net_dev); ++ enum reset_type method; ++ enum { ++ ETH_RESET_EFX_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER | ++ ETH_RESET_OFFLOAD | ETH_RESET_MAC) ++ }; ++ ++ /* Check for minimal reset flags */ ++ if ((*flags & ETH_RESET_EFX_INVISIBLE) != ETH_RESET_EFX_INVISIBLE) ++ return -EINVAL; ++ *flags ^= ETH_RESET_EFX_INVISIBLE; ++ method = RESET_TYPE_INVISIBLE; ++ ++ if (*flags & ETH_RESET_PHY) { ++ *flags ^= ETH_RESET_PHY; ++ method = RESET_TYPE_ALL; ++ } ++ ++ if ((*flags & efx->type->reset_world_flags) == ++ efx->type->reset_world_flags) { ++ *flags ^= efx->type->reset_world_flags; ++ method = RESET_TYPE_WORLD; ++ } ++ ++ return efx_reset(efx, method); ++} ++ + const struct ethtool_ops efx_ethtool_ops = { + .get_settings = efx_ethtool_get_settings, + .set_settings = efx_ethtool_set_settings, +@@ -747,11 +846,13 @@ const struct ethtool_ops efx_ethtool_ops = { + .get_rx_csum = efx_ethtool_get_rx_csum, + .set_rx_csum = efx_ethtool_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, +- .set_tx_csum = ethtool_op_set_tx_csum, ++ /* Need to enable/disable IPv6 too */ ++ .set_tx_csum = efx_ethtool_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_tso = ethtool_op_get_tso, +- .set_tso = ethtool_op_set_tso, ++ /* Need to enable/disable TSO-IPv6 too */ ++ .set_tso = efx_ethtool_set_tso, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, + .get_sset_count = efx_ethtool_get_sset_count, +@@ -759,4 +860,7 @@ const struct ethtool_ops efx_ethtool_ops = { + .get_strings = efx_ethtool_get_strings, + .phys_id = efx_ethtool_phys_id, + .get_ethtool_stats = efx_ethtool_get_stats, ++ .get_wol = efx_ethtool_get_wol, ++ .set_wol = efx_ethtool_set_wol, ++ .reset = efx_ethtool_reset, + }; +diff --git a/drivers/net/sfc/ethtool.h b/drivers/net/sfc/ethtool.h +deleted file mode 100644 +index 295ead4..0000000 +--- a/drivers/net/sfc/ethtool.h ++++ /dev/null +@@ -1,27 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2005 Fen Systems Ltd. +- * Copyright 2006 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +- +-#ifndef EFX_ETHTOOL_H +-#define EFX_ETHTOOL_H +- +-#include "net_driver.h" +- +-/* +- * Ethtool support +- */ +- +-extern int efx_ethtool_get_settings(struct net_device *net_dev, +- struct ethtool_cmd *ecmd); +-extern int efx_ethtool_set_settings(struct net_device *net_dev, +- struct ethtool_cmd *ecmd); +- +-extern const struct ethtool_ops efx_ethtool_ops; +- +-#endif /* EFX_ETHTOOL_H */ +diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c +index c049364..17afcd2 100644 +--- a/drivers/net/sfc/falcon.c ++++ b/drivers/net/sfc/falcon.c +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -14,66 +14,20 @@ + #include + #include + #include +-#include + #include + #include "net_driver.h" + #include "bitfield.h" + #include "efx.h" + #include "mac.h" + #include "spi.h" +-#include "falcon.h" +-#include "falcon_hwdefs.h" +-#include "falcon_io.h" ++#include "nic.h" ++#include "regs.h" ++#include "io.h" + #include "mdio_10g.h" + #include "phy.h" +-#include "boards.h" + #include "workarounds.h" + +-/* Falcon hardware control. +- * Falcon is the internal codename for the SFC4000 controller that is +- * present in SFE400X evaluation boards +- */ +- +-/** +- * struct falcon_nic_data - Falcon NIC state +- * @next_buffer_table: First available buffer table id +- * @pci_dev2: The secondary PCI device if present +- * @i2c_data: Operations and state for I2C bit-bashing algorithm +- * @int_error_count: Number of internal errors seen recently +- * @int_error_expire: Time at which error count will be expired +- */ +-struct falcon_nic_data { +- unsigned next_buffer_table; +- struct pci_dev *pci_dev2; +- struct i2c_algo_bit_data i2c_data; +- +- unsigned int_error_count; +- unsigned long int_error_expire; +-}; +- +-/************************************************************************** +- * +- * Configurable values +- * +- ************************************************************************** +- */ +- +-static int disable_dma_stats; +- +-/* This is set to 16 for a good reason. In summary, if larger than +- * 16, the descriptor cache holds more than a default socket +- * buffer's worth of packets (for UDP we can only have at most one +- * socket buffer's worth outstanding). This combined with the fact +- * that we only get 1 TX event per descriptor cache means the NIC +- * goes idle. +- */ +-#define TX_DC_ENTRIES 16 +-#define TX_DC_ENTRIES_ORDER 0 +-#define TX_DC_BASE 0x130000 +- +-#define RX_DC_ENTRIES 64 +-#define RX_DC_ENTRIES_ORDER 2 +-#define RX_DC_BASE 0x100000 ++/* Hardware control for SFC4000 (aka Falcon). */ + + static const unsigned int + /* "Large" EEPROM device: Atmel AT25640 or similar +@@ -89,104 +43,6 @@ default_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN) + | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN) + | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)); + +-/* RX FIFO XOFF watermark +- * +- * When the amount of the RX FIFO increases used increases past this +- * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A) +- * This also has an effect on RX/TX arbitration +- */ +-static int rx_xoff_thresh_bytes = -1; +-module_param(rx_xoff_thresh_bytes, int, 0644); +-MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold"); +- +-/* RX FIFO XON watermark +- * +- * When the amount of the RX FIFO used decreases below this +- * watermark send XON. Only used if TX flow control is enabled (ethtool -A) +- * This also has an effect on RX/TX arbitration +- */ +-static int rx_xon_thresh_bytes = -1; +-module_param(rx_xon_thresh_bytes, int, 0644); +-MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); +- +-/* TX descriptor ring size - min 512 max 4k */ +-#define FALCON_TXD_RING_ORDER TX_DESCQ_SIZE_1K +-#define FALCON_TXD_RING_SIZE 1024 +-#define FALCON_TXD_RING_MASK (FALCON_TXD_RING_SIZE - 1) +- +-/* RX descriptor ring size - min 512 max 4k */ +-#define FALCON_RXD_RING_ORDER RX_DESCQ_SIZE_1K +-#define FALCON_RXD_RING_SIZE 1024 +-#define FALCON_RXD_RING_MASK (FALCON_RXD_RING_SIZE - 1) +- +-/* Event queue size - max 32k */ +-#define FALCON_EVQ_ORDER EVQ_SIZE_4K +-#define FALCON_EVQ_SIZE 4096 +-#define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1) +- +-/* If FALCON_MAX_INT_ERRORS internal errors occur within +- * FALCON_INT_ERROR_EXPIRE seconds, we consider the NIC broken and +- * disable it. +- */ +-#define FALCON_INT_ERROR_EXPIRE 3600 +-#define FALCON_MAX_INT_ERRORS 5 +- +-/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times +- */ +-#define FALCON_FLUSH_INTERVAL 10 +-#define FALCON_FLUSH_POLL_COUNT 100 +- +-/************************************************************************** +- * +- * Falcon constants +- * +- ************************************************************************** +- */ +- +-/* DMA address mask */ +-#define FALCON_DMA_MASK DMA_BIT_MASK(46) +- +-/* TX DMA length mask (13-bit) */ +-#define FALCON_TX_DMA_MASK (4096 - 1) +- +-/* Size and alignment of special buffers (4KB) */ +-#define FALCON_BUF_SIZE 4096 +- +-/* Dummy SRAM size code */ +-#define SRM_NB_BSZ_ONCHIP_ONLY (-1) +- +-#define FALCON_IS_DUAL_FUNC(efx) \ +- (falcon_rev(efx) < FALCON_REV_B0) +- +-/************************************************************************** +- * +- * Falcon hardware access +- * +- **************************************************************************/ +- +-/* Read the current event from the event queue */ +-static inline efx_qword_t *falcon_event(struct efx_channel *channel, +- unsigned int index) +-{ +- return (((efx_qword_t *) (channel->eventq.addr)) + index); +-} +- +-/* See if an event is present +- * +- * We check both the high and low dword of the event for all ones. We +- * wrote all ones when we cleared the event, and no valid event can +- * have all ones in either its high or low dwords. This approach is +- * robust against reordering. +- * +- * Note that using a single 64-bit comparison is incorrect; even +- * though the CPU read will be atomic, the DMA write may not be. +- */ +-static inline int falcon_event_present(efx_qword_t *event) +-{ +- return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) | +- EFX_DWORD_IS_ALL_ONES(event->dword[1]))); +-} +- + /************************************************************************** + * + * I2C bus - this is a bit-bashing interface using GPIO pins +@@ -200,9 +56,9 @@ static void falcon_setsda(void *data, int state) + struct efx_nic *efx = (struct efx_nic *)data; + efx_oword_t reg; + +- falcon_read(efx, ®, GPIO_CTL_REG_KER); +- EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, !state); +- falcon_write(efx, ®, GPIO_CTL_REG_KER); ++ efx_reado(efx, ®, FR_AB_GPIO_CTL); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, !state); ++ efx_writeo(efx, ®, FR_AB_GPIO_CTL); + } + + static void falcon_setscl(void *data, int state) +@@ -210,9 +66,9 @@ static void falcon_setscl(void *data, int state) + struct efx_nic *efx = (struct efx_nic *)data; + efx_oword_t reg; + +- falcon_read(efx, ®, GPIO_CTL_REG_KER); +- EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, !state); +- falcon_write(efx, ®, GPIO_CTL_REG_KER); ++ efx_reado(efx, ®, FR_AB_GPIO_CTL); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO0_OEN, !state); ++ efx_writeo(efx, ®, FR_AB_GPIO_CTL); + } + + static int falcon_getsda(void *data) +@@ -220,8 +76,8 @@ static int falcon_getsda(void *data) + struct efx_nic *efx = (struct efx_nic *)data; + efx_oword_t reg; + +- falcon_read(efx, ®, GPIO_CTL_REG_KER); +- return EFX_OWORD_FIELD(reg, GPIO3_IN); ++ efx_reado(efx, ®, FR_AB_GPIO_CTL); ++ return EFX_OWORD_FIELD(reg, FRF_AB_GPIO3_IN); + } + + static int falcon_getscl(void *data) +@@ -229,8 +85,8 @@ static int falcon_getscl(void *data) + struct efx_nic *efx = (struct efx_nic *)data; + efx_oword_t reg; + +- falcon_read(efx, ®, GPIO_CTL_REG_KER); +- return EFX_OWORD_FIELD(reg, GPIO0_IN); ++ efx_reado(efx, ®, FR_AB_GPIO_CTL); ++ return EFX_OWORD_FIELD(reg, FRF_AB_GPIO0_IN); + } + + static struct i2c_algo_bit_data falcon_i2c_bit_operations = { +@@ -243,1115 +99,39 @@ static struct i2c_algo_bit_data falcon_i2c_bit_operations = { + .timeout = DIV_ROUND_UP(HZ, 20), + }; + +-/************************************************************************** +- * +- * Falcon special buffer handling +- * Special buffers are used for event queues and the TX and RX +- * descriptor rings. +- * +- *************************************************************************/ +- +-/* +- * Initialise a Falcon special buffer +- * +- * This will define a buffer (previously allocated via +- * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing +- * it to be used for event queues, descriptor rings etc. +- */ +-static void +-falcon_init_special_buffer(struct efx_nic *efx, +- struct efx_special_buffer *buffer) +-{ +- efx_qword_t buf_desc; +- int index; +- dma_addr_t dma_addr; +- int i; +- +- EFX_BUG_ON_PARANOID(!buffer->addr); +- +- /* Write buffer descriptors to NIC */ +- for (i = 0; i < buffer->entries; i++) { +- index = buffer->index + i; +- dma_addr = buffer->dma_addr + (i * 4096); +- EFX_LOG(efx, "mapping special buffer %d at %llx\n", +- index, (unsigned long long)dma_addr); +- EFX_POPULATE_QWORD_4(buf_desc, +- IP_DAT_BUF_SIZE, IP_DAT_BUF_SIZE_4K, +- BUF_ADR_REGION, 0, +- BUF_ADR_FBUF, (dma_addr >> 12), +- BUF_OWNER_ID_FBUF, 0); +- falcon_write_sram(efx, &buf_desc, index); +- } +-} +- +-/* Unmaps a buffer from Falcon and clears the buffer table entries */ +-static void +-falcon_fini_special_buffer(struct efx_nic *efx, +- struct efx_special_buffer *buffer) +-{ +- efx_oword_t buf_tbl_upd; +- unsigned int start = buffer->index; +- unsigned int end = (buffer->index + buffer->entries - 1); +- +- if (!buffer->entries) +- return; +- +- EFX_LOG(efx, "unmapping special buffers %d-%d\n", +- buffer->index, buffer->index + buffer->entries - 1); +- +- EFX_POPULATE_OWORD_4(buf_tbl_upd, +- BUF_UPD_CMD, 0, +- BUF_CLR_CMD, 1, +- BUF_CLR_END_ID, end, +- BUF_CLR_START_ID, start); +- falcon_write(efx, &buf_tbl_upd, BUF_TBL_UPD_REG_KER); +-} +- +-/* +- * Allocate a new Falcon special buffer +- * +- * This allocates memory for a new buffer, clears it and allocates a +- * new buffer ID range. It does not write into Falcon's buffer table. +- * +- * This call will allocate 4KB buffers, since Falcon can't use 8KB +- * buffers for event queues and descriptor rings. +- */ +-static int falcon_alloc_special_buffer(struct efx_nic *efx, +- struct efx_special_buffer *buffer, +- unsigned int len) +-{ +- struct falcon_nic_data *nic_data = efx->nic_data; +- +- len = ALIGN(len, FALCON_BUF_SIZE); +- +- buffer->addr = pci_alloc_consistent(efx->pci_dev, len, +- &buffer->dma_addr); +- if (!buffer->addr) +- return -ENOMEM; +- buffer->len = len; +- buffer->entries = len / FALCON_BUF_SIZE; +- BUG_ON(buffer->dma_addr & (FALCON_BUF_SIZE - 1)); +- +- /* All zeros is a potentially valid event so memset to 0xff */ +- memset(buffer->addr, 0xff, len); +- +- /* Select new buffer ID */ +- buffer->index = nic_data->next_buffer_table; +- nic_data->next_buffer_table += buffer->entries; +- +- EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x " +- "(virt %p phys %llx)\n", buffer->index, +- buffer->index + buffer->entries - 1, +- (u64)buffer->dma_addr, len, +- buffer->addr, (u64)virt_to_phys(buffer->addr)); +- +- return 0; +-} +- +-static void falcon_free_special_buffer(struct efx_nic *efx, +- struct efx_special_buffer *buffer) +-{ +- if (!buffer->addr) +- return; +- +- EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x " +- "(virt %p phys %llx)\n", buffer->index, +- buffer->index + buffer->entries - 1, +- (u64)buffer->dma_addr, buffer->len, +- buffer->addr, (u64)virt_to_phys(buffer->addr)); +- +- pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr, +- buffer->dma_addr); +- buffer->addr = NULL; +- buffer->entries = 0; +-} +- +-/************************************************************************** +- * +- * Falcon generic buffer handling +- * These buffers are used for interrupt status and MAC stats +- * +- **************************************************************************/ +- +-static int falcon_alloc_buffer(struct efx_nic *efx, +- struct efx_buffer *buffer, unsigned int len) +-{ +- buffer->addr = pci_alloc_consistent(efx->pci_dev, len, +- &buffer->dma_addr); +- if (!buffer->addr) +- return -ENOMEM; +- buffer->len = len; +- memset(buffer->addr, 0, len); +- return 0; +-} +- +-static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) +-{ +- if (buffer->addr) { +- pci_free_consistent(efx->pci_dev, buffer->len, +- buffer->addr, buffer->dma_addr); +- buffer->addr = NULL; +- } +-} +- +-/************************************************************************** +- * +- * Falcon TX path +- * +- **************************************************************************/ +- +-/* Returns a pointer to the specified transmit descriptor in the TX +- * descriptor queue belonging to the specified channel. +- */ +-static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue, +- unsigned int index) +-{ +- return (((efx_qword_t *) (tx_queue->txd.addr)) + index); +-} +- +-/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */ +-static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue) +-{ +- unsigned write_ptr; +- efx_dword_t reg; +- +- write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK; +- EFX_POPULATE_DWORD_1(reg, TX_DESC_WPTR_DWORD, write_ptr); +- falcon_writel_page(tx_queue->efx, ®, +- TX_DESC_UPD_REG_KER_DWORD, tx_queue->queue); +-} +- +- +-/* For each entry inserted into the software descriptor ring, create a +- * descriptor in the hardware TX descriptor ring (in host memory), and +- * write a doorbell. +- */ +-void falcon_push_buffers(struct efx_tx_queue *tx_queue) +-{ +- +- struct efx_tx_buffer *buffer; +- efx_qword_t *txd; +- unsigned write_ptr; +- +- BUG_ON(tx_queue->write_count == tx_queue->insert_count); +- +- do { +- write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK; +- buffer = &tx_queue->buffer[write_ptr]; +- txd = falcon_tx_desc(tx_queue, write_ptr); +- ++tx_queue->write_count; +- +- /* Create TX descriptor ring entry */ +- EFX_POPULATE_QWORD_5(*txd, +- TX_KER_PORT, 0, +- TX_KER_CONT, buffer->continuation, +- TX_KER_BYTE_CNT, buffer->len, +- TX_KER_BUF_REGION, 0, +- TX_KER_BUF_ADR, buffer->dma_addr); +- } while (tx_queue->write_count != tx_queue->insert_count); +- +- wmb(); /* Ensure descriptors are written before they are fetched */ +- falcon_notify_tx_desc(tx_queue); +-} +- +-/* Allocate hardware resources for a TX queue */ +-int falcon_probe_tx(struct efx_tx_queue *tx_queue) +-{ +- struct efx_nic *efx = tx_queue->efx; +- return falcon_alloc_special_buffer(efx, &tx_queue->txd, +- FALCON_TXD_RING_SIZE * +- sizeof(efx_qword_t)); +-} +- +-void falcon_init_tx(struct efx_tx_queue *tx_queue) +-{ +- efx_oword_t tx_desc_ptr; +- struct efx_nic *efx = tx_queue->efx; +- +- tx_queue->flushed = false; +- +- /* Pin TX descriptor ring */ +- falcon_init_special_buffer(efx, &tx_queue->txd); +- +- /* Push TX descriptor ring to card */ +- EFX_POPULATE_OWORD_10(tx_desc_ptr, +- TX_DESCQ_EN, 1, +- TX_ISCSI_DDIG_EN, 0, +- TX_ISCSI_HDIG_EN, 0, +- TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index, +- TX_DESCQ_EVQ_ID, tx_queue->channel->channel, +- TX_DESCQ_OWNER_ID, 0, +- TX_DESCQ_LABEL, tx_queue->queue, +- TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER, +- TX_DESCQ_TYPE, 0, +- TX_NON_IP_DROP_DIS_B0, 1); +- +- if (falcon_rev(efx) >= FALCON_REV_B0) { +- int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM; +- EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, !csum); +- EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, !csum); +- } +- +- falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, +- tx_queue->queue); +- +- if (falcon_rev(efx) < FALCON_REV_B0) { +- efx_oword_t reg; +- +- /* Only 128 bits in this register */ +- BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128); +- +- falcon_read(efx, ®, TX_CHKSM_CFG_REG_KER_A1); +- if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM) +- clear_bit_le(tx_queue->queue, (void *)®); +- else +- set_bit_le(tx_queue->queue, (void *)®); +- falcon_write(efx, ®, TX_CHKSM_CFG_REG_KER_A1); +- } +-} +- +-static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) +-{ +- struct efx_nic *efx = tx_queue->efx; +- efx_oword_t tx_flush_descq; +- +- /* Post a flush command */ +- EFX_POPULATE_OWORD_2(tx_flush_descq, +- TX_FLUSH_DESCQ_CMD, 1, +- TX_FLUSH_DESCQ, tx_queue->queue); +- falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER); +-} +- +-void falcon_fini_tx(struct efx_tx_queue *tx_queue) +-{ +- struct efx_nic *efx = tx_queue->efx; +- efx_oword_t tx_desc_ptr; +- +- /* The queue should have been flushed */ +- WARN_ON(!tx_queue->flushed); +- +- /* Remove TX descriptor ring from card */ +- EFX_ZERO_OWORD(tx_desc_ptr); +- falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, +- tx_queue->queue); +- +- /* Unpin TX descriptor ring */ +- falcon_fini_special_buffer(efx, &tx_queue->txd); +-} +- +-/* Free buffers backing TX queue */ +-void falcon_remove_tx(struct efx_tx_queue *tx_queue) +-{ +- falcon_free_special_buffer(tx_queue->efx, &tx_queue->txd); +-} +- +-/************************************************************************** +- * +- * Falcon RX path +- * +- **************************************************************************/ +- +-/* Returns a pointer to the specified descriptor in the RX descriptor queue */ +-static inline efx_qword_t *falcon_rx_desc(struct efx_rx_queue *rx_queue, +- unsigned int index) +-{ +- return (((efx_qword_t *) (rx_queue->rxd.addr)) + index); +-} +- +-/* This creates an entry in the RX descriptor queue */ +-static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue, +- unsigned index) +-{ +- struct efx_rx_buffer *rx_buf; +- efx_qword_t *rxd; +- +- rxd = falcon_rx_desc(rx_queue, index); +- rx_buf = efx_rx_buffer(rx_queue, index); +- EFX_POPULATE_QWORD_3(*rxd, +- RX_KER_BUF_SIZE, +- rx_buf->len - +- rx_queue->efx->type->rx_buffer_padding, +- RX_KER_BUF_REGION, 0, +- RX_KER_BUF_ADR, rx_buf->dma_addr); +-} +- +-/* This writes to the RX_DESC_WPTR register for the specified receive +- * descriptor ring. +- */ +-void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue) +-{ +- efx_dword_t reg; +- unsigned write_ptr; +- +- while (rx_queue->notified_count != rx_queue->added_count) { +- falcon_build_rx_desc(rx_queue, +- rx_queue->notified_count & +- FALCON_RXD_RING_MASK); +- ++rx_queue->notified_count; +- } +- +- wmb(); +- write_ptr = rx_queue->added_count & FALCON_RXD_RING_MASK; +- EFX_POPULATE_DWORD_1(reg, RX_DESC_WPTR_DWORD, write_ptr); +- falcon_writel_page(rx_queue->efx, ®, +- RX_DESC_UPD_REG_KER_DWORD, rx_queue->queue); +-} +- +-int falcon_probe_rx(struct efx_rx_queue *rx_queue) +-{ +- struct efx_nic *efx = rx_queue->efx; +- return falcon_alloc_special_buffer(efx, &rx_queue->rxd, +- FALCON_RXD_RING_SIZE * +- sizeof(efx_qword_t)); +-} +- +-void falcon_init_rx(struct efx_rx_queue *rx_queue) +-{ +- efx_oword_t rx_desc_ptr; +- struct efx_nic *efx = rx_queue->efx; +- bool is_b0 = falcon_rev(efx) >= FALCON_REV_B0; +- bool iscsi_digest_en = is_b0; +- +- EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n", +- rx_queue->queue, rx_queue->rxd.index, +- rx_queue->rxd.index + rx_queue->rxd.entries - 1); +- +- rx_queue->flushed = false; +- +- /* Pin RX descriptor ring */ +- falcon_init_special_buffer(efx, &rx_queue->rxd); +- +- /* Push RX descriptor ring to card */ +- EFX_POPULATE_OWORD_10(rx_desc_ptr, +- RX_ISCSI_DDIG_EN, iscsi_digest_en, +- RX_ISCSI_HDIG_EN, iscsi_digest_en, +- RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index, +- RX_DESCQ_EVQ_ID, rx_queue->channel->channel, +- RX_DESCQ_OWNER_ID, 0, +- RX_DESCQ_LABEL, rx_queue->queue, +- RX_DESCQ_SIZE, FALCON_RXD_RING_ORDER, +- RX_DESCQ_TYPE, 0 /* kernel queue */ , +- /* For >=B0 this is scatter so disable */ +- RX_DESCQ_JUMBO, !is_b0, +- RX_DESCQ_EN, 1); +- falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, +- rx_queue->queue); +-} +- +-static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) +-{ +- struct efx_nic *efx = rx_queue->efx; +- efx_oword_t rx_flush_descq; +- +- /* Post a flush command */ +- EFX_POPULATE_OWORD_2(rx_flush_descq, +- RX_FLUSH_DESCQ_CMD, 1, +- RX_FLUSH_DESCQ, rx_queue->queue); +- falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER); +-} +- +-void falcon_fini_rx(struct efx_rx_queue *rx_queue) +-{ +- efx_oword_t rx_desc_ptr; +- struct efx_nic *efx = rx_queue->efx; +- +- /* The queue should already have been flushed */ +- WARN_ON(!rx_queue->flushed); +- +- /* Remove RX descriptor ring from card */ +- EFX_ZERO_OWORD(rx_desc_ptr); +- falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, +- rx_queue->queue); +- +- /* Unpin RX descriptor ring */ +- falcon_fini_special_buffer(efx, &rx_queue->rxd); +-} +- +-/* Free buffers backing RX queue */ +-void falcon_remove_rx(struct efx_rx_queue *rx_queue) +-{ +- falcon_free_special_buffer(rx_queue->efx, &rx_queue->rxd); +-} +- +-/************************************************************************** +- * +- * Falcon event queue processing +- * Event queues are processed by per-channel tasklets. +- * +- **************************************************************************/ +- +-/* Update a channel's event queue's read pointer (RPTR) register +- * +- * This writes the EVQ_RPTR_REG register for the specified channel's +- * event queue. +- * +- * Note that EVQ_RPTR_REG contains the index of the "last read" event, +- * whereas channel->eventq_read_ptr contains the index of the "next to +- * read" event. +- */ +-void falcon_eventq_read_ack(struct efx_channel *channel) +-{ +- efx_dword_t reg; +- struct efx_nic *efx = channel->efx; +- +- EFX_POPULATE_DWORD_1(reg, EVQ_RPTR_DWORD, channel->eventq_read_ptr); +- falcon_writel_table(efx, ®, efx->type->evq_rptr_tbl_base, +- channel->channel); +-} +- +-/* Use HW to insert a SW defined event */ +-void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event) +-{ +- efx_oword_t drv_ev_reg; +- +- EFX_POPULATE_OWORD_2(drv_ev_reg, +- DRV_EV_QID, channel->channel, +- DRV_EV_DATA, +- EFX_QWORD_FIELD64(*event, WHOLE_EVENT)); +- falcon_write(channel->efx, &drv_ev_reg, DRV_EV_REG_KER); +-} +- +-/* Handle a transmit completion event +- * +- * Falcon batches TX completion events; the message we receive is of +- * the form "complete all TX events up to this index". +- */ +-static void falcon_handle_tx_event(struct efx_channel *channel, +- efx_qword_t *event) +-{ +- unsigned int tx_ev_desc_ptr; +- unsigned int tx_ev_q_label; +- struct efx_tx_queue *tx_queue; +- struct efx_nic *efx = channel->efx; +- +- if (likely(EFX_QWORD_FIELD(*event, TX_EV_COMP))) { +- /* Transmit completion */ +- tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR); +- tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL); +- tx_queue = &efx->tx_queue[tx_ev_q_label]; +- channel->irq_mod_score += +- (tx_ev_desc_ptr - tx_queue->read_count) & +- efx->type->txd_ring_mask; +- efx_xmit_done(tx_queue, tx_ev_desc_ptr); +- } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) { +- /* Rewrite the FIFO write pointer */ +- tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL); +- tx_queue = &efx->tx_queue[tx_ev_q_label]; +- +- if (efx_dev_registered(efx)) +- netif_tx_lock(efx->net_dev); +- falcon_notify_tx_desc(tx_queue); +- if (efx_dev_registered(efx)) +- netif_tx_unlock(efx->net_dev); +- } else if (EFX_QWORD_FIELD(*event, TX_EV_PKT_ERR) && +- EFX_WORKAROUND_10727(efx)) { +- efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); +- } else { +- EFX_ERR(efx, "channel %d unexpected TX event " +- EFX_QWORD_FMT"\n", channel->channel, +- EFX_QWORD_VAL(*event)); +- } +-} +- +-/* Detect errors included in the rx_evt_pkt_ok bit. */ +-static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, +- const efx_qword_t *event, +- bool *rx_ev_pkt_ok, +- bool *discard) +-{ +- struct efx_nic *efx = rx_queue->efx; +- bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err; +- bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err; +- bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc; +- bool rx_ev_other_err, rx_ev_pause_frm; +- bool rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt; +- unsigned rx_ev_pkt_type; +- +- rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE); +- rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT); +- rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, RX_EV_TOBE_DISC); +- rx_ev_pkt_type = EFX_QWORD_FIELD(*event, RX_EV_PKT_TYPE); +- rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event, +- RX_EV_BUF_OWNER_ID_ERR); +- rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, RX_EV_IF_FRAG_ERR); +- rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event, +- RX_EV_IP_HDR_CHKSUM_ERR); +- rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event, +- RX_EV_TCP_UDP_CHKSUM_ERR); +- rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, RX_EV_ETH_CRC_ERR); +- rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, RX_EV_FRM_TRUNC); +- rx_ev_drib_nib = ((falcon_rev(efx) >= FALCON_REV_B0) ? +- 0 : EFX_QWORD_FIELD(*event, RX_EV_DRIB_NIB)); +- rx_ev_pause_frm = EFX_QWORD_FIELD(*event, RX_EV_PAUSE_FRM_ERR); +- +- /* Every error apart from tobe_disc and pause_frm */ +- rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err | +- rx_ev_buf_owner_id_err | rx_ev_eth_crc_err | +- rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err); +- +- /* Count errors that are not in MAC stats. Ignore expected +- * checksum errors during self-test. */ +- if (rx_ev_frm_trunc) +- ++rx_queue->channel->n_rx_frm_trunc; +- else if (rx_ev_tobe_disc) +- ++rx_queue->channel->n_rx_tobe_disc; +- else if (!efx->loopback_selftest) { +- if (rx_ev_ip_hdr_chksum_err) +- ++rx_queue->channel->n_rx_ip_hdr_chksum_err; +- else if (rx_ev_tcp_udp_chksum_err) +- ++rx_queue->channel->n_rx_tcp_udp_chksum_err; +- } +- if (rx_ev_ip_frag_err) +- ++rx_queue->channel->n_rx_ip_frag_err; +- +- /* The frame must be discarded if any of these are true. */ +- *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib | +- rx_ev_tobe_disc | rx_ev_pause_frm); +- +- /* TOBE_DISC is expected on unicast mismatches; don't print out an +- * error message. FRM_TRUNC indicates RXDP dropped the packet due +- * to a FIFO overflow. +- */ +-#ifdef EFX_ENABLE_DEBUG +- if (rx_ev_other_err) { +- EFX_INFO_RL(efx, " RX queue %d unexpected RX event " +- EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n", +- rx_queue->queue, EFX_QWORD_VAL(*event), +- rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "", +- rx_ev_ip_hdr_chksum_err ? +- " [IP_HDR_CHKSUM_ERR]" : "", +- rx_ev_tcp_udp_chksum_err ? +- " [TCP_UDP_CHKSUM_ERR]" : "", +- rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "", +- rx_ev_frm_trunc ? " [FRM_TRUNC]" : "", +- rx_ev_drib_nib ? " [DRIB_NIB]" : "", +- rx_ev_tobe_disc ? " [TOBE_DISC]" : "", +- rx_ev_pause_frm ? " [PAUSE]" : ""); +- } +-#endif +-} +- +-/* Handle receive events that are not in-order. */ +-static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue, +- unsigned index) +-{ +- struct efx_nic *efx = rx_queue->efx; +- unsigned expected, dropped; +- +- expected = rx_queue->removed_count & FALCON_RXD_RING_MASK; +- dropped = ((index + FALCON_RXD_RING_SIZE - expected) & +- FALCON_RXD_RING_MASK); +- EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n", +- dropped, index, expected); +- +- efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ? +- RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); +-} +- +-/* Handle a packet received event +- * +- * Falcon silicon gives a "discard" flag if it's a unicast packet with the +- * wrong destination address +- * Also "is multicast" and "matches multicast filter" flags can be used to +- * discard non-matching multicast packets. +- */ +-static void falcon_handle_rx_event(struct efx_channel *channel, +- const efx_qword_t *event) +-{ +- unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt; +- unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt; +- unsigned expected_ptr; +- bool rx_ev_pkt_ok, discard = false, checksummed; +- struct efx_rx_queue *rx_queue; +- struct efx_nic *efx = channel->efx; +- +- /* Basic packet information */ +- rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, RX_EV_BYTE_CNT); +- rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, RX_EV_PKT_OK); +- rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE); +- WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT)); +- WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1); +- WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL) != channel->channel); +- +- rx_queue = &efx->rx_queue[channel->channel]; +- +- rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR); +- expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK; +- if (unlikely(rx_ev_desc_ptr != expected_ptr)) +- falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); +- +- if (likely(rx_ev_pkt_ok)) { +- /* If packet is marked as OK and packet type is TCP/IPv4 or +- * UDP/IPv4, then we can rely on the hardware checksum. +- */ +- checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type); +- } else { +- falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, +- &discard); +- checksummed = false; +- } +- +- /* Detect multicast packets that didn't match the filter */ +- rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT); +- if (rx_ev_mcast_pkt) { +- unsigned int rx_ev_mcast_hash_match = +- EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH); +- +- if (unlikely(!rx_ev_mcast_hash_match)) +- discard = true; +- } +- +- channel->irq_mod_score += 2; +- +- /* Handle received packet */ +- efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, +- checksummed, discard); +-} +- +-/* Global events are basically PHY events */ +-static void falcon_handle_global_event(struct efx_channel *channel, +- efx_qword_t *event) +-{ +- struct efx_nic *efx = channel->efx; +- bool handled = false; +- +- if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) || +- EFX_QWORD_FIELD(*event, G_PHY1_INTR) || +- EFX_QWORD_FIELD(*event, XG_PHY_INTR) || +- EFX_QWORD_FIELD(*event, XFP_PHY_INTR)) { +- efx->phy_op->clear_interrupt(efx); +- queue_work(efx->workqueue, &efx->phy_work); +- handled = true; +- } +- +- if ((falcon_rev(efx) >= FALCON_REV_B0) && +- EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) { +- queue_work(efx->workqueue, &efx->mac_work); +- handled = true; +- } +- +- if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) { +- EFX_ERR(efx, "channel %d seen global RX_RESET " +- "event. Resetting.\n", channel->channel); +- +- atomic_inc(&efx->rx_reset); +- efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ? +- RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); +- handled = true; +- } +- +- if (!handled) +- EFX_ERR(efx, "channel %d unknown global event " +- EFX_QWORD_FMT "\n", channel->channel, +- EFX_QWORD_VAL(*event)); +-} +- +-static void falcon_handle_driver_event(struct efx_channel *channel, +- efx_qword_t *event) +-{ +- struct efx_nic *efx = channel->efx; +- unsigned int ev_sub_code; +- unsigned int ev_sub_data; +- +- ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); +- ev_sub_data = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_DATA); +- +- switch (ev_sub_code) { +- case TX_DESCQ_FLS_DONE_EV_DECODE: +- EFX_TRACE(efx, "channel %d TXQ %d flushed\n", +- channel->channel, ev_sub_data); +- break; +- case RX_DESCQ_FLS_DONE_EV_DECODE: +- EFX_TRACE(efx, "channel %d RXQ %d flushed\n", +- channel->channel, ev_sub_data); +- break; +- case EVQ_INIT_DONE_EV_DECODE: +- EFX_LOG(efx, "channel %d EVQ %d initialised\n", +- channel->channel, ev_sub_data); +- break; +- case SRM_UPD_DONE_EV_DECODE: +- EFX_TRACE(efx, "channel %d SRAM update done\n", +- channel->channel); +- break; +- case WAKE_UP_EV_DECODE: +- EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n", +- channel->channel, ev_sub_data); +- break; +- case TIMER_EV_DECODE: +- EFX_TRACE(efx, "channel %d RX queue %d timer expired\n", +- channel->channel, ev_sub_data); +- break; +- case RX_RECOVERY_EV_DECODE: +- EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. " +- "Resetting.\n", channel->channel); +- atomic_inc(&efx->rx_reset); +- efx_schedule_reset(efx, +- EFX_WORKAROUND_6555(efx) ? +- RESET_TYPE_RX_RECOVERY : +- RESET_TYPE_DISABLE); +- break; +- case RX_DSC_ERROR_EV_DECODE: +- EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error." +- " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data); +- efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH); +- break; +- case TX_DSC_ERROR_EV_DECODE: +- EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error." +- " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data); +- efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); +- break; +- default: +- EFX_TRACE(efx, "channel %d unknown driver event code %d " +- "data %04x\n", channel->channel, ev_sub_code, +- ev_sub_data); +- break; +- } +-} +- +-int falcon_process_eventq(struct efx_channel *channel, int rx_quota) +-{ +- unsigned int read_ptr; +- efx_qword_t event, *p_event; +- int ev_code; +- int rx_packets = 0; +- +- read_ptr = channel->eventq_read_ptr; +- +- do { +- p_event = falcon_event(channel, read_ptr); +- event = *p_event; +- +- if (!falcon_event_present(&event)) +- /* End of events */ +- break; +- +- EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n", +- channel->channel, EFX_QWORD_VAL(event)); +- +- /* Clear this event by marking it all ones */ +- EFX_SET_QWORD(*p_event); +- +- ev_code = EFX_QWORD_FIELD(event, EV_CODE); +- +- switch (ev_code) { +- case RX_IP_EV_DECODE: +- falcon_handle_rx_event(channel, &event); +- ++rx_packets; +- break; +- case TX_IP_EV_DECODE: +- falcon_handle_tx_event(channel, &event); +- break; +- case DRV_GEN_EV_DECODE: +- channel->eventq_magic +- = EFX_QWORD_FIELD(event, EVQ_MAGIC); +- EFX_LOG(channel->efx, "channel %d received generated " +- "event "EFX_QWORD_FMT"\n", channel->channel, +- EFX_QWORD_VAL(event)); +- break; +- case GLOBAL_EV_DECODE: +- falcon_handle_global_event(channel, &event); +- break; +- case DRIVER_EV_DECODE: +- falcon_handle_driver_event(channel, &event); +- break; +- default: +- EFX_ERR(channel->efx, "channel %d unknown event type %d" +- " (data " EFX_QWORD_FMT ")\n", channel->channel, +- ev_code, EFX_QWORD_VAL(event)); +- } +- +- /* Increment read pointer */ +- read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; +- +- } while (rx_packets < rx_quota); +- +- channel->eventq_read_ptr = read_ptr; +- return rx_packets; +-} +- +-void falcon_set_int_moderation(struct efx_channel *channel) ++static void falcon_push_irq_moderation(struct efx_channel *channel) + { + efx_dword_t timer_cmd; + struct efx_nic *efx = channel->efx; + + /* Set timer register */ + if (channel->irq_moderation) { +- /* Round to resolution supported by hardware. The value we +- * program is based at 0. So actual interrupt moderation +- * achieved is ((x + 1) * res). +- */ +- channel->irq_moderation -= (channel->irq_moderation % +- FALCON_IRQ_MOD_RESOLUTION); +- if (channel->irq_moderation < FALCON_IRQ_MOD_RESOLUTION) +- channel->irq_moderation = FALCON_IRQ_MOD_RESOLUTION; + EFX_POPULATE_DWORD_2(timer_cmd, +- TIMER_MODE, TIMER_MODE_INT_HLDOFF, +- TIMER_VAL, +- channel->irq_moderation / +- FALCON_IRQ_MOD_RESOLUTION - 1); ++ FRF_AB_TC_TIMER_MODE, ++ FFE_BB_TIMER_MODE_INT_HLDOFF, ++ FRF_AB_TC_TIMER_VAL, ++ channel->irq_moderation - 1); + } else { + EFX_POPULATE_DWORD_2(timer_cmd, +- TIMER_MODE, TIMER_MODE_DIS, +- TIMER_VAL, 0); ++ FRF_AB_TC_TIMER_MODE, ++ FFE_BB_TIMER_MODE_DIS, ++ FRF_AB_TC_TIMER_VAL, 0); + } +- falcon_writel_page_locked(efx, &timer_cmd, TIMER_CMD_REG_KER, +- channel->channel); +- ++ BUILD_BUG_ON(FR_AA_TIMER_COMMAND_KER != FR_BZ_TIMER_COMMAND_P0); ++ efx_writed_page_locked(efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0, ++ channel->channel); + } + +-/* Allocate buffer table entries for event queue */ +-int falcon_probe_eventq(struct efx_channel *channel) +-{ +- struct efx_nic *efx = channel->efx; +- unsigned int evq_size; +- +- evq_size = FALCON_EVQ_SIZE * sizeof(efx_qword_t); +- return falcon_alloc_special_buffer(efx, &channel->eventq, evq_size); +-} ++static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx); + +-void falcon_init_eventq(struct efx_channel *channel) ++static void falcon_prepare_flush(struct efx_nic *efx) + { +- efx_oword_t evq_ptr; +- struct efx_nic *efx = channel->efx; +- +- EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", +- channel->channel, channel->eventq.index, +- channel->eventq.index + channel->eventq.entries - 1); +- +- /* Pin event queue buffer */ +- falcon_init_special_buffer(efx, &channel->eventq); ++ falcon_deconfigure_mac_wrapper(efx); + +- /* Fill event queue with all ones (i.e. empty events) */ +- memset(channel->eventq.addr, 0xff, channel->eventq.len); +- +- /* Push event queue to card */ +- EFX_POPULATE_OWORD_3(evq_ptr, +- EVQ_EN, 1, +- EVQ_SIZE, FALCON_EVQ_ORDER, +- EVQ_BUF_BASE_ID, channel->eventq.index); +- falcon_write_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base, +- channel->channel); +- +- falcon_set_int_moderation(channel); +-} +- +-void falcon_fini_eventq(struct efx_channel *channel) +-{ +- efx_oword_t eventq_ptr; +- struct efx_nic *efx = channel->efx; +- +- /* Remove event queue from card */ +- EFX_ZERO_OWORD(eventq_ptr); +- falcon_write_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base, +- channel->channel); +- +- /* Unpin event queue */ +- falcon_fini_special_buffer(efx, &channel->eventq); +-} +- +-/* Free buffers backing event queue */ +-void falcon_remove_eventq(struct efx_channel *channel) +-{ +- falcon_free_special_buffer(channel->efx, &channel->eventq); +-} +- +- +-/* Generates a test event on the event queue. A subsequent call to +- * process_eventq() should pick up the event and place the value of +- * "magic" into channel->eventq_magic; +- */ +-void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) +-{ +- efx_qword_t test_event; +- +- EFX_POPULATE_QWORD_2(test_event, +- EV_CODE, DRV_GEN_EV_DECODE, +- EVQ_MAGIC, magic); +- falcon_generate_event(channel, &test_event); +-} +- +-void falcon_sim_phy_event(struct efx_nic *efx) +-{ +- efx_qword_t phy_event; +- +- EFX_POPULATE_QWORD_1(phy_event, EV_CODE, GLOBAL_EV_DECODE); +- if (EFX_IS10G(efx)) +- EFX_SET_QWORD_FIELD(phy_event, XG_PHY_INTR, 1); +- else +- EFX_SET_QWORD_FIELD(phy_event, G_PHY0_INTR, 1); +- +- falcon_generate_event(&efx->channel[0], &phy_event); +-} +- +-/************************************************************************** +- * +- * Flush handling +- * +- **************************************************************************/ +- +- +-static void falcon_poll_flush_events(struct efx_nic *efx) +-{ +- struct efx_channel *channel = &efx->channel[0]; +- struct efx_tx_queue *tx_queue; +- struct efx_rx_queue *rx_queue; +- unsigned int read_ptr = channel->eventq_read_ptr; +- unsigned int end_ptr = (read_ptr - 1) & FALCON_EVQ_MASK; +- +- do { +- efx_qword_t *event = falcon_event(channel, read_ptr); +- int ev_code, ev_sub_code, ev_queue; +- bool ev_failed; +- +- if (!falcon_event_present(event)) +- break; +- +- ev_code = EFX_QWORD_FIELD(*event, EV_CODE); +- ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); +- if (ev_code == DRIVER_EV_DECODE && +- ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) { +- ev_queue = EFX_QWORD_FIELD(*event, +- DRIVER_EV_TX_DESCQ_ID); +- if (ev_queue < EFX_TX_QUEUE_COUNT) { +- tx_queue = efx->tx_queue + ev_queue; +- tx_queue->flushed = true; +- } +- } else if (ev_code == DRIVER_EV_DECODE && +- ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) { +- ev_queue = EFX_QWORD_FIELD(*event, +- DRIVER_EV_RX_DESCQ_ID); +- ev_failed = EFX_QWORD_FIELD(*event, +- DRIVER_EV_RX_FLUSH_FAIL); +- if (ev_queue < efx->n_rx_queues) { +- rx_queue = efx->rx_queue + ev_queue; +- +- /* retry the rx flush */ +- if (ev_failed) +- falcon_flush_rx_queue(rx_queue); +- else +- rx_queue->flushed = true; +- } +- } +- +- read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; +- } while (read_ptr != end_ptr); +-} +- +-/* Handle tx and rx flushes at the same time, since they run in +- * parallel in the hardware and there's no reason for us to +- * serialise them */ +-int falcon_flush_queues(struct efx_nic *efx) +-{ +- struct efx_rx_queue *rx_queue; +- struct efx_tx_queue *tx_queue; +- int i; +- bool outstanding; +- +- /* Issue flush requests */ +- efx_for_each_tx_queue(tx_queue, efx) { +- tx_queue->flushed = false; +- falcon_flush_tx_queue(tx_queue); +- } +- efx_for_each_rx_queue(rx_queue, efx) { +- rx_queue->flushed = false; +- falcon_flush_rx_queue(rx_queue); +- } +- +- /* Poll the evq looking for flush completions. Since we're not pushing +- * any more rx or tx descriptors at this point, we're in no danger of +- * overflowing the evq whilst we wait */ +- for (i = 0; i < FALCON_FLUSH_POLL_COUNT; ++i) { +- msleep(FALCON_FLUSH_INTERVAL); +- falcon_poll_flush_events(efx); +- +- /* Check if every queue has been succesfully flushed */ +- outstanding = false; +- efx_for_each_tx_queue(tx_queue, efx) +- outstanding |= !tx_queue->flushed; +- efx_for_each_rx_queue(rx_queue, efx) +- outstanding |= !rx_queue->flushed; +- if (!outstanding) +- return 0; +- } +- +- /* Mark the queues as all flushed. We're going to return failure +- * leading to a reset, or fake up success anyway. "flushed" now +- * indicates that we tried to flush. */ +- efx_for_each_tx_queue(tx_queue, efx) { +- if (!tx_queue->flushed) +- EFX_ERR(efx, "tx queue %d flush command timed out\n", +- tx_queue->queue); +- tx_queue->flushed = true; +- } +- efx_for_each_rx_queue(rx_queue, efx) { +- if (!rx_queue->flushed) +- EFX_ERR(efx, "rx queue %d flush command timed out\n", +- rx_queue->queue); +- rx_queue->flushed = true; +- } +- +- if (EFX_WORKAROUND_7803(efx)) +- return 0; +- +- return -ETIMEDOUT; +-} +- +-/************************************************************************** +- * +- * Falcon hardware interrupts +- * The hardware interrupt handler does very little work; all the event +- * queue processing is carried out by per-channel tasklets. +- * +- **************************************************************************/ +- +-/* Enable/disable/generate Falcon interrupts */ +-static inline void falcon_interrupts(struct efx_nic *efx, int enabled, +- int force) +-{ +- efx_oword_t int_en_reg_ker; +- +- EFX_POPULATE_OWORD_2(int_en_reg_ker, +- KER_INT_KER, force, +- DRV_INT_EN_KER, enabled); +- falcon_write(efx, &int_en_reg_ker, INT_EN_REG_KER); +-} +- +-void falcon_enable_interrupts(struct efx_nic *efx) +-{ +- efx_oword_t int_adr_reg_ker; +- struct efx_channel *channel; +- +- EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr)); +- wmb(); /* Ensure interrupt vector is clear before interrupts enabled */ +- +- /* Program address */ +- EFX_POPULATE_OWORD_2(int_adr_reg_ker, +- NORM_INT_VEC_DIS_KER, EFX_INT_MODE_USE_MSI(efx), +- INT_ADR_KER, efx->irq_status.dma_addr); +- falcon_write(efx, &int_adr_reg_ker, INT_ADR_REG_KER); +- +- /* Enable interrupts */ +- falcon_interrupts(efx, 1, 0); +- +- /* Force processing of all the channels to get the EVQ RPTRs up to +- date */ +- efx_for_each_channel(channel, efx) +- efx_schedule_channel(channel); +-} +- +-void falcon_disable_interrupts(struct efx_nic *efx) +-{ +- /* Disable interrupts */ +- falcon_interrupts(efx, 0, 0); +-} +- +-/* Generate a Falcon test interrupt +- * Interrupt must already have been enabled, otherwise nasty things +- * may happen. +- */ +-void falcon_generate_interrupt(struct efx_nic *efx) +-{ +- falcon_interrupts(efx, 1, 1); ++ /* Wait for the tx and rx fifo's to get to the next packet boundary ++ * (~1ms without back-pressure), then to drain the remainder of the ++ * fifo's at data path speeds (negligible), with a healthy margin. */ ++ msleep(10); + } + + /* Acknowledge a legacy interrupt from Falcon +@@ -1364,113 +144,17 @@ void falcon_generate_interrupt(struct efx_nic *efx) + * + * NB most hardware supports MSI interrupts + */ +-static inline void falcon_irq_ack_a1(struct efx_nic *efx) +-{ +- efx_dword_t reg; +- +- EFX_POPULATE_DWORD_1(reg, INT_ACK_DUMMY_DATA, 0xb7eb7e); +- falcon_writel(efx, ®, INT_ACK_REG_KER_A1); +- falcon_readl(efx, ®, WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1); +-} +- +-/* Process a fatal interrupt +- * Disable bus mastering ASAP and schedule a reset +- */ +-static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx) ++inline void falcon_irq_ack_a1(struct efx_nic *efx) + { +- struct falcon_nic_data *nic_data = efx->nic_data; +- efx_oword_t *int_ker = efx->irq_status.addr; +- efx_oword_t fatal_intr; +- int error, mem_perr; +- +- falcon_read(efx, &fatal_intr, FATAL_INTR_REG_KER); +- error = EFX_OWORD_FIELD(fatal_intr, INT_KER_ERROR); +- +- EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status " +- EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker), +- EFX_OWORD_VAL(fatal_intr), +- error ? "disabling bus mastering" : "no recognised error"); +- if (error == 0) +- goto out; +- +- /* If this is a memory parity error dump which blocks are offending */ +- mem_perr = EFX_OWORD_FIELD(fatal_intr, MEM_PERR_INT_KER); +- if (mem_perr) { +- efx_oword_t reg; +- falcon_read(efx, ®, MEM_STAT_REG_KER); +- EFX_ERR(efx, "SYSTEM ERROR: memory parity error " +- EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg)); +- } +- +- /* Disable both devices */ +- pci_clear_master(efx->pci_dev); +- if (FALCON_IS_DUAL_FUNC(efx)) +- pci_clear_master(nic_data->pci_dev2); +- falcon_disable_interrupts(efx); +- +- /* Count errors and reset or disable the NIC accordingly */ +- if (nic_data->int_error_count == 0 || +- time_after(jiffies, nic_data->int_error_expire)) { +- nic_data->int_error_count = 0; +- nic_data->int_error_expire = +- jiffies + FALCON_INT_ERROR_EXPIRE * HZ; +- } +- if (++nic_data->int_error_count < FALCON_MAX_INT_ERRORS) { +- EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n"); +- efx_schedule_reset(efx, RESET_TYPE_INT_ERROR); +- } else { +- EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen." +- "NIC will be disabled\n"); +- efx_schedule_reset(efx, RESET_TYPE_DISABLE); +- } +-out: +- return IRQ_HANDLED; +-} +- +-/* Handle a legacy interrupt from Falcon +- * Acknowledges the interrupt and schedule event queue processing. +- */ +-static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id) +-{ +- struct efx_nic *efx = dev_id; +- efx_oword_t *int_ker = efx->irq_status.addr; +- irqreturn_t result = IRQ_NONE; +- struct efx_channel *channel; + efx_dword_t reg; +- u32 queues; +- int syserr; + +- /* Read the ISR which also ACKs the interrupts */ +- falcon_readl(efx, ®, INT_ISR0_B0); +- queues = EFX_EXTRACT_DWORD(reg, 0, 31); +- +- /* Check to see if we have a serious error condition */ +- syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT); +- if (unlikely(syserr)) +- return falcon_fatal_interrupt(efx); +- +- /* Schedule processing of any interrupting queues */ +- efx_for_each_channel(channel, efx) { +- if ((queues & 1) || +- falcon_event_present( +- falcon_event(channel, channel->eventq_read_ptr))) { +- efx_schedule_channel(channel); +- result = IRQ_HANDLED; +- } +- queues >>= 1; +- } +- +- if (result == IRQ_HANDLED) { +- efx->last_irq_cpu = raw_smp_processor_id(); +- EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n", +- irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg)); +- } +- +- return result; ++ EFX_POPULATE_DWORD_1(reg, FRF_AA_INT_ACK_KER_FIELD, 0xb7eb7e); ++ efx_writed(efx, ®, FR_AA_INT_ACK_KER); ++ efx_readd(efx, ®, FR_AA_WORK_AROUND_BROKEN_PCI_READS); + } + + +-static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) ++irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) + { + struct efx_nic *efx = dev_id; + efx_oword_t *int_ker = efx->irq_status.addr; +@@ -1491,15 +175,15 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) + irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); + + /* Check to see if we have a serious error condition */ +- syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT); ++ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); + if (unlikely(syserr)) +- return falcon_fatal_interrupt(efx); ++ return efx_nic_fatal_interrupt(efx); + + /* Determine interrupting queues, clear interrupt status + * register and acknowledge the device interrupt. + */ +- BUILD_BUG_ON(INT_EVQS_WIDTH > EFX_MAX_CHANNELS); +- queues = EFX_OWORD_FIELD(*int_ker, INT_EVQS); ++ BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS); ++ queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q); + EFX_ZERO_OWORD(*int_ker); + wmb(); /* Ensure the vector is cleared before interrupt ack */ + falcon_irq_ack_a1(efx); +@@ -1515,126 +199,6 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) + + return IRQ_HANDLED; + } +- +-/* Handle an MSI interrupt from Falcon +- * +- * Handle an MSI hardware interrupt. This routine schedules event +- * queue processing. No interrupt acknowledgement cycle is necessary. +- * Also, we never need to check that the interrupt is for us, since +- * MSI interrupts cannot be shared. +- */ +-static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id) +-{ +- struct efx_channel *channel = dev_id; +- struct efx_nic *efx = channel->efx; +- efx_oword_t *int_ker = efx->irq_status.addr; +- int syserr; +- +- efx->last_irq_cpu = raw_smp_processor_id(); +- EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n", +- irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); +- +- /* Check to see if we have a serious error condition */ +- syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT); +- if (unlikely(syserr)) +- return falcon_fatal_interrupt(efx); +- +- /* Schedule processing of the channel */ +- efx_schedule_channel(channel); +- +- return IRQ_HANDLED; +-} +- +- +-/* Setup RSS indirection table. +- * This maps from the hash value of the packet to RXQ +- */ +-static void falcon_setup_rss_indir_table(struct efx_nic *efx) +-{ +- int i = 0; +- unsigned long offset; +- efx_dword_t dword; +- +- if (falcon_rev(efx) < FALCON_REV_B0) +- return; +- +- for (offset = RX_RSS_INDIR_TBL_B0; +- offset < RX_RSS_INDIR_TBL_B0 + 0x800; +- offset += 0x10) { +- EFX_POPULATE_DWORD_1(dword, RX_RSS_INDIR_ENT_B0, +- i % efx->n_rx_queues); +- falcon_writel(efx, &dword, offset); +- i++; +- } +-} +- +-/* Hook interrupt handler(s) +- * Try MSI and then legacy interrupts. +- */ +-int falcon_init_interrupt(struct efx_nic *efx) +-{ +- struct efx_channel *channel; +- int rc; +- +- if (!EFX_INT_MODE_USE_MSI(efx)) { +- irq_handler_t handler; +- if (falcon_rev(efx) >= FALCON_REV_B0) +- handler = falcon_legacy_interrupt_b0; +- else +- handler = falcon_legacy_interrupt_a1; +- +- rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED, +- efx->name, efx); +- if (rc) { +- EFX_ERR(efx, "failed to hook legacy IRQ %d\n", +- efx->pci_dev->irq); +- goto fail1; +- } +- return 0; +- } +- +- /* Hook MSI or MSI-X interrupt */ +- efx_for_each_channel(channel, efx) { +- rc = request_irq(channel->irq, falcon_msi_interrupt, +- IRQF_PROBE_SHARED, /* Not shared */ +- channel->name, channel); +- if (rc) { +- EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq); +- goto fail2; +- } +- } +- +- return 0; +- +- fail2: +- efx_for_each_channel(channel, efx) +- free_irq(channel->irq, channel); +- fail1: +- return rc; +-} +- +-void falcon_fini_interrupt(struct efx_nic *efx) +-{ +- struct efx_channel *channel; +- efx_oword_t reg; +- +- /* Disable MSI/MSI-X interrupts */ +- efx_for_each_channel(channel, efx) { +- if (channel->irq) +- free_irq(channel->irq, channel); +- } +- +- /* ACK legacy interrupt */ +- if (falcon_rev(efx) >= FALCON_REV_B0) +- falcon_read(efx, ®, INT_ISR0_B0); +- else +- falcon_irq_ack_a1(efx); +- +- /* Disable legacy interrupt */ +- if (efx->legacy_irq) +- free_irq(efx->legacy_irq, efx); +-} +- + /************************************************************************** + * + * EEPROM/flash +@@ -1647,8 +211,8 @@ void falcon_fini_interrupt(struct efx_nic *efx) + static int falcon_spi_poll(struct efx_nic *efx) + { + efx_oword_t reg; +- falcon_read(efx, ®, EE_SPI_HCMD_REG_KER); +- return EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0; ++ efx_reado(efx, ®, FR_AB_EE_SPI_HCMD); ++ return EFX_OWORD_FIELD(reg, FRF_AB_EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0; + } + + /* Wait for SPI command completion */ +@@ -1678,11 +242,10 @@ static int falcon_spi_wait(struct efx_nic *efx) + } + } + +-int falcon_spi_cmd(const struct efx_spi_device *spi, ++int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi, + unsigned int command, int address, + const void *in, void *out, size_t len) + { +- struct efx_nic *efx = spi->efx; + bool addressed = (address >= 0); + bool reading = (out != NULL); + efx_oword_t reg; +@@ -1700,27 +263,27 @@ int falcon_spi_cmd(const struct efx_spi_device *spi, + + /* Program address register, if we have an address */ + if (addressed) { +- EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address); +- falcon_write(efx, ®, EE_SPI_HADR_REG_KER); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_EE_SPI_HADR_ADR, address); ++ efx_writeo(efx, ®, FR_AB_EE_SPI_HADR); + } + + /* Program data register, if we have data */ + if (in != NULL) { + memcpy(®, in, len); +- falcon_write(efx, ®, EE_SPI_HDATA_REG_KER); ++ efx_writeo(efx, ®, FR_AB_EE_SPI_HDATA); + } + + /* Issue read/write command */ + EFX_POPULATE_OWORD_7(reg, +- EE_SPI_HCMD_CMD_EN, 1, +- EE_SPI_HCMD_SF_SEL, spi->device_id, +- EE_SPI_HCMD_DABCNT, len, +- EE_SPI_HCMD_READ, reading, +- EE_SPI_HCMD_DUBCNT, 0, +- EE_SPI_HCMD_ADBCNT, ++ FRF_AB_EE_SPI_HCMD_CMD_EN, 1, ++ FRF_AB_EE_SPI_HCMD_SF_SEL, spi->device_id, ++ FRF_AB_EE_SPI_HCMD_DABCNT, len, ++ FRF_AB_EE_SPI_HCMD_READ, reading, ++ FRF_AB_EE_SPI_HCMD_DUBCNT, 0, ++ FRF_AB_EE_SPI_HCMD_ADBCNT, + (addressed ? spi->addr_len : 0), +- EE_SPI_HCMD_ENC, command); +- falcon_write(efx, ®, EE_SPI_HCMD_REG_KER); ++ FRF_AB_EE_SPI_HCMD_ENC, command); ++ efx_writeo(efx, ®, FR_AB_EE_SPI_HCMD); + + /* Wait for read/write to complete */ + rc = falcon_spi_wait(efx); +@@ -1729,7 +292,7 @@ int falcon_spi_cmd(const struct efx_spi_device *spi, + + /* Read data */ + if (out != NULL) { +- falcon_read(efx, ®, EE_SPI_HDATA_REG_KER); ++ efx_reado(efx, ®, FR_AB_EE_SPI_HDATA); + memcpy(out, ®, len); + } + +@@ -1751,15 +314,15 @@ efx_spi_munge_command(const struct efx_spi_device *spi, + } + + /* Wait up to 10 ms for buffered write completion */ +-int falcon_spi_wait_write(const struct efx_spi_device *spi) ++int ++falcon_spi_wait_write(struct efx_nic *efx, const struct efx_spi_device *spi) + { +- struct efx_nic *efx = spi->efx; + unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); + u8 status; + int rc; + + for (;;) { +- rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, ++ rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, + &status, sizeof(status)); + if (rc) + return rc; +@@ -1775,8 +338,8 @@ int falcon_spi_wait_write(const struct efx_spi_device *spi) + } + } + +-int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, +- size_t len, size_t *retlen, u8 *buffer) ++int falcon_spi_read(struct efx_nic *efx, const struct efx_spi_device *spi, ++ loff_t start, size_t len, size_t *retlen, u8 *buffer) + { + size_t block_len, pos = 0; + unsigned int command; +@@ -1786,7 +349,7 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, + block_len = min(len - pos, FALCON_SPI_MAX_LEN); + + command = efx_spi_munge_command(spi, SPI_READ, start + pos); +- rc = falcon_spi_cmd(spi, command, start + pos, NULL, ++ rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL, + buffer + pos, block_len); + if (rc) + break; +@@ -1805,8 +368,9 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, + return rc; + } + +-int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, +- size_t len, size_t *retlen, const u8 *buffer) ++int ++falcon_spi_write(struct efx_nic *efx, const struct efx_spi_device *spi, ++ loff_t start, size_t len, size_t *retlen, const u8 *buffer) + { + u8 verify_buffer[FALCON_SPI_MAX_LEN]; + size_t block_len, pos = 0; +@@ -1814,24 +378,24 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, + int rc = 0; + + while (pos < len) { +- rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); ++ rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); + if (rc) + break; + + block_len = min(len - pos, + falcon_spi_write_limit(spi, start + pos)); + command = efx_spi_munge_command(spi, SPI_WRITE, start + pos); +- rc = falcon_spi_cmd(spi, command, start + pos, ++ rc = falcon_spi_cmd(efx, spi, command, start + pos, + buffer + pos, NULL, block_len); + if (rc) + break; + +- rc = falcon_spi_wait_write(spi); ++ rc = falcon_spi_wait_write(efx, spi); + if (rc) + break; + + command = efx_spi_munge_command(spi, SPI_READ, start + pos); +- rc = falcon_spi_cmd(spi, command, start + pos, ++ rc = falcon_spi_cmd(efx, spi, command, start + pos, + NULL, verify_buffer, block_len); + if (memcmp(verify_buffer, buffer + pos, block_len)) { + rc = -EIO; +@@ -1860,60 +424,70 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, + ************************************************************************** + */ + +-static int falcon_reset_macs(struct efx_nic *efx) ++static void falcon_push_multicast_hash(struct efx_nic *efx) + { +- efx_oword_t reg; ++ union efx_multicast_hash *mc_hash = &efx->multicast_hash; ++ ++ WARN_ON(!mutex_is_locked(&efx->mac_lock)); ++ ++ efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0); ++ efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1); ++} ++ ++static void falcon_reset_macs(struct efx_nic *efx) ++{ ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ efx_oword_t reg, mac_ctrl; + int count; + +- if (falcon_rev(efx) < FALCON_REV_B0) { ++ if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { + /* It's not safe to use GLB_CTL_REG to reset the + * macs, so instead use the internal MAC resets + */ + if (!EFX_IS10G(efx)) { +- EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 1); +- falcon_write(efx, ®, GM_CFG1_REG); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 1); ++ efx_writeo(efx, ®, FR_AB_GM_CFG1); + udelay(1000); + +- EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 0); +- falcon_write(efx, ®, GM_CFG1_REG); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0); ++ efx_writeo(efx, ®, FR_AB_GM_CFG1); + udelay(1000); +- return 0; ++ return; + } else { +- EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1); +- falcon_write(efx, ®, XM_GLB_CFG_REG); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1); ++ efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); + + for (count = 0; count < 10000; count++) { +- falcon_read(efx, ®, XM_GLB_CFG_REG); +- if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0) +- return 0; ++ efx_reado(efx, ®, FR_AB_XM_GLB_CFG); ++ if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) == ++ 0) ++ return; + udelay(10); + } + + EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); +- return -ETIMEDOUT; + } + } + +- /* MAC stats will fail whilst the TX fifo is draining. Serialise +- * the drain sequence with the statistics fetch */ +- efx_stats_disable(efx); ++ /* Mac stats will fail whist the TX fifo is draining */ ++ WARN_ON(nic_data->stats_disable_count == 0); + +- falcon_read(efx, ®, MAC0_CTRL_REG_KER); +- EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1); +- falcon_write(efx, ®, MAC0_CTRL_REG_KER); ++ efx_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL); ++ EFX_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1); ++ efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); + +- falcon_read(efx, ®, GLB_CTL_REG_KER); +- EFX_SET_OWORD_FIELD(reg, RST_XGTX, 1); +- EFX_SET_OWORD_FIELD(reg, RST_XGRX, 1); +- EFX_SET_OWORD_FIELD(reg, RST_EM, 1); +- falcon_write(efx, ®, GLB_CTL_REG_KER); ++ efx_reado(efx, ®, FR_AB_GLB_CTL); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGRX, 1); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_EM, 1); ++ efx_writeo(efx, ®, FR_AB_GLB_CTL); + + count = 0; + while (1) { +- falcon_read(efx, ®, GLB_CTL_REG_KER); +- if (!EFX_OWORD_FIELD(reg, RST_XGTX) && +- !EFX_OWORD_FIELD(reg, RST_XGRX) && +- !EFX_OWORD_FIELD(reg, RST_EM)) { ++ efx_reado(efx, ®, FR_AB_GLB_CTL); ++ if (!EFX_OWORD_FIELD(reg, FRF_AB_RST_XGTX) && ++ !EFX_OWORD_FIELD(reg, FRF_AB_RST_XGRX) && ++ !EFX_OWORD_FIELD(reg, FRF_AB_RST_EM)) { + EFX_LOG(efx, "Completed MAC reset after %d loops\n", + count); + break; +@@ -1926,55 +500,50 @@ static int falcon_reset_macs(struct efx_nic *efx) + udelay(10); + } + +- efx_stats_enable(efx); +- +- /* If we've reset the EM block and the link is up, then +- * we'll have to kick the XAUI link so the PHY can recover */ +- if (efx->link_up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx)) +- falcon_reset_xaui(efx); +- +- return 0; ++ /* Ensure the correct MAC is selected before statistics ++ * are re-enabled by the caller */ ++ efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); + } + + void falcon_drain_tx_fifo(struct efx_nic *efx) + { + efx_oword_t reg; + +- if ((falcon_rev(efx) < FALCON_REV_B0) || ++ if ((efx_nic_rev(efx) < EFX_REV_FALCON_B0) || + (efx->loopback_mode != LOOPBACK_NONE)) + return; + +- falcon_read(efx, ®, MAC0_CTRL_REG_KER); ++ efx_reado(efx, ®, FR_AB_MAC_CTRL); + /* There is no point in draining more than once */ +- if (EFX_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0)) ++ if (EFX_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN)) + return; + + falcon_reset_macs(efx); + } + +-void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) ++static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) + { + efx_oword_t reg; + +- if (falcon_rev(efx) < FALCON_REV_B0) ++ if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) + return; + + /* Isolate the MAC -> RX */ +- falcon_read(efx, ®, RX_CFG_REG_KER); +- EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 0); +- falcon_write(efx, ®, RX_CFG_REG_KER); ++ efx_reado(efx, ®, FR_AZ_RX_CFG); ++ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0); ++ efx_writeo(efx, ®, FR_AZ_RX_CFG); + +- if (!efx->link_up) +- falcon_drain_tx_fifo(efx); ++ /* Isolate TX -> MAC */ ++ falcon_drain_tx_fifo(efx); + } + + void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) + { ++ struct efx_link_state *link_state = &efx->link_state; + efx_oword_t reg; + int link_speed; +- bool tx_fc; + +- switch (efx->link_speed) { ++ switch (link_state->speed) { + case 10000: link_speed = 3; break; + case 1000: link_speed = 2; break; + case 100: link_speed = 1; break; +@@ -1985,75 +554,139 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) + * indefinitely held and TX queue can be flushed at any point + * while the link is down. */ + EFX_POPULATE_OWORD_5(reg, +- MAC_XOFF_VAL, 0xffff /* max pause time */, +- MAC_BCAD_ACPT, 1, +- MAC_UC_PROM, efx->promiscuous, +- MAC_LINK_STATUS, 1, /* always set */ +- MAC_SPEED, link_speed); ++ FRF_AB_MAC_XOFF_VAL, 0xffff /* max pause time */, ++ FRF_AB_MAC_BCAD_ACPT, 1, ++ FRF_AB_MAC_UC_PROM, efx->promiscuous, ++ FRF_AB_MAC_LINK_STATUS, 1, /* always set */ ++ FRF_AB_MAC_SPEED, link_speed); + /* On B0, MAC backpressure can be disabled and packets get + * discarded. */ +- if (falcon_rev(efx) >= FALCON_REV_B0) { +- EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, +- !efx->link_up); ++ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { ++ EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, ++ !link_state->up); + } + +- falcon_write(efx, ®, MAC0_CTRL_REG_KER); ++ efx_writeo(efx, ®, FR_AB_MAC_CTRL); + + /* Restore the multicast hash registers. */ +- falcon_set_multicast_hash(efx); +- +- /* Transmission of pause frames when RX crosses the threshold is +- * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. +- * Action on receipt of pause frames is controller by XM_DIS_FCNTL */ +- tx_fc = !!(efx->link_fc & EFX_FC_TX); +- falcon_read(efx, ®, RX_CFG_REG_KER); +- EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc); ++ falcon_push_multicast_hash(efx); + ++ efx_reado(efx, ®, FR_AZ_RX_CFG); ++ /* Enable XOFF signal from RX FIFO (we enabled it during NIC ++ * initialisation but it may read back as 0) */ ++ EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); + /* Unisolate the MAC -> RX */ +- if (falcon_rev(efx) >= FALCON_REV_B0) +- EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 1); +- falcon_write(efx, ®, RX_CFG_REG_KER); ++ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ++ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); ++ efx_writeo(efx, ®, FR_AZ_RX_CFG); + } + +-int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) ++static void falcon_stats_request(struct efx_nic *efx) + { ++ struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t reg; +- u32 *dma_done; +- int i; + +- if (disable_dma_stats) +- return 0; ++ WARN_ON(nic_data->stats_pending); ++ WARN_ON(nic_data->stats_disable_count); + +- /* Statistics fetch will fail if the MAC is in TX drain */ +- if (falcon_rev(efx) >= FALCON_REV_B0) { +- efx_oword_t temp; +- falcon_read(efx, &temp, MAC0_CTRL_REG_KER); +- if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0)) +- return 0; +- } ++ if (nic_data->stats_dma_done == NULL) ++ return; /* no mac selected */ + +- dma_done = (efx->stats_buffer.addr + done_offset); +- *dma_done = FALCON_STATS_NOT_DONE; ++ *nic_data->stats_dma_done = FALCON_STATS_NOT_DONE; ++ nic_data->stats_pending = true; + wmb(); /* ensure done flag is clear */ + + /* Initiate DMA transfer of stats */ + EFX_POPULATE_OWORD_2(reg, +- MAC_STAT_DMA_CMD, 1, +- MAC_STAT_DMA_ADR, ++ FRF_AB_MAC_STAT_DMA_CMD, 1, ++ FRF_AB_MAC_STAT_DMA_ADR, + efx->stats_buffer.dma_addr); +- falcon_write(efx, ®, MAC0_STAT_DMA_REG_KER); ++ efx_writeo(efx, ®, FR_AB_MAC_STAT_DMA); + +- /* Wait for transfer to complete */ +- for (i = 0; i < 400; i++) { +- if (*(volatile u32 *)dma_done == FALCON_STATS_DONE) { +- rmb(); /* Ensure the stats are valid. */ +- return 0; +- } +- udelay(10); ++ mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2)); ++} ++ ++static void falcon_stats_complete(struct efx_nic *efx) ++{ ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ ++ if (!nic_data->stats_pending) ++ return; ++ ++ nic_data->stats_pending = 0; ++ if (*nic_data->stats_dma_done == FALCON_STATS_DONE) { ++ rmb(); /* read the done flag before the stats */ ++ efx->mac_op->update_stats(efx); ++ } else { ++ EFX_ERR(efx, "timed out waiting for statistics\n"); + } ++} + +- EFX_ERR(efx, "timed out waiting for statistics\n"); +- return -ETIMEDOUT; ++static void falcon_stats_timer_func(unsigned long context) ++{ ++ struct efx_nic *efx = (struct efx_nic *)context; ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ ++ spin_lock(&efx->stats_lock); ++ ++ falcon_stats_complete(efx); ++ if (nic_data->stats_disable_count == 0) ++ falcon_stats_request(efx); ++ ++ spin_unlock(&efx->stats_lock); ++} ++ ++static void falcon_switch_mac(struct efx_nic *efx); ++ ++static bool falcon_loopback_link_poll(struct efx_nic *efx) ++{ ++ struct efx_link_state old_state = efx->link_state; ++ ++ WARN_ON(!mutex_is_locked(&efx->mac_lock)); ++ WARN_ON(!LOOPBACK_INTERNAL(efx)); ++ ++ efx->link_state.fd = true; ++ efx->link_state.fc = efx->wanted_fc; ++ efx->link_state.up = true; ++ ++ if (efx->loopback_mode == LOOPBACK_GMAC) ++ efx->link_state.speed = 1000; ++ else ++ efx->link_state.speed = 10000; ++ ++ return !efx_link_state_equal(&efx->link_state, &old_state); ++} ++ ++static int falcon_reconfigure_port(struct efx_nic *efx) ++{ ++ int rc; ++ ++ WARN_ON(efx_nic_rev(efx) > EFX_REV_FALCON_B0); ++ ++ /* Poll the PHY link state *before* reconfiguring it. This means we ++ * will pick up the correct speed (in loopback) to select the correct ++ * MAC. ++ */ ++ if (LOOPBACK_INTERNAL(efx)) ++ falcon_loopback_link_poll(efx); ++ else ++ efx->phy_op->poll(efx); ++ ++ falcon_stop_nic_stats(efx); ++ falcon_deconfigure_mac_wrapper(efx); ++ ++ falcon_switch_mac(efx); ++ ++ efx->phy_op->reconfigure(efx); ++ rc = efx->mac_op->reconfigure(efx); ++ BUG_ON(rc); ++ ++ falcon_start_nic_stats(efx); ++ ++ /* Synchronise efx->link_state with the kernel */ ++ efx_link_status_changed(efx); ++ ++ return 0; + } + + /************************************************************************** +@@ -2066,18 +699,18 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) + /* Wait for GMII access to complete */ + static int falcon_gmii_wait(struct efx_nic *efx) + { +- efx_dword_t md_stat; ++ efx_oword_t md_stat; + int count; + + /* wait upto 50ms - taken max from datasheet */ + for (count = 0; count < 5000; count++) { +- falcon_readl(efx, &md_stat, MD_STAT_REG_KER); +- if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) { +- if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 || +- EFX_DWORD_FIELD(md_stat, MD_BSERR) != 0) { ++ efx_reado(efx, &md_stat, FR_AB_MD_STAT); ++ if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) { ++ if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 || ++ EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) { + EFX_ERR(efx, "error from GMII access " +- EFX_DWORD_FMT"\n", +- EFX_DWORD_VAL(md_stat)); ++ EFX_OWORD_FMT"\n", ++ EFX_OWORD_VAL(md_stat)); + return -EIO; + } + return 0; +@@ -2099,7 +732,7 @@ static int falcon_mdio_write(struct net_device *net_dev, + EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n", + prtad, devad, addr, value); + +- spin_lock_bh(&efx->phy_lock); ++ mutex_lock(&efx->mdio_lock); + + /* Check MDIO not currently being accessed */ + rc = falcon_gmii_wait(efx); +@@ -2107,34 +740,35 @@ static int falcon_mdio_write(struct net_device *net_dev, + goto out; + + /* Write the address/ID register */ +- EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr); +- falcon_write(efx, ®, MD_PHY_ADR_REG_KER); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr); ++ efx_writeo(efx, ®, FR_AB_MD_PHY_ADR); + +- EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad); +- falcon_write(efx, ®, MD_ID_REG_KER); ++ EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad, ++ FRF_AB_MD_DEV_ADR, devad); ++ efx_writeo(efx, ®, FR_AB_MD_ID); + + /* Write data */ +- EFX_POPULATE_OWORD_1(reg, MD_TXD, value); +- falcon_write(efx, ®, MD_TXD_REG_KER); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_TXD, value); ++ efx_writeo(efx, ®, FR_AB_MD_TXD); + + EFX_POPULATE_OWORD_2(reg, +- MD_WRC, 1, +- MD_GC, 0); +- falcon_write(efx, ®, MD_CS_REG_KER); ++ FRF_AB_MD_WRC, 1, ++ FRF_AB_MD_GC, 0); ++ efx_writeo(efx, ®, FR_AB_MD_CS); + + /* Wait for data to be written */ + rc = falcon_gmii_wait(efx); + if (rc) { + /* Abort the write operation */ + EFX_POPULATE_OWORD_2(reg, +- MD_WRC, 0, +- MD_GC, 1); +- falcon_write(efx, ®, MD_CS_REG_KER); ++ FRF_AB_MD_WRC, 0, ++ FRF_AB_MD_GC, 1); ++ efx_writeo(efx, ®, FR_AB_MD_CS); + udelay(10); + } + +- out: +- spin_unlock_bh(&efx->phy_lock); ++out: ++ mutex_unlock(&efx->mdio_lock); + return rc; + } + +@@ -2146,152 +780,139 @@ static int falcon_mdio_read(struct net_device *net_dev, + efx_oword_t reg; + int rc; + +- spin_lock_bh(&efx->phy_lock); ++ mutex_lock(&efx->mdio_lock); + + /* Check MDIO not currently being accessed */ + rc = falcon_gmii_wait(efx); + if (rc) + goto out; + +- EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr); +- falcon_write(efx, ®, MD_PHY_ADR_REG_KER); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr); ++ efx_writeo(efx, ®, FR_AB_MD_PHY_ADR); + +- EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad); +- falcon_write(efx, ®, MD_ID_REG_KER); ++ EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad, ++ FRF_AB_MD_DEV_ADR, devad); ++ efx_writeo(efx, ®, FR_AB_MD_ID); + + /* Request data to be read */ +- EFX_POPULATE_OWORD_2(reg, MD_RDC, 1, MD_GC, 0); +- falcon_write(efx, ®, MD_CS_REG_KER); ++ EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_RDC, 1, FRF_AB_MD_GC, 0); ++ efx_writeo(efx, ®, FR_AB_MD_CS); + + /* Wait for data to become available */ + rc = falcon_gmii_wait(efx); + if (rc == 0) { +- falcon_read(efx, ®, MD_RXD_REG_KER); +- rc = EFX_OWORD_FIELD(reg, MD_RXD); ++ efx_reado(efx, ®, FR_AB_MD_RXD); ++ rc = EFX_OWORD_FIELD(reg, FRF_AB_MD_RXD); + EFX_REGDUMP(efx, "read from MDIO %d register %d.%d, got %04x\n", + prtad, devad, addr, rc); + } else { + /* Abort the read operation */ + EFX_POPULATE_OWORD_2(reg, +- MD_RIC, 0, +- MD_GC, 1); +- falcon_write(efx, ®, MD_CS_REG_KER); ++ FRF_AB_MD_RIC, 0, ++ FRF_AB_MD_GC, 1); ++ efx_writeo(efx, ®, FR_AB_MD_CS); + + EFX_LOG(efx, "read from MDIO %d register %d.%d, got error %d\n", + prtad, devad, addr, rc); + } + +- out: +- spin_unlock_bh(&efx->phy_lock); ++out: ++ mutex_unlock(&efx->mdio_lock); + return rc; + } + +-static int falcon_probe_phy(struct efx_nic *efx) ++static void falcon_clock_mac(struct efx_nic *efx) + { +- switch (efx->phy_type) { +- case PHY_TYPE_SFX7101: +- efx->phy_op = &falcon_sfx7101_phy_ops; +- break; +- case PHY_TYPE_SFT9001A: +- case PHY_TYPE_SFT9001B: +- efx->phy_op = &falcon_sft9001_phy_ops; +- break; +- case PHY_TYPE_QT2022C2: +- case PHY_TYPE_QT2025C: +- efx->phy_op = &falcon_xfp_phy_ops; +- break; +- default: +- EFX_ERR(efx, "Unknown PHY type %d\n", +- efx->phy_type); +- return -1; +- } +- +- if (efx->phy_op->macs & EFX_XMAC) +- efx->loopback_modes |= ((1 << LOOPBACK_XGMII) | +- (1 << LOOPBACK_XGXS) | +- (1 << LOOPBACK_XAUI)); +- if (efx->phy_op->macs & EFX_GMAC) +- efx->loopback_modes |= (1 << LOOPBACK_GMAC); +- efx->loopback_modes |= efx->phy_op->loopbacks; ++ unsigned strap_val; ++ efx_oword_t nic_stat; + +- return 0; ++ /* Configure the NIC generated MAC clock correctly */ ++ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); ++ strap_val = EFX_IS10G(efx) ? 5 : 3; ++ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { ++ EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP_EN, 1); ++ EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP, strap_val); ++ efx_writeo(efx, &nic_stat, FR_AB_NIC_STAT); ++ } else { ++ /* Falcon A1 does not support 1G/10G speed switching ++ * and must not be used with a PHY that does. */ ++ BUG_ON(EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_PINS) != ++ strap_val); ++ } + } + +-int falcon_switch_mac(struct efx_nic *efx) ++static void falcon_switch_mac(struct efx_nic *efx) + { + struct efx_mac_operations *old_mac_op = efx->mac_op; +- efx_oword_t nic_stat; +- unsigned strap_val; +- int rc = 0; +- +- /* Don't try to fetch MAC stats while we're switching MACs */ +- efx_stats_disable(efx); +- +- /* Internal loopbacks override the phy speed setting */ +- if (efx->loopback_mode == LOOPBACK_GMAC) { +- efx->link_speed = 1000; +- efx->link_fd = true; +- } else if (LOOPBACK_INTERNAL(efx)) { +- efx->link_speed = 10000; +- efx->link_fd = true; +- } ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ unsigned int stats_done_offset; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); ++ WARN_ON(nic_data->stats_disable_count == 0); ++ + efx->mac_op = (EFX_IS10G(efx) ? + &falcon_xmac_operations : &falcon_gmac_operations); + +- /* Always push the NIC_STAT_REG setting even if the mac hasn't +- * changed, because this function is run post online reset */ +- falcon_read(efx, &nic_stat, NIC_STAT_REG); +- strap_val = EFX_IS10G(efx) ? 5 : 3; +- if (falcon_rev(efx) >= FALCON_REV_B0) { +- EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_EN, 1); +- EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_OVR, strap_val); +- falcon_write(efx, &nic_stat, NIC_STAT_REG); +- } else { +- /* Falcon A1 does not support 1G/10G speed switching +- * and must not be used with a PHY that does. */ +- BUG_ON(EFX_OWORD_FIELD(nic_stat, STRAP_PINS) != strap_val); +- } ++ if (EFX_IS10G(efx)) ++ stats_done_offset = XgDmaDone_offset; ++ else ++ stats_done_offset = GDmaDone_offset; ++ nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset; + + if (old_mac_op == efx->mac_op) +- goto out; ++ return; ++ ++ falcon_clock_mac(efx); + + EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G'); + /* Not all macs support a mac-level link state */ +- efx->mac_up = true; +- +- rc = falcon_reset_macs(efx); +-out: +- efx_stats_enable(efx); +- return rc; ++ efx->xmac_poll_required = false; ++ falcon_reset_macs(efx); + } + + /* This call is responsible for hooking in the MAC and PHY operations */ +-int falcon_probe_port(struct efx_nic *efx) ++static int falcon_probe_port(struct efx_nic *efx) + { + int rc; + +- /* Hook in PHY operations table */ +- rc = falcon_probe_phy(efx); +- if (rc) +- return rc; ++ switch (efx->phy_type) { ++ case PHY_TYPE_SFX7101: ++ efx->phy_op = &falcon_sfx7101_phy_ops; ++ break; ++ case PHY_TYPE_SFT9001A: ++ case PHY_TYPE_SFT9001B: ++ efx->phy_op = &falcon_sft9001_phy_ops; ++ break; ++ case PHY_TYPE_QT2022C2: ++ case PHY_TYPE_QT2025C: ++ efx->phy_op = &falcon_qt202x_phy_ops; ++ break; ++ default: ++ EFX_ERR(efx, "Unknown PHY type %d\n", ++ efx->phy_type); ++ return -ENODEV; ++ } + +- /* Set up MDIO structure for PHY */ +- efx->mdio.mmds = efx->phy_op->mmds; +- efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; ++ /* Fill out MDIO structure and loopback modes */ + efx->mdio.mdio_read = falcon_mdio_read; + efx->mdio.mdio_write = falcon_mdio_write; ++ rc = efx->phy_op->probe(efx); ++ if (rc != 0) ++ return rc; ++ ++ /* Initial assumption */ ++ efx->link_state.speed = 10000; ++ efx->link_state.fd = true; + + /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ +- if (falcon_rev(efx) >= FALCON_REV_B0) ++ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) + efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; + else + efx->wanted_fc = EFX_FC_RX; + + /* Allocate buffer for stats */ +- rc = falcon_alloc_buffer(efx, &efx->stats_buffer, +- FALCON_MAC_STATS_SIZE); ++ rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, ++ FALCON_MAC_STATS_SIZE); + if (rc) + return rc; + EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n", +@@ -2302,40 +923,19 @@ int falcon_probe_port(struct efx_nic *efx) + return 0; + } + +-void falcon_remove_port(struct efx_nic *efx) ++static void falcon_remove_port(struct efx_nic *efx) + { +- falcon_free_buffer(efx, &efx->stats_buffer); ++ efx_nic_free_buffer(efx, &efx->stats_buffer); + } + + /************************************************************************** + * +- * Multicast filtering +- * +- ************************************************************************** +- */ +- +-void falcon_set_multicast_hash(struct efx_nic *efx) +-{ +- union efx_multicast_hash *mc_hash = &efx->multicast_hash; +- +- /* Broadcast packets go through the multicast hash filter. +- * ether_crc_le() of the broadcast address is 0xbe2612ff +- * so we always add bit 0xff to the mask. +- */ +- set_bit_le(0xff, mc_hash->byte); +- +- falcon_write(efx, &mc_hash->oword[0], MAC_MCAST_HASH_REG0_KER); +- falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER); +-} +- +- +-/************************************************************************** +- * + * Falcon test code + * + **************************************************************************/ + +-int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) ++static int ++falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) + { + struct falcon_nvconfig *nvconfig; + struct efx_spi_device *spi; +@@ -2351,10 +951,10 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) + region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL); + if (!region) + return -ENOMEM; +- nvconfig = region + NVCONFIG_OFFSET; ++ nvconfig = region + FALCON_NVCONFIG_OFFSET; + + mutex_lock(&efx->spi_lock); +- rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region); ++ rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region); + mutex_unlock(&efx->spi_lock); + if (rc) { + EFX_ERR(efx, "Failed to read %s\n", +@@ -2367,7 +967,7 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) + struct_ver = le16_to_cpu(nvconfig->board_struct_ver); + + rc = -EINVAL; +- if (magic_num != NVCONFIG_BOARD_MAGIC_NUM) { ++ if (magic_num != FALCON_NVCONFIG_BOARD_MAGIC_NUM) { + EFX_ERR(efx, "NVRAM bad magic 0x%x\n", magic_num); + goto out; + } +@@ -2398,107 +998,54 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) + return rc; + } + +-/* Registers tested in the falcon register test */ +-static struct { +- unsigned address; +- efx_oword_t mask; +-} efx_test_registers[] = { +- { ADR_REGION_REG_KER, ++static int falcon_test_nvram(struct efx_nic *efx) ++{ ++ return falcon_read_nvram(efx, NULL); ++} ++ ++static const struct efx_nic_register_test falcon_b0_register_tests[] = { ++ { FR_AZ_ADR_REGION, + EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, +- { RX_CFG_REG_KER, ++ { FR_AZ_RX_CFG, + EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) }, +- { TX_CFG_REG_KER, ++ { FR_AZ_TX_CFG, + EFX_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) }, +- { TX_CFG2_REG_KER, ++ { FR_AZ_TX_RESERVED, + EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, +- { MAC0_CTRL_REG_KER, ++ { FR_AB_MAC_CTRL, + EFX_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) }, +- { SRM_TX_DC_CFG_REG_KER, ++ { FR_AZ_SRM_TX_DC_CFG, + EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, +- { RX_DC_CFG_REG_KER, ++ { FR_AZ_RX_DC_CFG, + EFX_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) }, +- { RX_DC_PF_WM_REG_KER, ++ { FR_AZ_RX_DC_PF_WM, + EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, +- { DP_CTRL_REG, ++ { FR_BZ_DP_CTRL, + EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, +- { GM_CFG2_REG, ++ { FR_AB_GM_CFG2, + EFX_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) }, +- { GMF_CFG0_REG, ++ { FR_AB_GMF_CFG0, + EFX_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) }, +- { XM_GLB_CFG_REG, ++ { FR_AB_XM_GLB_CFG, + EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) }, +- { XM_TX_CFG_REG, ++ { FR_AB_XM_TX_CFG, + EFX_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) }, +- { XM_RX_CFG_REG, ++ { FR_AB_XM_RX_CFG, + EFX_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) }, +- { XM_RX_PARAM_REG, ++ { FR_AB_XM_RX_PARAM, + EFX_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) }, +- { XM_FC_REG, ++ { FR_AB_XM_FC, + EFX_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) }, +- { XM_ADR_LO_REG, ++ { FR_AB_XM_ADR_LO, + EFX_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) }, +- { XX_SD_CTL_REG, ++ { FR_AB_XX_SD_CTL, + EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) }, + }; + +-static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, +- const efx_oword_t *mask) ++static int falcon_b0_test_registers(struct efx_nic *efx) + { +- return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) || +- ((a->u64[1] ^ b->u64[1]) & mask->u64[1]); +-} +- +-int falcon_test_registers(struct efx_nic *efx) +-{ +- unsigned address = 0, i, j; +- efx_oword_t mask, imask, original, reg, buf; +- +- /* Falcon should be in loopback to isolate the XMAC from the PHY */ +- WARN_ON(!LOOPBACK_INTERNAL(efx)); +- +- for (i = 0; i < ARRAY_SIZE(efx_test_registers); ++i) { +- address = efx_test_registers[i].address; +- mask = imask = efx_test_registers[i].mask; +- EFX_INVERT_OWORD(imask); +- +- falcon_read(efx, &original, address); +- +- /* bit sweep on and off */ +- for (j = 0; j < 128; j++) { +- if (!EFX_EXTRACT_OWORD32(mask, j, j)) +- continue; +- +- /* Test this testable bit can be set in isolation */ +- EFX_AND_OWORD(reg, original, mask); +- EFX_SET_OWORD32(reg, j, j, 1); +- +- falcon_write(efx, ®, address); +- falcon_read(efx, &buf, address); +- +- if (efx_masked_compare_oword(®, &buf, &mask)) +- goto fail; +- +- /* Test this testable bit can be cleared in isolation */ +- EFX_OR_OWORD(reg, original, mask); +- EFX_SET_OWORD32(reg, j, j, 0); +- +- falcon_write(efx, ®, address); +- falcon_read(efx, &buf, address); +- +- if (efx_masked_compare_oword(®, &buf, &mask)) +- goto fail; +- } +- +- falcon_write(efx, &original, address); +- } +- +- return 0; +- +-fail: +- EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT +- " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg), +- EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask)); +- return -EIO; ++ return efx_nic_test_registers(efx, falcon_b0_register_tests, ++ ARRAY_SIZE(falcon_b0_register_tests)); + } + + /************************************************************************** +@@ -2510,13 +1057,13 @@ fail: + + /* Resets NIC to known state. This routine must be called in process + * context and is allowed to sleep. */ +-int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) ++static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) + { + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t glb_ctl_reg_ker; + int rc; + +- EFX_LOG(efx, "performing hardware reset (%d)\n", method); ++ EFX_LOG(efx, "performing %s hardware reset\n", RESET_TYPE(method)); + + /* Initiate device reset */ + if (method == RESET_TYPE_WORLD) { +@@ -2526,7 +1073,7 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) + "function prior to hardware reset\n"); + goto fail1; + } +- if (FALCON_IS_DUAL_FUNC(efx)) { ++ if (efx_nic_is_dual_func(efx)) { + rc = pci_save_state(nic_data->pci_dev2); + if (rc) { + EFX_ERR(efx, "failed to backup PCI state of " +@@ -2537,29 +1084,31 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) + } + + EFX_POPULATE_OWORD_2(glb_ctl_reg_ker, +- EXT_PHY_RST_DUR, 0x7, +- SWRST, 1); ++ FRF_AB_EXT_PHY_RST_DUR, ++ FFE_AB_EXT_PHY_RST_DUR_10240US, ++ FRF_AB_SWRST, 1); + } else { +- int reset_phy = (method == RESET_TYPE_INVISIBLE ? +- EXCLUDE_FROM_RESET : 0); +- + EFX_POPULATE_OWORD_7(glb_ctl_reg_ker, +- EXT_PHY_RST_CTL, reset_phy, +- PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET, +- PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET, +- PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET, +- EE_RST_CTL, EXCLUDE_FROM_RESET, +- EXT_PHY_RST_DUR, 0x7 /* 10ms */, +- SWRST, 1); +- } +- falcon_write(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER); ++ /* exclude PHY from "invisible" reset */ ++ FRF_AB_EXT_PHY_RST_CTL, ++ method == RESET_TYPE_INVISIBLE, ++ /* exclude EEPROM/flash and PCIe */ ++ FRF_AB_PCIE_CORE_RST_CTL, 1, ++ FRF_AB_PCIE_NSTKY_RST_CTL, 1, ++ FRF_AB_PCIE_SD_RST_CTL, 1, ++ FRF_AB_EE_RST_CTL, 1, ++ FRF_AB_EXT_PHY_RST_DUR, ++ FFE_AB_EXT_PHY_RST_DUR_10240US, ++ FRF_AB_SWRST, 1); ++ } ++ efx_writeo(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL); + + EFX_LOG(efx, "waiting for hardware reset\n"); + schedule_timeout_uninterruptible(HZ / 20); + + /* Restore PCI configuration if needed */ + if (method == RESET_TYPE_WORLD) { +- if (FALCON_IS_DUAL_FUNC(efx)) { ++ if (efx_nic_is_dual_func(efx)) { + rc = pci_restore_state(nic_data->pci_dev2); + if (rc) { + EFX_ERR(efx, "failed to restore PCI config for " +@@ -2577,8 +1126,8 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) + } + + /* Assert that reset complete */ +- falcon_read(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER); +- if (EFX_OWORD_FIELD(glb_ctl_reg_ker, SWRST) != 0) { ++ efx_reado(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL); ++ if (EFX_OWORD_FIELD(glb_ctl_reg_ker, FRF_AB_SWRST) != 0) { + rc = -ETIMEDOUT; + EFX_ERR(efx, "timed out waiting for hardware reset\n"); + goto fail5; +@@ -2597,6 +1146,44 @@ fail5: + return rc; + } + ++static void falcon_monitor(struct efx_nic *efx) ++{ ++ bool link_changed; ++ int rc; ++ ++ BUG_ON(!mutex_is_locked(&efx->mac_lock)); ++ ++ rc = falcon_board(efx)->type->monitor(efx); ++ if (rc) { ++ EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", ++ (rc == -ERANGE) ? "reported fault" : "failed"); ++ efx->phy_mode |= PHY_MODE_LOW_POWER; ++ rc = __efx_reconfigure_port(efx); ++ WARN_ON(rc); ++ } ++ ++ if (LOOPBACK_INTERNAL(efx)) ++ link_changed = falcon_loopback_link_poll(efx); ++ else ++ link_changed = efx->phy_op->poll(efx); ++ ++ if (link_changed) { ++ falcon_stop_nic_stats(efx); ++ falcon_deconfigure_mac_wrapper(efx); ++ ++ falcon_switch_mac(efx); ++ rc = efx->mac_op->reconfigure(efx); ++ BUG_ON(rc); ++ ++ falcon_start_nic_stats(efx); ++ ++ efx_link_status_changed(efx); ++ } ++ ++ if (EFX_IS10G(efx)) ++ falcon_poll_xmac(efx); ++} ++ + /* Zeroes out the SRAM contents. This routine must be called in + * process context and is allowed to sleep. + */ +@@ -2606,16 +1193,16 @@ static int falcon_reset_sram(struct efx_nic *efx) + int count; + + /* Set the SRAM wake/sleep GPIO appropriately. */ +- falcon_read(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER); +- EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OEN, 1); +- EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OUT, 1); +- falcon_write(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER); ++ efx_reado(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL); ++ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OEN, 1); ++ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OUT, 1); ++ efx_writeo(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL); + + /* Initiate SRAM reset */ + EFX_POPULATE_OWORD_2(srm_cfg_reg_ker, +- SRAM_OOB_BT_INIT_EN, 1, +- SRM_NUM_BANKS_AND_BANK_SIZE, 0); +- falcon_write(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER); ++ FRF_AZ_SRM_INIT_EN, 1, ++ FRF_AZ_SRM_NB_SZ, 0); ++ efx_writeo(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG); + + /* Wait for SRAM reset to complete */ + count = 0; +@@ -2626,8 +1213,8 @@ static int falcon_reset_sram(struct efx_nic *efx) + schedule_timeout_uninterruptible(HZ / 50); + + /* Check for reset complete */ +- falcon_read(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER); +- if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, SRAM_OOB_BT_INIT_EN)) { ++ efx_reado(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG); ++ if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, FRF_AZ_SRM_INIT_EN)) { + EFX_LOG(efx, "SRAM reset complete\n"); + + return 0; +@@ -2663,8 +1250,6 @@ static int falcon_spi_device_init(struct efx_nic *efx, + spi_device->block_size = + 1 << SPI_DEV_TYPE_FIELD(device_type, + SPI_DEV_TYPE_BLOCK_SIZE); +- +- spi_device->efx = efx; + } else { + spi_device = NULL; + } +@@ -2674,7 +1259,6 @@ static int falcon_spi_device_init(struct efx_nic *efx, + return 0; + } + +- + static void falcon_remove_spi_devices(struct efx_nic *efx) + { + kfree(efx->spi_eeprom); +@@ -2712,16 +1296,16 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) + board_rev = le16_to_cpu(v2->board_revision); + + if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) { +- __le32 fl = v3->spi_device_type[EE_SPI_FLASH]; +- __le32 ee = v3->spi_device_type[EE_SPI_EEPROM]; +- rc = falcon_spi_device_init(efx, &efx->spi_flash, +- EE_SPI_FLASH, +- le32_to_cpu(fl)); ++ rc = falcon_spi_device_init( ++ efx, &efx->spi_flash, FFE_AB_SPI_DEVICE_FLASH, ++ le32_to_cpu(v3->spi_device_type ++ [FFE_AB_SPI_DEVICE_FLASH])); + if (rc) + goto fail2; +- rc = falcon_spi_device_init(efx, &efx->spi_eeprom, +- EE_SPI_EEPROM, +- le32_to_cpu(ee)); ++ rc = falcon_spi_device_init( ++ efx, &efx->spi_eeprom, FFE_AB_SPI_DEVICE_EEPROM, ++ le32_to_cpu(v3->spi_device_type ++ [FFE_AB_SPI_DEVICE_EEPROM])); + if (rc) + goto fail2; + } +@@ -2732,7 +1316,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) + + EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad); + +- efx_set_board_info(efx, board_rev); ++ falcon_probe_board(efx, board_rev); + + kfree(nvconfig); + return 0; +@@ -2744,89 +1328,49 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) + return rc; + } + +-/* Probe the NIC variant (revision, ASIC vs FPGA, function count, port +- * count, port speed). Set workaround and feature flags accordingly. +- */ +-static int falcon_probe_nic_variant(struct efx_nic *efx) +-{ +- efx_oword_t altera_build; +- efx_oword_t nic_stat; +- +- falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER); +- if (EFX_OWORD_FIELD(altera_build, VER_ALL)) { +- EFX_ERR(efx, "Falcon FPGA not supported\n"); +- return -ENODEV; +- } +- +- falcon_read(efx, &nic_stat, NIC_STAT_REG); +- +- switch (falcon_rev(efx)) { +- case FALCON_REV_A0: +- case 0xff: +- EFX_ERR(efx, "Falcon rev A0 not supported\n"); +- return -ENODEV; +- +- case FALCON_REV_A1: +- if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) { +- EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n"); +- return -ENODEV; +- } +- break; +- +- case FALCON_REV_B0: +- break; +- +- default: +- EFX_ERR(efx, "Unknown Falcon rev %d\n", falcon_rev(efx)); +- return -ENODEV; +- } +- +- /* Initial assumed speed */ +- efx->link_speed = EFX_OWORD_FIELD(nic_stat, STRAP_10G) ? 10000 : 1000; +- +- return 0; +-} +- + /* Probe all SPI devices on the NIC */ + static void falcon_probe_spi_devices(struct efx_nic *efx) + { + efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg; + int boot_dev; + +- falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER); +- falcon_read(efx, &nic_stat, NIC_STAT_REG); +- falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); ++ efx_reado(efx, &gpio_ctl, FR_AB_GPIO_CTL); ++ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); ++ efx_reado(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0); + +- if (EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE)) { +- boot_dev = (EFX_OWORD_FIELD(nic_stat, SF_PRST) ? +- EE_SPI_FLASH : EE_SPI_EEPROM); ++ if (EFX_OWORD_FIELD(gpio_ctl, FRF_AB_GPIO3_PWRUP_VALUE)) { ++ boot_dev = (EFX_OWORD_FIELD(nic_stat, FRF_AB_SF_PRST) ? ++ FFE_AB_SPI_DEVICE_FLASH : FFE_AB_SPI_DEVICE_EEPROM); + EFX_LOG(efx, "Booted from %s\n", +- boot_dev == EE_SPI_FLASH ? "flash" : "EEPROM"); ++ boot_dev == FFE_AB_SPI_DEVICE_FLASH ? "flash" : "EEPROM"); + } else { + /* Disable VPD and set clock dividers to safe + * values for initial programming. */ + boot_dev = -1; + EFX_LOG(efx, "Booted from internal ASIC settings;" + " setting SPI config\n"); +- EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0, ++ EFX_POPULATE_OWORD_3(ee_vpd_cfg, FRF_AB_EE_VPD_EN, 0, + /* 125 MHz / 7 ~= 20 MHz */ +- EE_SF_CLOCK_DIV, 7, ++ FRF_AB_EE_SF_CLOCK_DIV, 7, + /* 125 MHz / 63 ~= 2 MHz */ +- EE_EE_CLOCK_DIV, 63); +- falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); ++ FRF_AB_EE_EE_CLOCK_DIV, 63); ++ efx_writeo(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0); + } + +- if (boot_dev == EE_SPI_FLASH) +- falcon_spi_device_init(efx, &efx->spi_flash, EE_SPI_FLASH, ++ if (boot_dev == FFE_AB_SPI_DEVICE_FLASH) ++ falcon_spi_device_init(efx, &efx->spi_flash, ++ FFE_AB_SPI_DEVICE_FLASH, + default_flash_type); +- if (boot_dev == EE_SPI_EEPROM) +- falcon_spi_device_init(efx, &efx->spi_eeprom, EE_SPI_EEPROM, ++ if (boot_dev == FFE_AB_SPI_DEVICE_EEPROM) ++ falcon_spi_device_init(efx, &efx->spi_eeprom, ++ FFE_AB_SPI_DEVICE_EEPROM, + large_eeprom_type); + } + +-int falcon_probe_nic(struct efx_nic *efx) ++static int falcon_probe_nic(struct efx_nic *efx) + { + struct falcon_nic_data *nic_data; ++ struct falcon_board *board; + int rc; + + /* Allocate storage for hardware specific data */ +@@ -2835,15 +1379,33 @@ int falcon_probe_nic(struct efx_nic *efx) + return -ENOMEM; + efx->nic_data = nic_data; + +- /* Determine number of ports etc. */ +- rc = falcon_probe_nic_variant(efx); +- if (rc) ++ rc = -ENODEV; ++ ++ if (efx_nic_fpga_ver(efx) != 0) { ++ EFX_ERR(efx, "Falcon FPGA not supported\n"); + goto fail1; ++ } + +- /* Probe secondary function if expected */ +- if (FALCON_IS_DUAL_FUNC(efx)) { +- struct pci_dev *dev = pci_dev_get(efx->pci_dev); ++ if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { ++ efx_oword_t nic_stat; ++ struct pci_dev *dev; ++ u8 pci_rev = efx->pci_dev->revision; ++ ++ if ((pci_rev == 0xff) || (pci_rev == 0)) { ++ EFX_ERR(efx, "Falcon rev A0 not supported\n"); ++ goto fail1; ++ } ++ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); ++ if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) { ++ EFX_ERR(efx, "Falcon rev A1 1G not supported\n"); ++ goto fail1; ++ } ++ if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) { ++ EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n"); ++ goto fail1; ++ } + ++ dev = pci_dev_get(efx->pci_dev); + while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID, + dev))) { + if (dev->bus == efx->pci_dev->bus && +@@ -2867,7 +1429,7 @@ int falcon_probe_nic(struct efx_nic *efx) + } + + /* Allocate memory for INT_KER */ +- rc = falcon_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); ++ rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); + if (rc) + goto fail4; + BUG_ON(efx->irq_status.dma_addr & 0x0f); +@@ -2884,21 +1446,36 @@ int falcon_probe_nic(struct efx_nic *efx) + goto fail5; + + /* Initialise I2C adapter */ +- efx->i2c_adap.owner = THIS_MODULE; +- nic_data->i2c_data = falcon_i2c_bit_operations; +- nic_data->i2c_data.data = efx; +- efx->i2c_adap.algo_data = &nic_data->i2c_data; +- efx->i2c_adap.dev.parent = &efx->pci_dev->dev; +- strlcpy(efx->i2c_adap.name, "SFC4000 GPIO", sizeof(efx->i2c_adap.name)); +- rc = i2c_bit_add_bus(&efx->i2c_adap); ++ board = falcon_board(efx); ++ board->i2c_adap.owner = THIS_MODULE; ++ board->i2c_data = falcon_i2c_bit_operations; ++ board->i2c_data.data = efx; ++ board->i2c_adap.algo_data = &board->i2c_data; ++ board->i2c_adap.dev.parent = &efx->pci_dev->dev; ++ strlcpy(board->i2c_adap.name, "SFC4000 GPIO", ++ sizeof(board->i2c_adap.name)); ++ rc = i2c_bit_add_bus(&board->i2c_adap); + if (rc) + goto fail5; + ++ rc = falcon_board(efx)->type->init(efx); ++ if (rc) { ++ EFX_ERR(efx, "failed to initialise board\n"); ++ goto fail6; ++ } ++ ++ nic_data->stats_disable_count = 1; ++ setup_timer(&nic_data->stats_timer, &falcon_stats_timer_func, ++ (unsigned long)efx); ++ + return 0; + ++ fail6: ++ BUG_ON(i2c_del_adapter(&board->i2c_adap)); ++ memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); + fail5: + falcon_remove_spi_devices(efx); +- falcon_free_buffer(efx, &efx->irq_status); ++ efx_nic_free_buffer(efx, &efx->irq_status); + fail4: + fail3: + if (nic_data->pci_dev2) { +@@ -2911,166 +1488,147 @@ int falcon_probe_nic(struct efx_nic *efx) + return rc; + } + ++static void falcon_init_rx_cfg(struct efx_nic *efx) ++{ ++ /* Prior to Siena the RX DMA engine will split each frame at ++ * intervals of RX_USR_BUF_SIZE (32-byte units). We set it to ++ * be so large that that never happens. */ ++ const unsigned huge_buf_size = (3 * 4096) >> 5; ++ /* RX control FIFO thresholds (32 entries) */ ++ const unsigned ctrl_xon_thr = 20; ++ const unsigned ctrl_xoff_thr = 25; ++ /* RX data FIFO thresholds (256-byte units; size varies) */ ++ int data_xon_thr = efx_nic_rx_xon_thresh >> 8; ++ int data_xoff_thr = efx_nic_rx_xoff_thresh >> 8; ++ efx_oword_t reg; ++ ++ efx_reado(efx, ®, FR_AZ_RX_CFG); ++ if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { ++ /* Data FIFO size is 5.5K */ ++ if (data_xon_thr < 0) ++ data_xon_thr = 512 >> 8; ++ if (data_xoff_thr < 0) ++ data_xoff_thr = 2048 >> 8; ++ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_DESC_PUSH_EN, 0); ++ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_USR_BUF_SIZE, ++ huge_buf_size); ++ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, data_xon_thr); ++ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, data_xoff_thr); ++ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_TX_TH, ctrl_xon_thr); ++ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_TX_TH, ctrl_xoff_thr); ++ } else { ++ /* Data FIFO size is 80K; register fields moved */ ++ if (data_xon_thr < 0) ++ data_xon_thr = 27648 >> 8; /* ~3*max MTU */ ++ if (data_xoff_thr < 0) ++ data_xoff_thr = 54272 >> 8; /* ~80Kb - 3*max MTU */ ++ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_DESC_PUSH_EN, 0); ++ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_USR_BUF_SIZE, ++ huge_buf_size); ++ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, data_xon_thr); ++ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, data_xoff_thr); ++ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr); ++ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr); ++ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); ++ } ++ /* Always enable XOFF signal from RX FIFO. We enable ++ * or disable transmission of pause frames at the MAC. */ ++ EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); ++ efx_writeo(efx, ®, FR_AZ_RX_CFG); ++} ++ + /* This call performs hardware-specific global initialisation, such as + * defining the descriptor cache sizes and number of RSS channels. + * It does not set up any buffers, descriptor rings or event queues. + */ +-int falcon_init_nic(struct efx_nic *efx) ++static int falcon_init_nic(struct efx_nic *efx) + { + efx_oword_t temp; +- unsigned thresh; + int rc; + + /* Use on-chip SRAM */ +- falcon_read(efx, &temp, NIC_STAT_REG); +- EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1); +- falcon_write(efx, &temp, NIC_STAT_REG); ++ efx_reado(efx, &temp, FR_AB_NIC_STAT); ++ EFX_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1); ++ efx_writeo(efx, &temp, FR_AB_NIC_STAT); + + /* Set the source of the GMAC clock */ +- if (falcon_rev(efx) == FALCON_REV_B0) { +- falcon_read(efx, &temp, GPIO_CTL_REG_KER); +- EFX_SET_OWORD_FIELD(temp, GPIO_USE_NIC_CLK, true); +- falcon_write(efx, &temp, GPIO_CTL_REG_KER); ++ if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { ++ efx_reado(efx, &temp, FR_AB_GPIO_CTL); ++ EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true); ++ efx_writeo(efx, &temp, FR_AB_GPIO_CTL); + } + +- /* Set buffer table mode */ +- EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL); +- falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER); ++ /* Select the correct MAC */ ++ falcon_clock_mac(efx); + + rc = falcon_reset_sram(efx); + if (rc) + return rc; + +- /* Set positions of descriptor caches in SRAM. */ +- EFX_POPULATE_OWORD_1(temp, SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8); +- falcon_write(efx, &temp, SRM_TX_DC_CFG_REG_KER); +- EFX_POPULATE_OWORD_1(temp, SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8); +- falcon_write(efx, &temp, SRM_RX_DC_CFG_REG_KER); +- +- /* Set TX descriptor cache size. */ +- BUILD_BUG_ON(TX_DC_ENTRIES != (16 << TX_DC_ENTRIES_ORDER)); +- EFX_POPULATE_OWORD_1(temp, TX_DC_SIZE, TX_DC_ENTRIES_ORDER); +- falcon_write(efx, &temp, TX_DC_CFG_REG_KER); +- +- /* Set RX descriptor cache size. Set low watermark to size-8, as +- * this allows most efficient prefetching. +- */ +- BUILD_BUG_ON(RX_DC_ENTRIES != (16 << RX_DC_ENTRIES_ORDER)); +- EFX_POPULATE_OWORD_1(temp, RX_DC_SIZE, RX_DC_ENTRIES_ORDER); +- falcon_write(efx, &temp, RX_DC_CFG_REG_KER); +- EFX_POPULATE_OWORD_1(temp, RX_DC_PF_LWM, RX_DC_ENTRIES - 8); +- falcon_write(efx, &temp, RX_DC_PF_WM_REG_KER); +- + /* Clear the parity enables on the TX data fifos as + * they produce false parity errors because of timing issues + */ + if (EFX_WORKAROUND_5129(efx)) { +- falcon_read(efx, &temp, SPARE_REG_KER); +- EFX_SET_OWORD_FIELD(temp, MEM_PERR_EN_TX_DATA, 0); +- falcon_write(efx, &temp, SPARE_REG_KER); ++ efx_reado(efx, &temp, FR_AZ_CSR_SPARE); ++ EFX_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0); ++ efx_writeo(efx, &temp, FR_AZ_CSR_SPARE); + } + +- /* Enable all the genuinely fatal interrupts. (They are still +- * masked by the overall interrupt mask, controlled by +- * falcon_interrupts()). +- * +- * Note: All other fatal interrupts are enabled +- */ +- EFX_POPULATE_OWORD_3(temp, +- ILL_ADR_INT_KER_EN, 1, +- RBUF_OWN_INT_KER_EN, 1, +- TBUF_OWN_INT_KER_EN, 1); +- EFX_INVERT_OWORD(temp); +- falcon_write(efx, &temp, FATAL_INTR_REG_KER); +- + if (EFX_WORKAROUND_7244(efx)) { +- falcon_read(efx, &temp, RX_FILTER_CTL_REG); +- EFX_SET_OWORD_FIELD(temp, UDP_FULL_SRCH_LIMIT, 8); +- EFX_SET_OWORD_FIELD(temp, UDP_WILD_SRCH_LIMIT, 8); +- EFX_SET_OWORD_FIELD(temp, TCP_FULL_SRCH_LIMIT, 8); +- EFX_SET_OWORD_FIELD(temp, TCP_WILD_SRCH_LIMIT, 8); +- falcon_write(efx, &temp, RX_FILTER_CTL_REG); ++ efx_reado(efx, &temp, FR_BZ_RX_FILTER_CTL); ++ EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_FULL_SRCH_LIMIT, 8); ++ EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_WILD_SRCH_LIMIT, 8); ++ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TCP_FULL_SRCH_LIMIT, 8); ++ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TCP_WILD_SRCH_LIMIT, 8); ++ efx_writeo(efx, &temp, FR_BZ_RX_FILTER_CTL); + } + +- falcon_setup_rss_indir_table(efx); +- ++ /* XXX This is documented only for Falcon A0/A1 */ + /* Setup RX. Wait for descriptor is broken and must + * be disabled. RXDP recovery shouldn't be needed, but is. + */ +- falcon_read(efx, &temp, RX_SELF_RST_REG_KER); +- EFX_SET_OWORD_FIELD(temp, RX_NODESC_WAIT_DIS, 1); +- EFX_SET_OWORD_FIELD(temp, RX_RECOVERY_EN, 1); ++ efx_reado(efx, &temp, FR_AA_RX_SELF_RST); ++ EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_NODESC_WAIT_DIS, 1); ++ EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_SELF_RST_EN, 1); + if (EFX_WORKAROUND_5583(efx)) +- EFX_SET_OWORD_FIELD(temp, RX_ISCSI_DIS, 1); +- falcon_write(efx, &temp, RX_SELF_RST_REG_KER); +- +- /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be +- * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q. +- */ +- falcon_read(efx, &temp, TX_CFG2_REG_KER); +- EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER, 0xfe); +- EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER_EN, 1); +- EFX_SET_OWORD_FIELD(temp, TX_ONE_PKT_PER_Q, 1); +- EFX_SET_OWORD_FIELD(temp, TX_CSR_PUSH_EN, 0); +- EFX_SET_OWORD_FIELD(temp, TX_DIS_NON_IP_EV, 1); +- /* Enable SW_EV to inherit in char driver - assume harmless here */ +- EFX_SET_OWORD_FIELD(temp, TX_SW_EV_EN, 1); +- /* Prefetch threshold 2 => fetch when descriptor cache half empty */ +- EFX_SET_OWORD_FIELD(temp, TX_PREF_THRESHOLD, 2); +- /* Squash TX of packets of 16 bytes or less */ +- if (falcon_rev(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx)) +- EFX_SET_OWORD_FIELD(temp, TX_FLUSH_MIN_LEN_EN_B0, 1); +- falcon_write(efx, &temp, TX_CFG2_REG_KER); ++ EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_ISCSI_DIS, 1); ++ efx_writeo(efx, &temp, FR_AA_RX_SELF_RST); + + /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16 + * descriptors (which is bad). + */ +- falcon_read(efx, &temp, TX_CFG_REG_KER); +- EFX_SET_OWORD_FIELD(temp, TX_NO_EOP_DISC_EN, 0); +- falcon_write(efx, &temp, TX_CFG_REG_KER); +- +- /* RX config */ +- falcon_read(efx, &temp, RX_CFG_REG_KER); +- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_DESC_PUSH_EN, 0); +- if (EFX_WORKAROUND_7575(efx)) +- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_USR_BUF_SIZE, +- (3 * 4096) / 32); +- if (falcon_rev(efx) >= FALCON_REV_B0) +- EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 1); +- +- /* RX FIFO flow control thresholds */ +- thresh = ((rx_xon_thresh_bytes >= 0) ? +- rx_xon_thresh_bytes : efx->type->rx_xon_thresh); +- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_MAC_TH, thresh / 256); +- thresh = ((rx_xoff_thresh_bytes >= 0) ? +- rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh); +- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256); +- /* RX control FIFO thresholds [32 entries] */ +- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 20); +- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 25); +- falcon_write(efx, &temp, RX_CFG_REG_KER); ++ efx_reado(efx, &temp, FR_AZ_TX_CFG); ++ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0); ++ efx_writeo(efx, &temp, FR_AZ_TX_CFG); ++ ++ falcon_init_rx_cfg(efx); + + /* Set destination of both TX and RX Flush events */ +- if (falcon_rev(efx) >= FALCON_REV_B0) { +- EFX_POPULATE_OWORD_1(temp, FLS_EVQ_ID, 0); +- falcon_write(efx, &temp, DP_CTRL_REG); ++ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { ++ EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); ++ efx_writeo(efx, &temp, FR_BZ_DP_CTRL); + } + ++ efx_nic_init_common(efx); ++ + return 0; + } + +-void falcon_remove_nic(struct efx_nic *efx) ++static void falcon_remove_nic(struct efx_nic *efx) + { + struct falcon_nic_data *nic_data = efx->nic_data; ++ struct falcon_board *board = falcon_board(efx); + int rc; + ++ board->type->fini(efx); ++ + /* Remove I2C adapter and clear it in preparation for a retry */ +- rc = i2c_del_adapter(&efx->i2c_adap); ++ rc = i2c_del_adapter(&board->i2c_adap); + BUG_ON(rc); +- memset(&efx->i2c_adap, 0, sizeof(efx->i2c_adap)); ++ memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); + + falcon_remove_spi_devices(efx); +- falcon_free_buffer(efx, &efx->irq_status); ++ efx_nic_free_buffer(efx, &efx->irq_status); + + falcon_reset_hw(efx, RESET_TYPE_ALL); + +@@ -3085,12 +1643,86 @@ void falcon_remove_nic(struct efx_nic *efx) + efx->nic_data = NULL; + } + +-void falcon_update_nic_stats(struct efx_nic *efx) ++static void falcon_update_nic_stats(struct efx_nic *efx) + { ++ struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t cnt; + +- falcon_read(efx, &cnt, RX_NODESC_DROP_REG_KER); +- efx->n_rx_nodesc_drop_cnt += EFX_OWORD_FIELD(cnt, RX_NODESC_DROP_CNT); ++ if (nic_data->stats_disable_count) ++ return; ++ ++ efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP); ++ efx->n_rx_nodesc_drop_cnt += ++ EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT); ++ ++ if (nic_data->stats_pending && ++ *nic_data->stats_dma_done == FALCON_STATS_DONE) { ++ nic_data->stats_pending = false; ++ rmb(); /* read the done flag before the stats */ ++ efx->mac_op->update_stats(efx); ++ } ++} ++ ++void falcon_start_nic_stats(struct efx_nic *efx) ++{ ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ ++ spin_lock_bh(&efx->stats_lock); ++ if (--nic_data->stats_disable_count == 0) ++ falcon_stats_request(efx); ++ spin_unlock_bh(&efx->stats_lock); ++} ++ ++void falcon_stop_nic_stats(struct efx_nic *efx) ++{ ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ int i; ++ ++ might_sleep(); ++ ++ spin_lock_bh(&efx->stats_lock); ++ ++nic_data->stats_disable_count; ++ spin_unlock_bh(&efx->stats_lock); ++ ++ del_timer_sync(&nic_data->stats_timer); ++ ++ /* Wait enough time for the most recent transfer to ++ * complete. */ ++ for (i = 0; i < 4 && nic_data->stats_pending; i++) { ++ if (*nic_data->stats_dma_done == FALCON_STATS_DONE) ++ break; ++ msleep(1); ++ } ++ ++ spin_lock_bh(&efx->stats_lock); ++ falcon_stats_complete(efx); ++ spin_unlock_bh(&efx->stats_lock); ++} ++ ++static void falcon_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) ++{ ++ falcon_board(efx)->type->set_id_led(efx, mode); ++} ++ ++/************************************************************************** ++ * ++ * Wake on LAN ++ * ++ ************************************************************************** ++ */ ++ ++static void falcon_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol) ++{ ++ wol->supported = 0; ++ wol->wolopts = 0; ++ memset(&wol->sopass, 0, sizeof(wol->sopass)); ++} ++ ++static int falcon_set_wol(struct efx_nic *efx, u32 type) ++{ ++ if (type != 0) ++ return -EINVAL; ++ return 0; + } + + /************************************************************************** +@@ -3100,50 +1732,91 @@ void falcon_update_nic_stats(struct efx_nic *efx) + ************************************************************************** + */ + +-struct efx_nic_type falcon_a_nic_type = { +- .mem_bar = 2, ++struct efx_nic_type falcon_a1_nic_type = { ++ .probe = falcon_probe_nic, ++ .remove = falcon_remove_nic, ++ .init = falcon_init_nic, ++ .fini = efx_port_dummy_op_void, ++ .monitor = falcon_monitor, ++ .reset = falcon_reset_hw, ++ .probe_port = falcon_probe_port, ++ .remove_port = falcon_remove_port, ++ .prepare_flush = falcon_prepare_flush, ++ .update_stats = falcon_update_nic_stats, ++ .start_stats = falcon_start_nic_stats, ++ .stop_stats = falcon_stop_nic_stats, ++ .set_id_led = falcon_set_id_led, ++ .push_irq_moderation = falcon_push_irq_moderation, ++ .push_multicast_hash = falcon_push_multicast_hash, ++ .reconfigure_port = falcon_reconfigure_port, ++ .get_wol = falcon_get_wol, ++ .set_wol = falcon_set_wol, ++ .resume_wol = efx_port_dummy_op_void, ++ .test_nvram = falcon_test_nvram, ++ .default_mac_ops = &falcon_xmac_operations, ++ ++ .revision = EFX_REV_FALCON_A1, + .mem_map_size = 0x20000, +- .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_A1, +- .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_A1, +- .buf_tbl_base = BUF_TBL_KER_A1, +- .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_A1, +- .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_A1, +- .txd_ring_mask = FALCON_TXD_RING_MASK, +- .rxd_ring_mask = FALCON_RXD_RING_MASK, +- .evq_size = FALCON_EVQ_SIZE, +- .max_dma_mask = FALCON_DMA_MASK, +- .tx_dma_mask = FALCON_TX_DMA_MASK, +- .bug5391_mask = 0xf, +- .rx_xoff_thresh = 2048, +- .rx_xon_thresh = 512, ++ .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER, ++ .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER, ++ .buf_tbl_base = FR_AA_BUF_FULL_TBL_KER, ++ .evq_ptr_tbl_base = FR_AA_EVQ_PTR_TBL_KER, ++ .evq_rptr_tbl_base = FR_AA_EVQ_RPTR_KER, ++ .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), + .rx_buffer_padding = 0x24, + .max_interrupt_mode = EFX_INT_MODE_MSI, + .phys_addr_channels = 4, ++ .tx_dc_base = 0x130000, ++ .rx_dc_base = 0x100000, ++ .offload_features = NETIF_F_IP_CSUM, ++ .reset_world_flags = ETH_RESET_IRQ, + }; + +-struct efx_nic_type falcon_b_nic_type = { +- .mem_bar = 2, ++struct efx_nic_type falcon_b0_nic_type = { ++ .probe = falcon_probe_nic, ++ .remove = falcon_remove_nic, ++ .init = falcon_init_nic, ++ .fini = efx_port_dummy_op_void, ++ .monitor = falcon_monitor, ++ .reset = falcon_reset_hw, ++ .probe_port = falcon_probe_port, ++ .remove_port = falcon_remove_port, ++ .prepare_flush = falcon_prepare_flush, ++ .update_stats = falcon_update_nic_stats, ++ .start_stats = falcon_start_nic_stats, ++ .stop_stats = falcon_stop_nic_stats, ++ .set_id_led = falcon_set_id_led, ++ .push_irq_moderation = falcon_push_irq_moderation, ++ .push_multicast_hash = falcon_push_multicast_hash, ++ .reconfigure_port = falcon_reconfigure_port, ++ .get_wol = falcon_get_wol, ++ .set_wol = falcon_set_wol, ++ .resume_wol = efx_port_dummy_op_void, ++ .test_registers = falcon_b0_test_registers, ++ .test_nvram = falcon_test_nvram, ++ .default_mac_ops = &falcon_xmac_operations, ++ ++ .revision = EFX_REV_FALCON_B0, + /* Map everything up to and including the RSS indirection + * table. Don't map MSI-X table, MSI-X PBA since Linux + * requires that they not be mapped. */ +- .mem_map_size = RX_RSS_INDIR_TBL_B0 + 0x800, +- .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_B0, +- .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_B0, +- .buf_tbl_base = BUF_TBL_KER_B0, +- .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_B0, +- .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_B0, +- .txd_ring_mask = FALCON_TXD_RING_MASK, +- .rxd_ring_mask = FALCON_RXD_RING_MASK, +- .evq_size = FALCON_EVQ_SIZE, +- .max_dma_mask = FALCON_DMA_MASK, +- .tx_dma_mask = FALCON_TX_DMA_MASK, +- .bug5391_mask = 0, +- .rx_xoff_thresh = 54272, /* ~80Kb - 3*max MTU */ +- .rx_xon_thresh = 27648, /* ~3*max MTU */ ++ .mem_map_size = (FR_BZ_RX_INDIRECTION_TBL + ++ FR_BZ_RX_INDIRECTION_TBL_STEP * ++ FR_BZ_RX_INDIRECTION_TBL_ROWS), ++ .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, ++ .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, ++ .buf_tbl_base = FR_BZ_BUF_FULL_TBL, ++ .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL, ++ .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR, ++ .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), + .rx_buffer_padding = 0, + .max_interrupt_mode = EFX_INT_MODE_MSIX, + .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy + * interrupt handler only supports 32 + * channels */ ++ .tx_dc_base = 0x130000, ++ .rx_dc_base = 0x100000, ++ .offload_features = NETIF_F_IP_CSUM, ++ .reset_world_flags = ETH_RESET_IRQ, + }; + +diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h +deleted file mode 100644 +index 77f2e0d..0000000 +--- a/drivers/net/sfc/falcon.h ++++ /dev/null +@@ -1,145 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +- +-#ifndef EFX_FALCON_H +-#define EFX_FALCON_H +- +-#include "net_driver.h" +-#include "efx.h" +- +-/* +- * Falcon hardware control +- */ +- +-enum falcon_revision { +- FALCON_REV_A0 = 0, +- FALCON_REV_A1 = 1, +- FALCON_REV_B0 = 2, +-}; +- +-static inline int falcon_rev(struct efx_nic *efx) +-{ +- return efx->pci_dev->revision; +-} +- +-extern struct efx_nic_type falcon_a_nic_type; +-extern struct efx_nic_type falcon_b_nic_type; +- +-/************************************************************************** +- * +- * Externs +- * +- ************************************************************************** +- */ +- +-/* TX data path */ +-extern int falcon_probe_tx(struct efx_tx_queue *tx_queue); +-extern void falcon_init_tx(struct efx_tx_queue *tx_queue); +-extern void falcon_fini_tx(struct efx_tx_queue *tx_queue); +-extern void falcon_remove_tx(struct efx_tx_queue *tx_queue); +-extern void falcon_push_buffers(struct efx_tx_queue *tx_queue); +- +-/* RX data path */ +-extern int falcon_probe_rx(struct efx_rx_queue *rx_queue); +-extern void falcon_init_rx(struct efx_rx_queue *rx_queue); +-extern void falcon_fini_rx(struct efx_rx_queue *rx_queue); +-extern void falcon_remove_rx(struct efx_rx_queue *rx_queue); +-extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue); +- +-/* Event data path */ +-extern int falcon_probe_eventq(struct efx_channel *channel); +-extern void falcon_init_eventq(struct efx_channel *channel); +-extern void falcon_fini_eventq(struct efx_channel *channel); +-extern void falcon_remove_eventq(struct efx_channel *channel); +-extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota); +-extern void falcon_eventq_read_ack(struct efx_channel *channel); +- +-/* Ports */ +-extern int falcon_probe_port(struct efx_nic *efx); +-extern void falcon_remove_port(struct efx_nic *efx); +- +-/* MAC/PHY */ +-extern int falcon_switch_mac(struct efx_nic *efx); +-extern bool falcon_xaui_link_ok(struct efx_nic *efx); +-extern int falcon_dma_stats(struct efx_nic *efx, +- unsigned int done_offset); +-extern void falcon_drain_tx_fifo(struct efx_nic *efx); +-extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx); +-extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); +- +-/* Interrupts and test events */ +-extern int falcon_init_interrupt(struct efx_nic *efx); +-extern void falcon_enable_interrupts(struct efx_nic *efx); +-extern void falcon_generate_test_event(struct efx_channel *channel, +- unsigned int magic); +-extern void falcon_sim_phy_event(struct efx_nic *efx); +-extern void falcon_generate_interrupt(struct efx_nic *efx); +-extern void falcon_set_int_moderation(struct efx_channel *channel); +-extern void falcon_disable_interrupts(struct efx_nic *efx); +-extern void falcon_fini_interrupt(struct efx_nic *efx); +- +-#define FALCON_IRQ_MOD_RESOLUTION 5 +- +-/* Global Resources */ +-extern int falcon_probe_nic(struct efx_nic *efx); +-extern int falcon_probe_resources(struct efx_nic *efx); +-extern int falcon_init_nic(struct efx_nic *efx); +-extern int falcon_flush_queues(struct efx_nic *efx); +-extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method); +-extern void falcon_remove_resources(struct efx_nic *efx); +-extern void falcon_remove_nic(struct efx_nic *efx); +-extern void falcon_update_nic_stats(struct efx_nic *efx); +-extern void falcon_set_multicast_hash(struct efx_nic *efx); +-extern int falcon_reset_xaui(struct efx_nic *efx); +- +-/* Tests */ +-struct falcon_nvconfig; +-extern int falcon_read_nvram(struct efx_nic *efx, +- struct falcon_nvconfig *nvconfig); +-extern int falcon_test_registers(struct efx_nic *efx); +- +-/************************************************************************** +- * +- * Falcon MAC stats +- * +- ************************************************************************** +- */ +- +-#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset) +-#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH) +- +-/* Retrieve statistic from statistics block */ +-#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \ +- if (FALCON_STAT_WIDTH(falcon_stat) == 16) \ +- (efx)->mac_stats.efx_stat += le16_to_cpu( \ +- *((__force __le16 *) \ +- (efx->stats_buffer.addr + \ +- FALCON_STAT_OFFSET(falcon_stat)))); \ +- else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \ +- (efx)->mac_stats.efx_stat += le32_to_cpu( \ +- *((__force __le32 *) \ +- (efx->stats_buffer.addr + \ +- FALCON_STAT_OFFSET(falcon_stat)))); \ +- else \ +- (efx)->mac_stats.efx_stat += le64_to_cpu( \ +- *((__force __le64 *) \ +- (efx->stats_buffer.addr + \ +- FALCON_STAT_OFFSET(falcon_stat)))); \ +- } while (0) +- +-#define FALCON_MAC_STATS_SIZE 0x100 +- +-#define MAC_DATA_LBN 0 +-#define MAC_DATA_WIDTH 32 +- +-extern void falcon_generate_event(struct efx_channel *channel, +- efx_qword_t *event); +- +-#endif /* EFX_FALCON_H */ +diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c +new file mode 100644 +index 0000000..bf0b96a +--- /dev/null ++++ b/drivers/net/sfc/falcon_boards.c +@@ -0,0 +1,752 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2007-2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++#include ++ ++#include "net_driver.h" ++#include "phy.h" ++#include "efx.h" ++#include "nic.h" ++#include "regs.h" ++#include "io.h" ++#include "workarounds.h" ++ ++/* Macros for unpacking the board revision */ ++/* The revision info is in host byte order. */ ++#define FALCON_BOARD_TYPE(_rev) (_rev >> 8) ++#define FALCON_BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf) ++#define FALCON_BOARD_MINOR(_rev) (_rev & 0xf) ++ ++/* Board types */ ++#define FALCON_BOARD_SFE4001 0x01 ++#define FALCON_BOARD_SFE4002 0x02 ++#define FALCON_BOARD_SFN4111T 0x51 ++#define FALCON_BOARD_SFN4112F 0x52 ++ ++/***************************************************************************** ++ * Support for LM87 sensor chip used on several boards ++ */ ++#define LM87_REG_ALARMS1 0x41 ++#define LM87_REG_ALARMS2 0x42 ++#define LM87_IN_LIMITS(nr, _min, _max) \ ++ 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min ++#define LM87_AIN_LIMITS(nr, _min, _max) \ ++ 0x3B + (nr), _max, 0x1A + (nr), _min ++#define LM87_TEMP_INT_LIMITS(_min, _max) \ ++ 0x39, _max, 0x3A, _min ++#define LM87_TEMP_EXT1_LIMITS(_min, _max) \ ++ 0x37, _max, 0x38, _min ++ ++#define LM87_ALARM_TEMP_INT 0x10 ++#define LM87_ALARM_TEMP_EXT1 0x20 ++ ++#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE) ++ ++static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, ++ const u8 *reg_values) ++{ ++ struct falcon_board *board = falcon_board(efx); ++ struct i2c_client *client = i2c_new_device(&board->i2c_adap, info); ++ int rc; ++ ++ if (!client) ++ return -EIO; ++ ++ while (*reg_values) { ++ u8 reg = *reg_values++; ++ u8 value = *reg_values++; ++ rc = i2c_smbus_write_byte_data(client, reg, value); ++ if (rc) ++ goto err; ++ } ++ ++ board->hwmon_client = client; ++ return 0; ++ ++err: ++ i2c_unregister_device(client); ++ return rc; ++} ++ ++static void efx_fini_lm87(struct efx_nic *efx) ++{ ++ i2c_unregister_device(falcon_board(efx)->hwmon_client); ++} ++ ++static int efx_check_lm87(struct efx_nic *efx, unsigned mask) ++{ ++ struct i2c_client *client = falcon_board(efx)->hwmon_client; ++ s32 alarms1, alarms2; ++ ++ /* If link is up then do not monitor temperature */ ++ if (EFX_WORKAROUND_7884(efx) && efx->link_state.up) ++ return 0; ++ ++ alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); ++ alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); ++ if (alarms1 < 0) ++ return alarms1; ++ if (alarms2 < 0) ++ return alarms2; ++ alarms1 &= mask; ++ alarms2 &= mask >> 8; ++ if (alarms1 || alarms2) { ++ EFX_ERR(efx, ++ "LM87 detected a hardware failure (status %02x:%02x)" ++ "%s%s\n", ++ alarms1, alarms2, ++ (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "", ++ (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : ""); ++ return -ERANGE; ++ } ++ ++ return 0; ++} ++ ++#else /* !CONFIG_SENSORS_LM87 */ ++ ++static inline int ++efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, ++ const u8 *reg_values) ++{ ++ return 0; ++} ++static inline void efx_fini_lm87(struct efx_nic *efx) ++{ ++} ++static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_SENSORS_LM87 */ ++ ++/***************************************************************************** ++ * Support for the SFE4001 and SFN4111T NICs. ++ * ++ * The SFE4001 does not power-up fully at reset due to its high power ++ * consumption. We control its power via a PCA9539 I/O expander. ++ * Both boards have a MAX6647 temperature monitor which we expose to ++ * the lm90 driver. ++ * ++ * This also provides minimal support for reflashing the PHY, which is ++ * initiated by resetting it with the FLASH_CFG_1 pin pulled down. ++ * On SFE4001 rev A2 and later this is connected to the 3V3X output of ++ * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3. ++ * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually ++ * exclusive with the network device being open. ++ */ ++ ++/************************************************************************** ++ * Support for I2C IO Expander device on SFE4001 ++ */ ++#define PCA9539 0x74 ++ ++#define P0_IN 0x00 ++#define P0_OUT 0x02 ++#define P0_INVERT 0x04 ++#define P0_CONFIG 0x06 ++ ++#define P0_EN_1V0X_LBN 0 ++#define P0_EN_1V0X_WIDTH 1 ++#define P0_EN_1V2_LBN 1 ++#define P0_EN_1V2_WIDTH 1 ++#define P0_EN_2V5_LBN 2 ++#define P0_EN_2V5_WIDTH 1 ++#define P0_EN_3V3X_LBN 3 ++#define P0_EN_3V3X_WIDTH 1 ++#define P0_EN_5V_LBN 4 ++#define P0_EN_5V_WIDTH 1 ++#define P0_SHORTEN_JTAG_LBN 5 ++#define P0_SHORTEN_JTAG_WIDTH 1 ++#define P0_X_TRST_LBN 6 ++#define P0_X_TRST_WIDTH 1 ++#define P0_DSP_RESET_LBN 7 ++#define P0_DSP_RESET_WIDTH 1 ++ ++#define P1_IN 0x01 ++#define P1_OUT 0x03 ++#define P1_INVERT 0x05 ++#define P1_CONFIG 0x07 ++ ++#define P1_AFE_PWD_LBN 0 ++#define P1_AFE_PWD_WIDTH 1 ++#define P1_DSP_PWD25_LBN 1 ++#define P1_DSP_PWD25_WIDTH 1 ++#define P1_RESERVED_LBN 2 ++#define P1_RESERVED_WIDTH 2 ++#define P1_SPARE_LBN 4 ++#define P1_SPARE_WIDTH 4 ++ ++/* Temperature Sensor */ ++#define MAX664X_REG_RSL 0x02 ++#define MAX664X_REG_WLHO 0x0B ++ ++static void sfe4001_poweroff(struct efx_nic *efx) ++{ ++ struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; ++ struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; ++ ++ /* Turn off all power rails and disable outputs */ ++ i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); ++ i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff); ++ i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); ++ ++ /* Clear any over-temperature alert */ ++ i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); ++} ++ ++static int sfe4001_poweron(struct efx_nic *efx) ++{ ++ struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; ++ struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; ++ unsigned int i, j; ++ int rc; ++ u8 out; ++ ++ /* Clear any previous over-temperature alert */ ++ rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); ++ if (rc < 0) ++ return rc; ++ ++ /* Enable port 0 and port 1 outputs on IO expander */ ++ rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); ++ if (rc) ++ return rc; ++ rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, ++ 0xff & ~(1 << P1_SPARE_LBN)); ++ if (rc) ++ goto fail_on; ++ ++ /* If PHY power is on, turn it all off and wait 1 second to ++ * ensure a full reset. ++ */ ++ rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT); ++ if (rc < 0) ++ goto fail_on; ++ out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | ++ (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | ++ (0 << P0_EN_1V0X_LBN)); ++ if (rc != out) { ++ EFX_INFO(efx, "power-cycling PHY\n"); ++ rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); ++ if (rc) ++ goto fail_on; ++ schedule_timeout_uninterruptible(HZ); ++ } ++ ++ for (i = 0; i < 20; ++i) { ++ /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ ++ out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | ++ (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | ++ (1 << P0_X_TRST_LBN)); ++ if (efx->phy_mode & PHY_MODE_SPECIAL) ++ out |= 1 << P0_EN_3V3X_LBN; ++ ++ rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); ++ if (rc) ++ goto fail_on; ++ msleep(10); ++ ++ /* Turn on 1V power rail */ ++ out &= ~(1 << P0_EN_1V0X_LBN); ++ rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); ++ if (rc) ++ goto fail_on; ++ ++ EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i); ++ ++ /* In flash config mode, DSP does not turn on AFE, so ++ * just wait 1 second. ++ */ ++ if (efx->phy_mode & PHY_MODE_SPECIAL) { ++ schedule_timeout_uninterruptible(HZ); ++ return 0; ++ } ++ ++ for (j = 0; j < 10; ++j) { ++ msleep(100); ++ ++ /* Check DSP has asserted AFE power line */ ++ rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); ++ if (rc < 0) ++ goto fail_on; ++ if (rc & (1 << P1_AFE_PWD_LBN)) ++ return 0; ++ } ++ } ++ ++ EFX_INFO(efx, "timed out waiting for DSP boot\n"); ++ rc = -ETIMEDOUT; ++fail_on: ++ sfe4001_poweroff(efx); ++ return rc; ++} ++ ++static int sfn4111t_reset(struct efx_nic *efx) ++{ ++ struct falcon_board *board = falcon_board(efx); ++ efx_oword_t reg; ++ ++ /* GPIO 3 and the GPIO register are shared with I2C, so block that */ ++ i2c_lock_adapter(&board->i2c_adap); ++ ++ /* Pull RST_N (GPIO 2) low then let it up again, setting the ++ * FLASH_CFG_1 strap (GPIO 3) appropriately. Only change the ++ * output enables; the output levels should always be 0 (low) ++ * and we rely on external pull-ups. */ ++ efx_reado(efx, ®, FR_AB_GPIO_CTL); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, true); ++ efx_writeo(efx, ®, FR_AB_GPIO_CTL); ++ msleep(1000); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, false); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, ++ !!(efx->phy_mode & PHY_MODE_SPECIAL)); ++ efx_writeo(efx, ®, FR_AB_GPIO_CTL); ++ msleep(1); ++ ++ i2c_unlock_adapter(&board->i2c_adap); ++ ++ ssleep(1); ++ return 0; ++} ++ ++static ssize_t show_phy_flash_cfg(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); ++ return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL)); ++} ++ ++static ssize_t set_phy_flash_cfg(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); ++ enum efx_phy_mode old_mode, new_mode; ++ int err; ++ ++ rtnl_lock(); ++ old_mode = efx->phy_mode; ++ if (count == 0 || *buf == '0') ++ new_mode = old_mode & ~PHY_MODE_SPECIAL; ++ else ++ new_mode = PHY_MODE_SPECIAL; ++ if (old_mode == new_mode) { ++ err = 0; ++ } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { ++ err = -EBUSY; ++ } else { ++ /* Reset the PHY, reconfigure the MAC and enable/disable ++ * MAC stats accordingly. */ ++ efx->phy_mode = new_mode; ++ if (new_mode & PHY_MODE_SPECIAL) ++ falcon_stop_nic_stats(efx); ++ if (falcon_board(efx)->type->id == FALCON_BOARD_SFE4001) ++ err = sfe4001_poweron(efx); ++ else ++ err = sfn4111t_reset(efx); ++ if (!err) ++ err = efx_reconfigure_port(efx); ++ if (!(new_mode & PHY_MODE_SPECIAL)) ++ falcon_start_nic_stats(efx); ++ } ++ rtnl_unlock(); ++ ++ return err ? err : count; ++} ++ ++static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg); ++ ++static void sfe4001_fini(struct efx_nic *efx) ++{ ++ struct falcon_board *board = falcon_board(efx); ++ ++ EFX_INFO(efx, "%s\n", __func__); ++ ++ device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); ++ sfe4001_poweroff(efx); ++ i2c_unregister_device(board->ioexp_client); ++ i2c_unregister_device(board->hwmon_client); ++} ++ ++static int sfe4001_check_hw(struct efx_nic *efx) ++{ ++ s32 status; ++ ++ /* If XAUI link is up then do not monitor */ ++ if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required) ++ return 0; ++ ++ /* Check the powered status of the PHY. Lack of power implies that ++ * the MAX6647 has shut down power to it, probably due to a temp. ++ * alarm. Reading the power status rather than the MAX6647 status ++ * directly because the later is read-to-clear and would thus ++ * start to power up the PHY again when polled, causing us to blip ++ * the power undesirably. ++ * We know we can read from the IO expander because we did ++ * it during power-on. Assume failure now is bad news. */ ++ status = i2c_smbus_read_byte_data(falcon_board(efx)->ioexp_client, P1_IN); ++ if (status >= 0 && ++ (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) ++ return 0; ++ ++ /* Use board power control, not PHY power control */ ++ sfe4001_poweroff(efx); ++ efx->phy_mode = PHY_MODE_OFF; ++ ++ return (status < 0) ? -EIO : -ERANGE; ++} ++ ++static struct i2c_board_info sfe4001_hwmon_info = { ++ I2C_BOARD_INFO("max6647", 0x4e), ++}; ++ ++/* This board uses an I2C expander to provider power to the PHY, which needs to ++ * be turned on before the PHY can be used. ++ * Context: Process context, rtnl lock held ++ */ ++static int sfe4001_init(struct efx_nic *efx) ++{ ++ struct falcon_board *board = falcon_board(efx); ++ int rc; ++ ++#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE) ++ board->hwmon_client = ++ i2c_new_device(&board->i2c_adap, &sfe4001_hwmon_info); ++#else ++ board->hwmon_client = ++ i2c_new_dummy(&board->i2c_adap, sfe4001_hwmon_info.addr); ++#endif ++ if (!board->hwmon_client) ++ return -EIO; ++ ++ /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ ++ rc = i2c_smbus_write_byte_data(board->hwmon_client, ++ MAX664X_REG_WLHO, 90); ++ if (rc) ++ goto fail_hwmon; ++ ++ board->ioexp_client = i2c_new_dummy(&board->i2c_adap, PCA9539); ++ if (!board->ioexp_client) { ++ rc = -EIO; ++ goto fail_hwmon; ++ } ++ ++ if (efx->phy_mode & PHY_MODE_SPECIAL) { ++ /* PHY won't generate a 156.25 MHz clock and MAC stats fetch ++ * will fail. */ ++ falcon_stop_nic_stats(efx); ++ } ++ rc = sfe4001_poweron(efx); ++ if (rc) ++ goto fail_ioexp; ++ ++ rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); ++ if (rc) ++ goto fail_on; ++ ++ EFX_INFO(efx, "PHY is powered on\n"); ++ return 0; ++ ++fail_on: ++ sfe4001_poweroff(efx); ++fail_ioexp: ++ i2c_unregister_device(board->ioexp_client); ++fail_hwmon: ++ i2c_unregister_device(board->hwmon_client); ++ return rc; ++} ++ ++static int sfn4111t_check_hw(struct efx_nic *efx) ++{ ++ s32 status; ++ ++ /* If XAUI link is up then do not monitor */ ++ if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required) ++ return 0; ++ ++ /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */ ++ status = i2c_smbus_read_byte_data(falcon_board(efx)->hwmon_client, ++ MAX664X_REG_RSL); ++ if (status < 0) ++ return -EIO; ++ if (status & 0x57) ++ return -ERANGE; ++ return 0; ++} ++ ++static void sfn4111t_fini(struct efx_nic *efx) ++{ ++ EFX_INFO(efx, "%s\n", __func__); ++ ++ device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); ++ i2c_unregister_device(falcon_board(efx)->hwmon_client); ++} ++ ++static struct i2c_board_info sfn4111t_a0_hwmon_info = { ++ I2C_BOARD_INFO("max6647", 0x4e), ++}; ++ ++static struct i2c_board_info sfn4111t_r5_hwmon_info = { ++ I2C_BOARD_INFO("max6646", 0x4d), ++}; ++ ++static void sfn4111t_init_phy(struct efx_nic *efx) ++{ ++ if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { ++ if (sft9001_wait_boot(efx) != -EINVAL) ++ return; ++ ++ efx->phy_mode = PHY_MODE_SPECIAL; ++ falcon_stop_nic_stats(efx); ++ } ++ ++ sfn4111t_reset(efx); ++ sft9001_wait_boot(efx); ++} ++ ++static int sfn4111t_init(struct efx_nic *efx) ++{ ++ struct falcon_board *board = falcon_board(efx); ++ int rc; ++ ++ board->hwmon_client = ++ i2c_new_device(&board->i2c_adap, ++ (board->minor < 5) ? ++ &sfn4111t_a0_hwmon_info : ++ &sfn4111t_r5_hwmon_info); ++ if (!board->hwmon_client) ++ return -EIO; ++ ++ rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); ++ if (rc) ++ goto fail_hwmon; ++ ++ if (efx->phy_mode & PHY_MODE_SPECIAL) ++ /* PHY may not generate a 156.25 MHz clock and MAC ++ * stats fetch will fail. */ ++ falcon_stop_nic_stats(efx); ++ ++ return 0; ++ ++fail_hwmon: ++ i2c_unregister_device(board->hwmon_client); ++ return rc; ++} ++ ++/***************************************************************************** ++ * Support for the SFE4002 ++ * ++ */ ++static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */ ++ ++static const u8 sfe4002_lm87_regs[] = { ++ LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ ++ LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ ++ LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ ++ LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */ ++ LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ ++ LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ ++ LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */ ++ LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ ++ LM87_TEMP_INT_LIMITS(10, 60), /* board */ ++ LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ ++ 0 ++}; ++ ++static struct i2c_board_info sfe4002_hwmon_info = { ++ I2C_BOARD_INFO("lm87", 0x2e), ++ .platform_data = &sfe4002_lm87_channel, ++}; ++ ++/****************************************************************************/ ++/* LED allocations. Note that on rev A0 boards the schematic and the reality ++ * differ: red and green are swapped. Below is the fixed (A1) layout (there ++ * are only 3 A0 boards in existence, so no real reason to make this ++ * conditional). ++ */ ++#define SFE4002_FAULT_LED (2) /* Red */ ++#define SFE4002_RX_LED (0) /* Green */ ++#define SFE4002_TX_LED (1) /* Amber */ ++ ++static void sfe4002_init_phy(struct efx_nic *efx) ++{ ++ /* Set the TX and RX LEDs to reflect status and activity, and the ++ * fault LED off */ ++ falcon_qt202x_set_led(efx, SFE4002_TX_LED, ++ QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT); ++ falcon_qt202x_set_led(efx, SFE4002_RX_LED, ++ QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT); ++ falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF); ++} ++ ++static void sfe4002_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) ++{ ++ falcon_qt202x_set_led( ++ efx, SFE4002_FAULT_LED, ++ (mode == EFX_LED_ON) ? QUAKE_LED_ON : QUAKE_LED_OFF); ++} ++ ++static int sfe4002_check_hw(struct efx_nic *efx) ++{ ++ struct falcon_board *board = falcon_board(efx); ++ ++ /* A0 board rev. 4002s report a temperature fault the whole time ++ * (bad sensor) so we mask it out. */ ++ unsigned alarm_mask = ++ (board->major == 0 && board->minor == 0) ? ++ ~LM87_ALARM_TEMP_EXT1 : ~0; ++ ++ return efx_check_lm87(efx, alarm_mask); ++} ++ ++static int sfe4002_init(struct efx_nic *efx) ++{ ++ return efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); ++} ++ ++/***************************************************************************** ++ * Support for the SFN4112F ++ * ++ */ ++static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */ ++ ++static const u8 sfn4112f_lm87_regs[] = { ++ LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ ++ LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ ++ LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ ++ LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ ++ LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ ++ LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ ++ LM87_TEMP_INT_LIMITS(10, 60), /* board */ ++ LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ ++ 0 ++}; ++ ++static struct i2c_board_info sfn4112f_hwmon_info = { ++ I2C_BOARD_INFO("lm87", 0x2e), ++ .platform_data = &sfn4112f_lm87_channel, ++}; ++ ++#define SFN4112F_ACT_LED 0 ++#define SFN4112F_LINK_LED 1 ++ ++static void sfn4112f_init_phy(struct efx_nic *efx) ++{ ++ falcon_qt202x_set_led(efx, SFN4112F_ACT_LED, ++ QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT); ++ falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, ++ QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT); ++} ++ ++static void sfn4112f_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) ++{ ++ int reg; ++ ++ switch (mode) { ++ case EFX_LED_OFF: ++ reg = QUAKE_LED_OFF; ++ break; ++ case EFX_LED_ON: ++ reg = QUAKE_LED_ON; ++ break; ++ default: ++ reg = QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT; ++ break; ++ } ++ ++ falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, reg); ++} ++ ++static int sfn4112f_check_hw(struct efx_nic *efx) ++{ ++ /* Mask out unused sensors */ ++ return efx_check_lm87(efx, ~0x48); ++} ++ ++static int sfn4112f_init(struct efx_nic *efx) ++{ ++ return efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs); ++} ++ ++static const struct falcon_board_type board_types[] = { ++ { ++ .id = FALCON_BOARD_SFE4001, ++ .ref_model = "SFE4001", ++ .gen_type = "10GBASE-T adapter", ++ .init = sfe4001_init, ++ .init_phy = efx_port_dummy_op_void, ++ .fini = sfe4001_fini, ++ .set_id_led = tenxpress_set_id_led, ++ .monitor = sfe4001_check_hw, ++ }, ++ { ++ .id = FALCON_BOARD_SFE4002, ++ .ref_model = "SFE4002", ++ .gen_type = "XFP adapter", ++ .init = sfe4002_init, ++ .init_phy = sfe4002_init_phy, ++ .fini = efx_fini_lm87, ++ .set_id_led = sfe4002_set_id_led, ++ .monitor = sfe4002_check_hw, ++ }, ++ { ++ .id = FALCON_BOARD_SFN4111T, ++ .ref_model = "SFN4111T", ++ .gen_type = "100/1000/10GBASE-T adapter", ++ .init = sfn4111t_init, ++ .init_phy = sfn4111t_init_phy, ++ .fini = sfn4111t_fini, ++ .set_id_led = tenxpress_set_id_led, ++ .monitor = sfn4111t_check_hw, ++ }, ++ { ++ .id = FALCON_BOARD_SFN4112F, ++ .ref_model = "SFN4112F", ++ .gen_type = "SFP+ adapter", ++ .init = sfn4112f_init, ++ .init_phy = sfn4112f_init_phy, ++ .fini = efx_fini_lm87, ++ .set_id_led = sfn4112f_set_id_led, ++ .monitor = sfn4112f_check_hw, ++ }, ++}; ++ ++static const struct falcon_board_type falcon_dummy_board = { ++ .init = efx_port_dummy_op_int, ++ .init_phy = efx_port_dummy_op_void, ++ .fini = efx_port_dummy_op_void, ++ .set_id_led = efx_port_dummy_op_set_id_led, ++ .monitor = efx_port_dummy_op_int, ++}; ++ ++void falcon_probe_board(struct efx_nic *efx, u16 revision_info) ++{ ++ struct falcon_board *board = falcon_board(efx); ++ u8 type_id = FALCON_BOARD_TYPE(revision_info); ++ int i; ++ ++ board->major = FALCON_BOARD_MAJOR(revision_info); ++ board->minor = FALCON_BOARD_MINOR(revision_info); ++ ++ for (i = 0; i < ARRAY_SIZE(board_types); i++) ++ if (board_types[i].id == type_id) ++ board->type = &board_types[i]; ++ ++ if (board->type) { ++ EFX_INFO(efx, "board is %s rev %c%d\n", ++ (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) ++ ? board->type->ref_model : board->type->gen_type, ++ 'A' + board->major, board->minor); ++ } else { ++ EFX_ERR(efx, "unknown board type %d\n", type_id); ++ board->type = &falcon_dummy_board; ++ } ++} +diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c +index 8865eae..7dadfcb 100644 +--- a/drivers/net/sfc/falcon_gmac.c ++++ b/drivers/net/sfc/falcon_gmac.c +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -11,11 +11,10 @@ + #include + #include "net_driver.h" + #include "efx.h" +-#include "falcon.h" ++#include "nic.h" + #include "mac.h" +-#include "falcon_hwdefs.h" +-#include "falcon_io.h" +-#include "gmii.h" ++#include "regs.h" ++#include "io.h" + + /************************************************************************** + * +@@ -23,106 +22,109 @@ + * + *************************************************************************/ + +-static void falcon_reconfigure_gmac(struct efx_nic *efx) ++static int falcon_reconfigure_gmac(struct efx_nic *efx) + { ++ struct efx_link_state *link_state = &efx->link_state; + bool loopback, tx_fc, rx_fc, bytemode; + int if_mode; + unsigned int max_frame_len; + efx_oword_t reg; + + /* Configuration register 1 */ +- tx_fc = (efx->link_fc & EFX_FC_TX) || !efx->link_fd; +- rx_fc = !!(efx->link_fc & EFX_FC_RX); ++ tx_fc = (link_state->fc & EFX_FC_TX) || !link_state->fd; ++ rx_fc = !!(link_state->fc & EFX_FC_RX); + loopback = (efx->loopback_mode == LOOPBACK_GMAC); +- bytemode = (efx->link_speed == 1000); ++ bytemode = (link_state->speed == 1000); + + EFX_POPULATE_OWORD_5(reg, +- GM_LOOP, loopback, +- GM_TX_EN, 1, +- GM_TX_FC_EN, tx_fc, +- GM_RX_EN, 1, +- GM_RX_FC_EN, rx_fc); +- falcon_write(efx, ®, GM_CFG1_REG); ++ FRF_AB_GM_LOOP, loopback, ++ FRF_AB_GM_TX_EN, 1, ++ FRF_AB_GM_TX_FC_EN, tx_fc, ++ FRF_AB_GM_RX_EN, 1, ++ FRF_AB_GM_RX_FC_EN, rx_fc); ++ efx_writeo(efx, ®, FR_AB_GM_CFG1); + udelay(10); + + /* Configuration register 2 */ + if_mode = (bytemode) ? 2 : 1; + EFX_POPULATE_OWORD_5(reg, +- GM_IF_MODE, if_mode, +- GM_PAD_CRC_EN, 1, +- GM_LEN_CHK, 1, +- GM_FD, efx->link_fd, +- GM_PAMBL_LEN, 0x7/*datasheet recommended */); ++ FRF_AB_GM_IF_MODE, if_mode, ++ FRF_AB_GM_PAD_CRC_EN, 1, ++ FRF_AB_GM_LEN_CHK, 1, ++ FRF_AB_GM_FD, link_state->fd, ++ FRF_AB_GM_PAMBL_LEN, 0x7/*datasheet recommended */); + +- falcon_write(efx, ®, GM_CFG2_REG); ++ efx_writeo(efx, ®, FR_AB_GM_CFG2); + udelay(10); + + /* Max frame len register */ + max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); +- EFX_POPULATE_OWORD_1(reg, GM_MAX_FLEN, max_frame_len); +- falcon_write(efx, ®, GM_MAX_FLEN_REG); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_MAX_FLEN, max_frame_len); ++ efx_writeo(efx, ®, FR_AB_GM_MAX_FLEN); + udelay(10); + + /* FIFO configuration register 0 */ + EFX_POPULATE_OWORD_5(reg, +- GMF_FTFENREQ, 1, +- GMF_STFENREQ, 1, +- GMF_FRFENREQ, 1, +- GMF_SRFENREQ, 1, +- GMF_WTMENREQ, 1); +- falcon_write(efx, ®, GMF_CFG0_REG); ++ FRF_AB_GMF_FTFENREQ, 1, ++ FRF_AB_GMF_STFENREQ, 1, ++ FRF_AB_GMF_FRFENREQ, 1, ++ FRF_AB_GMF_SRFENREQ, 1, ++ FRF_AB_GMF_WTMENREQ, 1); ++ efx_writeo(efx, ®, FR_AB_GMF_CFG0); + udelay(10); + + /* FIFO configuration register 1 */ + EFX_POPULATE_OWORD_2(reg, +- GMF_CFGFRTH, 0x12, +- GMF_CFGXOFFRTX, 0xffff); +- falcon_write(efx, ®, GMF_CFG1_REG); ++ FRF_AB_GMF_CFGFRTH, 0x12, ++ FRF_AB_GMF_CFGXOFFRTX, 0xffff); ++ efx_writeo(efx, ®, FR_AB_GMF_CFG1); + udelay(10); + + /* FIFO configuration register 2 */ + EFX_POPULATE_OWORD_2(reg, +- GMF_CFGHWM, 0x3f, +- GMF_CFGLWM, 0xa); +- falcon_write(efx, ®, GMF_CFG2_REG); ++ FRF_AB_GMF_CFGHWM, 0x3f, ++ FRF_AB_GMF_CFGLWM, 0xa); ++ efx_writeo(efx, ®, FR_AB_GMF_CFG2); + udelay(10); + + /* FIFO configuration register 3 */ + EFX_POPULATE_OWORD_2(reg, +- GMF_CFGHWMFT, 0x1c, +- GMF_CFGFTTH, 0x08); +- falcon_write(efx, ®, GMF_CFG3_REG); ++ FRF_AB_GMF_CFGHWMFT, 0x1c, ++ FRF_AB_GMF_CFGFTTH, 0x08); ++ efx_writeo(efx, ®, FR_AB_GMF_CFG3); + udelay(10); + + /* FIFO configuration register 4 */ +- EFX_POPULATE_OWORD_1(reg, GMF_HSTFLTRFRM_PAUSE, 1); +- falcon_write(efx, ®, GMF_CFG4_REG); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_GMF_HSTFLTRFRM_PAUSE, 1); ++ efx_writeo(efx, ®, FR_AB_GMF_CFG4); + udelay(10); + + /* FIFO configuration register 5 */ +- falcon_read(efx, ®, GMF_CFG5_REG); +- EFX_SET_OWORD_FIELD(reg, GMF_CFGBYTMODE, bytemode); +- EFX_SET_OWORD_FIELD(reg, GMF_CFGHDPLX, !efx->link_fd); +- EFX_SET_OWORD_FIELD(reg, GMF_HSTDRPLT64, !efx->link_fd); +- EFX_SET_OWORD_FIELD(reg, GMF_HSTFLTRFRMDC_PAUSE, 0); +- falcon_write(efx, ®, GMF_CFG5_REG); ++ efx_reado(efx, ®, FR_AB_GMF_CFG5); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGBYTMODE, bytemode); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGHDPLX, !link_state->fd); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTDRPLT64, !link_state->fd); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTFLTRFRMDC_PAUSE, 0); ++ efx_writeo(efx, ®, FR_AB_GMF_CFG5); + udelay(10); + + /* MAC address */ + EFX_POPULATE_OWORD_4(reg, +- GM_HWADDR_5, efx->net_dev->dev_addr[5], +- GM_HWADDR_4, efx->net_dev->dev_addr[4], +- GM_HWADDR_3, efx->net_dev->dev_addr[3], +- GM_HWADDR_2, efx->net_dev->dev_addr[2]); +- falcon_write(efx, ®, GM_ADR1_REG); ++ FRF_AB_GM_ADR_B0, efx->net_dev->dev_addr[5], ++ FRF_AB_GM_ADR_B1, efx->net_dev->dev_addr[4], ++ FRF_AB_GM_ADR_B2, efx->net_dev->dev_addr[3], ++ FRF_AB_GM_ADR_B3, efx->net_dev->dev_addr[2]); ++ efx_writeo(efx, ®, FR_AB_GM_ADR1); + udelay(10); + EFX_POPULATE_OWORD_2(reg, +- GM_HWADDR_1, efx->net_dev->dev_addr[1], +- GM_HWADDR_0, efx->net_dev->dev_addr[0]); +- falcon_write(efx, ®, GM_ADR2_REG); ++ FRF_AB_GM_ADR_B4, efx->net_dev->dev_addr[1], ++ FRF_AB_GM_ADR_B5, efx->net_dev->dev_addr[0]); ++ efx_writeo(efx, ®, FR_AB_GM_ADR2); + udelay(10); + + falcon_reconfigure_mac_wrapper(efx); ++ ++ return 0; + } + + static void falcon_update_stats_gmac(struct efx_nic *efx) +@@ -130,11 +132,6 @@ static void falcon_update_stats_gmac(struct efx_nic *efx) + struct efx_mac_stats *mac_stats = &efx->mac_stats; + unsigned long old_rx_pause, old_tx_pause; + unsigned long new_rx_pause, new_tx_pause; +- int rc; +- +- rc = falcon_dma_stats(efx, GDmaDone_offset); +- if (rc) +- return; + + /* Pause frames are erroneously counted as errors (SFC bug 3269) */ + old_rx_pause = mac_stats->rx_pause; +@@ -221,9 +218,13 @@ static void falcon_update_stats_gmac(struct efx_nic *efx) + mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64; + } + ++static bool falcon_gmac_check_fault(struct efx_nic *efx) ++{ ++ return false; ++} ++ + struct efx_mac_operations falcon_gmac_operations = { + .reconfigure = falcon_reconfigure_gmac, + .update_stats = falcon_update_stats_gmac, +- .irq = efx_port_dummy_op_void, +- .poll = efx_port_dummy_op_void, ++ .check_fault = falcon_gmac_check_fault, + }; +diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h +deleted file mode 100644 +index 2d22611..0000000 +--- a/drivers/net/sfc/falcon_hwdefs.h ++++ /dev/null +@@ -1,1333 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +- +-#ifndef EFX_FALCON_HWDEFS_H +-#define EFX_FALCON_HWDEFS_H +- +-/* +- * Falcon hardware value definitions. +- * Falcon is the internal codename for the SFC4000 controller that is +- * present in SFE400X evaluation boards +- */ +- +-/************************************************************************** +- * +- * Falcon registers +- * +- ************************************************************************** +- */ +- +-/* Address region register */ +-#define ADR_REGION_REG_KER 0x00 +-#define ADR_REGION0_LBN 0 +-#define ADR_REGION0_WIDTH 18 +-#define ADR_REGION1_LBN 32 +-#define ADR_REGION1_WIDTH 18 +-#define ADR_REGION2_LBN 64 +-#define ADR_REGION2_WIDTH 18 +-#define ADR_REGION3_LBN 96 +-#define ADR_REGION3_WIDTH 18 +- +-/* Interrupt enable register */ +-#define INT_EN_REG_KER 0x0010 +-#define KER_INT_KER_LBN 3 +-#define KER_INT_KER_WIDTH 1 +-#define DRV_INT_EN_KER_LBN 0 +-#define DRV_INT_EN_KER_WIDTH 1 +- +-/* Interrupt status address register */ +-#define INT_ADR_REG_KER 0x0030 +-#define NORM_INT_VEC_DIS_KER_LBN 64 +-#define NORM_INT_VEC_DIS_KER_WIDTH 1 +-#define INT_ADR_KER_LBN 0 +-#define INT_ADR_KER_WIDTH EFX_DMA_TYPE_WIDTH(64) /* not 46 for this one */ +- +-/* Interrupt status register (B0 only) */ +-#define INT_ISR0_B0 0x90 +-#define INT_ISR1_B0 0xA0 +- +-/* Interrupt acknowledge register (A0/A1 only) */ +-#define INT_ACK_REG_KER_A1 0x0050 +-#define INT_ACK_DUMMY_DATA_LBN 0 +-#define INT_ACK_DUMMY_DATA_WIDTH 32 +- +-/* Interrupt acknowledge work-around register (A0/A1 only )*/ +-#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070 +- +-/* SPI host command register */ +-#define EE_SPI_HCMD_REG_KER 0x0100 +-#define EE_SPI_HCMD_CMD_EN_LBN 31 +-#define EE_SPI_HCMD_CMD_EN_WIDTH 1 +-#define EE_WR_TIMER_ACTIVE_LBN 28 +-#define EE_WR_TIMER_ACTIVE_WIDTH 1 +-#define EE_SPI_HCMD_SF_SEL_LBN 24 +-#define EE_SPI_HCMD_SF_SEL_WIDTH 1 +-#define EE_SPI_EEPROM 0 +-#define EE_SPI_FLASH 1 +-#define EE_SPI_HCMD_DABCNT_LBN 16 +-#define EE_SPI_HCMD_DABCNT_WIDTH 5 +-#define EE_SPI_HCMD_READ_LBN 15 +-#define EE_SPI_HCMD_READ_WIDTH 1 +-#define EE_SPI_READ 1 +-#define EE_SPI_WRITE 0 +-#define EE_SPI_HCMD_DUBCNT_LBN 12 +-#define EE_SPI_HCMD_DUBCNT_WIDTH 2 +-#define EE_SPI_HCMD_ADBCNT_LBN 8 +-#define EE_SPI_HCMD_ADBCNT_WIDTH 2 +-#define EE_SPI_HCMD_ENC_LBN 0 +-#define EE_SPI_HCMD_ENC_WIDTH 8 +- +-/* SPI host address register */ +-#define EE_SPI_HADR_REG_KER 0x0110 +-#define EE_SPI_HADR_ADR_LBN 0 +-#define EE_SPI_HADR_ADR_WIDTH 24 +- +-/* SPI host data register */ +-#define EE_SPI_HDATA_REG_KER 0x0120 +- +-/* SPI/VPD config register */ +-#define EE_VPD_CFG_REG_KER 0x0140 +-#define EE_VPD_EN_LBN 0 +-#define EE_VPD_EN_WIDTH 1 +-#define EE_VPD_EN_AD9_MODE_LBN 1 +-#define EE_VPD_EN_AD9_MODE_WIDTH 1 +-#define EE_EE_CLOCK_DIV_LBN 112 +-#define EE_EE_CLOCK_DIV_WIDTH 7 +-#define EE_SF_CLOCK_DIV_LBN 120 +-#define EE_SF_CLOCK_DIV_WIDTH 7 +- +-/* PCIE CORE ACCESS REG */ +-#define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68 +-#define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70 +-#define PCIE_CORE_ADDR_ACK_RPL_TIMER 0x700 +-#define PCIE_CORE_ADDR_ACK_FREQ 0x70C +- +-/* NIC status register */ +-#define NIC_STAT_REG 0x0200 +-#define EE_STRAP_EN_LBN 31 +-#define EE_STRAP_EN_WIDTH 1 +-#define EE_STRAP_OVR_LBN 24 +-#define EE_STRAP_OVR_WIDTH 4 +-#define ONCHIP_SRAM_LBN 16 +-#define ONCHIP_SRAM_WIDTH 1 +-#define SF_PRST_LBN 9 +-#define SF_PRST_WIDTH 1 +-#define EE_PRST_LBN 8 +-#define EE_PRST_WIDTH 1 +-#define STRAP_PINS_LBN 0 +-#define STRAP_PINS_WIDTH 3 +-/* These bit definitions are extrapolated from the list of numerical +- * values for STRAP_PINS. +- */ +-#define STRAP_10G_LBN 2 +-#define STRAP_10G_WIDTH 1 +-#define STRAP_PCIE_LBN 0 +-#define STRAP_PCIE_WIDTH 1 +- +-#define BOOTED_USING_NVDEVICE_LBN 3 +-#define BOOTED_USING_NVDEVICE_WIDTH 1 +- +-/* GPIO control register */ +-#define GPIO_CTL_REG_KER 0x0210 +-#define GPIO_USE_NIC_CLK_LBN (30) +-#define GPIO_USE_NIC_CLK_WIDTH (1) +-#define GPIO_OUTPUTS_LBN (16) +-#define GPIO_OUTPUTS_WIDTH (4) +-#define GPIO_INPUTS_LBN (8) +-#define GPIO_DIRECTION_LBN (24) +-#define GPIO_DIRECTION_WIDTH (4) +-#define GPIO_DIRECTION_OUT (1) +-#define GPIO_SRAM_SLEEP (1 << 1) +- +-#define GPIO3_OEN_LBN (GPIO_DIRECTION_LBN + 3) +-#define GPIO3_OEN_WIDTH 1 +-#define GPIO2_OEN_LBN (GPIO_DIRECTION_LBN + 2) +-#define GPIO2_OEN_WIDTH 1 +-#define GPIO1_OEN_LBN (GPIO_DIRECTION_LBN + 1) +-#define GPIO1_OEN_WIDTH 1 +-#define GPIO0_OEN_LBN (GPIO_DIRECTION_LBN + 0) +-#define GPIO0_OEN_WIDTH 1 +- +-#define GPIO3_OUT_LBN (GPIO_OUTPUTS_LBN + 3) +-#define GPIO3_OUT_WIDTH 1 +-#define GPIO2_OUT_LBN (GPIO_OUTPUTS_LBN + 2) +-#define GPIO2_OUT_WIDTH 1 +-#define GPIO1_OUT_LBN (GPIO_OUTPUTS_LBN + 1) +-#define GPIO1_OUT_WIDTH 1 +-#define GPIO0_OUT_LBN (GPIO_OUTPUTS_LBN + 0) +-#define GPIO0_OUT_WIDTH 1 +- +-#define GPIO3_IN_LBN (GPIO_INPUTS_LBN + 3) +-#define GPIO3_IN_WIDTH 1 +-#define GPIO2_IN_WIDTH 1 +-#define GPIO1_IN_WIDTH 1 +-#define GPIO0_IN_LBN (GPIO_INPUTS_LBN + 0) +-#define GPIO0_IN_WIDTH 1 +- +-/* Global control register */ +-#define GLB_CTL_REG_KER 0x0220 +-#define EXT_PHY_RST_CTL_LBN 63 +-#define EXT_PHY_RST_CTL_WIDTH 1 +-#define PCIE_SD_RST_CTL_LBN 61 +-#define PCIE_SD_RST_CTL_WIDTH 1 +- +-#define PCIE_NSTCK_RST_CTL_LBN 58 +-#define PCIE_NSTCK_RST_CTL_WIDTH 1 +-#define PCIE_CORE_RST_CTL_LBN 57 +-#define PCIE_CORE_RST_CTL_WIDTH 1 +-#define EE_RST_CTL_LBN 49 +-#define EE_RST_CTL_WIDTH 1 +-#define RST_XGRX_LBN 24 +-#define RST_XGRX_WIDTH 1 +-#define RST_XGTX_LBN 23 +-#define RST_XGTX_WIDTH 1 +-#define RST_EM_LBN 22 +-#define RST_EM_WIDTH 1 +-#define EXT_PHY_RST_DUR_LBN 1 +-#define EXT_PHY_RST_DUR_WIDTH 3 +-#define SWRST_LBN 0 +-#define SWRST_WIDTH 1 +-#define INCLUDE_IN_RESET 0 +-#define EXCLUDE_FROM_RESET 1 +- +-/* Fatal interrupt register */ +-#define FATAL_INTR_REG_KER 0x0230 +-#define RBUF_OWN_INT_KER_EN_LBN 39 +-#define RBUF_OWN_INT_KER_EN_WIDTH 1 +-#define TBUF_OWN_INT_KER_EN_LBN 38 +-#define TBUF_OWN_INT_KER_EN_WIDTH 1 +-#define ILL_ADR_INT_KER_EN_LBN 33 +-#define ILL_ADR_INT_KER_EN_WIDTH 1 +-#define MEM_PERR_INT_KER_LBN 8 +-#define MEM_PERR_INT_KER_WIDTH 1 +-#define INT_KER_ERROR_LBN 0 +-#define INT_KER_ERROR_WIDTH 12 +- +-#define DP_CTRL_REG 0x250 +-#define FLS_EVQ_ID_LBN 0 +-#define FLS_EVQ_ID_WIDTH 11 +- +-#define MEM_STAT_REG_KER 0x260 +- +-/* Debug probe register */ +-#define DEBUG_BLK_SEL_MISC 7 +-#define DEBUG_BLK_SEL_SERDES 6 +-#define DEBUG_BLK_SEL_EM 5 +-#define DEBUG_BLK_SEL_SR 4 +-#define DEBUG_BLK_SEL_EV 3 +-#define DEBUG_BLK_SEL_RX 2 +-#define DEBUG_BLK_SEL_TX 1 +-#define DEBUG_BLK_SEL_BIU 0 +- +-/* FPGA build version */ +-#define ALTERA_BUILD_REG_KER 0x0300 +-#define VER_ALL_LBN 0 +-#define VER_ALL_WIDTH 32 +- +-/* Spare EEPROM bits register (flash 0x390) */ +-#define SPARE_REG_KER 0x310 +-#define MEM_PERR_EN_TX_DATA_LBN 72 +-#define MEM_PERR_EN_TX_DATA_WIDTH 2 +- +-/* Timer table for kernel access */ +-#define TIMER_CMD_REG_KER 0x420 +-#define TIMER_MODE_LBN 12 +-#define TIMER_MODE_WIDTH 2 +-#define TIMER_MODE_DIS 0 +-#define TIMER_MODE_INT_HLDOFF 2 +-#define TIMER_VAL_LBN 0 +-#define TIMER_VAL_WIDTH 12 +- +-/* Driver generated event register */ +-#define DRV_EV_REG_KER 0x440 +-#define DRV_EV_QID_LBN 64 +-#define DRV_EV_QID_WIDTH 12 +-#define DRV_EV_DATA_LBN 0 +-#define DRV_EV_DATA_WIDTH 64 +- +-/* Buffer table configuration register */ +-#define BUF_TBL_CFG_REG_KER 0x600 +-#define BUF_TBL_MODE_LBN 3 +-#define BUF_TBL_MODE_WIDTH 1 +-#define BUF_TBL_MODE_HALF 0 +-#define BUF_TBL_MODE_FULL 1 +- +-/* SRAM receive descriptor cache configuration register */ +-#define SRM_RX_DC_CFG_REG_KER 0x610 +-#define SRM_RX_DC_BASE_ADR_LBN 0 +-#define SRM_RX_DC_BASE_ADR_WIDTH 21 +- +-/* SRAM transmit descriptor cache configuration register */ +-#define SRM_TX_DC_CFG_REG_KER 0x620 +-#define SRM_TX_DC_BASE_ADR_LBN 0 +-#define SRM_TX_DC_BASE_ADR_WIDTH 21 +- +-/* SRAM configuration register */ +-#define SRM_CFG_REG_KER 0x630 +-#define SRAM_OOB_BT_INIT_EN_LBN 3 +-#define SRAM_OOB_BT_INIT_EN_WIDTH 1 +-#define SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0 +-#define SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3 +-#define SRM_NB_BSZ_1BANKS_2M 0 +-#define SRM_NB_BSZ_1BANKS_4M 1 +-#define SRM_NB_BSZ_1BANKS_8M 2 +-#define SRM_NB_BSZ_DEFAULT 3 /* char driver will set the default */ +-#define SRM_NB_BSZ_2BANKS_4M 4 +-#define SRM_NB_BSZ_2BANKS_8M 5 +-#define SRM_NB_BSZ_2BANKS_16M 6 +-#define SRM_NB_BSZ_RESERVED 7 +- +-/* Special buffer table update register */ +-#define BUF_TBL_UPD_REG_KER 0x0650 +-#define BUF_UPD_CMD_LBN 63 +-#define BUF_UPD_CMD_WIDTH 1 +-#define BUF_CLR_CMD_LBN 62 +-#define BUF_CLR_CMD_WIDTH 1 +-#define BUF_CLR_END_ID_LBN 32 +-#define BUF_CLR_END_ID_WIDTH 20 +-#define BUF_CLR_START_ID_LBN 0 +-#define BUF_CLR_START_ID_WIDTH 20 +- +-/* Receive configuration register */ +-#define RX_CFG_REG_KER 0x800 +- +-/* B0 */ +-#define RX_INGR_EN_B0_LBN 47 +-#define RX_INGR_EN_B0_WIDTH 1 +-#define RX_DESC_PUSH_EN_B0_LBN 43 +-#define RX_DESC_PUSH_EN_B0_WIDTH 1 +-#define RX_XON_TX_TH_B0_LBN 33 +-#define RX_XON_TX_TH_B0_WIDTH 5 +-#define RX_XOFF_TX_TH_B0_LBN 28 +-#define RX_XOFF_TX_TH_B0_WIDTH 5 +-#define RX_USR_BUF_SIZE_B0_LBN 19 +-#define RX_USR_BUF_SIZE_B0_WIDTH 9 +-#define RX_XON_MAC_TH_B0_LBN 10 +-#define RX_XON_MAC_TH_B0_WIDTH 9 +-#define RX_XOFF_MAC_TH_B0_LBN 1 +-#define RX_XOFF_MAC_TH_B0_WIDTH 9 +-#define RX_XOFF_MAC_EN_B0_LBN 0 +-#define RX_XOFF_MAC_EN_B0_WIDTH 1 +- +-/* A1 */ +-#define RX_DESC_PUSH_EN_A1_LBN 35 +-#define RX_DESC_PUSH_EN_A1_WIDTH 1 +-#define RX_XON_TX_TH_A1_LBN 25 +-#define RX_XON_TX_TH_A1_WIDTH 5 +-#define RX_XOFF_TX_TH_A1_LBN 20 +-#define RX_XOFF_TX_TH_A1_WIDTH 5 +-#define RX_USR_BUF_SIZE_A1_LBN 11 +-#define RX_USR_BUF_SIZE_A1_WIDTH 9 +-#define RX_XON_MAC_TH_A1_LBN 6 +-#define RX_XON_MAC_TH_A1_WIDTH 5 +-#define RX_XOFF_MAC_TH_A1_LBN 1 +-#define RX_XOFF_MAC_TH_A1_WIDTH 5 +-#define RX_XOFF_MAC_EN_A1_LBN 0 +-#define RX_XOFF_MAC_EN_A1_WIDTH 1 +- +-/* Receive filter control register */ +-#define RX_FILTER_CTL_REG 0x810 +-#define UDP_FULL_SRCH_LIMIT_LBN 32 +-#define UDP_FULL_SRCH_LIMIT_WIDTH 8 +-#define NUM_KER_LBN 24 +-#define NUM_KER_WIDTH 2 +-#define UDP_WILD_SRCH_LIMIT_LBN 16 +-#define UDP_WILD_SRCH_LIMIT_WIDTH 8 +-#define TCP_WILD_SRCH_LIMIT_LBN 8 +-#define TCP_WILD_SRCH_LIMIT_WIDTH 8 +-#define TCP_FULL_SRCH_LIMIT_LBN 0 +-#define TCP_FULL_SRCH_LIMIT_WIDTH 8 +- +-/* RX queue flush register */ +-#define RX_FLUSH_DESCQ_REG_KER 0x0820 +-#define RX_FLUSH_DESCQ_CMD_LBN 24 +-#define RX_FLUSH_DESCQ_CMD_WIDTH 1 +-#define RX_FLUSH_DESCQ_LBN 0 +-#define RX_FLUSH_DESCQ_WIDTH 12 +- +-/* Receive descriptor update register */ +-#define RX_DESC_UPD_REG_KER_DWORD (0x830 + 12) +-#define RX_DESC_WPTR_DWORD_LBN 0 +-#define RX_DESC_WPTR_DWORD_WIDTH 12 +- +-/* Receive descriptor cache configuration register */ +-#define RX_DC_CFG_REG_KER 0x840 +-#define RX_DC_SIZE_LBN 0 +-#define RX_DC_SIZE_WIDTH 2 +- +-#define RX_DC_PF_WM_REG_KER 0x850 +-#define RX_DC_PF_LWM_LBN 0 +-#define RX_DC_PF_LWM_WIDTH 6 +- +-/* RX no descriptor drop counter */ +-#define RX_NODESC_DROP_REG_KER 0x880 +-#define RX_NODESC_DROP_CNT_LBN 0 +-#define RX_NODESC_DROP_CNT_WIDTH 16 +- +-/* RX black magic register */ +-#define RX_SELF_RST_REG_KER 0x890 +-#define RX_ISCSI_DIS_LBN 17 +-#define RX_ISCSI_DIS_WIDTH 1 +-#define RX_NODESC_WAIT_DIS_LBN 9 +-#define RX_NODESC_WAIT_DIS_WIDTH 1 +-#define RX_RECOVERY_EN_LBN 8 +-#define RX_RECOVERY_EN_WIDTH 1 +- +-/* TX queue flush register */ +-#define TX_FLUSH_DESCQ_REG_KER 0x0a00 +-#define TX_FLUSH_DESCQ_CMD_LBN 12 +-#define TX_FLUSH_DESCQ_CMD_WIDTH 1 +-#define TX_FLUSH_DESCQ_LBN 0 +-#define TX_FLUSH_DESCQ_WIDTH 12 +- +-/* Transmit descriptor update register */ +-#define TX_DESC_UPD_REG_KER_DWORD (0xa10 + 12) +-#define TX_DESC_WPTR_DWORD_LBN 0 +-#define TX_DESC_WPTR_DWORD_WIDTH 12 +- +-/* Transmit descriptor cache configuration register */ +-#define TX_DC_CFG_REG_KER 0xa20 +-#define TX_DC_SIZE_LBN 0 +-#define TX_DC_SIZE_WIDTH 2 +- +-/* Transmit checksum configuration register (A0/A1 only) */ +-#define TX_CHKSM_CFG_REG_KER_A1 0xa30 +- +-/* Transmit configuration register */ +-#define TX_CFG_REG_KER 0xa50 +-#define TX_NO_EOP_DISC_EN_LBN 5 +-#define TX_NO_EOP_DISC_EN_WIDTH 1 +- +-/* Transmit configuration register 2 */ +-#define TX_CFG2_REG_KER 0xa80 +-#define TX_CSR_PUSH_EN_LBN 89 +-#define TX_CSR_PUSH_EN_WIDTH 1 +-#define TX_RX_SPACER_LBN 64 +-#define TX_RX_SPACER_WIDTH 8 +-#define TX_SW_EV_EN_LBN 59 +-#define TX_SW_EV_EN_WIDTH 1 +-#define TX_RX_SPACER_EN_LBN 57 +-#define TX_RX_SPACER_EN_WIDTH 1 +-#define TX_PREF_THRESHOLD_LBN 19 +-#define TX_PREF_THRESHOLD_WIDTH 2 +-#define TX_ONE_PKT_PER_Q_LBN 18 +-#define TX_ONE_PKT_PER_Q_WIDTH 1 +-#define TX_DIS_NON_IP_EV_LBN 17 +-#define TX_DIS_NON_IP_EV_WIDTH 1 +-#define TX_FLUSH_MIN_LEN_EN_B0_LBN 7 +-#define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1 +- +-/* PHY management transmit data register */ +-#define MD_TXD_REG_KER 0xc00 +-#define MD_TXD_LBN 0 +-#define MD_TXD_WIDTH 16 +- +-/* PHY management receive data register */ +-#define MD_RXD_REG_KER 0xc10 +-#define MD_RXD_LBN 0 +-#define MD_RXD_WIDTH 16 +- +-/* PHY management configuration & status register */ +-#define MD_CS_REG_KER 0xc20 +-#define MD_GC_LBN 4 +-#define MD_GC_WIDTH 1 +-#define MD_RIC_LBN 2 +-#define MD_RIC_WIDTH 1 +-#define MD_RDC_LBN 1 +-#define MD_RDC_WIDTH 1 +-#define MD_WRC_LBN 0 +-#define MD_WRC_WIDTH 1 +- +-/* PHY management PHY address register */ +-#define MD_PHY_ADR_REG_KER 0xc30 +-#define MD_PHY_ADR_LBN 0 +-#define MD_PHY_ADR_WIDTH 16 +- +-/* PHY management ID register */ +-#define MD_ID_REG_KER 0xc40 +-#define MD_PRT_ADR_LBN 11 +-#define MD_PRT_ADR_WIDTH 5 +-#define MD_DEV_ADR_LBN 6 +-#define MD_DEV_ADR_WIDTH 5 +- +-/* PHY management status & mask register (DWORD read only) */ +-#define MD_STAT_REG_KER 0xc50 +-#define MD_BSERR_LBN 2 +-#define MD_BSERR_WIDTH 1 +-#define MD_LNFL_LBN 1 +-#define MD_LNFL_WIDTH 1 +-#define MD_BSY_LBN 0 +-#define MD_BSY_WIDTH 1 +- +-/* Port 0 and 1 MAC stats registers */ +-#define MAC0_STAT_DMA_REG_KER 0xc60 +-#define MAC_STAT_DMA_CMD_LBN 48 +-#define MAC_STAT_DMA_CMD_WIDTH 1 +-#define MAC_STAT_DMA_ADR_LBN 0 +-#define MAC_STAT_DMA_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46) +- +-/* Port 0 and 1 MAC control registers */ +-#define MAC0_CTRL_REG_KER 0xc80 +-#define MAC_XOFF_VAL_LBN 16 +-#define MAC_XOFF_VAL_WIDTH 16 +-#define TXFIFO_DRAIN_EN_B0_LBN 7 +-#define TXFIFO_DRAIN_EN_B0_WIDTH 1 +-#define MAC_BCAD_ACPT_LBN 4 +-#define MAC_BCAD_ACPT_WIDTH 1 +-#define MAC_UC_PROM_LBN 3 +-#define MAC_UC_PROM_WIDTH 1 +-#define MAC_LINK_STATUS_LBN 2 +-#define MAC_LINK_STATUS_WIDTH 1 +-#define MAC_SPEED_LBN 0 +-#define MAC_SPEED_WIDTH 2 +- +-/* 10G XAUI XGXS default values */ +-#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */ +-#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */ +-#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */ +- +-/* Multicast address hash table */ +-#define MAC_MCAST_HASH_REG0_KER 0xca0 +-#define MAC_MCAST_HASH_REG1_KER 0xcb0 +- +-/* GMAC configuration register 1 */ +-#define GM_CFG1_REG 0xe00 +-#define GM_SW_RST_LBN 31 +-#define GM_SW_RST_WIDTH 1 +-#define GM_LOOP_LBN 8 +-#define GM_LOOP_WIDTH 1 +-#define GM_RX_FC_EN_LBN 5 +-#define GM_RX_FC_EN_WIDTH 1 +-#define GM_TX_FC_EN_LBN 4 +-#define GM_TX_FC_EN_WIDTH 1 +-#define GM_RX_EN_LBN 2 +-#define GM_RX_EN_WIDTH 1 +-#define GM_TX_EN_LBN 0 +-#define GM_TX_EN_WIDTH 1 +- +-/* GMAC configuration register 2 */ +-#define GM_CFG2_REG 0xe10 +-#define GM_PAMBL_LEN_LBN 12 +-#define GM_PAMBL_LEN_WIDTH 4 +-#define GM_IF_MODE_LBN 8 +-#define GM_IF_MODE_WIDTH 2 +-#define GM_LEN_CHK_LBN 4 +-#define GM_LEN_CHK_WIDTH 1 +-#define GM_PAD_CRC_EN_LBN 2 +-#define GM_PAD_CRC_EN_WIDTH 1 +-#define GM_FD_LBN 0 +-#define GM_FD_WIDTH 1 +- +-/* GMAC maximum frame length register */ +-#define GM_MAX_FLEN_REG 0xe40 +-#define GM_MAX_FLEN_LBN 0 +-#define GM_MAX_FLEN_WIDTH 16 +- +-/* GMAC station address register 1 */ +-#define GM_ADR1_REG 0xf00 +-#define GM_HWADDR_5_LBN 24 +-#define GM_HWADDR_5_WIDTH 8 +-#define GM_HWADDR_4_LBN 16 +-#define GM_HWADDR_4_WIDTH 8 +-#define GM_HWADDR_3_LBN 8 +-#define GM_HWADDR_3_WIDTH 8 +-#define GM_HWADDR_2_LBN 0 +-#define GM_HWADDR_2_WIDTH 8 +- +-/* GMAC station address register 2 */ +-#define GM_ADR2_REG 0xf10 +-#define GM_HWADDR_1_LBN 24 +-#define GM_HWADDR_1_WIDTH 8 +-#define GM_HWADDR_0_LBN 16 +-#define GM_HWADDR_0_WIDTH 8 +- +-/* GMAC FIFO configuration register 0 */ +-#define GMF_CFG0_REG 0xf20 +-#define GMF_FTFENREQ_LBN 12 +-#define GMF_FTFENREQ_WIDTH 1 +-#define GMF_STFENREQ_LBN 11 +-#define GMF_STFENREQ_WIDTH 1 +-#define GMF_FRFENREQ_LBN 10 +-#define GMF_FRFENREQ_WIDTH 1 +-#define GMF_SRFENREQ_LBN 9 +-#define GMF_SRFENREQ_WIDTH 1 +-#define GMF_WTMENREQ_LBN 8 +-#define GMF_WTMENREQ_WIDTH 1 +- +-/* GMAC FIFO configuration register 1 */ +-#define GMF_CFG1_REG 0xf30 +-#define GMF_CFGFRTH_LBN 16 +-#define GMF_CFGFRTH_WIDTH 5 +-#define GMF_CFGXOFFRTX_LBN 0 +-#define GMF_CFGXOFFRTX_WIDTH 16 +- +-/* GMAC FIFO configuration register 2 */ +-#define GMF_CFG2_REG 0xf40 +-#define GMF_CFGHWM_LBN 16 +-#define GMF_CFGHWM_WIDTH 6 +-#define GMF_CFGLWM_LBN 0 +-#define GMF_CFGLWM_WIDTH 6 +- +-/* GMAC FIFO configuration register 3 */ +-#define GMF_CFG3_REG 0xf50 +-#define GMF_CFGHWMFT_LBN 16 +-#define GMF_CFGHWMFT_WIDTH 6 +-#define GMF_CFGFTTH_LBN 0 +-#define GMF_CFGFTTH_WIDTH 6 +- +-/* GMAC FIFO configuration register 4 */ +-#define GMF_CFG4_REG 0xf60 +-#define GMF_HSTFLTRFRM_PAUSE_LBN 12 +-#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12 +- +-/* GMAC FIFO configuration register 5 */ +-#define GMF_CFG5_REG 0xf70 +-#define GMF_CFGHDPLX_LBN 22 +-#define GMF_CFGHDPLX_WIDTH 1 +-#define GMF_CFGBYTMODE_LBN 19 +-#define GMF_CFGBYTMODE_WIDTH 1 +-#define GMF_HSTDRPLT64_LBN 18 +-#define GMF_HSTDRPLT64_WIDTH 1 +-#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12 +-#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1 +- +-/* XGMAC address register low */ +-#define XM_ADR_LO_REG 0x1200 +-#define XM_ADR_3_LBN 24 +-#define XM_ADR_3_WIDTH 8 +-#define XM_ADR_2_LBN 16 +-#define XM_ADR_2_WIDTH 8 +-#define XM_ADR_1_LBN 8 +-#define XM_ADR_1_WIDTH 8 +-#define XM_ADR_0_LBN 0 +-#define XM_ADR_0_WIDTH 8 +- +-/* XGMAC address register high */ +-#define XM_ADR_HI_REG 0x1210 +-#define XM_ADR_5_LBN 8 +-#define XM_ADR_5_WIDTH 8 +-#define XM_ADR_4_LBN 0 +-#define XM_ADR_4_WIDTH 8 +- +-/* XGMAC global configuration */ +-#define XM_GLB_CFG_REG 0x1220 +-#define XM_RX_STAT_EN_LBN 11 +-#define XM_RX_STAT_EN_WIDTH 1 +-#define XM_TX_STAT_EN_LBN 10 +-#define XM_TX_STAT_EN_WIDTH 1 +-#define XM_RX_JUMBO_MODE_LBN 6 +-#define XM_RX_JUMBO_MODE_WIDTH 1 +-#define XM_INTCLR_MODE_LBN 3 +-#define XM_INTCLR_MODE_WIDTH 1 +-#define XM_CORE_RST_LBN 0 +-#define XM_CORE_RST_WIDTH 1 +- +-/* XGMAC transmit configuration */ +-#define XM_TX_CFG_REG 0x1230 +-#define XM_IPG_LBN 16 +-#define XM_IPG_WIDTH 4 +-#define XM_FCNTL_LBN 10 +-#define XM_FCNTL_WIDTH 1 +-#define XM_TXCRC_LBN 8 +-#define XM_TXCRC_WIDTH 1 +-#define XM_AUTO_PAD_LBN 5 +-#define XM_AUTO_PAD_WIDTH 1 +-#define XM_TX_PRMBL_LBN 2 +-#define XM_TX_PRMBL_WIDTH 1 +-#define XM_TXEN_LBN 1 +-#define XM_TXEN_WIDTH 1 +- +-/* XGMAC receive configuration */ +-#define XM_RX_CFG_REG 0x1240 +-#define XM_PASS_CRC_ERR_LBN 25 +-#define XM_PASS_CRC_ERR_WIDTH 1 +-#define XM_ACPT_ALL_MCAST_LBN 11 +-#define XM_ACPT_ALL_MCAST_WIDTH 1 +-#define XM_ACPT_ALL_UCAST_LBN 9 +-#define XM_ACPT_ALL_UCAST_WIDTH 1 +-#define XM_AUTO_DEPAD_LBN 8 +-#define XM_AUTO_DEPAD_WIDTH 1 +-#define XM_RXEN_LBN 1 +-#define XM_RXEN_WIDTH 1 +- +-/* XGMAC management interrupt mask register */ +-#define XM_MGT_INT_MSK_REG_B0 0x1250 +-#define XM_MSK_PRMBLE_ERR_LBN 2 +-#define XM_MSK_PRMBLE_ERR_WIDTH 1 +-#define XM_MSK_RMTFLT_LBN 1 +-#define XM_MSK_RMTFLT_WIDTH 1 +-#define XM_MSK_LCLFLT_LBN 0 +-#define XM_MSK_LCLFLT_WIDTH 1 +- +-/* XGMAC flow control register */ +-#define XM_FC_REG 0x1270 +-#define XM_PAUSE_TIME_LBN 16 +-#define XM_PAUSE_TIME_WIDTH 16 +-#define XM_DIS_FCNTL_LBN 0 +-#define XM_DIS_FCNTL_WIDTH 1 +- +-/* XGMAC pause time count register */ +-#define XM_PAUSE_TIME_REG 0x1290 +- +-/* XGMAC transmit parameter register */ +-#define XM_TX_PARAM_REG 0x012d0 +-#define XM_TX_JUMBO_MODE_LBN 31 +-#define XM_TX_JUMBO_MODE_WIDTH 1 +-#define XM_MAX_TX_FRM_SIZE_LBN 16 +-#define XM_MAX_TX_FRM_SIZE_WIDTH 14 +- +-/* XGMAC receive parameter register */ +-#define XM_RX_PARAM_REG 0x12e0 +-#define XM_MAX_RX_FRM_SIZE_LBN 0 +-#define XM_MAX_RX_FRM_SIZE_WIDTH 14 +- +-/* XGMAC management interrupt status register */ +-#define XM_MGT_INT_REG_B0 0x12f0 +-#define XM_PRMBLE_ERR 2 +-#define XM_PRMBLE_WIDTH 1 +-#define XM_RMTFLT_LBN 1 +-#define XM_RMTFLT_WIDTH 1 +-#define XM_LCLFLT_LBN 0 +-#define XM_LCLFLT_WIDTH 1 +- +-/* XGXS/XAUI powerdown/reset register */ +-#define XX_PWR_RST_REG 0x1300 +- +-#define XX_SD_RST_ACT_LBN 16 +-#define XX_SD_RST_ACT_WIDTH 1 +-#define XX_PWRDND_EN_LBN 15 +-#define XX_PWRDND_EN_WIDTH 1 +-#define XX_PWRDNC_EN_LBN 14 +-#define XX_PWRDNC_EN_WIDTH 1 +-#define XX_PWRDNB_EN_LBN 13 +-#define XX_PWRDNB_EN_WIDTH 1 +-#define XX_PWRDNA_EN_LBN 12 +-#define XX_PWRDNA_EN_WIDTH 1 +-#define XX_RSTPLLCD_EN_LBN 9 +-#define XX_RSTPLLCD_EN_WIDTH 1 +-#define XX_RSTPLLAB_EN_LBN 8 +-#define XX_RSTPLLAB_EN_WIDTH 1 +-#define XX_RESETD_EN_LBN 7 +-#define XX_RESETD_EN_WIDTH 1 +-#define XX_RESETC_EN_LBN 6 +-#define XX_RESETC_EN_WIDTH 1 +-#define XX_RESETB_EN_LBN 5 +-#define XX_RESETB_EN_WIDTH 1 +-#define XX_RESETA_EN_LBN 4 +-#define XX_RESETA_EN_WIDTH 1 +-#define XX_RSTXGXSRX_EN_LBN 2 +-#define XX_RSTXGXSRX_EN_WIDTH 1 +-#define XX_RSTXGXSTX_EN_LBN 1 +-#define XX_RSTXGXSTX_EN_WIDTH 1 +-#define XX_RST_XX_EN_LBN 0 +-#define XX_RST_XX_EN_WIDTH 1 +- +-/* XGXS/XAUI powerdown/reset control register */ +-#define XX_SD_CTL_REG 0x1310 +-#define XX_HIDRVD_LBN 15 +-#define XX_HIDRVD_WIDTH 1 +-#define XX_LODRVD_LBN 14 +-#define XX_LODRVD_WIDTH 1 +-#define XX_HIDRVC_LBN 13 +-#define XX_HIDRVC_WIDTH 1 +-#define XX_LODRVC_LBN 12 +-#define XX_LODRVC_WIDTH 1 +-#define XX_HIDRVB_LBN 11 +-#define XX_HIDRVB_WIDTH 1 +-#define XX_LODRVB_LBN 10 +-#define XX_LODRVB_WIDTH 1 +-#define XX_HIDRVA_LBN 9 +-#define XX_HIDRVA_WIDTH 1 +-#define XX_LODRVA_LBN 8 +-#define XX_LODRVA_WIDTH 1 +-#define XX_LPBKD_LBN 3 +-#define XX_LPBKD_WIDTH 1 +-#define XX_LPBKC_LBN 2 +-#define XX_LPBKC_WIDTH 1 +-#define XX_LPBKB_LBN 1 +-#define XX_LPBKB_WIDTH 1 +-#define XX_LPBKA_LBN 0 +-#define XX_LPBKA_WIDTH 1 +- +-#define XX_TXDRV_CTL_REG 0x1320 +-#define XX_DEQD_LBN 28 +-#define XX_DEQD_WIDTH 4 +-#define XX_DEQC_LBN 24 +-#define XX_DEQC_WIDTH 4 +-#define XX_DEQB_LBN 20 +-#define XX_DEQB_WIDTH 4 +-#define XX_DEQA_LBN 16 +-#define XX_DEQA_WIDTH 4 +-#define XX_DTXD_LBN 12 +-#define XX_DTXD_WIDTH 4 +-#define XX_DTXC_LBN 8 +-#define XX_DTXC_WIDTH 4 +-#define XX_DTXB_LBN 4 +-#define XX_DTXB_WIDTH 4 +-#define XX_DTXA_LBN 0 +-#define XX_DTXA_WIDTH 4 +- +-/* XAUI XGXS core status register */ +-#define XX_CORE_STAT_REG 0x1360 +-#define XX_FORCE_SIG_LBN 24 +-#define XX_FORCE_SIG_WIDTH 8 +-#define XX_FORCE_SIG_DECODE_FORCED 0xff +-#define XX_XGXS_LB_EN_LBN 23 +-#define XX_XGXS_LB_EN_WIDTH 1 +-#define XX_XGMII_LB_EN_LBN 22 +-#define XX_XGMII_LB_EN_WIDTH 1 +-#define XX_ALIGN_DONE_LBN 20 +-#define XX_ALIGN_DONE_WIDTH 1 +-#define XX_SYNC_STAT_LBN 16 +-#define XX_SYNC_STAT_WIDTH 4 +-#define XX_SYNC_STAT_DECODE_SYNCED 0xf +-#define XX_COMMA_DET_LBN 12 +-#define XX_COMMA_DET_WIDTH 4 +-#define XX_COMMA_DET_DECODE_DETECTED 0xf +-#define XX_COMMA_DET_RESET 0xf +-#define XX_CHARERR_LBN 4 +-#define XX_CHARERR_WIDTH 4 +-#define XX_CHARERR_RESET 0xf +-#define XX_DISPERR_LBN 0 +-#define XX_DISPERR_WIDTH 4 +-#define XX_DISPERR_RESET 0xf +- +-/* Receive filter table */ +-#define RX_FILTER_TBL0 0xF00000 +- +-/* Receive descriptor pointer table */ +-#define RX_DESC_PTR_TBL_KER_A1 0x11800 +-#define RX_DESC_PTR_TBL_KER_B0 0xF40000 +-#define RX_DESC_PTR_TBL_KER_P0 0x900 +-#define RX_ISCSI_DDIG_EN_LBN 88 +-#define RX_ISCSI_DDIG_EN_WIDTH 1 +-#define RX_ISCSI_HDIG_EN_LBN 87 +-#define RX_ISCSI_HDIG_EN_WIDTH 1 +-#define RX_DESCQ_BUF_BASE_ID_LBN 36 +-#define RX_DESCQ_BUF_BASE_ID_WIDTH 20 +-#define RX_DESCQ_EVQ_ID_LBN 24 +-#define RX_DESCQ_EVQ_ID_WIDTH 12 +-#define RX_DESCQ_OWNER_ID_LBN 10 +-#define RX_DESCQ_OWNER_ID_WIDTH 14 +-#define RX_DESCQ_LABEL_LBN 5 +-#define RX_DESCQ_LABEL_WIDTH 5 +-#define RX_DESCQ_SIZE_LBN 3 +-#define RX_DESCQ_SIZE_WIDTH 2 +-#define RX_DESCQ_SIZE_4K 3 +-#define RX_DESCQ_SIZE_2K 2 +-#define RX_DESCQ_SIZE_1K 1 +-#define RX_DESCQ_SIZE_512 0 +-#define RX_DESCQ_TYPE_LBN 2 +-#define RX_DESCQ_TYPE_WIDTH 1 +-#define RX_DESCQ_JUMBO_LBN 1 +-#define RX_DESCQ_JUMBO_WIDTH 1 +-#define RX_DESCQ_EN_LBN 0 +-#define RX_DESCQ_EN_WIDTH 1 +- +-/* Transmit descriptor pointer table */ +-#define TX_DESC_PTR_TBL_KER_A1 0x11900 +-#define TX_DESC_PTR_TBL_KER_B0 0xF50000 +-#define TX_DESC_PTR_TBL_KER_P0 0xa40 +-#define TX_NON_IP_DROP_DIS_B0_LBN 91 +-#define TX_NON_IP_DROP_DIS_B0_WIDTH 1 +-#define TX_IP_CHKSM_DIS_B0_LBN 90 +-#define TX_IP_CHKSM_DIS_B0_WIDTH 1 +-#define TX_TCP_CHKSM_DIS_B0_LBN 89 +-#define TX_TCP_CHKSM_DIS_B0_WIDTH 1 +-#define TX_DESCQ_EN_LBN 88 +-#define TX_DESCQ_EN_WIDTH 1 +-#define TX_ISCSI_DDIG_EN_LBN 87 +-#define TX_ISCSI_DDIG_EN_WIDTH 1 +-#define TX_ISCSI_HDIG_EN_LBN 86 +-#define TX_ISCSI_HDIG_EN_WIDTH 1 +-#define TX_DESCQ_BUF_BASE_ID_LBN 36 +-#define TX_DESCQ_BUF_BASE_ID_WIDTH 20 +-#define TX_DESCQ_EVQ_ID_LBN 24 +-#define TX_DESCQ_EVQ_ID_WIDTH 12 +-#define TX_DESCQ_OWNER_ID_LBN 10 +-#define TX_DESCQ_OWNER_ID_WIDTH 14 +-#define TX_DESCQ_LABEL_LBN 5 +-#define TX_DESCQ_LABEL_WIDTH 5 +-#define TX_DESCQ_SIZE_LBN 3 +-#define TX_DESCQ_SIZE_WIDTH 2 +-#define TX_DESCQ_SIZE_4K 3 +-#define TX_DESCQ_SIZE_2K 2 +-#define TX_DESCQ_SIZE_1K 1 +-#define TX_DESCQ_SIZE_512 0 +-#define TX_DESCQ_TYPE_LBN 1 +-#define TX_DESCQ_TYPE_WIDTH 2 +- +-/* Event queue pointer */ +-#define EVQ_PTR_TBL_KER_A1 0x11a00 +-#define EVQ_PTR_TBL_KER_B0 0xf60000 +-#define EVQ_PTR_TBL_KER_P0 0x500 +-#define EVQ_EN_LBN 23 +-#define EVQ_EN_WIDTH 1 +-#define EVQ_SIZE_LBN 20 +-#define EVQ_SIZE_WIDTH 3 +-#define EVQ_SIZE_32K 6 +-#define EVQ_SIZE_16K 5 +-#define EVQ_SIZE_8K 4 +-#define EVQ_SIZE_4K 3 +-#define EVQ_SIZE_2K 2 +-#define EVQ_SIZE_1K 1 +-#define EVQ_SIZE_512 0 +-#define EVQ_BUF_BASE_ID_LBN 0 +-#define EVQ_BUF_BASE_ID_WIDTH 20 +- +-/* Event queue read pointer */ +-#define EVQ_RPTR_REG_KER_A1 0x11b00 +-#define EVQ_RPTR_REG_KER_B0 0xfa0000 +-#define EVQ_RPTR_REG_KER_DWORD (EVQ_RPTR_REG_KER + 0) +-#define EVQ_RPTR_DWORD_LBN 0 +-#define EVQ_RPTR_DWORD_WIDTH 14 +- +-/* RSS indirection table */ +-#define RX_RSS_INDIR_TBL_B0 0xFB0000 +-#define RX_RSS_INDIR_ENT_B0_LBN 0 +-#define RX_RSS_INDIR_ENT_B0_WIDTH 6 +- +-/* Special buffer descriptors (full-mode) */ +-#define BUF_FULL_TBL_KER_A1 0x8000 +-#define BUF_FULL_TBL_KER_B0 0x800000 +-#define IP_DAT_BUF_SIZE_LBN 50 +-#define IP_DAT_BUF_SIZE_WIDTH 1 +-#define IP_DAT_BUF_SIZE_8K 1 +-#define IP_DAT_BUF_SIZE_4K 0 +-#define BUF_ADR_REGION_LBN 48 +-#define BUF_ADR_REGION_WIDTH 2 +-#define BUF_ADR_FBUF_LBN 14 +-#define BUF_ADR_FBUF_WIDTH 34 +-#define BUF_OWNER_ID_FBUF_LBN 0 +-#define BUF_OWNER_ID_FBUF_WIDTH 14 +- +-/* Transmit descriptor */ +-#define TX_KER_PORT_LBN 63 +-#define TX_KER_PORT_WIDTH 1 +-#define TX_KER_CONT_LBN 62 +-#define TX_KER_CONT_WIDTH 1 +-#define TX_KER_BYTE_CNT_LBN 48 +-#define TX_KER_BYTE_CNT_WIDTH 14 +-#define TX_KER_BUF_REGION_LBN 46 +-#define TX_KER_BUF_REGION_WIDTH 2 +-#define TX_KER_BUF_REGION0_DECODE 0 +-#define TX_KER_BUF_REGION1_DECODE 1 +-#define TX_KER_BUF_REGION2_DECODE 2 +-#define TX_KER_BUF_REGION3_DECODE 3 +-#define TX_KER_BUF_ADR_LBN 0 +-#define TX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46) +- +-/* Receive descriptor */ +-#define RX_KER_BUF_SIZE_LBN 48 +-#define RX_KER_BUF_SIZE_WIDTH 14 +-#define RX_KER_BUF_REGION_LBN 46 +-#define RX_KER_BUF_REGION_WIDTH 2 +-#define RX_KER_BUF_REGION0_DECODE 0 +-#define RX_KER_BUF_REGION1_DECODE 1 +-#define RX_KER_BUF_REGION2_DECODE 2 +-#define RX_KER_BUF_REGION3_DECODE 3 +-#define RX_KER_BUF_ADR_LBN 0 +-#define RX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46) +- +-/************************************************************************** +- * +- * Falcon events +- * +- ************************************************************************** +- */ +- +-/* Event queue entries */ +-#define EV_CODE_LBN 60 +-#define EV_CODE_WIDTH 4 +-#define RX_IP_EV_DECODE 0 +-#define TX_IP_EV_DECODE 2 +-#define DRIVER_EV_DECODE 5 +-#define GLOBAL_EV_DECODE 6 +-#define DRV_GEN_EV_DECODE 7 +-#define WHOLE_EVENT_LBN 0 +-#define WHOLE_EVENT_WIDTH 64 +- +-/* Receive events */ +-#define RX_EV_PKT_OK_LBN 56 +-#define RX_EV_PKT_OK_WIDTH 1 +-#define RX_EV_PAUSE_FRM_ERR_LBN 55 +-#define RX_EV_PAUSE_FRM_ERR_WIDTH 1 +-#define RX_EV_BUF_OWNER_ID_ERR_LBN 54 +-#define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1 +-#define RX_EV_IF_FRAG_ERR_LBN 53 +-#define RX_EV_IF_FRAG_ERR_WIDTH 1 +-#define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52 +-#define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1 +-#define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51 +-#define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1 +-#define RX_EV_ETH_CRC_ERR_LBN 50 +-#define RX_EV_ETH_CRC_ERR_WIDTH 1 +-#define RX_EV_FRM_TRUNC_LBN 49 +-#define RX_EV_FRM_TRUNC_WIDTH 1 +-#define RX_EV_DRIB_NIB_LBN 48 +-#define RX_EV_DRIB_NIB_WIDTH 1 +-#define RX_EV_TOBE_DISC_LBN 47 +-#define RX_EV_TOBE_DISC_WIDTH 1 +-#define RX_EV_PKT_TYPE_LBN 44 +-#define RX_EV_PKT_TYPE_WIDTH 3 +-#define RX_EV_PKT_TYPE_ETH_DECODE 0 +-#define RX_EV_PKT_TYPE_LLC_DECODE 1 +-#define RX_EV_PKT_TYPE_JUMBO_DECODE 2 +-#define RX_EV_PKT_TYPE_VLAN_DECODE 3 +-#define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4 +-#define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5 +-#define RX_EV_HDR_TYPE_LBN 42 +-#define RX_EV_HDR_TYPE_WIDTH 2 +-#define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0 +-#define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1 +-#define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2 +-#define RX_EV_HDR_TYPE_NON_IP_DECODE 3 +-#define RX_EV_HDR_TYPE_HAS_CHECKSUMS(hdr_type) \ +- ((hdr_type) <= RX_EV_HDR_TYPE_UDP_IPV4_DECODE) +-#define RX_EV_MCAST_HASH_MATCH_LBN 40 +-#define RX_EV_MCAST_HASH_MATCH_WIDTH 1 +-#define RX_EV_MCAST_PKT_LBN 39 +-#define RX_EV_MCAST_PKT_WIDTH 1 +-#define RX_EV_Q_LABEL_LBN 32 +-#define RX_EV_Q_LABEL_WIDTH 5 +-#define RX_EV_JUMBO_CONT_LBN 31 +-#define RX_EV_JUMBO_CONT_WIDTH 1 +-#define RX_EV_BYTE_CNT_LBN 16 +-#define RX_EV_BYTE_CNT_WIDTH 14 +-#define RX_EV_SOP_LBN 15 +-#define RX_EV_SOP_WIDTH 1 +-#define RX_EV_DESC_PTR_LBN 0 +-#define RX_EV_DESC_PTR_WIDTH 12 +- +-/* Transmit events */ +-#define TX_EV_PKT_ERR_LBN 38 +-#define TX_EV_PKT_ERR_WIDTH 1 +-#define TX_EV_Q_LABEL_LBN 32 +-#define TX_EV_Q_LABEL_WIDTH 5 +-#define TX_EV_WQ_FF_FULL_LBN 15 +-#define TX_EV_WQ_FF_FULL_WIDTH 1 +-#define TX_EV_COMP_LBN 12 +-#define TX_EV_COMP_WIDTH 1 +-#define TX_EV_DESC_PTR_LBN 0 +-#define TX_EV_DESC_PTR_WIDTH 12 +- +-/* Driver events */ +-#define DRIVER_EV_SUB_CODE_LBN 56 +-#define DRIVER_EV_SUB_CODE_WIDTH 4 +-#define DRIVER_EV_SUB_DATA_LBN 0 +-#define DRIVER_EV_SUB_DATA_WIDTH 14 +-#define TX_DESCQ_FLS_DONE_EV_DECODE 0 +-#define RX_DESCQ_FLS_DONE_EV_DECODE 1 +-#define EVQ_INIT_DONE_EV_DECODE 2 +-#define EVQ_NOT_EN_EV_DECODE 3 +-#define RX_DESCQ_FLSFF_OVFL_EV_DECODE 4 +-#define SRM_UPD_DONE_EV_DECODE 5 +-#define WAKE_UP_EV_DECODE 6 +-#define TX_PKT_NON_TCP_UDP_DECODE 9 +-#define TIMER_EV_DECODE 10 +-#define RX_RECOVERY_EV_DECODE 11 +-#define RX_DSC_ERROR_EV_DECODE 14 +-#define TX_DSC_ERROR_EV_DECODE 15 +-#define DRIVER_EV_TX_DESCQ_ID_LBN 0 +-#define DRIVER_EV_TX_DESCQ_ID_WIDTH 12 +-#define DRIVER_EV_RX_FLUSH_FAIL_LBN 12 +-#define DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1 +-#define DRIVER_EV_RX_DESCQ_ID_LBN 0 +-#define DRIVER_EV_RX_DESCQ_ID_WIDTH 12 +-#define SRM_CLR_EV_DECODE 0 +-#define SRM_UPD_EV_DECODE 1 +-#define SRM_ILLCLR_EV_DECODE 2 +- +-/* Global events */ +-#define RX_RECOVERY_B0_LBN 12 +-#define RX_RECOVERY_B0_WIDTH 1 +-#define XG_MNT_INTR_B0_LBN 11 +-#define XG_MNT_INTR_B0_WIDTH 1 +-#define RX_RECOVERY_A1_LBN 11 +-#define RX_RECOVERY_A1_WIDTH 1 +-#define XFP_PHY_INTR_LBN 10 +-#define XFP_PHY_INTR_WIDTH 1 +-#define XG_PHY_INTR_LBN 9 +-#define XG_PHY_INTR_WIDTH 1 +-#define G_PHY1_INTR_LBN 8 +-#define G_PHY1_INTR_WIDTH 1 +-#define G_PHY0_INTR_LBN 7 +-#define G_PHY0_INTR_WIDTH 1 +- +-/* Driver-generated test events */ +-#define EVQ_MAGIC_LBN 0 +-#define EVQ_MAGIC_WIDTH 32 +- +-/************************************************************************** +- * +- * Falcon MAC stats +- * +- ************************************************************************** +- * +- */ +- +-#define GRxGoodOct_offset 0x0 +-#define GRxGoodOct_WIDTH 48 +-#define GRxBadOct_offset 0x8 +-#define GRxBadOct_WIDTH 48 +-#define GRxMissPkt_offset 0x10 +-#define GRxMissPkt_WIDTH 32 +-#define GRxFalseCRS_offset 0x14 +-#define GRxFalseCRS_WIDTH 32 +-#define GRxPausePkt_offset 0x18 +-#define GRxPausePkt_WIDTH 32 +-#define GRxBadPkt_offset 0x1C +-#define GRxBadPkt_WIDTH 32 +-#define GRxUcastPkt_offset 0x20 +-#define GRxUcastPkt_WIDTH 32 +-#define GRxMcastPkt_offset 0x24 +-#define GRxMcastPkt_WIDTH 32 +-#define GRxBcastPkt_offset 0x28 +-#define GRxBcastPkt_WIDTH 32 +-#define GRxGoodLt64Pkt_offset 0x2C +-#define GRxGoodLt64Pkt_WIDTH 32 +-#define GRxBadLt64Pkt_offset 0x30 +-#define GRxBadLt64Pkt_WIDTH 32 +-#define GRx64Pkt_offset 0x34 +-#define GRx64Pkt_WIDTH 32 +-#define GRx65to127Pkt_offset 0x38 +-#define GRx65to127Pkt_WIDTH 32 +-#define GRx128to255Pkt_offset 0x3C +-#define GRx128to255Pkt_WIDTH 32 +-#define GRx256to511Pkt_offset 0x40 +-#define GRx256to511Pkt_WIDTH 32 +-#define GRx512to1023Pkt_offset 0x44 +-#define GRx512to1023Pkt_WIDTH 32 +-#define GRx1024to15xxPkt_offset 0x48 +-#define GRx1024to15xxPkt_WIDTH 32 +-#define GRx15xxtoJumboPkt_offset 0x4C +-#define GRx15xxtoJumboPkt_WIDTH 32 +-#define GRxGtJumboPkt_offset 0x50 +-#define GRxGtJumboPkt_WIDTH 32 +-#define GRxFcsErr64to15xxPkt_offset 0x54 +-#define GRxFcsErr64to15xxPkt_WIDTH 32 +-#define GRxFcsErr15xxtoJumboPkt_offset 0x58 +-#define GRxFcsErr15xxtoJumboPkt_WIDTH 32 +-#define GRxFcsErrGtJumboPkt_offset 0x5C +-#define GRxFcsErrGtJumboPkt_WIDTH 32 +-#define GTxGoodBadOct_offset 0x80 +-#define GTxGoodBadOct_WIDTH 48 +-#define GTxGoodOct_offset 0x88 +-#define GTxGoodOct_WIDTH 48 +-#define GTxSglColPkt_offset 0x90 +-#define GTxSglColPkt_WIDTH 32 +-#define GTxMultColPkt_offset 0x94 +-#define GTxMultColPkt_WIDTH 32 +-#define GTxExColPkt_offset 0x98 +-#define GTxExColPkt_WIDTH 32 +-#define GTxDefPkt_offset 0x9C +-#define GTxDefPkt_WIDTH 32 +-#define GTxLateCol_offset 0xA0 +-#define GTxLateCol_WIDTH 32 +-#define GTxExDefPkt_offset 0xA4 +-#define GTxExDefPkt_WIDTH 32 +-#define GTxPausePkt_offset 0xA8 +-#define GTxPausePkt_WIDTH 32 +-#define GTxBadPkt_offset 0xAC +-#define GTxBadPkt_WIDTH 32 +-#define GTxUcastPkt_offset 0xB0 +-#define GTxUcastPkt_WIDTH 32 +-#define GTxMcastPkt_offset 0xB4 +-#define GTxMcastPkt_WIDTH 32 +-#define GTxBcastPkt_offset 0xB8 +-#define GTxBcastPkt_WIDTH 32 +-#define GTxLt64Pkt_offset 0xBC +-#define GTxLt64Pkt_WIDTH 32 +-#define GTx64Pkt_offset 0xC0 +-#define GTx64Pkt_WIDTH 32 +-#define GTx65to127Pkt_offset 0xC4 +-#define GTx65to127Pkt_WIDTH 32 +-#define GTx128to255Pkt_offset 0xC8 +-#define GTx128to255Pkt_WIDTH 32 +-#define GTx256to511Pkt_offset 0xCC +-#define GTx256to511Pkt_WIDTH 32 +-#define GTx512to1023Pkt_offset 0xD0 +-#define GTx512to1023Pkt_WIDTH 32 +-#define GTx1024to15xxPkt_offset 0xD4 +-#define GTx1024to15xxPkt_WIDTH 32 +-#define GTx15xxtoJumboPkt_offset 0xD8 +-#define GTx15xxtoJumboPkt_WIDTH 32 +-#define GTxGtJumboPkt_offset 0xDC +-#define GTxGtJumboPkt_WIDTH 32 +-#define GTxNonTcpUdpPkt_offset 0xE0 +-#define GTxNonTcpUdpPkt_WIDTH 16 +-#define GTxMacSrcErrPkt_offset 0xE4 +-#define GTxMacSrcErrPkt_WIDTH 16 +-#define GTxIpSrcErrPkt_offset 0xE8 +-#define GTxIpSrcErrPkt_WIDTH 16 +-#define GDmaDone_offset 0xEC +-#define GDmaDone_WIDTH 32 +- +-#define XgRxOctets_offset 0x0 +-#define XgRxOctets_WIDTH 48 +-#define XgRxOctetsOK_offset 0x8 +-#define XgRxOctetsOK_WIDTH 48 +-#define XgRxPkts_offset 0x10 +-#define XgRxPkts_WIDTH 32 +-#define XgRxPktsOK_offset 0x14 +-#define XgRxPktsOK_WIDTH 32 +-#define XgRxBroadcastPkts_offset 0x18 +-#define XgRxBroadcastPkts_WIDTH 32 +-#define XgRxMulticastPkts_offset 0x1C +-#define XgRxMulticastPkts_WIDTH 32 +-#define XgRxUnicastPkts_offset 0x20 +-#define XgRxUnicastPkts_WIDTH 32 +-#define XgRxUndersizePkts_offset 0x24 +-#define XgRxUndersizePkts_WIDTH 32 +-#define XgRxOversizePkts_offset 0x28 +-#define XgRxOversizePkts_WIDTH 32 +-#define XgRxJabberPkts_offset 0x2C +-#define XgRxJabberPkts_WIDTH 32 +-#define XgRxUndersizeFCSerrorPkts_offset 0x30 +-#define XgRxUndersizeFCSerrorPkts_WIDTH 32 +-#define XgRxDropEvents_offset 0x34 +-#define XgRxDropEvents_WIDTH 32 +-#define XgRxFCSerrorPkts_offset 0x38 +-#define XgRxFCSerrorPkts_WIDTH 32 +-#define XgRxAlignError_offset 0x3C +-#define XgRxAlignError_WIDTH 32 +-#define XgRxSymbolError_offset 0x40 +-#define XgRxSymbolError_WIDTH 32 +-#define XgRxInternalMACError_offset 0x44 +-#define XgRxInternalMACError_WIDTH 32 +-#define XgRxControlPkts_offset 0x48 +-#define XgRxControlPkts_WIDTH 32 +-#define XgRxPausePkts_offset 0x4C +-#define XgRxPausePkts_WIDTH 32 +-#define XgRxPkts64Octets_offset 0x50 +-#define XgRxPkts64Octets_WIDTH 32 +-#define XgRxPkts65to127Octets_offset 0x54 +-#define XgRxPkts65to127Octets_WIDTH 32 +-#define XgRxPkts128to255Octets_offset 0x58 +-#define XgRxPkts128to255Octets_WIDTH 32 +-#define XgRxPkts256to511Octets_offset 0x5C +-#define XgRxPkts256to511Octets_WIDTH 32 +-#define XgRxPkts512to1023Octets_offset 0x60 +-#define XgRxPkts512to1023Octets_WIDTH 32 +-#define XgRxPkts1024to15xxOctets_offset 0x64 +-#define XgRxPkts1024to15xxOctets_WIDTH 32 +-#define XgRxPkts15xxtoMaxOctets_offset 0x68 +-#define XgRxPkts15xxtoMaxOctets_WIDTH 32 +-#define XgRxLengthError_offset 0x6C +-#define XgRxLengthError_WIDTH 32 +-#define XgTxPkts_offset 0x80 +-#define XgTxPkts_WIDTH 32 +-#define XgTxOctets_offset 0x88 +-#define XgTxOctets_WIDTH 48 +-#define XgTxMulticastPkts_offset 0x90 +-#define XgTxMulticastPkts_WIDTH 32 +-#define XgTxBroadcastPkts_offset 0x94 +-#define XgTxBroadcastPkts_WIDTH 32 +-#define XgTxUnicastPkts_offset 0x98 +-#define XgTxUnicastPkts_WIDTH 32 +-#define XgTxControlPkts_offset 0x9C +-#define XgTxControlPkts_WIDTH 32 +-#define XgTxPausePkts_offset 0xA0 +-#define XgTxPausePkts_WIDTH 32 +-#define XgTxPkts64Octets_offset 0xA4 +-#define XgTxPkts64Octets_WIDTH 32 +-#define XgTxPkts65to127Octets_offset 0xA8 +-#define XgTxPkts65to127Octets_WIDTH 32 +-#define XgTxPkts128to255Octets_offset 0xAC +-#define XgTxPkts128to255Octets_WIDTH 32 +-#define XgTxPkts256to511Octets_offset 0xB0 +-#define XgTxPkts256to511Octets_WIDTH 32 +-#define XgTxPkts512to1023Octets_offset 0xB4 +-#define XgTxPkts512to1023Octets_WIDTH 32 +-#define XgTxPkts1024to15xxOctets_offset 0xB8 +-#define XgTxPkts1024to15xxOctets_WIDTH 32 +-#define XgTxPkts1519toMaxOctets_offset 0xBC +-#define XgTxPkts1519toMaxOctets_WIDTH 32 +-#define XgTxUndersizePkts_offset 0xC0 +-#define XgTxUndersizePkts_WIDTH 32 +-#define XgTxOversizePkts_offset 0xC4 +-#define XgTxOversizePkts_WIDTH 32 +-#define XgTxNonTcpUdpPkt_offset 0xC8 +-#define XgTxNonTcpUdpPkt_WIDTH 16 +-#define XgTxMacSrcErrPkt_offset 0xCC +-#define XgTxMacSrcErrPkt_WIDTH 16 +-#define XgTxIpSrcErrPkt_offset 0xD0 +-#define XgTxIpSrcErrPkt_WIDTH 16 +-#define XgDmaDone_offset 0xD4 +- +-#define FALCON_STATS_NOT_DONE 0x00000000 +-#define FALCON_STATS_DONE 0xffffffff +- +-/* Interrupt status register bits */ +-#define FATAL_INT_LBN 64 +-#define FATAL_INT_WIDTH 1 +-#define INT_EVQS_LBN 40 +-#define INT_EVQS_WIDTH 4 +- +-/************************************************************************** +- * +- * Falcon non-volatile configuration +- * +- ************************************************************************** +- */ +- +-/* Board configuration v2 (v1 is obsolete; later versions are compatible) */ +-struct falcon_nvconfig_board_v2 { +- __le16 nports; +- u8 port0_phy_addr; +- u8 port0_phy_type; +- u8 port1_phy_addr; +- u8 port1_phy_type; +- __le16 asic_sub_revision; +- __le16 board_revision; +-} __packed; +- +-/* Board configuration v3 extra information */ +-struct falcon_nvconfig_board_v3 { +- __le32 spi_device_type[2]; +-} __packed; +- +-/* Bit numbers for spi_device_type */ +-#define SPI_DEV_TYPE_SIZE_LBN 0 +-#define SPI_DEV_TYPE_SIZE_WIDTH 5 +-#define SPI_DEV_TYPE_ADDR_LEN_LBN 6 +-#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2 +-#define SPI_DEV_TYPE_ERASE_CMD_LBN 8 +-#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8 +-#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16 +-#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5 +-#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24 +-#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5 +-#define SPI_DEV_TYPE_FIELD(type, field) \ +- (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field))) +- +-#define NVCONFIG_OFFSET 0x300 +- +-#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C +-struct falcon_nvconfig { +- efx_oword_t ee_vpd_cfg_reg; /* 0x300 */ +- u8 mac_address[2][8]; /* 0x310 */ +- efx_oword_t pcie_sd_ctl0123_reg; /* 0x320 */ +- efx_oword_t pcie_sd_ctl45_reg; /* 0x330 */ +- efx_oword_t pcie_pcs_ctl_stat_reg; /* 0x340 */ +- efx_oword_t hw_init_reg; /* 0x350 */ +- efx_oword_t nic_stat_reg; /* 0x360 */ +- efx_oword_t glb_ctl_reg; /* 0x370 */ +- efx_oword_t srm_cfg_reg; /* 0x380 */ +- efx_oword_t spare_reg; /* 0x390 */ +- __le16 board_magic_num; /* 0x3A0 */ +- __le16 board_struct_ver; +- __le16 board_checksum; +- struct falcon_nvconfig_board_v2 board_v2; +- efx_oword_t ee_base_page_reg; /* 0x3B0 */ +- struct falcon_nvconfig_board_v3 board_v3; +-} __packed; +- +-#endif /* EFX_FALCON_HWDEFS_H */ +diff --git a/drivers/net/sfc/falcon_io.h b/drivers/net/sfc/falcon_io.h +deleted file mode 100644 +index 8883092..0000000 +--- a/drivers/net/sfc/falcon_io.h ++++ /dev/null +@@ -1,258 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +- +-#ifndef EFX_FALCON_IO_H +-#define EFX_FALCON_IO_H +- +-#include +-#include +- +-/************************************************************************** +- * +- * Falcon hardware access +- * +- ************************************************************************** +- * +- * Notes on locking strategy: +- * +- * Most Falcon registers require 16-byte (or 8-byte, for SRAM +- * registers) atomic writes which necessitates locking. +- * Under normal operation few writes to the Falcon BAR are made and these +- * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special +- * cased to allow 4-byte (hence lockless) accesses. +- * +- * It *is* safe to write to these 4-byte registers in the middle of an +- * access to an 8-byte or 16-byte register. We therefore use a +- * spinlock to protect accesses to the larger registers, but no locks +- * for the 4-byte registers. +- * +- * A write barrier is needed to ensure that DW3 is written after DW0/1/2 +- * due to the way the 16byte registers are "collected" in the Falcon BIU +- * +- * We also lock when carrying out reads, to ensure consistency of the +- * data (made possible since the BIU reads all 128 bits into a cache). +- * Reads are very rare, so this isn't a significant performance +- * impact. (Most data transferred from NIC to host is DMAed directly +- * into host memory). +- * +- * I/O BAR access uses locks for both reads and writes (but is only provided +- * for testing purposes). +- */ +- +-/* Special buffer descriptors (Falcon SRAM) */ +-#define BUF_TBL_KER_A1 0x18000 +-#define BUF_TBL_KER_B0 0x800000 +- +- +-#if BITS_PER_LONG == 64 +-#define FALCON_USE_QWORD_IO 1 +-#endif +- +-#ifdef FALCON_USE_QWORD_IO +-static inline void _falcon_writeq(struct efx_nic *efx, __le64 value, +- unsigned int reg) +-{ +- __raw_writeq((__force u64)value, efx->membase + reg); +-} +-static inline __le64 _falcon_readq(struct efx_nic *efx, unsigned int reg) +-{ +- return (__force __le64)__raw_readq(efx->membase + reg); +-} +-#endif +- +-static inline void _falcon_writel(struct efx_nic *efx, __le32 value, +- unsigned int reg) +-{ +- __raw_writel((__force u32)value, efx->membase + reg); +-} +-static inline __le32 _falcon_readl(struct efx_nic *efx, unsigned int reg) +-{ +- return (__force __le32)__raw_readl(efx->membase + reg); +-} +- +-/* Writes to a normal 16-byte Falcon register, locking as appropriate. */ +-static inline void falcon_write(struct efx_nic *efx, efx_oword_t *value, +- unsigned int reg) +-{ +- unsigned long flags; +- +- EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg, +- EFX_OWORD_VAL(*value)); +- +- spin_lock_irqsave(&efx->biu_lock, flags); +-#ifdef FALCON_USE_QWORD_IO +- _falcon_writeq(efx, value->u64[0], reg + 0); +- wmb(); +- _falcon_writeq(efx, value->u64[1], reg + 8); +-#else +- _falcon_writel(efx, value->u32[0], reg + 0); +- _falcon_writel(efx, value->u32[1], reg + 4); +- _falcon_writel(efx, value->u32[2], reg + 8); +- wmb(); +- _falcon_writel(efx, value->u32[3], reg + 12); +-#endif +- mmiowb(); +- spin_unlock_irqrestore(&efx->biu_lock, flags); +-} +- +-/* Writes to an 8-byte Falcon SRAM register, locking as appropriate. */ +-static inline void falcon_write_sram(struct efx_nic *efx, efx_qword_t *value, +- unsigned int index) +-{ +- unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value)); +- unsigned long flags; +- +- EFX_REGDUMP(efx, "writing SRAM register %x with " EFX_QWORD_FMT "\n", +- reg, EFX_QWORD_VAL(*value)); +- +- spin_lock_irqsave(&efx->biu_lock, flags); +-#ifdef FALCON_USE_QWORD_IO +- _falcon_writeq(efx, value->u64[0], reg + 0); +-#else +- _falcon_writel(efx, value->u32[0], reg + 0); +- wmb(); +- _falcon_writel(efx, value->u32[1], reg + 4); +-#endif +- mmiowb(); +- spin_unlock_irqrestore(&efx->biu_lock, flags); +-} +- +-/* Write dword to Falcon register that allows partial writes +- * +- * Some Falcon registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and +- * TX_DESC_UPD_REG) can be written to as a single dword. This allows +- * for lockless writes. +- */ +-static inline void falcon_writel(struct efx_nic *efx, efx_dword_t *value, +- unsigned int reg) +-{ +- EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n", +- reg, EFX_DWORD_VAL(*value)); +- +- /* No lock required */ +- _falcon_writel(efx, value->u32[0], reg); +-} +- +-/* Read from a Falcon register +- * +- * This reads an entire 16-byte Falcon register in one go, locking as +- * appropriate. It is essential to read the first dword first, as this +- * prompts Falcon to load the current value into the shadow register. +- */ +-static inline void falcon_read(struct efx_nic *efx, efx_oword_t *value, +- unsigned int reg) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&efx->biu_lock, flags); +- value->u32[0] = _falcon_readl(efx, reg + 0); +- rmb(); +- value->u32[1] = _falcon_readl(efx, reg + 4); +- value->u32[2] = _falcon_readl(efx, reg + 8); +- value->u32[3] = _falcon_readl(efx, reg + 12); +- spin_unlock_irqrestore(&efx->biu_lock, flags); +- +- EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg, +- EFX_OWORD_VAL(*value)); +-} +- +-/* This reads an 8-byte Falcon SRAM entry in one go. */ +-static inline void falcon_read_sram(struct efx_nic *efx, efx_qword_t *value, +- unsigned int index) +-{ +- unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value)); +- unsigned long flags; +- +- spin_lock_irqsave(&efx->biu_lock, flags); +-#ifdef FALCON_USE_QWORD_IO +- value->u64[0] = _falcon_readq(efx, reg + 0); +-#else +- value->u32[0] = _falcon_readl(efx, reg + 0); +- rmb(); +- value->u32[1] = _falcon_readl(efx, reg + 4); +-#endif +- spin_unlock_irqrestore(&efx->biu_lock, flags); +- +- EFX_REGDUMP(efx, "read from SRAM register %x, got "EFX_QWORD_FMT"\n", +- reg, EFX_QWORD_VAL(*value)); +-} +- +-/* Read dword from Falcon register that allows partial writes (sic) */ +-static inline void falcon_readl(struct efx_nic *efx, efx_dword_t *value, +- unsigned int reg) +-{ +- value->u32[0] = _falcon_readl(efx, reg); +- EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n", +- reg, EFX_DWORD_VAL(*value)); +-} +- +-/* Write to a register forming part of a table */ +-static inline void falcon_write_table(struct efx_nic *efx, efx_oword_t *value, +- unsigned int reg, unsigned int index) +-{ +- falcon_write(efx, value, reg + index * sizeof(efx_oword_t)); +-} +- +-/* Read to a register forming part of a table */ +-static inline void falcon_read_table(struct efx_nic *efx, efx_oword_t *value, +- unsigned int reg, unsigned int index) +-{ +- falcon_read(efx, value, reg + index * sizeof(efx_oword_t)); +-} +- +-/* Write to a dword register forming part of a table */ +-static inline void falcon_writel_table(struct efx_nic *efx, efx_dword_t *value, +- unsigned int reg, unsigned int index) +-{ +- falcon_writel(efx, value, reg + index * sizeof(efx_oword_t)); +-} +- +-/* Page-mapped register block size */ +-#define FALCON_PAGE_BLOCK_SIZE 0x2000 +- +-/* Calculate offset to page-mapped register block */ +-#define FALCON_PAGED_REG(page, reg) \ +- ((page) * FALCON_PAGE_BLOCK_SIZE + (reg)) +- +-/* As for falcon_write(), but for a page-mapped register. */ +-static inline void falcon_write_page(struct efx_nic *efx, efx_oword_t *value, +- unsigned int reg, unsigned int page) +-{ +- falcon_write(efx, value, FALCON_PAGED_REG(page, reg)); +-} +- +-/* As for falcon_writel(), but for a page-mapped register. */ +-static inline void falcon_writel_page(struct efx_nic *efx, efx_dword_t *value, +- unsigned int reg, unsigned int page) +-{ +- falcon_writel(efx, value, FALCON_PAGED_REG(page, reg)); +-} +- +-/* Write dword to Falcon page-mapped register with an extra lock. +- * +- * As for falcon_writel_page(), but for a register that suffers from +- * SFC bug 3181. If writing to page 0, take out a lock so the BIU +- * collector cannot be confused. +- */ +-static inline void falcon_writel_page_locked(struct efx_nic *efx, +- efx_dword_t *value, +- unsigned int reg, +- unsigned int page) +-{ +- unsigned long flags = 0; +- +- if (page == 0) +- spin_lock_irqsave(&efx->biu_lock, flags); +- falcon_writel(efx, value, FALCON_PAGED_REG(page, reg)); +- if (page == 0) +- spin_unlock_irqrestore(&efx->biu_lock, flags); +-} +- +-#endif /* EFX_FALCON_IO_H */ +diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c +index bec52ca..3da933f 100644 +--- a/drivers/net/sfc/falcon_xmac.c ++++ b/drivers/net/sfc/falcon_xmac.c +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -11,13 +11,12 @@ + #include + #include "net_driver.h" + #include "efx.h" +-#include "falcon.h" +-#include "falcon_hwdefs.h" +-#include "falcon_io.h" ++#include "nic.h" ++#include "regs.h" ++#include "io.h" + #include "mac.h" + #include "mdio_10g.h" + #include "phy.h" +-#include "boards.h" + #include "workarounds.h" + + /************************************************************************** +@@ -36,43 +35,47 @@ static void falcon_setup_xaui(struct efx_nic *efx) + if (efx->phy_type == PHY_TYPE_NONE) + return; + +- falcon_read(efx, &sdctl, XX_SD_CTL_REG); +- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT); +- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT); +- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT); +- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT); +- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT); +- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT); +- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT); +- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT); +- falcon_write(efx, &sdctl, XX_SD_CTL_REG); ++ efx_reado(efx, &sdctl, FR_AB_XX_SD_CTL); ++ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVD, FFE_AB_XX_SD_CTL_DRV_DEF); ++ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVD, FFE_AB_XX_SD_CTL_DRV_DEF); ++ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVC, FFE_AB_XX_SD_CTL_DRV_DEF); ++ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVC, FFE_AB_XX_SD_CTL_DRV_DEF); ++ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVB, FFE_AB_XX_SD_CTL_DRV_DEF); ++ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVB, FFE_AB_XX_SD_CTL_DRV_DEF); ++ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVA, FFE_AB_XX_SD_CTL_DRV_DEF); ++ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVA, FFE_AB_XX_SD_CTL_DRV_DEF); ++ efx_writeo(efx, &sdctl, FR_AB_XX_SD_CTL); + + EFX_POPULATE_OWORD_8(txdrv, +- XX_DEQD, XX_TXDRV_DEQ_DEFAULT, +- XX_DEQC, XX_TXDRV_DEQ_DEFAULT, +- XX_DEQB, XX_TXDRV_DEQ_DEFAULT, +- XX_DEQA, XX_TXDRV_DEQ_DEFAULT, +- XX_DTXD, XX_TXDRV_DTX_DEFAULT, +- XX_DTXC, XX_TXDRV_DTX_DEFAULT, +- XX_DTXB, XX_TXDRV_DTX_DEFAULT, +- XX_DTXA, XX_TXDRV_DTX_DEFAULT); +- falcon_write(efx, &txdrv, XX_TXDRV_CTL_REG); ++ FRF_AB_XX_DEQD, FFE_AB_XX_TXDRV_DEQ_DEF, ++ FRF_AB_XX_DEQC, FFE_AB_XX_TXDRV_DEQ_DEF, ++ FRF_AB_XX_DEQB, FFE_AB_XX_TXDRV_DEQ_DEF, ++ FRF_AB_XX_DEQA, FFE_AB_XX_TXDRV_DEQ_DEF, ++ FRF_AB_XX_DTXD, FFE_AB_XX_TXDRV_DTX_DEF, ++ FRF_AB_XX_DTXC, FFE_AB_XX_TXDRV_DTX_DEF, ++ FRF_AB_XX_DTXB, FFE_AB_XX_TXDRV_DTX_DEF, ++ FRF_AB_XX_DTXA, FFE_AB_XX_TXDRV_DTX_DEF); ++ efx_writeo(efx, &txdrv, FR_AB_XX_TXDRV_CTL); + } + + int falcon_reset_xaui(struct efx_nic *efx) + { ++ struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t reg; + int count; + ++ /* Don't fetch MAC statistics over an XMAC reset */ ++ WARN_ON(nic_data->stats_disable_count == 0); ++ + /* Start reset sequence */ +- EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1); +- falcon_write(efx, ®, XX_PWR_RST_REG); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1); ++ efx_writeo(efx, ®, FR_AB_XX_PWR_RST); + + /* Wait up to 10 ms for completion, then reinitialise */ + for (count = 0; count < 1000; count++) { +- falcon_read(efx, ®, XX_PWR_RST_REG); +- if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0 && +- EFX_OWORD_FIELD(reg, XX_SD_RST_ACT) == 0) { ++ efx_reado(efx, ®, FR_AB_XX_PWR_RST); ++ if (EFX_OWORD_FIELD(reg, FRF_AB_XX_RST_XX_EN) == 0 && ++ EFX_OWORD_FIELD(reg, FRF_AB_XX_SD_RST_ACT) == 0) { + falcon_setup_xaui(efx); + return 0; + } +@@ -86,30 +89,30 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) + { + efx_oword_t reg; + +- if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) ++ if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx)) + return; + + /* We expect xgmii faults if the wireside link is up */ +- if (!EFX_WORKAROUND_5147(efx) || !efx->link_up) ++ if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up) + return; + + /* We can only use this interrupt to signal the negative edge of + * xaui_align [we have to poll the positive edge]. */ +- if (!efx->mac_up) ++ if (efx->xmac_poll_required) + return; + + /* Flush the ISR */ + if (enable) +- falcon_read(efx, ®, XM_MGT_INT_REG_B0); ++ efx_reado(efx, ®, FR_AB_XM_MGT_INT_MSK); + + EFX_POPULATE_OWORD_2(reg, +- XM_MSK_RMTFLT, !enable, +- XM_MSK_LCLFLT, !enable); +- falcon_write(efx, ®, XM_MGT_INT_MSK_REG_B0); ++ FRF_AB_XM_MSK_RMTFLT, !enable, ++ FRF_AB_XM_MSK_LCLFLT, !enable); ++ efx_writeo(efx, ®, FR_AB_XM_MGT_INT_MASK); + } + + /* Get status of XAUI link */ +-bool falcon_xaui_link_ok(struct efx_nic *efx) ++static bool falcon_xaui_link_ok(struct efx_nic *efx) + { + efx_oword_t reg; + bool align_done, link_ok = false; +@@ -119,84 +122,79 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) + return true; + + /* Read link status */ +- falcon_read(efx, ®, XX_CORE_STAT_REG); ++ efx_reado(efx, ®, FR_AB_XX_CORE_STAT); + +- align_done = EFX_OWORD_FIELD(reg, XX_ALIGN_DONE); +- sync_status = EFX_OWORD_FIELD(reg, XX_SYNC_STAT); +- if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED)) ++ align_done = EFX_OWORD_FIELD(reg, FRF_AB_XX_ALIGN_DONE); ++ sync_status = EFX_OWORD_FIELD(reg, FRF_AB_XX_SYNC_STAT); ++ if (align_done && (sync_status == FFE_AB_XX_STAT_ALL_LANES)) + link_ok = true; + + /* Clear link status ready for next read */ +- EFX_SET_OWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET); +- EFX_SET_OWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET); +- EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET); +- falcon_write(efx, ®, XX_CORE_STAT_REG); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_COMMA_DET, FFE_AB_XX_STAT_ALL_LANES); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_CHAR_ERR, FFE_AB_XX_STAT_ALL_LANES); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES); ++ efx_writeo(efx, ®, FR_AB_XX_CORE_STAT); + + /* If the link is up, then check the phy side of the xaui link */ +- if (efx->link_up && link_ok) +- if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) ++ if (efx->link_state.up && link_ok) ++ if (efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) + link_ok = efx_mdio_phyxgxs_lane_sync(efx); + + return link_ok; + } + +-static void falcon_reconfigure_xmac_core(struct efx_nic *efx) ++void falcon_reconfigure_xmac_core(struct efx_nic *efx) + { + unsigned int max_frame_len; + efx_oword_t reg; +- bool rx_fc = !!(efx->link_fc & EFX_FC_RX); ++ bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX); ++ bool tx_fc = !!(efx->link_state.fc & EFX_FC_TX); + + /* Configure MAC - cut-thru mode is hard wired on */ +- EFX_POPULATE_DWORD_3(reg, +- XM_RX_JUMBO_MODE, 1, +- XM_TX_STAT_EN, 1, +- XM_RX_STAT_EN, 1); +- falcon_write(efx, ®, XM_GLB_CFG_REG); ++ EFX_POPULATE_OWORD_3(reg, ++ FRF_AB_XM_RX_JUMBO_MODE, 1, ++ FRF_AB_XM_TX_STAT_EN, 1, ++ FRF_AB_XM_RX_STAT_EN, 1); ++ efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); + + /* Configure TX */ +- EFX_POPULATE_DWORD_6(reg, +- XM_TXEN, 1, +- XM_TX_PRMBL, 1, +- XM_AUTO_PAD, 1, +- XM_TXCRC, 1, +- XM_FCNTL, 1, +- XM_IPG, 0x3); +- falcon_write(efx, ®, XM_TX_CFG_REG); ++ EFX_POPULATE_OWORD_6(reg, ++ FRF_AB_XM_TXEN, 1, ++ FRF_AB_XM_TX_PRMBL, 1, ++ FRF_AB_XM_AUTO_PAD, 1, ++ FRF_AB_XM_TXCRC, 1, ++ FRF_AB_XM_FCNTL, tx_fc, ++ FRF_AB_XM_IPG, 0x3); ++ efx_writeo(efx, ®, FR_AB_XM_TX_CFG); + + /* Configure RX */ +- EFX_POPULATE_DWORD_5(reg, +- XM_RXEN, 1, +- XM_AUTO_DEPAD, 0, +- XM_ACPT_ALL_MCAST, 1, +- XM_ACPT_ALL_UCAST, efx->promiscuous, +- XM_PASS_CRC_ERR, 1); +- falcon_write(efx, ®, XM_RX_CFG_REG); ++ EFX_POPULATE_OWORD_5(reg, ++ FRF_AB_XM_RXEN, 1, ++ FRF_AB_XM_AUTO_DEPAD, 0, ++ FRF_AB_XM_ACPT_ALL_MCAST, 1, ++ FRF_AB_XM_ACPT_ALL_UCAST, efx->promiscuous, ++ FRF_AB_XM_PASS_CRC_ERR, 1); ++ efx_writeo(efx, ®, FR_AB_XM_RX_CFG); + + /* Set frame length */ + max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); +- EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len); +- falcon_write(efx, ®, XM_RX_PARAM_REG); +- EFX_POPULATE_DWORD_2(reg, +- XM_MAX_TX_FRM_SIZE, max_frame_len, +- XM_TX_JUMBO_MODE, 1); +- falcon_write(efx, ®, XM_TX_PARAM_REG); +- +- EFX_POPULATE_DWORD_2(reg, +- XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */ +- XM_DIS_FCNTL, !rx_fc); +- falcon_write(efx, ®, XM_FC_REG); ++ EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len); ++ efx_writeo(efx, ®, FR_AB_XM_RX_PARAM); ++ EFX_POPULATE_OWORD_2(reg, ++ FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len, ++ FRF_AB_XM_TX_JUMBO_MODE, 1); ++ efx_writeo(efx, ®, FR_AB_XM_TX_PARAM); ++ ++ EFX_POPULATE_OWORD_2(reg, ++ FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */ ++ FRF_AB_XM_DIS_FCNTL, !rx_fc); ++ efx_writeo(efx, ®, FR_AB_XM_FC); + + /* Set MAC address */ +- EFX_POPULATE_DWORD_4(reg, +- XM_ADR_0, efx->net_dev->dev_addr[0], +- XM_ADR_1, efx->net_dev->dev_addr[1], +- XM_ADR_2, efx->net_dev->dev_addr[2], +- XM_ADR_3, efx->net_dev->dev_addr[3]); +- falcon_write(efx, ®, XM_ADR_LO_REG); +- EFX_POPULATE_DWORD_2(reg, +- XM_ADR_4, efx->net_dev->dev_addr[4], +- XM_ADR_5, efx->net_dev->dev_addr[5]); +- falcon_write(efx, ®, XM_ADR_HI_REG); ++ memcpy(®, &efx->net_dev->dev_addr[0], 4); ++ efx_writeo(efx, ®, FR_AB_XM_ADR_LO); ++ memcpy(®, &efx->net_dev->dev_addr[4], 2); ++ efx_writeo(efx, ®, FR_AB_XM_ADR_HI); + } + + static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) +@@ -212,12 +210,13 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) + bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback; + bool reset_xgxs; + +- falcon_read(efx, ®, XX_CORE_STAT_REG); +- old_xgxs_loopback = EFX_OWORD_FIELD(reg, XX_XGXS_LB_EN); +- old_xgmii_loopback = EFX_OWORD_FIELD(reg, XX_XGMII_LB_EN); ++ efx_reado(efx, ®, FR_AB_XX_CORE_STAT); ++ old_xgxs_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN); ++ old_xgmii_loopback = ++ EFX_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN); + +- falcon_read(efx, ®, XX_SD_CTL_REG); +- old_xaui_loopback = EFX_OWORD_FIELD(reg, XX_LPBKA); ++ efx_reado(efx, ®, FR_AB_XX_SD_CTL); ++ old_xaui_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_LPBKA); + + /* The PHY driver may have turned XAUI off */ + reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) || +@@ -228,45 +227,55 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) + falcon_reset_xaui(efx); + } + +- falcon_read(efx, ®, XX_CORE_STAT_REG); +- EFX_SET_OWORD_FIELD(reg, XX_FORCE_SIG, ++ efx_reado(efx, ®, FR_AB_XX_CORE_STAT); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_FORCE_SIG, + (xgxs_loopback || xaui_loopback) ? +- XX_FORCE_SIG_DECODE_FORCED : 0); +- EFX_SET_OWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback); +- EFX_SET_OWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback); +- falcon_write(efx, ®, XX_CORE_STAT_REG); +- +- falcon_read(efx, ®, XX_SD_CTL_REG); +- EFX_SET_OWORD_FIELD(reg, XX_LPBKD, xaui_loopback); +- EFX_SET_OWORD_FIELD(reg, XX_LPBKC, xaui_loopback); +- EFX_SET_OWORD_FIELD(reg, XX_LPBKB, xaui_loopback); +- EFX_SET_OWORD_FIELD(reg, XX_LPBKA, xaui_loopback); +- falcon_write(efx, ®, XX_SD_CTL_REG); ++ FFE_AB_XX_FORCE_SIG_ALL_LANES : 0); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN, xgxs_loopback); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN, xgmii_loopback); ++ efx_writeo(efx, ®, FR_AB_XX_CORE_STAT); ++ ++ efx_reado(efx, ®, FR_AB_XX_SD_CTL); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKD, xaui_loopback); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKC, xaui_loopback); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKB, xaui_loopback); ++ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKA, xaui_loopback); ++ efx_writeo(efx, ®, FR_AB_XX_SD_CTL); + } + + +-/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails +- * to come back up. Bash it until it comes back up */ +-static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries) ++/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */ ++static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) + { +- efx->mac_up = falcon_xaui_link_ok(efx); ++ bool mac_up = falcon_xaui_link_ok(efx); + +- if ((efx->loopback_mode == LOOPBACK_NETWORK) || ++ if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS || + efx_phy_mode_disabled(efx->phy_mode)) + /* XAUI link is expected to be down */ +- return; ++ return mac_up; + +- while (!efx->mac_up && tries) { ++ falcon_stop_nic_stats(efx); ++ ++ while (!mac_up && tries) { + EFX_LOG(efx, "bashing xaui\n"); + falcon_reset_xaui(efx); + udelay(200); + +- efx->mac_up = falcon_xaui_link_ok(efx); ++ mac_up = falcon_xaui_link_ok(efx); + --tries; + } ++ ++ falcon_start_nic_stats(efx); ++ ++ return mac_up; + } + +-static void falcon_reconfigure_xmac(struct efx_nic *efx) ++static bool falcon_xmac_check_fault(struct efx_nic *efx) ++{ ++ return !falcon_check_xaui_link_up(efx, 5); ++} ++ ++static int falcon_reconfigure_xmac(struct efx_nic *efx) + { + falcon_mask_status_intr(efx, false); + +@@ -275,18 +284,15 @@ static void falcon_reconfigure_xmac(struct efx_nic *efx) + + falcon_reconfigure_mac_wrapper(efx); + +- falcon_check_xaui_link_up(efx, 5); ++ efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5); + falcon_mask_status_intr(efx, true); ++ ++ return 0; + } + + static void falcon_update_stats_xmac(struct efx_nic *efx) + { + struct efx_mac_stats *mac_stats = &efx->mac_stats; +- int rc; +- +- rc = falcon_dma_stats(efx, XgDmaDone_offset); +- if (rc) +- return; + + /* Update MAC stats from DMAed values */ + FALCON_STAT(efx, XgRxOctets, rx_bytes); +@@ -344,35 +350,19 @@ static void falcon_update_stats_xmac(struct efx_nic *efx) + mac_stats->rx_control * 64); + } + +-static void falcon_xmac_irq(struct efx_nic *efx) +-{ +- /* The XGMII link has a transient fault, which indicates either: +- * - there's a transient xgmii fault +- * - falcon's end of the xaui link may need a kick +- * - the wire-side link may have gone down, but the lasi/poll() +- * hasn't noticed yet. +- * +- * We only want to even bother polling XAUI if we're confident it's +- * not (1) or (3). In both cases, the only reliable way to spot this +- * is to wait a bit. We do this here by forcing the mac link state +- * to down, and waiting for the mac poll to come round and check +- */ +- efx->mac_up = false; +-} +- +-static void falcon_poll_xmac(struct efx_nic *efx) ++void falcon_poll_xmac(struct efx_nic *efx) + { +- if (!EFX_WORKAROUND_5147(efx) || !efx->link_up || efx->mac_up) ++ if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up || ++ !efx->xmac_poll_required) + return; + + falcon_mask_status_intr(efx, false); +- falcon_check_xaui_link_up(efx, 1); ++ efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 1); + falcon_mask_status_intr(efx, true); + } + + struct efx_mac_operations falcon_xmac_operations = { + .reconfigure = falcon_reconfigure_xmac, + .update_stats = falcon_update_stats_xmac, +- .irq = falcon_xmac_irq, +- .poll = falcon_poll_xmac, ++ .check_fault = falcon_xmac_check_fault, + }; +diff --git a/drivers/net/sfc/gmii.h b/drivers/net/sfc/gmii.h +deleted file mode 100644 +index dfccaa7..0000000 +--- a/drivers/net/sfc/gmii.h ++++ /dev/null +@@ -1,60 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +- +-#ifndef EFX_GMII_H +-#define EFX_GMII_H +- +-/* +- * GMII interface +- */ +- +-#include +- +-/* GMII registers, excluding registers already defined as MII +- * registers in mii.h +- */ +-#define GMII_IER 0x12 /* Interrupt enable register */ +-#define GMII_ISR 0x13 /* Interrupt status register */ +- +-/* Interrupt enable register */ +-#define IER_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */ +-#define IER_SPEED_CHG 0x4000 /* Bit 14 - speed changed */ +-#define IER_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */ +-#define IER_PAGE_RCVD 0x1000 /* Bit 12 - page received */ +-#define IER_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */ +-#define IER_LINK_CHG 0x0400 /* Bit 10 - link status changed */ +-#define IER_SYM_ERR 0x0200 /* Bit 9 - symbol error */ +-#define IER_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */ +-#define IER_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */ +-#define IER_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */ +-#define IER_DOWNSHIFT 0x0020 /* Bit 5 - downshift */ +-#define IER_ENERGY 0x0010 /* Bit 4 - energy detect */ +-#define IER_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */ +-#define IER_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */ +-#define IER_JABBER 0x0001 /* Bit 0 - jabber */ +- +-/* Interrupt status register */ +-#define ISR_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */ +-#define ISR_SPEED_CHG 0x4000 /* Bit 14 - speed changed */ +-#define ISR_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */ +-#define ISR_PAGE_RCVD 0x1000 /* Bit 12 - page received */ +-#define ISR_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */ +-#define ISR_LINK_CHG 0x0400 /* Bit 10 - link status changed */ +-#define ISR_SYM_ERR 0x0200 /* Bit 9 - symbol error */ +-#define ISR_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */ +-#define ISR_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */ +-#define ISR_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */ +-#define ISR_DOWNSHIFT 0x0020 /* Bit 5 - downshift */ +-#define ISR_ENERGY 0x0010 /* Bit 4 - energy detect */ +-#define ISR_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */ +-#define ISR_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */ +-#define ISR_JABBER 0x0001 /* Bit 0 - jabber */ +- +-#endif /* EFX_GMII_H */ +diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h +new file mode 100644 +index 0000000..b89177c +--- /dev/null ++++ b/drivers/net/sfc/io.h +@@ -0,0 +1,256 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2005-2006 Fen Systems Ltd. ++ * Copyright 2006-2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++#ifndef EFX_IO_H ++#define EFX_IO_H ++ ++#include ++#include ++ ++/************************************************************************** ++ * ++ * NIC register I/O ++ * ++ ************************************************************************** ++ * ++ * Notes on locking strategy: ++ * ++ * Most NIC registers require 16-byte (or 8-byte, for SRAM) atomic writes ++ * which necessitates locking. ++ * Under normal operation few writes to NIC registers are made and these ++ * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special ++ * cased to allow 4-byte (hence lockless) accesses. ++ * ++ * It *is* safe to write to these 4-byte registers in the middle of an ++ * access to an 8-byte or 16-byte register. We therefore use a ++ * spinlock to protect accesses to the larger registers, but no locks ++ * for the 4-byte registers. ++ * ++ * A write barrier is needed to ensure that DW3 is written after DW0/1/2 ++ * due to the way the 16byte registers are "collected" in the BIU. ++ * ++ * We also lock when carrying out reads, to ensure consistency of the ++ * data (made possible since the BIU reads all 128 bits into a cache). ++ * Reads are very rare, so this isn't a significant performance ++ * impact. (Most data transferred from NIC to host is DMAed directly ++ * into host memory). ++ * ++ * I/O BAR access uses locks for both reads and writes (but is only provided ++ * for testing purposes). ++ */ ++ ++#if BITS_PER_LONG == 64 ++#define EFX_USE_QWORD_IO 1 ++#endif ++ ++#ifdef EFX_USE_QWORD_IO ++static inline void _efx_writeq(struct efx_nic *efx, __le64 value, ++ unsigned int reg) ++{ ++ __raw_writeq((__force u64)value, efx->membase + reg); ++} ++static inline __le64 _efx_readq(struct efx_nic *efx, unsigned int reg) ++{ ++ return (__force __le64)__raw_readq(efx->membase + reg); ++} ++#endif ++ ++static inline void _efx_writed(struct efx_nic *efx, __le32 value, ++ unsigned int reg) ++{ ++ __raw_writel((__force u32)value, efx->membase + reg); ++} ++static inline __le32 _efx_readd(struct efx_nic *efx, unsigned int reg) ++{ ++ return (__force __le32)__raw_readl(efx->membase + reg); ++} ++ ++/* Writes to a normal 16-byte Efx register, locking as appropriate. */ ++static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value, ++ unsigned int reg) ++{ ++ unsigned long flags __attribute__ ((unused)); ++ ++ EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg, ++ EFX_OWORD_VAL(*value)); ++ ++ spin_lock_irqsave(&efx->biu_lock, flags); ++#ifdef EFX_USE_QWORD_IO ++ _efx_writeq(efx, value->u64[0], reg + 0); ++ wmb(); ++ _efx_writeq(efx, value->u64[1], reg + 8); ++#else ++ _efx_writed(efx, value->u32[0], reg + 0); ++ _efx_writed(efx, value->u32[1], reg + 4); ++ _efx_writed(efx, value->u32[2], reg + 8); ++ wmb(); ++ _efx_writed(efx, value->u32[3], reg + 12); ++#endif ++ mmiowb(); ++ spin_unlock_irqrestore(&efx->biu_lock, flags); ++} ++ ++/* Write an 8-byte NIC SRAM entry through the supplied mapping, ++ * locking as appropriate. */ ++static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase, ++ efx_qword_t *value, unsigned int index) ++{ ++ unsigned int addr = index * sizeof(*value); ++ unsigned long flags __attribute__ ((unused)); ++ ++ EFX_REGDUMP(efx, "writing SRAM address %x with " EFX_QWORD_FMT "\n", ++ addr, EFX_QWORD_VAL(*value)); ++ ++ spin_lock_irqsave(&efx->biu_lock, flags); ++#ifdef EFX_USE_QWORD_IO ++ __raw_writeq((__force u64)value->u64[0], membase + addr); ++#else ++ __raw_writel((__force u32)value->u32[0], membase + addr); ++ wmb(); ++ __raw_writel((__force u32)value->u32[1], membase + addr + 4); ++#endif ++ mmiowb(); ++ spin_unlock_irqrestore(&efx->biu_lock, flags); ++} ++ ++/* Write dword to NIC register that allows partial writes ++ * ++ * Some registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and ++ * TX_DESC_UPD_REG) can be written to as a single dword. This allows ++ * for lockless writes. ++ */ ++static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value, ++ unsigned int reg) ++{ ++ EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n", ++ reg, EFX_DWORD_VAL(*value)); ++ ++ /* No lock required */ ++ _efx_writed(efx, value->u32[0], reg); ++} ++ ++/* Read from a NIC register ++ * ++ * This reads an entire 16-byte register in one go, locking as ++ * appropriate. It is essential to read the first dword first, as this ++ * prompts the NIC to load the current value into the shadow register. ++ */ ++static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value, ++ unsigned int reg) ++{ ++ unsigned long flags __attribute__ ((unused)); ++ ++ spin_lock_irqsave(&efx->biu_lock, flags); ++ value->u32[0] = _efx_readd(efx, reg + 0); ++ rmb(); ++ value->u32[1] = _efx_readd(efx, reg + 4); ++ value->u32[2] = _efx_readd(efx, reg + 8); ++ value->u32[3] = _efx_readd(efx, reg + 12); ++ spin_unlock_irqrestore(&efx->biu_lock, flags); ++ ++ EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg, ++ EFX_OWORD_VAL(*value)); ++} ++ ++/* Read an 8-byte SRAM entry through supplied mapping, ++ * locking as appropriate. */ ++static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase, ++ efx_qword_t *value, unsigned int index) ++{ ++ unsigned int addr = index * sizeof(*value); ++ unsigned long flags __attribute__ ((unused)); ++ ++ spin_lock_irqsave(&efx->biu_lock, flags); ++#ifdef EFX_USE_QWORD_IO ++ value->u64[0] = (__force __le64)__raw_readq(membase + addr); ++#else ++ value->u32[0] = (__force __le32)__raw_readl(membase + addr); ++ rmb(); ++ value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4); ++#endif ++ spin_unlock_irqrestore(&efx->biu_lock, flags); ++ ++ EFX_REGDUMP(efx, "read from SRAM address %x, got "EFX_QWORD_FMT"\n", ++ addr, EFX_QWORD_VAL(*value)); ++} ++ ++/* Read dword from register that allows partial writes (sic) */ ++static inline void efx_readd(struct efx_nic *efx, efx_dword_t *value, ++ unsigned int reg) ++{ ++ value->u32[0] = _efx_readd(efx, reg); ++ EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n", ++ reg, EFX_DWORD_VAL(*value)); ++} ++ ++/* Write to a register forming part of a table */ ++static inline void efx_writeo_table(struct efx_nic *efx, efx_oword_t *value, ++ unsigned int reg, unsigned int index) ++{ ++ efx_writeo(efx, value, reg + index * sizeof(efx_oword_t)); ++} ++ ++/* Read to a register forming part of a table */ ++static inline void efx_reado_table(struct efx_nic *efx, efx_oword_t *value, ++ unsigned int reg, unsigned int index) ++{ ++ efx_reado(efx, value, reg + index * sizeof(efx_oword_t)); ++} ++ ++/* Write to a dword register forming part of a table */ ++static inline void efx_writed_table(struct efx_nic *efx, efx_dword_t *value, ++ unsigned int reg, unsigned int index) ++{ ++ efx_writed(efx, value, reg + index * sizeof(efx_oword_t)); ++} ++ ++/* Page-mapped register block size */ ++#define EFX_PAGE_BLOCK_SIZE 0x2000 ++ ++/* Calculate offset to page-mapped register block */ ++#define EFX_PAGED_REG(page, reg) \ ++ ((page) * EFX_PAGE_BLOCK_SIZE + (reg)) ++ ++/* As for efx_writeo(), but for a page-mapped register. */ ++static inline void efx_writeo_page(struct efx_nic *efx, efx_oword_t *value, ++ unsigned int reg, unsigned int page) ++{ ++ efx_writeo(efx, value, EFX_PAGED_REG(page, reg)); ++} ++ ++/* As for efx_writed(), but for a page-mapped register. */ ++static inline void efx_writed_page(struct efx_nic *efx, efx_dword_t *value, ++ unsigned int reg, unsigned int page) ++{ ++ efx_writed(efx, value, EFX_PAGED_REG(page, reg)); ++} ++ ++/* Write dword to page-mapped register with an extra lock. ++ * ++ * As for efx_writed_page(), but for a register that suffers from ++ * SFC bug 3181. Take out a lock so the BIU collector cannot be ++ * confused. */ ++static inline void efx_writed_page_locked(struct efx_nic *efx, ++ efx_dword_t *value, ++ unsigned int reg, ++ unsigned int page) ++{ ++ unsigned long flags __attribute__ ((unused)); ++ ++ if (page == 0) { ++ spin_lock_irqsave(&efx->biu_lock, flags); ++ efx_writed(efx, value, EFX_PAGED_REG(page, reg)); ++ spin_unlock_irqrestore(&efx->biu_lock, flags); ++ } else { ++ efx_writed(efx, value, EFX_PAGED_REG(page, reg)); ++ } ++} ++ ++#endif /* EFX_IO_H */ +diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h +index 4e70742..f1aa5f3 100644 +--- a/drivers/net/sfc/mac.h ++++ b/drivers/net/sfc/mac.h +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -15,5 +15,9 @@ + + extern struct efx_mac_operations falcon_gmac_operations; + extern struct efx_mac_operations falcon_xmac_operations; ++extern struct efx_mac_operations efx_mcdi_mac_operations; ++extern void falcon_reconfigure_xmac_core(struct efx_nic *efx); ++extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, ++ u32 dma_len, int enable, int clear); + + #endif +diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c +new file mode 100644 +index 0000000..683353b +--- /dev/null ++++ b/drivers/net/sfc/mcdi.c +@@ -0,0 +1,1112 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2008-2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++#include ++#include "net_driver.h" ++#include "nic.h" ++#include "io.h" ++#include "regs.h" ++#include "mcdi_pcol.h" ++#include "phy.h" ++ ++/************************************************************************** ++ * ++ * Management-Controller-to-Driver Interface ++ * ++ ************************************************************************** ++ */ ++ ++/* Software-defined structure to the shared-memory */ ++#define CMD_NOTIFY_PORT0 0 ++#define CMD_NOTIFY_PORT1 4 ++#define CMD_PDU_PORT0 0x008 ++#define CMD_PDU_PORT1 0x108 ++#define REBOOT_FLAG_PORT0 0x3f8 ++#define REBOOT_FLAG_PORT1 0x3fc ++ ++#define MCDI_RPC_TIMEOUT 10 /*seconds */ ++ ++#define MCDI_PDU(efx) \ ++ (efx_port_num(efx) ? CMD_PDU_PORT1 : CMD_PDU_PORT0) ++#define MCDI_DOORBELL(efx) \ ++ (efx_port_num(efx) ? CMD_NOTIFY_PORT1 : CMD_NOTIFY_PORT0) ++#define MCDI_REBOOT_FLAG(efx) \ ++ (efx_port_num(efx) ? REBOOT_FLAG_PORT1 : REBOOT_FLAG_PORT0) ++ ++#define SEQ_MASK \ ++ EFX_MASK32(EFX_WIDTH(MCDI_HEADER_SEQ)) ++ ++static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) ++{ ++ struct siena_nic_data *nic_data; ++ EFX_BUG_ON_PARANOID(efx_nic_rev(efx) < EFX_REV_SIENA_A0); ++ nic_data = efx->nic_data; ++ return &nic_data->mcdi; ++} ++ ++void efx_mcdi_init(struct efx_nic *efx) ++{ ++ struct efx_mcdi_iface *mcdi; ++ ++ if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) ++ return; ++ ++ mcdi = efx_mcdi(efx); ++ init_waitqueue_head(&mcdi->wq); ++ spin_lock_init(&mcdi->iface_lock); ++ atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT); ++ mcdi->mode = MCDI_MODE_POLL; ++ ++ (void) efx_mcdi_poll_reboot(efx); ++} ++ ++static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, ++ const u8 *inbuf, size_t inlen) ++{ ++ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); ++ unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); ++ unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); ++ unsigned int i; ++ efx_dword_t hdr; ++ u32 xflags, seqno; ++ ++ BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); ++ BUG_ON(inlen & 3 || inlen >= 0x100); ++ ++ seqno = mcdi->seqno & SEQ_MASK; ++ xflags = 0; ++ if (mcdi->mode == MCDI_MODE_EVENTS) ++ xflags |= MCDI_HEADER_XFLAGS_EVREQ; ++ ++ EFX_POPULATE_DWORD_6(hdr, ++ MCDI_HEADER_RESPONSE, 0, ++ MCDI_HEADER_RESYNC, 1, ++ MCDI_HEADER_CODE, cmd, ++ MCDI_HEADER_DATALEN, inlen, ++ MCDI_HEADER_SEQ, seqno, ++ MCDI_HEADER_XFLAGS, xflags); ++ ++ efx_writed(efx, &hdr, pdu); ++ ++ for (i = 0; i < inlen; i += 4) ++ _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i); ++ ++ /* Ensure the payload is written out before the header */ ++ wmb(); ++ ++ /* ring the doorbell with a distinctive value */ ++ _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); ++} ++ ++static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen) ++{ ++ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); ++ unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); ++ int i; ++ ++ BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); ++ BUG_ON(outlen & 3 || outlen >= 0x100); ++ ++ for (i = 0; i < outlen; i += 4) ++ *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i); ++} ++ ++static int efx_mcdi_poll(struct efx_nic *efx) ++{ ++ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); ++ unsigned int time, finish; ++ unsigned int respseq, respcmd, error; ++ unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); ++ unsigned int rc, spins; ++ efx_dword_t reg; ++ ++ /* Check for a reboot atomically with respect to efx_mcdi_copyout() */ ++ rc = efx_mcdi_poll_reboot(efx); ++ if (rc) ++ goto out; ++ ++ /* Poll for completion. Poll quickly (once a us) for the 1st jiffy, ++ * because generally mcdi responses are fast. After that, back off ++ * and poll once a jiffy (approximately) ++ */ ++ spins = TICK_USEC; ++ finish = get_seconds() + MCDI_RPC_TIMEOUT; ++ ++ while (1) { ++ if (spins != 0) { ++ --spins; ++ udelay(1); ++ } else ++ schedule(); ++ ++ time = get_seconds(); ++ ++ rmb(); ++ efx_readd(efx, ®, pdu); ++ ++ /* All 1's indicates that shared memory is in reset (and is ++ * not a valid header). Wait for it to come out reset before ++ * completing the command */ ++ if (EFX_DWORD_FIELD(reg, EFX_DWORD_0) != 0xffffffff && ++ EFX_DWORD_FIELD(reg, MCDI_HEADER_RESPONSE)) ++ break; ++ ++ if (time >= finish) ++ return -ETIMEDOUT; ++ } ++ ++ mcdi->resplen = EFX_DWORD_FIELD(reg, MCDI_HEADER_DATALEN); ++ respseq = EFX_DWORD_FIELD(reg, MCDI_HEADER_SEQ); ++ respcmd = EFX_DWORD_FIELD(reg, MCDI_HEADER_CODE); ++ error = EFX_DWORD_FIELD(reg, MCDI_HEADER_ERROR); ++ ++ if (error && mcdi->resplen == 0) { ++ EFX_ERR(efx, "MC rebooted\n"); ++ rc = EIO; ++ } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) { ++ EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx seq 0x%x\n", ++ respseq, mcdi->seqno); ++ rc = EIO; ++ } else if (error) { ++ efx_readd(efx, ®, pdu + 4); ++ switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { ++#define TRANSLATE_ERROR(name) \ ++ case MC_CMD_ERR_ ## name: \ ++ rc = name; \ ++ break ++ TRANSLATE_ERROR(ENOENT); ++ TRANSLATE_ERROR(EINTR); ++ TRANSLATE_ERROR(EACCES); ++ TRANSLATE_ERROR(EBUSY); ++ TRANSLATE_ERROR(EINVAL); ++ TRANSLATE_ERROR(EDEADLK); ++ TRANSLATE_ERROR(ENOSYS); ++ TRANSLATE_ERROR(ETIME); ++#undef TRANSLATE_ERROR ++ default: ++ rc = EIO; ++ break; ++ } ++ } else ++ rc = 0; ++ ++out: ++ mcdi->resprc = rc; ++ if (rc) ++ mcdi->resplen = 0; ++ ++ /* Return rc=0 like wait_event_timeout() */ ++ return 0; ++} ++ ++/* Test and clear MC-rebooted flag for this port/function */ ++int efx_mcdi_poll_reboot(struct efx_nic *efx) ++{ ++ unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx); ++ efx_dword_t reg; ++ uint32_t value; ++ ++ if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) ++ return false; ++ ++ efx_readd(efx, ®, addr); ++ value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); ++ ++ if (value == 0) ++ return 0; ++ ++ EFX_ZERO_DWORD(reg); ++ efx_writed(efx, ®, addr); ++ ++ if (value == MC_STATUS_DWORD_ASSERT) ++ return -EINTR; ++ else ++ return -EIO; ++} ++ ++static void efx_mcdi_acquire(struct efx_mcdi_iface *mcdi) ++{ ++ /* Wait until the interface becomes QUIESCENT and we win the race ++ * to mark it RUNNING. */ ++ wait_event(mcdi->wq, ++ atomic_cmpxchg(&mcdi->state, ++ MCDI_STATE_QUIESCENT, ++ MCDI_STATE_RUNNING) ++ == MCDI_STATE_QUIESCENT); ++} ++ ++static int efx_mcdi_await_completion(struct efx_nic *efx) ++{ ++ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); ++ ++ if (wait_event_timeout( ++ mcdi->wq, ++ atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED, ++ msecs_to_jiffies(MCDI_RPC_TIMEOUT * 1000)) == 0) ++ return -ETIMEDOUT; ++ ++ /* Check if efx_mcdi_set_mode() switched us back to polled completions. ++ * In which case, poll for completions directly. If efx_mcdi_ev_cpl() ++ * completed the request first, then we'll just end up completing the ++ * request again, which is safe. ++ * ++ * We need an smp_rmb() to synchronise with efx_mcdi_mode_poll(), which ++ * wait_event_timeout() implicitly provides. ++ */ ++ if (mcdi->mode == MCDI_MODE_POLL) ++ return efx_mcdi_poll(efx); ++ ++ return 0; ++} ++ ++static bool efx_mcdi_complete(struct efx_mcdi_iface *mcdi) ++{ ++ /* If the interface is RUNNING, then move to COMPLETED and wake any ++ * waiters. If the interface isn't in RUNNING then we've received a ++ * duplicate completion after we've already transitioned back to ++ * QUIESCENT. [A subsequent invocation would increment seqno, so would ++ * have failed the seqno check]. ++ */ ++ if (atomic_cmpxchg(&mcdi->state, ++ MCDI_STATE_RUNNING, ++ MCDI_STATE_COMPLETED) == MCDI_STATE_RUNNING) { ++ wake_up(&mcdi->wq); ++ return true; ++ } ++ ++ return false; ++} ++ ++static void efx_mcdi_release(struct efx_mcdi_iface *mcdi) ++{ ++ atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT); ++ wake_up(&mcdi->wq); ++} ++ ++static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno, ++ unsigned int datalen, unsigned int errno) ++{ ++ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); ++ bool wake = false; ++ ++ spin_lock(&mcdi->iface_lock); ++ ++ if ((seqno ^ mcdi->seqno) & SEQ_MASK) { ++ if (mcdi->credits) ++ /* The request has been cancelled */ ++ --mcdi->credits; ++ else ++ EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx " ++ "seq 0x%x\n", seqno, mcdi->seqno); ++ } else { ++ mcdi->resprc = errno; ++ mcdi->resplen = datalen; ++ ++ wake = true; ++ } ++ ++ spin_unlock(&mcdi->iface_lock); ++ ++ if (wake) ++ efx_mcdi_complete(mcdi); ++} ++ ++/* Issue the given command by writing the data into the shared memory PDU, ++ * ring the doorbell and wait for completion. Copyout the result. */ ++int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, ++ const u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen, ++ size_t *outlen_actual) ++{ ++ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); ++ int rc; ++ BUG_ON(efx_nic_rev(efx) < EFX_REV_SIENA_A0); ++ ++ efx_mcdi_acquire(mcdi); ++ ++ /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */ ++ spin_lock_bh(&mcdi->iface_lock); ++ ++mcdi->seqno; ++ spin_unlock_bh(&mcdi->iface_lock); ++ ++ efx_mcdi_copyin(efx, cmd, inbuf, inlen); ++ ++ if (mcdi->mode == MCDI_MODE_POLL) ++ rc = efx_mcdi_poll(efx); ++ else ++ rc = efx_mcdi_await_completion(efx); ++ ++ if (rc != 0) { ++ /* Close the race with efx_mcdi_ev_cpl() executing just too late ++ * and completing a request we've just cancelled, by ensuring ++ * that the seqno check therein fails. ++ */ ++ spin_lock_bh(&mcdi->iface_lock); ++ ++mcdi->seqno; ++ ++mcdi->credits; ++ spin_unlock_bh(&mcdi->iface_lock); ++ ++ EFX_ERR(efx, "MC command 0x%x inlen %d mode %d timed out\n", ++ cmd, (int)inlen, mcdi->mode); ++ } else { ++ size_t resplen; ++ ++ /* At the very least we need a memory barrier here to ensure ++ * we pick up changes from efx_mcdi_ev_cpl(). Protect against ++ * a spurious efx_mcdi_ev_cpl() running concurrently by ++ * acquiring the iface_lock. */ ++ spin_lock_bh(&mcdi->iface_lock); ++ rc = -mcdi->resprc; ++ resplen = mcdi->resplen; ++ spin_unlock_bh(&mcdi->iface_lock); ++ ++ if (rc == 0) { ++ efx_mcdi_copyout(efx, outbuf, ++ min(outlen, mcdi->resplen + 3) & ~0x3); ++ if (outlen_actual != NULL) ++ *outlen_actual = resplen; ++ } else if (cmd == MC_CMD_REBOOT && rc == -EIO) ++ ; /* Don't reset if MC_CMD_REBOOT returns EIO */ ++ else if (rc == -EIO || rc == -EINTR) { ++ EFX_ERR(efx, "MC fatal error %d\n", -rc); ++ efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE); ++ } else ++ EFX_ERR(efx, "MC command 0x%x inlen %d failed rc=%d\n", ++ cmd, (int)inlen, -rc); ++ } ++ ++ efx_mcdi_release(mcdi); ++ return rc; ++} ++ ++void efx_mcdi_mode_poll(struct efx_nic *efx) ++{ ++ struct efx_mcdi_iface *mcdi; ++ ++ if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) ++ return; ++ ++ mcdi = efx_mcdi(efx); ++ if (mcdi->mode == MCDI_MODE_POLL) ++ return; ++ ++ /* We can switch from event completion to polled completion, because ++ * mcdi requests are always completed in shared memory. We do this by ++ * switching the mode to POLL'd then completing the request. ++ * efx_mcdi_await_completion() will then call efx_mcdi_poll(). ++ * ++ * We need an smp_wmb() to synchronise with efx_mcdi_await_completion(), ++ * which efx_mcdi_complete() provides for us. ++ */ ++ mcdi->mode = MCDI_MODE_POLL; ++ ++ efx_mcdi_complete(mcdi); ++} ++ ++void efx_mcdi_mode_event(struct efx_nic *efx) ++{ ++ struct efx_mcdi_iface *mcdi; ++ ++ if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) ++ return; ++ ++ mcdi = efx_mcdi(efx); ++ ++ if (mcdi->mode == MCDI_MODE_EVENTS) ++ return; ++ ++ /* We can't switch from polled to event completion in the middle of a ++ * request, because the completion method is specified in the request. ++ * So acquire the interface to serialise the requestors. We don't need ++ * to acquire the iface_lock to change the mode here, but we do need a ++ * write memory barrier ensure that efx_mcdi_rpc() sees it, which ++ * efx_mcdi_acquire() provides. ++ */ ++ efx_mcdi_acquire(mcdi); ++ mcdi->mode = MCDI_MODE_EVENTS; ++ efx_mcdi_release(mcdi); ++} ++ ++static void efx_mcdi_ev_death(struct efx_nic *efx, int rc) ++{ ++ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); ++ ++ /* If there is an outstanding MCDI request, it has been terminated ++ * either by a BADASSERT or REBOOT event. If the mcdi interface is ++ * in polled mode, then do nothing because the MC reboot handler will ++ * set the header correctly. However, if the mcdi interface is waiting ++ * for a CMDDONE event it won't receive it [and since all MCDI events ++ * are sent to the same queue, we can't be racing with ++ * efx_mcdi_ev_cpl()] ++ * ++ * There's a race here with efx_mcdi_rpc(), because we might receive ++ * a REBOOT event *before* the request has been copied out. In polled ++ * mode (during startup) this is irrelevent, because efx_mcdi_complete() ++ * is ignored. In event mode, this condition is just an edge-case of ++ * receiving a REBOOT event after posting the MCDI request. Did the mc ++ * reboot before or after the copyout? The best we can do always is ++ * just return failure. ++ */ ++ spin_lock(&mcdi->iface_lock); ++ if (efx_mcdi_complete(mcdi)) { ++ if (mcdi->mode == MCDI_MODE_EVENTS) { ++ mcdi->resprc = rc; ++ mcdi->resplen = 0; ++ } ++ } else ++ /* Nobody was waiting for an MCDI request, so trigger a reset */ ++ efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE); ++ ++ spin_unlock(&mcdi->iface_lock); ++} ++ ++static unsigned int efx_mcdi_event_link_speed[] = { ++ [MCDI_EVENT_LINKCHANGE_SPEED_100M] = 100, ++ [MCDI_EVENT_LINKCHANGE_SPEED_1G] = 1000, ++ [MCDI_EVENT_LINKCHANGE_SPEED_10G] = 10000, ++}; ++ ++ ++static void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev) ++{ ++ u32 flags, fcntl, speed, lpa; ++ ++ speed = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_SPEED); ++ EFX_BUG_ON_PARANOID(speed >= ARRAY_SIZE(efx_mcdi_event_link_speed)); ++ speed = efx_mcdi_event_link_speed[speed]; ++ ++ flags = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LINK_FLAGS); ++ fcntl = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_FCNTL); ++ lpa = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LP_CAP); ++ ++ /* efx->link_state is only modified by efx_mcdi_phy_get_link(), ++ * which is only run after flushing the event queues. Therefore, it ++ * is safe to modify the link state outside of the mac_lock here. ++ */ ++ efx_mcdi_phy_decode_link(efx, &efx->link_state, speed, flags, fcntl); ++ ++ efx_mcdi_phy_check_fcntl(efx, lpa); ++ ++ efx_link_status_changed(efx); ++} ++ ++static const char *sensor_names[] = { ++ [MC_CMD_SENSOR_CONTROLLER_TEMP] = "Controller temp. sensor", ++ [MC_CMD_SENSOR_PHY_COMMON_TEMP] = "PHY shared temp. sensor", ++ [MC_CMD_SENSOR_CONTROLLER_COOLING] = "Controller cooling", ++ [MC_CMD_SENSOR_PHY0_TEMP] = "PHY 0 temp. sensor", ++ [MC_CMD_SENSOR_PHY0_COOLING] = "PHY 0 cooling", ++ [MC_CMD_SENSOR_PHY1_TEMP] = "PHY 1 temp. sensor", ++ [MC_CMD_SENSOR_PHY1_COOLING] = "PHY 1 cooling", ++ [MC_CMD_SENSOR_IN_1V0] = "1.0V supply sensor", ++ [MC_CMD_SENSOR_IN_1V2] = "1.2V supply sensor", ++ [MC_CMD_SENSOR_IN_1V8] = "1.8V supply sensor", ++ [MC_CMD_SENSOR_IN_2V5] = "2.5V supply sensor", ++ [MC_CMD_SENSOR_IN_3V3] = "3.3V supply sensor", ++ [MC_CMD_SENSOR_IN_12V0] = "12V supply sensor" ++}; ++ ++static const char *sensor_status_names[] = { ++ [MC_CMD_SENSOR_STATE_OK] = "OK", ++ [MC_CMD_SENSOR_STATE_WARNING] = "Warning", ++ [MC_CMD_SENSOR_STATE_FATAL] = "Fatal", ++ [MC_CMD_SENSOR_STATE_BROKEN] = "Device failure", ++}; ++ ++static void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev) ++{ ++ unsigned int monitor, state, value; ++ const char *name, *state_txt; ++ monitor = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR); ++ state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE); ++ value = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_VALUE); ++ /* Deal gracefully with the board having more drivers than we ++ * know about, but do not expect new sensor states. */ ++ name = (monitor >= ARRAY_SIZE(sensor_names)) ++ ? "No sensor name available" : ++ sensor_names[monitor]; ++ EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names)); ++ state_txt = sensor_status_names[state]; ++ ++ EFX_ERR(efx, "Sensor %d (%s) reports condition '%s' for raw value %d\n", ++ monitor, name, state_txt, value); ++} ++ ++/* Called from falcon_process_eventq for MCDI events */ ++void efx_mcdi_process_event(struct efx_channel *channel, ++ efx_qword_t *event) ++{ ++ struct efx_nic *efx = channel->efx; ++ int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE); ++ u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA); ++ ++ switch (code) { ++ case MCDI_EVENT_CODE_BADSSERT: ++ EFX_ERR(efx, "MC watchdog or assertion failure at 0x%x\n", data); ++ efx_mcdi_ev_death(efx, EINTR); ++ break; ++ ++ case MCDI_EVENT_CODE_PMNOTICE: ++ EFX_INFO(efx, "MCDI PM event.\n"); ++ break; ++ ++ case MCDI_EVENT_CODE_CMDDONE: ++ efx_mcdi_ev_cpl(efx, ++ MCDI_EVENT_FIELD(*event, CMDDONE_SEQ), ++ MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN), ++ MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO)); ++ break; ++ ++ case MCDI_EVENT_CODE_LINKCHANGE: ++ efx_mcdi_process_link_change(efx, event); ++ break; ++ case MCDI_EVENT_CODE_SENSOREVT: ++ efx_mcdi_sensor_event(efx, event); ++ break; ++ case MCDI_EVENT_CODE_SCHEDERR: ++ EFX_INFO(efx, "MC Scheduler error address=0x%x\n", data); ++ break; ++ case MCDI_EVENT_CODE_REBOOT: ++ EFX_INFO(efx, "MC Reboot\n"); ++ efx_mcdi_ev_death(efx, EIO); ++ break; ++ case MCDI_EVENT_CODE_MAC_STATS_DMA: ++ /* MAC stats are gather lazily. We can ignore this. */ ++ break; ++ ++ default: ++ EFX_ERR(efx, "Unknown MCDI event 0x%x\n", code); ++ } ++} ++ ++/************************************************************************** ++ * ++ * Specific request functions ++ * ++ ************************************************************************** ++ */ ++ ++int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build) ++{ ++ u8 outbuf[ALIGN(MC_CMD_GET_VERSION_V1_OUT_LEN, 4)]; ++ size_t outlength; ++ const __le16 *ver_words; ++ int rc; ++ ++ BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, 0, ++ outbuf, sizeof(outbuf), &outlength); ++ if (rc) ++ goto fail; ++ ++ if (outlength == MC_CMD_GET_VERSION_V0_OUT_LEN) { ++ *version = 0; ++ *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE); ++ return 0; ++ } ++ ++ if (outlength < MC_CMD_GET_VERSION_V1_OUT_LEN) { ++ rc = -EMSGSIZE; ++ goto fail; ++ } ++ ++ ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION); ++ *version = (((u64)le16_to_cpu(ver_words[0]) << 48) | ++ ((u64)le16_to_cpu(ver_words[1]) << 32) | ++ ((u64)le16_to_cpu(ver_words[2]) << 16) | ++ le16_to_cpu(ver_words[3])); ++ *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE); ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, ++ bool *was_attached) ++{ ++ u8 inbuf[MC_CMD_DRV_ATTACH_IN_LEN]; ++ u8 outbuf[MC_CMD_DRV_ATTACH_OUT_LEN]; ++ size_t outlen; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE, ++ driver_operating ? 1 : 0); ++ MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf), ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) ++ goto fail; ++ ++ if (was_attached != NULL) ++ *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE); ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, ++ u16 *fw_subtype_list) ++{ ++ uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LEN]; ++ size_t outlen; ++ int port_num = efx_port_num(efx); ++ int offset; ++ int rc; ++ ++ BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0, ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ ++ if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LEN) { ++ rc = -EMSGSIZE; ++ goto fail; ++ } ++ ++ offset = (port_num) ++ ? MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST ++ : MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST; ++ if (mac_address) ++ memcpy(mac_address, outbuf + offset, ETH_ALEN); ++ if (fw_subtype_list) ++ memcpy(fw_subtype_list, ++ outbuf + MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST, ++ MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN); ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d len=%d\n", __func__, rc, (int)outlen); ++ ++ return rc; ++} ++ ++int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq) ++{ ++ u8 inbuf[MC_CMD_LOG_CTRL_IN_LEN]; ++ u32 dest = 0; ++ int rc; ++ ++ if (uart) ++ dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_UART; ++ if (evq) ++ dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ; ++ ++ MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST, dest); ++ MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST_EVQ, dest_evq); ++ ++ BUILD_BUG_ON(MC_CMD_LOG_CTRL_OUT_LEN != 0); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf), ++ NULL, 0, NULL); ++ if (rc) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out) ++{ ++ u8 outbuf[MC_CMD_NVRAM_TYPES_OUT_LEN]; ++ size_t outlen; ++ int rc; ++ ++ BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, 0, ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) ++ goto fail; ++ ++ *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES); ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", ++ __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, ++ size_t *size_out, size_t *erase_size_out, ++ bool *protected_out) ++{ ++ u8 inbuf[MC_CMD_NVRAM_INFO_IN_LEN]; ++ u8 outbuf[MC_CMD_NVRAM_INFO_OUT_LEN]; ++ size_t outlen; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, sizeof(inbuf), ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) ++ goto fail; ++ ++ *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE); ++ *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE); ++ *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) & ++ (1 << MC_CMD_NVRAM_PROTECTED_LBN)); ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type) ++{ ++ u8 inbuf[MC_CMD_NVRAM_UPDATE_START_IN_LEN]; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type); ++ ++ BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf), ++ NULL, 0, NULL); ++ if (rc) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, ++ loff_t offset, u8 *buffer, size_t length) ++{ ++ u8 inbuf[MC_CMD_NVRAM_READ_IN_LEN]; ++ u8 outbuf[MC_CMD_NVRAM_READ_OUT_LEN(length)]; ++ size_t outlen; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type); ++ MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset); ++ MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf), ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ ++ memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length); ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, ++ loff_t offset, const u8 *buffer, size_t length) ++{ ++ u8 inbuf[MC_CMD_NVRAM_WRITE_IN_LEN(length)]; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type); ++ MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset); ++ MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length); ++ memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length); ++ ++ BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, sizeof(inbuf), ++ NULL, 0, NULL); ++ if (rc) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, ++ loff_t offset, size_t length) ++{ ++ u8 inbuf[MC_CMD_NVRAM_ERASE_IN_LEN]; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type); ++ MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset); ++ MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length); ++ ++ BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf), ++ NULL, 0, NULL); ++ if (rc) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type) ++{ ++ u8 inbuf[MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN]; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type); ++ ++ BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf), ++ NULL, 0, NULL); ++ if (rc) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_handle_assertion(struct efx_nic *efx) ++{ ++ union { ++ u8 asserts[MC_CMD_GET_ASSERTS_IN_LEN]; ++ u8 reboot[MC_CMD_REBOOT_IN_LEN]; ++ } inbuf; ++ u8 assertion[MC_CMD_GET_ASSERTS_OUT_LEN]; ++ unsigned int flags, index, ofst; ++ const char *reason; ++ size_t outlen; ++ int retry; ++ int rc; ++ ++ /* Check if the MC is in the assertion handler, retrying twice. Once ++ * because a boot-time assertion might cause this command to fail ++ * with EINTR. And once again because GET_ASSERTS can race with ++ * MC_CMD_REBOOT running on the other port. */ ++ retry = 2; ++ do { ++ MCDI_SET_DWORD(inbuf.asserts, GET_ASSERTS_IN_CLEAR, 0); ++ rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS, ++ inbuf.asserts, MC_CMD_GET_ASSERTS_IN_LEN, ++ assertion, sizeof(assertion), &outlen); ++ } while ((rc == -EINTR || rc == -EIO) && retry-- > 0); ++ ++ if (rc) ++ return rc; ++ if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN) ++ return -EINVAL; ++ ++ flags = MCDI_DWORD(assertion, GET_ASSERTS_OUT_GLOBAL_FLAGS); ++ if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) ++ return 0; ++ ++ /* Reset the hardware atomically such that only one port with succeed. ++ * This command will succeed if a reboot is no longer required (because ++ * the other port did it first), but fail with EIO if it succeeds. ++ */ ++ BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); ++ MCDI_SET_DWORD(inbuf.reboot, REBOOT_IN_FLAGS, ++ MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION); ++ efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf.reboot, MC_CMD_REBOOT_IN_LEN, ++ NULL, 0, NULL); ++ ++ /* Print out the assertion */ ++ reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) ++ ? "system-level assertion" ++ : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) ++ ? "thread-level assertion" ++ : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) ++ ? "watchdog reset" ++ : "unknown assertion"; ++ EFX_ERR(efx, "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason, ++ MCDI_DWORD(assertion, GET_ASSERTS_OUT_SAVED_PC_OFFS), ++ MCDI_DWORD(assertion, GET_ASSERTS_OUT_THREAD_OFFS)); ++ ++ /* Print out the registers */ ++ ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; ++ for (index = 1; index < 32; index++) { ++ EFX_ERR(efx, "R%.2d (?): 0x%.8x\n", index, ++ MCDI_DWORD2(assertion, ofst)); ++ ofst += sizeof(efx_dword_t); ++ } ++ ++ return 0; ++} ++ ++void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) ++{ ++ u8 inbuf[MC_CMD_SET_ID_LED_IN_LEN]; ++ int rc; ++ ++ BUILD_BUG_ON(EFX_LED_OFF != MC_CMD_LED_OFF); ++ BUILD_BUG_ON(EFX_LED_ON != MC_CMD_LED_ON); ++ BUILD_BUG_ON(EFX_LED_DEFAULT != MC_CMD_LED_DEFAULT); ++ ++ BUILD_BUG_ON(MC_CMD_SET_ID_LED_OUT_LEN != 0); ++ ++ MCDI_SET_DWORD(inbuf, SET_ID_LED_IN_STATE, mode); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf), ++ NULL, 0, NULL); ++ if (rc) ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++} ++ ++int efx_mcdi_reset_port(struct efx_nic *efx) ++{ ++ int rc = efx_mcdi_rpc(efx, MC_CMD_PORT_RESET, NULL, 0, NULL, 0, NULL); ++ if (rc) ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_reset_mc(struct efx_nic *efx) ++{ ++ u8 inbuf[MC_CMD_REBOOT_IN_LEN]; ++ int rc; ++ ++ BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); ++ MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0); ++ rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, sizeof(inbuf), ++ NULL, 0, NULL); ++ /* White is black, and up is down */ ++ if (rc == -EIO) ++ return 0; ++ if (rc == 0) ++ rc = -EIO; ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, ++ const u8 *mac, int *id_out) ++{ ++ u8 inbuf[MC_CMD_WOL_FILTER_SET_IN_LEN]; ++ u8 outbuf[MC_CMD_WOL_FILTER_SET_OUT_LEN]; ++ size_t outlen; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type); ++ MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE, ++ MC_CMD_FILTER_MODE_SIMPLE); ++ memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf), ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ ++ if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) { ++ rc = -EMSGSIZE; ++ goto fail; ++ } ++ ++ *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID); ++ ++ return 0; ++ ++fail: ++ *id_out = -1; ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++ ++} ++ ++ ++int ++efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out) ++{ ++ return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out); ++} ++ ++ ++int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out) ++{ ++ u8 outbuf[MC_CMD_WOL_FILTER_GET_OUT_LEN]; ++ size_t outlen; ++ int rc; ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0, ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ ++ if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) { ++ rc = -EMSGSIZE; ++ goto fail; ++ } ++ ++ *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID); ++ ++ return 0; ++ ++fail: ++ *id_out = -1; ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++ ++int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id) ++{ ++ u8 inbuf[MC_CMD_WOL_FILTER_REMOVE_IN_LEN]; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, WOL_FILTER_REMOVE_IN_FILTER_ID, (u32)id); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf), ++ NULL, 0, NULL); ++ if (rc) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++ ++int efx_mcdi_wol_filter_reset(struct efx_nic *efx) ++{ ++ int rc; ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL); ++ if (rc) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ +diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h +new file mode 100644 +index 0000000..de91672 +--- /dev/null ++++ b/drivers/net/sfc/mcdi.h +@@ -0,0 +1,130 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2008-2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++#ifndef EFX_MCDI_H ++#define EFX_MCDI_H ++ ++/** ++ * enum efx_mcdi_state ++ * @MCDI_STATE_QUIESCENT: No pending MCDI requests. If the caller holds the ++ * mcdi_lock then they are able to move to MCDI_STATE_RUNNING ++ * @MCDI_STATE_RUNNING: There is an MCDI request pending. Only the thread that ++ * moved into this state is allowed to move out of it. ++ * @MCDI_STATE_COMPLETED: An MCDI request has completed, but the owning thread ++ * has not yet consumed the result. For all other threads, equivalent to ++ * MCDI_STATE_RUNNING. ++ */ ++enum efx_mcdi_state { ++ MCDI_STATE_QUIESCENT, ++ MCDI_STATE_RUNNING, ++ MCDI_STATE_COMPLETED, ++}; ++ ++enum efx_mcdi_mode { ++ MCDI_MODE_POLL, ++ MCDI_MODE_EVENTS, ++}; ++ ++/** ++ * struct efx_mcdi_iface ++ * @state: Interface state. Waited for by mcdi_wq. ++ * @wq: Wait queue for threads waiting for state != STATE_RUNNING ++ * @iface_lock: Protects @credits, @seqno, @resprc, @resplen ++ * @mode: Poll for mcdi completion, or wait for an mcdi_event. ++ * Serialised by @lock ++ * @seqno: The next sequence number to use for mcdi requests. ++ * Serialised by @lock ++ * @credits: Number of spurious MCDI completion events allowed before we ++ * trigger a fatal error. Protected by @lock ++ * @resprc: Returned MCDI completion ++ * @resplen: Returned payload length ++ */ ++struct efx_mcdi_iface { ++ atomic_t state; ++ wait_queue_head_t wq; ++ spinlock_t iface_lock; ++ enum efx_mcdi_mode mode; ++ unsigned int credits; ++ unsigned int seqno; ++ unsigned int resprc; ++ size_t resplen; ++}; ++ ++extern void efx_mcdi_init(struct efx_nic *efx); ++ ++extern int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const u8 *inbuf, ++ size_t inlen, u8 *outbuf, size_t outlen, ++ size_t *outlen_actual); ++ ++extern int efx_mcdi_poll_reboot(struct efx_nic *efx); ++extern void efx_mcdi_mode_poll(struct efx_nic *efx); ++extern void efx_mcdi_mode_event(struct efx_nic *efx); ++ ++extern void efx_mcdi_process_event(struct efx_channel *channel, ++ efx_qword_t *event); ++ ++#define MCDI_PTR2(_buf, _ofst) \ ++ (((u8 *)_buf) + _ofst) ++#define MCDI_SET_DWORD2(_buf, _ofst, _value) \ ++ EFX_POPULATE_DWORD_1(*((efx_dword_t *)MCDI_PTR2(_buf, _ofst)), \ ++ EFX_DWORD_0, _value) ++#define MCDI_DWORD2(_buf, _ofst) \ ++ EFX_DWORD_FIELD(*((efx_dword_t *)MCDI_PTR2(_buf, _ofst)), \ ++ EFX_DWORD_0) ++#define MCDI_QWORD2(_buf, _ofst) \ ++ EFX_QWORD_FIELD64(*((efx_qword_t *)MCDI_PTR2(_buf, _ofst)), \ ++ EFX_QWORD_0) ++ ++#define MCDI_PTR(_buf, _ofst) \ ++ MCDI_PTR2(_buf, MC_CMD_ ## _ofst ## _OFST) ++#define MCDI_SET_DWORD(_buf, _ofst, _value) \ ++ MCDI_SET_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST, _value) ++#define MCDI_DWORD(_buf, _ofst) \ ++ MCDI_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST) ++#define MCDI_QWORD(_buf, _ofst) \ ++ MCDI_QWORD2(_buf, MC_CMD_ ## _ofst ## _OFST) ++ ++#define MCDI_EVENT_FIELD(_ev, _field) \ ++ EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field) ++ ++extern int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build); ++extern int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, ++ bool *was_attached_out); ++extern int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, ++ u16 *fw_subtype_list); ++extern int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, ++ u32 dest_evq); ++extern int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out); ++extern int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, ++ size_t *size_out, size_t *erase_size_out, ++ bool *protected_out); ++extern int efx_mcdi_nvram_update_start(struct efx_nic *efx, ++ unsigned int type); ++extern int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, ++ loff_t offset, u8 *buffer, size_t length); ++extern int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, ++ loff_t offset, const u8 *buffer, ++ size_t length); ++extern int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, ++ loff_t offset, size_t length); ++extern int efx_mcdi_nvram_update_finish(struct efx_nic *efx, ++ unsigned int type); ++extern int efx_mcdi_handle_assertion(struct efx_nic *efx); ++extern void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); ++extern int efx_mcdi_reset_port(struct efx_nic *efx); ++extern int efx_mcdi_reset_mc(struct efx_nic *efx); ++extern int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, ++ const u8 *mac, int *id_out); ++extern int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, ++ const u8 *mac, int *id_out); ++extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out); ++extern int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id); ++extern int efx_mcdi_wol_filter_reset(struct efx_nic *efx); ++ ++#endif /* EFX_MCDI_H */ +diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c +new file mode 100644 +index 0000000..06d24a1 +--- /dev/null ++++ b/drivers/net/sfc/mcdi_mac.c +@@ -0,0 +1,152 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++#include "net_driver.h" ++#include "efx.h" ++#include "mac.h" ++#include "mcdi.h" ++#include "mcdi_pcol.h" ++ ++static int efx_mcdi_set_mac(struct efx_nic *efx) ++{ ++ u32 reject, fcntl; ++ u8 cmdbytes[MC_CMD_SET_MAC_IN_LEN]; ++ ++ memcpy(cmdbytes + MC_CMD_SET_MAC_IN_ADDR_OFST, ++ efx->net_dev->dev_addr, ETH_ALEN); ++ ++ MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU, ++ EFX_MAX_FRAME_LEN(efx->net_dev->mtu)); ++ MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_DRAIN, 0); ++ ++ /* The MCDI command provides for controlling accept/reject ++ * of broadcast packets too, but the driver doesn't currently ++ * expose this. */ ++ reject = (efx->promiscuous) ? 0 : ++ (1 << MC_CMD_SET_MAC_IN_REJECT_UNCST_LBN); ++ MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_REJECT, reject); ++ ++ switch (efx->wanted_fc) { ++ case EFX_FC_RX | EFX_FC_TX: ++ fcntl = MC_CMD_FCNTL_BIDIR; ++ break; ++ case EFX_FC_RX: ++ fcntl = MC_CMD_FCNTL_RESPOND; ++ break; ++ default: ++ fcntl = MC_CMD_FCNTL_OFF; ++ break; ++ } ++ if (efx->wanted_fc & EFX_FC_AUTO) ++ fcntl = MC_CMD_FCNTL_AUTO; ++ ++ MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_FCNTL, fcntl); ++ ++ return efx_mcdi_rpc(efx, MC_CMD_SET_MAC, cmdbytes, sizeof(cmdbytes), ++ NULL, 0, NULL); ++} ++ ++static int efx_mcdi_get_mac_faults(struct efx_nic *efx, u32 *faults) ++{ ++ u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; ++ size_t outlength; ++ int rc; ++ ++ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, ++ outbuf, sizeof(outbuf), &outlength); ++ if (rc) ++ goto fail; ++ ++ *faults = MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT); ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", ++ __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, ++ u32 dma_len, int enable, int clear) ++{ ++ u8 inbuf[MC_CMD_MAC_STATS_IN_LEN]; ++ int rc; ++ efx_dword_t *cmd_ptr; ++ int period = 1000; ++ u32 addr_hi; ++ u32 addr_lo; ++ ++ BUILD_BUG_ON(MC_CMD_MAC_STATS_OUT_LEN != 0); ++ ++ addr_lo = ((u64)dma_addr) >> 0; ++ addr_hi = ((u64)dma_addr) >> 32; ++ ++ MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_LO, addr_lo); ++ MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_HI, addr_hi); ++ cmd_ptr = (efx_dword_t *)MCDI_PTR(inbuf, MAC_STATS_IN_CMD); ++ if (enable) ++ EFX_POPULATE_DWORD_6(*cmd_ptr, ++ MC_CMD_MAC_STATS_CMD_DMA, 1, ++ MC_CMD_MAC_STATS_CMD_CLEAR, clear, ++ MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1, ++ MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 1, ++ MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0, ++ MC_CMD_MAC_STATS_CMD_PERIOD_MS, period); ++ else ++ EFX_POPULATE_DWORD_5(*cmd_ptr, ++ MC_CMD_MAC_STATS_CMD_DMA, 0, ++ MC_CMD_MAC_STATS_CMD_CLEAR, clear, ++ MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1, ++ MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 0, ++ MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0); ++ MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf), ++ NULL, 0, NULL); ++ if (rc) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: %s failed rc=%d\n", ++ __func__, enable ? "enable" : "disable", rc); ++ return rc; ++} ++ ++static int efx_mcdi_mac_reconfigure(struct efx_nic *efx) ++{ ++ int rc; ++ ++ rc = efx_mcdi_set_mac(efx); ++ if (rc != 0) ++ return rc; ++ ++ /* Restore the multicast hash registers. */ ++ efx->type->push_multicast_hash(efx); ++ ++ return 0; ++} ++ ++ ++static bool efx_mcdi_mac_check_fault(struct efx_nic *efx) ++{ ++ u32 faults; ++ int rc = efx_mcdi_get_mac_faults(efx, &faults); ++ return (rc != 0) || (faults != 0); ++} ++ ++ ++struct efx_mac_operations efx_mcdi_mac_operations = { ++ .reconfigure = efx_mcdi_mac_reconfigure, ++ .update_stats = efx_port_dummy_op_void, ++ .check_fault = efx_mcdi_mac_check_fault, ++}; +diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h +new file mode 100644 +index 0000000..2a85360 +--- /dev/null ++++ b/drivers/net/sfc/mcdi_pcol.h +@@ -0,0 +1,1578 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++ ++#ifndef MCDI_PCOL_H ++#define MCDI_PCOL_H ++ ++/* Values to be written into FMCR_CZ_RESET_STATE_REG to control boot. */ ++/* Power-on reset state */ ++#define MC_FW_STATE_POR (1) ++/* If this is set in MC_RESET_STATE_REG then it should be ++ * possible to jump into IMEM without loading code from flash. */ ++#define MC_FW_WARM_BOOT_OK (2) ++/* The MC main image has started to boot. */ ++#define MC_FW_STATE_BOOTING (4) ++/* The Scheduler has started. */ ++#define MC_FW_STATE_SCHED (8) ++ ++/* Values to be written to the per-port status dword in shared ++ * memory on reboot and assert */ ++#define MC_STATUS_DWORD_REBOOT (0xb007b007) ++#define MC_STATUS_DWORD_ASSERT (0xdeaddead) ++ ++/* The current version of the MCDI protocol. ++ * ++ * Note that the ROM burnt into the card only talks V0, so at the very ++ * least every driver must support version 0 and MCDI_PCOL_VERSION ++ */ ++#define MCDI_PCOL_VERSION 1 ++ ++/** ++ * MCDI version 1 ++ * ++ * Each MCDI request starts with an MCDI_HEADER, which is a 32byte ++ * structure, filled in by the client. ++ * ++ * 0 7 8 16 20 22 23 24 31 ++ * | CODE | R | LEN | SEQ | Rsvd | E | R | XFLAGS | ++ * | | | ++ * | | \--- Response ++ * | \------- Error ++ * \------------------------------ Resync (always set) ++ * ++ * The client writes it's request into MC shared memory, and rings the ++ * doorbell. Each request is completed by either by the MC writting ++ * back into shared memory, or by writting out an event. ++ * ++ * All MCDI commands support completion by shared memory response. Each ++ * request may also contain additional data (accounted for by HEADER.LEN), ++ * and some response's may also contain additional data (again, accounted ++ * for by HEADER.LEN). ++ * ++ * Some MCDI commands support completion by event, in which any associated ++ * response data is included in the event. ++ * ++ * The protocol requires one response to be delivered for every request, a ++ * request should not be sent unless the response for the previous request ++ * has been received (either by polling shared memory, or by receiving ++ * an event). ++ */ ++ ++/** Request/Response structure */ ++#define MCDI_HEADER_OFST 0 ++#define MCDI_HEADER_CODE_LBN 0 ++#define MCDI_HEADER_CODE_WIDTH 7 ++#define MCDI_HEADER_RESYNC_LBN 7 ++#define MCDI_HEADER_RESYNC_WIDTH 1 ++#define MCDI_HEADER_DATALEN_LBN 8 ++#define MCDI_HEADER_DATALEN_WIDTH 8 ++#define MCDI_HEADER_SEQ_LBN 16 ++#define MCDI_HEADER_RSVD_LBN 20 ++#define MCDI_HEADER_RSVD_WIDTH 2 ++#define MCDI_HEADER_SEQ_WIDTH 4 ++#define MCDI_HEADER_ERROR_LBN 22 ++#define MCDI_HEADER_ERROR_WIDTH 1 ++#define MCDI_HEADER_RESPONSE_LBN 23 ++#define MCDI_HEADER_RESPONSE_WIDTH 1 ++#define MCDI_HEADER_XFLAGS_LBN 24 ++#define MCDI_HEADER_XFLAGS_WIDTH 8 ++/* Request response using event */ ++#define MCDI_HEADER_XFLAGS_EVREQ 0x01 ++ ++/* Maximum number of payload bytes */ ++#define MCDI_CTL_SDU_LEN_MAX 0xfc ++ ++/* The MC can generate events for two reasons: ++ * - To complete a shared memory request if XFLAGS_EVREQ was set ++ * - As a notification (link state, i2c event), controlled ++ * via MC_CMD_LOG_CTRL ++ * ++ * Both events share a common structure: ++ * ++ * 0 32 33 36 44 52 60 ++ * | Data | Cont | Level | Src | Code | Rsvd | ++ * | ++ * \ There is another event pending in this notification ++ * ++ * If Code==CMDDONE, then the fields are further interpreted as: ++ * ++ * - LEVEL==INFO Command succeded ++ * - LEVEL==ERR Command failed ++ * ++ * 0 8 16 24 32 ++ * | Seq | Datalen | Errno | Rsvd | ++ * ++ * These fields are taken directly out of the standard MCDI header, i.e., ++ * LEVEL==ERR, Datalen == 0 => Reboot ++ * ++ * Events can be squirted out of the UART (using LOG_CTRL) without a ++ * MCDI header. An event can be distinguished from a MCDI response by ++ * examining the first byte which is 0xc0. This corresponds to the ++ * non-existent MCDI command MC_CMD_DEBUG_LOG. ++ * ++ * 0 7 8 ++ * | command | Resync | = 0xc0 ++ * ++ * Since the event is written in big-endian byte order, this works ++ * providing bits 56-63 of the event are 0xc0. ++ * ++ * 56 60 63 ++ * | Rsvd | Code | = 0xc0 ++ * ++ * Which means for convenience the event code is 0xc for all MC ++ * generated events. ++ */ ++#define FSE_AZ_EV_CODE_MCDI_EVRESPONSE 0xc ++ ++#define MCDI_EVENT_DATA_LBN 0 ++#define MCDI_EVENT_DATA_WIDTH 32 ++#define MCDI_EVENT_CONT_LBN 32 ++#define MCDI_EVENT_CONT_WIDTH 1 ++#define MCDI_EVENT_LEVEL_LBN 33 ++#define MCDI_EVENT_LEVEL_WIDTH 3 ++#define MCDI_EVENT_LEVEL_INFO (0) ++#define MCDI_EVENT_LEVEL_WARN (1) ++#define MCDI_EVENT_LEVEL_ERR (2) ++#define MCDI_EVENT_LEVEL_FATAL (3) ++#define MCDI_EVENT_SRC_LBN 36 ++#define MCDI_EVENT_SRC_WIDTH 8 ++#define MCDI_EVENT_CODE_LBN 44 ++#define MCDI_EVENT_CODE_WIDTH 8 ++#define MCDI_EVENT_CODE_BADSSERT (1) ++#define MCDI_EVENT_CODE_PMNOTICE (2) ++#define MCDI_EVENT_CODE_CMDDONE (3) ++#define MCDI_EVENT_CMDDONE_SEQ_LBN 0 ++#define MCDI_EVENT_CMDDONE_SEQ_WIDTH 8 ++#define MCDI_EVENT_CMDDONE_DATALEN_LBN 8 ++#define MCDI_EVENT_CMDDONE_DATALEN_WIDTH 8 ++#define MCDI_EVENT_CMDDONE_ERRNO_LBN 16 ++#define MCDI_EVENT_CMDDONE_ERRNO_WIDTH 8 ++#define MCDI_EVENT_CODE_LINKCHANGE (4) ++#define MCDI_EVENT_LINKCHANGE_LP_CAP_LBN 0 ++#define MCDI_EVENT_LINKCHANGE_LP_CAP_WIDTH 16 ++#define MCDI_EVENT_LINKCHANGE_SPEED_LBN 16 ++#define MCDI_EVENT_LINKCHANGE_SPEED_WIDTH 4 ++#define MCDI_EVENT_LINKCHANGE_SPEED_100M 1 ++#define MCDI_EVENT_LINKCHANGE_SPEED_1G 2 ++#define MCDI_EVENT_LINKCHANGE_SPEED_10G 3 ++#define MCDI_EVENT_LINKCHANGE_FCNTL_LBN 20 ++#define MCDI_EVENT_LINKCHANGE_FCNTL_WIDTH 4 ++#define MCDI_EVENT_LINKCHANGE_LINK_FLAGS_LBN 24 ++#define MCDI_EVENT_LINKCHANGE_LINK_FLAGS_WIDTH 8 ++#define MCDI_EVENT_CODE_SENSOREVT (5) ++#define MCDI_EVENT_SENSOREVT_MONITOR_LBN 0 ++#define MCDI_EVENT_SENSOREVT_MONITOR_WIDTH 8 ++#define MCDI_EVENT_SENSOREVT_STATE_LBN 8 ++#define MCDI_EVENT_SENSOREVT_STATE_WIDTH 8 ++#define MCDI_EVENT_SENSOREVT_VALUE_LBN 16 ++#define MCDI_EVENT_SENSOREVT_VALUE_WIDTH 16 ++#define MCDI_EVENT_CODE_SCHEDERR (6) ++#define MCDI_EVENT_CODE_REBOOT (7) ++#define MCDI_EVENT_CODE_MAC_STATS_DMA (8) ++#define MCDI_EVENT_MAC_STATS_DMA_GENERATION_LBN 0 ++#define MCDI_EVENT_MAC_STATS_DMA_GENERATION_WIDTH 32 ++ ++/* Non-existent command target */ ++#define MC_CMD_ERR_ENOENT 2 ++/* assert() has killed the MC */ ++#define MC_CMD_ERR_EINTR 4 ++/* Caller does not hold required locks */ ++#define MC_CMD_ERR_EACCES 13 ++/* Resource is currently unavailable (e.g. lock contention) */ ++#define MC_CMD_ERR_EBUSY 16 ++/* Invalid argument to target */ ++#define MC_CMD_ERR_EINVAL 22 ++/* Non-recursive resource is already acquired */ ++#define MC_CMD_ERR_EDEADLK 35 ++/* Operation not implemented */ ++#define MC_CMD_ERR_ENOSYS 38 ++/* Operation timed out */ ++#define MC_CMD_ERR_ETIME 62 ++ ++#define MC_CMD_ERR_CODE_OFST 0 ++ ++ ++/* MC_CMD_READ32: (debug, variadic out) ++ * Read multiple 32byte words from MC memory ++ */ ++#define MC_CMD_READ32 0x01 ++#define MC_CMD_READ32_IN_LEN 8 ++#define MC_CMD_READ32_IN_ADDR_OFST 0 ++#define MC_CMD_READ32_IN_NUMWORDS_OFST 4 ++#define MC_CMD_READ32_OUT_LEN(_numwords) \ ++ (4 * (_numwords)) ++#define MC_CMD_READ32_OUT_BUFFER_OFST 0 ++ ++/* MC_CMD_WRITE32: (debug, variadic in) ++ * Write multiple 32byte words to MC memory ++ */ ++#define MC_CMD_WRITE32 0x02 ++#define MC_CMD_WRITE32_IN_LEN(_numwords) (((_numwords) * 4) + 4) ++#define MC_CMD_WRITE32_IN_ADDR_OFST 0 ++#define MC_CMD_WRITE32_IN_BUFFER_OFST 4 ++#define MC_CMD_WRITE32_OUT_LEN 0 ++ ++/* MC_CMD_COPYCODE: (debug) ++ * Copy MC code between two locations and jump ++ */ ++#define MC_CMD_COPYCODE 0x03 ++#define MC_CMD_COPYCODE_IN_LEN 16 ++#define MC_CMD_COPYCODE_IN_SRC_ADDR_OFST 0 ++#define MC_CMD_COPYCODE_IN_DEST_ADDR_OFST 4 ++#define MC_CMD_COPYCODE_IN_NUMWORDS_OFST 8 ++#define MC_CMD_COPYCODE_IN_JUMP_OFST 12 ++/* Control should return to the caller rather than jumping */ ++#define MC_CMD_COPYCODE_JUMP_NONE 1 ++#define MC_CMD_COPYCODE_OUT_LEN 0 ++ ++/* MC_CMD_SET_FUNC: (debug) ++ * Select function for function-specific commands. ++ */ ++#define MC_CMD_SET_FUNC 0x04 ++#define MC_CMD_SET_FUNC_IN_LEN 4 ++#define MC_CMD_SET_FUNC_IN_FUNC_OFST 0 ++#define MC_CMD_SET_FUNC_OUT_LEN 0 ++ ++/* MC_CMD_GET_BOOT_STATUS: ++ * Get the instruction address from which the MC booted. ++ */ ++#define MC_CMD_GET_BOOT_STATUS 0x05 ++#define MC_CMD_GET_BOOT_STATUS_IN_LEN 0 ++#define MC_CMD_GET_BOOT_STATUS_OUT_LEN 8 ++#define MC_CMD_GET_BOOT_STATUS_OUT_BOOT_OFFSET_OFST 0 ++#define MC_CMD_GET_BOOT_STATUS_OUT_FLAGS_OFST 4 ++/* Reboot caused by watchdog */ ++#define MC_CMD_GET_BOOT_STATUS_FLAGS_WATCHDOG_LBN (0) ++#define MC_CMD_GET_BOOT_STATUS_FLAGS_WATCHDOG_WIDTH (1) ++/* MC booted from primary flash partition */ ++#define MC_CMD_GET_BOOT_STATUS_FLAGS_PRIMARY_LBN (1) ++#define MC_CMD_GET_BOOT_STATUS_FLAGS_PRIMARY_WIDTH (1) ++/* MC booted from backup flash partition */ ++#define MC_CMD_GET_BOOT_STATUS_FLAGS_BACKUP_LBN (2) ++#define MC_CMD_GET_BOOT_STATUS_FLAGS_BACKUP_WIDTH (1) ++ ++/* MC_CMD_GET_ASSERTS: (debug, variadic out) ++ * Get (and optionally clear) the current assertion status. ++ * ++ * Only OUT.GLOBAL_FLAGS is guaranteed to exist in the completion ++ * payload. The other fields will only be present if ++ * OUT.GLOBAL_FLAGS != NO_FAILS ++ */ ++#define MC_CMD_GET_ASSERTS 0x06 ++#define MC_CMD_GET_ASSERTS_IN_LEN 4 ++#define MC_CMD_GET_ASSERTS_IN_CLEAR_OFST 0 ++#define MC_CMD_GET_ASSERTS_OUT_LEN 140 ++/* Assertion status flag */ ++#define MC_CMD_GET_ASSERTS_OUT_GLOBAL_FLAGS_OFST 0 ++/*! No assertions have failed. */ ++#define MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS 1 ++/*! A system-level assertion has failed. */ ++#define MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL 2 ++/*! A thread-level assertion has failed. */ ++#define MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL 3 ++/*! The system was reset by the watchdog. */ ++#define MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED 4 ++/* Failing PC value */ ++#define MC_CMD_GET_ASSERTS_OUT_SAVED_PC_OFFS_OFST 4 ++/* Saved GP regs */ ++#define MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST 8 ++#define MC_CMD_GET_ASSERTS_OUT_GP_REGS_LEN 124 ++/* Failing thread address */ ++#define MC_CMD_GET_ASSERTS_OUT_THREAD_OFFS_OFST 132 ++ ++/* MC_CMD_LOG_CTRL: ++ * Determine the output stream for various events and messages ++ */ ++#define MC_CMD_LOG_CTRL 0x07 ++#define MC_CMD_LOG_CTRL_IN_LEN 8 ++#define MC_CMD_LOG_CTRL_IN_LOG_DEST_OFST 0 ++#define MC_CMD_LOG_CTRL_IN_LOG_DEST_UART (1) ++#define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ (2) ++#define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ_OFST 4 ++#define MC_CMD_LOG_CTRL_OUT_LEN 0 ++ ++/* MC_CMD_GET_VERSION: ++ * Get version information about the MC firmware ++ */ ++#define MC_CMD_GET_VERSION 0x08 ++#define MC_CMD_GET_VERSION_IN_LEN 0 ++#define MC_CMD_GET_VERSION_V0_OUT_LEN 4 ++#define MC_CMD_GET_VERSION_V1_OUT_LEN 32 ++#define MC_CMD_GET_VERSION_OUT_FIRMWARE_OFST 0 ++/* Reserved version number to indicate "any" version. */ ++#define MC_CMD_GET_VERSION_OUT_FIRMWARE_ANY 0xffffffff ++/* The version response of a boot ROM awaiting rescue */ ++#define MC_CMD_GET_VERSION_OUT_FIRMWARE_BOOTROM 0xb0070000 ++#define MC_CMD_GET_VERSION_V1_OUT_PCOL_OFST 4 ++/* 128bit mask of functions supported by the current firmware */ ++#define MC_CMD_GET_VERSION_V1_OUT_SUPPORTED_FUNCS_OFST 8 ++/* The command set exported by the boot ROM (MCDI v0) */ ++#define MC_CMD_GET_VERSION_V0_SUPPORTED_FUNCS { \ ++ (1 << MC_CMD_READ32) | \ ++ (1 << MC_CMD_WRITE32) | \ ++ (1 << MC_CMD_COPYCODE) | \ ++ (1 << MC_CMD_GET_VERSION), \ ++ 0, 0, 0 } ++#define MC_CMD_GET_VERSION_OUT_VERSION_OFST 24 ++ ++/* Vectors in the boot ROM */ ++/* Point to the copycode entry point. */ ++#define MC_BOOTROM_COPYCODE_VEC (0x7f4) ++/* Points to the recovery mode entry point. */ ++#define MC_BOOTROM_NOFLASH_VEC (0x7f8) ++ ++/* Test execution limits */ ++#define MC_TESTEXEC_VARIANT_COUNT 16 ++#define MC_TESTEXEC_RESULT_COUNT 7 ++ ++/* MC_CMD_SET_TESTVARS: (debug, variadic in) ++ * Write variant words for test. ++ * ++ * The user supplies a bitmap of the variants they wish to set. ++ * They must ensure that IN.LEN >= 4 + 4 * ffs(BITMAP) ++ */ ++#define MC_CMD_SET_TESTVARS 0x09 ++#define MC_CMD_SET_TESTVARS_IN_LEN(_numwords) \ ++ (4 + 4*(_numwords)) ++#define MC_CMD_SET_TESTVARS_IN_ARGS_BITMAP_OFST 0 ++/* Up to MC_TESTEXEC_VARIANT_COUNT of 32byte words start here */ ++#define MC_CMD_SET_TESTVARS_IN_ARGS_BUFFER_OFST 4 ++#define MC_CMD_SET_TESTVARS_OUT_LEN 0 ++ ++/* MC_CMD_GET_TESTRCS: (debug, variadic out) ++ * Return result words from test. ++ */ ++#define MC_CMD_GET_TESTRCS 0x0a ++#define MC_CMD_GET_TESTRCS_IN_LEN 4 ++#define MC_CMD_GET_TESTRCS_IN_NUMWORDS_OFST 0 ++#define MC_CMD_GET_TESTRCS_OUT_LEN(_numwords) \ ++ (4 * (_numwords)) ++#define MC_CMD_GET_TESTRCS_OUT_BUFFER_OFST 0 ++ ++/* MC_CMD_RUN_TEST: (debug) ++ * Run the test exported by this firmware image ++ */ ++#define MC_CMD_RUN_TEST 0x0b ++#define MC_CMD_RUN_TEST_IN_LEN 0 ++#define MC_CMD_RUN_TEST_OUT_LEN 0 ++ ++/* MC_CMD_CSR_READ32: (debug, variadic out) ++ * Read 32bit words from the indirect memory map ++ */ ++#define MC_CMD_CSR_READ32 0x0c ++#define MC_CMD_CSR_READ32_IN_LEN 12 ++#define MC_CMD_CSR_READ32_IN_ADDR_OFST 0 ++#define MC_CMD_CSR_READ32_IN_STEP_OFST 4 ++#define MC_CMD_CSR_READ32_IN_NUMWORDS_OFST 8 ++#define MC_CMD_CSR_READ32_OUT_LEN(_numwords) \ ++ (((_numwords) * 4) + 4) ++/* IN.NUMWORDS of 32bit words start here */ ++#define MC_CMD_CSR_READ32_OUT_BUFFER_OFST 0 ++#define MC_CMD_CSR_READ32_OUT_IREG_STATUS_OFST(_numwords) \ ++ ((_numwords) * 4) ++ ++/* MC_CMD_CSR_WRITE32: (debug, variadic in) ++ * Write 32bit dwords to the indirect memory map ++ */ ++#define MC_CMD_CSR_WRITE32 0x0d ++#define MC_CMD_CSR_WRITE32_IN_LEN(_numwords) \ ++ (((_numwords) * 4) + 8) ++#define MC_CMD_CSR_WRITE32_IN_ADDR_OFST 0 ++#define MC_CMD_CSR_WRITE32_IN_STEP_OFST 4 ++/* Multiple 32bit words of data to write start here */ ++#define MC_CMD_CSR_WRITE32_IN_BUFFER_OFST 8 ++#define MC_CMD_CSR_WRITE32_OUT_LEN 4 ++#define MC_CMD_CSR_WRITE32_OUT_STATUS_OFST 0 ++ ++/* MC_CMD_JTAG_WORK: (debug, fpga only) ++ * Process JTAG work buffer for RBF acceleration. ++ * ++ * Host: bit count, (up to) 32 words of data to clock out to JTAG ++ * (bits 1,0=TMS,TDO for first bit; bits 3,2=TMS,TDO for second bit, etc.) ++ * MC: bit count, (up to) 32 words of data clocked in from JTAG ++ * (bit 0=TDI for first bit, bit 1=TDI for second bit, etc.; [31:16] unused) ++ */ ++#define MC_CMD_JTAG_WORK 0x0e ++ ++/* MC_CMD_STACKINFO: (debug, variadic out) ++ * Get stack information ++ * ++ * Host: nothing ++ * MC: (thread ptr, stack size, free space) for each thread in system ++ */ ++#define MC_CMD_STACKINFO 0x0f ++ ++/* MC_CMD_MDIO_READ: ++ * MDIO register read ++ */ ++#define MC_CMD_MDIO_READ 0x10 ++#define MC_CMD_MDIO_READ_IN_LEN 16 ++#define MC_CMD_MDIO_READ_IN_BUS_OFST 0 ++#define MC_CMD_MDIO_READ_IN_PRTAD_OFST 4 ++#define MC_CMD_MDIO_READ_IN_DEVAD_OFST 8 ++#define MC_CMD_MDIO_READ_IN_ADDR_OFST 12 ++#define MC_CMD_MDIO_READ_OUT_LEN 8 ++#define MC_CMD_MDIO_READ_OUT_VALUE_OFST 0 ++#define MC_CMD_MDIO_READ_OUT_STATUS_OFST 4 ++ ++/* MC_CMD_MDIO_WRITE: ++ * MDIO register write ++ */ ++#define MC_CMD_MDIO_WRITE 0x11 ++#define MC_CMD_MDIO_WRITE_IN_LEN 20 ++#define MC_CMD_MDIO_WRITE_IN_BUS_OFST 0 ++#define MC_CMD_MDIO_WRITE_IN_PRTAD_OFST 4 ++#define MC_CMD_MDIO_WRITE_IN_DEVAD_OFST 8 ++#define MC_CMD_MDIO_WRITE_IN_ADDR_OFST 12 ++#define MC_CMD_MDIO_WRITE_IN_VALUE_OFST 16 ++#define MC_CMD_MDIO_WRITE_OUT_LEN 4 ++#define MC_CMD_MDIO_WRITE_OUT_STATUS_OFST 0 ++ ++/* By default all the MCDI MDIO operations perform clause45 mode. ++ * If you want to use clause22 then set DEVAD = MC_CMD_MDIO_CLAUSE22. ++ */ ++#define MC_CMD_MDIO_CLAUSE22 32 ++ ++/* There are two MDIO buses: one for the internal PHY, and one for external ++ * devices. ++ */ ++#define MC_CMD_MDIO_BUS_INTERNAL 0 ++#define MC_CMD_MDIO_BUS_EXTERNAL 1 ++ ++/* The MDIO commands return the raw status bits from the MDIO block. A "good" ++ * transaction should have the DONE bit set and all other bits clear. ++ */ ++#define MC_CMD_MDIO_STATUS_GOOD 0x08 ++ ++ ++/* MC_CMD_DBI_WRITE: (debug) ++ * Write DBI register(s) ++ * ++ * Host: address, byte-enables (and VF selection, and cs2 flag), ++ * value [,address ...] ++ * MC: nothing ++ */ ++#define MC_CMD_DBI_WRITE 0x12 ++#define MC_CMD_DBI_WRITE_IN_LEN(_numwords) \ ++ (12 * (_numwords)) ++#define MC_CMD_DBI_WRITE_IN_ADDRESS_OFST(_word) \ ++ (((_word) * 12) + 0) ++#define MC_CMD_DBI_WRITE_IN_BYTE_MASK_OFST(_word) \ ++ (((_word) * 12) + 4) ++#define MC_CMD_DBI_WRITE_IN_VALUE_OFST(_word) \ ++ (((_word) * 12) + 8) ++#define MC_CMD_DBI_WRITE_OUT_LEN 0 ++ ++/* MC_CMD_DBI_READ: (debug) ++ * Read DBI register(s) ++ * ++ * Host: address, [,address ...] ++ * MC: value [,value ...] ++ * (note: this does not support reading from VFs, but is retained for backwards ++ * compatibility; see MC_CMD_DBI_READX below) ++ */ ++#define MC_CMD_DBI_READ 0x13 ++#define MC_CMD_DBI_READ_IN_LEN(_numwords) \ ++ (4 * (_numwords)) ++#define MC_CMD_DBI_READ_OUT_LEN(_numwords) \ ++ (4 * (_numwords)) ++ ++/* MC_CMD_PORT_READ32: (debug) ++ * Read a 32-bit register from the indirect port register map. ++ * ++ * The port to access is implied by the Shared memory channel used. ++ */ ++#define MC_CMD_PORT_READ32 0x14 ++#define MC_CMD_PORT_READ32_IN_LEN 4 ++#define MC_CMD_PORT_READ32_IN_ADDR_OFST 0 ++#define MC_CMD_PORT_READ32_OUT_LEN 8 ++#define MC_CMD_PORT_READ32_OUT_VALUE_OFST 0 ++#define MC_CMD_PORT_READ32_OUT_STATUS_OFST 4 ++ ++/* MC_CMD_PORT_WRITE32: (debug) ++ * Write a 32-bit register to the indirect port register map. ++ * ++ * The port to access is implied by the Shared memory channel used. ++ */ ++#define MC_CMD_PORT_WRITE32 0x15 ++#define MC_CMD_PORT_WRITE32_IN_LEN 8 ++#define MC_CMD_PORT_WRITE32_IN_ADDR_OFST 0 ++#define MC_CMD_PORT_WRITE32_IN_VALUE_OFST 4 ++#define MC_CMD_PORT_WRITE32_OUT_LEN 4 ++#define MC_CMD_PORT_WRITE32_OUT_STATUS_OFST 0 ++ ++/* MC_CMD_PORT_READ128: (debug) ++ * Read a 128-bit register from indirect port register map ++ * ++ * The port to access is implied by the Shared memory channel used. ++ */ ++#define MC_CMD_PORT_READ128 0x16 ++#define MC_CMD_PORT_READ128_IN_LEN 4 ++#define MC_CMD_PORT_READ128_IN_ADDR_OFST 0 ++#define MC_CMD_PORT_READ128_OUT_LEN 20 ++#define MC_CMD_PORT_READ128_OUT_VALUE_OFST 0 ++#define MC_CMD_PORT_READ128_OUT_STATUS_OFST 16 ++ ++/* MC_CMD_PORT_WRITE128: (debug) ++ * Write a 128-bit register to indirect port register map. ++ * ++ * The port to access is implied by the Shared memory channel used. ++ */ ++#define MC_CMD_PORT_WRITE128 0x17 ++#define MC_CMD_PORT_WRITE128_IN_LEN 20 ++#define MC_CMD_PORT_WRITE128_IN_ADDR_OFST 0 ++#define MC_CMD_PORT_WRITE128_IN_VALUE_OFST 4 ++#define MC_CMD_PORT_WRITE128_OUT_LEN 4 ++#define MC_CMD_PORT_WRITE128_OUT_STATUS_OFST 0 ++ ++/* MC_CMD_GET_BOARD_CFG: ++ * Returns the MC firmware configuration structure ++ * ++ * The FW_SUBTYPE_LIST contains a 16-bit value for each of the 12 types of ++ * NVRAM area. The values are defined in the firmware/mc/platform/.c file ++ * for a specific board type, but otherwise have no meaning to the MC; they ++ * are used by the driver to manage selection of appropriate firmware updates. ++ */ ++#define MC_CMD_GET_BOARD_CFG 0x18 ++#define MC_CMD_GET_BOARD_CFG_IN_LEN 0 ++#define MC_CMD_GET_BOARD_CFG_OUT_LEN 96 ++#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_TYPE_OFST 0 ++#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_NAME_OFST 4 ++#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_NAME_LEN 32 ++#define MC_CMD_GET_BOARD_CFG_OUT_CAPABILITIES_PORT0_OFST 36 ++#define MC_CMD_GET_BOARD_CFG_OUT_CAPABILITIES_PORT1_OFST 40 ++#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST 44 ++#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_LEN 6 ++#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST 50 ++#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_LEN 6 ++#define MC_CMD_GET_BOARD_CFG_OUT_MAC_COUNT_PORT0_OFST 56 ++#define MC_CMD_GET_BOARD_CFG_OUT_MAC_COUNT_PORT1_OFST 60 ++#define MC_CMD_GET_BOARD_CFG_OUT_MAC_STRIDE_PORT0_OFST 64 ++#define MC_CMD_GET_BOARD_CFG_OUT_MAC_STRIDE_PORT1_OFST 68 ++#define MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST 72 ++#define MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN 24 ++ ++/* MC_CMD_DBI_READX: (debug) ++ * Read DBI register(s) -- extended functionality ++ * ++ * Host: vf selection, address, [,vf selection ...] ++ * MC: value [,value ...] ++ */ ++#define MC_CMD_DBI_READX 0x19 ++#define MC_CMD_DBI_READX_IN_LEN(_numwords) \ ++ (8*(_numwords)) ++#define MC_CMD_DBI_READX_OUT_LEN(_numwords) \ ++ (4*(_numwords)) ++ ++/* MC_CMD_SET_RAND_SEED: ++ * Set the 16byte seed for the MC psuedo-random generator ++ */ ++#define MC_CMD_SET_RAND_SEED 0x1a ++#define MC_CMD_SET_RAND_SEED_IN_LEN 16 ++#define MC_CMD_SET_RAND_SEED_IN_SEED_OFST 0 ++#define MC_CMD_SET_RAND_SEED_OUT_LEN 0 ++ ++/* MC_CMD_LTSSM_HIST: (debug) ++ * Retrieve the history of the LTSSM, if the build supports it. ++ * ++ * Host: nothing ++ * MC: variable number of LTSSM values, as bytes ++ * The history is read-to-clear. ++ */ ++#define MC_CMD_LTSSM_HIST 0x1b ++ ++/* MC_CMD_DRV_ATTACH: ++ * Inform MCPU that this port is managed on the host (i.e. driver active) ++ */ ++#define MC_CMD_DRV_ATTACH 0x1c ++#define MC_CMD_DRV_ATTACH_IN_LEN 8 ++#define MC_CMD_DRV_ATTACH_IN_NEW_STATE_OFST 0 ++#define MC_CMD_DRV_ATTACH_IN_UPDATE_OFST 4 ++#define MC_CMD_DRV_ATTACH_OUT_LEN 4 ++#define MC_CMD_DRV_ATTACH_OUT_OLD_STATE_OFST 0 ++ ++/* MC_CMD_NCSI_PROD: (debug) ++ * Trigger an NC-SI event (and possibly an AEN in response) ++ */ ++#define MC_CMD_NCSI_PROD 0x1d ++#define MC_CMD_NCSI_PROD_IN_LEN 4 ++#define MC_CMD_NCSI_PROD_IN_EVENTS_OFST 0 ++#define MC_CMD_NCSI_PROD_LINKCHANGE_LBN 0 ++#define MC_CMD_NCSI_PROD_LINKCHANGE_WIDTH 1 ++#define MC_CMD_NCSI_PROD_RESET_LBN 1 ++#define MC_CMD_NCSI_PROD_RESET_WIDTH 1 ++#define MC_CMD_NCSI_PROD_DRVATTACH_LBN 2 ++#define MC_CMD_NCSI_PROD_DRVATTACH_WIDTH 1 ++#define MC_CMD_NCSI_PROD_OUT_LEN 0 ++ ++/* Enumeration */ ++#define MC_CMD_NCSI_PROD_LINKCHANGE 0 ++#define MC_CMD_NCSI_PROD_RESET 1 ++#define MC_CMD_NCSI_PROD_DRVATTACH 2 ++ ++/* MC_CMD_DEVEL: (debug) ++ * Reserved for development ++ */ ++#define MC_CMD_DEVEL 0x1e ++ ++/* MC_CMD_SHMUART: (debug) ++ * Route UART output to circular buffer in shared memory instead. ++ */ ++#define MC_CMD_SHMUART 0x1f ++#define MC_CMD_SHMUART_IN_FLAG_OFST 0 ++#define MC_CMD_SHMUART_IN_LEN 4 ++#define MC_CMD_SHMUART_OUT_LEN 0 ++ ++/* MC_CMD_PORT_RESET: ++ * Generic per-port reset. There is no equivalent for per-board reset. ++ * ++ * Locks required: None ++ * Return code: 0, ETIME ++ */ ++#define MC_CMD_PORT_RESET 0x20 ++#define MC_CMD_PORT_RESET_IN_LEN 0 ++#define MC_CMD_PORT_RESET_OUT_LEN 0 ++ ++/* MC_CMD_RESOURCE_LOCK: ++ * Generic resource lock/unlock interface. ++ * ++ * Locks required: None ++ * Return code: 0, ++ * EBUSY (if trylock is contended by other port), ++ * EDEADLK (if trylock is already acquired by this port) ++ * EINVAL (if unlock doesn't own the lock) ++ */ ++#define MC_CMD_RESOURCE_LOCK 0x21 ++#define MC_CMD_RESOURCE_LOCK_IN_LEN 8 ++#define MC_CMD_RESOURCE_LOCK_IN_ACTION_OFST 0 ++#define MC_CMD_RESOURCE_LOCK_ACTION_TRYLOCK 1 ++#define MC_CMD_RESOURCE_LOCK_ACTION_UNLOCK 0 ++#define MC_CMD_RESOURCE_LOCK_IN_RESOURCE_OFST 4 ++#define MC_CMD_RESOURCE_LOCK_I2C 2 ++#define MC_CMD_RESOURCE_LOCK_PHY 3 ++#define MC_CMD_RESOURCE_LOCK_OUT_LEN 0 ++ ++/* MC_CMD_SPI_COMMAND: (variadic in, variadic out) ++ * Read/Write to/from the SPI device. ++ * ++ * Locks required: SPI_LOCK ++ * Return code: 0, ETIME, EINVAL, EACCES (if SPI_LOCK is not held) ++ */ ++#define MC_CMD_SPI_COMMAND 0x22 ++#define MC_CMD_SPI_COMMAND_IN_LEN(_write_bytes) (12 + (_write_bytes)) ++#define MC_CMD_SPI_COMMAND_IN_ARGS_OFST 0 ++#define MC_CMD_SPI_COMMAND_IN_ARGS_ADDRESS_OFST 0 ++#define MC_CMD_SPI_COMMAND_IN_ARGS_READ_BYTES_OFST 4 ++#define MC_CMD_SPI_COMMAND_IN_ARGS_CHIP_SELECT_OFST 8 ++/* Data to write here */ ++#define MC_CMD_SPI_COMMAND_IN_WRITE_BUFFER_OFST 12 ++#define MC_CMD_SPI_COMMAND_OUT_LEN(_read_bytes) (_read_bytes) ++/* Data read here */ ++#define MC_CMD_SPI_COMMAND_OUT_READ_BUFFER_OFST 0 ++ ++/* MC_CMD_I2C_READ_WRITE: (variadic in, variadic out) ++ * Read/Write to/from the I2C bus. ++ * ++ * Locks required: I2C_LOCK ++ * Return code: 0, ETIME, EINVAL, EACCES (if I2C_LOCK is not held) ++ */ ++#define MC_CMD_I2C_RW 0x23 ++#define MC_CMD_I2C_RW_IN_LEN(_write_bytes) (8 + (_write_bytes)) ++#define MC_CMD_I2C_RW_IN_ARGS_OFST 0 ++#define MC_CMD_I2C_RW_IN_ARGS_ADDR_OFST 0 ++#define MC_CMD_I2C_RW_IN_ARGS_READ_BYTES_OFST 4 ++/* Data to write here */ ++#define MC_CMD_I2C_RW_IN_WRITE_BUFFER_OFSET 8 ++#define MC_CMD_I2C_RW_OUT_LEN(_read_bytes) (_read_bytes) ++/* Data read here */ ++#define MC_CMD_I2C_RW_OUT_READ_BUFFER_OFST 0 ++ ++/* Generic phy capability bitmask */ ++#define MC_CMD_PHY_CAP_10HDX_LBN 1 ++#define MC_CMD_PHY_CAP_10HDX_WIDTH 1 ++#define MC_CMD_PHY_CAP_10FDX_LBN 2 ++#define MC_CMD_PHY_CAP_10FDX_WIDTH 1 ++#define MC_CMD_PHY_CAP_100HDX_LBN 3 ++#define MC_CMD_PHY_CAP_100HDX_WIDTH 1 ++#define MC_CMD_PHY_CAP_100FDX_LBN 4 ++#define MC_CMD_PHY_CAP_100FDX_WIDTH 1 ++#define MC_CMD_PHY_CAP_1000HDX_LBN 5 ++#define MC_CMD_PHY_CAP_1000HDX_WIDTH 1 ++#define MC_CMD_PHY_CAP_1000FDX_LBN 6 ++#define MC_CMD_PHY_CAP_1000FDX_WIDTH 1 ++#define MC_CMD_PHY_CAP_10000FDX_LBN 7 ++#define MC_CMD_PHY_CAP_10000FDX_WIDTH 1 ++#define MC_CMD_PHY_CAP_PAUSE_LBN 8 ++#define MC_CMD_PHY_CAP_PAUSE_WIDTH 1 ++#define MC_CMD_PHY_CAP_ASYM_LBN 9 ++#define MC_CMD_PHY_CAP_ASYM_WIDTH 1 ++#define MC_CMD_PHY_CAP_AN_LBN 10 ++#define MC_CMD_PHY_CAP_AN_WIDTH 1 ++ ++/* Generic loopback enumeration */ ++#define MC_CMD_LOOPBACK_NONE 0 ++#define MC_CMD_LOOPBACK_DATA 1 ++#define MC_CMD_LOOPBACK_GMAC 2 ++#define MC_CMD_LOOPBACK_XGMII 3 ++#define MC_CMD_LOOPBACK_XGXS 4 ++#define MC_CMD_LOOPBACK_XAUI 5 ++#define MC_CMD_LOOPBACK_GMII 6 ++#define MC_CMD_LOOPBACK_SGMII 7 ++#define MC_CMD_LOOPBACK_XGBR 8 ++#define MC_CMD_LOOPBACK_XFI 9 ++#define MC_CMD_LOOPBACK_XAUI_FAR 10 ++#define MC_CMD_LOOPBACK_GMII_FAR 11 ++#define MC_CMD_LOOPBACK_SGMII_FAR 12 ++#define MC_CMD_LOOPBACK_XFI_FAR 13 ++#define MC_CMD_LOOPBACK_GPHY 14 ++#define MC_CMD_LOOPBACK_PHYXS 15 ++#define MC_CMD_LOOPBACK_PCS 16 ++#define MC_CMD_LOOPBACK_PMAPMD 17 ++#define MC_CMD_LOOPBACK_XPORT 18 ++#define MC_CMD_LOOPBACK_XGMII_WS 19 ++#define MC_CMD_LOOPBACK_XAUI_WS 20 ++#define MC_CMD_LOOPBACK_XAUI_WS_FAR 21 ++#define MC_CMD_LOOPBACK_XAUI_WS_NEAR 22 ++#define MC_CMD_LOOPBACK_GMII_WS 23 ++#define MC_CMD_LOOPBACK_XFI_WS 24 ++#define MC_CMD_LOOPBACK_XFI_WS_FAR 25 ++#define MC_CMD_LOOPBACK_PHYXS_WS 26 ++ ++/* Generic PHY statistics enumeration */ ++#define MC_CMD_OUI 0 ++#define MC_CMD_PMA_PMD_LINK_UP 1 ++#define MC_CMD_PMA_PMD_RX_FAULT 2 ++#define MC_CMD_PMA_PMD_TX_FAULT 3 ++#define MC_CMD_PMA_PMD_SIGNAL 4 ++#define MC_CMD_PMA_PMD_SNR_A 5 ++#define MC_CMD_PMA_PMD_SNR_B 6 ++#define MC_CMD_PMA_PMD_SNR_C 7 ++#define MC_CMD_PMA_PMD_SNR_D 8 ++#define MC_CMD_PCS_LINK_UP 9 ++#define MC_CMD_PCS_RX_FAULT 10 ++#define MC_CMD_PCS_TX_FAULT 11 ++#define MC_CMD_PCS_BER 12 ++#define MC_CMD_PCS_BLOCK_ERRORS 13 ++#define MC_CMD_PHYXS_LINK_UP 14 ++#define MC_CMD_PHYXS_RX_FAULT 15 ++#define MC_CMD_PHYXS_TX_FAULT 16 ++#define MC_CMD_PHYXS_ALIGN 17 ++#define MC_CMD_PHYXS_SYNC 18 ++#define MC_CMD_AN_LINK_UP 19 ++#define MC_CMD_AN_COMPLETE 20 ++#define MC_CMD_AN_10GBT_STATUS 21 ++#define MC_CMD_CL22_LINK_UP 22 ++#define MC_CMD_PHY_NSTATS 23 ++ ++/* MC_CMD_GET_PHY_CFG: ++ * Report PHY configuration. This guarantees to succeed even if the PHY is in ++ * a "zombie" state. ++ * ++ * Locks required: None ++ * Return code: 0 ++ */ ++#define MC_CMD_GET_PHY_CFG 0x24 ++ ++#define MC_CMD_GET_PHY_CFG_IN_LEN 0 ++#define MC_CMD_GET_PHY_CFG_OUT_LEN 72 ++ ++#define MC_CMD_GET_PHY_CFG_OUT_FLAGS_OFST 0 ++#define MC_CMD_GET_PHY_CFG_PRESENT_LBN 0 ++#define MC_CMD_GET_PHY_CFG_PRESENT_WIDTH 1 ++#define MC_CMD_GET_PHY_CFG_SHORTBIST_LBN 1 ++#define MC_CMD_GET_PHY_CFG_SHORTBIST_WIDTH 1 ++#define MC_CMD_GET_PHY_CFG_LONGBIST_LBN 2 ++#define MC_CMD_GET_PHY_CFG_LONGBIST_WIDTH 1 ++#define MC_CMD_GET_PHY_CFG_LOWPOWER_LBN 3 ++#define MC_CMD_GET_PHY_CFG_LOWPOWER_WIDTH 1 ++#define MC_CMD_GET_PHY_CFG_POWEROFF_LBN 4 ++#define MC_CMD_GET_PHY_CFG_POWEROFF_WIDTH 1 ++#define MC_CMD_GET_PHY_CFG_TXDIS_LBN 5 ++#define MC_CMD_GET_PHY_CFG_TXDIS_WIDTH 1 ++#define MC_CMD_GET_PHY_CFG_OUT_TYPE_OFST 4 ++/* Bitmask of supported capabilities */ ++#define MC_CMD_GET_PHY_CFG_OUT_SUPPORTED_CAP_OFST 8 ++#define MC_CMD_GET_PHY_CFG_OUT_CHANNEL_OFST 12 ++#define MC_CMD_GET_PHY_CFG_OUT_PRT_OFST 16 ++/* PHY statistics bitmap */ ++#define MC_CMD_GET_PHY_CFG_OUT_STATS_MASK_OFST 20 ++/* PHY type/name string */ ++#define MC_CMD_GET_PHY_CFG_OUT_NAME_OFST 24 ++#define MC_CMD_GET_PHY_CFG_OUT_NAME_LEN 20 ++#define MC_CMD_GET_PHY_CFG_OUT_MEDIA_TYPE_OFST 44 ++#define MC_CMD_MEDIA_XAUI 1 ++#define MC_CMD_MEDIA_CX4 2 ++#define MC_CMD_MEDIA_KX4 3 ++#define MC_CMD_MEDIA_XFP 4 ++#define MC_CMD_MEDIA_SFP_PLUS 5 ++#define MC_CMD_MEDIA_BASE_T 6 ++/* MDIO "MMDS" supported */ ++#define MC_CMD_GET_PHY_CFG_OUT_MMD_MASK_OFST 48 ++/* Native clause 22 */ ++#define MC_CMD_MMD_CLAUSE22 0 ++#define MC_CMD_MMD_CLAUSE45_PMAPMD 1 ++#define MC_CMD_MMD_CLAUSE45_WIS 2 ++#define MC_CMD_MMD_CLAUSE45_PCS 3 ++#define MC_CMD_MMD_CLAUSE45_PHYXS 4 ++#define MC_CMD_MMD_CLAUSE45_DTEXS 5 ++#define MC_CMD_MMD_CLAUSE45_TC 6 ++#define MC_CMD_MMD_CLAUSE45_AN 7 ++/* Clause22 proxied over clause45 by PHY */ ++#define MC_CMD_MMD_CLAUSE45_C22EXT 29 ++#define MC_CMD_MMD_CLAUSE45_VEND1 30 ++#define MC_CMD_MMD_CLAUSE45_VEND2 31 ++/* PHY stepping version */ ++#define MC_CMD_GET_PHY_CFG_OUT_REVISION_OFST 52 ++#define MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN 20 ++ ++/* MC_CMD_START_PHY_BIST: ++ * Start a BIST test on the PHY. ++ * ++ * Locks required: PHY_LOCK if doing a PHY BIST ++ * Return code: 0, EINVAL, EACCES (if PHY_LOCK is not held) ++ */ ++#define MC_CMD_START_BIST 0x25 ++#define MC_CMD_START_BIST_IN_LEN 4 ++#define MC_CMD_START_BIST_TYPE_OFST 0 ++ ++/* Run the PHY's short BIST */ ++#define MC_CMD_PHY_BIST_SHORT 1 ++/* Run the PHY's long BIST */ ++#define MC_CMD_PHY_BIST_LONG 2 ++/* Run BIST on the currently selected BPX Serdes (XAUI or XFI) */ ++#define MC_CMD_BPX_SERDES_BIST 3 ++ ++/* MC_CMD_POLL_PHY_BIST: (variadic output) ++ * Poll for BIST completion ++ * ++ * Returns a single status code, and a binary blob of phy-specific ++ * bist output. If the driver can't succesfully parse the BIST output, ++ * it should still respect the Pass/Fail in OUT.RESULT. ++ * ++ * Locks required: PHY_LOCK if doing a PHY BIST ++ * Return code: 0, EACCES (if PHY_LOCK is not held) ++ */ ++#define MC_CMD_POLL_BIST 0x26 ++#define MC_CMD_POLL_BIST_IN_LEN 0 ++#define MC_CMD_POLL_BIST_OUT_LEN UNKNOWN ++#define MC_CMD_POLL_BIST_OUT_RESULT_OFST 0 ++#define MC_CMD_POLL_BIST_RUNNING 1 ++#define MC_CMD_POLL_BIST_PASSED 2 ++#define MC_CMD_POLL_BIST_FAILED 3 ++#define MC_CMD_POLL_BIST_TIMEOUT 4 ++#define MC_CMD_POLL_BIST_OUT_PRIVATE_OFST 4 ++ ++/* MC_CMD_PHY_SPI: (variadic in, variadic out) ++ * Read/Write/Erase the PHY SPI device ++ * ++ * Locks required: PHY_LOCK ++ * Return code: 0, ETIME, EINVAL, EACCES (if PHY_LOCK is not held) ++ */ ++#define MC_CMD_PHY_SPI 0x27 ++#define MC_CMD_PHY_SPI_IN_LEN(_write_bytes) (12 + (_write_bytes)) ++#define MC_CMD_PHY_SPI_IN_ARGS_OFST 0 ++#define MC_CMD_PHY_SPI_IN_ARGS_ADDR_OFST 0 ++#define MC_CMD_PHY_SPI_IN_ARGS_READ_BYTES_OFST 4 ++#define MC_CMD_PHY_SPI_IN_ARGS_ERASE_ALL_OFST 8 ++/* Data to write here */ ++#define MC_CMD_PHY_SPI_IN_WRITE_BUFFER_OFSET 12 ++#define MC_CMD_PHY_SPI_OUT_LEN(_read_bytes) (_read_bytes) ++/* Data read here */ ++#define MC_CMD_PHY_SPI_OUT_READ_BUFFER_OFST 0 ++ ++ ++/* MC_CMD_GET_LOOPBACK_MODES: ++ * Returns a bitmask of loopback modes evailable at each speed. ++ * ++ * Locks required: None ++ * Return code: 0 ++ */ ++#define MC_CMD_GET_LOOPBACK_MODES 0x28 ++#define MC_CMD_GET_LOOPBACK_MODES_IN_LEN 0 ++#define MC_CMD_GET_LOOPBACK_MODES_OUT_LEN 32 ++#define MC_CMD_GET_LOOPBACK_MODES_100M_OFST 0 ++#define MC_CMD_GET_LOOPBACK_MODES_1G_OFST 8 ++#define MC_CMD_GET_LOOPBACK_MODES_10G_OFST 16 ++#define MC_CMD_GET_LOOPBACK_MODES_SUGGESTED_OFST 24 ++ ++/* Flow control enumeration */ ++#define MC_CMD_FCNTL_OFF 0 ++#define MC_CMD_FCNTL_RESPOND 1 ++#define MC_CMD_FCNTL_BIDIR 2 ++/* Auto - Use what the link has autonegotiated ++ * - The driver should modify the advertised capabilities via SET_LINK.CAP ++ * to control the negotiated flow control mode. ++ * - Can only be set if the PHY supports PAUSE+ASYM capabilities ++ * - Never returned by GET_LINK as the value programmed into the MAC ++ */ ++#define MC_CMD_FCNTL_AUTO 3 ++ ++/* Generic mac fault bitmask */ ++#define MC_CMD_MAC_FAULT_XGMII_LOCAL_LBN 0 ++#define MC_CMD_MAC_FAULT_XGMII_LOCAL_WIDTH 1 ++#define MC_CMD_MAC_FAULT_XGMII_REMOTE_LBN 1 ++#define MC_CMD_MAC_FAULT_XGMII_REMOTE_WIDTH 1 ++#define MC_CMD_MAC_FAULT_SGMII_REMOTE_LBN 2 ++#define MC_CMD_MAC_FAULT_SGMII_REMOTE_WIDTH 1 ++ ++/* MC_CMD_GET_LINK: ++ * Read the unified MAC/PHY link state ++ * ++ * Locks required: None ++ * Return code: 0, ETIME ++ */ ++#define MC_CMD_GET_LINK 0x29 ++#define MC_CMD_GET_LINK_IN_LEN 0 ++#define MC_CMD_GET_LINK_OUT_LEN 28 ++/* near-side and link-partner advertised capabilities */ ++#define MC_CMD_GET_LINK_OUT_CAP_OFST 0 ++#define MC_CMD_GET_LINK_OUT_LP_CAP_OFST 4 ++/* Autonegotiated speed in mbit/s. The link may still be down ++ * even if this reads non-zero */ ++#define MC_CMD_GET_LINK_OUT_LINK_SPEED_OFST 8 ++#define MC_CMD_GET_LINK_OUT_LOOPBACK_MODE_OFST 12 ++#define MC_CMD_GET_LINK_OUT_FLAGS_OFST 16 ++/* Whether we have overall link up */ ++#define MC_CMD_GET_LINK_LINK_UP_LBN 0 ++#define MC_CMD_GET_LINK_LINK_UP_WIDTH 1 ++#define MC_CMD_GET_LINK_FULL_DUPLEX_LBN 1 ++#define MC_CMD_GET_LINK_FULL_DUPLEX_WIDTH 1 ++/* Whether we have link at the layers provided by the BPX */ ++#define MC_CMD_GET_LINK_BPX_LINK_LBN 2 ++#define MC_CMD_GET_LINK_BPX_LINK_WIDTH 1 ++/* Whether the PHY has external link */ ++#define MC_CMD_GET_LINK_PHY_LINK_LBN 3 ++#define MC_CMD_GET_LINK_PHY_LINK_WIDTH 1 ++#define MC_CMD_GET_LINK_OUT_FCNTL_OFST 20 ++#define MC_CMD_GET_LINK_OUT_MAC_FAULT_OFST 24 ++ ++/* MC_CMD_SET_LINK: ++ * Write the unified MAC/PHY link configuration ++ * ++ * A loopback speed of "0" is supported, and means ++ * (choose any available speed) ++ * ++ * Locks required: None ++ * Return code: 0, EINVAL, ETIME ++ */ ++#define MC_CMD_SET_LINK 0x2a ++#define MC_CMD_SET_LINK_IN_LEN 16 ++#define MC_CMD_SET_LINK_IN_CAP_OFST 0 ++#define MC_CMD_SET_LINK_IN_FLAGS_OFST 4 ++#define MC_CMD_SET_LINK_LOWPOWER_LBN 0 ++#define MC_CMD_SET_LINK_LOWPOWER_WIDTH 1 ++#define MC_CMD_SET_LINK_POWEROFF_LBN 1 ++#define MC_CMD_SET_LINK_POWEROFF_WIDTH 1 ++#define MC_CMD_SET_LINK_TXDIS_LBN 2 ++#define MC_CMD_SET_LINK_TXDIS_WIDTH 1 ++#define MC_CMD_SET_LINK_IN_LOOPBACK_MODE_OFST 8 ++#define MC_CMD_SET_LINK_IN_LOOPBACK_SPEED_OFST 12 ++#define MC_CMD_SET_LINK_OUT_LEN 0 ++ ++/* MC_CMD_SET_ID_LED: ++ * Set indentification LED state ++ * ++ * Locks required: None ++ * Return code: 0, EINVAL ++ */ ++#define MC_CMD_SET_ID_LED 0x2b ++#define MC_CMD_SET_ID_LED_IN_LEN 4 ++#define MC_CMD_SET_ID_LED_IN_STATE_OFST 0 ++#define MC_CMD_LED_OFF 0 ++#define MC_CMD_LED_ON 1 ++#define MC_CMD_LED_DEFAULT 2 ++#define MC_CMD_SET_ID_LED_OUT_LEN 0 ++ ++/* MC_CMD_SET_MAC: ++ * Set MAC configuration ++ * ++ * The MTU is the MTU programmed directly into the XMAC/GMAC ++ * (inclusive of EtherII, VLAN, bug16011 padding) ++ * ++ * Locks required: None ++ * Return code: 0, EINVAL ++ */ ++#define MC_CMD_SET_MAC 0x2c ++#define MC_CMD_SET_MAC_IN_LEN 24 ++#define MC_CMD_SET_MAC_IN_MTU_OFST 0 ++#define MC_CMD_SET_MAC_IN_DRAIN_OFST 4 ++#define MC_CMD_SET_MAC_IN_ADDR_OFST 8 ++#define MC_CMD_SET_MAC_IN_REJECT_OFST 16 ++#define MC_CMD_SET_MAC_IN_REJECT_UNCST_LBN 0 ++#define MC_CMD_SET_MAC_IN_REJECT_UNCST_WIDTH 1 ++#define MC_CMD_SET_MAC_IN_REJECT_BRDCST_LBN 1 ++#define MC_CMD_SET_MAC_IN_REJECT_BRDCST_WIDTH 1 ++#define MC_CMD_SET_MAC_IN_FCNTL_OFST 20 ++#define MC_CMD_SET_MAC_OUT_LEN 0 ++ ++/* MC_CMD_PHY_STATS: ++ * Get generic PHY statistics ++ * ++ * This call returns the statistics for a generic PHY, by direct DMA ++ * into host memory, in a sparse array (indexed by the enumerate). ++ * Each value is represented by a 32bit number. ++ * ++ * Locks required: None ++ * Returns: 0, ETIME ++ * Response methods: shared memory, event ++ */ ++#define MC_CMD_PHY_STATS 0x2d ++#define MC_CMD_PHY_STATS_IN_LEN 8 ++#define MC_CMD_PHY_STATS_IN_DMA_ADDR_LO_OFST 0 ++#define MC_CMD_PHY_STATS_IN_DMA_ADDR_HI_OFST 4 ++#define MC_CMD_PHY_STATS_OUT_LEN 0 ++ ++/* Unified MAC statistics enumeration */ ++#define MC_CMD_MAC_GENERATION_START 0 ++#define MC_CMD_MAC_TX_PKTS 1 ++#define MC_CMD_MAC_TX_PAUSE_PKTS 2 ++#define MC_CMD_MAC_TX_CONTROL_PKTS 3 ++#define MC_CMD_MAC_TX_UNICAST_PKTS 4 ++#define MC_CMD_MAC_TX_MULTICAST_PKTS 5 ++#define MC_CMD_MAC_TX_BROADCAST_PKTS 6 ++#define MC_CMD_MAC_TX_BYTES 7 ++#define MC_CMD_MAC_TX_BAD_BYTES 8 ++#define MC_CMD_MAC_TX_LT64_PKTS 9 ++#define MC_CMD_MAC_TX_64_PKTS 10 ++#define MC_CMD_MAC_TX_65_TO_127_PKTS 11 ++#define MC_CMD_MAC_TX_128_TO_255_PKTS 12 ++#define MC_CMD_MAC_TX_256_TO_511_PKTS 13 ++#define MC_CMD_MAC_TX_512_TO_1023_PKTS 14 ++#define MC_CMD_MAC_TX_1024_TO_15XX_PKTS 15 ++#define MC_CMD_MAC_TX_15XX_TO_JUMBO_PKTS 16 ++#define MC_CMD_MAC_TX_GTJUMBO_PKTS 17 ++#define MC_CMD_MAC_TX_BAD_FCS_PKTS 18 ++#define MC_CMD_MAC_TX_SINGLE_COLLISION_PKTS 19 ++#define MC_CMD_MAC_TX_MULTIPLE_COLLISION_PKTS 20 ++#define MC_CMD_MAC_TX_EXCESSIVE_COLLISION_PKTS 21 ++#define MC_CMD_MAC_TX_LATE_COLLISION_PKTS 22 ++#define MC_CMD_MAC_TX_DEFERRED_PKTS 23 ++#define MC_CMD_MAC_TX_EXCESSIVE_DEFERRED_PKTS 24 ++#define MC_CMD_MAC_TX_NON_TCPUDP_PKTS 25 ++#define MC_CMD_MAC_TX_MAC_SRC_ERR_PKTS 26 ++#define MC_CMD_MAC_TX_IP_SRC_ERR_PKTS 27 ++#define MC_CMD_MAC_RX_PKTS 28 ++#define MC_CMD_MAC_RX_PAUSE_PKTS 29 ++#define MC_CMD_MAC_RX_GOOD_PKTS 30 ++#define MC_CMD_MAC_RX_CONTROL_PKTS 31 ++#define MC_CMD_MAC_RX_UNICAST_PKTS 32 ++#define MC_CMD_MAC_RX_MULTICAST_PKTS 33 ++#define MC_CMD_MAC_RX_BROADCAST_PKTS 34 ++#define MC_CMD_MAC_RX_BYTES 35 ++#define MC_CMD_MAC_RX_BAD_BYTES 36 ++#define MC_CMD_MAC_RX_64_PKTS 37 ++#define MC_CMD_MAC_RX_65_TO_127_PKTS 38 ++#define MC_CMD_MAC_RX_128_TO_255_PKTS 39 ++#define MC_CMD_MAC_RX_256_TO_511_PKTS 40 ++#define MC_CMD_MAC_RX_512_TO_1023_PKTS 41 ++#define MC_CMD_MAC_RX_1024_TO_15XX_PKTS 42 ++#define MC_CMD_MAC_RX_15XX_TO_JUMBO_PKTS 43 ++#define MC_CMD_MAC_RX_GTJUMBO_PKTS 44 ++#define MC_CMD_MAC_RX_UNDERSIZE_PKTS 45 ++#define MC_CMD_MAC_RX_BAD_FCS_PKTS 46 ++#define MC_CMD_MAC_RX_OVERFLOW_PKTS 47 ++#define MC_CMD_MAC_RX_FALSE_CARRIER_PKTS 48 ++#define MC_CMD_MAC_RX_SYMBOL_ERROR_PKTS 49 ++#define MC_CMD_MAC_RX_ALIGN_ERROR_PKTS 50 ++#define MC_CMD_MAC_RX_LENGTH_ERROR_PKTS 51 ++#define MC_CMD_MAC_RX_INTERNAL_ERROR_PKTS 52 ++#define MC_CMD_MAC_RX_JABBER_PKTS 53 ++#define MC_CMD_MAC_RX_NODESC_DROPS 54 ++#define MC_CMD_MAC_RX_LANES01_CHAR_ERR 55 ++#define MC_CMD_MAC_RX_LANES23_CHAR_ERR 56 ++#define MC_CMD_MAC_RX_LANES01_DISP_ERR 57 ++#define MC_CMD_MAC_RX_LANES23_DISP_ERR 58 ++#define MC_CMD_MAC_RX_MATCH_FAULT 59 ++/* Insert new members here. */ ++#define MC_CMD_MAC_GENERATION_END 60 ++#define MC_CMD_MAC_NSTATS (MC_CMD_MAC_GENERATION_END+1) ++ ++/* MC_CMD_MAC_STATS: ++ * Get unified GMAC/XMAC statistics ++ * ++ * This call returns unified statistics maintained by the MC as it ++ * switches between the GMAC and XMAC. The MC will write out all ++ * supported stats. The driver should zero initialise the buffer to ++ * guarantee consistent results. ++ * ++ * Locks required: None ++ * Returns: 0 ++ * Response methods: shared memory, event ++ */ ++#define MC_CMD_MAC_STATS 0x2e ++#define MC_CMD_MAC_STATS_IN_LEN 16 ++#define MC_CMD_MAC_STATS_IN_DMA_ADDR_LO_OFST 0 ++#define MC_CMD_MAC_STATS_IN_DMA_ADDR_HI_OFST 4 ++#define MC_CMD_MAC_STATS_IN_CMD_OFST 8 ++#define MC_CMD_MAC_STATS_CMD_DMA_LBN 0 ++#define MC_CMD_MAC_STATS_CMD_DMA_WIDTH 1 ++#define MC_CMD_MAC_STATS_CMD_CLEAR_LBN 1 ++#define MC_CMD_MAC_STATS_CMD_CLEAR_WIDTH 1 ++#define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_LBN 2 ++#define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_WIDTH 1 ++/* Fields only relevent when PERIODIC_CHANGE is set */ ++#define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_LBN 3 ++#define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_WIDTH 1 ++#define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_LBN 4 ++#define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_WIDTH 1 ++#define MC_CMD_MAC_STATS_CMD_PERIOD_MS_LBN 16 ++#define MC_CMD_MAC_STATS_CMD_PERIOD_MS_WIDTH 16 ++#define MC_CMD_MAC_STATS_IN_DMA_LEN_OFST 12 ++ ++#define MC_CMD_MAC_STATS_OUT_LEN 0 ++ ++/* Callisto flags */ ++#define MC_CMD_SFT9001_ROBUST_LBN 0 ++#define MC_CMD_SFT9001_ROBUST_WIDTH 1 ++#define MC_CMD_SFT9001_SHORT_REACH_LBN 1 ++#define MC_CMD_SFT9001_SHORT_REACH_WIDTH 1 ++ ++/* MC_CMD_SFT9001_GET: ++ * Read current callisto specific setting ++ * ++ * Locks required: None ++ * Returns: 0, ETIME ++ */ ++#define MC_CMD_SFT9001_GET 0x30 ++#define MC_CMD_SFT9001_GET_IN_LEN 0 ++#define MC_CMD_SFT9001_GET_OUT_LEN 4 ++#define MC_CMD_SFT9001_GET_OUT_FLAGS_OFST 0 ++ ++/* MC_CMD_SFT9001_SET: ++ * Write current callisto specific setting ++ * ++ * Locks required: None ++ * Returns: 0, ETIME, EINVAL ++ */ ++#define MC_CMD_SFT9001_SET 0x31 ++#define MC_CMD_SFT9001_SET_IN_LEN 4 ++#define MC_CMD_SFT9001_SET_IN_FLAGS_OFST 0 ++#define MC_CMD_SFT9001_SET_OUT_LEN 0 ++ ++ ++/* MC_CMD_WOL_FILTER_SET: ++ * Set a WoL filter ++ * ++ * Locks required: None ++ * Returns: 0, EBUSY, EINVAL, ENOSYS ++ */ ++#define MC_CMD_WOL_FILTER_SET 0x32 ++#define MC_CMD_WOL_FILTER_SET_IN_LEN 192 /* 190 rounded up to a word */ ++#define MC_CMD_WOL_FILTER_SET_IN_FILTER_MODE_OFST 0 ++#define MC_CMD_WOL_FILTER_SET_IN_WOL_TYPE_OFST 4 ++ ++/* There is a union at offset 8, following defines overlap due to ++ * this */ ++#define MC_CMD_WOL_FILTER_SET_IN_DATA_OFST 8 ++ ++#define MC_CMD_WOL_FILTER_SET_IN_MAGIC_MAC_OFST \ ++ MC_CMD_WOL_FILTER_SET_IN_DATA_OFST ++ ++#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_SRC_IP_OFST \ ++ MC_CMD_WOL_FILTER_SET_IN_DATA_OFST ++#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_DST_IP_OFST \ ++ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 4) ++#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_SRC_PORT_OFST \ ++ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 8) ++#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_DST_PORT_OFST \ ++ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 10) ++ ++#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_SRC_IP_OFST \ ++ MC_CMD_WOL_FILTER_SET_IN_DATA_OFST ++#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_DST_IP_OFST \ ++ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 16) ++#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_SRC_PORT_OFST \ ++ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 32) ++#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_DST_PORT_OFST \ ++ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 34) ++ ++#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_MASK_OFST \ ++ MC_CMD_WOL_FILTER_SET_IN_DATA_OFST ++#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_OFST \ ++ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 48) ++#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LEN_OFST \ ++ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 176) ++#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER3_OFST \ ++ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 177) ++#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER4_OFST \ ++ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 178) ++ ++#define MC_CMD_WOL_FILTER_SET_OUT_LEN 4 ++#define MC_CMD_WOL_FILTER_SET_OUT_FILTER_ID_OFST 0 ++ ++/* WOL Filter types enumeration */ ++#define MC_CMD_WOL_TYPE_MAGIC 0x0 ++ /* unused 0x1 */ ++#define MC_CMD_WOL_TYPE_WIN_MAGIC 0x2 ++#define MC_CMD_WOL_TYPE_IPV4_SYN 0x3 ++#define MC_CMD_WOL_TYPE_IPV6_SYN 0x4 ++#define MC_CMD_WOL_TYPE_BITMAP 0x5 ++#define MC_CMD_WOL_TYPE_MAX 0x6 ++ ++#define MC_CMD_FILTER_MODE_SIMPLE 0x0 ++#define MC_CMD_FILTER_MODE_STRUCTURED 0xffffffff ++ ++/* MC_CMD_WOL_FILTER_REMOVE: ++ * Remove a WoL filter ++ * ++ * Locks required: None ++ * Returns: 0, EINVAL, ENOSYS ++ */ ++#define MC_CMD_WOL_FILTER_REMOVE 0x33 ++#define MC_CMD_WOL_FILTER_REMOVE_IN_LEN 4 ++#define MC_CMD_WOL_FILTER_REMOVE_IN_FILTER_ID_OFST 0 ++#define MC_CMD_WOL_FILTER_REMOVE_OUT_LEN 0 ++ ++ ++/* MC_CMD_WOL_FILTER_RESET: ++ * Reset (i.e. remove all) WoL filters ++ * ++ * Locks required: None ++ * Returns: 0, ENOSYS ++ */ ++#define MC_CMD_WOL_FILTER_RESET 0x34 ++#define MC_CMD_WOL_FILTER_RESET_IN_LEN 0 ++#define MC_CMD_WOL_FILTER_RESET_OUT_LEN 0 ++ ++/* MC_CMD_SET_MCAST_HASH: ++ * Set the MCASH hash value without otherwise ++ * reconfiguring the MAC ++ */ ++#define MC_CMD_SET_MCAST_HASH 0x35 ++#define MC_CMD_SET_MCAST_HASH_IN_LEN 32 ++#define MC_CMD_SET_MCAST_HASH_IN_HASH0_OFST 0 ++#define MC_CMD_SET_MCAST_HASH_IN_HASH1_OFST 16 ++#define MC_CMD_SET_MCAST_HASH_OUT_LEN 0 ++ ++/* MC_CMD_NVRAM_TYPES: ++ * Return bitfield indicating available types of virtual NVRAM partitions ++ * ++ * Locks required: none ++ * Returns: 0 ++ */ ++#define MC_CMD_NVRAM_TYPES 0x36 ++#define MC_CMD_NVRAM_TYPES_IN_LEN 0 ++#define MC_CMD_NVRAM_TYPES_OUT_LEN 4 ++#define MC_CMD_NVRAM_TYPES_OUT_TYPES_OFST 0 ++ ++/* Supported NVRAM types */ ++#define MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO 0 ++#define MC_CMD_NVRAM_TYPE_MC_FW 1 ++#define MC_CMD_NVRAM_TYPE_MC_FW_BACKUP 2 ++#define MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 3 ++#define MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1 4 ++#define MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 5 ++#define MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1 6 ++#define MC_CMD_NVRAM_TYPE_EXP_ROM 7 ++#define MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0 8 ++#define MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1 9 ++#define MC_CMD_NVRAM_TYPE_PHY_PORT0 10 ++#define MC_CMD_NVRAM_TYPE_PHY_PORT1 11 ++#define MC_CMD_NVRAM_TYPE_LOG 12 ++ ++/* MC_CMD_NVRAM_INFO: ++ * Read info about a virtual NVRAM partition ++ * ++ * Locks required: none ++ * Returns: 0, EINVAL (bad type) ++ */ ++#define MC_CMD_NVRAM_INFO 0x37 ++#define MC_CMD_NVRAM_INFO_IN_LEN 4 ++#define MC_CMD_NVRAM_INFO_IN_TYPE_OFST 0 ++#define MC_CMD_NVRAM_INFO_OUT_LEN 24 ++#define MC_CMD_NVRAM_INFO_OUT_TYPE_OFST 0 ++#define MC_CMD_NVRAM_INFO_OUT_SIZE_OFST 4 ++#define MC_CMD_NVRAM_INFO_OUT_ERASESIZE_OFST 8 ++#define MC_CMD_NVRAM_INFO_OUT_FLAGS_OFST 12 ++#define MC_CMD_NVRAM_PROTECTED_LBN 0 ++#define MC_CMD_NVRAM_PROTECTED_WIDTH 1 ++#define MC_CMD_NVRAM_INFO_OUT_PHYSDEV_OFST 16 ++#define MC_CMD_NVRAM_INFO_OUT_PHYSADDR_OFST 20 ++ ++/* MC_CMD_NVRAM_UPDATE_START: ++ * Start a group of update operations on a virtual NVRAM partition ++ * ++ * Locks required: PHY_LOCK if type==*PHY* ++ * Returns: 0, EINVAL (bad type), EACCES (if PHY_LOCK required and not held) ++ */ ++#define MC_CMD_NVRAM_UPDATE_START 0x38 ++#define MC_CMD_NVRAM_UPDATE_START_IN_LEN 4 ++#define MC_CMD_NVRAM_UPDATE_START_IN_TYPE_OFST 0 ++#define MC_CMD_NVRAM_UPDATE_START_OUT_LEN 0 ++ ++/* MC_CMD_NVRAM_READ: ++ * Read data from a virtual NVRAM partition ++ * ++ * Locks required: PHY_LOCK if type==*PHY* ++ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) ++ */ ++#define MC_CMD_NVRAM_READ 0x39 ++#define MC_CMD_NVRAM_READ_IN_LEN 12 ++#define MC_CMD_NVRAM_READ_IN_TYPE_OFST 0 ++#define MC_CMD_NVRAM_READ_IN_OFFSET_OFST 4 ++#define MC_CMD_NVRAM_READ_IN_LENGTH_OFST 8 ++#define MC_CMD_NVRAM_READ_OUT_LEN(_read_bytes) (_read_bytes) ++#define MC_CMD_NVRAM_READ_OUT_READ_BUFFER_OFST 0 ++ ++/* MC_CMD_NVRAM_WRITE: ++ * Write data to a virtual NVRAM partition ++ * ++ * Locks required: PHY_LOCK if type==*PHY* ++ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) ++ */ ++#define MC_CMD_NVRAM_WRITE 0x3a ++#define MC_CMD_NVRAM_WRITE_IN_TYPE_OFST 0 ++#define MC_CMD_NVRAM_WRITE_IN_OFFSET_OFST 4 ++#define MC_CMD_NVRAM_WRITE_IN_LENGTH_OFST 8 ++#define MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_OFST 12 ++#define MC_CMD_NVRAM_WRITE_IN_LEN(_write_bytes) (12 + _write_bytes) ++#define MC_CMD_NVRAM_WRITE_OUT_LEN 0 ++ ++/* MC_CMD_NVRAM_ERASE: ++ * Erase sector(s) from a virtual NVRAM partition ++ * ++ * Locks required: PHY_LOCK if type==*PHY* ++ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) ++ */ ++#define MC_CMD_NVRAM_ERASE 0x3b ++#define MC_CMD_NVRAM_ERASE_IN_LEN 12 ++#define MC_CMD_NVRAM_ERASE_IN_TYPE_OFST 0 ++#define MC_CMD_NVRAM_ERASE_IN_OFFSET_OFST 4 ++#define MC_CMD_NVRAM_ERASE_IN_LENGTH_OFST 8 ++#define MC_CMD_NVRAM_ERASE_OUT_LEN 0 ++ ++/* MC_CMD_NVRAM_UPDATE_FINISH: ++ * Finish a group of update operations on a virtual NVRAM partition ++ * ++ * Locks required: PHY_LOCK if type==*PHY* ++ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) ++ */ ++#define MC_CMD_NVRAM_UPDATE_FINISH 0x3c ++#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 4 ++#define MC_CMD_NVRAM_UPDATE_FINISH_IN_TYPE_OFST 0 ++#define MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN 0 ++ ++/* MC_CMD_REBOOT: ++ * Reboot the MC. The AFTER_ASSERTION flag is intended to be used ++ * when the driver notices an assertion failure, to allow two ports to ++ * both recover (semi-)gracefully. ++ * ++ * Locks required: NONE ++ * Returns: Nothing. You get back a response with ERR=1, DATALEN=0 ++ */ ++#define MC_CMD_REBOOT 0x3d ++#define MC_CMD_REBOOT_IN_LEN 4 ++#define MC_CMD_REBOOT_IN_FLAGS_OFST 0 ++#define MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION 1 ++#define MC_CMD_REBOOT_OUT_LEN 0 ++ ++/* MC_CMD_SCHEDINFO: ++ * Request scheduler info. from the MC. ++ * ++ * Locks required: NONE ++ * Returns: An array of (timeslice,maximum overrun), one for each thread, ++ * in ascending order of thread address.s ++ */ ++#define MC_CMD_SCHEDINFO 0x3e ++#define MC_CMD_SCHEDINFO_IN_LEN 0 ++ ++ ++/* MC_CMD_SET_REBOOT_MODE: (debug) ++ * Set the mode for the next MC reboot. ++ * ++ * Locks required: NONE ++ * ++ * Sets the reboot mode to the specified value. Returns the old mode. ++ */ ++#define MC_CMD_REBOOT_MODE 0x3f ++#define MC_CMD_REBOOT_MODE_IN_LEN 4 ++#define MC_CMD_REBOOT_MODE_IN_VALUE_OFST 0 ++#define MC_CMD_REBOOT_MODE_OUT_LEN 4 ++#define MC_CMD_REBOOT_MODE_OUT_VALUE_OFST 0 ++#define MC_CMD_REBOOT_MODE_NORMAL 0 ++#define MC_CMD_REBOOT_MODE_SNAPPER 3 ++ ++/* MC_CMD_DEBUG_LOG: ++ * Null request/response command (debug) ++ * - sequence number is always zero ++ * - only supported on the UART interface ++ * (the same set of bytes is delivered as an ++ * event over PCI) ++ */ ++#define MC_CMD_DEBUG_LOG 0x40 ++#define MC_CMD_DEBUG_LOG_IN_LEN 0 ++#define MC_CMD_DEBUG_LOG_OUT_LEN 0 ++ ++/* Generic sensor enumeration. Note that a dual port NIC ++ * will EITHER expose PHY_COMMON_TEMP OR PHY0_TEMP and ++ * PHY1_TEMP depending on whether there is a single sensor ++ * in the vicinity of the two port, or one per port. ++ */ ++#define MC_CMD_SENSOR_CONTROLLER_TEMP 0 /* degC */ ++#define MC_CMD_SENSOR_PHY_COMMON_TEMP 1 /* degC */ ++#define MC_CMD_SENSOR_CONTROLLER_COOLING 2 /* bool */ ++#define MC_CMD_SENSOR_PHY0_TEMP 3 /* degC */ ++#define MC_CMD_SENSOR_PHY0_COOLING 4 /* bool */ ++#define MC_CMD_SENSOR_PHY1_TEMP 5 /* degC */ ++#define MC_CMD_SENSOR_PHY1_COOLING 6 /* bool */ ++#define MC_CMD_SENSOR_IN_1V0 7 /* mV */ ++#define MC_CMD_SENSOR_IN_1V2 8 /* mV */ ++#define MC_CMD_SENSOR_IN_1V8 9 /* mV */ ++#define MC_CMD_SENSOR_IN_2V5 10 /* mV */ ++#define MC_CMD_SENSOR_IN_3V3 11 /* mV */ ++#define MC_CMD_SENSOR_IN_12V0 12 /* mV */ ++ ++ ++/* Sensor state */ ++#define MC_CMD_SENSOR_STATE_OK 0 ++#define MC_CMD_SENSOR_STATE_WARNING 1 ++#define MC_CMD_SENSOR_STATE_FATAL 2 ++#define MC_CMD_SENSOR_STATE_BROKEN 3 ++ ++/* MC_CMD_SENSOR_INFO: ++ * Returns information about every available sensor. ++ * ++ * Each sensor has a single (16bit) value, and a corresponding state. ++ * The mapping between value and sensor is nominally determined by the ++ * MC, but in practise is implemented as zero (BROKEN), one (TEMPERATURE), ++ * or two (VOLTAGE) ranges per sensor per state. ++ * ++ * This call returns a mask (32bit) of the sensors that are supported ++ * by this platform, then an array (indexed by MC_CMD_SENSOR) of byte ++ * offsets to the per-sensor arrays. Each sensor array has four 16bit ++ * numbers, min1, max1, min2, max2. ++ * ++ * Locks required: None ++ * Returns: 0 ++ */ ++#define MC_CMD_SENSOR_INFO 0x41 ++#define MC_CMD_SENSOR_INFO_IN_LEN 0 ++#define MC_CMD_SENSOR_INFO_OUT_MASK_OFST 0 ++#define MC_CMD_SENSOR_INFO_OUT_OFFSET_OFST(_x) \ ++ (4 + (_x)) ++#define MC_CMD_SENSOR_INFO_OUT_MIN1_OFST(_ofst) \ ++ ((_ofst) + 0) ++#define MC_CMD_SENSOR_INFO_OUT_MAX1_OFST(_ofst) \ ++ ((_ofst) + 2) ++#define MC_CMD_SENSOR_INFO_OUT_MIN2_OFST(_ofst) \ ++ ((_ofst) + 4) ++#define MC_CMD_SENSOR_INFO_OUT_MAX2_OFST(_ofst) \ ++ ((_ofst) + 6) ++ ++/* MC_CMD_READ_SENSORS ++ * Returns the current (value, state) for each sensor ++ * ++ * Returns the current (value, state) [each 16bit] of each sensor supported by ++ * this board, by DMA'ing a sparse array (indexed by the sensor type) into host ++ * memory. ++ * ++ * The MC will send a SENSOREVT event every time any sensor changes state. The ++ * driver is responsible for ensuring that it doesn't miss any events. The board ++ * will function normally if all sensors are in STATE_OK or state_WARNING. ++ * Otherwise the board should not be expected to function. ++ */ ++#define MC_CMD_READ_SENSORS 0x42 ++#define MC_CMD_READ_SENSORS_IN_LEN 8 ++#define MC_CMD_READ_SENSORS_IN_DMA_ADDR_LO_OFST 0 ++#define MC_CMD_READ_SENSORS_IN_DMA_ADDR_HI_OFST 4 ++#define MC_CMD_READ_SENSORS_OUT_LEN 0 ++ ++ ++/* MC_CMD_GET_PHY_STATE: ++ * Report current state of PHY. A "zombie" PHY is a PHY that has failed to ++ * boot (e.g. due to missing or corrupted firmware). ++ * ++ * Locks required: None ++ * Return code: 0 ++ */ ++#define MC_CMD_GET_PHY_STATE 0x43 ++ ++#define MC_CMD_GET_PHY_STATE_IN_LEN 0 ++#define MC_CMD_GET_PHY_STATE_OUT_LEN 4 ++#define MC_CMD_GET_PHY_STATE_STATE_OFST 0 ++/* PHY state enumeration: */ ++#define MC_CMD_PHY_STATE_OK 1 ++#define MC_CMD_PHY_STATE_ZOMBIE 2 ++ ++ ++/* 802.1Qbb control. 8 Tx queues that map to priorities 0 - 7. Use all 1s to ++ * disable 802.Qbb for a given priority. */ ++#define MC_CMD_SETUP_8021QBB 0x44 ++#define MC_CMD_SETUP_8021QBB_IN_LEN 32 ++#define MC_CMD_SETUP_8021QBB_OUT_LEN 0 ++#define MC_CMD_SETUP_8021QBB_IN_TXQS_OFFST 0 ++ ++ ++/* MC_CMD_WOL_FILTER_GET: ++ * Retrieve ID of any WoL filters ++ * ++ * Locks required: None ++ * Returns: 0, ENOSYS ++ */ ++#define MC_CMD_WOL_FILTER_GET 0x45 ++#define MC_CMD_WOL_FILTER_GET_IN_LEN 0 ++#define MC_CMD_WOL_FILTER_GET_OUT_LEN 4 ++#define MC_CMD_WOL_FILTER_GET_OUT_FILTER_ID_OFST 0 ++ ++ ++/* MC_CMD_ADD_LIGHTSOUT_OFFLOAD: ++ * Offload a protocol to NIC for lights-out state ++ * ++ * Locks required: None ++ * Returns: 0, ENOSYS ++ */ ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD 0x46 ++ ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_LEN 16 ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_PROTOCOL_OFST 0 ++ ++/* There is a union at offset 4, following defines overlap due to ++ * this */ ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_DATA_OFST 4 ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARPMAC_OFST 4 ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARPIP_OFST 10 ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSMAC_OFST 4 ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSSNIPV6_OFST 10 ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSIPV6_OFST 26 ++ ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN 4 ++#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_FILTER_ID_OFST 0 ++ ++ ++/* MC_CMD_REMOVE_LIGHTSOUT_PROTOCOL_OFFLOAD: ++ * Offload a protocol to NIC for lights-out state ++ * ++ * Locks required: None ++ * Returns: 0, ENOSYS ++ */ ++#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD 0x47 ++#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN 8 ++#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_OUT_LEN 0 ++ ++#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_PROTOCOL_OFST 0 ++#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_FILTER_ID_OFST 4 ++ ++/* Lights-out offload protocols enumeration */ ++#define MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_ARP 0x1 ++#define MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_NS 0x2 ++ ++ ++/* MC_CMD_MAC_RESET_RESTORE: ++ * Restore MAC after block reset ++ * ++ * Locks required: None ++ * Returns: 0 ++ */ ++ ++#define MC_CMD_MAC_RESET_RESTORE 0x48 ++#define MC_CMD_MAC_RESET_RESTORE_IN_LEN 0 ++#define MC_CMD_MAC_RESET_RESTORE_OUT_LEN 0 ++ ++#endif /* MCDI_PCOL_H */ +diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c +new file mode 100644 +index 0000000..0e1bcc5 +--- /dev/null ++++ b/drivers/net/sfc/mcdi_phy.c +@@ -0,0 +1,597 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++/* ++ * Driver for PHY related operations via MCDI. ++ */ ++ ++#include "efx.h" ++#include "phy.h" ++#include "mcdi.h" ++#include "mcdi_pcol.h" ++#include "mdio_10g.h" ++ ++struct efx_mcdi_phy_cfg { ++ u32 flags; ++ u32 type; ++ u32 supported_cap; ++ u32 channel; ++ u32 port; ++ u32 stats_mask; ++ u8 name[20]; ++ u32 media; ++ u32 mmd_mask; ++ u8 revision[20]; ++ u32 forced_cap; ++}; ++ ++static int ++efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg) ++{ ++ u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN]; ++ size_t outlen; ++ int rc; ++ ++ BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_IN_LEN != 0); ++ BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_OUT_NAME_LEN != sizeof(cfg->name)); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_CFG, NULL, 0, ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ ++ if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) { ++ rc = -EMSGSIZE; ++ goto fail; ++ } ++ ++ cfg->flags = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_FLAGS); ++ cfg->type = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_TYPE); ++ cfg->supported_cap = ++ MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_SUPPORTED_CAP); ++ cfg->channel = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_CHANNEL); ++ cfg->port = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_PRT); ++ cfg->stats_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_STATS_MASK); ++ memcpy(cfg->name, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_NAME), ++ sizeof(cfg->name)); ++ cfg->media = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MEDIA_TYPE); ++ cfg->mmd_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MMD_MASK); ++ memcpy(cfg->revision, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_REVISION), ++ sizeof(cfg->revision)); ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++static int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities, ++ u32 flags, u32 loopback_mode, ++ u32 loopback_speed) ++{ ++ u8 inbuf[MC_CMD_SET_LINK_IN_LEN]; ++ int rc; ++ ++ BUILD_BUG_ON(MC_CMD_SET_LINK_OUT_LEN != 0); ++ ++ MCDI_SET_DWORD(inbuf, SET_LINK_IN_CAP, capabilities); ++ MCDI_SET_DWORD(inbuf, SET_LINK_IN_FLAGS, flags); ++ MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_MODE, loopback_mode); ++ MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_SPEED, loopback_speed); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf), ++ NULL, 0, NULL); ++ if (rc) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++static int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes) ++{ ++ u8 outbuf[MC_CMD_GET_LOOPBACK_MODES_OUT_LEN]; ++ size_t outlen; ++ int rc; ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LOOPBACK_MODES, NULL, 0, ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ ++ if (outlen < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) { ++ rc = -EMSGSIZE; ++ goto fail; ++ } ++ ++ *loopback_modes = MCDI_QWORD(outbuf, GET_LOOPBACK_MODES_SUGGESTED); ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, ++ unsigned int prtad, unsigned int devad, u16 addr, ++ u16 *value_out, u32 *status_out) ++{ ++ u8 inbuf[MC_CMD_MDIO_READ_IN_LEN]; ++ u8 outbuf[MC_CMD_MDIO_READ_OUT_LEN]; ++ size_t outlen; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, bus); ++ MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad); ++ MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad); ++ MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf), ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ ++ *value_out = (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE); ++ *status_out = MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS); ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus, ++ unsigned int prtad, unsigned int devad, u16 addr, ++ u16 value, u32 *status_out) ++{ ++ u8 inbuf[MC_CMD_MDIO_WRITE_IN_LEN]; ++ u8 outbuf[MC_CMD_MDIO_WRITE_OUT_LEN]; ++ size_t outlen; ++ int rc; ++ ++ MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_BUS, bus); ++ MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_PRTAD, prtad); ++ MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_DEVAD, devad); ++ MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_ADDR, addr); ++ MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_VALUE, value); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf), ++ outbuf, sizeof(outbuf), &outlen); ++ if (rc) ++ goto fail; ++ ++ *status_out = MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS); ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return rc; ++} ++ ++static u32 mcdi_to_ethtool_cap(u32 media, u32 cap) ++{ ++ u32 result = 0; ++ ++ switch (media) { ++ case MC_CMD_MEDIA_KX4: ++ result |= SUPPORTED_Backplane; ++ if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) ++ result |= SUPPORTED_1000baseKX_Full; ++ if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) ++ result |= SUPPORTED_10000baseKX4_Full; ++ break; ++ ++ case MC_CMD_MEDIA_XFP: ++ case MC_CMD_MEDIA_SFP_PLUS: ++ result |= SUPPORTED_FIBRE; ++ break; ++ ++ case MC_CMD_MEDIA_BASE_T: ++ result |= SUPPORTED_TP; ++ if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) ++ result |= SUPPORTED_10baseT_Half; ++ if (cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) ++ result |= SUPPORTED_10baseT_Full; ++ if (cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) ++ result |= SUPPORTED_100baseT_Half; ++ if (cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) ++ result |= SUPPORTED_100baseT_Full; ++ if (cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) ++ result |= SUPPORTED_1000baseT_Half; ++ if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) ++ result |= SUPPORTED_1000baseT_Full; ++ if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) ++ result |= SUPPORTED_10000baseT_Full; ++ break; ++ } ++ ++ if (cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) ++ result |= SUPPORTED_Pause; ++ if (cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) ++ result |= SUPPORTED_Asym_Pause; ++ if (cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) ++ result |= SUPPORTED_Autoneg; ++ ++ return result; ++} ++ ++static u32 ethtool_to_mcdi_cap(u32 cap) ++{ ++ u32 result = 0; ++ ++ if (cap & SUPPORTED_10baseT_Half) ++ result |= (1 << MC_CMD_PHY_CAP_10HDX_LBN); ++ if (cap & SUPPORTED_10baseT_Full) ++ result |= (1 << MC_CMD_PHY_CAP_10FDX_LBN); ++ if (cap & SUPPORTED_100baseT_Half) ++ result |= (1 << MC_CMD_PHY_CAP_100HDX_LBN); ++ if (cap & SUPPORTED_100baseT_Full) ++ result |= (1 << MC_CMD_PHY_CAP_100FDX_LBN); ++ if (cap & SUPPORTED_1000baseT_Half) ++ result |= (1 << MC_CMD_PHY_CAP_1000HDX_LBN); ++ if (cap & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseKX_Full)) ++ result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN); ++ if (cap & (SUPPORTED_10000baseT_Full | SUPPORTED_10000baseKX4_Full)) ++ result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN); ++ if (cap & SUPPORTED_Pause) ++ result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN); ++ if (cap & SUPPORTED_Asym_Pause) ++ result |= (1 << MC_CMD_PHY_CAP_ASYM_LBN); ++ if (cap & SUPPORTED_Autoneg) ++ result |= (1 << MC_CMD_PHY_CAP_AN_LBN); ++ ++ return result; ++} ++ ++static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx) ++{ ++ struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; ++ enum efx_phy_mode mode, supported; ++ u32 flags; ++ ++ /* TODO: Advertise the capabilities supported by this PHY */ ++ supported = 0; ++ if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_TXDIS_LBN)) ++ supported |= PHY_MODE_TX_DISABLED; ++ if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_LOWPOWER_LBN)) ++ supported |= PHY_MODE_LOW_POWER; ++ if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_POWEROFF_LBN)) ++ supported |= PHY_MODE_OFF; ++ ++ mode = efx->phy_mode & supported; ++ ++ flags = 0; ++ if (mode & PHY_MODE_TX_DISABLED) ++ flags |= (1 << MC_CMD_SET_LINK_TXDIS_LBN); ++ if (mode & PHY_MODE_LOW_POWER) ++ flags |= (1 << MC_CMD_SET_LINK_LOWPOWER_LBN); ++ if (mode & PHY_MODE_OFF) ++ flags |= (1 << MC_CMD_SET_LINK_POWEROFF_LBN); ++ ++ return flags; ++} ++ ++static u32 mcdi_to_ethtool_media(u32 media) ++{ ++ switch (media) { ++ case MC_CMD_MEDIA_XAUI: ++ case MC_CMD_MEDIA_CX4: ++ case MC_CMD_MEDIA_KX4: ++ return PORT_OTHER; ++ ++ case MC_CMD_MEDIA_XFP: ++ case MC_CMD_MEDIA_SFP_PLUS: ++ return PORT_FIBRE; ++ ++ case MC_CMD_MEDIA_BASE_T: ++ return PORT_TP; ++ ++ default: ++ return PORT_OTHER; ++ } ++} ++ ++static int efx_mcdi_phy_probe(struct efx_nic *efx) ++{ ++ struct efx_mcdi_phy_cfg *phy_cfg; ++ int rc; ++ ++ /* TODO: Move phy_data initialisation to ++ * phy_op->probe/remove, rather than init/fini */ ++ phy_cfg = kzalloc(sizeof(*phy_cfg), GFP_KERNEL); ++ if (phy_cfg == NULL) { ++ rc = -ENOMEM; ++ goto fail_alloc; ++ } ++ rc = efx_mcdi_get_phy_cfg(efx, phy_cfg); ++ if (rc != 0) ++ goto fail; ++ ++ efx->phy_type = phy_cfg->type; ++ ++ efx->mdio_bus = phy_cfg->channel; ++ efx->mdio.prtad = phy_cfg->port; ++ efx->mdio.mmds = phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); ++ efx->mdio.mode_support = 0; ++ if (phy_cfg->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) ++ efx->mdio.mode_support |= MDIO_SUPPORTS_C22; ++ if (phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) ++ efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; ++ ++ /* Assert that we can map efx -> mcdi loopback modes */ ++ BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE); ++ BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA); ++ BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC); ++ BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII); ++ BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS); ++ BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI); ++ BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII); ++ BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII); ++ BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR); ++ BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI); ++ BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR); ++ BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR); ++ BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR); ++ BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR); ++ BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY); ++ BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS); ++ BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS); ++ BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD); ++ BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT); ++ BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS); ++ BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS); ++ BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR); ++ BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR); ++ BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS); ++ BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS); ++ BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR); ++ BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS); ++ ++ rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes); ++ if (rc != 0) ++ goto fail; ++ /* The MC indicates that LOOPBACK_NONE is a valid loopback mode, ++ * but by convention we don't */ ++ efx->loopback_modes &= ~(1 << LOOPBACK_NONE); ++ ++ kfree(phy_cfg); ++ ++ return 0; ++ ++fail: ++ kfree(phy_cfg); ++fail_alloc: ++ return rc; ++} ++ ++static int efx_mcdi_phy_init(struct efx_nic *efx) ++{ ++ struct efx_mcdi_phy_cfg *phy_data; ++ u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; ++ u32 caps; ++ int rc; ++ ++ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); ++ if (phy_data == NULL) ++ return -ENOMEM; ++ ++ rc = efx_mcdi_get_phy_cfg(efx, phy_data); ++ if (rc != 0) ++ goto fail; ++ ++ efx->phy_data = phy_data; ++ ++ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); ++ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, ++ outbuf, sizeof(outbuf), NULL); ++ if (rc) ++ goto fail; ++ ++ caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); ++ if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) ++ efx->link_advertising = ++ mcdi_to_ethtool_cap(phy_data->media, caps); ++ else ++ phy_data->forced_cap = caps; ++ ++ return 0; ++ ++fail: ++ kfree(phy_data); ++ return rc; ++} ++ ++int efx_mcdi_phy_reconfigure(struct efx_nic *efx) ++{ ++ struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; ++ u32 caps = (efx->link_advertising ? ++ ethtool_to_mcdi_cap(efx->link_advertising) : ++ phy_cfg->forced_cap); ++ ++ return efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), ++ efx->loopback_mode, 0); ++} ++ ++void efx_mcdi_phy_decode_link(struct efx_nic *efx, ++ struct efx_link_state *link_state, ++ u32 speed, u32 flags, u32 fcntl) ++{ ++ switch (fcntl) { ++ case MC_CMD_FCNTL_AUTO: ++ WARN_ON(1); /* This is not a link mode */ ++ link_state->fc = EFX_FC_AUTO | EFX_FC_TX | EFX_FC_RX; ++ break; ++ case MC_CMD_FCNTL_BIDIR: ++ link_state->fc = EFX_FC_TX | EFX_FC_RX; ++ break; ++ case MC_CMD_FCNTL_RESPOND: ++ link_state->fc = EFX_FC_RX; ++ break; ++ default: ++ WARN_ON(1); ++ case MC_CMD_FCNTL_OFF: ++ link_state->fc = 0; ++ break; ++ } ++ ++ link_state->up = !!(flags & (1 << MC_CMD_GET_LINK_LINK_UP_LBN)); ++ link_state->fd = !!(flags & (1 << MC_CMD_GET_LINK_FULL_DUPLEX_LBN)); ++ link_state->speed = speed; ++} ++ ++/* Verify that the forced flow control settings (!EFX_FC_AUTO) are ++ * supported by the link partner. Warn the user if this isn't the case ++ */ ++void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa) ++{ ++ struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; ++ u32 rmtadv; ++ ++ /* The link partner capabilities are only relevent if the ++ * link supports flow control autonegotiation */ ++ if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) ++ return; ++ ++ /* If flow control autoneg is supported and enabled, then fine */ ++ if (efx->wanted_fc & EFX_FC_AUTO) ++ return; ++ ++ rmtadv = 0; ++ if (lpa & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) ++ rmtadv |= ADVERTISED_Pause; ++ if (lpa & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) ++ rmtadv |= ADVERTISED_Asym_Pause; ++ ++ if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause) ++ EFX_ERR(efx, "warning: link partner doesn't support " ++ "pause frames"); ++} ++ ++static bool efx_mcdi_phy_poll(struct efx_nic *efx) ++{ ++ struct efx_link_state old_state = efx->link_state; ++ u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; ++ int rc; ++ ++ WARN_ON(!mutex_is_locked(&efx->mac_lock)); ++ ++ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); ++ ++ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, ++ outbuf, sizeof(outbuf), NULL); ++ if (rc) { ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ efx->link_state.up = false; ++ } else { ++ efx_mcdi_phy_decode_link( ++ efx, &efx->link_state, ++ MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), ++ MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), ++ MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); ++ } ++ ++ return !efx_link_state_equal(&efx->link_state, &old_state); ++} ++ ++static void efx_mcdi_phy_fini(struct efx_nic *efx) ++{ ++ struct efx_mcdi_phy_data *phy_data = efx->phy_data; ++ ++ efx->phy_data = NULL; ++ kfree(phy_data); ++} ++ ++static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) ++{ ++ struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; ++ u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; ++ int rc; ++ ++ ecmd->supported = ++ mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap); ++ ecmd->advertising = efx->link_advertising; ++ ecmd->speed = efx->link_state.speed; ++ ecmd->duplex = efx->link_state.fd; ++ ecmd->port = mcdi_to_ethtool_media(phy_cfg->media); ++ ecmd->phy_address = phy_cfg->port; ++ ecmd->transceiver = XCVR_INTERNAL; ++ ecmd->autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg); ++ ecmd->mdio_support = (efx->mdio.mode_support & ++ (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22)); ++ ++ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); ++ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, ++ outbuf, sizeof(outbuf), NULL); ++ if (rc) { ++ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); ++ return; ++ } ++ ecmd->lp_advertising = ++ mcdi_to_ethtool_cap(phy_cfg->media, ++ MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP)); ++} ++ ++static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) ++{ ++ struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; ++ u32 caps; ++ int rc; ++ ++ if (ecmd->autoneg) { ++ caps = (ethtool_to_mcdi_cap(ecmd->advertising) | ++ 1 << MC_CMD_PHY_CAP_AN_LBN); ++ } else if (ecmd->duplex) { ++ switch (ecmd->speed) { ++ case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break; ++ case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break; ++ case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break; ++ case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break; ++ default: return -EINVAL; ++ } ++ } else { ++ switch (ecmd->speed) { ++ case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break; ++ case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break; ++ case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break; ++ default: return -EINVAL; ++ } ++ } ++ ++ rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), ++ efx->loopback_mode, 0); ++ if (rc) ++ return rc; ++ ++ if (ecmd->autoneg) { ++ efx_link_set_advertising( ++ efx, ecmd->advertising | ADVERTISED_Autoneg); ++ phy_cfg->forced_cap = 0; ++ } else { ++ efx_link_set_advertising(efx, 0); ++ phy_cfg->forced_cap = caps; ++ } ++ return 0; ++} ++ ++struct efx_phy_operations efx_mcdi_phy_ops = { ++ .probe = efx_mcdi_phy_probe, ++ .init = efx_mcdi_phy_init, ++ .reconfigure = efx_mcdi_phy_reconfigure, ++ .poll = efx_mcdi_phy_poll, ++ .fini = efx_mcdi_phy_fini, ++ .get_settings = efx_mcdi_phy_get_settings, ++ .set_settings = efx_mcdi_phy_set_settings, ++ .run_tests = NULL, ++ .test_name = NULL, ++}; +diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c +index 6c33459..1574e52 100644 +--- a/drivers/net/sfc/mdio_10g.c ++++ b/drivers/net/sfc/mdio_10g.c +@@ -1,6 +1,6 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -14,8 +14,8 @@ + #include + #include "net_driver.h" + #include "mdio_10g.h" +-#include "boards.h" + #include "workarounds.h" ++#include "nic.h" + + unsigned efx_mdio_id_oui(u32 id) + { +@@ -174,7 +174,7 @@ bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask) + * of mmd's */ + if (LOOPBACK_INTERNAL(efx)) + return true; +- else if (efx->loopback_mode == LOOPBACK_NETWORK) ++ else if (LOOPBACK_MASK(efx) & LOOPBACKS_WS) + return false; + else if (efx_phy_mode_disabled(efx->phy_mode)) + return false; +@@ -211,7 +211,7 @@ void efx_mdio_phy_reconfigure(struct efx_nic *efx) + efx->loopback_mode == LOOPBACK_PCS); + efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, + MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK, +- efx->loopback_mode == LOOPBACK_NETWORK); ++ efx->loopback_mode == LOOPBACK_PHYXS_WS); + } + + static void efx_mdio_set_mmd_lpower(struct efx_nic *efx, +@@ -249,8 +249,6 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx, + int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) + { + struct ethtool_cmd prev; +- u32 required; +- int reg; + + efx->phy_op->get_settings(efx, &prev); + +@@ -266,86 +264,74 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) + return -EINVAL; + + /* Check that PHY supports these settings */ +- if (ecmd->autoneg) { +- required = SUPPORTED_Autoneg; +- } else if (ecmd->duplex) { +- switch (ecmd->speed) { +- case SPEED_10: required = SUPPORTED_10baseT_Full; break; +- case SPEED_100: required = SUPPORTED_100baseT_Full; break; +- default: return -EINVAL; +- } +- } else { +- switch (ecmd->speed) { +- case SPEED_10: required = SUPPORTED_10baseT_Half; break; +- case SPEED_100: required = SUPPORTED_100baseT_Half; break; +- default: return -EINVAL; +- } +- } +- required |= ecmd->advertising; +- if (required & ~prev.supported) ++ if (!ecmd->autoneg || ++ (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported) + return -EINVAL; + +- if (ecmd->autoneg) { +- bool xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full +- || EFX_WORKAROUND_13204(efx)); +- +- /* Set up the base page */ +- reg = ADVERTISE_CSMA; +- if (ecmd->advertising & ADVERTISED_10baseT_Half) +- reg |= ADVERTISE_10HALF; +- if (ecmd->advertising & ADVERTISED_10baseT_Full) +- reg |= ADVERTISE_10FULL; +- if (ecmd->advertising & ADVERTISED_100baseT_Half) +- reg |= ADVERTISE_100HALF; +- if (ecmd->advertising & ADVERTISED_100baseT_Full) +- reg |= ADVERTISE_100FULL; +- if (xnp) +- reg |= ADVERTISE_RESV; +- else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | +- ADVERTISED_1000baseT_Full)) +- reg |= ADVERTISE_NPAGE; +- reg |= mii_advertise_flowctrl(efx->wanted_fc); +- efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); +- +- /* Set up the (extended) next page if necessary */ +- if (efx->phy_op->set_npage_adv) +- efx->phy_op->set_npage_adv(efx, ecmd->advertising); +- +- /* Enable and restart AN */ +- reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); +- reg |= MDIO_AN_CTRL1_ENABLE; +- if (!(EFX_WORKAROUND_15195(efx) && +- LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) +- reg |= MDIO_AN_CTRL1_RESTART; +- if (xnp) +- reg |= MDIO_AN_CTRL1_XNP; +- else +- reg &= ~MDIO_AN_CTRL1_XNP; +- efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); +- } else { +- /* Disable AN */ +- efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_CTRL1, +- MDIO_AN_CTRL1_ENABLE, false); +- +- /* Set the basic control bits */ +- reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1); +- reg &= ~(MDIO_CTRL1_SPEEDSEL | MDIO_CTRL1_FULLDPLX); +- if (ecmd->speed == SPEED_100) +- reg |= MDIO_PMA_CTRL1_SPEED100; +- if (ecmd->duplex) +- reg |= MDIO_CTRL1_FULLDPLX; +- efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, reg); +- } +- ++ efx_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg); ++ efx_mdio_an_reconfigure(efx); + return 0; + } + ++/** ++ * efx_mdio_an_reconfigure - Push advertising flags and restart autonegotiation ++ * @efx: Efx NIC ++ */ ++void efx_mdio_an_reconfigure(struct efx_nic *efx) ++{ ++ bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full ++ || EFX_WORKAROUND_13204(efx)); ++ int reg; ++ ++ WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN)); ++ ++ /* Set up the base page */ ++ reg = ADVERTISE_CSMA; ++ if (efx->link_advertising & ADVERTISED_10baseT_Half) ++ reg |= ADVERTISE_10HALF; ++ if (efx->link_advertising & ADVERTISED_10baseT_Full) ++ reg |= ADVERTISE_10FULL; ++ if (efx->link_advertising & ADVERTISED_100baseT_Half) ++ reg |= ADVERTISE_100HALF; ++ if (efx->link_advertising & ADVERTISED_100baseT_Full) ++ reg |= ADVERTISE_100FULL; ++ if (xnp) ++ reg |= ADVERTISE_RESV; ++ else if (efx->link_advertising & (ADVERTISED_1000baseT_Half | ++ ADVERTISED_1000baseT_Full)) ++ reg |= ADVERTISE_NPAGE; ++ if (efx->link_advertising & ADVERTISED_Pause) ++ reg |= ADVERTISE_PAUSE_CAP; ++ if (efx->link_advertising & ADVERTISED_Asym_Pause) ++ reg |= ADVERTISE_PAUSE_ASYM; ++ efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); ++ ++ /* Set up the (extended) next page if necessary */ ++ if (efx->phy_op->set_npage_adv) ++ efx->phy_op->set_npage_adv(efx, efx->link_advertising); ++ ++ /* Enable and restart AN */ ++ reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); ++ reg |= MDIO_AN_CTRL1_ENABLE; ++ if (!(EFX_WORKAROUND_15195(efx) && LOOPBACK_EXTERNAL(efx))) ++ reg |= MDIO_AN_CTRL1_RESTART; ++ if (xnp) ++ reg |= MDIO_AN_CTRL1_XNP; ++ else ++ reg &= ~MDIO_AN_CTRL1_XNP; ++ efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); ++} ++ + enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) + { +- int lpa; ++ BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX)); + +- if (!(efx->phy_op->mmds & MDIO_DEVS_AN)) ++ if (!(efx->wanted_fc & EFX_FC_AUTO)) + return efx->wanted_fc; +- lpa = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA); +- return efx_fc_resolve(efx->wanted_fc, lpa); ++ ++ WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN)); ++ ++ return mii_resolve_flowctrl_fdx( ++ mii_advertise_flowctrl(efx->wanted_fc), ++ efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA)); + } +diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h +index 6b14421..f6ac950 100644 +--- a/drivers/net/sfc/mdio_10g.h ++++ b/drivers/net/sfc/mdio_10g.h +@@ -1,6 +1,6 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -17,7 +17,6 @@ + */ + + #include "efx.h" +-#include "boards.h" + + static inline unsigned efx_mdio_id_rev(u32 id) { return id & 0xf; } + static inline unsigned efx_mdio_id_model(u32 id) { return (id >> 4) & 0x3f; } +@@ -87,6 +86,9 @@ extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx, + /* Set (some of) the PHY settings over MDIO */ + extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); + ++/* Push advertising flags and restart autonegotiation */ ++extern void efx_mdio_an_reconfigure(struct efx_nic *efx); ++ + /* Get pause parameters from AN if available (otherwise return + * requested pause parameters) + */ +diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c +index 820c233..3a46452 100644 +--- a/drivers/net/sfc/mtd.c ++++ b/drivers/net/sfc/mtd.c +@@ -1,36 +1,80 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + ++#include + #include + #include + #include ++#include + + #define EFX_DRIVER_NAME "sfc_mtd" + #include "net_driver.h" + #include "spi.h" + #include "efx.h" ++#include "nic.h" ++#include "mcdi.h" ++#include "mcdi_pcol.h" + + #define EFX_SPI_VERIFY_BUF_LEN 16 ++#define EFX_MCDI_CHUNK_LEN 128 + +-struct efx_mtd { +- const struct efx_spi_device *spi; ++struct efx_mtd_partition { + struct mtd_info mtd; ++ union { ++ struct { ++ bool updating; ++ u8 nvram_type; ++ u16 fw_subtype; ++ } mcdi; ++ size_t offset; ++ }; ++ const char *type_name; + char name[IFNAMSIZ + 20]; + }; + ++struct efx_mtd_ops { ++ int (*read)(struct mtd_info *mtd, loff_t start, size_t len, ++ size_t *retlen, u8 *buffer); ++ int (*erase)(struct mtd_info *mtd, loff_t start, size_t len); ++ int (*write)(struct mtd_info *mtd, loff_t start, size_t len, ++ size_t *retlen, const u8 *buffer); ++ int (*sync)(struct mtd_info *mtd); ++}; ++ ++struct efx_mtd { ++ struct list_head node; ++ struct efx_nic *efx; ++ const struct efx_spi_device *spi; ++ const char *name; ++ const struct efx_mtd_ops *ops; ++ size_t n_parts; ++ struct efx_mtd_partition part[0]; ++}; ++ ++#define efx_for_each_partition(part, efx_mtd) \ ++ for ((part) = &(efx_mtd)->part[0]; \ ++ (part) != &(efx_mtd)->part[(efx_mtd)->n_parts]; \ ++ (part)++) ++ ++#define to_efx_mtd_partition(mtd) \ ++ container_of(mtd, struct efx_mtd_partition, mtd) ++ ++static int falcon_mtd_probe(struct efx_nic *efx); ++static int siena_mtd_probe(struct efx_nic *efx); ++ + /* SPI utilities */ + + static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) + { + const struct efx_spi_device *spi = efx_mtd->spi; +- struct efx_nic *efx = spi->efx; ++ struct efx_nic *efx = efx_mtd->efx; + u8 status; + int rc, i; + +@@ -39,7 +83,7 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) + __set_current_state(uninterruptible ? + TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); +- rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, ++ rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, + &status, sizeof(status)); + if (rc) + return rc; +@@ -52,32 +96,35 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) + return -ETIMEDOUT; + } + +-static int efx_spi_unlock(const struct efx_spi_device *spi) ++static int ++efx_spi_unlock(struct efx_nic *efx, const struct efx_spi_device *spi) + { + const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 | + SPI_STATUS_BP0); + u8 status; + int rc; + +- rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); ++ rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, ++ &status, sizeof(status)); + if (rc) + return rc; + + if (!(status & unlock_mask)) + return 0; /* already unlocked */ + +- rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); ++ rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); + if (rc) + return rc; +- rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0); ++ rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0); + if (rc) + return rc; + + status &= ~unlock_mask; +- rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status)); ++ rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status, ++ NULL, sizeof(status)); + if (rc) + return rc; +- rc = falcon_spi_wait_write(spi); ++ rc = falcon_spi_wait_write(efx, spi); + if (rc) + return rc; + +@@ -87,6 +134,7 @@ static int efx_spi_unlock(const struct efx_spi_device *spi) + static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) + { + const struct efx_spi_device *spi = efx_mtd->spi; ++ struct efx_nic *efx = efx_mtd->efx; + unsigned pos, block_len; + u8 empty[EFX_SPI_VERIFY_BUF_LEN]; + u8 buffer[EFX_SPI_VERIFY_BUF_LEN]; +@@ -98,13 +146,14 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) + if (spi->erase_command == 0) + return -EOPNOTSUPP; + +- rc = efx_spi_unlock(spi); ++ rc = efx_spi_unlock(efx, spi); + if (rc) + return rc; +- rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); ++ rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); + if (rc) + return rc; +- rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0); ++ rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL, ++ NULL, 0); + if (rc) + return rc; + rc = efx_spi_slow_wait(efx_mtd, false); +@@ -113,7 +162,8 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) + memset(empty, 0xff, sizeof(empty)); + for (pos = 0; pos < len; pos += block_len) { + block_len = min(len - pos, sizeof(buffer)); +- rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer); ++ rc = falcon_spi_read(efx, spi, start + pos, block_len, ++ NULL, buffer); + if (rc) + return rc; + if (memcmp(empty, buffer, block_len)) +@@ -130,140 +180,473 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) + + /* MTD interface */ + +-static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len, +- size_t *retlen, u8 *buffer) ++static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) + { + struct efx_mtd *efx_mtd = mtd->priv; ++ int rc; ++ ++ rc = efx_mtd->ops->erase(mtd, erase->addr, erase->len); ++ if (rc == 0) { ++ erase->state = MTD_ERASE_DONE; ++ } else { ++ erase->state = MTD_ERASE_FAILED; ++ erase->fail_addr = 0xffffffff; ++ } ++ mtd_erase_callback(erase); ++ return rc; ++} ++ ++static void efx_mtd_sync(struct mtd_info *mtd) ++{ ++ struct efx_mtd *efx_mtd = mtd->priv; ++ struct efx_nic *efx = efx_mtd->efx; ++ int rc; ++ ++ rc = efx_mtd->ops->sync(mtd); ++ if (rc) ++ EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); ++} ++ ++static void efx_mtd_remove_partition(struct efx_mtd_partition *part) ++{ ++ int rc; ++ ++ for (;;) { ++ rc = del_mtd_device(&part->mtd); ++ if (rc != -EBUSY) ++ break; ++ ssleep(1); ++ } ++ WARN_ON(rc); ++} ++ ++static void efx_mtd_remove_device(struct efx_mtd *efx_mtd) ++{ ++ struct efx_mtd_partition *part; ++ ++ efx_for_each_partition(part, efx_mtd) ++ efx_mtd_remove_partition(part); ++ list_del(&efx_mtd->node); ++ kfree(efx_mtd); ++} ++ ++static void efx_mtd_rename_device(struct efx_mtd *efx_mtd) ++{ ++ struct efx_mtd_partition *part; ++ ++ efx_for_each_partition(part, efx_mtd) ++ if (efx_nic_rev(efx_mtd->efx) >= EFX_REV_SIENA_A0) ++ snprintf(part->name, sizeof(part->name), ++ "%s %s:%02x", efx_mtd->efx->name, ++ part->type_name, part->mcdi.fw_subtype); ++ else ++ snprintf(part->name, sizeof(part->name), ++ "%s %s", efx_mtd->efx->name, ++ part->type_name); ++} ++ ++static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd) ++{ ++ struct efx_mtd_partition *part; ++ ++ efx_mtd->efx = efx; ++ ++ efx_mtd_rename_device(efx_mtd); ++ ++ efx_for_each_partition(part, efx_mtd) { ++ part->mtd.writesize = 1; ++ ++ part->mtd.owner = THIS_MODULE; ++ part->mtd.priv = efx_mtd; ++ part->mtd.name = part->name; ++ part->mtd.erase = efx_mtd_erase; ++ part->mtd.read = efx_mtd->ops->read; ++ part->mtd.write = efx_mtd->ops->write; ++ part->mtd.sync = efx_mtd_sync; ++ ++ if (add_mtd_device(&part->mtd)) ++ goto fail; ++ } ++ ++ list_add(&efx_mtd->node, &efx->mtd_list); ++ return 0; ++ ++fail: ++ while (part != &efx_mtd->part[0]) { ++ --part; ++ efx_mtd_remove_partition(part); ++ } ++ /* add_mtd_device() returns 1 if the MTD table is full */ ++ return -ENOMEM; ++} ++ ++void efx_mtd_remove(struct efx_nic *efx) ++{ ++ struct efx_mtd *efx_mtd, *next; ++ ++ WARN_ON(efx_dev_registered(efx)); ++ ++ list_for_each_entry_safe(efx_mtd, next, &efx->mtd_list, node) ++ efx_mtd_remove_device(efx_mtd); ++} ++ ++void efx_mtd_rename(struct efx_nic *efx) ++{ ++ struct efx_mtd *efx_mtd; ++ ++ ASSERT_RTNL(); ++ ++ list_for_each_entry(efx_mtd, &efx->mtd_list, node) ++ efx_mtd_rename_device(efx_mtd); ++} ++ ++int efx_mtd_probe(struct efx_nic *efx) ++{ ++ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) ++ return siena_mtd_probe(efx); ++ else ++ return falcon_mtd_probe(efx); ++} ++ ++/* Implementation of MTD operations for Falcon */ ++ ++static int falcon_mtd_read(struct mtd_info *mtd, loff_t start, ++ size_t len, size_t *retlen, u8 *buffer) ++{ ++ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); ++ struct efx_mtd *efx_mtd = mtd->priv; + const struct efx_spi_device *spi = efx_mtd->spi; +- struct efx_nic *efx = spi->efx; ++ struct efx_nic *efx = efx_mtd->efx; + int rc; + + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; +- rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start, +- len, retlen, buffer); ++ rc = falcon_spi_read(efx, spi, part->offset + start, len, ++ retlen, buffer); + mutex_unlock(&efx->spi_lock); + return rc; + } + +-static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) ++static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) + { ++ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; +- struct efx_nic *efx = efx_mtd->spi->efx; ++ struct efx_nic *efx = efx_mtd->efx; + int rc; + + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; +- rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr, +- erase->len); ++ rc = efx_spi_erase(efx_mtd, part->offset + start, len); + mutex_unlock(&efx->spi_lock); +- +- if (rc == 0) { +- erase->state = MTD_ERASE_DONE; +- } else { +- erase->state = MTD_ERASE_FAILED; +- erase->fail_addr = 0xffffffff; +- } +- mtd_erase_callback(erase); + return rc; + } + +-static int efx_mtd_write(struct mtd_info *mtd, loff_t start, +- size_t len, size_t *retlen, const u8 *buffer) ++static int falcon_mtd_write(struct mtd_info *mtd, loff_t start, ++ size_t len, size_t *retlen, const u8 *buffer) + { ++ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; + const struct efx_spi_device *spi = efx_mtd->spi; +- struct efx_nic *efx = spi->efx; ++ struct efx_nic *efx = efx_mtd->efx; + int rc; + + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; +- rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start, +- len, retlen, buffer); ++ rc = falcon_spi_write(efx, spi, part->offset + start, len, ++ retlen, buffer); + mutex_unlock(&efx->spi_lock); + return rc; + } + +-static void efx_mtd_sync(struct mtd_info *mtd) ++static int falcon_mtd_sync(struct mtd_info *mtd) + { + struct efx_mtd *efx_mtd = mtd->priv; +- struct efx_nic *efx = efx_mtd->spi->efx; ++ struct efx_nic *efx = efx_mtd->efx; + int rc; + + mutex_lock(&efx->spi_lock); + rc = efx_spi_slow_wait(efx_mtd, true); + mutex_unlock(&efx->spi_lock); ++ return rc; ++} ++ ++static struct efx_mtd_ops falcon_mtd_ops = { ++ .read = falcon_mtd_read, ++ .erase = falcon_mtd_erase, ++ .write = falcon_mtd_write, ++ .sync = falcon_mtd_sync, ++}; ++ ++static int falcon_mtd_probe(struct efx_nic *efx) ++{ ++ struct efx_spi_device *spi = efx->spi_flash; ++ struct efx_mtd *efx_mtd; ++ int rc; ++ ++ ASSERT_RTNL(); + ++ if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) ++ return -ENODEV; ++ ++ efx_mtd = kzalloc(sizeof(*efx_mtd) + sizeof(efx_mtd->part[0]), ++ GFP_KERNEL); ++ if (!efx_mtd) ++ return -ENOMEM; ++ ++ efx_mtd->spi = spi; ++ efx_mtd->name = "flash"; ++ efx_mtd->ops = &falcon_mtd_ops; ++ ++ efx_mtd->n_parts = 1; ++ efx_mtd->part[0].mtd.type = MTD_NORFLASH; ++ efx_mtd->part[0].mtd.flags = MTD_CAP_NORFLASH; ++ efx_mtd->part[0].mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; ++ efx_mtd->part[0].mtd.erasesize = spi->erase_size; ++ efx_mtd->part[0].offset = FALCON_FLASH_BOOTCODE_START; ++ efx_mtd->part[0].type_name = "sfc_flash_bootrom"; ++ ++ rc = efx_mtd_probe_device(efx, efx_mtd); + if (rc) +- EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); +- return; ++ kfree(efx_mtd); ++ return rc; + } + +-void efx_mtd_remove(struct efx_nic *efx) ++/* Implementation of MTD operations for Siena */ ++ ++static int siena_mtd_read(struct mtd_info *mtd, loff_t start, ++ size_t len, size_t *retlen, u8 *buffer) + { +- if (efx->spi_flash && efx->spi_flash->mtd) { +- struct efx_mtd *efx_mtd = efx->spi_flash->mtd; +- int rc; +- +- for (;;) { +- rc = del_mtd_device(&efx_mtd->mtd); +- if (rc != -EBUSY) +- break; +- ssleep(1); +- } +- WARN_ON(rc); +- kfree(efx_mtd); ++ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); ++ struct efx_mtd *efx_mtd = mtd->priv; ++ struct efx_nic *efx = efx_mtd->efx; ++ loff_t offset = start; ++ loff_t end = min_t(loff_t, start + len, mtd->size); ++ size_t chunk; ++ int rc = 0; ++ ++ while (offset < end) { ++ chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); ++ rc = efx_mcdi_nvram_read(efx, part->mcdi.nvram_type, offset, ++ buffer, chunk); ++ if (rc) ++ goto out; ++ offset += chunk; ++ buffer += chunk; + } ++out: ++ *retlen = offset - start; ++ return rc; + } + +-void efx_mtd_rename(struct efx_nic *efx) ++static int siena_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) + { +- if (efx->spi_flash && efx->spi_flash->mtd) { +- struct efx_mtd *efx_mtd = efx->spi_flash->mtd; +- snprintf(efx_mtd->name, sizeof(efx_mtd->name), +- "%s sfc_flash_bootrom", efx->name); ++ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); ++ struct efx_mtd *efx_mtd = mtd->priv; ++ struct efx_nic *efx = efx_mtd->efx; ++ loff_t offset = start & ~((loff_t)(mtd->erasesize - 1)); ++ loff_t end = min_t(loff_t, start + len, mtd->size); ++ size_t chunk = part->mtd.erasesize; ++ int rc = 0; ++ ++ if (!part->mcdi.updating) { ++ rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type); ++ if (rc) ++ goto out; ++ part->mcdi.updating = 1; ++ } ++ ++ /* The MCDI interface can in fact do multiple erase blocks at once; ++ * but erasing may be slow, so we make multiple calls here to avoid ++ * tripping the MCDI RPC timeout. */ ++ while (offset < end) { ++ rc = efx_mcdi_nvram_erase(efx, part->mcdi.nvram_type, offset, ++ chunk); ++ if (rc) ++ goto out; ++ offset += chunk; + } ++out: ++ return rc; + } + +-int efx_mtd_probe(struct efx_nic *efx) ++static int siena_mtd_write(struct mtd_info *mtd, loff_t start, ++ size_t len, size_t *retlen, const u8 *buffer) + { +- struct efx_spi_device *spi = efx->spi_flash; +- struct efx_mtd *efx_mtd; ++ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); ++ struct efx_mtd *efx_mtd = mtd->priv; ++ struct efx_nic *efx = efx_mtd->efx; ++ loff_t offset = start; ++ loff_t end = min_t(loff_t, start + len, mtd->size); ++ size_t chunk; ++ int rc = 0; ++ ++ if (!part->mcdi.updating) { ++ rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type); ++ if (rc) ++ goto out; ++ part->mcdi.updating = 1; ++ } + +- if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) ++ while (offset < end) { ++ chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); ++ rc = efx_mcdi_nvram_write(efx, part->mcdi.nvram_type, offset, ++ buffer, chunk); ++ if (rc) ++ goto out; ++ offset += chunk; ++ buffer += chunk; ++ } ++out: ++ *retlen = offset - start; ++ return rc; ++} ++ ++static int siena_mtd_sync(struct mtd_info *mtd) ++{ ++ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); ++ struct efx_mtd *efx_mtd = mtd->priv; ++ struct efx_nic *efx = efx_mtd->efx; ++ int rc = 0; ++ ++ if (part->mcdi.updating) { ++ part->mcdi.updating = 0; ++ rc = efx_mcdi_nvram_update_finish(efx, part->mcdi.nvram_type); ++ } ++ ++ return rc; ++} ++ ++static struct efx_mtd_ops siena_mtd_ops = { ++ .read = siena_mtd_read, ++ .erase = siena_mtd_erase, ++ .write = siena_mtd_write, ++ .sync = siena_mtd_sync, ++}; ++ ++struct siena_nvram_type_info { ++ int port; ++ const char *name; ++}; ++ ++static struct siena_nvram_type_info siena_nvram_types[] = { ++ [MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO] = { 0, "sfc_dummy_phy" }, ++ [MC_CMD_NVRAM_TYPE_MC_FW] = { 0, "sfc_mcfw" }, ++ [MC_CMD_NVRAM_TYPE_MC_FW_BACKUP] = { 0, "sfc_mcfw_backup" }, ++ [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0] = { 0, "sfc_static_cfg" }, ++ [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1] = { 1, "sfc_static_cfg" }, ++ [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0] = { 0, "sfc_dynamic_cfg" }, ++ [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1] = { 1, "sfc_dynamic_cfg" }, ++ [MC_CMD_NVRAM_TYPE_EXP_ROM] = { 0, "sfc_exp_rom" }, ++ [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0] = { 0, "sfc_exp_rom_cfg" }, ++ [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1] = { 1, "sfc_exp_rom_cfg" }, ++ [MC_CMD_NVRAM_TYPE_PHY_PORT0] = { 0, "sfc_phy_fw" }, ++ [MC_CMD_NVRAM_TYPE_PHY_PORT1] = { 1, "sfc_phy_fw" }, ++}; ++ ++static int siena_mtd_probe_partition(struct efx_nic *efx, ++ struct efx_mtd *efx_mtd, ++ unsigned int part_id, ++ unsigned int type) ++{ ++ struct efx_mtd_partition *part = &efx_mtd->part[part_id]; ++ struct siena_nvram_type_info *info; ++ size_t size, erase_size; ++ bool protected; ++ int rc; ++ ++ if (type >= ARRAY_SIZE(siena_nvram_types)) + return -ENODEV; + +- efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL); ++ info = &siena_nvram_types[type]; ++ ++ if (info->port != efx_port_num(efx)) ++ return -ENODEV; ++ ++ rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected); ++ if (rc) ++ return rc; ++ if (protected) ++ return -ENODEV; /* hide it */ ++ ++ part->mcdi.nvram_type = type; ++ part->type_name = info->name; ++ ++ part->mtd.type = MTD_NORFLASH; ++ part->mtd.flags = MTD_CAP_NORFLASH; ++ part->mtd.size = size; ++ part->mtd.erasesize = erase_size; ++ ++ return 0; ++} ++ ++static int siena_mtd_get_fw_subtypes(struct efx_nic *efx, ++ struct efx_mtd *efx_mtd) ++{ ++ struct efx_mtd_partition *part; ++ uint16_t fw_subtype_list[MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN / ++ sizeof(uint16_t)]; ++ int rc; ++ ++ rc = efx_mcdi_get_board_cfg(efx, NULL, fw_subtype_list); ++ if (rc) ++ return rc; ++ ++ efx_for_each_partition(part, efx_mtd) ++ part->mcdi.fw_subtype = fw_subtype_list[part->mcdi.nvram_type]; ++ ++ return 0; ++} ++ ++static int siena_mtd_probe(struct efx_nic *efx) ++{ ++ struct efx_mtd *efx_mtd; ++ int rc = -ENODEV; ++ u32 nvram_types; ++ unsigned int type; ++ ++ ASSERT_RTNL(); ++ ++ rc = efx_mcdi_nvram_types(efx, &nvram_types); ++ if (rc) ++ return rc; ++ ++ efx_mtd = kzalloc(sizeof(*efx_mtd) + ++ hweight32(nvram_types) * sizeof(efx_mtd->part[0]), ++ GFP_KERNEL); + if (!efx_mtd) + return -ENOMEM; + +- efx_mtd->spi = spi; +- spi->mtd = efx_mtd; +- +- efx_mtd->mtd.type = MTD_NORFLASH; +- efx_mtd->mtd.flags = MTD_CAP_NORFLASH; +- efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; +- efx_mtd->mtd.erasesize = spi->erase_size; +- efx_mtd->mtd.writesize = 1; +- efx_mtd_rename(efx); +- +- efx_mtd->mtd.owner = THIS_MODULE; +- efx_mtd->mtd.priv = efx_mtd; +- efx_mtd->mtd.name = efx_mtd->name; +- efx_mtd->mtd.erase = efx_mtd_erase; +- efx_mtd->mtd.read = efx_mtd_read; +- efx_mtd->mtd.write = efx_mtd_write; +- efx_mtd->mtd.sync = efx_mtd_sync; +- +- if (add_mtd_device(&efx_mtd->mtd)) { +- kfree(efx_mtd); +- spi->mtd = NULL; +- /* add_mtd_device() returns 1 if the MTD table is full */ +- return -ENOMEM; ++ efx_mtd->name = "Siena NVRAM manager"; ++ ++ efx_mtd->ops = &siena_mtd_ops; ++ ++ type = 0; ++ efx_mtd->n_parts = 0; ++ ++ while (nvram_types != 0) { ++ if (nvram_types & 1) { ++ rc = siena_mtd_probe_partition(efx, efx_mtd, ++ efx_mtd->n_parts, type); ++ if (rc == 0) ++ efx_mtd->n_parts++; ++ else if (rc != -ENODEV) ++ goto fail; ++ } ++ type++; ++ nvram_types >>= 1; + } + +- return 0; ++ rc = siena_mtd_get_fw_subtypes(efx, efx_mtd); ++ if (rc) ++ goto fail; ++ ++ rc = efx_mtd_probe_device(efx, efx_mtd); ++fail: ++ if (rc) ++ kfree(efx_mtd); ++ return rc; + } ++ +diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h +index 298566d..34c381f 100644 +--- a/drivers/net/sfc/net_driver.h ++++ b/drivers/net/sfc/net_driver.h +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2005-2008 Solarflare Communications Inc. ++ * Copyright 2005-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -38,7 +38,7 @@ + #ifndef EFX_DRIVER_NAME + #define EFX_DRIVER_NAME "sfc" + #endif +-#define EFX_DRIVER_VERSION "2.3" ++#define EFX_DRIVER_VERSION "3.0" + + #ifdef EFX_ENABLE_DEBUG + #define EFX_BUG_ON_PARANOID(x) BUG_ON(x) +@@ -113,6 +113,13 @@ struct efx_special_buffer { + int entries; + }; + ++enum efx_flush_state { ++ FLUSH_NONE, ++ FLUSH_PENDING, ++ FLUSH_FAILED, ++ FLUSH_DONE, ++}; ++ + /** + * struct efx_tx_buffer - An Efx TX buffer + * @skb: The associated socket buffer. +@@ -189,7 +196,7 @@ struct efx_tx_queue { + struct efx_nic *nic; + struct efx_tx_buffer *buffer; + struct efx_special_buffer txd; +- bool flushed; ++ enum efx_flush_state flushed; + + /* Members used mainly on the completion path */ + unsigned int read_count ____cacheline_aligned_in_smp; +@@ -284,7 +291,7 @@ struct efx_rx_queue { + struct page *buf_page; + dma_addr_t buf_dma_addr; + char *buf_data; +- bool flushed; ++ enum efx_flush_state flushed; + }; + + /** +@@ -327,7 +334,7 @@ enum efx_rx_alloc_method { + * @used_flags: Channel is used by net driver + * @enabled: Channel enabled indicator + * @irq: IRQ number (MSI and MSI-X only) +- * @irq_moderation: IRQ moderation value (in us) ++ * @irq_moderation: IRQ moderation value (in hardware ticks) + * @napi_dev: Net device used with NAPI + * @napi_str: NAPI control structure + * @reset_work: Scheduled reset work thread +@@ -343,9 +350,9 @@ enum efx_rx_alloc_method { + * @rx_alloc_push_pages: RX allocation method currently in use for pushing + * descriptors + * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors +- * @n_rx_ip_frag_err: Count of RX IP fragment errors + * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors + * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors ++ * @n_rx_mcast_mismatch: Count of unmatched multicast frames + * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors + * @n_rx_overlength: Count of RX_OVERLENGTH errors + * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun +@@ -373,9 +380,9 @@ struct efx_channel { + int rx_alloc_push_pages; + + unsigned n_rx_tobe_disc; +- unsigned n_rx_ip_frag_err; + unsigned n_rx_ip_hdr_chksum_err; + unsigned n_rx_tcp_udp_chksum_err; ++ unsigned n_rx_mcast_mismatch; + unsigned n_rx_frm_trunc; + unsigned n_rx_overlength; + unsigned n_skbuff_leaks; +@@ -388,53 +395,29 @@ struct efx_channel { + + }; + +-/** +- * struct efx_blinker - S/W LED blinking context +- * @state: Current state - on or off +- * @resubmit: Timer resubmission flag +- * @timer: Control timer for blinking +- */ +-struct efx_blinker { +- bool state; +- bool resubmit; +- struct timer_list timer; ++enum efx_led_mode { ++ EFX_LED_OFF = 0, ++ EFX_LED_ON = 1, ++ EFX_LED_DEFAULT = 2 + }; + ++#define STRING_TABLE_LOOKUP(val, member) \ ++ ((val) < member ## _max) ? member ## _names[val] : "(invalid)" + +-/** +- * struct efx_board - board information +- * @type: Board model type +- * @major: Major rev. ('A', 'B' ...) +- * @minor: Minor rev. (0, 1, ...) +- * @init: Initialisation function +- * @init_leds: Sets up board LEDs. May be called repeatedly. +- * @set_id_led: Turns the identification LED on or off +- * @blink: Starts/stops blinking +- * @monitor: Board-specific health check function +- * @fini: Cleanup function +- * @blinker: used to blink LEDs in software +- * @hwmon_client: I2C client for hardware monitor +- * @ioexp_client: I2C client for power/port control +- */ +-struct efx_board { +- int type; +- int major; +- int minor; +- int (*init) (struct efx_nic *nic); +- /* As the LEDs are typically attached to the PHY, LEDs +- * have a separate init callback that happens later than +- * board init. */ +- void (*init_leds)(struct efx_nic *efx); +- void (*set_id_led) (struct efx_nic *efx, bool state); +- int (*monitor) (struct efx_nic *nic); +- void (*blink) (struct efx_nic *efx, bool start); +- void (*fini) (struct efx_nic *nic); +- struct efx_blinker blinker; +- struct i2c_client *hwmon_client, *ioexp_client; +-}; ++extern const char *efx_loopback_mode_names[]; ++extern const unsigned int efx_loopback_mode_max; ++#define LOOPBACK_MODE(efx) \ ++ STRING_TABLE_LOOKUP((efx)->loopback_mode, efx_loopback_mode) ++ ++extern const char *efx_interrupt_mode_names[]; ++extern const unsigned int efx_interrupt_mode_max; ++#define INT_MODE(efx) \ ++ STRING_TABLE_LOOKUP(efx->interrupt_mode, efx_interrupt_mode) + +-#define STRING_TABLE_LOOKUP(val, member) \ +- member ## _names[val] ++extern const char *efx_reset_type_names[]; ++extern const unsigned int efx_reset_type_max; ++#define RESET_TYPE(type) \ ++ STRING_TABLE_LOOKUP(type, efx_reset_type) + + enum efx_int_mode { + /* Be careful if altering to correct macro below */ +@@ -445,20 +428,7 @@ enum efx_int_mode { + }; + #define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI) + +-enum phy_type { +- PHY_TYPE_NONE = 0, +- PHY_TYPE_TXC43128 = 1, +- PHY_TYPE_88E1111 = 2, +- PHY_TYPE_SFX7101 = 3, +- PHY_TYPE_QT2022C2 = 4, +- PHY_TYPE_PM8358 = 6, +- PHY_TYPE_SFT9001A = 8, +- PHY_TYPE_QT2025C = 9, +- PHY_TYPE_SFT9001B = 10, +- PHY_TYPE_MAX /* Insert any new items before this */ +-}; +- +-#define EFX_IS10G(efx) ((efx)->link_speed == 10000) ++#define EFX_IS10G(efx) ((efx)->link_state.speed == 10000) + + enum nic_state { + STATE_INIT = 0, +@@ -500,73 +470,69 @@ enum efx_fc_type { + EFX_FC_AUTO = 4, + }; + +-/* Supported MAC bit-mask */ +-enum efx_mac_type { +- EFX_GMAC = 1, +- EFX_XMAC = 2, ++/** ++ * struct efx_link_state - Current state of the link ++ * @up: Link is up ++ * @fd: Link is full-duplex ++ * @fc: Actual flow control flags ++ * @speed: Link speed (Mbps) ++ */ ++struct efx_link_state { ++ bool up; ++ bool fd; ++ enum efx_fc_type fc; ++ unsigned int speed; + }; + +-static inline enum efx_fc_type efx_fc_resolve(enum efx_fc_type wanted_fc, +- unsigned int lpa) ++static inline bool efx_link_state_equal(const struct efx_link_state *left, ++ const struct efx_link_state *right) + { +- BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX)); +- +- if (!(wanted_fc & EFX_FC_AUTO)) +- return wanted_fc; +- +- return mii_resolve_flowctrl_fdx(mii_advertise_flowctrl(wanted_fc), lpa); ++ return left->up == right->up && left->fd == right->fd && ++ left->fc == right->fc && left->speed == right->speed; + } + + /** + * struct efx_mac_operations - Efx MAC operations table + * @reconfigure: Reconfigure MAC. Serialised by the mac_lock + * @update_stats: Update statistics +- * @irq: Hardware MAC event callback. Serialised by the mac_lock +- * @poll: Poll for hardware state. Serialised by the mac_lock ++ * @check_fault: Check fault state. True if fault present. + */ + struct efx_mac_operations { +- void (*reconfigure) (struct efx_nic *efx); ++ int (*reconfigure) (struct efx_nic *efx); + void (*update_stats) (struct efx_nic *efx); +- void (*irq) (struct efx_nic *efx); +- void (*poll) (struct efx_nic *efx); ++ bool (*check_fault)(struct efx_nic *efx); + }; + + /** + * struct efx_phy_operations - Efx PHY operations table ++ * @probe: Probe PHY and initialise efx->mdio.mode_support, efx->mdio.mmds, ++ * efx->loopback_modes. + * @init: Initialise PHY + * @fini: Shut down PHY + * @reconfigure: Reconfigure PHY (e.g. for new link parameters) +- * @clear_interrupt: Clear down interrupt +- * @blink: Blink LEDs +- * @poll: Poll for hardware state. Serialised by the mac_lock. ++ * @poll: Update @link_state and report whether it changed. ++ * Serialised by the mac_lock. + * @get_settings: Get ethtool settings. Serialised by the mac_lock. + * @set_settings: Set ethtool settings. Serialised by the mac_lock. + * @set_npage_adv: Set abilities advertised in (Extended) Next Page + * (only needed where AN bit is set in mmds) +- * @num_tests: Number of PHY-specific tests/results +- * @test_names: Names of the tests/results ++ * @test_name: Get the name of a PHY-specific test/result + * @run_tests: Run tests and record results as appropriate. + * Flags are the ethtool tests flags. +- * @mmds: MMD presence mask +- * @loopbacks: Supported loopback modes mask + */ + struct efx_phy_operations { +- enum efx_mac_type macs; ++ int (*probe) (struct efx_nic *efx); + int (*init) (struct efx_nic *efx); + void (*fini) (struct efx_nic *efx); +- void (*reconfigure) (struct efx_nic *efx); +- void (*clear_interrupt) (struct efx_nic *efx); +- void (*poll) (struct efx_nic *efx); ++ int (*reconfigure) (struct efx_nic *efx); ++ bool (*poll) (struct efx_nic *efx); + void (*get_settings) (struct efx_nic *efx, + struct ethtool_cmd *ecmd); + int (*set_settings) (struct efx_nic *efx, + struct ethtool_cmd *ecmd); + void (*set_npage_adv) (struct efx_nic *efx, u32); +- u32 num_tests; +- const char *const *test_names; ++ const char *(*test_name) (struct efx_nic *efx, unsigned int index); + int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags); +- int mmds; +- unsigned loopbacks; + }; + + /** +@@ -690,36 +656,38 @@ union efx_multicast_hash { + * @interrupt_mode: Interrupt mode + * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues + * @irq_rx_moderation: IRQ moderation time for RX event queues +- * @i2c_adap: I2C adapter +- * @board_info: Board-level information + * @state: Device state flag. Serialised by the rtnl_lock. + * @reset_pending: Pending reset method (normally RESET_TYPE_NONE) + * @tx_queue: TX DMA queues + * @rx_queue: RX DMA queues + * @channel: Channels ++ * @next_buffer_table: First available buffer table id + * @n_rx_queues: Number of RX queues + * @n_channels: Number of channels in use + * @rx_buffer_len: RX buffer length + * @rx_buffer_order: Order (log2) of number of pages for each RX buffer ++ * @int_error_count: Number of internal errors seen recently ++ * @int_error_expire: Time at which error count will be expired + * @irq_status: Interrupt status buffer + * @last_irq_cpu: Last CPU to handle interrupt. + * This register is written with the SMP processor ID whenever an + * interrupt is handled. It is used by falcon_test_interrupt() + * to verify that an interrupt has occurred. + * @spi_flash: SPI flash device +- * This field will be %NULL if no flash device is present. ++ * This field will be %NULL if no flash device is present (or for Siena). + * @spi_eeprom: SPI EEPROM device +- * This field will be %NULL if no EEPROM device is present. ++ * This field will be %NULL if no EEPROM device is present (or for Siena). + * @spi_lock: SPI bus lock ++ * @mtd_list: List of MTDs attached to the NIC + * @n_rx_nodesc_drop_cnt: RX no descriptor drop count + * @nic_data: Hardware dependant state + * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, + * @port_inhibited, efx_monitor() and efx_reconfigure_port() + * @port_enabled: Port enabled indicator. +- * Serialises efx_stop_all(), efx_start_all(), efx_monitor(), +- * efx_phy_work(), and efx_mac_work() with kernel interfaces. Safe to read +- * under any one of the rtnl_lock, mac_lock, or netif_tx_lock, but all +- * three must be held to modify it. ++ * Serialises efx_stop_all(), efx_start_all(), efx_monitor() and ++ * efx_mac_work() with kernel interfaces. Safe to read under any ++ * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must ++ * be held to modify it. + * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock + * @port_initialized: Port initialized? + * @net_dev: Operating system network device. Consider holding the rtnl lock +@@ -731,26 +699,23 @@ union efx_multicast_hash { + * &struct net_device_stats. + * @stats_buffer: DMA buffer for statistics + * @stats_lock: Statistics update lock. Serialises statistics fetches +- * @stats_disable_count: Nest count for disabling statistics fetches + * @mac_op: MAC interface + * @mac_address: Permanent MAC address + * @phy_type: PHY type +- * @phy_lock: PHY access lock ++ * @mdio_lock: MDIO lock + * @phy_op: PHY interface + * @phy_data: PHY private data (including PHY-specific stats) + * @mdio: PHY MDIO interface ++ * @mdio_bus: PHY MDIO bus ID (only used by Siena) + * @phy_mode: PHY operating mode. Serialised by @mac_lock. +- * @mac_up: MAC link state +- * @link_up: Link status +- * @link_fd: Link is full duplex +- * @link_fc: Actualy flow control flags +- * @link_speed: Link speed (Mbps) ++ * @xmac_poll_required: XMAC link state needs polling ++ * @link_advertising: Autonegotiation advertising flags ++ * @link_state: Current state of the link + * @n_link_state_changes: Number of times the link has changed state + * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. + * @multicast_hash: Multicast hash table + * @wanted_fc: Wanted flow control flags +- * @phy_work: work item for dealing with PHY events +- * @mac_work: work item for dealing with MAC events ++ * @mac_work: Work item for changing MAC promiscuity and multicast hash + * @loopback_mode: Loopback status + * @loopback_modes: Supported loopback mode bitmask + * @loopback_selftest: Offline self-test private state +@@ -774,9 +739,6 @@ struct efx_nic { + bool irq_rx_adaptive; + unsigned int irq_rx_moderation; + +- struct i2c_adapter i2c_adap; +- struct efx_board board_info; +- + enum nic_state state; + enum reset_type reset_pending; + +@@ -784,21 +746,29 @@ struct efx_nic { + struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES]; + struct efx_channel channel[EFX_MAX_CHANNELS]; + ++ unsigned next_buffer_table; + int n_rx_queues; + int n_channels; + unsigned int rx_buffer_len; + unsigned int rx_buffer_order; + ++ unsigned int_error_count; ++ unsigned long int_error_expire; ++ + struct efx_buffer irq_status; + volatile signed int last_irq_cpu; ++ unsigned long irq_zero_count; + + struct efx_spi_device *spi_flash; + struct efx_spi_device *spi_eeprom; + struct mutex spi_lock; ++#ifdef CONFIG_SFC_MTD ++ struct list_head mtd_list; ++#endif + + unsigned n_rx_nodesc_drop_cnt; + +- struct falcon_nic_data *nic_data; ++ void *nic_data; + + struct mutex mac_lock; + struct work_struct mac_work; +@@ -815,24 +785,21 @@ struct efx_nic { + struct efx_mac_stats mac_stats; + struct efx_buffer stats_buffer; + spinlock_t stats_lock; +- unsigned int stats_disable_count; + + struct efx_mac_operations *mac_op; + unsigned char mac_address[ETH_ALEN]; + +- enum phy_type phy_type; +- spinlock_t phy_lock; +- struct work_struct phy_work; ++ unsigned int phy_type; ++ struct mutex mdio_lock; + struct efx_phy_operations *phy_op; + void *phy_data; + struct mdio_if_info mdio; ++ unsigned int mdio_bus; + enum efx_phy_mode phy_mode; + +- bool mac_up; +- bool link_up; +- bool link_fd; +- enum efx_fc_type link_fc; +- unsigned int link_speed; ++ bool xmac_poll_required; ++ u32 link_advertising; ++ struct efx_link_state link_state; + unsigned int n_link_state_changes; + + bool promiscuous; +@@ -841,7 +808,7 @@ struct efx_nic { + + atomic_t rx_reset; + enum efx_loopback_mode loopback_mode; +- unsigned int loopback_modes; ++ u64 loopback_modes; + + void *loopback_selftest; + }; +@@ -860,50 +827,95 @@ static inline const char *efx_dev_name(struct efx_nic *efx) + return efx_dev_registered(efx) ? efx->name : ""; + } + ++static inline unsigned int efx_port_num(struct efx_nic *efx) ++{ ++ return PCI_FUNC(efx->pci_dev->devfn); ++} ++ + /** + * struct efx_nic_type - Efx device type definition +- * @mem_bar: Memory BAR number ++ * @probe: Probe the controller ++ * @remove: Free resources allocated by probe() ++ * @init: Initialise the controller ++ * @fini: Shut down the controller ++ * @monitor: Periodic function for polling link state and hardware monitor ++ * @reset: Reset the controller hardware and possibly the PHY. This will ++ * be called while the controller is uninitialised. ++ * @probe_port: Probe the MAC and PHY ++ * @remove_port: Free resources allocated by probe_port() ++ * @prepare_flush: Prepare the hardware for flushing the DMA queues ++ * @update_stats: Update statistics not provided by event handling ++ * @start_stats: Start the regular fetching of statistics ++ * @stop_stats: Stop the regular fetching of statistics ++ * @set_id_led: Set state of identifying LED or revert to automatic function ++ * @push_irq_moderation: Apply interrupt moderation value ++ * @push_multicast_hash: Apply multicast hash table ++ * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY ++ * @get_wol: Get WoL configuration from driver state ++ * @set_wol: Push WoL configuration to the NIC ++ * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume) ++ * @test_registers: Test read/write functionality of control registers ++ * @test_nvram: Test validity of NVRAM contents ++ * @default_mac_ops: efx_mac_operations to set at startup ++ * @revision: Hardware architecture revision + * @mem_map_size: Memory BAR mapped size + * @txd_ptr_tbl_base: TX descriptor ring base address + * @rxd_ptr_tbl_base: RX descriptor ring base address + * @buf_tbl_base: Buffer table base address + * @evq_ptr_tbl_base: Event queue pointer table base address + * @evq_rptr_tbl_base: Event queue read-pointer table base address +- * @txd_ring_mask: TX descriptor ring size - 1 (must be a power of two - 1) +- * @rxd_ring_mask: RX descriptor ring size - 1 (must be a power of two - 1) +- * @evq_size: Event queue size (must be a power of two) + * @max_dma_mask: Maximum possible DMA mask +- * @tx_dma_mask: TX DMA mask +- * @bug5391_mask: Address mask for bug 5391 workaround +- * @rx_xoff_thresh: RX FIFO XOFF watermark (bytes) +- * @rx_xon_thresh: RX FIFO XON watermark (bytes) + * @rx_buffer_padding: Padding added to each RX buffer + * @max_interrupt_mode: Highest capability interrupt mode supported + * from &enum efx_init_mode. + * @phys_addr_channels: Number of channels with physically addressed + * descriptors ++ * @tx_dc_base: Base address in SRAM of TX queue descriptor caches ++ * @rx_dc_base: Base address in SRAM of RX queue descriptor caches ++ * @offload_features: net_device feature flags for protocol offload ++ * features implemented in hardware ++ * @reset_world_flags: Flags for additional components covered by ++ * reset method RESET_TYPE_WORLD + */ + struct efx_nic_type { +- unsigned int mem_bar; ++ int (*probe)(struct efx_nic *efx); ++ void (*remove)(struct efx_nic *efx); ++ int (*init)(struct efx_nic *efx); ++ void (*fini)(struct efx_nic *efx); ++ void (*monitor)(struct efx_nic *efx); ++ int (*reset)(struct efx_nic *efx, enum reset_type method); ++ int (*probe_port)(struct efx_nic *efx); ++ void (*remove_port)(struct efx_nic *efx); ++ void (*prepare_flush)(struct efx_nic *efx); ++ void (*update_stats)(struct efx_nic *efx); ++ void (*start_stats)(struct efx_nic *efx); ++ void (*stop_stats)(struct efx_nic *efx); ++ void (*set_id_led)(struct efx_nic *efx, enum efx_led_mode mode); ++ void (*push_irq_moderation)(struct efx_channel *channel); ++ void (*push_multicast_hash)(struct efx_nic *efx); ++ int (*reconfigure_port)(struct efx_nic *efx); ++ void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol); ++ int (*set_wol)(struct efx_nic *efx, u32 type); ++ void (*resume_wol)(struct efx_nic *efx); ++ int (*test_registers)(struct efx_nic *efx); ++ int (*test_nvram)(struct efx_nic *efx); ++ struct efx_mac_operations *default_mac_ops; ++ ++ int revision; + unsigned int mem_map_size; + unsigned int txd_ptr_tbl_base; + unsigned int rxd_ptr_tbl_base; + unsigned int buf_tbl_base; + unsigned int evq_ptr_tbl_base; + unsigned int evq_rptr_tbl_base; +- +- unsigned int txd_ring_mask; +- unsigned int rxd_ring_mask; +- unsigned int evq_size; + u64 max_dma_mask; +- unsigned int tx_dma_mask; +- unsigned bug5391_mask; +- +- int rx_xoff_thresh; +- int rx_xon_thresh; + unsigned int rx_buffer_padding; + unsigned int max_interrupt_mode; + unsigned int phys_addr_channels; ++ unsigned int tx_dc_base; ++ unsigned int rx_dc_base; ++ unsigned long offload_features; ++ u32 reset_world_flags; + }; + + /************************************************************************** +diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c +new file mode 100644 +index 0000000..a577be2 +--- /dev/null ++++ b/drivers/net/sfc/nic.c +@@ -0,0 +1,1583 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2005-2006 Fen Systems Ltd. ++ * Copyright 2006-2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "net_driver.h" ++#include "bitfield.h" ++#include "efx.h" ++#include "nic.h" ++#include "regs.h" ++#include "io.h" ++#include "workarounds.h" ++ ++/************************************************************************** ++ * ++ * Configurable values ++ * ++ ************************************************************************** ++ */ ++ ++/* This is set to 16 for a good reason. In summary, if larger than ++ * 16, the descriptor cache holds more than a default socket ++ * buffer's worth of packets (for UDP we can only have at most one ++ * socket buffer's worth outstanding). This combined with the fact ++ * that we only get 1 TX event per descriptor cache means the NIC ++ * goes idle. ++ */ ++#define TX_DC_ENTRIES 16 ++#define TX_DC_ENTRIES_ORDER 1 ++ ++#define RX_DC_ENTRIES 64 ++#define RX_DC_ENTRIES_ORDER 3 ++ ++/* RX FIFO XOFF watermark ++ * ++ * When the amount of the RX FIFO increases used increases past this ++ * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A) ++ * This also has an effect on RX/TX arbitration ++ */ ++int efx_nic_rx_xoff_thresh = -1; ++module_param_named(rx_xoff_thresh_bytes, efx_nic_rx_xoff_thresh, int, 0644); ++MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold"); ++ ++/* RX FIFO XON watermark ++ * ++ * When the amount of the RX FIFO used decreases below this ++ * watermark send XON. Only used if TX flow control is enabled (ethtool -A) ++ * This also has an effect on RX/TX arbitration ++ */ ++int efx_nic_rx_xon_thresh = -1; ++module_param_named(rx_xon_thresh_bytes, efx_nic_rx_xon_thresh, int, 0644); ++MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); ++ ++/* If EFX_MAX_INT_ERRORS internal errors occur within ++ * EFX_INT_ERROR_EXPIRE seconds, we consider the NIC broken and ++ * disable it. ++ */ ++#define EFX_INT_ERROR_EXPIRE 3600 ++#define EFX_MAX_INT_ERRORS 5 ++ ++/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times ++ */ ++#define EFX_FLUSH_INTERVAL 10 ++#define EFX_FLUSH_POLL_COUNT 100 ++ ++/* Size and alignment of special buffers (4KB) */ ++#define EFX_BUF_SIZE 4096 ++ ++/* Depth of RX flush request fifo */ ++#define EFX_RX_FLUSH_COUNT 4 ++ ++/************************************************************************** ++ * ++ * Solarstorm hardware access ++ * ++ **************************************************************************/ ++ ++static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, ++ unsigned int index) ++{ ++ efx_sram_writeq(efx, efx->membase + efx->type->buf_tbl_base, ++ value, index); ++} ++ ++/* Read the current event from the event queue */ ++static inline efx_qword_t *efx_event(struct efx_channel *channel, ++ unsigned int index) ++{ ++ return (((efx_qword_t *) (channel->eventq.addr)) + index); ++} ++ ++/* See if an event is present ++ * ++ * We check both the high and low dword of the event for all ones. We ++ * wrote all ones when we cleared the event, and no valid event can ++ * have all ones in either its high or low dwords. This approach is ++ * robust against reordering. ++ * ++ * Note that using a single 64-bit comparison is incorrect; even ++ * though the CPU read will be atomic, the DMA write may not be. ++ */ ++static inline int efx_event_present(efx_qword_t *event) ++{ ++ return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) | ++ EFX_DWORD_IS_ALL_ONES(event->dword[1]))); ++} ++ ++static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, ++ const efx_oword_t *mask) ++{ ++ return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) || ++ ((a->u64[1] ^ b->u64[1]) & mask->u64[1]); ++} ++ ++int efx_nic_test_registers(struct efx_nic *efx, ++ const struct efx_nic_register_test *regs, ++ size_t n_regs) ++{ ++ unsigned address = 0, i, j; ++ efx_oword_t mask, imask, original, reg, buf; ++ ++ /* Falcon should be in loopback to isolate the XMAC from the PHY */ ++ WARN_ON(!LOOPBACK_INTERNAL(efx)); ++ ++ for (i = 0; i < n_regs; ++i) { ++ address = regs[i].address; ++ mask = imask = regs[i].mask; ++ EFX_INVERT_OWORD(imask); ++ ++ efx_reado(efx, &original, address); ++ ++ /* bit sweep on and off */ ++ for (j = 0; j < 128; j++) { ++ if (!EFX_EXTRACT_OWORD32(mask, j, j)) ++ continue; ++ ++ /* Test this testable bit can be set in isolation */ ++ EFX_AND_OWORD(reg, original, mask); ++ EFX_SET_OWORD32(reg, j, j, 1); ++ ++ efx_writeo(efx, ®, address); ++ efx_reado(efx, &buf, address); ++ ++ if (efx_masked_compare_oword(®, &buf, &mask)) ++ goto fail; ++ ++ /* Test this testable bit can be cleared in isolation */ ++ EFX_OR_OWORD(reg, original, mask); ++ EFX_SET_OWORD32(reg, j, j, 0); ++ ++ efx_writeo(efx, ®, address); ++ efx_reado(efx, &buf, address); ++ ++ if (efx_masked_compare_oword(®, &buf, &mask)) ++ goto fail; ++ } ++ ++ efx_writeo(efx, &original, address); ++ } ++ ++ return 0; ++ ++fail: ++ EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT ++ " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg), ++ EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask)); ++ return -EIO; ++} ++ ++/************************************************************************** ++ * ++ * Special buffer handling ++ * Special buffers are used for event queues and the TX and RX ++ * descriptor rings. ++ * ++ *************************************************************************/ ++ ++/* ++ * Initialise a special buffer ++ * ++ * This will define a buffer (previously allocated via ++ * efx_alloc_special_buffer()) in the buffer table, allowing ++ * it to be used for event queues, descriptor rings etc. ++ */ ++static void ++efx_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) ++{ ++ efx_qword_t buf_desc; ++ int index; ++ dma_addr_t dma_addr; ++ int i; ++ ++ EFX_BUG_ON_PARANOID(!buffer->addr); ++ ++ /* Write buffer descriptors to NIC */ ++ for (i = 0; i < buffer->entries; i++) { ++ index = buffer->index + i; ++ dma_addr = buffer->dma_addr + (i * 4096); ++ EFX_LOG(efx, "mapping special buffer %d at %llx\n", ++ index, (unsigned long long)dma_addr); ++ EFX_POPULATE_QWORD_3(buf_desc, ++ FRF_AZ_BUF_ADR_REGION, 0, ++ FRF_AZ_BUF_ADR_FBUF, dma_addr >> 12, ++ FRF_AZ_BUF_OWNER_ID_FBUF, 0); ++ efx_write_buf_tbl(efx, &buf_desc, index); ++ } ++} ++ ++/* Unmaps a buffer and clears the buffer table entries */ ++static void ++efx_fini_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) ++{ ++ efx_oword_t buf_tbl_upd; ++ unsigned int start = buffer->index; ++ unsigned int end = (buffer->index + buffer->entries - 1); ++ ++ if (!buffer->entries) ++ return; ++ ++ EFX_LOG(efx, "unmapping special buffers %d-%d\n", ++ buffer->index, buffer->index + buffer->entries - 1); ++ ++ EFX_POPULATE_OWORD_4(buf_tbl_upd, ++ FRF_AZ_BUF_UPD_CMD, 0, ++ FRF_AZ_BUF_CLR_CMD, 1, ++ FRF_AZ_BUF_CLR_END_ID, end, ++ FRF_AZ_BUF_CLR_START_ID, start); ++ efx_writeo(efx, &buf_tbl_upd, FR_AZ_BUF_TBL_UPD); ++} ++ ++/* ++ * Allocate a new special buffer ++ * ++ * This allocates memory for a new buffer, clears it and allocates a ++ * new buffer ID range. It does not write into the buffer table. ++ * ++ * This call will allocate 4KB buffers, since 8KB buffers can't be ++ * used for event queues and descriptor rings. ++ */ ++static int efx_alloc_special_buffer(struct efx_nic *efx, ++ struct efx_special_buffer *buffer, ++ unsigned int len) ++{ ++ len = ALIGN(len, EFX_BUF_SIZE); ++ ++ buffer->addr = pci_alloc_consistent(efx->pci_dev, len, ++ &buffer->dma_addr); ++ if (!buffer->addr) ++ return -ENOMEM; ++ buffer->len = len; ++ buffer->entries = len / EFX_BUF_SIZE; ++ BUG_ON(buffer->dma_addr & (EFX_BUF_SIZE - 1)); ++ ++ /* All zeros is a potentially valid event so memset to 0xff */ ++ memset(buffer->addr, 0xff, len); ++ ++ /* Select new buffer ID */ ++ buffer->index = efx->next_buffer_table; ++ efx->next_buffer_table += buffer->entries; ++ ++ EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x " ++ "(virt %p phys %llx)\n", buffer->index, ++ buffer->index + buffer->entries - 1, ++ (u64)buffer->dma_addr, len, ++ buffer->addr, (u64)virt_to_phys(buffer->addr)); ++ ++ return 0; ++} ++ ++static void ++efx_free_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) ++{ ++ if (!buffer->addr) ++ return; ++ ++ EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x " ++ "(virt %p phys %llx)\n", buffer->index, ++ buffer->index + buffer->entries - 1, ++ (u64)buffer->dma_addr, buffer->len, ++ buffer->addr, (u64)virt_to_phys(buffer->addr)); ++ ++ pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr, ++ buffer->dma_addr); ++ buffer->addr = NULL; ++ buffer->entries = 0; ++} ++ ++/************************************************************************** ++ * ++ * Generic buffer handling ++ * These buffers are used for interrupt status and MAC stats ++ * ++ **************************************************************************/ ++ ++int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, ++ unsigned int len) ++{ ++ buffer->addr = pci_alloc_consistent(efx->pci_dev, len, ++ &buffer->dma_addr); ++ if (!buffer->addr) ++ return -ENOMEM; ++ buffer->len = len; ++ memset(buffer->addr, 0, len); ++ return 0; ++} ++ ++void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) ++{ ++ if (buffer->addr) { ++ pci_free_consistent(efx->pci_dev, buffer->len, ++ buffer->addr, buffer->dma_addr); ++ buffer->addr = NULL; ++ } ++} ++ ++/************************************************************************** ++ * ++ * TX path ++ * ++ **************************************************************************/ ++ ++/* Returns a pointer to the specified transmit descriptor in the TX ++ * descriptor queue belonging to the specified channel. ++ */ ++static inline efx_qword_t * ++efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index) ++{ ++ return (((efx_qword_t *) (tx_queue->txd.addr)) + index); ++} ++ ++/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */ ++static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue) ++{ ++ unsigned write_ptr; ++ efx_dword_t reg; ++ ++ write_ptr = tx_queue->write_count & EFX_TXQ_MASK; ++ EFX_POPULATE_DWORD_1(reg, FRF_AZ_TX_DESC_WPTR_DWORD, write_ptr); ++ efx_writed_page(tx_queue->efx, ®, ++ FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue); ++} ++ ++ ++/* For each entry inserted into the software descriptor ring, create a ++ * descriptor in the hardware TX descriptor ring (in host memory), and ++ * write a doorbell. ++ */ ++void efx_nic_push_buffers(struct efx_tx_queue *tx_queue) ++{ ++ ++ struct efx_tx_buffer *buffer; ++ efx_qword_t *txd; ++ unsigned write_ptr; ++ ++ BUG_ON(tx_queue->write_count == tx_queue->insert_count); ++ ++ do { ++ write_ptr = tx_queue->write_count & EFX_TXQ_MASK; ++ buffer = &tx_queue->buffer[write_ptr]; ++ txd = efx_tx_desc(tx_queue, write_ptr); ++ ++tx_queue->write_count; ++ ++ /* Create TX descriptor ring entry */ ++ EFX_POPULATE_QWORD_4(*txd, ++ FSF_AZ_TX_KER_CONT, buffer->continuation, ++ FSF_AZ_TX_KER_BYTE_COUNT, buffer->len, ++ FSF_AZ_TX_KER_BUF_REGION, 0, ++ FSF_AZ_TX_KER_BUF_ADDR, buffer->dma_addr); ++ } while (tx_queue->write_count != tx_queue->insert_count); ++ ++ wmb(); /* Ensure descriptors are written before they are fetched */ ++ efx_notify_tx_desc(tx_queue); ++} ++ ++/* Allocate hardware resources for a TX queue */ ++int efx_nic_probe_tx(struct efx_tx_queue *tx_queue) ++{ ++ struct efx_nic *efx = tx_queue->efx; ++ BUILD_BUG_ON(EFX_TXQ_SIZE < 512 || EFX_TXQ_SIZE > 4096 || ++ EFX_TXQ_SIZE & EFX_TXQ_MASK); ++ return efx_alloc_special_buffer(efx, &tx_queue->txd, ++ EFX_TXQ_SIZE * sizeof(efx_qword_t)); ++} ++ ++void efx_nic_init_tx(struct efx_tx_queue *tx_queue) ++{ ++ efx_oword_t tx_desc_ptr; ++ struct efx_nic *efx = tx_queue->efx; ++ ++ tx_queue->flushed = FLUSH_NONE; ++ ++ /* Pin TX descriptor ring */ ++ efx_init_special_buffer(efx, &tx_queue->txd); ++ ++ /* Push TX descriptor ring to card */ ++ EFX_POPULATE_OWORD_10(tx_desc_ptr, ++ FRF_AZ_TX_DESCQ_EN, 1, ++ FRF_AZ_TX_ISCSI_DDIG_EN, 0, ++ FRF_AZ_TX_ISCSI_HDIG_EN, 0, ++ FRF_AZ_TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index, ++ FRF_AZ_TX_DESCQ_EVQ_ID, ++ tx_queue->channel->channel, ++ FRF_AZ_TX_DESCQ_OWNER_ID, 0, ++ FRF_AZ_TX_DESCQ_LABEL, tx_queue->queue, ++ FRF_AZ_TX_DESCQ_SIZE, ++ __ffs(tx_queue->txd.entries), ++ FRF_AZ_TX_DESCQ_TYPE, 0, ++ FRF_BZ_TX_NON_IP_DROP_DIS, 1); ++ ++ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { ++ int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM; ++ EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum); ++ EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS, ++ !csum); ++ } ++ ++ efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, ++ tx_queue->queue); ++ ++ if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { ++ efx_oword_t reg; ++ ++ /* Only 128 bits in this register */ ++ BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128); ++ ++ efx_reado(efx, ®, FR_AA_TX_CHKSM_CFG); ++ if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM) ++ clear_bit_le(tx_queue->queue, (void *)®); ++ else ++ set_bit_le(tx_queue->queue, (void *)®); ++ efx_writeo(efx, ®, FR_AA_TX_CHKSM_CFG); ++ } ++} ++ ++static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue) ++{ ++ struct efx_nic *efx = tx_queue->efx; ++ efx_oword_t tx_flush_descq; ++ ++ tx_queue->flushed = FLUSH_PENDING; ++ ++ /* Post a flush command */ ++ EFX_POPULATE_OWORD_2(tx_flush_descq, ++ FRF_AZ_TX_FLUSH_DESCQ_CMD, 1, ++ FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue); ++ efx_writeo(efx, &tx_flush_descq, FR_AZ_TX_FLUSH_DESCQ); ++} ++ ++void efx_nic_fini_tx(struct efx_tx_queue *tx_queue) ++{ ++ struct efx_nic *efx = tx_queue->efx; ++ efx_oword_t tx_desc_ptr; ++ ++ /* The queue should have been flushed */ ++ WARN_ON(tx_queue->flushed != FLUSH_DONE); ++ ++ /* Remove TX descriptor ring from card */ ++ EFX_ZERO_OWORD(tx_desc_ptr); ++ efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, ++ tx_queue->queue); ++ ++ /* Unpin TX descriptor ring */ ++ efx_fini_special_buffer(efx, &tx_queue->txd); ++} ++ ++/* Free buffers backing TX queue */ ++void efx_nic_remove_tx(struct efx_tx_queue *tx_queue) ++{ ++ efx_free_special_buffer(tx_queue->efx, &tx_queue->txd); ++} ++ ++/************************************************************************** ++ * ++ * RX path ++ * ++ **************************************************************************/ ++ ++/* Returns a pointer to the specified descriptor in the RX descriptor queue */ ++static inline efx_qword_t * ++efx_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index) ++{ ++ return (((efx_qword_t *) (rx_queue->rxd.addr)) + index); ++} ++ ++/* This creates an entry in the RX descriptor queue */ ++static inline void ++efx_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned index) ++{ ++ struct efx_rx_buffer *rx_buf; ++ efx_qword_t *rxd; ++ ++ rxd = efx_rx_desc(rx_queue, index); ++ rx_buf = efx_rx_buffer(rx_queue, index); ++ EFX_POPULATE_QWORD_3(*rxd, ++ FSF_AZ_RX_KER_BUF_SIZE, ++ rx_buf->len - ++ rx_queue->efx->type->rx_buffer_padding, ++ FSF_AZ_RX_KER_BUF_REGION, 0, ++ FSF_AZ_RX_KER_BUF_ADDR, rx_buf->dma_addr); ++} ++ ++/* This writes to the RX_DESC_WPTR register for the specified receive ++ * descriptor ring. ++ */ ++void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue) ++{ ++ efx_dword_t reg; ++ unsigned write_ptr; ++ ++ while (rx_queue->notified_count != rx_queue->added_count) { ++ efx_build_rx_desc(rx_queue, ++ rx_queue->notified_count & ++ EFX_RXQ_MASK); ++ ++rx_queue->notified_count; ++ } ++ ++ wmb(); ++ write_ptr = rx_queue->added_count & EFX_RXQ_MASK; ++ EFX_POPULATE_DWORD_1(reg, FRF_AZ_RX_DESC_WPTR_DWORD, write_ptr); ++ efx_writed_page(rx_queue->efx, ®, ++ FR_AZ_RX_DESC_UPD_DWORD_P0, rx_queue->queue); ++} ++ ++int efx_nic_probe_rx(struct efx_rx_queue *rx_queue) ++{ ++ struct efx_nic *efx = rx_queue->efx; ++ BUILD_BUG_ON(EFX_RXQ_SIZE < 512 || EFX_RXQ_SIZE > 4096 || ++ EFX_RXQ_SIZE & EFX_RXQ_MASK); ++ return efx_alloc_special_buffer(efx, &rx_queue->rxd, ++ EFX_RXQ_SIZE * sizeof(efx_qword_t)); ++} ++ ++void efx_nic_init_rx(struct efx_rx_queue *rx_queue) ++{ ++ efx_oword_t rx_desc_ptr; ++ struct efx_nic *efx = rx_queue->efx; ++ bool is_b0 = efx_nic_rev(efx) >= EFX_REV_FALCON_B0; ++ bool iscsi_digest_en = is_b0; ++ ++ EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n", ++ rx_queue->queue, rx_queue->rxd.index, ++ rx_queue->rxd.index + rx_queue->rxd.entries - 1); ++ ++ rx_queue->flushed = FLUSH_NONE; ++ ++ /* Pin RX descriptor ring */ ++ efx_init_special_buffer(efx, &rx_queue->rxd); ++ ++ /* Push RX descriptor ring to card */ ++ EFX_POPULATE_OWORD_10(rx_desc_ptr, ++ FRF_AZ_RX_ISCSI_DDIG_EN, iscsi_digest_en, ++ FRF_AZ_RX_ISCSI_HDIG_EN, iscsi_digest_en, ++ FRF_AZ_RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index, ++ FRF_AZ_RX_DESCQ_EVQ_ID, ++ rx_queue->channel->channel, ++ FRF_AZ_RX_DESCQ_OWNER_ID, 0, ++ FRF_AZ_RX_DESCQ_LABEL, rx_queue->queue, ++ FRF_AZ_RX_DESCQ_SIZE, ++ __ffs(rx_queue->rxd.entries), ++ FRF_AZ_RX_DESCQ_TYPE, 0 /* kernel queue */ , ++ /* For >=B0 this is scatter so disable */ ++ FRF_AZ_RX_DESCQ_JUMBO, !is_b0, ++ FRF_AZ_RX_DESCQ_EN, 1); ++ efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, ++ rx_queue->queue); ++} ++ ++static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue) ++{ ++ struct efx_nic *efx = rx_queue->efx; ++ efx_oword_t rx_flush_descq; ++ ++ rx_queue->flushed = FLUSH_PENDING; ++ ++ /* Post a flush command */ ++ EFX_POPULATE_OWORD_2(rx_flush_descq, ++ FRF_AZ_RX_FLUSH_DESCQ_CMD, 1, ++ FRF_AZ_RX_FLUSH_DESCQ, rx_queue->queue); ++ efx_writeo(efx, &rx_flush_descq, FR_AZ_RX_FLUSH_DESCQ); ++} ++ ++void efx_nic_fini_rx(struct efx_rx_queue *rx_queue) ++{ ++ efx_oword_t rx_desc_ptr; ++ struct efx_nic *efx = rx_queue->efx; ++ ++ /* The queue should already have been flushed */ ++ WARN_ON(rx_queue->flushed != FLUSH_DONE); ++ ++ /* Remove RX descriptor ring from card */ ++ EFX_ZERO_OWORD(rx_desc_ptr); ++ efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, ++ rx_queue->queue); ++ ++ /* Unpin RX descriptor ring */ ++ efx_fini_special_buffer(efx, &rx_queue->rxd); ++} ++ ++/* Free buffers backing RX queue */ ++void efx_nic_remove_rx(struct efx_rx_queue *rx_queue) ++{ ++ efx_free_special_buffer(rx_queue->efx, &rx_queue->rxd); ++} ++ ++/************************************************************************** ++ * ++ * Event queue processing ++ * Event queues are processed by per-channel tasklets. ++ * ++ **************************************************************************/ ++ ++/* Update a channel's event queue's read pointer (RPTR) register ++ * ++ * This writes the EVQ_RPTR_REG register for the specified channel's ++ * event queue. ++ * ++ * Note that EVQ_RPTR_REG contains the index of the "last read" event, ++ * whereas channel->eventq_read_ptr contains the index of the "next to ++ * read" event. ++ */ ++void efx_nic_eventq_read_ack(struct efx_channel *channel) ++{ ++ efx_dword_t reg; ++ struct efx_nic *efx = channel->efx; ++ ++ EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr); ++ efx_writed_table(efx, ®, efx->type->evq_rptr_tbl_base, ++ channel->channel); ++} ++ ++/* Use HW to insert a SW defined event */ ++void efx_generate_event(struct efx_channel *channel, efx_qword_t *event) ++{ ++ efx_oword_t drv_ev_reg; ++ ++ BUILD_BUG_ON(FRF_AZ_DRV_EV_DATA_LBN != 0 || ++ FRF_AZ_DRV_EV_DATA_WIDTH != 64); ++ drv_ev_reg.u32[0] = event->u32[0]; ++ drv_ev_reg.u32[1] = event->u32[1]; ++ drv_ev_reg.u32[2] = 0; ++ drv_ev_reg.u32[3] = 0; ++ EFX_SET_OWORD_FIELD(drv_ev_reg, FRF_AZ_DRV_EV_QID, channel->channel); ++ efx_writeo(channel->efx, &drv_ev_reg, FR_AZ_DRV_EV); ++} ++ ++/* Handle a transmit completion event ++ * ++ * The NIC batches TX completion events; the message we receive is of ++ * the form "complete all TX events up to this index". ++ */ ++static void ++efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) ++{ ++ unsigned int tx_ev_desc_ptr; ++ unsigned int tx_ev_q_label; ++ struct efx_tx_queue *tx_queue; ++ struct efx_nic *efx = channel->efx; ++ ++ if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) { ++ /* Transmit completion */ ++ tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR); ++ tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); ++ tx_queue = &efx->tx_queue[tx_ev_q_label]; ++ channel->irq_mod_score += ++ (tx_ev_desc_ptr - tx_queue->read_count) & ++ EFX_TXQ_MASK; ++ efx_xmit_done(tx_queue, tx_ev_desc_ptr); ++ } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) { ++ /* Rewrite the FIFO write pointer */ ++ tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); ++ tx_queue = &efx->tx_queue[tx_ev_q_label]; ++ ++ if (efx_dev_registered(efx)) ++ netif_tx_lock(efx->net_dev); ++ efx_notify_tx_desc(tx_queue); ++ if (efx_dev_registered(efx)) ++ netif_tx_unlock(efx->net_dev); ++ } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR) && ++ EFX_WORKAROUND_10727(efx)) { ++ efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); ++ } else { ++ EFX_ERR(efx, "channel %d unexpected TX event " ++ EFX_QWORD_FMT"\n", channel->channel, ++ EFX_QWORD_VAL(*event)); ++ } ++} ++ ++/* Detect errors included in the rx_evt_pkt_ok bit. */ ++static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue, ++ const efx_qword_t *event, ++ bool *rx_ev_pkt_ok, ++ bool *discard) ++{ ++ struct efx_nic *efx = rx_queue->efx; ++ bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err; ++ bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err; ++ bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc; ++ bool rx_ev_other_err, rx_ev_pause_frm; ++ bool rx_ev_hdr_type, rx_ev_mcast_pkt; ++ unsigned rx_ev_pkt_type; ++ ++ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE); ++ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT); ++ rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_TOBE_DISC); ++ rx_ev_pkt_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_TYPE); ++ rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event, ++ FSF_AZ_RX_EV_BUF_OWNER_ID_ERR); ++ rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event, ++ FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR); ++ rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event, ++ FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR); ++ rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_ETH_CRC_ERR); ++ rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_FRM_TRUNC); ++ rx_ev_drib_nib = ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ? ++ 0 : EFX_QWORD_FIELD(*event, FSF_AA_RX_EV_DRIB_NIB)); ++ rx_ev_pause_frm = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PAUSE_FRM_ERR); ++ ++ /* Every error apart from tobe_disc and pause_frm */ ++ rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err | ++ rx_ev_buf_owner_id_err | rx_ev_eth_crc_err | ++ rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err); ++ ++ /* Count errors that are not in MAC stats. Ignore expected ++ * checksum errors during self-test. */ ++ if (rx_ev_frm_trunc) ++ ++rx_queue->channel->n_rx_frm_trunc; ++ else if (rx_ev_tobe_disc) ++ ++rx_queue->channel->n_rx_tobe_disc; ++ else if (!efx->loopback_selftest) { ++ if (rx_ev_ip_hdr_chksum_err) ++ ++rx_queue->channel->n_rx_ip_hdr_chksum_err; ++ else if (rx_ev_tcp_udp_chksum_err) ++ ++rx_queue->channel->n_rx_tcp_udp_chksum_err; ++ } ++ ++ /* The frame must be discarded if any of these are true. */ ++ *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib | ++ rx_ev_tobe_disc | rx_ev_pause_frm); ++ ++ /* TOBE_DISC is expected on unicast mismatches; don't print out an ++ * error message. FRM_TRUNC indicates RXDP dropped the packet due ++ * to a FIFO overflow. ++ */ ++#ifdef EFX_ENABLE_DEBUG ++ if (rx_ev_other_err) { ++ EFX_INFO_RL(efx, " RX queue %d unexpected RX event " ++ EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n", ++ rx_queue->queue, EFX_QWORD_VAL(*event), ++ rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "", ++ rx_ev_ip_hdr_chksum_err ? ++ " [IP_HDR_CHKSUM_ERR]" : "", ++ rx_ev_tcp_udp_chksum_err ? ++ " [TCP_UDP_CHKSUM_ERR]" : "", ++ rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "", ++ rx_ev_frm_trunc ? " [FRM_TRUNC]" : "", ++ rx_ev_drib_nib ? " [DRIB_NIB]" : "", ++ rx_ev_tobe_disc ? " [TOBE_DISC]" : "", ++ rx_ev_pause_frm ? " [PAUSE]" : ""); ++ } ++#endif ++} ++ ++/* Handle receive events that are not in-order. */ ++static void ++efx_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index) ++{ ++ struct efx_nic *efx = rx_queue->efx; ++ unsigned expected, dropped; ++ ++ expected = rx_queue->removed_count & EFX_RXQ_MASK; ++ dropped = (index - expected) & EFX_RXQ_MASK; ++ EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n", ++ dropped, index, expected); ++ ++ efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ? ++ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); ++} ++ ++/* Handle a packet received event ++ * ++ * The NIC gives a "discard" flag if it's a unicast packet with the ++ * wrong destination address ++ * Also "is multicast" and "matches multicast filter" flags can be used to ++ * discard non-matching multicast packets. ++ */ ++static void ++efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) ++{ ++ unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt; ++ unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt; ++ unsigned expected_ptr; ++ bool rx_ev_pkt_ok, discard = false, checksummed; ++ struct efx_rx_queue *rx_queue; ++ struct efx_nic *efx = channel->efx; ++ ++ /* Basic packet information */ ++ rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT); ++ rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_OK); ++ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE); ++ WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_JUMBO_CONT)); ++ WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_SOP) != 1); ++ WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_Q_LABEL) != ++ channel->channel); ++ ++ rx_queue = &efx->rx_queue[channel->channel]; ++ ++ rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR); ++ expected_ptr = rx_queue->removed_count & EFX_RXQ_MASK; ++ if (unlikely(rx_ev_desc_ptr != expected_ptr)) ++ efx_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); ++ ++ if (likely(rx_ev_pkt_ok)) { ++ /* If packet is marked as OK and packet type is TCP/IP or ++ * UDP/IP, then we can rely on the hardware checksum. ++ */ ++ checksummed = ++ likely(efx->rx_checksum_enabled) && ++ (rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP || ++ rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP); ++ } else { ++ efx_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, &discard); ++ checksummed = false; ++ } ++ ++ /* Detect multicast packets that didn't match the filter */ ++ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT); ++ if (rx_ev_mcast_pkt) { ++ unsigned int rx_ev_mcast_hash_match = ++ EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_HASH_MATCH); ++ ++ if (unlikely(!rx_ev_mcast_hash_match)) { ++ ++channel->n_rx_mcast_mismatch; ++ discard = true; ++ } ++ } ++ ++ channel->irq_mod_score += 2; ++ ++ /* Handle received packet */ ++ efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, ++ checksummed, discard); ++} ++ ++/* Global events are basically PHY events */ ++static void ++efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event) ++{ ++ struct efx_nic *efx = channel->efx; ++ bool handled = false; ++ ++ if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) || ++ EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) || ++ EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) { ++ /* Ignored */ ++ handled = true; ++ } ++ ++ if ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) && ++ EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) { ++ efx->xmac_poll_required = true; ++ handled = true; ++ } ++ ++ if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ? ++ EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) : ++ EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) { ++ EFX_ERR(efx, "channel %d seen global RX_RESET " ++ "event. Resetting.\n", channel->channel); ++ ++ atomic_inc(&efx->rx_reset); ++ efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ? ++ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); ++ handled = true; ++ } ++ ++ if (!handled) ++ EFX_ERR(efx, "channel %d unknown global event " ++ EFX_QWORD_FMT "\n", channel->channel, ++ EFX_QWORD_VAL(*event)); ++} ++ ++static void ++efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) ++{ ++ struct efx_nic *efx = channel->efx; ++ unsigned int ev_sub_code; ++ unsigned int ev_sub_data; ++ ++ ev_sub_code = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBCODE); ++ ev_sub_data = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA); ++ ++ switch (ev_sub_code) { ++ case FSE_AZ_TX_DESCQ_FLS_DONE_EV: ++ EFX_TRACE(efx, "channel %d TXQ %d flushed\n", ++ channel->channel, ev_sub_data); ++ break; ++ case FSE_AZ_RX_DESCQ_FLS_DONE_EV: ++ EFX_TRACE(efx, "channel %d RXQ %d flushed\n", ++ channel->channel, ev_sub_data); ++ break; ++ case FSE_AZ_EVQ_INIT_DONE_EV: ++ EFX_LOG(efx, "channel %d EVQ %d initialised\n", ++ channel->channel, ev_sub_data); ++ break; ++ case FSE_AZ_SRM_UPD_DONE_EV: ++ EFX_TRACE(efx, "channel %d SRAM update done\n", ++ channel->channel); ++ break; ++ case FSE_AZ_WAKE_UP_EV: ++ EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n", ++ channel->channel, ev_sub_data); ++ break; ++ case FSE_AZ_TIMER_EV: ++ EFX_TRACE(efx, "channel %d RX queue %d timer expired\n", ++ channel->channel, ev_sub_data); ++ break; ++ case FSE_AA_RX_RECOVER_EV: ++ EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. " ++ "Resetting.\n", channel->channel); ++ atomic_inc(&efx->rx_reset); ++ efx_schedule_reset(efx, ++ EFX_WORKAROUND_6555(efx) ? ++ RESET_TYPE_RX_RECOVERY : ++ RESET_TYPE_DISABLE); ++ break; ++ case FSE_BZ_RX_DSC_ERROR_EV: ++ EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error." ++ " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data); ++ efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH); ++ break; ++ case FSE_BZ_TX_DSC_ERROR_EV: ++ EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error." ++ " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data); ++ efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); ++ break; ++ default: ++ EFX_TRACE(efx, "channel %d unknown driver event code %d " ++ "data %04x\n", channel->channel, ev_sub_code, ++ ev_sub_data); ++ break; ++ } ++} ++ ++int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota) ++{ ++ unsigned int read_ptr; ++ efx_qword_t event, *p_event; ++ int ev_code; ++ int rx_packets = 0; ++ ++ read_ptr = channel->eventq_read_ptr; ++ ++ do { ++ p_event = efx_event(channel, read_ptr); ++ event = *p_event; ++ ++ if (!efx_event_present(&event)) ++ /* End of events */ ++ break; ++ ++ EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n", ++ channel->channel, EFX_QWORD_VAL(event)); ++ ++ /* Clear this event by marking it all ones */ ++ EFX_SET_QWORD(*p_event); ++ ++ ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); ++ ++ switch (ev_code) { ++ case FSE_AZ_EV_CODE_RX_EV: ++ efx_handle_rx_event(channel, &event); ++ ++rx_packets; ++ break; ++ case FSE_AZ_EV_CODE_TX_EV: ++ efx_handle_tx_event(channel, &event); ++ break; ++ case FSE_AZ_EV_CODE_DRV_GEN_EV: ++ channel->eventq_magic = EFX_QWORD_FIELD( ++ event, FSF_AZ_DRV_GEN_EV_MAGIC); ++ EFX_LOG(channel->efx, "channel %d received generated " ++ "event "EFX_QWORD_FMT"\n", channel->channel, ++ EFX_QWORD_VAL(event)); ++ break; ++ case FSE_AZ_EV_CODE_GLOBAL_EV: ++ efx_handle_global_event(channel, &event); ++ break; ++ case FSE_AZ_EV_CODE_DRIVER_EV: ++ efx_handle_driver_event(channel, &event); ++ break; ++ case FSE_CZ_EV_CODE_MCDI_EV: ++ efx_mcdi_process_event(channel, &event); ++ break; ++ default: ++ EFX_ERR(channel->efx, "channel %d unknown event type %d" ++ " (data " EFX_QWORD_FMT ")\n", channel->channel, ++ ev_code, EFX_QWORD_VAL(event)); ++ } ++ ++ /* Increment read pointer */ ++ read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; ++ ++ } while (rx_packets < rx_quota); ++ ++ channel->eventq_read_ptr = read_ptr; ++ return rx_packets; ++} ++ ++ ++/* Allocate buffer table entries for event queue */ ++int efx_nic_probe_eventq(struct efx_channel *channel) ++{ ++ struct efx_nic *efx = channel->efx; ++ BUILD_BUG_ON(EFX_EVQ_SIZE < 512 || EFX_EVQ_SIZE > 32768 || ++ EFX_EVQ_SIZE & EFX_EVQ_MASK); ++ return efx_alloc_special_buffer(efx, &channel->eventq, ++ EFX_EVQ_SIZE * sizeof(efx_qword_t)); ++} ++ ++void efx_nic_init_eventq(struct efx_channel *channel) ++{ ++ efx_oword_t reg; ++ struct efx_nic *efx = channel->efx; ++ ++ EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", ++ channel->channel, channel->eventq.index, ++ channel->eventq.index + channel->eventq.entries - 1); ++ ++ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) { ++ EFX_POPULATE_OWORD_3(reg, ++ FRF_CZ_TIMER_Q_EN, 1, ++ FRF_CZ_HOST_NOTIFY_MODE, 0, ++ FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS); ++ efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); ++ } ++ ++ /* Pin event queue buffer */ ++ efx_init_special_buffer(efx, &channel->eventq); ++ ++ /* Fill event queue with all ones (i.e. empty events) */ ++ memset(channel->eventq.addr, 0xff, channel->eventq.len); ++ ++ /* Push event queue to card */ ++ EFX_POPULATE_OWORD_3(reg, ++ FRF_AZ_EVQ_EN, 1, ++ FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries), ++ FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index); ++ efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, ++ channel->channel); ++ ++ efx->type->push_irq_moderation(channel); ++} ++ ++void efx_nic_fini_eventq(struct efx_channel *channel) ++{ ++ efx_oword_t reg; ++ struct efx_nic *efx = channel->efx; ++ ++ /* Remove event queue from card */ ++ EFX_ZERO_OWORD(reg); ++ efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, ++ channel->channel); ++ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) ++ efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); ++ ++ /* Unpin event queue */ ++ efx_fini_special_buffer(efx, &channel->eventq); ++} ++ ++/* Free buffers backing event queue */ ++void efx_nic_remove_eventq(struct efx_channel *channel) ++{ ++ efx_free_special_buffer(channel->efx, &channel->eventq); ++} ++ ++ ++/* Generates a test event on the event queue. A subsequent call to ++ * process_eventq() should pick up the event and place the value of ++ * "magic" into channel->eventq_magic; ++ */ ++void efx_nic_generate_test_event(struct efx_channel *channel, unsigned int magic) ++{ ++ efx_qword_t test_event; ++ ++ EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE, ++ FSE_AZ_EV_CODE_DRV_GEN_EV, ++ FSF_AZ_DRV_GEN_EV_MAGIC, magic); ++ efx_generate_event(channel, &test_event); ++} ++ ++/************************************************************************** ++ * ++ * Flush handling ++ * ++ **************************************************************************/ ++ ++ ++static void efx_poll_flush_events(struct efx_nic *efx) ++{ ++ struct efx_channel *channel = &efx->channel[0]; ++ struct efx_tx_queue *tx_queue; ++ struct efx_rx_queue *rx_queue; ++ unsigned int read_ptr = channel->eventq_read_ptr; ++ unsigned int end_ptr = (read_ptr - 1) & EFX_EVQ_MASK; ++ ++ do { ++ efx_qword_t *event = efx_event(channel, read_ptr); ++ int ev_code, ev_sub_code, ev_queue; ++ bool ev_failed; ++ ++ if (!efx_event_present(event)) ++ break; ++ ++ ev_code = EFX_QWORD_FIELD(*event, FSF_AZ_EV_CODE); ++ ev_sub_code = EFX_QWORD_FIELD(*event, ++ FSF_AZ_DRIVER_EV_SUBCODE); ++ if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV && ++ ev_sub_code == FSE_AZ_TX_DESCQ_FLS_DONE_EV) { ++ ev_queue = EFX_QWORD_FIELD(*event, ++ FSF_AZ_DRIVER_EV_SUBDATA); ++ if (ev_queue < EFX_TX_QUEUE_COUNT) { ++ tx_queue = efx->tx_queue + ev_queue; ++ tx_queue->flushed = FLUSH_DONE; ++ } ++ } else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV && ++ ev_sub_code == FSE_AZ_RX_DESCQ_FLS_DONE_EV) { ++ ev_queue = EFX_QWORD_FIELD( ++ *event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID); ++ ev_failed = EFX_QWORD_FIELD( ++ *event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL); ++ if (ev_queue < efx->n_rx_queues) { ++ rx_queue = efx->rx_queue + ev_queue; ++ rx_queue->flushed = ++ ev_failed ? FLUSH_FAILED : FLUSH_DONE; ++ } ++ } ++ ++ /* We're about to destroy the queue anyway, so ++ * it's ok to throw away every non-flush event */ ++ EFX_SET_QWORD(*event); ++ ++ read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; ++ } while (read_ptr != end_ptr); ++ ++ channel->eventq_read_ptr = read_ptr; ++} ++ ++/* Handle tx and rx flushes at the same time, since they run in ++ * parallel in the hardware and there's no reason for us to ++ * serialise them */ ++int efx_nic_flush_queues(struct efx_nic *efx) ++{ ++ struct efx_rx_queue *rx_queue; ++ struct efx_tx_queue *tx_queue; ++ int i, tx_pending, rx_pending; ++ ++ /* If necessary prepare the hardware for flushing */ ++ efx->type->prepare_flush(efx); ++ ++ /* Flush all tx queues in parallel */ ++ efx_for_each_tx_queue(tx_queue, efx) ++ efx_flush_tx_queue(tx_queue); ++ ++ /* The hardware supports four concurrent rx flushes, each of which may ++ * need to be retried if there is an outstanding descriptor fetch */ ++ for (i = 0; i < EFX_FLUSH_POLL_COUNT; ++i) { ++ rx_pending = tx_pending = 0; ++ efx_for_each_rx_queue(rx_queue, efx) { ++ if (rx_queue->flushed == FLUSH_PENDING) ++ ++rx_pending; ++ } ++ efx_for_each_rx_queue(rx_queue, efx) { ++ if (rx_pending == EFX_RX_FLUSH_COUNT) ++ break; ++ if (rx_queue->flushed == FLUSH_FAILED || ++ rx_queue->flushed == FLUSH_NONE) { ++ efx_flush_rx_queue(rx_queue); ++ ++rx_pending; ++ } ++ } ++ efx_for_each_tx_queue(tx_queue, efx) { ++ if (tx_queue->flushed != FLUSH_DONE) ++ ++tx_pending; ++ } ++ ++ if (rx_pending == 0 && tx_pending == 0) ++ return 0; ++ ++ msleep(EFX_FLUSH_INTERVAL); ++ efx_poll_flush_events(efx); ++ } ++ ++ /* Mark the queues as all flushed. We're going to return failure ++ * leading to a reset, or fake up success anyway */ ++ efx_for_each_tx_queue(tx_queue, efx) { ++ if (tx_queue->flushed != FLUSH_DONE) ++ EFX_ERR(efx, "tx queue %d flush command timed out\n", ++ tx_queue->queue); ++ tx_queue->flushed = FLUSH_DONE; ++ } ++ efx_for_each_rx_queue(rx_queue, efx) { ++ if (rx_queue->flushed != FLUSH_DONE) ++ EFX_ERR(efx, "rx queue %d flush command timed out\n", ++ rx_queue->queue); ++ rx_queue->flushed = FLUSH_DONE; ++ } ++ ++ if (EFX_WORKAROUND_7803(efx)) ++ return 0; ++ ++ return -ETIMEDOUT; ++} ++ ++/************************************************************************** ++ * ++ * Hardware interrupts ++ * The hardware interrupt handler does very little work; all the event ++ * queue processing is carried out by per-channel tasklets. ++ * ++ **************************************************************************/ ++ ++/* Enable/disable/generate interrupts */ ++static inline void efx_nic_interrupts(struct efx_nic *efx, ++ bool enabled, bool force) ++{ ++ efx_oword_t int_en_reg_ker; ++ unsigned int level = 0; ++ ++ if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx)) ++ /* Set the level always even if we're generating a test ++ * interrupt, because our legacy interrupt handler is safe */ ++ level = 0x1f; ++ ++ EFX_POPULATE_OWORD_3(int_en_reg_ker, ++ FRF_AZ_KER_INT_LEVE_SEL, level, ++ FRF_AZ_KER_INT_KER, force, ++ FRF_AZ_DRV_INT_EN_KER, enabled); ++ efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); ++} ++ ++void efx_nic_enable_interrupts(struct efx_nic *efx) ++{ ++ struct efx_channel *channel; ++ ++ EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr)); ++ wmb(); /* Ensure interrupt vector is clear before interrupts enabled */ ++ ++ /* Enable interrupts */ ++ efx_nic_interrupts(efx, true, false); ++ ++ /* Force processing of all the channels to get the EVQ RPTRs up to ++ date */ ++ efx_for_each_channel(channel, efx) ++ efx_schedule_channel(channel); ++} ++ ++void efx_nic_disable_interrupts(struct efx_nic *efx) ++{ ++ /* Disable interrupts */ ++ efx_nic_interrupts(efx, false, false); ++} ++ ++/* Generate a test interrupt ++ * Interrupt must already have been enabled, otherwise nasty things ++ * may happen. ++ */ ++void efx_nic_generate_interrupt(struct efx_nic *efx) ++{ ++ efx_nic_interrupts(efx, true, true); ++} ++ ++/* Process a fatal interrupt ++ * Disable bus mastering ASAP and schedule a reset ++ */ ++irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx) ++{ ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ efx_oword_t *int_ker = efx->irq_status.addr; ++ efx_oword_t fatal_intr; ++ int error, mem_perr; ++ ++ efx_reado(efx, &fatal_intr, FR_AZ_FATAL_INTR_KER); ++ error = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_FATAL_INTR); ++ ++ EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status " ++ EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker), ++ EFX_OWORD_VAL(fatal_intr), ++ error ? "disabling bus mastering" : "no recognised error"); ++ if (error == 0) ++ goto out; ++ ++ /* If this is a memory parity error dump which blocks are offending */ ++ mem_perr = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER); ++ if (mem_perr) { ++ efx_oword_t reg; ++ efx_reado(efx, ®, FR_AZ_MEM_STAT); ++ EFX_ERR(efx, "SYSTEM ERROR: memory parity error " ++ EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg)); ++ } ++ ++ /* Disable both devices */ ++ pci_clear_master(efx->pci_dev); ++ if (efx_nic_is_dual_func(efx)) ++ pci_clear_master(nic_data->pci_dev2); ++ efx_nic_disable_interrupts(efx); ++ ++ /* Count errors and reset or disable the NIC accordingly */ ++ if (efx->int_error_count == 0 || ++ time_after(jiffies, efx->int_error_expire)) { ++ efx->int_error_count = 0; ++ efx->int_error_expire = ++ jiffies + EFX_INT_ERROR_EXPIRE * HZ; ++ } ++ if (++efx->int_error_count < EFX_MAX_INT_ERRORS) { ++ EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n"); ++ efx_schedule_reset(efx, RESET_TYPE_INT_ERROR); ++ } else { ++ EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen." ++ "NIC will be disabled\n"); ++ efx_schedule_reset(efx, RESET_TYPE_DISABLE); ++ } ++out: ++ return IRQ_HANDLED; ++} ++ ++/* Handle a legacy interrupt ++ * Acknowledges the interrupt and schedule event queue processing. ++ */ ++static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) ++{ ++ struct efx_nic *efx = dev_id; ++ efx_oword_t *int_ker = efx->irq_status.addr; ++ irqreturn_t result = IRQ_NONE; ++ struct efx_channel *channel; ++ efx_dword_t reg; ++ u32 queues; ++ int syserr; ++ ++ /* Read the ISR which also ACKs the interrupts */ ++ efx_readd(efx, ®, FR_BZ_INT_ISR0); ++ queues = EFX_EXTRACT_DWORD(reg, 0, 31); ++ ++ /* Check to see if we have a serious error condition */ ++ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); ++ if (unlikely(syserr)) ++ return efx_nic_fatal_interrupt(efx); ++ ++ if (queues != 0) { ++ if (EFX_WORKAROUND_15783(efx)) ++ efx->irq_zero_count = 0; ++ ++ /* Schedule processing of any interrupting queues */ ++ efx_for_each_channel(channel, efx) { ++ if (queues & 1) ++ efx_schedule_channel(channel); ++ queues >>= 1; ++ } ++ result = IRQ_HANDLED; ++ ++ } else if (EFX_WORKAROUND_15783(efx) && ++ efx->irq_zero_count++ == 0) { ++ efx_qword_t *event; ++ ++ /* Ensure we rearm all event queues */ ++ efx_for_each_channel(channel, efx) { ++ event = efx_event(channel, channel->eventq_read_ptr); ++ if (efx_event_present(event)) ++ efx_schedule_channel(channel); ++ } ++ ++ result = IRQ_HANDLED; ++ } ++ ++ if (result == IRQ_HANDLED) { ++ efx->last_irq_cpu = raw_smp_processor_id(); ++ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n", ++ irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg)); ++ } ++ ++ return result; ++} ++ ++/* Handle an MSI interrupt ++ * ++ * Handle an MSI hardware interrupt. This routine schedules event ++ * queue processing. No interrupt acknowledgement cycle is necessary. ++ * Also, we never need to check that the interrupt is for us, since ++ * MSI interrupts cannot be shared. ++ */ ++static irqreturn_t efx_msi_interrupt(int irq, void *dev_id) ++{ ++ struct efx_channel *channel = dev_id; ++ struct efx_nic *efx = channel->efx; ++ efx_oword_t *int_ker = efx->irq_status.addr; ++ int syserr; ++ ++ efx->last_irq_cpu = raw_smp_processor_id(); ++ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n", ++ irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); ++ ++ /* Check to see if we have a serious error condition */ ++ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); ++ if (unlikely(syserr)) ++ return efx_nic_fatal_interrupt(efx); ++ ++ /* Schedule processing of the channel */ ++ efx_schedule_channel(channel); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++/* Setup RSS indirection table. ++ * This maps from the hash value of the packet to RXQ ++ */ ++static void efx_setup_rss_indir_table(struct efx_nic *efx) ++{ ++ int i = 0; ++ unsigned long offset; ++ efx_dword_t dword; ++ ++ if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) ++ return; ++ ++ for (offset = FR_BZ_RX_INDIRECTION_TBL; ++ offset < FR_BZ_RX_INDIRECTION_TBL + 0x800; ++ offset += 0x10) { ++ EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE, ++ i % efx->n_rx_queues); ++ efx_writed(efx, &dword, offset); ++ i++; ++ } ++} ++ ++/* Hook interrupt handler(s) ++ * Try MSI and then legacy interrupts. ++ */ ++int efx_nic_init_interrupt(struct efx_nic *efx) ++{ ++ struct efx_channel *channel; ++ int rc; ++ ++ if (!EFX_INT_MODE_USE_MSI(efx)) { ++ irq_handler_t handler; ++ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ++ handler = efx_legacy_interrupt; ++ else ++ handler = falcon_legacy_interrupt_a1; ++ ++ rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED, ++ efx->name, efx); ++ if (rc) { ++ EFX_ERR(efx, "failed to hook legacy IRQ %d\n", ++ efx->pci_dev->irq); ++ goto fail1; ++ } ++ return 0; ++ } ++ ++ /* Hook MSI or MSI-X interrupt */ ++ efx_for_each_channel(channel, efx) { ++ rc = request_irq(channel->irq, efx_msi_interrupt, ++ IRQF_PROBE_SHARED, /* Not shared */ ++ channel->name, channel); ++ if (rc) { ++ EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq); ++ goto fail2; ++ } ++ } ++ ++ return 0; ++ ++ fail2: ++ efx_for_each_channel(channel, efx) ++ free_irq(channel->irq, channel); ++ fail1: ++ return rc; ++} ++ ++void efx_nic_fini_interrupt(struct efx_nic *efx) ++{ ++ struct efx_channel *channel; ++ efx_oword_t reg; ++ ++ /* Disable MSI/MSI-X interrupts */ ++ efx_for_each_channel(channel, efx) { ++ if (channel->irq) ++ free_irq(channel->irq, channel); ++ } ++ ++ /* ACK legacy interrupt */ ++ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ++ efx_reado(efx, ®, FR_BZ_INT_ISR0); ++ else ++ falcon_irq_ack_a1(efx); ++ ++ /* Disable legacy interrupt */ ++ if (efx->legacy_irq) ++ free_irq(efx->legacy_irq, efx); ++} ++ ++u32 efx_nic_fpga_ver(struct efx_nic *efx) ++{ ++ efx_oword_t altera_build; ++ efx_reado(efx, &altera_build, FR_AZ_ALTERA_BUILD); ++ return EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER); ++} ++ ++void efx_nic_init_common(struct efx_nic *efx) ++{ ++ efx_oword_t temp; ++ ++ /* Set positions of descriptor caches in SRAM. */ ++ EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR, ++ efx->type->tx_dc_base / 8); ++ efx_writeo(efx, &temp, FR_AZ_SRM_TX_DC_CFG); ++ EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR, ++ efx->type->rx_dc_base / 8); ++ efx_writeo(efx, &temp, FR_AZ_SRM_RX_DC_CFG); ++ ++ /* Set TX descriptor cache size. */ ++ BUILD_BUG_ON(TX_DC_ENTRIES != (8 << TX_DC_ENTRIES_ORDER)); ++ EFX_POPULATE_OWORD_1(temp, FRF_AZ_TX_DC_SIZE, TX_DC_ENTRIES_ORDER); ++ efx_writeo(efx, &temp, FR_AZ_TX_DC_CFG); ++ ++ /* Set RX descriptor cache size. Set low watermark to size-8, as ++ * this allows most efficient prefetching. ++ */ ++ BUILD_BUG_ON(RX_DC_ENTRIES != (8 << RX_DC_ENTRIES_ORDER)); ++ EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_SIZE, RX_DC_ENTRIES_ORDER); ++ efx_writeo(efx, &temp, FR_AZ_RX_DC_CFG); ++ EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_PF_LWM, RX_DC_ENTRIES - 8); ++ efx_writeo(efx, &temp, FR_AZ_RX_DC_PF_WM); ++ ++ /* Program INT_KER address */ ++ EFX_POPULATE_OWORD_2(temp, ++ FRF_AZ_NORM_INT_VEC_DIS_KER, ++ EFX_INT_MODE_USE_MSI(efx), ++ FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr); ++ efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER); ++ ++ /* Enable all the genuinely fatal interrupts. (They are still ++ * masked by the overall interrupt mask, controlled by ++ * falcon_interrupts()). ++ * ++ * Note: All other fatal interrupts are enabled ++ */ ++ EFX_POPULATE_OWORD_3(temp, ++ FRF_AZ_ILL_ADR_INT_KER_EN, 1, ++ FRF_AZ_RBUF_OWN_INT_KER_EN, 1, ++ FRF_AZ_TBUF_OWN_INT_KER_EN, 1); ++ EFX_INVERT_OWORD(temp); ++ efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER); ++ ++ efx_setup_rss_indir_table(efx); ++ ++ /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be ++ * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q. ++ */ ++ efx_reado(efx, &temp, FR_AZ_TX_RESERVED); ++ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe); ++ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1); ++ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1); ++ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0); ++ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1); ++ /* Enable SW_EV to inherit in char driver - assume harmless here */ ++ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1); ++ /* Prefetch threshold 2 => fetch when descriptor cache half empty */ ++ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2); ++ /* Squash TX of packets of 16 bytes or less */ ++ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ++ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); ++ efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); ++} +diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h +new file mode 100644 +index 0000000..9351c03 +--- /dev/null ++++ b/drivers/net/sfc/nic.h +@@ -0,0 +1,261 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2005-2006 Fen Systems Ltd. ++ * Copyright 2006-2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++#ifndef EFX_NIC_H ++#define EFX_NIC_H ++ ++#include ++#include "net_driver.h" ++#include "efx.h" ++#include "mcdi.h" ++ ++/* ++ * Falcon hardware control ++ */ ++ ++enum { ++ EFX_REV_FALCON_A0 = 0, ++ EFX_REV_FALCON_A1 = 1, ++ EFX_REV_FALCON_B0 = 2, ++ EFX_REV_SIENA_A0 = 3, ++}; ++ ++static inline int efx_nic_rev(struct efx_nic *efx) ++{ ++ return efx->type->revision; ++} ++ ++extern u32 efx_nic_fpga_ver(struct efx_nic *efx); ++ ++static inline bool efx_nic_has_mc(struct efx_nic *efx) ++{ ++ return efx_nic_rev(efx) >= EFX_REV_SIENA_A0; ++} ++/* NIC has two interlinked PCI functions for the same port. */ ++static inline bool efx_nic_is_dual_func(struct efx_nic *efx) ++{ ++ return efx_nic_rev(efx) < EFX_REV_FALCON_B0; ++} ++ ++enum { ++ PHY_TYPE_NONE = 0, ++ PHY_TYPE_TXC43128 = 1, ++ PHY_TYPE_88E1111 = 2, ++ PHY_TYPE_SFX7101 = 3, ++ PHY_TYPE_QT2022C2 = 4, ++ PHY_TYPE_PM8358 = 6, ++ PHY_TYPE_SFT9001A = 8, ++ PHY_TYPE_QT2025C = 9, ++ PHY_TYPE_SFT9001B = 10, ++}; ++ ++#define FALCON_XMAC_LOOPBACKS \ ++ ((1 << LOOPBACK_XGMII) | \ ++ (1 << LOOPBACK_XGXS) | \ ++ (1 << LOOPBACK_XAUI)) ++ ++#define FALCON_GMAC_LOOPBACKS \ ++ (1 << LOOPBACK_GMAC) ++ ++/** ++ * struct falcon_board_type - board operations and type information ++ * @id: Board type id, as found in NVRAM ++ * @ref_model: Model number of Solarflare reference design ++ * @gen_type: Generic board type description ++ * @init: Allocate resources and initialise peripheral hardware ++ * @init_phy: Do board-specific PHY initialisation ++ * @fini: Shut down hardware and free resources ++ * @set_id_led: Set state of identifying LED or revert to automatic function ++ * @monitor: Board-specific health check function ++ */ ++struct falcon_board_type { ++ u8 id; ++ const char *ref_model; ++ const char *gen_type; ++ int (*init) (struct efx_nic *nic); ++ void (*init_phy) (struct efx_nic *efx); ++ void (*fini) (struct efx_nic *nic); ++ void (*set_id_led) (struct efx_nic *efx, enum efx_led_mode mode); ++ int (*monitor) (struct efx_nic *nic); ++}; ++ ++/** ++ * struct falcon_board - board information ++ * @type: Type of board ++ * @major: Major rev. ('A', 'B' ...) ++ * @minor: Minor rev. (0, 1, ...) ++ * @i2c_adap: I2C adapter for on-board peripherals ++ * @i2c_data: Data for bit-banging algorithm ++ * @hwmon_client: I2C client for hardware monitor ++ * @ioexp_client: I2C client for power/port control ++ */ ++struct falcon_board { ++ const struct falcon_board_type *type; ++ int major; ++ int minor; ++ struct i2c_adapter i2c_adap; ++ struct i2c_algo_bit_data i2c_data; ++ struct i2c_client *hwmon_client, *ioexp_client; ++}; ++ ++/** ++ * struct falcon_nic_data - Falcon NIC state ++ * @pci_dev2: Secondary function of Falcon A ++ * @board: Board state and functions ++ * @stats_disable_count: Nest count for disabling statistics fetches ++ * @stats_pending: Is there a pending DMA of MAC statistics. ++ * @stats_timer: A timer for regularly fetching MAC statistics. ++ * @stats_dma_done: Pointer to the flag which indicates DMA completion. ++ */ ++struct falcon_nic_data { ++ struct pci_dev *pci_dev2; ++ struct falcon_board board; ++ unsigned int stats_disable_count; ++ bool stats_pending; ++ struct timer_list stats_timer; ++ u32 *stats_dma_done; ++}; ++ ++static inline struct falcon_board *falcon_board(struct efx_nic *efx) ++{ ++ struct falcon_nic_data *data = efx->nic_data; ++ return &data->board; ++} ++ ++/** ++ * struct siena_nic_data - Siena NIC state ++ * @fw_version: Management controller firmware version ++ * @fw_build: Firmware build number ++ * @mcdi: Management-Controller-to-Driver Interface ++ * @wol_filter_id: Wake-on-LAN packet filter id ++ */ ++struct siena_nic_data { ++ u64 fw_version; ++ u32 fw_build; ++ struct efx_mcdi_iface mcdi; ++ int wol_filter_id; ++}; ++ ++extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len); ++ ++extern struct efx_nic_type falcon_a1_nic_type; ++extern struct efx_nic_type falcon_b0_nic_type; ++extern struct efx_nic_type siena_a0_nic_type; ++ ++/************************************************************************** ++ * ++ * Externs ++ * ++ ************************************************************************** ++ */ ++ ++extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info); ++ ++/* TX data path */ ++extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue); ++extern void efx_nic_init_tx(struct efx_tx_queue *tx_queue); ++extern void efx_nic_fini_tx(struct efx_tx_queue *tx_queue); ++extern void efx_nic_remove_tx(struct efx_tx_queue *tx_queue); ++extern void efx_nic_push_buffers(struct efx_tx_queue *tx_queue); ++ ++/* RX data path */ ++extern int efx_nic_probe_rx(struct efx_rx_queue *rx_queue); ++extern void efx_nic_init_rx(struct efx_rx_queue *rx_queue); ++extern void efx_nic_fini_rx(struct efx_rx_queue *rx_queue); ++extern void efx_nic_remove_rx(struct efx_rx_queue *rx_queue); ++extern void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue); ++ ++/* Event data path */ ++extern int efx_nic_probe_eventq(struct efx_channel *channel); ++extern void efx_nic_init_eventq(struct efx_channel *channel); ++extern void efx_nic_fini_eventq(struct efx_channel *channel); ++extern void efx_nic_remove_eventq(struct efx_channel *channel); ++extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota); ++extern void efx_nic_eventq_read_ack(struct efx_channel *channel); ++ ++/* MAC/PHY */ ++extern void falcon_drain_tx_fifo(struct efx_nic *efx); ++extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); ++extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh; ++ ++/* Interrupts and test events */ ++extern int efx_nic_init_interrupt(struct efx_nic *efx); ++extern void efx_nic_enable_interrupts(struct efx_nic *efx); ++extern void efx_nic_generate_test_event(struct efx_channel *channel, ++ unsigned int magic); ++extern void efx_nic_generate_interrupt(struct efx_nic *efx); ++extern void efx_nic_disable_interrupts(struct efx_nic *efx); ++extern void efx_nic_fini_interrupt(struct efx_nic *efx); ++extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx); ++extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); ++extern void falcon_irq_ack_a1(struct efx_nic *efx); ++ ++#define EFX_IRQ_MOD_RESOLUTION 5 ++ ++/* Global Resources */ ++extern int efx_nic_flush_queues(struct efx_nic *efx); ++extern void falcon_start_nic_stats(struct efx_nic *efx); ++extern void falcon_stop_nic_stats(struct efx_nic *efx); ++extern int falcon_reset_xaui(struct efx_nic *efx); ++extern void efx_nic_init_common(struct efx_nic *efx); ++ ++int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, ++ unsigned int len); ++void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer); ++ ++/* Tests */ ++struct efx_nic_register_test { ++ unsigned address; ++ efx_oword_t mask; ++}; ++extern int efx_nic_test_registers(struct efx_nic *efx, ++ const struct efx_nic_register_test *regs, ++ size_t n_regs); ++ ++/************************************************************************** ++ * ++ * Falcon MAC stats ++ * ++ ************************************************************************** ++ */ ++ ++#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset) ++#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH) ++ ++/* Retrieve statistic from statistics block */ ++#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \ ++ if (FALCON_STAT_WIDTH(falcon_stat) == 16) \ ++ (efx)->mac_stats.efx_stat += le16_to_cpu( \ ++ *((__force __le16 *) \ ++ (efx->stats_buffer.addr + \ ++ FALCON_STAT_OFFSET(falcon_stat)))); \ ++ else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \ ++ (efx)->mac_stats.efx_stat += le32_to_cpu( \ ++ *((__force __le32 *) \ ++ (efx->stats_buffer.addr + \ ++ FALCON_STAT_OFFSET(falcon_stat)))); \ ++ else \ ++ (efx)->mac_stats.efx_stat += le64_to_cpu( \ ++ *((__force __le64 *) \ ++ (efx->stats_buffer.addr + \ ++ FALCON_STAT_OFFSET(falcon_stat)))); \ ++ } while (0) ++ ++#define FALCON_MAC_STATS_SIZE 0x100 ++ ++#define MAC_DATA_LBN 0 ++#define MAC_DATA_WIDTH 32 ++ ++extern void efx_nic_generate_event(struct efx_channel *channel, ++ efx_qword_t *event); ++ ++extern void falcon_poll_xmac(struct efx_nic *efx); ++ ++#endif /* EFX_NIC_H */ +diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h +index c1cff9c..5bc2613 100644 +--- a/drivers/net/sfc/phy.h ++++ b/drivers/net/sfc/phy.h +@@ -1,6 +1,6 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2007-2008 Solarflare Communications Inc. ++ * Copyright 2007-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -16,16 +16,16 @@ + extern struct efx_phy_operations falcon_sfx7101_phy_ops; + extern struct efx_phy_operations falcon_sft9001_phy_ops; + +-extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); ++extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); + + /* Wait for the PHY to boot. Return 0 on success, -EINVAL if the PHY failed + * to boot due to corrupt flash, or some other negative error code. */ + extern int sft9001_wait_boot(struct efx_nic *efx); + + /**************************************************************************** +- * AMCC/Quake QT20xx PHYs ++ * AMCC/Quake QT202x PHYs + */ +-extern struct efx_phy_operations falcon_xfp_phy_ops; ++extern struct efx_phy_operations falcon_qt202x_phy_ops; + + /* These PHYs provide various H/W control states for LEDs */ + #define QUAKE_LED_LINK_INVAL (0) +@@ -39,6 +39,23 @@ extern struct efx_phy_operations falcon_xfp_phy_ops; + #define QUAKE_LED_TXLINK (0) + #define QUAKE_LED_RXLINK (8) + +-extern void xfp_set_led(struct efx_nic *p, int led, int state); ++extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); ++ ++/**************************************************************************** ++ * Siena managed PHYs ++ */ ++extern struct efx_phy_operations efx_mcdi_phy_ops; ++ ++extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, ++ unsigned int prtad, unsigned int devad, ++ u16 addr, u16 *value_out, u32 *status_out); ++extern int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus, ++ unsigned int prtad, unsigned int devad, ++ u16 addr, u16 value, u32 *status_out); ++extern void efx_mcdi_phy_decode_link(struct efx_nic *efx, ++ struct efx_link_state *link_state, ++ u32 speed, u32 flags, u32 fcntl); ++extern int efx_mcdi_phy_reconfigure(struct efx_nic *efx); ++extern void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa); + + #endif +diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c +new file mode 100644 +index 0000000..3800fc7 +--- /dev/null ++++ b/drivers/net/sfc/qt202x_phy.c +@@ -0,0 +1,242 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2006-2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++/* ++ * Driver for AMCC QT202x SFP+ and XFP adapters; see www.amcc.com for details ++ */ ++ ++#include ++#include ++#include "efx.h" ++#include "mdio_10g.h" ++#include "phy.h" ++#include "nic.h" ++ ++#define QT202X_REQUIRED_DEVS (MDIO_DEVS_PCS | \ ++ MDIO_DEVS_PMAPMD | \ ++ MDIO_DEVS_PHYXS) ++ ++#define QT202X_LOOPBACKS ((1 << LOOPBACK_PCS) | \ ++ (1 << LOOPBACK_PMAPMD) | \ ++ (1 << LOOPBACK_PHYXS_WS)) ++ ++/****************************************************************************/ ++/* Quake-specific MDIO registers */ ++#define MDIO_QUAKE_LED0_REG (0xD006) ++ ++/* QT2025C only */ ++#define PCS_FW_HEARTBEAT_REG 0xd7ee ++#define PCS_FW_HEARTB_LBN 0 ++#define PCS_FW_HEARTB_WIDTH 8 ++#define PCS_UC8051_STATUS_REG 0xd7fd ++#define PCS_UC_STATUS_LBN 0 ++#define PCS_UC_STATUS_WIDTH 8 ++#define PCS_UC_STATUS_FW_SAVE 0x20 ++#define PMA_PMD_FTX_CTRL2_REG 0xc309 ++#define PMA_PMD_FTX_STATIC_LBN 13 ++#define PMA_PMD_VEND1_REG 0xc001 ++#define PMA_PMD_VEND1_LBTXD_LBN 15 ++#define PCS_VEND1_REG 0xc000 ++#define PCS_VEND1_LBTXD_LBN 5 ++ ++void falcon_qt202x_set_led(struct efx_nic *p, int led, int mode) ++{ ++ int addr = MDIO_QUAKE_LED0_REG + led; ++ efx_mdio_write(p, MDIO_MMD_PMAPMD, addr, mode); ++} ++ ++struct qt202x_phy_data { ++ enum efx_phy_mode phy_mode; ++}; ++ ++#define QT2022C2_MAX_RESET_TIME 500 ++#define QT2022C2_RESET_WAIT 10 ++ ++static int qt2025c_wait_reset(struct efx_nic *efx) ++{ ++ unsigned long timeout = jiffies + 10 * HZ; ++ int reg, old_counter = 0; ++ ++ /* Wait for firmware heartbeat to start */ ++ for (;;) { ++ int counter; ++ reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_FW_HEARTBEAT_REG); ++ if (reg < 0) ++ return reg; ++ counter = ((reg >> PCS_FW_HEARTB_LBN) & ++ ((1 << PCS_FW_HEARTB_WIDTH) - 1)); ++ if (old_counter == 0) ++ old_counter = counter; ++ else if (counter != old_counter) ++ break; ++ if (time_after(jiffies, timeout)) ++ return -ETIMEDOUT; ++ msleep(10); ++ } ++ ++ /* Wait for firmware status to look good */ ++ for (;;) { ++ reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG); ++ if (reg < 0) ++ return reg; ++ if ((reg & ++ ((1 << PCS_UC_STATUS_WIDTH) - 1) << PCS_UC_STATUS_LBN) >= ++ PCS_UC_STATUS_FW_SAVE) ++ break; ++ if (time_after(jiffies, timeout)) ++ return -ETIMEDOUT; ++ msleep(100); ++ } ++ ++ return 0; ++} ++ ++static int qt202x_reset_phy(struct efx_nic *efx) ++{ ++ int rc; ++ ++ if (efx->phy_type == PHY_TYPE_QT2025C) { ++ /* Wait for the reset triggered by falcon_reset_hw() ++ * to complete */ ++ rc = qt2025c_wait_reset(efx); ++ if (rc < 0) ++ goto fail; ++ } else { ++ /* Reset the PHYXS MMD. This is documented as doing ++ * a complete soft reset. */ ++ rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS, ++ QT2022C2_MAX_RESET_TIME / ++ QT2022C2_RESET_WAIT, ++ QT2022C2_RESET_WAIT); ++ if (rc < 0) ++ goto fail; ++ } ++ ++ /* Wait 250ms for the PHY to complete bootup */ ++ msleep(250); ++ ++ /* Check that all the MMDs we expect are present and responding. We ++ * expect faults on some if the link is down, but not on the PHY XS */ ++ rc = efx_mdio_check_mmds(efx, QT202X_REQUIRED_DEVS, MDIO_DEVS_PHYXS); ++ if (rc < 0) ++ goto fail; ++ ++ falcon_board(efx)->type->init_phy(efx); ++ ++ return rc; ++ ++ fail: ++ EFX_ERR(efx, "PHY reset timed out\n"); ++ return rc; ++} ++ ++static int qt202x_phy_probe(struct efx_nic *efx) ++{ ++ efx->mdio.mmds = QT202X_REQUIRED_DEVS; ++ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; ++ efx->loopback_modes = QT202X_LOOPBACKS | FALCON_XMAC_LOOPBACKS; ++ return 0; ++} ++ ++static int qt202x_phy_init(struct efx_nic *efx) ++{ ++ struct qt202x_phy_data *phy_data; ++ u32 devid; ++ int rc; ++ ++ rc = qt202x_reset_phy(efx); ++ if (rc) { ++ EFX_ERR(efx, "PHY init failed\n"); ++ return rc; ++ } ++ ++ phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL); ++ if (!phy_data) ++ return -ENOMEM; ++ efx->phy_data = phy_data; ++ ++ devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); ++ EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n", ++ devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), ++ efx_mdio_id_rev(devid)); ++ ++ phy_data->phy_mode = efx->phy_mode; ++ return 0; ++} ++ ++static int qt202x_link_ok(struct efx_nic *efx) ++{ ++ return efx_mdio_links_ok(efx, QT202X_REQUIRED_DEVS); ++} ++ ++static bool qt202x_phy_poll(struct efx_nic *efx) ++{ ++ bool was_up = efx->link_state.up; ++ ++ efx->link_state.up = qt202x_link_ok(efx); ++ efx->link_state.speed = 10000; ++ efx->link_state.fd = true; ++ efx->link_state.fc = efx->wanted_fc; ++ ++ return efx->link_state.up != was_up; ++} ++ ++static int qt202x_phy_reconfigure(struct efx_nic *efx) ++{ ++ struct qt202x_phy_data *phy_data = efx->phy_data; ++ ++ if (efx->phy_type == PHY_TYPE_QT2025C) { ++ /* There are several different register bits which can ++ * disable TX (and save power) on direct-attach cables ++ * or optical transceivers, varying somewhat between ++ * firmware versions. Only 'static mode' appears to ++ * cover everything. */ ++ mdio_set_flag( ++ &efx->mdio, efx->mdio.prtad, MDIO_MMD_PMAPMD, ++ PMA_PMD_FTX_CTRL2_REG, 1 << PMA_PMD_FTX_STATIC_LBN, ++ efx->phy_mode & PHY_MODE_TX_DISABLED || ++ efx->phy_mode & PHY_MODE_LOW_POWER || ++ efx->loopback_mode == LOOPBACK_PCS || ++ efx->loopback_mode == LOOPBACK_PMAPMD); ++ } else { ++ /* Reset the PHY when moving from tx off to tx on */ ++ if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) && ++ (phy_data->phy_mode & PHY_MODE_TX_DISABLED)) ++ qt202x_reset_phy(efx); ++ ++ efx_mdio_transmit_disable(efx); ++ } ++ ++ efx_mdio_phy_reconfigure(efx); ++ ++ phy_data->phy_mode = efx->phy_mode; ++ ++ return 0; ++} ++ ++static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) ++{ ++ mdio45_ethtool_gset(&efx->mdio, ecmd); ++} ++ ++static void qt202x_phy_fini(struct efx_nic *efx) ++{ ++ /* Free the context block */ ++ kfree(efx->phy_data); ++ efx->phy_data = NULL; ++} ++ ++struct efx_phy_operations falcon_qt202x_phy_ops = { ++ .probe = qt202x_phy_probe, ++ .init = qt202x_phy_init, ++ .reconfigure = qt202x_phy_reconfigure, ++ .poll = qt202x_phy_poll, ++ .fini = qt202x_phy_fini, ++ .get_settings = qt202x_phy_get_settings, ++ .set_settings = efx_mdio_set_settings, ++}; +diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h +new file mode 100644 +index 0000000..89d606f +--- /dev/null ++++ b/drivers/net/sfc/regs.h +@@ -0,0 +1,3168 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2005-2006 Fen Systems Ltd. ++ * Copyright 2006-2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++#ifndef EFX_REGS_H ++#define EFX_REGS_H ++ ++/* ++ * Falcon hardware architecture definitions have a name prefix following ++ * the format: ++ * ++ * F__ ++ * ++ * The following strings are used: ++ * ++ * MMIO register MC register Host memory structure ++ * ------------------------------------------------------------- ++ * Address R MCR ++ * Bitfield RF MCRF SF ++ * Enumerator FE MCFE SE ++ * ++ * is the first revision to which the definition applies: ++ * ++ * A: Falcon A1 (SFC4000AB) ++ * B: Falcon B0 (SFC4000BA) ++ * C: Siena A0 (SFL9021AA) ++ * ++ * If the definition has been changed or removed in later revisions ++ * then is the last revision to which the definition applies; ++ * otherwise it is "Z". ++ */ ++ ++/************************************************************************** ++ * ++ * Falcon/Siena registers and descriptors ++ * ++ ************************************************************************** ++ */ ++ ++/* ADR_REGION_REG: Address region register */ ++#define FR_AZ_ADR_REGION 0x00000000 ++#define FRF_AZ_ADR_REGION3_LBN 96 ++#define FRF_AZ_ADR_REGION3_WIDTH 18 ++#define FRF_AZ_ADR_REGION2_LBN 64 ++#define FRF_AZ_ADR_REGION2_WIDTH 18 ++#define FRF_AZ_ADR_REGION1_LBN 32 ++#define FRF_AZ_ADR_REGION1_WIDTH 18 ++#define FRF_AZ_ADR_REGION0_LBN 0 ++#define FRF_AZ_ADR_REGION0_WIDTH 18 ++ ++/* INT_EN_REG_KER: Kernel driver Interrupt enable register */ ++#define FR_AZ_INT_EN_KER 0x00000010 ++#define FRF_AZ_KER_INT_LEVE_SEL_LBN 8 ++#define FRF_AZ_KER_INT_LEVE_SEL_WIDTH 6 ++#define FRF_AZ_KER_INT_CHAR_LBN 4 ++#define FRF_AZ_KER_INT_CHAR_WIDTH 1 ++#define FRF_AZ_KER_INT_KER_LBN 3 ++#define FRF_AZ_KER_INT_KER_WIDTH 1 ++#define FRF_AZ_DRV_INT_EN_KER_LBN 0 ++#define FRF_AZ_DRV_INT_EN_KER_WIDTH 1 ++ ++/* INT_EN_REG_CHAR: Char Driver interrupt enable register */ ++#define FR_BZ_INT_EN_CHAR 0x00000020 ++#define FRF_BZ_CHAR_INT_LEVE_SEL_LBN 8 ++#define FRF_BZ_CHAR_INT_LEVE_SEL_WIDTH 6 ++#define FRF_BZ_CHAR_INT_CHAR_LBN 4 ++#define FRF_BZ_CHAR_INT_CHAR_WIDTH 1 ++#define FRF_BZ_CHAR_INT_KER_LBN 3 ++#define FRF_BZ_CHAR_INT_KER_WIDTH 1 ++#define FRF_BZ_DRV_INT_EN_CHAR_LBN 0 ++#define FRF_BZ_DRV_INT_EN_CHAR_WIDTH 1 ++ ++/* INT_ADR_REG_KER: Interrupt host address for Kernel driver */ ++#define FR_AZ_INT_ADR_KER 0x00000030 ++#define FRF_AZ_NORM_INT_VEC_DIS_KER_LBN 64 ++#define FRF_AZ_NORM_INT_VEC_DIS_KER_WIDTH 1 ++#define FRF_AZ_INT_ADR_KER_LBN 0 ++#define FRF_AZ_INT_ADR_KER_WIDTH 64 ++ ++/* INT_ADR_REG_CHAR: Interrupt host address for Char driver */ ++#define FR_BZ_INT_ADR_CHAR 0x00000040 ++#define FRF_BZ_NORM_INT_VEC_DIS_CHAR_LBN 64 ++#define FRF_BZ_NORM_INT_VEC_DIS_CHAR_WIDTH 1 ++#define FRF_BZ_INT_ADR_CHAR_LBN 0 ++#define FRF_BZ_INT_ADR_CHAR_WIDTH 64 ++ ++/* INT_ACK_KER: Kernel interrupt acknowledge register */ ++#define FR_AA_INT_ACK_KER 0x00000050 ++#define FRF_AA_INT_ACK_KER_FIELD_LBN 0 ++#define FRF_AA_INT_ACK_KER_FIELD_WIDTH 32 ++ ++/* INT_ISR0_REG: Function 0 Interrupt Acknowlege Status register */ ++#define FR_BZ_INT_ISR0 0x00000090 ++#define FRF_BZ_INT_ISR_REG_LBN 0 ++#define FRF_BZ_INT_ISR_REG_WIDTH 64 ++ ++/* HW_INIT_REG: Hardware initialization register */ ++#define FR_AZ_HW_INIT 0x000000c0 ++#define FRF_BB_BDMRD_CPLF_FULL_LBN 124 ++#define FRF_BB_BDMRD_CPLF_FULL_WIDTH 1 ++#define FRF_BB_PCIE_CPL_TIMEOUT_CTRL_LBN 121 ++#define FRF_BB_PCIE_CPL_TIMEOUT_CTRL_WIDTH 3 ++#define FRF_CZ_TX_MRG_TAGS_LBN 120 ++#define FRF_CZ_TX_MRG_TAGS_WIDTH 1 ++#define FRF_AB_TRGT_MASK_ALL_LBN 100 ++#define FRF_AB_TRGT_MASK_ALL_WIDTH 1 ++#define FRF_AZ_DOORBELL_DROP_LBN 92 ++#define FRF_AZ_DOORBELL_DROP_WIDTH 8 ++#define FRF_AB_TX_RREQ_MASK_EN_LBN 76 ++#define FRF_AB_TX_RREQ_MASK_EN_WIDTH 1 ++#define FRF_AB_PE_EIDLE_DIS_LBN 75 ++#define FRF_AB_PE_EIDLE_DIS_WIDTH 1 ++#define FRF_AA_FC_BLOCKING_EN_LBN 45 ++#define FRF_AA_FC_BLOCKING_EN_WIDTH 1 ++#define FRF_BZ_B2B_REQ_EN_LBN 45 ++#define FRF_BZ_B2B_REQ_EN_WIDTH 1 ++#define FRF_AA_B2B_REQ_EN_LBN 44 ++#define FRF_AA_B2B_REQ_EN_WIDTH 1 ++#define FRF_BB_FC_BLOCKING_EN_LBN 44 ++#define FRF_BB_FC_BLOCKING_EN_WIDTH 1 ++#define FRF_AZ_POST_WR_MASK_LBN 40 ++#define FRF_AZ_POST_WR_MASK_WIDTH 4 ++#define FRF_AZ_TLP_TC_LBN 34 ++#define FRF_AZ_TLP_TC_WIDTH 3 ++#define FRF_AZ_TLP_ATTR_LBN 32 ++#define FRF_AZ_TLP_ATTR_WIDTH 2 ++#define FRF_AB_INTB_VEC_LBN 24 ++#define FRF_AB_INTB_VEC_WIDTH 5 ++#define FRF_AB_INTA_VEC_LBN 16 ++#define FRF_AB_INTA_VEC_WIDTH 5 ++#define FRF_AZ_WD_TIMER_LBN 8 ++#define FRF_AZ_WD_TIMER_WIDTH 8 ++#define FRF_AZ_US_DISABLE_LBN 5 ++#define FRF_AZ_US_DISABLE_WIDTH 1 ++#define FRF_AZ_TLP_EP_LBN 4 ++#define FRF_AZ_TLP_EP_WIDTH 1 ++#define FRF_AZ_ATTR_SEL_LBN 3 ++#define FRF_AZ_ATTR_SEL_WIDTH 1 ++#define FRF_AZ_TD_SEL_LBN 1 ++#define FRF_AZ_TD_SEL_WIDTH 1 ++#define FRF_AZ_TLP_TD_LBN 0 ++#define FRF_AZ_TLP_TD_WIDTH 1 ++ ++/* EE_SPI_HCMD_REG: SPI host command register */ ++#define FR_AB_EE_SPI_HCMD 0x00000100 ++#define FRF_AB_EE_SPI_HCMD_CMD_EN_LBN 31 ++#define FRF_AB_EE_SPI_HCMD_CMD_EN_WIDTH 1 ++#define FRF_AB_EE_WR_TIMER_ACTIVE_LBN 28 ++#define FRF_AB_EE_WR_TIMER_ACTIVE_WIDTH 1 ++#define FRF_AB_EE_SPI_HCMD_SF_SEL_LBN 24 ++#define FRF_AB_EE_SPI_HCMD_SF_SEL_WIDTH 1 ++#define FRF_AB_EE_SPI_HCMD_DABCNT_LBN 16 ++#define FRF_AB_EE_SPI_HCMD_DABCNT_WIDTH 5 ++#define FRF_AB_EE_SPI_HCMD_READ_LBN 15 ++#define FRF_AB_EE_SPI_HCMD_READ_WIDTH 1 ++#define FRF_AB_EE_SPI_HCMD_DUBCNT_LBN 12 ++#define FRF_AB_EE_SPI_HCMD_DUBCNT_WIDTH 2 ++#define FRF_AB_EE_SPI_HCMD_ADBCNT_LBN 8 ++#define FRF_AB_EE_SPI_HCMD_ADBCNT_WIDTH 2 ++#define FRF_AB_EE_SPI_HCMD_ENC_LBN 0 ++#define FRF_AB_EE_SPI_HCMD_ENC_WIDTH 8 ++ ++/* USR_EV_CFG: User Level Event Configuration register */ ++#define FR_CZ_USR_EV_CFG 0x00000100 ++#define FRF_CZ_USREV_DIS_LBN 16 ++#define FRF_CZ_USREV_DIS_WIDTH 1 ++#define FRF_CZ_DFLT_EVQ_LBN 0 ++#define FRF_CZ_DFLT_EVQ_WIDTH 10 ++ ++/* EE_SPI_HADR_REG: SPI host address register */ ++#define FR_AB_EE_SPI_HADR 0x00000110 ++#define FRF_AB_EE_SPI_HADR_DUBYTE_LBN 24 ++#define FRF_AB_EE_SPI_HADR_DUBYTE_WIDTH 8 ++#define FRF_AB_EE_SPI_HADR_ADR_LBN 0 ++#define FRF_AB_EE_SPI_HADR_ADR_WIDTH 24 ++ ++/* EE_SPI_HDATA_REG: SPI host data register */ ++#define FR_AB_EE_SPI_HDATA 0x00000120 ++#define FRF_AB_EE_SPI_HDATA3_LBN 96 ++#define FRF_AB_EE_SPI_HDATA3_WIDTH 32 ++#define FRF_AB_EE_SPI_HDATA2_LBN 64 ++#define FRF_AB_EE_SPI_HDATA2_WIDTH 32 ++#define FRF_AB_EE_SPI_HDATA1_LBN 32 ++#define FRF_AB_EE_SPI_HDATA1_WIDTH 32 ++#define FRF_AB_EE_SPI_HDATA0_LBN 0 ++#define FRF_AB_EE_SPI_HDATA0_WIDTH 32 ++ ++/* EE_BASE_PAGE_REG: Expansion ROM base mirror register */ ++#define FR_AB_EE_BASE_PAGE 0x00000130 ++#define FRF_AB_EE_EXPROM_MASK_LBN 16 ++#define FRF_AB_EE_EXPROM_MASK_WIDTH 13 ++#define FRF_AB_EE_EXP_ROM_WINDOW_BASE_LBN 0 ++#define FRF_AB_EE_EXP_ROM_WINDOW_BASE_WIDTH 13 ++ ++/* EE_VPD_CFG0_REG: SPI/VPD configuration register 0 */ ++#define FR_AB_EE_VPD_CFG0 0x00000140 ++#define FRF_AB_EE_SF_FASTRD_EN_LBN 127 ++#define FRF_AB_EE_SF_FASTRD_EN_WIDTH 1 ++#define FRF_AB_EE_SF_CLOCK_DIV_LBN 120 ++#define FRF_AB_EE_SF_CLOCK_DIV_WIDTH 7 ++#define FRF_AB_EE_VPD_WIP_POLL_LBN 119 ++#define FRF_AB_EE_VPD_WIP_POLL_WIDTH 1 ++#define FRF_AB_EE_EE_CLOCK_DIV_LBN 112 ++#define FRF_AB_EE_EE_CLOCK_DIV_WIDTH 7 ++#define FRF_AB_EE_EE_WR_TMR_VALUE_LBN 96 ++#define FRF_AB_EE_EE_WR_TMR_VALUE_WIDTH 16 ++#define FRF_AB_EE_VPDW_LENGTH_LBN 80 ++#define FRF_AB_EE_VPDW_LENGTH_WIDTH 15 ++#define FRF_AB_EE_VPDW_BASE_LBN 64 ++#define FRF_AB_EE_VPDW_BASE_WIDTH 15 ++#define FRF_AB_EE_VPD_WR_CMD_EN_LBN 56 ++#define FRF_AB_EE_VPD_WR_CMD_EN_WIDTH 8 ++#define FRF_AB_EE_VPD_BASE_LBN 32 ++#define FRF_AB_EE_VPD_BASE_WIDTH 24 ++#define FRF_AB_EE_VPD_LENGTH_LBN 16 ++#define FRF_AB_EE_VPD_LENGTH_WIDTH 15 ++#define FRF_AB_EE_VPD_AD_SIZE_LBN 8 ++#define FRF_AB_EE_VPD_AD_SIZE_WIDTH 5 ++#define FRF_AB_EE_VPD_ACCESS_ON_LBN 5 ++#define FRF_AB_EE_VPD_ACCESS_ON_WIDTH 1 ++#define FRF_AB_EE_VPD_ACCESS_BLOCK_LBN 4 ++#define FRF_AB_EE_VPD_ACCESS_BLOCK_WIDTH 1 ++#define FRF_AB_EE_VPD_DEV_SF_SEL_LBN 2 ++#define FRF_AB_EE_VPD_DEV_SF_SEL_WIDTH 1 ++#define FRF_AB_EE_VPD_EN_AD9_MODE_LBN 1 ++#define FRF_AB_EE_VPD_EN_AD9_MODE_WIDTH 1 ++#define FRF_AB_EE_VPD_EN_LBN 0 ++#define FRF_AB_EE_VPD_EN_WIDTH 1 ++ ++/* EE_VPD_SW_CNTL_REG: VPD access SW control register */ ++#define FR_AB_EE_VPD_SW_CNTL 0x00000150 ++#define FRF_AB_EE_VPD_CYCLE_PENDING_LBN 31 ++#define FRF_AB_EE_VPD_CYCLE_PENDING_WIDTH 1 ++#define FRF_AB_EE_VPD_CYC_WRITE_LBN 28 ++#define FRF_AB_EE_VPD_CYC_WRITE_WIDTH 1 ++#define FRF_AB_EE_VPD_CYC_ADR_LBN 0 ++#define FRF_AB_EE_VPD_CYC_ADR_WIDTH 15 ++ ++/* EE_VPD_SW_DATA_REG: VPD access SW data register */ ++#define FR_AB_EE_VPD_SW_DATA 0x00000160 ++#define FRF_AB_EE_VPD_CYC_DAT_LBN 0 ++#define FRF_AB_EE_VPD_CYC_DAT_WIDTH 32 ++ ++/* PBMX_DBG_IADDR_REG: Capture Module address register */ ++#define FR_CZ_PBMX_DBG_IADDR 0x000001f0 ++#define FRF_CZ_PBMX_DBG_IADDR_LBN 0 ++#define FRF_CZ_PBMX_DBG_IADDR_WIDTH 32 ++ ++/* PCIE_CORE_INDIRECT_REG: Indirect Access to PCIE Core registers */ ++#define FR_BB_PCIE_CORE_INDIRECT 0x000001f0 ++#define FRF_BB_PCIE_CORE_TARGET_DATA_LBN 32 ++#define FRF_BB_PCIE_CORE_TARGET_DATA_WIDTH 32 ++#define FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_LBN 15 ++#define FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_WIDTH 1 ++#define FRF_BB_PCIE_CORE_TARGET_REG_ADRS_LBN 0 ++#define FRF_BB_PCIE_CORE_TARGET_REG_ADRS_WIDTH 12 ++ ++/* PBMX_DBG_IDATA_REG: Capture Module data register */ ++#define FR_CZ_PBMX_DBG_IDATA 0x000001f8 ++#define FRF_CZ_PBMX_DBG_IDATA_LBN 0 ++#define FRF_CZ_PBMX_DBG_IDATA_WIDTH 64 ++ ++/* NIC_STAT_REG: NIC status register */ ++#define FR_AB_NIC_STAT 0x00000200 ++#define FRF_BB_AER_DIS_LBN 34 ++#define FRF_BB_AER_DIS_WIDTH 1 ++#define FRF_BB_EE_STRAP_EN_LBN 31 ++#define FRF_BB_EE_STRAP_EN_WIDTH 1 ++#define FRF_BB_EE_STRAP_LBN 24 ++#define FRF_BB_EE_STRAP_WIDTH 4 ++#define FRF_BB_REVISION_ID_LBN 17 ++#define FRF_BB_REVISION_ID_WIDTH 7 ++#define FRF_AB_ONCHIP_SRAM_LBN 16 ++#define FRF_AB_ONCHIP_SRAM_WIDTH 1 ++#define FRF_AB_SF_PRST_LBN 9 ++#define FRF_AB_SF_PRST_WIDTH 1 ++#define FRF_AB_EE_PRST_LBN 8 ++#define FRF_AB_EE_PRST_WIDTH 1 ++#define FRF_AB_ATE_MODE_LBN 3 ++#define FRF_AB_ATE_MODE_WIDTH 1 ++#define FRF_AB_STRAP_PINS_LBN 0 ++#define FRF_AB_STRAP_PINS_WIDTH 3 ++ ++/* GPIO_CTL_REG: GPIO control register */ ++#define FR_AB_GPIO_CTL 0x00000210 ++#define FRF_AB_GPIO_OUT3_LBN 112 ++#define FRF_AB_GPIO_OUT3_WIDTH 16 ++#define FRF_AB_GPIO_IN3_LBN 104 ++#define FRF_AB_GPIO_IN3_WIDTH 8 ++#define FRF_AB_GPIO_PWRUP_VALUE3_LBN 96 ++#define FRF_AB_GPIO_PWRUP_VALUE3_WIDTH 8 ++#define FRF_AB_GPIO_OUT2_LBN 80 ++#define FRF_AB_GPIO_OUT2_WIDTH 16 ++#define FRF_AB_GPIO_IN2_LBN 72 ++#define FRF_AB_GPIO_IN2_WIDTH 8 ++#define FRF_AB_GPIO_PWRUP_VALUE2_LBN 64 ++#define FRF_AB_GPIO_PWRUP_VALUE2_WIDTH 8 ++#define FRF_AB_GPIO15_OEN_LBN 63 ++#define FRF_AB_GPIO15_OEN_WIDTH 1 ++#define FRF_AB_GPIO14_OEN_LBN 62 ++#define FRF_AB_GPIO14_OEN_WIDTH 1 ++#define FRF_AB_GPIO13_OEN_LBN 61 ++#define FRF_AB_GPIO13_OEN_WIDTH 1 ++#define FRF_AB_GPIO12_OEN_LBN 60 ++#define FRF_AB_GPIO12_OEN_WIDTH 1 ++#define FRF_AB_GPIO11_OEN_LBN 59 ++#define FRF_AB_GPIO11_OEN_WIDTH 1 ++#define FRF_AB_GPIO10_OEN_LBN 58 ++#define FRF_AB_GPIO10_OEN_WIDTH 1 ++#define FRF_AB_GPIO9_OEN_LBN 57 ++#define FRF_AB_GPIO9_OEN_WIDTH 1 ++#define FRF_AB_GPIO8_OEN_LBN 56 ++#define FRF_AB_GPIO8_OEN_WIDTH 1 ++#define FRF_AB_GPIO15_OUT_LBN 55 ++#define FRF_AB_GPIO15_OUT_WIDTH 1 ++#define FRF_AB_GPIO14_OUT_LBN 54 ++#define FRF_AB_GPIO14_OUT_WIDTH 1 ++#define FRF_AB_GPIO13_OUT_LBN 53 ++#define FRF_AB_GPIO13_OUT_WIDTH 1 ++#define FRF_AB_GPIO12_OUT_LBN 52 ++#define FRF_AB_GPIO12_OUT_WIDTH 1 ++#define FRF_AB_GPIO11_OUT_LBN 51 ++#define FRF_AB_GPIO11_OUT_WIDTH 1 ++#define FRF_AB_GPIO10_OUT_LBN 50 ++#define FRF_AB_GPIO10_OUT_WIDTH 1 ++#define FRF_AB_GPIO9_OUT_LBN 49 ++#define FRF_AB_GPIO9_OUT_WIDTH 1 ++#define FRF_AB_GPIO8_OUT_LBN 48 ++#define FRF_AB_GPIO8_OUT_WIDTH 1 ++#define FRF_AB_GPIO15_IN_LBN 47 ++#define FRF_AB_GPIO15_IN_WIDTH 1 ++#define FRF_AB_GPIO14_IN_LBN 46 ++#define FRF_AB_GPIO14_IN_WIDTH 1 ++#define FRF_AB_GPIO13_IN_LBN 45 ++#define FRF_AB_GPIO13_IN_WIDTH 1 ++#define FRF_AB_GPIO12_IN_LBN 44 ++#define FRF_AB_GPIO12_IN_WIDTH 1 ++#define FRF_AB_GPIO11_IN_LBN 43 ++#define FRF_AB_GPIO11_IN_WIDTH 1 ++#define FRF_AB_GPIO10_IN_LBN 42 ++#define FRF_AB_GPIO10_IN_WIDTH 1 ++#define FRF_AB_GPIO9_IN_LBN 41 ++#define FRF_AB_GPIO9_IN_WIDTH 1 ++#define FRF_AB_GPIO8_IN_LBN 40 ++#define FRF_AB_GPIO8_IN_WIDTH 1 ++#define FRF_AB_GPIO15_PWRUP_VALUE_LBN 39 ++#define FRF_AB_GPIO15_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO14_PWRUP_VALUE_LBN 38 ++#define FRF_AB_GPIO14_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO13_PWRUP_VALUE_LBN 37 ++#define FRF_AB_GPIO13_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO12_PWRUP_VALUE_LBN 36 ++#define FRF_AB_GPIO12_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO11_PWRUP_VALUE_LBN 35 ++#define FRF_AB_GPIO11_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO10_PWRUP_VALUE_LBN 34 ++#define FRF_AB_GPIO10_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO9_PWRUP_VALUE_LBN 33 ++#define FRF_AB_GPIO9_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO8_PWRUP_VALUE_LBN 32 ++#define FRF_AB_GPIO8_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_CLK156_OUT_EN_LBN 31 ++#define FRF_AB_CLK156_OUT_EN_WIDTH 1 ++#define FRF_AB_USE_NIC_CLK_LBN 30 ++#define FRF_AB_USE_NIC_CLK_WIDTH 1 ++#define FRF_AB_GPIO5_OEN_LBN 29 ++#define FRF_AB_GPIO5_OEN_WIDTH 1 ++#define FRF_AB_GPIO4_OEN_LBN 28 ++#define FRF_AB_GPIO4_OEN_WIDTH 1 ++#define FRF_AB_GPIO3_OEN_LBN 27 ++#define FRF_AB_GPIO3_OEN_WIDTH 1 ++#define FRF_AB_GPIO2_OEN_LBN 26 ++#define FRF_AB_GPIO2_OEN_WIDTH 1 ++#define FRF_AB_GPIO1_OEN_LBN 25 ++#define FRF_AB_GPIO1_OEN_WIDTH 1 ++#define FRF_AB_GPIO0_OEN_LBN 24 ++#define FRF_AB_GPIO0_OEN_WIDTH 1 ++#define FRF_AB_GPIO7_OUT_LBN 23 ++#define FRF_AB_GPIO7_OUT_WIDTH 1 ++#define FRF_AB_GPIO6_OUT_LBN 22 ++#define FRF_AB_GPIO6_OUT_WIDTH 1 ++#define FRF_AB_GPIO5_OUT_LBN 21 ++#define FRF_AB_GPIO5_OUT_WIDTH 1 ++#define FRF_AB_GPIO4_OUT_LBN 20 ++#define FRF_AB_GPIO4_OUT_WIDTH 1 ++#define FRF_AB_GPIO3_OUT_LBN 19 ++#define FRF_AB_GPIO3_OUT_WIDTH 1 ++#define FRF_AB_GPIO2_OUT_LBN 18 ++#define FRF_AB_GPIO2_OUT_WIDTH 1 ++#define FRF_AB_GPIO1_OUT_LBN 17 ++#define FRF_AB_GPIO1_OUT_WIDTH 1 ++#define FRF_AB_GPIO0_OUT_LBN 16 ++#define FRF_AB_GPIO0_OUT_WIDTH 1 ++#define FRF_AB_GPIO7_IN_LBN 15 ++#define FRF_AB_GPIO7_IN_WIDTH 1 ++#define FRF_AB_GPIO6_IN_LBN 14 ++#define FRF_AB_GPIO6_IN_WIDTH 1 ++#define FRF_AB_GPIO5_IN_LBN 13 ++#define FRF_AB_GPIO5_IN_WIDTH 1 ++#define FRF_AB_GPIO4_IN_LBN 12 ++#define FRF_AB_GPIO4_IN_WIDTH 1 ++#define FRF_AB_GPIO3_IN_LBN 11 ++#define FRF_AB_GPIO3_IN_WIDTH 1 ++#define FRF_AB_GPIO2_IN_LBN 10 ++#define FRF_AB_GPIO2_IN_WIDTH 1 ++#define FRF_AB_GPIO1_IN_LBN 9 ++#define FRF_AB_GPIO1_IN_WIDTH 1 ++#define FRF_AB_GPIO0_IN_LBN 8 ++#define FRF_AB_GPIO0_IN_WIDTH 1 ++#define FRF_AB_GPIO7_PWRUP_VALUE_LBN 7 ++#define FRF_AB_GPIO7_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO6_PWRUP_VALUE_LBN 6 ++#define FRF_AB_GPIO6_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO5_PWRUP_VALUE_LBN 5 ++#define FRF_AB_GPIO5_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO4_PWRUP_VALUE_LBN 4 ++#define FRF_AB_GPIO4_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO3_PWRUP_VALUE_LBN 3 ++#define FRF_AB_GPIO3_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO2_PWRUP_VALUE_LBN 2 ++#define FRF_AB_GPIO2_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO1_PWRUP_VALUE_LBN 1 ++#define FRF_AB_GPIO1_PWRUP_VALUE_WIDTH 1 ++#define FRF_AB_GPIO0_PWRUP_VALUE_LBN 0 ++#define FRF_AB_GPIO0_PWRUP_VALUE_WIDTH 1 ++ ++/* GLB_CTL_REG: Global control register */ ++#define FR_AB_GLB_CTL 0x00000220 ++#define FRF_AB_EXT_PHY_RST_CTL_LBN 63 ++#define FRF_AB_EXT_PHY_RST_CTL_WIDTH 1 ++#define FRF_AB_XAUI_SD_RST_CTL_LBN 62 ++#define FRF_AB_XAUI_SD_RST_CTL_WIDTH 1 ++#define FRF_AB_PCIE_SD_RST_CTL_LBN 61 ++#define FRF_AB_PCIE_SD_RST_CTL_WIDTH 1 ++#define FRF_AA_PCIX_RST_CTL_LBN 60 ++#define FRF_AA_PCIX_RST_CTL_WIDTH 1 ++#define FRF_BB_BIU_RST_CTL_LBN 60 ++#define FRF_BB_BIU_RST_CTL_WIDTH 1 ++#define FRF_AB_PCIE_STKY_RST_CTL_LBN 59 ++#define FRF_AB_PCIE_STKY_RST_CTL_WIDTH 1 ++#define FRF_AB_PCIE_NSTKY_RST_CTL_LBN 58 ++#define FRF_AB_PCIE_NSTKY_RST_CTL_WIDTH 1 ++#define FRF_AB_PCIE_CORE_RST_CTL_LBN 57 ++#define FRF_AB_PCIE_CORE_RST_CTL_WIDTH 1 ++#define FRF_AB_XGRX_RST_CTL_LBN 56 ++#define FRF_AB_XGRX_RST_CTL_WIDTH 1 ++#define FRF_AB_XGTX_RST_CTL_LBN 55 ++#define FRF_AB_XGTX_RST_CTL_WIDTH 1 ++#define FRF_AB_EM_RST_CTL_LBN 54 ++#define FRF_AB_EM_RST_CTL_WIDTH 1 ++#define FRF_AB_EV_RST_CTL_LBN 53 ++#define FRF_AB_EV_RST_CTL_WIDTH 1 ++#define FRF_AB_SR_RST_CTL_LBN 52 ++#define FRF_AB_SR_RST_CTL_WIDTH 1 ++#define FRF_AB_RX_RST_CTL_LBN 51 ++#define FRF_AB_RX_RST_CTL_WIDTH 1 ++#define FRF_AB_TX_RST_CTL_LBN 50 ++#define FRF_AB_TX_RST_CTL_WIDTH 1 ++#define FRF_AB_EE_RST_CTL_LBN 49 ++#define FRF_AB_EE_RST_CTL_WIDTH 1 ++#define FRF_AB_CS_RST_CTL_LBN 48 ++#define FRF_AB_CS_RST_CTL_WIDTH 1 ++#define FRF_AB_HOT_RST_CTL_LBN 40 ++#define FRF_AB_HOT_RST_CTL_WIDTH 2 ++#define FRF_AB_RST_EXT_PHY_LBN 31 ++#define FRF_AB_RST_EXT_PHY_WIDTH 1 ++#define FRF_AB_RST_XAUI_SD_LBN 30 ++#define FRF_AB_RST_XAUI_SD_WIDTH 1 ++#define FRF_AB_RST_PCIE_SD_LBN 29 ++#define FRF_AB_RST_PCIE_SD_WIDTH 1 ++#define FRF_AA_RST_PCIX_LBN 28 ++#define FRF_AA_RST_PCIX_WIDTH 1 ++#define FRF_BB_RST_BIU_LBN 28 ++#define FRF_BB_RST_BIU_WIDTH 1 ++#define FRF_AB_RST_PCIE_STKY_LBN 27 ++#define FRF_AB_RST_PCIE_STKY_WIDTH 1 ++#define FRF_AB_RST_PCIE_NSTKY_LBN 26 ++#define FRF_AB_RST_PCIE_NSTKY_WIDTH 1 ++#define FRF_AB_RST_PCIE_CORE_LBN 25 ++#define FRF_AB_RST_PCIE_CORE_WIDTH 1 ++#define FRF_AB_RST_XGRX_LBN 24 ++#define FRF_AB_RST_XGRX_WIDTH 1 ++#define FRF_AB_RST_XGTX_LBN 23 ++#define FRF_AB_RST_XGTX_WIDTH 1 ++#define FRF_AB_RST_EM_LBN 22 ++#define FRF_AB_RST_EM_WIDTH 1 ++#define FRF_AB_RST_EV_LBN 21 ++#define FRF_AB_RST_EV_WIDTH 1 ++#define FRF_AB_RST_SR_LBN 20 ++#define FRF_AB_RST_SR_WIDTH 1 ++#define FRF_AB_RST_RX_LBN 19 ++#define FRF_AB_RST_RX_WIDTH 1 ++#define FRF_AB_RST_TX_LBN 18 ++#define FRF_AB_RST_TX_WIDTH 1 ++#define FRF_AB_RST_SF_LBN 17 ++#define FRF_AB_RST_SF_WIDTH 1 ++#define FRF_AB_RST_CS_LBN 16 ++#define FRF_AB_RST_CS_WIDTH 1 ++#define FRF_AB_INT_RST_DUR_LBN 4 ++#define FRF_AB_INT_RST_DUR_WIDTH 3 ++#define FRF_AB_EXT_PHY_RST_DUR_LBN 1 ++#define FRF_AB_EXT_PHY_RST_DUR_WIDTH 3 ++#define FFE_AB_EXT_PHY_RST_DUR_10240US 7 ++#define FFE_AB_EXT_PHY_RST_DUR_5120US 6 ++#define FFE_AB_EXT_PHY_RST_DUR_2560US 5 ++#define FFE_AB_EXT_PHY_RST_DUR_1280US 4 ++#define FFE_AB_EXT_PHY_RST_DUR_640US 3 ++#define FFE_AB_EXT_PHY_RST_DUR_320US 2 ++#define FFE_AB_EXT_PHY_RST_DUR_160US 1 ++#define FFE_AB_EXT_PHY_RST_DUR_80US 0 ++#define FRF_AB_SWRST_LBN 0 ++#define FRF_AB_SWRST_WIDTH 1 ++ ++/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */ ++#define FR_AZ_FATAL_INTR_KER 0x00000230 ++#define FRF_CZ_SRAM_PERR_INT_P_KER_EN_LBN 44 ++#define FRF_CZ_SRAM_PERR_INT_P_KER_EN_WIDTH 1 ++#define FRF_AB_PCI_BUSERR_INT_KER_EN_LBN 43 ++#define FRF_AB_PCI_BUSERR_INT_KER_EN_WIDTH 1 ++#define FRF_CZ_MBU_PERR_INT_KER_EN_LBN 43 ++#define FRF_CZ_MBU_PERR_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_SRAM_OOB_INT_KER_EN_LBN 42 ++#define FRF_AZ_SRAM_OOB_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_BUFID_OOB_INT_KER_EN_LBN 41 ++#define FRF_AZ_BUFID_OOB_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_MEM_PERR_INT_KER_EN_LBN 40 ++#define FRF_AZ_MEM_PERR_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_RBUF_OWN_INT_KER_EN_LBN 39 ++#define FRF_AZ_RBUF_OWN_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_TBUF_OWN_INT_KER_EN_LBN 38 ++#define FRF_AZ_TBUF_OWN_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_RDESCQ_OWN_INT_KER_EN_LBN 37 ++#define FRF_AZ_RDESCQ_OWN_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_TDESCQ_OWN_INT_KER_EN_LBN 36 ++#define FRF_AZ_TDESCQ_OWN_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_EVQ_OWN_INT_KER_EN_LBN 35 ++#define FRF_AZ_EVQ_OWN_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_EVF_OFLO_INT_KER_EN_LBN 34 ++#define FRF_AZ_EVF_OFLO_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_ILL_ADR_INT_KER_EN_LBN 33 ++#define FRF_AZ_ILL_ADR_INT_KER_EN_WIDTH 1 ++#define FRF_AZ_SRM_PERR_INT_KER_EN_LBN 32 ++#define FRF_AZ_SRM_PERR_INT_KER_EN_WIDTH 1 ++#define FRF_CZ_SRAM_PERR_INT_P_KER_LBN 12 ++#define FRF_CZ_SRAM_PERR_INT_P_KER_WIDTH 1 ++#define FRF_AB_PCI_BUSERR_INT_KER_LBN 11 ++#define FRF_AB_PCI_BUSERR_INT_KER_WIDTH 1 ++#define FRF_CZ_MBU_PERR_INT_KER_LBN 11 ++#define FRF_CZ_MBU_PERR_INT_KER_WIDTH 1 ++#define FRF_AZ_SRAM_OOB_INT_KER_LBN 10 ++#define FRF_AZ_SRAM_OOB_INT_KER_WIDTH 1 ++#define FRF_AZ_BUFID_DC_OOB_INT_KER_LBN 9 ++#define FRF_AZ_BUFID_DC_OOB_INT_KER_WIDTH 1 ++#define FRF_AZ_MEM_PERR_INT_KER_LBN 8 ++#define FRF_AZ_MEM_PERR_INT_KER_WIDTH 1 ++#define FRF_AZ_RBUF_OWN_INT_KER_LBN 7 ++#define FRF_AZ_RBUF_OWN_INT_KER_WIDTH 1 ++#define FRF_AZ_TBUF_OWN_INT_KER_LBN 6 ++#define FRF_AZ_TBUF_OWN_INT_KER_WIDTH 1 ++#define FRF_AZ_RDESCQ_OWN_INT_KER_LBN 5 ++#define FRF_AZ_RDESCQ_OWN_INT_KER_WIDTH 1 ++#define FRF_AZ_TDESCQ_OWN_INT_KER_LBN 4 ++#define FRF_AZ_TDESCQ_OWN_INT_KER_WIDTH 1 ++#define FRF_AZ_EVQ_OWN_INT_KER_LBN 3 ++#define FRF_AZ_EVQ_OWN_INT_KER_WIDTH 1 ++#define FRF_AZ_EVF_OFLO_INT_KER_LBN 2 ++#define FRF_AZ_EVF_OFLO_INT_KER_WIDTH 1 ++#define FRF_AZ_ILL_ADR_INT_KER_LBN 1 ++#define FRF_AZ_ILL_ADR_INT_KER_WIDTH 1 ++#define FRF_AZ_SRM_PERR_INT_KER_LBN 0 ++#define FRF_AZ_SRM_PERR_INT_KER_WIDTH 1 ++ ++/* FATAL_INTR_REG_CHAR: Fatal interrupt register for Char */ ++#define FR_BZ_FATAL_INTR_CHAR 0x00000240 ++#define FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_LBN 44 ++#define FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_WIDTH 1 ++#define FRF_BB_PCI_BUSERR_INT_CHAR_EN_LBN 43 ++#define FRF_BB_PCI_BUSERR_INT_CHAR_EN_WIDTH 1 ++#define FRF_CZ_MBU_PERR_INT_CHAR_EN_LBN 43 ++#define FRF_CZ_MBU_PERR_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_SRAM_OOB_INT_CHAR_EN_LBN 42 ++#define FRF_BZ_SRAM_OOB_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_BUFID_OOB_INT_CHAR_EN_LBN 41 ++#define FRF_BZ_BUFID_OOB_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_MEM_PERR_INT_CHAR_EN_LBN 40 ++#define FRF_BZ_MEM_PERR_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_RBUF_OWN_INT_CHAR_EN_LBN 39 ++#define FRF_BZ_RBUF_OWN_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_TBUF_OWN_INT_CHAR_EN_LBN 38 ++#define FRF_BZ_TBUF_OWN_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_LBN 37 ++#define FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_LBN 36 ++#define FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_EVQ_OWN_INT_CHAR_EN_LBN 35 ++#define FRF_BZ_EVQ_OWN_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_EVF_OFLO_INT_CHAR_EN_LBN 34 ++#define FRF_BZ_EVF_OFLO_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_ILL_ADR_INT_CHAR_EN_LBN 33 ++#define FRF_BZ_ILL_ADR_INT_CHAR_EN_WIDTH 1 ++#define FRF_BZ_SRM_PERR_INT_CHAR_EN_LBN 32 ++#define FRF_BZ_SRM_PERR_INT_CHAR_EN_WIDTH 1 ++#define FRF_CZ_SRAM_PERR_INT_P_CHAR_LBN 12 ++#define FRF_CZ_SRAM_PERR_INT_P_CHAR_WIDTH 1 ++#define FRF_BB_PCI_BUSERR_INT_CHAR_LBN 11 ++#define FRF_BB_PCI_BUSERR_INT_CHAR_WIDTH 1 ++#define FRF_CZ_MBU_PERR_INT_CHAR_LBN 11 ++#define FRF_CZ_MBU_PERR_INT_CHAR_WIDTH 1 ++#define FRF_BZ_SRAM_OOB_INT_CHAR_LBN 10 ++#define FRF_BZ_SRAM_OOB_INT_CHAR_WIDTH 1 ++#define FRF_BZ_BUFID_DC_OOB_INT_CHAR_LBN 9 ++#define FRF_BZ_BUFID_DC_OOB_INT_CHAR_WIDTH 1 ++#define FRF_BZ_MEM_PERR_INT_CHAR_LBN 8 ++#define FRF_BZ_MEM_PERR_INT_CHAR_WIDTH 1 ++#define FRF_BZ_RBUF_OWN_INT_CHAR_LBN 7 ++#define FRF_BZ_RBUF_OWN_INT_CHAR_WIDTH 1 ++#define FRF_BZ_TBUF_OWN_INT_CHAR_LBN 6 ++#define FRF_BZ_TBUF_OWN_INT_CHAR_WIDTH 1 ++#define FRF_BZ_RDESCQ_OWN_INT_CHAR_LBN 5 ++#define FRF_BZ_RDESCQ_OWN_INT_CHAR_WIDTH 1 ++#define FRF_BZ_TDESCQ_OWN_INT_CHAR_LBN 4 ++#define FRF_BZ_TDESCQ_OWN_INT_CHAR_WIDTH 1 ++#define FRF_BZ_EVQ_OWN_INT_CHAR_LBN 3 ++#define FRF_BZ_EVQ_OWN_INT_CHAR_WIDTH 1 ++#define FRF_BZ_EVF_OFLO_INT_CHAR_LBN 2 ++#define FRF_BZ_EVF_OFLO_INT_CHAR_WIDTH 1 ++#define FRF_BZ_ILL_ADR_INT_CHAR_LBN 1 ++#define FRF_BZ_ILL_ADR_INT_CHAR_WIDTH 1 ++#define FRF_BZ_SRM_PERR_INT_CHAR_LBN 0 ++#define FRF_BZ_SRM_PERR_INT_CHAR_WIDTH 1 ++ ++/* DP_CTRL_REG: Datapath control register */ ++#define FR_BZ_DP_CTRL 0x00000250 ++#define FRF_BZ_FLS_EVQ_ID_LBN 0 ++#define FRF_BZ_FLS_EVQ_ID_WIDTH 12 ++ ++/* MEM_STAT_REG: Memory status register */ ++#define FR_AZ_MEM_STAT 0x00000260 ++#define FRF_AB_MEM_PERR_VEC_LBN 53 ++#define FRF_AB_MEM_PERR_VEC_WIDTH 38 ++#define FRF_AB_MBIST_CORR_LBN 38 ++#define FRF_AB_MBIST_CORR_WIDTH 15 ++#define FRF_AB_MBIST_ERR_LBN 0 ++#define FRF_AB_MBIST_ERR_WIDTH 40 ++#define FRF_CZ_MEM_PERR_VEC_LBN 0 ++#define FRF_CZ_MEM_PERR_VEC_WIDTH 35 ++ ++/* CS_DEBUG_REG: Debug register */ ++#define FR_AZ_CS_DEBUG 0x00000270 ++#define FRF_AB_GLB_DEBUG2_SEL_LBN 50 ++#define FRF_AB_GLB_DEBUG2_SEL_WIDTH 3 ++#define FRF_AB_DEBUG_BLK_SEL2_LBN 47 ++#define FRF_AB_DEBUG_BLK_SEL2_WIDTH 3 ++#define FRF_AB_DEBUG_BLK_SEL1_LBN 44 ++#define FRF_AB_DEBUG_BLK_SEL1_WIDTH 3 ++#define FRF_AB_DEBUG_BLK_SEL0_LBN 41 ++#define FRF_AB_DEBUG_BLK_SEL0_WIDTH 3 ++#define FRF_CZ_CS_PORT_NUM_LBN 40 ++#define FRF_CZ_CS_PORT_NUM_WIDTH 2 ++#define FRF_AB_MISC_DEBUG_ADDR_LBN 36 ++#define FRF_AB_MISC_DEBUG_ADDR_WIDTH 5 ++#define FRF_AB_SERDES_DEBUG_ADDR_LBN 31 ++#define FRF_AB_SERDES_DEBUG_ADDR_WIDTH 5 ++#define FRF_CZ_CS_PORT_FPE_LBN 1 ++#define FRF_CZ_CS_PORT_FPE_WIDTH 35 ++#define FRF_AB_EM_DEBUG_ADDR_LBN 26 ++#define FRF_AB_EM_DEBUG_ADDR_WIDTH 5 ++#define FRF_AB_SR_DEBUG_ADDR_LBN 21 ++#define FRF_AB_SR_DEBUG_ADDR_WIDTH 5 ++#define FRF_AB_EV_DEBUG_ADDR_LBN 16 ++#define FRF_AB_EV_DEBUG_ADDR_WIDTH 5 ++#define FRF_AB_RX_DEBUG_ADDR_LBN 11 ++#define FRF_AB_RX_DEBUG_ADDR_WIDTH 5 ++#define FRF_AB_TX_DEBUG_ADDR_LBN 6 ++#define FRF_AB_TX_DEBUG_ADDR_WIDTH 5 ++#define FRF_AB_CS_BIU_DEBUG_ADDR_LBN 1 ++#define FRF_AB_CS_BIU_DEBUG_ADDR_WIDTH 5 ++#define FRF_AZ_CS_DEBUG_EN_LBN 0 ++#define FRF_AZ_CS_DEBUG_EN_WIDTH 1 ++ ++/* DRIVER_REG: Driver scratch register [0-7] */ ++#define FR_AZ_DRIVER 0x00000280 ++#define FR_AZ_DRIVER_STEP 16 ++#define FR_AZ_DRIVER_ROWS 8 ++#define FRF_AZ_DRIVER_DW0_LBN 0 ++#define FRF_AZ_DRIVER_DW0_WIDTH 32 ++ ++/* ALTERA_BUILD_REG: Altera build register */ ++#define FR_AZ_ALTERA_BUILD 0x00000300 ++#define FRF_AZ_ALTERA_BUILD_VER_LBN 0 ++#define FRF_AZ_ALTERA_BUILD_VER_WIDTH 32 ++ ++/* CSR_SPARE_REG: Spare register */ ++#define FR_AZ_CSR_SPARE 0x00000310 ++#define FRF_AB_MEM_PERR_EN_LBN 64 ++#define FRF_AB_MEM_PERR_EN_WIDTH 38 ++#define FRF_CZ_MEM_PERR_EN_LBN 64 ++#define FRF_CZ_MEM_PERR_EN_WIDTH 35 ++#define FRF_AB_MEM_PERR_EN_TX_DATA_LBN 72 ++#define FRF_AB_MEM_PERR_EN_TX_DATA_WIDTH 2 ++#define FRF_AZ_CSR_SPARE_BITS_LBN 0 ++#define FRF_AZ_CSR_SPARE_BITS_WIDTH 32 ++ ++/* PCIE_SD_CTL0123_REG: PCIE SerDes control register 0 to 3 */ ++#define FR_AB_PCIE_SD_CTL0123 0x00000320 ++#define FRF_AB_PCIE_TESTSIG_H_LBN 96 ++#define FRF_AB_PCIE_TESTSIG_H_WIDTH 19 ++#define FRF_AB_PCIE_TESTSIG_L_LBN 64 ++#define FRF_AB_PCIE_TESTSIG_L_WIDTH 19 ++#define FRF_AB_PCIE_OFFSET_LBN 56 ++#define FRF_AB_PCIE_OFFSET_WIDTH 8 ++#define FRF_AB_PCIE_OFFSETEN_H_LBN 55 ++#define FRF_AB_PCIE_OFFSETEN_H_WIDTH 1 ++#define FRF_AB_PCIE_OFFSETEN_L_LBN 54 ++#define FRF_AB_PCIE_OFFSETEN_L_WIDTH 1 ++#define FRF_AB_PCIE_HIVMODE_H_LBN 53 ++#define FRF_AB_PCIE_HIVMODE_H_WIDTH 1 ++#define FRF_AB_PCIE_HIVMODE_L_LBN 52 ++#define FRF_AB_PCIE_HIVMODE_L_WIDTH 1 ++#define FRF_AB_PCIE_PARRESET_H_LBN 51 ++#define FRF_AB_PCIE_PARRESET_H_WIDTH 1 ++#define FRF_AB_PCIE_PARRESET_L_LBN 50 ++#define FRF_AB_PCIE_PARRESET_L_WIDTH 1 ++#define FRF_AB_PCIE_LPBKWDRV_H_LBN 49 ++#define FRF_AB_PCIE_LPBKWDRV_H_WIDTH 1 ++#define FRF_AB_PCIE_LPBKWDRV_L_LBN 48 ++#define FRF_AB_PCIE_LPBKWDRV_L_WIDTH 1 ++#define FRF_AB_PCIE_LPBK_LBN 40 ++#define FRF_AB_PCIE_LPBK_WIDTH 8 ++#define FRF_AB_PCIE_PARLPBK_LBN 32 ++#define FRF_AB_PCIE_PARLPBK_WIDTH 8 ++#define FRF_AB_PCIE_RXTERMADJ_H_LBN 30 ++#define FRF_AB_PCIE_RXTERMADJ_H_WIDTH 2 ++#define FRF_AB_PCIE_RXTERMADJ_L_LBN 28 ++#define FRF_AB_PCIE_RXTERMADJ_L_WIDTH 2 ++#define FFE_AB_PCIE_RXTERMADJ_MIN15PCNT 3 ++#define FFE_AB_PCIE_RXTERMADJ_PL10PCNT 2 ++#define FFE_AB_PCIE_RXTERMADJ_MIN17PCNT 1 ++#define FFE_AB_PCIE_RXTERMADJ_NOMNL 0 ++#define FRF_AB_PCIE_TXTERMADJ_H_LBN 26 ++#define FRF_AB_PCIE_TXTERMADJ_H_WIDTH 2 ++#define FRF_AB_PCIE_TXTERMADJ_L_LBN 24 ++#define FRF_AB_PCIE_TXTERMADJ_L_WIDTH 2 ++#define FFE_AB_PCIE_TXTERMADJ_MIN15PCNT 3 ++#define FFE_AB_PCIE_TXTERMADJ_PL10PCNT 2 ++#define FFE_AB_PCIE_TXTERMADJ_MIN17PCNT 1 ++#define FFE_AB_PCIE_TXTERMADJ_NOMNL 0 ++#define FRF_AB_PCIE_RXEQCTL_H_LBN 18 ++#define FRF_AB_PCIE_RXEQCTL_H_WIDTH 2 ++#define FRF_AB_PCIE_RXEQCTL_L_LBN 16 ++#define FRF_AB_PCIE_RXEQCTL_L_WIDTH 2 ++#define FFE_AB_PCIE_RXEQCTL_OFF_ALT 3 ++#define FFE_AB_PCIE_RXEQCTL_OFF 2 ++#define FFE_AB_PCIE_RXEQCTL_MIN 1 ++#define FFE_AB_PCIE_RXEQCTL_MAX 0 ++#define FRF_AB_PCIE_HIDRV_LBN 8 ++#define FRF_AB_PCIE_HIDRV_WIDTH 8 ++#define FRF_AB_PCIE_LODRV_LBN 0 ++#define FRF_AB_PCIE_LODRV_WIDTH 8 ++ ++/* PCIE_SD_CTL45_REG: PCIE SerDes control register 4 and 5 */ ++#define FR_AB_PCIE_SD_CTL45 0x00000330 ++#define FRF_AB_PCIE_DTX7_LBN 60 ++#define FRF_AB_PCIE_DTX7_WIDTH 4 ++#define FRF_AB_PCIE_DTX6_LBN 56 ++#define FRF_AB_PCIE_DTX6_WIDTH 4 ++#define FRF_AB_PCIE_DTX5_LBN 52 ++#define FRF_AB_PCIE_DTX5_WIDTH 4 ++#define FRF_AB_PCIE_DTX4_LBN 48 ++#define FRF_AB_PCIE_DTX4_WIDTH 4 ++#define FRF_AB_PCIE_DTX3_LBN 44 ++#define FRF_AB_PCIE_DTX3_WIDTH 4 ++#define FRF_AB_PCIE_DTX2_LBN 40 ++#define FRF_AB_PCIE_DTX2_WIDTH 4 ++#define FRF_AB_PCIE_DTX1_LBN 36 ++#define FRF_AB_PCIE_DTX1_WIDTH 4 ++#define FRF_AB_PCIE_DTX0_LBN 32 ++#define FRF_AB_PCIE_DTX0_WIDTH 4 ++#define FRF_AB_PCIE_DEQ7_LBN 28 ++#define FRF_AB_PCIE_DEQ7_WIDTH 4 ++#define FRF_AB_PCIE_DEQ6_LBN 24 ++#define FRF_AB_PCIE_DEQ6_WIDTH 4 ++#define FRF_AB_PCIE_DEQ5_LBN 20 ++#define FRF_AB_PCIE_DEQ5_WIDTH 4 ++#define FRF_AB_PCIE_DEQ4_LBN 16 ++#define FRF_AB_PCIE_DEQ4_WIDTH 4 ++#define FRF_AB_PCIE_DEQ3_LBN 12 ++#define FRF_AB_PCIE_DEQ3_WIDTH 4 ++#define FRF_AB_PCIE_DEQ2_LBN 8 ++#define FRF_AB_PCIE_DEQ2_WIDTH 4 ++#define FRF_AB_PCIE_DEQ1_LBN 4 ++#define FRF_AB_PCIE_DEQ1_WIDTH 4 ++#define FRF_AB_PCIE_DEQ0_LBN 0 ++#define FRF_AB_PCIE_DEQ0_WIDTH 4 ++ ++/* PCIE_PCS_CTL_STAT_REG: PCIE PCS control and status register */ ++#define FR_AB_PCIE_PCS_CTL_STAT 0x00000340 ++#define FRF_AB_PCIE_PRBSERRCOUNT0_H_LBN 52 ++#define FRF_AB_PCIE_PRBSERRCOUNT0_H_WIDTH 4 ++#define FRF_AB_PCIE_PRBSERRCOUNT0_L_LBN 48 ++#define FRF_AB_PCIE_PRBSERRCOUNT0_L_WIDTH 4 ++#define FRF_AB_PCIE_PRBSERR_LBN 40 ++#define FRF_AB_PCIE_PRBSERR_WIDTH 8 ++#define FRF_AB_PCIE_PRBSERRH0_LBN 32 ++#define FRF_AB_PCIE_PRBSERRH0_WIDTH 8 ++#define FRF_AB_PCIE_FASTINIT_H_LBN 15 ++#define FRF_AB_PCIE_FASTINIT_H_WIDTH 1 ++#define FRF_AB_PCIE_FASTINIT_L_LBN 14 ++#define FRF_AB_PCIE_FASTINIT_L_WIDTH 1 ++#define FRF_AB_PCIE_CTCDISABLE_H_LBN 13 ++#define FRF_AB_PCIE_CTCDISABLE_H_WIDTH 1 ++#define FRF_AB_PCIE_CTCDISABLE_L_LBN 12 ++#define FRF_AB_PCIE_CTCDISABLE_L_WIDTH 1 ++#define FRF_AB_PCIE_PRBSSYNC_H_LBN 11 ++#define FRF_AB_PCIE_PRBSSYNC_H_WIDTH 1 ++#define FRF_AB_PCIE_PRBSSYNC_L_LBN 10 ++#define FRF_AB_PCIE_PRBSSYNC_L_WIDTH 1 ++#define FRF_AB_PCIE_PRBSERRACK_H_LBN 9 ++#define FRF_AB_PCIE_PRBSERRACK_H_WIDTH 1 ++#define FRF_AB_PCIE_PRBSERRACK_L_LBN 8 ++#define FRF_AB_PCIE_PRBSERRACK_L_WIDTH 1 ++#define FRF_AB_PCIE_PRBSSEL_LBN 0 ++#define FRF_AB_PCIE_PRBSSEL_WIDTH 8 ++ ++/* DEBUG_DATA_OUT_REG: Live Debug and Debug 2 out ports */ ++#define FR_BB_DEBUG_DATA_OUT 0x00000350 ++#define FRF_BB_DEBUG2_PORT_LBN 25 ++#define FRF_BB_DEBUG2_PORT_WIDTH 15 ++#define FRF_BB_DEBUG1_PORT_LBN 0 ++#define FRF_BB_DEBUG1_PORT_WIDTH 25 ++ ++/* EVQ_RPTR_REGP0: Event queue read pointer register */ ++#define FR_BZ_EVQ_RPTR_P0 0x00000400 ++#define FR_BZ_EVQ_RPTR_P0_STEP 8192 ++#define FR_BZ_EVQ_RPTR_P0_ROWS 1024 ++/* EVQ_RPTR_REG_KER: Event queue read pointer register */ ++#define FR_AA_EVQ_RPTR_KER 0x00011b00 ++#define FR_AA_EVQ_RPTR_KER_STEP 4 ++#define FR_AA_EVQ_RPTR_KER_ROWS 4 ++/* EVQ_RPTR_REG: Event queue read pointer register */ ++#define FR_BZ_EVQ_RPTR 0x00fa0000 ++#define FR_BZ_EVQ_RPTR_STEP 16 ++#define FR_BB_EVQ_RPTR_ROWS 4096 ++#define FR_CZ_EVQ_RPTR_ROWS 1024 ++/* EVQ_RPTR_REGP123: Event queue read pointer register */ ++#define FR_BB_EVQ_RPTR_P123 0x01000400 ++#define FR_BB_EVQ_RPTR_P123_STEP 8192 ++#define FR_BB_EVQ_RPTR_P123_ROWS 3072 ++#define FRF_AZ_EVQ_RPTR_VLD_LBN 15 ++#define FRF_AZ_EVQ_RPTR_VLD_WIDTH 1 ++#define FRF_AZ_EVQ_RPTR_LBN 0 ++#define FRF_AZ_EVQ_RPTR_WIDTH 15 ++ ++/* TIMER_COMMAND_REGP0: Timer Command Registers */ ++#define FR_BZ_TIMER_COMMAND_P0 0x00000420 ++#define FR_BZ_TIMER_COMMAND_P0_STEP 8192 ++#define FR_BZ_TIMER_COMMAND_P0_ROWS 1024 ++/* TIMER_COMMAND_REG_KER: Timer Command Registers */ ++#define FR_AA_TIMER_COMMAND_KER 0x00000420 ++#define FR_AA_TIMER_COMMAND_KER_STEP 8192 ++#define FR_AA_TIMER_COMMAND_KER_ROWS 4 ++/* TIMER_COMMAND_REGP123: Timer Command Registers */ ++#define FR_BB_TIMER_COMMAND_P123 0x01000420 ++#define FR_BB_TIMER_COMMAND_P123_STEP 8192 ++#define FR_BB_TIMER_COMMAND_P123_ROWS 3072 ++#define FRF_CZ_TC_TIMER_MODE_LBN 14 ++#define FRF_CZ_TC_TIMER_MODE_WIDTH 2 ++#define FRF_AB_TC_TIMER_MODE_LBN 12 ++#define FRF_AB_TC_TIMER_MODE_WIDTH 2 ++#define FRF_CZ_TC_TIMER_VAL_LBN 0 ++#define FRF_CZ_TC_TIMER_VAL_WIDTH 14 ++#define FRF_AB_TC_TIMER_VAL_LBN 0 ++#define FRF_AB_TC_TIMER_VAL_WIDTH 12 ++ ++/* DRV_EV_REG: Driver generated event register */ ++#define FR_AZ_DRV_EV 0x00000440 ++#define FRF_AZ_DRV_EV_QID_LBN 64 ++#define FRF_AZ_DRV_EV_QID_WIDTH 12 ++#define FRF_AZ_DRV_EV_DATA_LBN 0 ++#define FRF_AZ_DRV_EV_DATA_WIDTH 64 ++ ++/* EVQ_CTL_REG: Event queue control register */ ++#define FR_AZ_EVQ_CTL 0x00000450 ++#define FRF_CZ_RX_EVQ_WAKEUP_MASK_LBN 15 ++#define FRF_CZ_RX_EVQ_WAKEUP_MASK_WIDTH 10 ++#define FRF_BB_RX_EVQ_WAKEUP_MASK_LBN 15 ++#define FRF_BB_RX_EVQ_WAKEUP_MASK_WIDTH 6 ++#define FRF_AZ_EVQ_OWNERR_CTL_LBN 14 ++#define FRF_AZ_EVQ_OWNERR_CTL_WIDTH 1 ++#define FRF_AZ_EVQ_FIFO_AF_TH_LBN 7 ++#define FRF_AZ_EVQ_FIFO_AF_TH_WIDTH 7 ++#define FRF_AZ_EVQ_FIFO_NOTAF_TH_LBN 0 ++#define FRF_AZ_EVQ_FIFO_NOTAF_TH_WIDTH 7 ++ ++/* EVQ_CNT1_REG: Event counter 1 register */ ++#define FR_AZ_EVQ_CNT1 0x00000460 ++#define FRF_AZ_EVQ_CNT_PRE_FIFO_LBN 120 ++#define FRF_AZ_EVQ_CNT_PRE_FIFO_WIDTH 7 ++#define FRF_AZ_EVQ_CNT_TOBIU_LBN 100 ++#define FRF_AZ_EVQ_CNT_TOBIU_WIDTH 20 ++#define FRF_AZ_EVQ_TX_REQ_CNT_LBN 80 ++#define FRF_AZ_EVQ_TX_REQ_CNT_WIDTH 20 ++#define FRF_AZ_EVQ_RX_REQ_CNT_LBN 60 ++#define FRF_AZ_EVQ_RX_REQ_CNT_WIDTH 20 ++#define FRF_AZ_EVQ_EM_REQ_CNT_LBN 40 ++#define FRF_AZ_EVQ_EM_REQ_CNT_WIDTH 20 ++#define FRF_AZ_EVQ_CSR_REQ_CNT_LBN 20 ++#define FRF_AZ_EVQ_CSR_REQ_CNT_WIDTH 20 ++#define FRF_AZ_EVQ_ERR_REQ_CNT_LBN 0 ++#define FRF_AZ_EVQ_ERR_REQ_CNT_WIDTH 20 ++ ++/* EVQ_CNT2_REG: Event counter 2 register */ ++#define FR_AZ_EVQ_CNT2 0x00000470 ++#define FRF_AZ_EVQ_UPD_REQ_CNT_LBN 104 ++#define FRF_AZ_EVQ_UPD_REQ_CNT_WIDTH 20 ++#define FRF_AZ_EVQ_CLR_REQ_CNT_LBN 84 ++#define FRF_AZ_EVQ_CLR_REQ_CNT_WIDTH 20 ++#define FRF_AZ_EVQ_RDY_CNT_LBN 80 ++#define FRF_AZ_EVQ_RDY_CNT_WIDTH 4 ++#define FRF_AZ_EVQ_WU_REQ_CNT_LBN 60 ++#define FRF_AZ_EVQ_WU_REQ_CNT_WIDTH 20 ++#define FRF_AZ_EVQ_WET_REQ_CNT_LBN 40 ++#define FRF_AZ_EVQ_WET_REQ_CNT_WIDTH 20 ++#define FRF_AZ_EVQ_INIT_REQ_CNT_LBN 20 ++#define FRF_AZ_EVQ_INIT_REQ_CNT_WIDTH 20 ++#define FRF_AZ_EVQ_TM_REQ_CNT_LBN 0 ++#define FRF_AZ_EVQ_TM_REQ_CNT_WIDTH 20 ++ ++/* USR_EV_REG: Event mailbox register */ ++#define FR_CZ_USR_EV 0x00000540 ++#define FR_CZ_USR_EV_STEP 8192 ++#define FR_CZ_USR_EV_ROWS 1024 ++#define FRF_CZ_USR_EV_DATA_LBN 0 ++#define FRF_CZ_USR_EV_DATA_WIDTH 32 ++ ++/* BUF_TBL_CFG_REG: Buffer table configuration register */ ++#define FR_AZ_BUF_TBL_CFG 0x00000600 ++#define FRF_AZ_BUF_TBL_MODE_LBN 3 ++#define FRF_AZ_BUF_TBL_MODE_WIDTH 1 ++ ++/* SRM_RX_DC_CFG_REG: SRAM receive descriptor cache configuration register */ ++#define FR_AZ_SRM_RX_DC_CFG 0x00000610 ++#define FRF_AZ_SRM_CLK_TMP_EN_LBN 21 ++#define FRF_AZ_SRM_CLK_TMP_EN_WIDTH 1 ++#define FRF_AZ_SRM_RX_DC_BASE_ADR_LBN 0 ++#define FRF_AZ_SRM_RX_DC_BASE_ADR_WIDTH 21 ++ ++/* SRM_TX_DC_CFG_REG: SRAM transmit descriptor cache configuration register */ ++#define FR_AZ_SRM_TX_DC_CFG 0x00000620 ++#define FRF_AZ_SRM_TX_DC_BASE_ADR_LBN 0 ++#define FRF_AZ_SRM_TX_DC_BASE_ADR_WIDTH 21 ++ ++/* SRM_CFG_REG: SRAM configuration register */ ++#define FR_AZ_SRM_CFG 0x00000630 ++#define FRF_AZ_SRM_OOB_ADR_INTEN_LBN 5 ++#define FRF_AZ_SRM_OOB_ADR_INTEN_WIDTH 1 ++#define FRF_AZ_SRM_OOB_BUF_INTEN_LBN 4 ++#define FRF_AZ_SRM_OOB_BUF_INTEN_WIDTH 1 ++#define FRF_AZ_SRM_INIT_EN_LBN 3 ++#define FRF_AZ_SRM_INIT_EN_WIDTH 1 ++#define FRF_AZ_SRM_NUM_BANK_LBN 2 ++#define FRF_AZ_SRM_NUM_BANK_WIDTH 1 ++#define FRF_AZ_SRM_BANK_SIZE_LBN 0 ++#define FRF_AZ_SRM_BANK_SIZE_WIDTH 2 ++ ++/* BUF_TBL_UPD_REG: Buffer table update register */ ++#define FR_AZ_BUF_TBL_UPD 0x00000650 ++#define FRF_AZ_BUF_UPD_CMD_LBN 63 ++#define FRF_AZ_BUF_UPD_CMD_WIDTH 1 ++#define FRF_AZ_BUF_CLR_CMD_LBN 62 ++#define FRF_AZ_BUF_CLR_CMD_WIDTH 1 ++#define FRF_AZ_BUF_CLR_END_ID_LBN 32 ++#define FRF_AZ_BUF_CLR_END_ID_WIDTH 20 ++#define FRF_AZ_BUF_CLR_START_ID_LBN 0 ++#define FRF_AZ_BUF_CLR_START_ID_WIDTH 20 ++ ++/* SRM_UPD_EVQ_REG: Buffer table update register */ ++#define FR_AZ_SRM_UPD_EVQ 0x00000660 ++#define FRF_AZ_SRM_UPD_EVQ_ID_LBN 0 ++#define FRF_AZ_SRM_UPD_EVQ_ID_WIDTH 12 ++ ++/* SRAM_PARITY_REG: SRAM parity register. */ ++#define FR_AZ_SRAM_PARITY 0x00000670 ++#define FRF_CZ_BYPASS_ECC_LBN 3 ++#define FRF_CZ_BYPASS_ECC_WIDTH 1 ++#define FRF_CZ_SEC_INT_LBN 2 ++#define FRF_CZ_SEC_INT_WIDTH 1 ++#define FRF_CZ_FORCE_SRAM_DOUBLE_ERR_LBN 1 ++#define FRF_CZ_FORCE_SRAM_DOUBLE_ERR_WIDTH 1 ++#define FRF_AB_FORCE_SRAM_PERR_LBN 0 ++#define FRF_AB_FORCE_SRAM_PERR_WIDTH 1 ++#define FRF_CZ_FORCE_SRAM_SINGLE_ERR_LBN 0 ++#define FRF_CZ_FORCE_SRAM_SINGLE_ERR_WIDTH 1 ++ ++/* RX_CFG_REG: Receive configuration register */ ++#define FR_AZ_RX_CFG 0x00000800 ++#define FRF_CZ_RX_MIN_KBUF_SIZE_LBN 72 ++#define FRF_CZ_RX_MIN_KBUF_SIZE_WIDTH 14 ++#define FRF_CZ_RX_HDR_SPLIT_EN_LBN 71 ++#define FRF_CZ_RX_HDR_SPLIT_EN_WIDTH 1 ++#define FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_LBN 62 ++#define FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_WIDTH 9 ++#define FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_LBN 53 ++#define FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_WIDTH 9 ++#define FRF_CZ_RX_PRE_RFF_IPG_LBN 49 ++#define FRF_CZ_RX_PRE_RFF_IPG_WIDTH 4 ++#define FRF_BZ_RX_TCP_SUP_LBN 48 ++#define FRF_BZ_RX_TCP_SUP_WIDTH 1 ++#define FRF_BZ_RX_INGR_EN_LBN 47 ++#define FRF_BZ_RX_INGR_EN_WIDTH 1 ++#define FRF_BZ_RX_IP_HASH_LBN 46 ++#define FRF_BZ_RX_IP_HASH_WIDTH 1 ++#define FRF_BZ_RX_HASH_ALG_LBN 45 ++#define FRF_BZ_RX_HASH_ALG_WIDTH 1 ++#define FRF_BZ_RX_HASH_INSRT_HDR_LBN 44 ++#define FRF_BZ_RX_HASH_INSRT_HDR_WIDTH 1 ++#define FRF_BZ_RX_DESC_PUSH_EN_LBN 43 ++#define FRF_BZ_RX_DESC_PUSH_EN_WIDTH 1 ++#define FRF_BZ_RX_RDW_PATCH_EN_LBN 42 ++#define FRF_BZ_RX_RDW_PATCH_EN_WIDTH 1 ++#define FRF_BB_RX_PCI_BURST_SIZE_LBN 39 ++#define FRF_BB_RX_PCI_BURST_SIZE_WIDTH 3 ++#define FRF_BZ_RX_OWNERR_CTL_LBN 38 ++#define FRF_BZ_RX_OWNERR_CTL_WIDTH 1 ++#define FRF_BZ_RX_XON_TX_TH_LBN 33 ++#define FRF_BZ_RX_XON_TX_TH_WIDTH 5 ++#define FRF_AA_RX_DESC_PUSH_EN_LBN 35 ++#define FRF_AA_RX_DESC_PUSH_EN_WIDTH 1 ++#define FRF_AA_RX_RDW_PATCH_EN_LBN 34 ++#define FRF_AA_RX_RDW_PATCH_EN_WIDTH 1 ++#define FRF_AA_RX_PCI_BURST_SIZE_LBN 31 ++#define FRF_AA_RX_PCI_BURST_SIZE_WIDTH 3 ++#define FRF_BZ_RX_XOFF_TX_TH_LBN 28 ++#define FRF_BZ_RX_XOFF_TX_TH_WIDTH 5 ++#define FRF_AA_RX_OWNERR_CTL_LBN 30 ++#define FRF_AA_RX_OWNERR_CTL_WIDTH 1 ++#define FRF_AA_RX_XON_TX_TH_LBN 25 ++#define FRF_AA_RX_XON_TX_TH_WIDTH 5 ++#define FRF_BZ_RX_USR_BUF_SIZE_LBN 19 ++#define FRF_BZ_RX_USR_BUF_SIZE_WIDTH 9 ++#define FRF_AA_RX_XOFF_TX_TH_LBN 20 ++#define FRF_AA_RX_XOFF_TX_TH_WIDTH 5 ++#define FRF_AA_RX_USR_BUF_SIZE_LBN 11 ++#define FRF_AA_RX_USR_BUF_SIZE_WIDTH 9 ++#define FRF_BZ_RX_XON_MAC_TH_LBN 10 ++#define FRF_BZ_RX_XON_MAC_TH_WIDTH 9 ++#define FRF_AA_RX_XON_MAC_TH_LBN 6 ++#define FRF_AA_RX_XON_MAC_TH_WIDTH 5 ++#define FRF_BZ_RX_XOFF_MAC_TH_LBN 1 ++#define FRF_BZ_RX_XOFF_MAC_TH_WIDTH 9 ++#define FRF_AA_RX_XOFF_MAC_TH_LBN 1 ++#define FRF_AA_RX_XOFF_MAC_TH_WIDTH 5 ++#define FRF_AZ_RX_XOFF_MAC_EN_LBN 0 ++#define FRF_AZ_RX_XOFF_MAC_EN_WIDTH 1 ++ ++/* RX_FILTER_CTL_REG: Receive filter control registers */ ++#define FR_BZ_RX_FILTER_CTL 0x00000810 ++#define FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_LBN 94 ++#define FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_WIDTH 8 ++#define FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_LBN 86 ++#define FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_WIDTH 8 ++#define FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_LBN 85 ++#define FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_WIDTH 1 ++#define FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_LBN 69 ++#define FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_WIDTH 16 ++#define FRF_CZ_MULTICAST_NOMATCH_Q_ID_LBN 57 ++#define FRF_CZ_MULTICAST_NOMATCH_Q_ID_WIDTH 12 ++#define FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_LBN 56 ++#define FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_WIDTH 1 ++#define FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_LBN 55 ++#define FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_WIDTH 1 ++#define FRF_CZ_UNICAST_NOMATCH_Q_ID_LBN 43 ++#define FRF_CZ_UNICAST_NOMATCH_Q_ID_WIDTH 12 ++#define FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_LBN 42 ++#define FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_WIDTH 1 ++#define FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_LBN 41 ++#define FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_WIDTH 1 ++#define FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_LBN 40 ++#define FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_WIDTH 1 ++#define FRF_BZ_UDP_FULL_SRCH_LIMIT_LBN 32 ++#define FRF_BZ_UDP_FULL_SRCH_LIMIT_WIDTH 8 ++#define FRF_BZ_NUM_KER_LBN 24 ++#define FRF_BZ_NUM_KER_WIDTH 2 ++#define FRF_BZ_UDP_WILD_SRCH_LIMIT_LBN 16 ++#define FRF_BZ_UDP_WILD_SRCH_LIMIT_WIDTH 8 ++#define FRF_BZ_TCP_WILD_SRCH_LIMIT_LBN 8 ++#define FRF_BZ_TCP_WILD_SRCH_LIMIT_WIDTH 8 ++#define FRF_BZ_TCP_FULL_SRCH_LIMIT_LBN 0 ++#define FRF_BZ_TCP_FULL_SRCH_LIMIT_WIDTH 8 ++ ++/* RX_FLUSH_DESCQ_REG: Receive flush descriptor queue register */ ++#define FR_AZ_RX_FLUSH_DESCQ 0x00000820 ++#define FRF_AZ_RX_FLUSH_DESCQ_CMD_LBN 24 ++#define FRF_AZ_RX_FLUSH_DESCQ_CMD_WIDTH 1 ++#define FRF_AZ_RX_FLUSH_DESCQ_LBN 0 ++#define FRF_AZ_RX_FLUSH_DESCQ_WIDTH 12 ++ ++/* RX_DESC_UPD_REGP0: Receive descriptor update register. */ ++#define FR_BZ_RX_DESC_UPD_P0 0x00000830 ++#define FR_BZ_RX_DESC_UPD_P0_STEP 8192 ++#define FR_BZ_RX_DESC_UPD_P0_ROWS 1024 ++/* RX_DESC_UPD_REG_KER: Receive descriptor update register. */ ++#define FR_AA_RX_DESC_UPD_KER 0x00000830 ++#define FR_AA_RX_DESC_UPD_KER_STEP 8192 ++#define FR_AA_RX_DESC_UPD_KER_ROWS 4 ++/* RX_DESC_UPD_REGP123: Receive descriptor update register. */ ++#define FR_BB_RX_DESC_UPD_P123 0x01000830 ++#define FR_BB_RX_DESC_UPD_P123_STEP 8192 ++#define FR_BB_RX_DESC_UPD_P123_ROWS 3072 ++#define FRF_AZ_RX_DESC_WPTR_LBN 96 ++#define FRF_AZ_RX_DESC_WPTR_WIDTH 12 ++#define FRF_AZ_RX_DESC_PUSH_CMD_LBN 95 ++#define FRF_AZ_RX_DESC_PUSH_CMD_WIDTH 1 ++#define FRF_AZ_RX_DESC_LBN 0 ++#define FRF_AZ_RX_DESC_WIDTH 64 ++ ++/* RX_DC_CFG_REG: Receive descriptor cache configuration register */ ++#define FR_AZ_RX_DC_CFG 0x00000840 ++#define FRF_AB_RX_MAX_PF_LBN 2 ++#define FRF_AB_RX_MAX_PF_WIDTH 2 ++#define FRF_AZ_RX_DC_SIZE_LBN 0 ++#define FRF_AZ_RX_DC_SIZE_WIDTH 2 ++#define FFE_AZ_RX_DC_SIZE_64 3 ++#define FFE_AZ_RX_DC_SIZE_32 2 ++#define FFE_AZ_RX_DC_SIZE_16 1 ++#define FFE_AZ_RX_DC_SIZE_8 0 ++ ++/* RX_DC_PF_WM_REG: Receive descriptor cache pre-fetch watermark register */ ++#define FR_AZ_RX_DC_PF_WM 0x00000850 ++#define FRF_AZ_RX_DC_PF_HWM_LBN 6 ++#define FRF_AZ_RX_DC_PF_HWM_WIDTH 6 ++#define FRF_AZ_RX_DC_PF_LWM_LBN 0 ++#define FRF_AZ_RX_DC_PF_LWM_WIDTH 6 ++ ++/* RX_RSS_TKEY_REG: RSS Toeplitz hash key */ ++#define FR_BZ_RX_RSS_TKEY 0x00000860 ++#define FRF_BZ_RX_RSS_TKEY_HI_LBN 64 ++#define FRF_BZ_RX_RSS_TKEY_HI_WIDTH 64 ++#define FRF_BZ_RX_RSS_TKEY_LO_LBN 0 ++#define FRF_BZ_RX_RSS_TKEY_LO_WIDTH 64 ++ ++/* RX_NODESC_DROP_REG: Receive dropped packet counter register */ ++#define FR_AZ_RX_NODESC_DROP 0x00000880 ++#define FRF_CZ_RX_NODESC_DROP_CNT_LBN 0 ++#define FRF_CZ_RX_NODESC_DROP_CNT_WIDTH 32 ++#define FRF_AB_RX_NODESC_DROP_CNT_LBN 0 ++#define FRF_AB_RX_NODESC_DROP_CNT_WIDTH 16 ++ ++/* RX_SELF_RST_REG: Receive self reset register */ ++#define FR_AA_RX_SELF_RST 0x00000890 ++#define FRF_AA_RX_ISCSI_DIS_LBN 17 ++#define FRF_AA_RX_ISCSI_DIS_WIDTH 1 ++#define FRF_AA_RX_SW_RST_REG_LBN 16 ++#define FRF_AA_RX_SW_RST_REG_WIDTH 1 ++#define FRF_AA_RX_NODESC_WAIT_DIS_LBN 9 ++#define FRF_AA_RX_NODESC_WAIT_DIS_WIDTH 1 ++#define FRF_AA_RX_SELF_RST_EN_LBN 8 ++#define FRF_AA_RX_SELF_RST_EN_WIDTH 1 ++#define FRF_AA_RX_MAX_PF_LAT_LBN 4 ++#define FRF_AA_RX_MAX_PF_LAT_WIDTH 4 ++#define FRF_AA_RX_MAX_LU_LAT_LBN 0 ++#define FRF_AA_RX_MAX_LU_LAT_WIDTH 4 ++ ++/* RX_DEBUG_REG: undocumented register */ ++#define FR_AZ_RX_DEBUG 0x000008a0 ++#define FRF_AZ_RX_DEBUG_LBN 0 ++#define FRF_AZ_RX_DEBUG_WIDTH 64 ++ ++/* RX_PUSH_DROP_REG: Receive descriptor push dropped counter register */ ++#define FR_AZ_RX_PUSH_DROP 0x000008b0 ++#define FRF_AZ_RX_PUSH_DROP_CNT_LBN 0 ++#define FRF_AZ_RX_PUSH_DROP_CNT_WIDTH 32 ++ ++/* RX_RSS_IPV6_REG1: IPv6 RSS Toeplitz hash key low bytes */ ++#define FR_CZ_RX_RSS_IPV6_REG1 0x000008d0 ++#define FRF_CZ_RX_RSS_IPV6_TKEY_LO_LBN 0 ++#define FRF_CZ_RX_RSS_IPV6_TKEY_LO_WIDTH 128 ++ ++/* RX_RSS_IPV6_REG2: IPv6 RSS Toeplitz hash key middle bytes */ ++#define FR_CZ_RX_RSS_IPV6_REG2 0x000008e0 ++#define FRF_CZ_RX_RSS_IPV6_TKEY_MID_LBN 0 ++#define FRF_CZ_RX_RSS_IPV6_TKEY_MID_WIDTH 128 ++ ++/* RX_RSS_IPV6_REG3: IPv6 RSS Toeplitz hash key upper bytes and IPv6 RSS settings */ ++#define FR_CZ_RX_RSS_IPV6_REG3 0x000008f0 ++#define FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_LBN 66 ++#define FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_WIDTH 1 ++#define FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_LBN 65 ++#define FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_WIDTH 1 ++#define FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_LBN 64 ++#define FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_WIDTH 1 ++#define FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN 0 ++#define FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH 64 ++ ++/* TX_FLUSH_DESCQ_REG: Transmit flush descriptor queue register */ ++#define FR_AZ_TX_FLUSH_DESCQ 0x00000a00 ++#define FRF_AZ_TX_FLUSH_DESCQ_CMD_LBN 12 ++#define FRF_AZ_TX_FLUSH_DESCQ_CMD_WIDTH 1 ++#define FRF_AZ_TX_FLUSH_DESCQ_LBN 0 ++#define FRF_AZ_TX_FLUSH_DESCQ_WIDTH 12 ++ ++/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */ ++#define FR_BZ_TX_DESC_UPD_P0 0x00000a10 ++#define FR_BZ_TX_DESC_UPD_P0_STEP 8192 ++#define FR_BZ_TX_DESC_UPD_P0_ROWS 1024 ++/* TX_DESC_UPD_REG_KER: Transmit descriptor update register. */ ++#define FR_AA_TX_DESC_UPD_KER 0x00000a10 ++#define FR_AA_TX_DESC_UPD_KER_STEP 8192 ++#define FR_AA_TX_DESC_UPD_KER_ROWS 8 ++/* TX_DESC_UPD_REGP123: Transmit descriptor update register. */ ++#define FR_BB_TX_DESC_UPD_P123 0x01000a10 ++#define FR_BB_TX_DESC_UPD_P123_STEP 8192 ++#define FR_BB_TX_DESC_UPD_P123_ROWS 3072 ++#define FRF_AZ_TX_DESC_WPTR_LBN 96 ++#define FRF_AZ_TX_DESC_WPTR_WIDTH 12 ++#define FRF_AZ_TX_DESC_PUSH_CMD_LBN 95 ++#define FRF_AZ_TX_DESC_PUSH_CMD_WIDTH 1 ++#define FRF_AZ_TX_DESC_LBN 0 ++#define FRF_AZ_TX_DESC_WIDTH 95 ++ ++/* TX_DC_CFG_REG: Transmit descriptor cache configuration register */ ++#define FR_AZ_TX_DC_CFG 0x00000a20 ++#define FRF_AZ_TX_DC_SIZE_LBN 0 ++#define FRF_AZ_TX_DC_SIZE_WIDTH 2 ++#define FFE_AZ_TX_DC_SIZE_32 2 ++#define FFE_AZ_TX_DC_SIZE_16 1 ++#define FFE_AZ_TX_DC_SIZE_8 0 ++ ++/* TX_CHKSM_CFG_REG: Transmit checksum configuration register */ ++#define FR_AA_TX_CHKSM_CFG 0x00000a30 ++#define FRF_AA_TX_Q_CHKSM_DIS_96_127_LBN 96 ++#define FRF_AA_TX_Q_CHKSM_DIS_96_127_WIDTH 32 ++#define FRF_AA_TX_Q_CHKSM_DIS_64_95_LBN 64 ++#define FRF_AA_TX_Q_CHKSM_DIS_64_95_WIDTH 32 ++#define FRF_AA_TX_Q_CHKSM_DIS_32_63_LBN 32 ++#define FRF_AA_TX_Q_CHKSM_DIS_32_63_WIDTH 32 ++#define FRF_AA_TX_Q_CHKSM_DIS_0_31_LBN 0 ++#define FRF_AA_TX_Q_CHKSM_DIS_0_31_WIDTH 32 ++ ++/* TX_CFG_REG: Transmit configuration register */ ++#define FR_AZ_TX_CFG 0x00000a50 ++#define FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_LBN 114 ++#define FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_WIDTH 8 ++#define FRF_CZ_TX_FILTER_TEST_MODE_BIT_LBN 113 ++#define FRF_CZ_TX_FILTER_TEST_MODE_BIT_WIDTH 1 ++#define FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_LBN 105 ++#define FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_WIDTH 8 ++#define FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_LBN 97 ++#define FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_WIDTH 8 ++#define FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_LBN 89 ++#define FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8 ++#define FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_LBN 81 ++#define FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8 ++#define FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_LBN 73 ++#define FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8 ++#define FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_LBN 65 ++#define FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8 ++#define FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_LBN 64 ++#define FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_WIDTH 1 ++#define FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_LBN 48 ++#define FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_WIDTH 16 ++#define FRF_CZ_TX_FILTER_EN_BIT_LBN 47 ++#define FRF_CZ_TX_FILTER_EN_BIT_WIDTH 1 ++#define FRF_AZ_TX_IP_ID_P0_OFS_LBN 16 ++#define FRF_AZ_TX_IP_ID_P0_OFS_WIDTH 15 ++#define FRF_AZ_TX_NO_EOP_DISC_EN_LBN 5 ++#define FRF_AZ_TX_NO_EOP_DISC_EN_WIDTH 1 ++#define FRF_AZ_TX_P1_PRI_EN_LBN 4 ++#define FRF_AZ_TX_P1_PRI_EN_WIDTH 1 ++#define FRF_AZ_TX_OWNERR_CTL_LBN 2 ++#define FRF_AZ_TX_OWNERR_CTL_WIDTH 1 ++#define FRF_AA_TX_NON_IP_DROP_DIS_LBN 1 ++#define FRF_AA_TX_NON_IP_DROP_DIS_WIDTH 1 ++#define FRF_AZ_TX_IP_ID_REP_EN_LBN 0 ++#define FRF_AZ_TX_IP_ID_REP_EN_WIDTH 1 ++ ++/* TX_PUSH_DROP_REG: Transmit push dropped register */ ++#define FR_AZ_TX_PUSH_DROP 0x00000a60 ++#define FRF_AZ_TX_PUSH_DROP_CNT_LBN 0 ++#define FRF_AZ_TX_PUSH_DROP_CNT_WIDTH 32 ++ ++/* TX_RESERVED_REG: Transmit configuration register */ ++#define FR_AZ_TX_RESERVED 0x00000a80 ++#define FRF_AZ_TX_EVT_CNT_LBN 121 ++#define FRF_AZ_TX_EVT_CNT_WIDTH 7 ++#define FRF_AZ_TX_PREF_AGE_CNT_LBN 119 ++#define FRF_AZ_TX_PREF_AGE_CNT_WIDTH 2 ++#define FRF_AZ_TX_RD_COMP_TMR_LBN 96 ++#define FRF_AZ_TX_RD_COMP_TMR_WIDTH 23 ++#define FRF_AZ_TX_PUSH_EN_LBN 89 ++#define FRF_AZ_TX_PUSH_EN_WIDTH 1 ++#define FRF_AZ_TX_PUSH_CHK_DIS_LBN 88 ++#define FRF_AZ_TX_PUSH_CHK_DIS_WIDTH 1 ++#define FRF_AZ_TX_D_FF_FULL_P0_LBN 85 ++#define FRF_AZ_TX_D_FF_FULL_P0_WIDTH 1 ++#define FRF_AZ_TX_DMAR_ST_P0_LBN 81 ++#define FRF_AZ_TX_DMAR_ST_P0_WIDTH 1 ++#define FRF_AZ_TX_DMAQ_ST_LBN 78 ++#define FRF_AZ_TX_DMAQ_ST_WIDTH 1 ++#define FRF_AZ_TX_RX_SPACER_LBN 64 ++#define FRF_AZ_TX_RX_SPACER_WIDTH 8 ++#define FRF_AZ_TX_DROP_ABORT_EN_LBN 60 ++#define FRF_AZ_TX_DROP_ABORT_EN_WIDTH 1 ++#define FRF_AZ_TX_SOFT_EVT_EN_LBN 59 ++#define FRF_AZ_TX_SOFT_EVT_EN_WIDTH 1 ++#define FRF_AZ_TX_PS_EVT_DIS_LBN 58 ++#define FRF_AZ_TX_PS_EVT_DIS_WIDTH 1 ++#define FRF_AZ_TX_RX_SPACER_EN_LBN 57 ++#define FRF_AZ_TX_RX_SPACER_EN_WIDTH 1 ++#define FRF_AZ_TX_XP_TIMER_LBN 52 ++#define FRF_AZ_TX_XP_TIMER_WIDTH 5 ++#define FRF_AZ_TX_PREF_SPACER_LBN 44 ++#define FRF_AZ_TX_PREF_SPACER_WIDTH 8 ++#define FRF_AZ_TX_PREF_WD_TMR_LBN 22 ++#define FRF_AZ_TX_PREF_WD_TMR_WIDTH 22 ++#define FRF_AZ_TX_ONLY1TAG_LBN 21 ++#define FRF_AZ_TX_ONLY1TAG_WIDTH 1 ++#define FRF_AZ_TX_PREF_THRESHOLD_LBN 19 ++#define FRF_AZ_TX_PREF_THRESHOLD_WIDTH 2 ++#define FRF_AZ_TX_ONE_PKT_PER_Q_LBN 18 ++#define FRF_AZ_TX_ONE_PKT_PER_Q_WIDTH 1 ++#define FRF_AZ_TX_DIS_NON_IP_EV_LBN 17 ++#define FRF_AZ_TX_DIS_NON_IP_EV_WIDTH 1 ++#define FRF_AA_TX_DMA_FF_THR_LBN 16 ++#define FRF_AA_TX_DMA_FF_THR_WIDTH 1 ++#define FRF_AZ_TX_DMA_SPACER_LBN 8 ++#define FRF_AZ_TX_DMA_SPACER_WIDTH 8 ++#define FRF_AA_TX_TCP_DIS_LBN 7 ++#define FRF_AA_TX_TCP_DIS_WIDTH 1 ++#define FRF_BZ_TX_FLUSH_MIN_LEN_EN_LBN 7 ++#define FRF_BZ_TX_FLUSH_MIN_LEN_EN_WIDTH 1 ++#define FRF_AA_TX_IP_DIS_LBN 6 ++#define FRF_AA_TX_IP_DIS_WIDTH 1 ++#define FRF_AZ_TX_MAX_CPL_LBN 2 ++#define FRF_AZ_TX_MAX_CPL_WIDTH 2 ++#define FFE_AZ_TX_MAX_CPL_16 3 ++#define FFE_AZ_TX_MAX_CPL_8 2 ++#define FFE_AZ_TX_MAX_CPL_4 1 ++#define FFE_AZ_TX_MAX_CPL_NOLIMIT 0 ++#define FRF_AZ_TX_MAX_PREF_LBN 0 ++#define FRF_AZ_TX_MAX_PREF_WIDTH 2 ++#define FFE_AZ_TX_MAX_PREF_32 3 ++#define FFE_AZ_TX_MAX_PREF_16 2 ++#define FFE_AZ_TX_MAX_PREF_8 1 ++#define FFE_AZ_TX_MAX_PREF_OFF 0 ++ ++/* TX_PACE_REG: Transmit pace control register */ ++#define FR_BZ_TX_PACE 0x00000a90 ++#define FRF_BZ_TX_PACE_SB_NOT_AF_LBN 19 ++#define FRF_BZ_TX_PACE_SB_NOT_AF_WIDTH 10 ++#define FRF_BZ_TX_PACE_SB_AF_LBN 9 ++#define FRF_BZ_TX_PACE_SB_AF_WIDTH 10 ++#define FRF_BZ_TX_PACE_FB_BASE_LBN 5 ++#define FRF_BZ_TX_PACE_FB_BASE_WIDTH 4 ++#define FRF_BZ_TX_PACE_BIN_TH_LBN 0 ++#define FRF_BZ_TX_PACE_BIN_TH_WIDTH 5 ++ ++/* TX_PACE_DROP_QID_REG: PACE Drop QID Counter */ ++#define FR_BZ_TX_PACE_DROP_QID 0x00000aa0 ++#define FRF_BZ_TX_PACE_QID_DRP_CNT_LBN 0 ++#define FRF_BZ_TX_PACE_QID_DRP_CNT_WIDTH 16 ++ ++/* TX_VLAN_REG: Transmit VLAN tag register */ ++#define FR_BB_TX_VLAN 0x00000ae0 ++#define FRF_BB_TX_VLAN_EN_LBN 127 ++#define FRF_BB_TX_VLAN_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN7_PORT1_EN_LBN 125 ++#define FRF_BB_TX_VLAN7_PORT1_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN7_PORT0_EN_LBN 124 ++#define FRF_BB_TX_VLAN7_PORT0_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN7_LBN 112 ++#define FRF_BB_TX_VLAN7_WIDTH 12 ++#define FRF_BB_TX_VLAN6_PORT1_EN_LBN 109 ++#define FRF_BB_TX_VLAN6_PORT1_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN6_PORT0_EN_LBN 108 ++#define FRF_BB_TX_VLAN6_PORT0_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN6_LBN 96 ++#define FRF_BB_TX_VLAN6_WIDTH 12 ++#define FRF_BB_TX_VLAN5_PORT1_EN_LBN 93 ++#define FRF_BB_TX_VLAN5_PORT1_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN5_PORT0_EN_LBN 92 ++#define FRF_BB_TX_VLAN5_PORT0_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN5_LBN 80 ++#define FRF_BB_TX_VLAN5_WIDTH 12 ++#define FRF_BB_TX_VLAN4_PORT1_EN_LBN 77 ++#define FRF_BB_TX_VLAN4_PORT1_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN4_PORT0_EN_LBN 76 ++#define FRF_BB_TX_VLAN4_PORT0_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN4_LBN 64 ++#define FRF_BB_TX_VLAN4_WIDTH 12 ++#define FRF_BB_TX_VLAN3_PORT1_EN_LBN 61 ++#define FRF_BB_TX_VLAN3_PORT1_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN3_PORT0_EN_LBN 60 ++#define FRF_BB_TX_VLAN3_PORT0_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN3_LBN 48 ++#define FRF_BB_TX_VLAN3_WIDTH 12 ++#define FRF_BB_TX_VLAN2_PORT1_EN_LBN 45 ++#define FRF_BB_TX_VLAN2_PORT1_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN2_PORT0_EN_LBN 44 ++#define FRF_BB_TX_VLAN2_PORT0_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN2_LBN 32 ++#define FRF_BB_TX_VLAN2_WIDTH 12 ++#define FRF_BB_TX_VLAN1_PORT1_EN_LBN 29 ++#define FRF_BB_TX_VLAN1_PORT1_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN1_PORT0_EN_LBN 28 ++#define FRF_BB_TX_VLAN1_PORT0_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN1_LBN 16 ++#define FRF_BB_TX_VLAN1_WIDTH 12 ++#define FRF_BB_TX_VLAN0_PORT1_EN_LBN 13 ++#define FRF_BB_TX_VLAN0_PORT1_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN0_PORT0_EN_LBN 12 ++#define FRF_BB_TX_VLAN0_PORT0_EN_WIDTH 1 ++#define FRF_BB_TX_VLAN0_LBN 0 ++#define FRF_BB_TX_VLAN0_WIDTH 12 ++ ++/* TX_IPFIL_PORTEN_REG: Transmit filter control register */ ++#define FR_BZ_TX_IPFIL_PORTEN 0x00000af0 ++#define FRF_BZ_TX_MADR0_FIL_EN_LBN 64 ++#define FRF_BZ_TX_MADR0_FIL_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL31_PORT_EN_LBN 62 ++#define FRF_BB_TX_IPFIL31_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL30_PORT_EN_LBN 60 ++#define FRF_BB_TX_IPFIL30_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL29_PORT_EN_LBN 58 ++#define FRF_BB_TX_IPFIL29_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL28_PORT_EN_LBN 56 ++#define FRF_BB_TX_IPFIL28_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL27_PORT_EN_LBN 54 ++#define FRF_BB_TX_IPFIL27_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL26_PORT_EN_LBN 52 ++#define FRF_BB_TX_IPFIL26_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL25_PORT_EN_LBN 50 ++#define FRF_BB_TX_IPFIL25_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL24_PORT_EN_LBN 48 ++#define FRF_BB_TX_IPFIL24_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL23_PORT_EN_LBN 46 ++#define FRF_BB_TX_IPFIL23_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL22_PORT_EN_LBN 44 ++#define FRF_BB_TX_IPFIL22_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL21_PORT_EN_LBN 42 ++#define FRF_BB_TX_IPFIL21_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL20_PORT_EN_LBN 40 ++#define FRF_BB_TX_IPFIL20_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL19_PORT_EN_LBN 38 ++#define FRF_BB_TX_IPFIL19_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL18_PORT_EN_LBN 36 ++#define FRF_BB_TX_IPFIL18_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL17_PORT_EN_LBN 34 ++#define FRF_BB_TX_IPFIL17_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL16_PORT_EN_LBN 32 ++#define FRF_BB_TX_IPFIL16_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL15_PORT_EN_LBN 30 ++#define FRF_BB_TX_IPFIL15_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL14_PORT_EN_LBN 28 ++#define FRF_BB_TX_IPFIL14_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL13_PORT_EN_LBN 26 ++#define FRF_BB_TX_IPFIL13_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL12_PORT_EN_LBN 24 ++#define FRF_BB_TX_IPFIL12_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL11_PORT_EN_LBN 22 ++#define FRF_BB_TX_IPFIL11_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL10_PORT_EN_LBN 20 ++#define FRF_BB_TX_IPFIL10_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL9_PORT_EN_LBN 18 ++#define FRF_BB_TX_IPFIL9_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL8_PORT_EN_LBN 16 ++#define FRF_BB_TX_IPFIL8_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL7_PORT_EN_LBN 14 ++#define FRF_BB_TX_IPFIL7_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL6_PORT_EN_LBN 12 ++#define FRF_BB_TX_IPFIL6_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL5_PORT_EN_LBN 10 ++#define FRF_BB_TX_IPFIL5_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL4_PORT_EN_LBN 8 ++#define FRF_BB_TX_IPFIL4_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL3_PORT_EN_LBN 6 ++#define FRF_BB_TX_IPFIL3_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL2_PORT_EN_LBN 4 ++#define FRF_BB_TX_IPFIL2_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL1_PORT_EN_LBN 2 ++#define FRF_BB_TX_IPFIL1_PORT_EN_WIDTH 1 ++#define FRF_BB_TX_IPFIL0_PORT_EN_LBN 0 ++#define FRF_BB_TX_IPFIL0_PORT_EN_WIDTH 1 ++ ++/* TX_IPFIL_TBL: Transmit IP source address filter table */ ++#define FR_BB_TX_IPFIL_TBL 0x00000b00 ++#define FR_BB_TX_IPFIL_TBL_STEP 16 ++#define FR_BB_TX_IPFIL_TBL_ROWS 16 ++#define FRF_BB_TX_IPFIL_MASK_1_LBN 96 ++#define FRF_BB_TX_IPFIL_MASK_1_WIDTH 32 ++#define FRF_BB_TX_IP_SRC_ADR_1_LBN 64 ++#define FRF_BB_TX_IP_SRC_ADR_1_WIDTH 32 ++#define FRF_BB_TX_IPFIL_MASK_0_LBN 32 ++#define FRF_BB_TX_IPFIL_MASK_0_WIDTH 32 ++#define FRF_BB_TX_IP_SRC_ADR_0_LBN 0 ++#define FRF_BB_TX_IP_SRC_ADR_0_WIDTH 32 ++ ++/* MD_TXD_REG: PHY management transmit data register */ ++#define FR_AB_MD_TXD 0x00000c00 ++#define FRF_AB_MD_TXD_LBN 0 ++#define FRF_AB_MD_TXD_WIDTH 16 ++ ++/* MD_RXD_REG: PHY management receive data register */ ++#define FR_AB_MD_RXD 0x00000c10 ++#define FRF_AB_MD_RXD_LBN 0 ++#define FRF_AB_MD_RXD_WIDTH 16 ++ ++/* MD_CS_REG: PHY management configuration & status register */ ++#define FR_AB_MD_CS 0x00000c20 ++#define FRF_AB_MD_RD_EN_CMD_LBN 15 ++#define FRF_AB_MD_RD_EN_CMD_WIDTH 1 ++#define FRF_AB_MD_WR_EN_CMD_LBN 14 ++#define FRF_AB_MD_WR_EN_CMD_WIDTH 1 ++#define FRF_AB_MD_ADDR_CMD_LBN 13 ++#define FRF_AB_MD_ADDR_CMD_WIDTH 1 ++#define FRF_AB_MD_PT_LBN 7 ++#define FRF_AB_MD_PT_WIDTH 3 ++#define FRF_AB_MD_PL_LBN 6 ++#define FRF_AB_MD_PL_WIDTH 1 ++#define FRF_AB_MD_INT_CLR_LBN 5 ++#define FRF_AB_MD_INT_CLR_WIDTH 1 ++#define FRF_AB_MD_GC_LBN 4 ++#define FRF_AB_MD_GC_WIDTH 1 ++#define FRF_AB_MD_PRSP_LBN 3 ++#define FRF_AB_MD_PRSP_WIDTH 1 ++#define FRF_AB_MD_RIC_LBN 2 ++#define FRF_AB_MD_RIC_WIDTH 1 ++#define FRF_AB_MD_RDC_LBN 1 ++#define FRF_AB_MD_RDC_WIDTH 1 ++#define FRF_AB_MD_WRC_LBN 0 ++#define FRF_AB_MD_WRC_WIDTH 1 ++ ++/* MD_PHY_ADR_REG: PHY management PHY address register */ ++#define FR_AB_MD_PHY_ADR 0x00000c30 ++#define FRF_AB_MD_PHY_ADR_LBN 0 ++#define FRF_AB_MD_PHY_ADR_WIDTH 16 ++ ++/* MD_ID_REG: PHY management ID register */ ++#define FR_AB_MD_ID 0x00000c40 ++#define FRF_AB_MD_PRT_ADR_LBN 11 ++#define FRF_AB_MD_PRT_ADR_WIDTH 5 ++#define FRF_AB_MD_DEV_ADR_LBN 6 ++#define FRF_AB_MD_DEV_ADR_WIDTH 5 ++ ++/* MD_STAT_REG: PHY management status & mask register */ ++#define FR_AB_MD_STAT 0x00000c50 ++#define FRF_AB_MD_PINT_LBN 4 ++#define FRF_AB_MD_PINT_WIDTH 1 ++#define FRF_AB_MD_DONE_LBN 3 ++#define FRF_AB_MD_DONE_WIDTH 1 ++#define FRF_AB_MD_BSERR_LBN 2 ++#define FRF_AB_MD_BSERR_WIDTH 1 ++#define FRF_AB_MD_LNFL_LBN 1 ++#define FRF_AB_MD_LNFL_WIDTH 1 ++#define FRF_AB_MD_BSY_LBN 0 ++#define FRF_AB_MD_BSY_WIDTH 1 ++ ++/* MAC_STAT_DMA_REG: Port MAC statistical counter DMA register */ ++#define FR_AB_MAC_STAT_DMA 0x00000c60 ++#define FRF_AB_MAC_STAT_DMA_CMD_LBN 48 ++#define FRF_AB_MAC_STAT_DMA_CMD_WIDTH 1 ++#define FRF_AB_MAC_STAT_DMA_ADR_LBN 0 ++#define FRF_AB_MAC_STAT_DMA_ADR_WIDTH 48 ++ ++/* MAC_CTRL_REG: Port MAC control register */ ++#define FR_AB_MAC_CTRL 0x00000c80 ++#define FRF_AB_MAC_XOFF_VAL_LBN 16 ++#define FRF_AB_MAC_XOFF_VAL_WIDTH 16 ++#define FRF_BB_TXFIFO_DRAIN_EN_LBN 7 ++#define FRF_BB_TXFIFO_DRAIN_EN_WIDTH 1 ++#define FRF_AB_MAC_XG_DISTXCRC_LBN 5 ++#define FRF_AB_MAC_XG_DISTXCRC_WIDTH 1 ++#define FRF_AB_MAC_BCAD_ACPT_LBN 4 ++#define FRF_AB_MAC_BCAD_ACPT_WIDTH 1 ++#define FRF_AB_MAC_UC_PROM_LBN 3 ++#define FRF_AB_MAC_UC_PROM_WIDTH 1 ++#define FRF_AB_MAC_LINK_STATUS_LBN 2 ++#define FRF_AB_MAC_LINK_STATUS_WIDTH 1 ++#define FRF_AB_MAC_SPEED_LBN 0 ++#define FRF_AB_MAC_SPEED_WIDTH 2 ++#define FFE_AB_MAC_SPEED_10G 3 ++#define FFE_AB_MAC_SPEED_1G 2 ++#define FFE_AB_MAC_SPEED_100M 1 ++#define FFE_AB_MAC_SPEED_10M 0 ++ ++/* GEN_MODE_REG: General Purpose mode register (external interrupt mask) */ ++#define FR_BB_GEN_MODE 0x00000c90 ++#define FRF_BB_XFP_PHY_INT_POL_SEL_LBN 3 ++#define FRF_BB_XFP_PHY_INT_POL_SEL_WIDTH 1 ++#define FRF_BB_XG_PHY_INT_POL_SEL_LBN 2 ++#define FRF_BB_XG_PHY_INT_POL_SEL_WIDTH 1 ++#define FRF_BB_XFP_PHY_INT_MASK_LBN 1 ++#define FRF_BB_XFP_PHY_INT_MASK_WIDTH 1 ++#define FRF_BB_XG_PHY_INT_MASK_LBN 0 ++#define FRF_BB_XG_PHY_INT_MASK_WIDTH 1 ++ ++/* MAC_MC_HASH_REG0: Multicast address hash table */ ++#define FR_AB_MAC_MC_HASH_REG0 0x00000ca0 ++#define FRF_AB_MAC_MCAST_HASH0_LBN 0 ++#define FRF_AB_MAC_MCAST_HASH0_WIDTH 128 ++ ++/* MAC_MC_HASH_REG1: Multicast address hash table */ ++#define FR_AB_MAC_MC_HASH_REG1 0x00000cb0 ++#define FRF_AB_MAC_MCAST_HASH1_LBN 0 ++#define FRF_AB_MAC_MCAST_HASH1_WIDTH 128 ++ ++/* GM_CFG1_REG: GMAC configuration register 1 */ ++#define FR_AB_GM_CFG1 0x00000e00 ++#define FRF_AB_GM_SW_RST_LBN 31 ++#define FRF_AB_GM_SW_RST_WIDTH 1 ++#define FRF_AB_GM_SIM_RST_LBN 30 ++#define FRF_AB_GM_SIM_RST_WIDTH 1 ++#define FRF_AB_GM_RST_RX_MAC_CTL_LBN 19 ++#define FRF_AB_GM_RST_RX_MAC_CTL_WIDTH 1 ++#define FRF_AB_GM_RST_TX_MAC_CTL_LBN 18 ++#define FRF_AB_GM_RST_TX_MAC_CTL_WIDTH 1 ++#define FRF_AB_GM_RST_RX_FUNC_LBN 17 ++#define FRF_AB_GM_RST_RX_FUNC_WIDTH 1 ++#define FRF_AB_GM_RST_TX_FUNC_LBN 16 ++#define FRF_AB_GM_RST_TX_FUNC_WIDTH 1 ++#define FRF_AB_GM_LOOP_LBN 8 ++#define FRF_AB_GM_LOOP_WIDTH 1 ++#define FRF_AB_GM_RX_FC_EN_LBN 5 ++#define FRF_AB_GM_RX_FC_EN_WIDTH 1 ++#define FRF_AB_GM_TX_FC_EN_LBN 4 ++#define FRF_AB_GM_TX_FC_EN_WIDTH 1 ++#define FRF_AB_GM_SYNC_RXEN_LBN 3 ++#define FRF_AB_GM_SYNC_RXEN_WIDTH 1 ++#define FRF_AB_GM_RX_EN_LBN 2 ++#define FRF_AB_GM_RX_EN_WIDTH 1 ++#define FRF_AB_GM_SYNC_TXEN_LBN 1 ++#define FRF_AB_GM_SYNC_TXEN_WIDTH 1 ++#define FRF_AB_GM_TX_EN_LBN 0 ++#define FRF_AB_GM_TX_EN_WIDTH 1 ++ ++/* GM_CFG2_REG: GMAC configuration register 2 */ ++#define FR_AB_GM_CFG2 0x00000e10 ++#define FRF_AB_GM_PAMBL_LEN_LBN 12 ++#define FRF_AB_GM_PAMBL_LEN_WIDTH 4 ++#define FRF_AB_GM_IF_MODE_LBN 8 ++#define FRF_AB_GM_IF_MODE_WIDTH 2 ++#define FFE_AB_IF_MODE_BYTE_MODE 2 ++#define FFE_AB_IF_MODE_NIBBLE_MODE 1 ++#define FRF_AB_GM_HUGE_FRM_EN_LBN 5 ++#define FRF_AB_GM_HUGE_FRM_EN_WIDTH 1 ++#define FRF_AB_GM_LEN_CHK_LBN 4 ++#define FRF_AB_GM_LEN_CHK_WIDTH 1 ++#define FRF_AB_GM_PAD_CRC_EN_LBN 2 ++#define FRF_AB_GM_PAD_CRC_EN_WIDTH 1 ++#define FRF_AB_GM_CRC_EN_LBN 1 ++#define FRF_AB_GM_CRC_EN_WIDTH 1 ++#define FRF_AB_GM_FD_LBN 0 ++#define FRF_AB_GM_FD_WIDTH 1 ++ ++/* GM_IPG_REG: GMAC IPG register */ ++#define FR_AB_GM_IPG 0x00000e20 ++#define FRF_AB_GM_NONB2B_IPG1_LBN 24 ++#define FRF_AB_GM_NONB2B_IPG1_WIDTH 7 ++#define FRF_AB_GM_NONB2B_IPG2_LBN 16 ++#define FRF_AB_GM_NONB2B_IPG2_WIDTH 7 ++#define FRF_AB_GM_MIN_IPG_ENF_LBN 8 ++#define FRF_AB_GM_MIN_IPG_ENF_WIDTH 8 ++#define FRF_AB_GM_B2B_IPG_LBN 0 ++#define FRF_AB_GM_B2B_IPG_WIDTH 7 ++ ++/* GM_HD_REG: GMAC half duplex register */ ++#define FR_AB_GM_HD 0x00000e30 ++#define FRF_AB_GM_ALT_BOFF_VAL_LBN 20 ++#define FRF_AB_GM_ALT_BOFF_VAL_WIDTH 4 ++#define FRF_AB_GM_ALT_BOFF_EN_LBN 19 ++#define FRF_AB_GM_ALT_BOFF_EN_WIDTH 1 ++#define FRF_AB_GM_BP_NO_BOFF_LBN 18 ++#define FRF_AB_GM_BP_NO_BOFF_WIDTH 1 ++#define FRF_AB_GM_DIS_BOFF_LBN 17 ++#define FRF_AB_GM_DIS_BOFF_WIDTH 1 ++#define FRF_AB_GM_EXDEF_TX_EN_LBN 16 ++#define FRF_AB_GM_EXDEF_TX_EN_WIDTH 1 ++#define FRF_AB_GM_RTRY_LIMIT_LBN 12 ++#define FRF_AB_GM_RTRY_LIMIT_WIDTH 4 ++#define FRF_AB_GM_COL_WIN_LBN 0 ++#define FRF_AB_GM_COL_WIN_WIDTH 10 ++ ++/* GM_MAX_FLEN_REG: GMAC maximum frame length register */ ++#define FR_AB_GM_MAX_FLEN 0x00000e40 ++#define FRF_AB_GM_MAX_FLEN_LBN 0 ++#define FRF_AB_GM_MAX_FLEN_WIDTH 16 ++ ++/* GM_TEST_REG: GMAC test register */ ++#define FR_AB_GM_TEST 0x00000e70 ++#define FRF_AB_GM_MAX_BOFF_LBN 3 ++#define FRF_AB_GM_MAX_BOFF_WIDTH 1 ++#define FRF_AB_GM_REG_TX_FLOW_EN_LBN 2 ++#define FRF_AB_GM_REG_TX_FLOW_EN_WIDTH 1 ++#define FRF_AB_GM_TEST_PAUSE_LBN 1 ++#define FRF_AB_GM_TEST_PAUSE_WIDTH 1 ++#define FRF_AB_GM_SHORT_SLOT_LBN 0 ++#define FRF_AB_GM_SHORT_SLOT_WIDTH 1 ++ ++/* GM_ADR1_REG: GMAC station address register 1 */ ++#define FR_AB_GM_ADR1 0x00000f00 ++#define FRF_AB_GM_ADR_B0_LBN 24 ++#define FRF_AB_GM_ADR_B0_WIDTH 8 ++#define FRF_AB_GM_ADR_B1_LBN 16 ++#define FRF_AB_GM_ADR_B1_WIDTH 8 ++#define FRF_AB_GM_ADR_B2_LBN 8 ++#define FRF_AB_GM_ADR_B2_WIDTH 8 ++#define FRF_AB_GM_ADR_B3_LBN 0 ++#define FRF_AB_GM_ADR_B3_WIDTH 8 ++ ++/* GM_ADR2_REG: GMAC station address register 2 */ ++#define FR_AB_GM_ADR2 0x00000f10 ++#define FRF_AB_GM_ADR_B4_LBN 24 ++#define FRF_AB_GM_ADR_B4_WIDTH 8 ++#define FRF_AB_GM_ADR_B5_LBN 16 ++#define FRF_AB_GM_ADR_B5_WIDTH 8 ++ ++/* GMF_CFG0_REG: GMAC FIFO configuration register 0 */ ++#define FR_AB_GMF_CFG0 0x00000f20 ++#define FRF_AB_GMF_FTFENRPLY_LBN 20 ++#define FRF_AB_GMF_FTFENRPLY_WIDTH 1 ++#define FRF_AB_GMF_STFENRPLY_LBN 19 ++#define FRF_AB_GMF_STFENRPLY_WIDTH 1 ++#define FRF_AB_GMF_FRFENRPLY_LBN 18 ++#define FRF_AB_GMF_FRFENRPLY_WIDTH 1 ++#define FRF_AB_GMF_SRFENRPLY_LBN 17 ++#define FRF_AB_GMF_SRFENRPLY_WIDTH 1 ++#define FRF_AB_GMF_WTMENRPLY_LBN 16 ++#define FRF_AB_GMF_WTMENRPLY_WIDTH 1 ++#define FRF_AB_GMF_FTFENREQ_LBN 12 ++#define FRF_AB_GMF_FTFENREQ_WIDTH 1 ++#define FRF_AB_GMF_STFENREQ_LBN 11 ++#define FRF_AB_GMF_STFENREQ_WIDTH 1 ++#define FRF_AB_GMF_FRFENREQ_LBN 10 ++#define FRF_AB_GMF_FRFENREQ_WIDTH 1 ++#define FRF_AB_GMF_SRFENREQ_LBN 9 ++#define FRF_AB_GMF_SRFENREQ_WIDTH 1 ++#define FRF_AB_GMF_WTMENREQ_LBN 8 ++#define FRF_AB_GMF_WTMENREQ_WIDTH 1 ++#define FRF_AB_GMF_HSTRSTFT_LBN 4 ++#define FRF_AB_GMF_HSTRSTFT_WIDTH 1 ++#define FRF_AB_GMF_HSTRSTST_LBN 3 ++#define FRF_AB_GMF_HSTRSTST_WIDTH 1 ++#define FRF_AB_GMF_HSTRSTFR_LBN 2 ++#define FRF_AB_GMF_HSTRSTFR_WIDTH 1 ++#define FRF_AB_GMF_HSTRSTSR_LBN 1 ++#define FRF_AB_GMF_HSTRSTSR_WIDTH 1 ++#define FRF_AB_GMF_HSTRSTWT_LBN 0 ++#define FRF_AB_GMF_HSTRSTWT_WIDTH 1 ++ ++/* GMF_CFG1_REG: GMAC FIFO configuration register 1 */ ++#define FR_AB_GMF_CFG1 0x00000f30 ++#define FRF_AB_GMF_CFGFRTH_LBN 16 ++#define FRF_AB_GMF_CFGFRTH_WIDTH 5 ++#define FRF_AB_GMF_CFGXOFFRTX_LBN 0 ++#define FRF_AB_GMF_CFGXOFFRTX_WIDTH 16 ++ ++/* GMF_CFG2_REG: GMAC FIFO configuration register 2 */ ++#define FR_AB_GMF_CFG2 0x00000f40 ++#define FRF_AB_GMF_CFGHWM_LBN 16 ++#define FRF_AB_GMF_CFGHWM_WIDTH 6 ++#define FRF_AB_GMF_CFGLWM_LBN 0 ++#define FRF_AB_GMF_CFGLWM_WIDTH 6 ++ ++/* GMF_CFG3_REG: GMAC FIFO configuration register 3 */ ++#define FR_AB_GMF_CFG3 0x00000f50 ++#define FRF_AB_GMF_CFGHWMFT_LBN 16 ++#define FRF_AB_GMF_CFGHWMFT_WIDTH 6 ++#define FRF_AB_GMF_CFGFTTH_LBN 0 ++#define FRF_AB_GMF_CFGFTTH_WIDTH 6 ++ ++/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */ ++#define FR_AB_GMF_CFG4 0x00000f60 ++#define FRF_AB_GMF_HSTFLTRFRM_LBN 0 ++#define FRF_AB_GMF_HSTFLTRFRM_WIDTH 18 ++ ++/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */ ++#define FR_AB_GMF_CFG5 0x00000f70 ++#define FRF_AB_GMF_CFGHDPLX_LBN 22 ++#define FRF_AB_GMF_CFGHDPLX_WIDTH 1 ++#define FRF_AB_GMF_SRFULL_LBN 21 ++#define FRF_AB_GMF_SRFULL_WIDTH 1 ++#define FRF_AB_GMF_HSTSRFULLCLR_LBN 20 ++#define FRF_AB_GMF_HSTSRFULLCLR_WIDTH 1 ++#define FRF_AB_GMF_CFGBYTMODE_LBN 19 ++#define FRF_AB_GMF_CFGBYTMODE_WIDTH 1 ++#define FRF_AB_GMF_HSTDRPLT64_LBN 18 ++#define FRF_AB_GMF_HSTDRPLT64_WIDTH 1 ++#define FRF_AB_GMF_HSTFLTRFRMDC_LBN 0 ++#define FRF_AB_GMF_HSTFLTRFRMDC_WIDTH 18 ++ ++/* TX_SRC_MAC_TBL: Transmit IP source address filter table */ ++#define FR_BB_TX_SRC_MAC_TBL 0x00001000 ++#define FR_BB_TX_SRC_MAC_TBL_STEP 16 ++#define FR_BB_TX_SRC_MAC_TBL_ROWS 16 ++#define FRF_BB_TX_SRC_MAC_ADR_1_LBN 64 ++#define FRF_BB_TX_SRC_MAC_ADR_1_WIDTH 48 ++#define FRF_BB_TX_SRC_MAC_ADR_0_LBN 0 ++#define FRF_BB_TX_SRC_MAC_ADR_0_WIDTH 48 ++ ++/* TX_SRC_MAC_CTL_REG: Transmit MAC source address filter control */ ++#define FR_BB_TX_SRC_MAC_CTL 0x00001100 ++#define FRF_BB_TX_SRC_DROP_CTR_LBN 16 ++#define FRF_BB_TX_SRC_DROP_CTR_WIDTH 16 ++#define FRF_BB_TX_SRC_FLTR_EN_LBN 15 ++#define FRF_BB_TX_SRC_FLTR_EN_WIDTH 1 ++#define FRF_BB_TX_DROP_CTR_CLR_LBN 12 ++#define FRF_BB_TX_DROP_CTR_CLR_WIDTH 1 ++#define FRF_BB_TX_MAC_QID_SEL_LBN 0 ++#define FRF_BB_TX_MAC_QID_SEL_WIDTH 3 ++ ++/* XM_ADR_LO_REG: XGMAC address register low */ ++#define FR_AB_XM_ADR_LO 0x00001200 ++#define FRF_AB_XM_ADR_LO_LBN 0 ++#define FRF_AB_XM_ADR_LO_WIDTH 32 ++ ++/* XM_ADR_HI_REG: XGMAC address register high */ ++#define FR_AB_XM_ADR_HI 0x00001210 ++#define FRF_AB_XM_ADR_HI_LBN 0 ++#define FRF_AB_XM_ADR_HI_WIDTH 16 ++ ++/* XM_GLB_CFG_REG: XGMAC global configuration */ ++#define FR_AB_XM_GLB_CFG 0x00001220 ++#define FRF_AB_XM_RMTFLT_GEN_LBN 17 ++#define FRF_AB_XM_RMTFLT_GEN_WIDTH 1 ++#define FRF_AB_XM_DEBUG_MODE_LBN 16 ++#define FRF_AB_XM_DEBUG_MODE_WIDTH 1 ++#define FRF_AB_XM_RX_STAT_EN_LBN 11 ++#define FRF_AB_XM_RX_STAT_EN_WIDTH 1 ++#define FRF_AB_XM_TX_STAT_EN_LBN 10 ++#define FRF_AB_XM_TX_STAT_EN_WIDTH 1 ++#define FRF_AB_XM_RX_JUMBO_MODE_LBN 6 ++#define FRF_AB_XM_RX_JUMBO_MODE_WIDTH 1 ++#define FRF_AB_XM_WAN_MODE_LBN 5 ++#define FRF_AB_XM_WAN_MODE_WIDTH 1 ++#define FRF_AB_XM_INTCLR_MODE_LBN 3 ++#define FRF_AB_XM_INTCLR_MODE_WIDTH 1 ++#define FRF_AB_XM_CORE_RST_LBN 0 ++#define FRF_AB_XM_CORE_RST_WIDTH 1 ++ ++/* XM_TX_CFG_REG: XGMAC transmit configuration */ ++#define FR_AB_XM_TX_CFG 0x00001230 ++#define FRF_AB_XM_TX_PROG_LBN 24 ++#define FRF_AB_XM_TX_PROG_WIDTH 1 ++#define FRF_AB_XM_IPG_LBN 16 ++#define FRF_AB_XM_IPG_WIDTH 4 ++#define FRF_AB_XM_FCNTL_LBN 10 ++#define FRF_AB_XM_FCNTL_WIDTH 1 ++#define FRF_AB_XM_TXCRC_LBN 8 ++#define FRF_AB_XM_TXCRC_WIDTH 1 ++#define FRF_AB_XM_EDRC_LBN 6 ++#define FRF_AB_XM_EDRC_WIDTH 1 ++#define FRF_AB_XM_AUTO_PAD_LBN 5 ++#define FRF_AB_XM_AUTO_PAD_WIDTH 1 ++#define FRF_AB_XM_TX_PRMBL_LBN 2 ++#define FRF_AB_XM_TX_PRMBL_WIDTH 1 ++#define FRF_AB_XM_TXEN_LBN 1 ++#define FRF_AB_XM_TXEN_WIDTH 1 ++#define FRF_AB_XM_TX_RST_LBN 0 ++#define FRF_AB_XM_TX_RST_WIDTH 1 ++ ++/* XM_RX_CFG_REG: XGMAC receive configuration */ ++#define FR_AB_XM_RX_CFG 0x00001240 ++#define FRF_AB_XM_PASS_LENERR_LBN 26 ++#define FRF_AB_XM_PASS_LENERR_WIDTH 1 ++#define FRF_AB_XM_PASS_CRC_ERR_LBN 25 ++#define FRF_AB_XM_PASS_CRC_ERR_WIDTH 1 ++#define FRF_AB_XM_PASS_PRMBLE_ERR_LBN 24 ++#define FRF_AB_XM_PASS_PRMBLE_ERR_WIDTH 1 ++#define FRF_AB_XM_REJ_BCAST_LBN 20 ++#define FRF_AB_XM_REJ_BCAST_WIDTH 1 ++#define FRF_AB_XM_ACPT_ALL_MCAST_LBN 11 ++#define FRF_AB_XM_ACPT_ALL_MCAST_WIDTH 1 ++#define FRF_AB_XM_ACPT_ALL_UCAST_LBN 9 ++#define FRF_AB_XM_ACPT_ALL_UCAST_WIDTH 1 ++#define FRF_AB_XM_AUTO_DEPAD_LBN 8 ++#define FRF_AB_XM_AUTO_DEPAD_WIDTH 1 ++#define FRF_AB_XM_RXCRC_LBN 3 ++#define FRF_AB_XM_RXCRC_WIDTH 1 ++#define FRF_AB_XM_RX_PRMBL_LBN 2 ++#define FRF_AB_XM_RX_PRMBL_WIDTH 1 ++#define FRF_AB_XM_RXEN_LBN 1 ++#define FRF_AB_XM_RXEN_WIDTH 1 ++#define FRF_AB_XM_RX_RST_LBN 0 ++#define FRF_AB_XM_RX_RST_WIDTH 1 ++ ++/* XM_MGT_INT_MASK: documentation to be written for sum_XM_MGT_INT_MASK */ ++#define FR_AB_XM_MGT_INT_MASK 0x00001250 ++#define FRF_AB_XM_MSK_STA_INTR_LBN 16 ++#define FRF_AB_XM_MSK_STA_INTR_WIDTH 1 ++#define FRF_AB_XM_MSK_STAT_CNTR_HF_LBN 9 ++#define FRF_AB_XM_MSK_STAT_CNTR_HF_WIDTH 1 ++#define FRF_AB_XM_MSK_STAT_CNTR_OF_LBN 8 ++#define FRF_AB_XM_MSK_STAT_CNTR_OF_WIDTH 1 ++#define FRF_AB_XM_MSK_PRMBLE_ERR_LBN 2 ++#define FRF_AB_XM_MSK_PRMBLE_ERR_WIDTH 1 ++#define FRF_AB_XM_MSK_RMTFLT_LBN 1 ++#define FRF_AB_XM_MSK_RMTFLT_WIDTH 1 ++#define FRF_AB_XM_MSK_LCLFLT_LBN 0 ++#define FRF_AB_XM_MSK_LCLFLT_WIDTH 1 ++ ++/* XM_FC_REG: XGMAC flow control register */ ++#define FR_AB_XM_FC 0x00001270 ++#define FRF_AB_XM_PAUSE_TIME_LBN 16 ++#define FRF_AB_XM_PAUSE_TIME_WIDTH 16 ++#define FRF_AB_XM_RX_MAC_STAT_LBN 11 ++#define FRF_AB_XM_RX_MAC_STAT_WIDTH 1 ++#define FRF_AB_XM_TX_MAC_STAT_LBN 10 ++#define FRF_AB_XM_TX_MAC_STAT_WIDTH 1 ++#define FRF_AB_XM_MCNTL_PASS_LBN 8 ++#define FRF_AB_XM_MCNTL_PASS_WIDTH 2 ++#define FRF_AB_XM_REJ_CNTL_UCAST_LBN 6 ++#define FRF_AB_XM_REJ_CNTL_UCAST_WIDTH 1 ++#define FRF_AB_XM_REJ_CNTL_MCAST_LBN 5 ++#define FRF_AB_XM_REJ_CNTL_MCAST_WIDTH 1 ++#define FRF_AB_XM_ZPAUSE_LBN 2 ++#define FRF_AB_XM_ZPAUSE_WIDTH 1 ++#define FRF_AB_XM_XMIT_PAUSE_LBN 1 ++#define FRF_AB_XM_XMIT_PAUSE_WIDTH 1 ++#define FRF_AB_XM_DIS_FCNTL_LBN 0 ++#define FRF_AB_XM_DIS_FCNTL_WIDTH 1 ++ ++/* XM_PAUSE_TIME_REG: XGMAC pause time register */ ++#define FR_AB_XM_PAUSE_TIME 0x00001290 ++#define FRF_AB_XM_TX_PAUSE_CNT_LBN 16 ++#define FRF_AB_XM_TX_PAUSE_CNT_WIDTH 16 ++#define FRF_AB_XM_RX_PAUSE_CNT_LBN 0 ++#define FRF_AB_XM_RX_PAUSE_CNT_WIDTH 16 ++ ++/* XM_TX_PARAM_REG: XGMAC transmit parameter register */ ++#define FR_AB_XM_TX_PARAM 0x000012d0 ++#define FRF_AB_XM_TX_JUMBO_MODE_LBN 31 ++#define FRF_AB_XM_TX_JUMBO_MODE_WIDTH 1 ++#define FRF_AB_XM_MAX_TX_FRM_SIZE_HI_LBN 19 ++#define FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH 11 ++#define FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN 16 ++#define FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH 3 ++#define FRF_AB_XM_PAD_CHAR_LBN 0 ++#define FRF_AB_XM_PAD_CHAR_WIDTH 8 ++ ++/* XM_RX_PARAM_REG: XGMAC receive parameter register */ ++#define FR_AB_XM_RX_PARAM 0x000012e0 ++#define FRF_AB_XM_MAX_RX_FRM_SIZE_HI_LBN 3 ++#define FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH 11 ++#define FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN 0 ++#define FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH 3 ++ ++/* XM_MGT_INT_MSK_REG: XGMAC management interrupt mask register */ ++#define FR_AB_XM_MGT_INT_MSK 0x000012f0 ++#define FRF_AB_XM_STAT_CNTR_OF_LBN 9 ++#define FRF_AB_XM_STAT_CNTR_OF_WIDTH 1 ++#define FRF_AB_XM_STAT_CNTR_HF_LBN 8 ++#define FRF_AB_XM_STAT_CNTR_HF_WIDTH 1 ++#define FRF_AB_XM_PRMBLE_ERR_LBN 2 ++#define FRF_AB_XM_PRMBLE_ERR_WIDTH 1 ++#define FRF_AB_XM_RMTFLT_LBN 1 ++#define FRF_AB_XM_RMTFLT_WIDTH 1 ++#define FRF_AB_XM_LCLFLT_LBN 0 ++#define FRF_AB_XM_LCLFLT_WIDTH 1 ++ ++/* XX_PWR_RST_REG: XGXS/XAUI powerdown/reset register */ ++#define FR_AB_XX_PWR_RST 0x00001300 ++#define FRF_AB_XX_PWRDND_SIG_LBN 31 ++#define FRF_AB_XX_PWRDND_SIG_WIDTH 1 ++#define FRF_AB_XX_PWRDNC_SIG_LBN 30 ++#define FRF_AB_XX_PWRDNC_SIG_WIDTH 1 ++#define FRF_AB_XX_PWRDNB_SIG_LBN 29 ++#define FRF_AB_XX_PWRDNB_SIG_WIDTH 1 ++#define FRF_AB_XX_PWRDNA_SIG_LBN 28 ++#define FRF_AB_XX_PWRDNA_SIG_WIDTH 1 ++#define FRF_AB_XX_SIM_MODE_LBN 27 ++#define FRF_AB_XX_SIM_MODE_WIDTH 1 ++#define FRF_AB_XX_RSTPLLCD_SIG_LBN 25 ++#define FRF_AB_XX_RSTPLLCD_SIG_WIDTH 1 ++#define FRF_AB_XX_RSTPLLAB_SIG_LBN 24 ++#define FRF_AB_XX_RSTPLLAB_SIG_WIDTH 1 ++#define FRF_AB_XX_RESETD_SIG_LBN 23 ++#define FRF_AB_XX_RESETD_SIG_WIDTH 1 ++#define FRF_AB_XX_RESETC_SIG_LBN 22 ++#define FRF_AB_XX_RESETC_SIG_WIDTH 1 ++#define FRF_AB_XX_RESETB_SIG_LBN 21 ++#define FRF_AB_XX_RESETB_SIG_WIDTH 1 ++#define FRF_AB_XX_RESETA_SIG_LBN 20 ++#define FRF_AB_XX_RESETA_SIG_WIDTH 1 ++#define FRF_AB_XX_RSTXGXSRX_SIG_LBN 18 ++#define FRF_AB_XX_RSTXGXSRX_SIG_WIDTH 1 ++#define FRF_AB_XX_RSTXGXSTX_SIG_LBN 17 ++#define FRF_AB_XX_RSTXGXSTX_SIG_WIDTH 1 ++#define FRF_AB_XX_SD_RST_ACT_LBN 16 ++#define FRF_AB_XX_SD_RST_ACT_WIDTH 1 ++#define FRF_AB_XX_PWRDND_EN_LBN 15 ++#define FRF_AB_XX_PWRDND_EN_WIDTH 1 ++#define FRF_AB_XX_PWRDNC_EN_LBN 14 ++#define FRF_AB_XX_PWRDNC_EN_WIDTH 1 ++#define FRF_AB_XX_PWRDNB_EN_LBN 13 ++#define FRF_AB_XX_PWRDNB_EN_WIDTH 1 ++#define FRF_AB_XX_PWRDNA_EN_LBN 12 ++#define FRF_AB_XX_PWRDNA_EN_WIDTH 1 ++#define FRF_AB_XX_RSTPLLCD_EN_LBN 9 ++#define FRF_AB_XX_RSTPLLCD_EN_WIDTH 1 ++#define FRF_AB_XX_RSTPLLAB_EN_LBN 8 ++#define FRF_AB_XX_RSTPLLAB_EN_WIDTH 1 ++#define FRF_AB_XX_RESETD_EN_LBN 7 ++#define FRF_AB_XX_RESETD_EN_WIDTH 1 ++#define FRF_AB_XX_RESETC_EN_LBN 6 ++#define FRF_AB_XX_RESETC_EN_WIDTH 1 ++#define FRF_AB_XX_RESETB_EN_LBN 5 ++#define FRF_AB_XX_RESETB_EN_WIDTH 1 ++#define FRF_AB_XX_RESETA_EN_LBN 4 ++#define FRF_AB_XX_RESETA_EN_WIDTH 1 ++#define FRF_AB_XX_RSTXGXSRX_EN_LBN 2 ++#define FRF_AB_XX_RSTXGXSRX_EN_WIDTH 1 ++#define FRF_AB_XX_RSTXGXSTX_EN_LBN 1 ++#define FRF_AB_XX_RSTXGXSTX_EN_WIDTH 1 ++#define FRF_AB_XX_RST_XX_EN_LBN 0 ++#define FRF_AB_XX_RST_XX_EN_WIDTH 1 ++ ++/* XX_SD_CTL_REG: XGXS/XAUI powerdown/reset control register */ ++#define FR_AB_XX_SD_CTL 0x00001310 ++#define FRF_AB_XX_TERMADJ1_LBN 17 ++#define FRF_AB_XX_TERMADJ1_WIDTH 1 ++#define FRF_AB_XX_TERMADJ0_LBN 16 ++#define FRF_AB_XX_TERMADJ0_WIDTH 1 ++#define FRF_AB_XX_HIDRVD_LBN 15 ++#define FRF_AB_XX_HIDRVD_WIDTH 1 ++#define FRF_AB_XX_LODRVD_LBN 14 ++#define FRF_AB_XX_LODRVD_WIDTH 1 ++#define FRF_AB_XX_HIDRVC_LBN 13 ++#define FRF_AB_XX_HIDRVC_WIDTH 1 ++#define FRF_AB_XX_LODRVC_LBN 12 ++#define FRF_AB_XX_LODRVC_WIDTH 1 ++#define FRF_AB_XX_HIDRVB_LBN 11 ++#define FRF_AB_XX_HIDRVB_WIDTH 1 ++#define FRF_AB_XX_LODRVB_LBN 10 ++#define FRF_AB_XX_LODRVB_WIDTH 1 ++#define FRF_AB_XX_HIDRVA_LBN 9 ++#define FRF_AB_XX_HIDRVA_WIDTH 1 ++#define FRF_AB_XX_LODRVA_LBN 8 ++#define FRF_AB_XX_LODRVA_WIDTH 1 ++#define FRF_AB_XX_LPBKD_LBN 3 ++#define FRF_AB_XX_LPBKD_WIDTH 1 ++#define FRF_AB_XX_LPBKC_LBN 2 ++#define FRF_AB_XX_LPBKC_WIDTH 1 ++#define FRF_AB_XX_LPBKB_LBN 1 ++#define FRF_AB_XX_LPBKB_WIDTH 1 ++#define FRF_AB_XX_LPBKA_LBN 0 ++#define FRF_AB_XX_LPBKA_WIDTH 1 ++ ++/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */ ++#define FR_AB_XX_TXDRV_CTL 0x00001320 ++#define FRF_AB_XX_DEQD_LBN 28 ++#define FRF_AB_XX_DEQD_WIDTH 4 ++#define FRF_AB_XX_DEQC_LBN 24 ++#define FRF_AB_XX_DEQC_WIDTH 4 ++#define FRF_AB_XX_DEQB_LBN 20 ++#define FRF_AB_XX_DEQB_WIDTH 4 ++#define FRF_AB_XX_DEQA_LBN 16 ++#define FRF_AB_XX_DEQA_WIDTH 4 ++#define FRF_AB_XX_DTXD_LBN 12 ++#define FRF_AB_XX_DTXD_WIDTH 4 ++#define FRF_AB_XX_DTXC_LBN 8 ++#define FRF_AB_XX_DTXC_WIDTH 4 ++#define FRF_AB_XX_DTXB_LBN 4 ++#define FRF_AB_XX_DTXB_WIDTH 4 ++#define FRF_AB_XX_DTXA_LBN 0 ++#define FRF_AB_XX_DTXA_WIDTH 4 ++ ++/* XX_PRBS_CTL_REG: documentation to be written for sum_XX_PRBS_CTL_REG */ ++#define FR_AB_XX_PRBS_CTL 0x00001330 ++#define FRF_AB_XX_CH3_RX_PRBS_SEL_LBN 30 ++#define FRF_AB_XX_CH3_RX_PRBS_SEL_WIDTH 2 ++#define FRF_AB_XX_CH3_RX_PRBS_INV_LBN 29 ++#define FRF_AB_XX_CH3_RX_PRBS_INV_WIDTH 1 ++#define FRF_AB_XX_CH3_RX_PRBS_CHKEN_LBN 28 ++#define FRF_AB_XX_CH3_RX_PRBS_CHKEN_WIDTH 1 ++#define FRF_AB_XX_CH2_RX_PRBS_SEL_LBN 26 ++#define FRF_AB_XX_CH2_RX_PRBS_SEL_WIDTH 2 ++#define FRF_AB_XX_CH2_RX_PRBS_INV_LBN 25 ++#define FRF_AB_XX_CH2_RX_PRBS_INV_WIDTH 1 ++#define FRF_AB_XX_CH2_RX_PRBS_CHKEN_LBN 24 ++#define FRF_AB_XX_CH2_RX_PRBS_CHKEN_WIDTH 1 ++#define FRF_AB_XX_CH1_RX_PRBS_SEL_LBN 22 ++#define FRF_AB_XX_CH1_RX_PRBS_SEL_WIDTH 2 ++#define FRF_AB_XX_CH1_RX_PRBS_INV_LBN 21 ++#define FRF_AB_XX_CH1_RX_PRBS_INV_WIDTH 1 ++#define FRF_AB_XX_CH1_RX_PRBS_CHKEN_LBN 20 ++#define FRF_AB_XX_CH1_RX_PRBS_CHKEN_WIDTH 1 ++#define FRF_AB_XX_CH0_RX_PRBS_SEL_LBN 18 ++#define FRF_AB_XX_CH0_RX_PRBS_SEL_WIDTH 2 ++#define FRF_AB_XX_CH0_RX_PRBS_INV_LBN 17 ++#define FRF_AB_XX_CH0_RX_PRBS_INV_WIDTH 1 ++#define FRF_AB_XX_CH0_RX_PRBS_CHKEN_LBN 16 ++#define FRF_AB_XX_CH0_RX_PRBS_CHKEN_WIDTH 1 ++#define FRF_AB_XX_CH3_TX_PRBS_SEL_LBN 14 ++#define FRF_AB_XX_CH3_TX_PRBS_SEL_WIDTH 2 ++#define FRF_AB_XX_CH3_TX_PRBS_INV_LBN 13 ++#define FRF_AB_XX_CH3_TX_PRBS_INV_WIDTH 1 ++#define FRF_AB_XX_CH3_TX_PRBS_CHKEN_LBN 12 ++#define FRF_AB_XX_CH3_TX_PRBS_CHKEN_WIDTH 1 ++#define FRF_AB_XX_CH2_TX_PRBS_SEL_LBN 10 ++#define FRF_AB_XX_CH2_TX_PRBS_SEL_WIDTH 2 ++#define FRF_AB_XX_CH2_TX_PRBS_INV_LBN 9 ++#define FRF_AB_XX_CH2_TX_PRBS_INV_WIDTH 1 ++#define FRF_AB_XX_CH2_TX_PRBS_CHKEN_LBN 8 ++#define FRF_AB_XX_CH2_TX_PRBS_CHKEN_WIDTH 1 ++#define FRF_AB_XX_CH1_TX_PRBS_SEL_LBN 6 ++#define FRF_AB_XX_CH1_TX_PRBS_SEL_WIDTH 2 ++#define FRF_AB_XX_CH1_TX_PRBS_INV_LBN 5 ++#define FRF_AB_XX_CH1_TX_PRBS_INV_WIDTH 1 ++#define FRF_AB_XX_CH1_TX_PRBS_CHKEN_LBN 4 ++#define FRF_AB_XX_CH1_TX_PRBS_CHKEN_WIDTH 1 ++#define FRF_AB_XX_CH0_TX_PRBS_SEL_LBN 2 ++#define FRF_AB_XX_CH0_TX_PRBS_SEL_WIDTH 2 ++#define FRF_AB_XX_CH0_TX_PRBS_INV_LBN 1 ++#define FRF_AB_XX_CH0_TX_PRBS_INV_WIDTH 1 ++#define FRF_AB_XX_CH0_TX_PRBS_CHKEN_LBN 0 ++#define FRF_AB_XX_CH0_TX_PRBS_CHKEN_WIDTH 1 ++ ++/* XX_PRBS_CHK_REG: documentation to be written for sum_XX_PRBS_CHK_REG */ ++#define FR_AB_XX_PRBS_CHK 0x00001340 ++#define FRF_AB_XX_REV_LB_EN_LBN 16 ++#define FRF_AB_XX_REV_LB_EN_WIDTH 1 ++#define FRF_AB_XX_CH3_DEG_DET_LBN 15 ++#define FRF_AB_XX_CH3_DEG_DET_WIDTH 1 ++#define FRF_AB_XX_CH3_LFSR_LOCK_IND_LBN 14 ++#define FRF_AB_XX_CH3_LFSR_LOCK_IND_WIDTH 1 ++#define FRF_AB_XX_CH3_PRBS_FRUN_LBN 13 ++#define FRF_AB_XX_CH3_PRBS_FRUN_WIDTH 1 ++#define FRF_AB_XX_CH3_ERR_CHK_LBN 12 ++#define FRF_AB_XX_CH3_ERR_CHK_WIDTH 1 ++#define FRF_AB_XX_CH2_DEG_DET_LBN 11 ++#define FRF_AB_XX_CH2_DEG_DET_WIDTH 1 ++#define FRF_AB_XX_CH2_LFSR_LOCK_IND_LBN 10 ++#define FRF_AB_XX_CH2_LFSR_LOCK_IND_WIDTH 1 ++#define FRF_AB_XX_CH2_PRBS_FRUN_LBN 9 ++#define FRF_AB_XX_CH2_PRBS_FRUN_WIDTH 1 ++#define FRF_AB_XX_CH2_ERR_CHK_LBN 8 ++#define FRF_AB_XX_CH2_ERR_CHK_WIDTH 1 ++#define FRF_AB_XX_CH1_DEG_DET_LBN 7 ++#define FRF_AB_XX_CH1_DEG_DET_WIDTH 1 ++#define FRF_AB_XX_CH1_LFSR_LOCK_IND_LBN 6 ++#define FRF_AB_XX_CH1_LFSR_LOCK_IND_WIDTH 1 ++#define FRF_AB_XX_CH1_PRBS_FRUN_LBN 5 ++#define FRF_AB_XX_CH1_PRBS_FRUN_WIDTH 1 ++#define FRF_AB_XX_CH1_ERR_CHK_LBN 4 ++#define FRF_AB_XX_CH1_ERR_CHK_WIDTH 1 ++#define FRF_AB_XX_CH0_DEG_DET_LBN 3 ++#define FRF_AB_XX_CH0_DEG_DET_WIDTH 1 ++#define FRF_AB_XX_CH0_LFSR_LOCK_IND_LBN 2 ++#define FRF_AB_XX_CH0_LFSR_LOCK_IND_WIDTH 1 ++#define FRF_AB_XX_CH0_PRBS_FRUN_LBN 1 ++#define FRF_AB_XX_CH0_PRBS_FRUN_WIDTH 1 ++#define FRF_AB_XX_CH0_ERR_CHK_LBN 0 ++#define FRF_AB_XX_CH0_ERR_CHK_WIDTH 1 ++ ++/* XX_PRBS_ERR_REG: documentation to be written for sum_XX_PRBS_ERR_REG */ ++#define FR_AB_XX_PRBS_ERR 0x00001350 ++#define FRF_AB_XX_CH3_PRBS_ERR_CNT_LBN 24 ++#define FRF_AB_XX_CH3_PRBS_ERR_CNT_WIDTH 8 ++#define FRF_AB_XX_CH2_PRBS_ERR_CNT_LBN 16 ++#define FRF_AB_XX_CH2_PRBS_ERR_CNT_WIDTH 8 ++#define FRF_AB_XX_CH1_PRBS_ERR_CNT_LBN 8 ++#define FRF_AB_XX_CH1_PRBS_ERR_CNT_WIDTH 8 ++#define FRF_AB_XX_CH0_PRBS_ERR_CNT_LBN 0 ++#define FRF_AB_XX_CH0_PRBS_ERR_CNT_WIDTH 8 ++ ++/* XX_CORE_STAT_REG: XAUI XGXS core status register */ ++#define FR_AB_XX_CORE_STAT 0x00001360 ++#define FRF_AB_XX_FORCE_SIG3_LBN 31 ++#define FRF_AB_XX_FORCE_SIG3_WIDTH 1 ++#define FRF_AB_XX_FORCE_SIG3_VAL_LBN 30 ++#define FRF_AB_XX_FORCE_SIG3_VAL_WIDTH 1 ++#define FRF_AB_XX_FORCE_SIG2_LBN 29 ++#define FRF_AB_XX_FORCE_SIG2_WIDTH 1 ++#define FRF_AB_XX_FORCE_SIG2_VAL_LBN 28 ++#define FRF_AB_XX_FORCE_SIG2_VAL_WIDTH 1 ++#define FRF_AB_XX_FORCE_SIG1_LBN 27 ++#define FRF_AB_XX_FORCE_SIG1_WIDTH 1 ++#define FRF_AB_XX_FORCE_SIG1_VAL_LBN 26 ++#define FRF_AB_XX_FORCE_SIG1_VAL_WIDTH 1 ++#define FRF_AB_XX_FORCE_SIG0_LBN 25 ++#define FRF_AB_XX_FORCE_SIG0_WIDTH 1 ++#define FRF_AB_XX_FORCE_SIG0_VAL_LBN 24 ++#define FRF_AB_XX_FORCE_SIG0_VAL_WIDTH 1 ++#define FRF_AB_XX_XGXS_LB_EN_LBN 23 ++#define FRF_AB_XX_XGXS_LB_EN_WIDTH 1 ++#define FRF_AB_XX_XGMII_LB_EN_LBN 22 ++#define FRF_AB_XX_XGMII_LB_EN_WIDTH 1 ++#define FRF_AB_XX_MATCH_FAULT_LBN 21 ++#define FRF_AB_XX_MATCH_FAULT_WIDTH 1 ++#define FRF_AB_XX_ALIGN_DONE_LBN 20 ++#define FRF_AB_XX_ALIGN_DONE_WIDTH 1 ++#define FRF_AB_XX_SYNC_STAT3_LBN 19 ++#define FRF_AB_XX_SYNC_STAT3_WIDTH 1 ++#define FRF_AB_XX_SYNC_STAT2_LBN 18 ++#define FRF_AB_XX_SYNC_STAT2_WIDTH 1 ++#define FRF_AB_XX_SYNC_STAT1_LBN 17 ++#define FRF_AB_XX_SYNC_STAT1_WIDTH 1 ++#define FRF_AB_XX_SYNC_STAT0_LBN 16 ++#define FRF_AB_XX_SYNC_STAT0_WIDTH 1 ++#define FRF_AB_XX_COMMA_DET_CH3_LBN 15 ++#define FRF_AB_XX_COMMA_DET_CH3_WIDTH 1 ++#define FRF_AB_XX_COMMA_DET_CH2_LBN 14 ++#define FRF_AB_XX_COMMA_DET_CH2_WIDTH 1 ++#define FRF_AB_XX_COMMA_DET_CH1_LBN 13 ++#define FRF_AB_XX_COMMA_DET_CH1_WIDTH 1 ++#define FRF_AB_XX_COMMA_DET_CH0_LBN 12 ++#define FRF_AB_XX_COMMA_DET_CH0_WIDTH 1 ++#define FRF_AB_XX_CGRP_ALIGN_CH3_LBN 11 ++#define FRF_AB_XX_CGRP_ALIGN_CH3_WIDTH 1 ++#define FRF_AB_XX_CGRP_ALIGN_CH2_LBN 10 ++#define FRF_AB_XX_CGRP_ALIGN_CH2_WIDTH 1 ++#define FRF_AB_XX_CGRP_ALIGN_CH1_LBN 9 ++#define FRF_AB_XX_CGRP_ALIGN_CH1_WIDTH 1 ++#define FRF_AB_XX_CGRP_ALIGN_CH0_LBN 8 ++#define FRF_AB_XX_CGRP_ALIGN_CH0_WIDTH 1 ++#define FRF_AB_XX_CHAR_ERR_CH3_LBN 7 ++#define FRF_AB_XX_CHAR_ERR_CH3_WIDTH 1 ++#define FRF_AB_XX_CHAR_ERR_CH2_LBN 6 ++#define FRF_AB_XX_CHAR_ERR_CH2_WIDTH 1 ++#define FRF_AB_XX_CHAR_ERR_CH1_LBN 5 ++#define FRF_AB_XX_CHAR_ERR_CH1_WIDTH 1 ++#define FRF_AB_XX_CHAR_ERR_CH0_LBN 4 ++#define FRF_AB_XX_CHAR_ERR_CH0_WIDTH 1 ++#define FRF_AB_XX_DISPERR_CH3_LBN 3 ++#define FRF_AB_XX_DISPERR_CH3_WIDTH 1 ++#define FRF_AB_XX_DISPERR_CH2_LBN 2 ++#define FRF_AB_XX_DISPERR_CH2_WIDTH 1 ++#define FRF_AB_XX_DISPERR_CH1_LBN 1 ++#define FRF_AB_XX_DISPERR_CH1_WIDTH 1 ++#define FRF_AB_XX_DISPERR_CH0_LBN 0 ++#define FRF_AB_XX_DISPERR_CH0_WIDTH 1 ++ ++/* RX_DESC_PTR_TBL_KER: Receive descriptor pointer table */ ++#define FR_AA_RX_DESC_PTR_TBL_KER 0x00011800 ++#define FR_AA_RX_DESC_PTR_TBL_KER_STEP 16 ++#define FR_AA_RX_DESC_PTR_TBL_KER_ROWS 4 ++/* RX_DESC_PTR_TBL: Receive descriptor pointer table */ ++#define FR_BZ_RX_DESC_PTR_TBL 0x00f40000 ++#define FR_BZ_RX_DESC_PTR_TBL_STEP 16 ++#define FR_BB_RX_DESC_PTR_TBL_ROWS 4096 ++#define FR_CZ_RX_DESC_PTR_TBL_ROWS 1024 ++#define FRF_CZ_RX_HDR_SPLIT_LBN 90 ++#define FRF_CZ_RX_HDR_SPLIT_WIDTH 1 ++#define FRF_AA_RX_RESET_LBN 89 ++#define FRF_AA_RX_RESET_WIDTH 1 ++#define FRF_AZ_RX_ISCSI_DDIG_EN_LBN 88 ++#define FRF_AZ_RX_ISCSI_DDIG_EN_WIDTH 1 ++#define FRF_AZ_RX_ISCSI_HDIG_EN_LBN 87 ++#define FRF_AZ_RX_ISCSI_HDIG_EN_WIDTH 1 ++#define FRF_AZ_RX_DESC_PREF_ACT_LBN 86 ++#define FRF_AZ_RX_DESC_PREF_ACT_WIDTH 1 ++#define FRF_AZ_RX_DC_HW_RPTR_LBN 80 ++#define FRF_AZ_RX_DC_HW_RPTR_WIDTH 6 ++#define FRF_AZ_RX_DESCQ_HW_RPTR_LBN 68 ++#define FRF_AZ_RX_DESCQ_HW_RPTR_WIDTH 12 ++#define FRF_AZ_RX_DESCQ_SW_WPTR_LBN 56 ++#define FRF_AZ_RX_DESCQ_SW_WPTR_WIDTH 12 ++#define FRF_AZ_RX_DESCQ_BUF_BASE_ID_LBN 36 ++#define FRF_AZ_RX_DESCQ_BUF_BASE_ID_WIDTH 20 ++#define FRF_AZ_RX_DESCQ_EVQ_ID_LBN 24 ++#define FRF_AZ_RX_DESCQ_EVQ_ID_WIDTH 12 ++#define FRF_AZ_RX_DESCQ_OWNER_ID_LBN 10 ++#define FRF_AZ_RX_DESCQ_OWNER_ID_WIDTH 14 ++#define FRF_AZ_RX_DESCQ_LABEL_LBN 5 ++#define FRF_AZ_RX_DESCQ_LABEL_WIDTH 5 ++#define FRF_AZ_RX_DESCQ_SIZE_LBN 3 ++#define FRF_AZ_RX_DESCQ_SIZE_WIDTH 2 ++#define FFE_AZ_RX_DESCQ_SIZE_4K 3 ++#define FFE_AZ_RX_DESCQ_SIZE_2K 2 ++#define FFE_AZ_RX_DESCQ_SIZE_1K 1 ++#define FFE_AZ_RX_DESCQ_SIZE_512 0 ++#define FRF_AZ_RX_DESCQ_TYPE_LBN 2 ++#define FRF_AZ_RX_DESCQ_TYPE_WIDTH 1 ++#define FRF_AZ_RX_DESCQ_JUMBO_LBN 1 ++#define FRF_AZ_RX_DESCQ_JUMBO_WIDTH 1 ++#define FRF_AZ_RX_DESCQ_EN_LBN 0 ++#define FRF_AZ_RX_DESCQ_EN_WIDTH 1 ++ ++/* TX_DESC_PTR_TBL_KER: Transmit descriptor pointer */ ++#define FR_AA_TX_DESC_PTR_TBL_KER 0x00011900 ++#define FR_AA_TX_DESC_PTR_TBL_KER_STEP 16 ++#define FR_AA_TX_DESC_PTR_TBL_KER_ROWS 8 ++/* TX_DESC_PTR_TBL: Transmit descriptor pointer */ ++#define FR_BZ_TX_DESC_PTR_TBL 0x00f50000 ++#define FR_BZ_TX_DESC_PTR_TBL_STEP 16 ++#define FR_BB_TX_DESC_PTR_TBL_ROWS 4096 ++#define FR_CZ_TX_DESC_PTR_TBL_ROWS 1024 ++#define FRF_CZ_TX_DPT_Q_MASK_WIDTH_LBN 94 ++#define FRF_CZ_TX_DPT_Q_MASK_WIDTH_WIDTH 2 ++#define FRF_CZ_TX_DPT_ETH_FILT_EN_LBN 93 ++#define FRF_CZ_TX_DPT_ETH_FILT_EN_WIDTH 1 ++#define FRF_CZ_TX_DPT_IP_FILT_EN_LBN 92 ++#define FRF_CZ_TX_DPT_IP_FILT_EN_WIDTH 1 ++#define FRF_BZ_TX_NON_IP_DROP_DIS_LBN 91 ++#define FRF_BZ_TX_NON_IP_DROP_DIS_WIDTH 1 ++#define FRF_BZ_TX_IP_CHKSM_DIS_LBN 90 ++#define FRF_BZ_TX_IP_CHKSM_DIS_WIDTH 1 ++#define FRF_BZ_TX_TCP_CHKSM_DIS_LBN 89 ++#define FRF_BZ_TX_TCP_CHKSM_DIS_WIDTH 1 ++#define FRF_AZ_TX_DESCQ_EN_LBN 88 ++#define FRF_AZ_TX_DESCQ_EN_WIDTH 1 ++#define FRF_AZ_TX_ISCSI_DDIG_EN_LBN 87 ++#define FRF_AZ_TX_ISCSI_DDIG_EN_WIDTH 1 ++#define FRF_AZ_TX_ISCSI_HDIG_EN_LBN 86 ++#define FRF_AZ_TX_ISCSI_HDIG_EN_WIDTH 1 ++#define FRF_AZ_TX_DC_HW_RPTR_LBN 80 ++#define FRF_AZ_TX_DC_HW_RPTR_WIDTH 6 ++#define FRF_AZ_TX_DESCQ_HW_RPTR_LBN 68 ++#define FRF_AZ_TX_DESCQ_HW_RPTR_WIDTH 12 ++#define FRF_AZ_TX_DESCQ_SW_WPTR_LBN 56 ++#define FRF_AZ_TX_DESCQ_SW_WPTR_WIDTH 12 ++#define FRF_AZ_TX_DESCQ_BUF_BASE_ID_LBN 36 ++#define FRF_AZ_TX_DESCQ_BUF_BASE_ID_WIDTH 20 ++#define FRF_AZ_TX_DESCQ_EVQ_ID_LBN 24 ++#define FRF_AZ_TX_DESCQ_EVQ_ID_WIDTH 12 ++#define FRF_AZ_TX_DESCQ_OWNER_ID_LBN 10 ++#define FRF_AZ_TX_DESCQ_OWNER_ID_WIDTH 14 ++#define FRF_AZ_TX_DESCQ_LABEL_LBN 5 ++#define FRF_AZ_TX_DESCQ_LABEL_WIDTH 5 ++#define FRF_AZ_TX_DESCQ_SIZE_LBN 3 ++#define FRF_AZ_TX_DESCQ_SIZE_WIDTH 2 ++#define FFE_AZ_TX_DESCQ_SIZE_4K 3 ++#define FFE_AZ_TX_DESCQ_SIZE_2K 2 ++#define FFE_AZ_TX_DESCQ_SIZE_1K 1 ++#define FFE_AZ_TX_DESCQ_SIZE_512 0 ++#define FRF_AZ_TX_DESCQ_TYPE_LBN 1 ++#define FRF_AZ_TX_DESCQ_TYPE_WIDTH 2 ++#define FRF_AZ_TX_DESCQ_FLUSH_LBN 0 ++#define FRF_AZ_TX_DESCQ_FLUSH_WIDTH 1 ++ ++/* EVQ_PTR_TBL_KER: Event queue pointer table */ ++#define FR_AA_EVQ_PTR_TBL_KER 0x00011a00 ++#define FR_AA_EVQ_PTR_TBL_KER_STEP 16 ++#define FR_AA_EVQ_PTR_TBL_KER_ROWS 4 ++/* EVQ_PTR_TBL: Event queue pointer table */ ++#define FR_BZ_EVQ_PTR_TBL 0x00f60000 ++#define FR_BZ_EVQ_PTR_TBL_STEP 16 ++#define FR_CZ_EVQ_PTR_TBL_ROWS 1024 ++#define FR_BB_EVQ_PTR_TBL_ROWS 4096 ++#define FRF_BZ_EVQ_RPTR_IGN_LBN 40 ++#define FRF_BZ_EVQ_RPTR_IGN_WIDTH 1 ++#define FRF_AB_EVQ_WKUP_OR_INT_EN_LBN 39 ++#define FRF_AB_EVQ_WKUP_OR_INT_EN_WIDTH 1 ++#define FRF_CZ_EVQ_DOS_PROTECT_EN_LBN 39 ++#define FRF_CZ_EVQ_DOS_PROTECT_EN_WIDTH 1 ++#define FRF_AZ_EVQ_NXT_WPTR_LBN 24 ++#define FRF_AZ_EVQ_NXT_WPTR_WIDTH 15 ++#define FRF_AZ_EVQ_EN_LBN 23 ++#define FRF_AZ_EVQ_EN_WIDTH 1 ++#define FRF_AZ_EVQ_SIZE_LBN 20 ++#define FRF_AZ_EVQ_SIZE_WIDTH 3 ++#define FFE_AZ_EVQ_SIZE_32K 6 ++#define FFE_AZ_EVQ_SIZE_16K 5 ++#define FFE_AZ_EVQ_SIZE_8K 4 ++#define FFE_AZ_EVQ_SIZE_4K 3 ++#define FFE_AZ_EVQ_SIZE_2K 2 ++#define FFE_AZ_EVQ_SIZE_1K 1 ++#define FFE_AZ_EVQ_SIZE_512 0 ++#define FRF_AZ_EVQ_BUF_BASE_ID_LBN 0 ++#define FRF_AZ_EVQ_BUF_BASE_ID_WIDTH 20 ++ ++/* BUF_HALF_TBL_KER: Buffer table in half buffer table mode direct access by driver */ ++#define FR_AA_BUF_HALF_TBL_KER 0x00018000 ++#define FR_AA_BUF_HALF_TBL_KER_STEP 8 ++#define FR_AA_BUF_HALF_TBL_KER_ROWS 4096 ++/* BUF_HALF_TBL: Buffer table in half buffer table mode direct access by driver */ ++#define FR_BZ_BUF_HALF_TBL 0x00800000 ++#define FR_BZ_BUF_HALF_TBL_STEP 8 ++#define FR_CZ_BUF_HALF_TBL_ROWS 147456 ++#define FR_BB_BUF_HALF_TBL_ROWS 524288 ++#define FRF_AZ_BUF_ADR_HBUF_ODD_LBN 44 ++#define FRF_AZ_BUF_ADR_HBUF_ODD_WIDTH 20 ++#define FRF_AZ_BUF_OWNER_ID_HBUF_ODD_LBN 32 ++#define FRF_AZ_BUF_OWNER_ID_HBUF_ODD_WIDTH 12 ++#define FRF_AZ_BUF_ADR_HBUF_EVEN_LBN 12 ++#define FRF_AZ_BUF_ADR_HBUF_EVEN_WIDTH 20 ++#define FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_LBN 0 ++#define FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_WIDTH 12 ++ ++/* BUF_FULL_TBL_KER: Buffer table in full buffer table mode direct access by driver */ ++#define FR_AA_BUF_FULL_TBL_KER 0x00018000 ++#define FR_AA_BUF_FULL_TBL_KER_STEP 8 ++#define FR_AA_BUF_FULL_TBL_KER_ROWS 4096 ++/* BUF_FULL_TBL: Buffer table in full buffer table mode direct access by driver */ ++#define FR_BZ_BUF_FULL_TBL 0x00800000 ++#define FR_BZ_BUF_FULL_TBL_STEP 8 ++#define FR_CZ_BUF_FULL_TBL_ROWS 147456 ++#define FR_BB_BUF_FULL_TBL_ROWS 917504 ++#define FRF_AZ_BUF_FULL_UNUSED_LBN 51 ++#define FRF_AZ_BUF_FULL_UNUSED_WIDTH 13 ++#define FRF_AZ_IP_DAT_BUF_SIZE_LBN 50 ++#define FRF_AZ_IP_DAT_BUF_SIZE_WIDTH 1 ++#define FRF_AZ_BUF_ADR_REGION_LBN 48 ++#define FRF_AZ_BUF_ADR_REGION_WIDTH 2 ++#define FFE_AZ_BUF_ADR_REGN3 3 ++#define FFE_AZ_BUF_ADR_REGN2 2 ++#define FFE_AZ_BUF_ADR_REGN1 1 ++#define FFE_AZ_BUF_ADR_REGN0 0 ++#define FRF_AZ_BUF_ADR_FBUF_LBN 14 ++#define FRF_AZ_BUF_ADR_FBUF_WIDTH 34 ++#define FRF_AZ_BUF_OWNER_ID_FBUF_LBN 0 ++#define FRF_AZ_BUF_OWNER_ID_FBUF_WIDTH 14 ++ ++/* RX_FILTER_TBL0: TCP/IPv4 Receive filter table */ ++#define FR_BZ_RX_FILTER_TBL0 0x00f00000 ++#define FR_BZ_RX_FILTER_TBL0_STEP 32 ++#define FR_BZ_RX_FILTER_TBL0_ROWS 8192 ++/* RX_FILTER_TBL1: TCP/IPv4 Receive filter table */ ++#define FR_BB_RX_FILTER_TBL1 0x00f00010 ++#define FR_BB_RX_FILTER_TBL1_STEP 32 ++#define FR_BB_RX_FILTER_TBL1_ROWS 8192 ++#define FRF_BZ_RSS_EN_LBN 110 ++#define FRF_BZ_RSS_EN_WIDTH 1 ++#define FRF_BZ_SCATTER_EN_LBN 109 ++#define FRF_BZ_SCATTER_EN_WIDTH 1 ++#define FRF_BZ_TCP_UDP_LBN 108 ++#define FRF_BZ_TCP_UDP_WIDTH 1 ++#define FRF_BZ_RXQ_ID_LBN 96 ++#define FRF_BZ_RXQ_ID_WIDTH 12 ++#define FRF_BZ_DEST_IP_LBN 64 ++#define FRF_BZ_DEST_IP_WIDTH 32 ++#define FRF_BZ_DEST_PORT_TCP_LBN 48 ++#define FRF_BZ_DEST_PORT_TCP_WIDTH 16 ++#define FRF_BZ_SRC_IP_LBN 16 ++#define FRF_BZ_SRC_IP_WIDTH 32 ++#define FRF_BZ_SRC_TCP_DEST_UDP_LBN 0 ++#define FRF_BZ_SRC_TCP_DEST_UDP_WIDTH 16 ++ ++/* RX_MAC_FILTER_TBL0: Receive Ethernet filter table */ ++#define FR_CZ_RX_MAC_FILTER_TBL0 0x00f00010 ++#define FR_CZ_RX_MAC_FILTER_TBL0_STEP 32 ++#define FR_CZ_RX_MAC_FILTER_TBL0_ROWS 512 ++#define FRF_CZ_RMFT_RSS_EN_LBN 75 ++#define FRF_CZ_RMFT_RSS_EN_WIDTH 1 ++#define FRF_CZ_RMFT_SCATTER_EN_LBN 74 ++#define FRF_CZ_RMFT_SCATTER_EN_WIDTH 1 ++#define FRF_CZ_RMFT_IP_OVERRIDE_LBN 73 ++#define FRF_CZ_RMFT_IP_OVERRIDE_WIDTH 1 ++#define FRF_CZ_RMFT_RXQ_ID_LBN 61 ++#define FRF_CZ_RMFT_RXQ_ID_WIDTH 12 ++#define FRF_CZ_RMFT_WILDCARD_MATCH_LBN 60 ++#define FRF_CZ_RMFT_WILDCARD_MATCH_WIDTH 1 ++#define FRF_CZ_RMFT_DEST_MAC_LBN 16 ++#define FRF_CZ_RMFT_DEST_MAC_WIDTH 44 ++#define FRF_CZ_RMFT_VLAN_ID_LBN 0 ++#define FRF_CZ_RMFT_VLAN_ID_WIDTH 12 ++ ++/* TIMER_TBL: Timer table */ ++#define FR_BZ_TIMER_TBL 0x00f70000 ++#define FR_BZ_TIMER_TBL_STEP 16 ++#define FR_CZ_TIMER_TBL_ROWS 1024 ++#define FR_BB_TIMER_TBL_ROWS 4096 ++#define FRF_CZ_TIMER_Q_EN_LBN 33 ++#define FRF_CZ_TIMER_Q_EN_WIDTH 1 ++#define FRF_CZ_INT_ARMD_LBN 32 ++#define FRF_CZ_INT_ARMD_WIDTH 1 ++#define FRF_CZ_INT_PEND_LBN 31 ++#define FRF_CZ_INT_PEND_WIDTH 1 ++#define FRF_CZ_HOST_NOTIFY_MODE_LBN 30 ++#define FRF_CZ_HOST_NOTIFY_MODE_WIDTH 1 ++#define FRF_CZ_RELOAD_TIMER_VAL_LBN 16 ++#define FRF_CZ_RELOAD_TIMER_VAL_WIDTH 14 ++#define FRF_CZ_TIMER_MODE_LBN 14 ++#define FRF_CZ_TIMER_MODE_WIDTH 2 ++#define FFE_CZ_TIMER_MODE_INT_HLDOFF 3 ++#define FFE_CZ_TIMER_MODE_TRIG_START 2 ++#define FFE_CZ_TIMER_MODE_IMMED_START 1 ++#define FFE_CZ_TIMER_MODE_DIS 0 ++#define FRF_BB_TIMER_MODE_LBN 12 ++#define FRF_BB_TIMER_MODE_WIDTH 2 ++#define FFE_BB_TIMER_MODE_INT_HLDOFF 2 ++#define FFE_BB_TIMER_MODE_TRIG_START 2 ++#define FFE_BB_TIMER_MODE_IMMED_START 1 ++#define FFE_BB_TIMER_MODE_DIS 0 ++#define FRF_CZ_TIMER_VAL_LBN 0 ++#define FRF_CZ_TIMER_VAL_WIDTH 14 ++#define FRF_BB_TIMER_VAL_LBN 0 ++#define FRF_BB_TIMER_VAL_WIDTH 12 ++ ++/* TX_PACE_TBL: Transmit pacing table */ ++#define FR_BZ_TX_PACE_TBL 0x00f80000 ++#define FR_BZ_TX_PACE_TBL_STEP 16 ++#define FR_CZ_TX_PACE_TBL_ROWS 1024 ++#define FR_BB_TX_PACE_TBL_ROWS 4096 ++#define FRF_BZ_TX_PACE_LBN 0 ++#define FRF_BZ_TX_PACE_WIDTH 5 ++ ++/* RX_INDIRECTION_TBL: RX Indirection Table */ ++#define FR_BZ_RX_INDIRECTION_TBL 0x00fb0000 ++#define FR_BZ_RX_INDIRECTION_TBL_STEP 16 ++#define FR_BZ_RX_INDIRECTION_TBL_ROWS 128 ++#define FRF_BZ_IT_QUEUE_LBN 0 ++#define FRF_BZ_IT_QUEUE_WIDTH 6 ++ ++/* TX_FILTER_TBL0: TCP/IPv4 Transmit filter table */ ++#define FR_CZ_TX_FILTER_TBL0 0x00fc0000 ++#define FR_CZ_TX_FILTER_TBL0_STEP 16 ++#define FR_CZ_TX_FILTER_TBL0_ROWS 8192 ++#define FRF_CZ_TIFT_TCP_UDP_LBN 108 ++#define FRF_CZ_TIFT_TCP_UDP_WIDTH 1 ++#define FRF_CZ_TIFT_TXQ_ID_LBN 96 ++#define FRF_CZ_TIFT_TXQ_ID_WIDTH 12 ++#define FRF_CZ_TIFT_DEST_IP_LBN 64 ++#define FRF_CZ_TIFT_DEST_IP_WIDTH 32 ++#define FRF_CZ_TIFT_DEST_PORT_TCP_LBN 48 ++#define FRF_CZ_TIFT_DEST_PORT_TCP_WIDTH 16 ++#define FRF_CZ_TIFT_SRC_IP_LBN 16 ++#define FRF_CZ_TIFT_SRC_IP_WIDTH 32 ++#define FRF_CZ_TIFT_SRC_TCP_DEST_UDP_LBN 0 ++#define FRF_CZ_TIFT_SRC_TCP_DEST_UDP_WIDTH 16 ++ ++/* TX_MAC_FILTER_TBL0: Transmit Ethernet filter table */ ++#define FR_CZ_TX_MAC_FILTER_TBL0 0x00fe0000 ++#define FR_CZ_TX_MAC_FILTER_TBL0_STEP 16 ++#define FR_CZ_TX_MAC_FILTER_TBL0_ROWS 512 ++#define FRF_CZ_TMFT_TXQ_ID_LBN 61 ++#define FRF_CZ_TMFT_TXQ_ID_WIDTH 12 ++#define FRF_CZ_TMFT_WILDCARD_MATCH_LBN 60 ++#define FRF_CZ_TMFT_WILDCARD_MATCH_WIDTH 1 ++#define FRF_CZ_TMFT_SRC_MAC_LBN 16 ++#define FRF_CZ_TMFT_SRC_MAC_WIDTH 44 ++#define FRF_CZ_TMFT_VLAN_ID_LBN 0 ++#define FRF_CZ_TMFT_VLAN_ID_WIDTH 12 ++ ++/* MC_TREG_SMEM: MC Shared Memory */ ++#define FR_CZ_MC_TREG_SMEM 0x00ff0000 ++#define FR_CZ_MC_TREG_SMEM_STEP 4 ++#define FR_CZ_MC_TREG_SMEM_ROWS 512 ++#define FRF_CZ_MC_TREG_SMEM_ROW_LBN 0 ++#define FRF_CZ_MC_TREG_SMEM_ROW_WIDTH 32 ++ ++/* MSIX_VECTOR_TABLE: MSIX Vector Table */ ++#define FR_BB_MSIX_VECTOR_TABLE 0x00ff0000 ++#define FR_BZ_MSIX_VECTOR_TABLE_STEP 16 ++#define FR_BB_MSIX_VECTOR_TABLE_ROWS 64 ++/* MSIX_VECTOR_TABLE: MSIX Vector Table */ ++#define FR_CZ_MSIX_VECTOR_TABLE 0x00000000 ++/* FR_BZ_MSIX_VECTOR_TABLE_STEP 16 */ ++#define FR_CZ_MSIX_VECTOR_TABLE_ROWS 1024 ++#define FRF_BZ_MSIX_VECTOR_RESERVED_LBN 97 ++#define FRF_BZ_MSIX_VECTOR_RESERVED_WIDTH 31 ++#define FRF_BZ_MSIX_VECTOR_MASK_LBN 96 ++#define FRF_BZ_MSIX_VECTOR_MASK_WIDTH 1 ++#define FRF_BZ_MSIX_MESSAGE_DATA_LBN 64 ++#define FRF_BZ_MSIX_MESSAGE_DATA_WIDTH 32 ++#define FRF_BZ_MSIX_MESSAGE_ADDRESS_HI_LBN 32 ++#define FRF_BZ_MSIX_MESSAGE_ADDRESS_HI_WIDTH 32 ++#define FRF_BZ_MSIX_MESSAGE_ADDRESS_LO_LBN 0 ++#define FRF_BZ_MSIX_MESSAGE_ADDRESS_LO_WIDTH 32 ++ ++/* MSIX_PBA_TABLE: MSIX Pending Bit Array */ ++#define FR_BB_MSIX_PBA_TABLE 0x00ff2000 ++#define FR_BZ_MSIX_PBA_TABLE_STEP 4 ++#define FR_BB_MSIX_PBA_TABLE_ROWS 2 ++/* MSIX_PBA_TABLE: MSIX Pending Bit Array */ ++#define FR_CZ_MSIX_PBA_TABLE 0x00008000 ++/* FR_BZ_MSIX_PBA_TABLE_STEP 4 */ ++#define FR_CZ_MSIX_PBA_TABLE_ROWS 32 ++#define FRF_BZ_MSIX_PBA_PEND_DWORD_LBN 0 ++#define FRF_BZ_MSIX_PBA_PEND_DWORD_WIDTH 32 ++ ++/* SRM_DBG_REG: SRAM debug access */ ++#define FR_BZ_SRM_DBG 0x03000000 ++#define FR_BZ_SRM_DBG_STEP 8 ++#define FR_CZ_SRM_DBG_ROWS 262144 ++#define FR_BB_SRM_DBG_ROWS 2097152 ++#define FRF_BZ_SRM_DBG_LBN 0 ++#define FRF_BZ_SRM_DBG_WIDTH 64 ++ ++/* TB_MSIX_PBA_TABLE: MSIX Pending Bit Array */ ++#define FR_CZ_TB_MSIX_PBA_TABLE 0x00008000 ++#define FR_CZ_TB_MSIX_PBA_TABLE_STEP 4 ++#define FR_CZ_TB_MSIX_PBA_TABLE_ROWS 1024 ++#define FRF_CZ_TB_MSIX_PBA_PEND_DWORD_LBN 0 ++#define FRF_CZ_TB_MSIX_PBA_PEND_DWORD_WIDTH 32 ++ ++/* DRIVER_EV */ ++#define FSF_AZ_DRIVER_EV_SUBCODE_LBN 56 ++#define FSF_AZ_DRIVER_EV_SUBCODE_WIDTH 4 ++#define FSE_BZ_TX_DSC_ERROR_EV 15 ++#define FSE_BZ_RX_DSC_ERROR_EV 14 ++#define FSE_AA_RX_RECOVER_EV 11 ++#define FSE_AZ_TIMER_EV 10 ++#define FSE_AZ_TX_PKT_NON_TCP_UDP 9 ++#define FSE_AZ_WAKE_UP_EV 6 ++#define FSE_AZ_SRM_UPD_DONE_EV 5 ++#define FSE_AB_EVQ_NOT_EN_EV 3 ++#define FSE_AZ_EVQ_INIT_DONE_EV 2 ++#define FSE_AZ_RX_DESCQ_FLS_DONE_EV 1 ++#define FSE_AZ_TX_DESCQ_FLS_DONE_EV 0 ++#define FSF_AZ_DRIVER_EV_SUBDATA_LBN 0 ++#define FSF_AZ_DRIVER_EV_SUBDATA_WIDTH 14 ++ ++/* EVENT_ENTRY */ ++#define FSF_AZ_EV_CODE_LBN 60 ++#define FSF_AZ_EV_CODE_WIDTH 4 ++#define FSE_CZ_EV_CODE_MCDI_EV 12 ++#define FSE_CZ_EV_CODE_USER_EV 8 ++#define FSE_AZ_EV_CODE_DRV_GEN_EV 7 ++#define FSE_AZ_EV_CODE_GLOBAL_EV 6 ++#define FSE_AZ_EV_CODE_DRIVER_EV 5 ++#define FSE_AZ_EV_CODE_TX_EV 2 ++#define FSE_AZ_EV_CODE_RX_EV 0 ++#define FSF_AZ_EV_DATA_LBN 0 ++#define FSF_AZ_EV_DATA_WIDTH 60 ++ ++/* GLOBAL_EV */ ++#define FSF_BB_GLB_EV_RX_RECOVERY_LBN 12 ++#define FSF_BB_GLB_EV_RX_RECOVERY_WIDTH 1 ++#define FSF_AA_GLB_EV_RX_RECOVERY_LBN 11 ++#define FSF_AA_GLB_EV_RX_RECOVERY_WIDTH 1 ++#define FSF_BB_GLB_EV_XG_MGT_INTR_LBN 11 ++#define FSF_BB_GLB_EV_XG_MGT_INTR_WIDTH 1 ++#define FSF_AB_GLB_EV_XFP_PHY0_INTR_LBN 10 ++#define FSF_AB_GLB_EV_XFP_PHY0_INTR_WIDTH 1 ++#define FSF_AB_GLB_EV_XG_PHY0_INTR_LBN 9 ++#define FSF_AB_GLB_EV_XG_PHY0_INTR_WIDTH 1 ++#define FSF_AB_GLB_EV_G_PHY0_INTR_LBN 7 ++#define FSF_AB_GLB_EV_G_PHY0_INTR_WIDTH 1 ++ ++/* LEGACY_INT_VEC */ ++#define FSF_AZ_NET_IVEC_FATAL_INT_LBN 64 ++#define FSF_AZ_NET_IVEC_FATAL_INT_WIDTH 1 ++#define FSF_AZ_NET_IVEC_INT_Q_LBN 40 ++#define FSF_AZ_NET_IVEC_INT_Q_WIDTH 4 ++#define FSF_AZ_NET_IVEC_INT_FLAG_LBN 32 ++#define FSF_AZ_NET_IVEC_INT_FLAG_WIDTH 1 ++#define FSF_AZ_NET_IVEC_EVQ_FIFO_HF_LBN 1 ++#define FSF_AZ_NET_IVEC_EVQ_FIFO_HF_WIDTH 1 ++#define FSF_AZ_NET_IVEC_EVQ_FIFO_AF_LBN 0 ++#define FSF_AZ_NET_IVEC_EVQ_FIFO_AF_WIDTH 1 ++ ++/* MC_XGMAC_FLTR_RULE_DEF */ ++#define FSF_CZ_MC_XFRC_MODE_LBN 416 ++#define FSF_CZ_MC_XFRC_MODE_WIDTH 1 ++#define FSE_CZ_MC_XFRC_MODE_LAYERED 1 ++#define FSE_CZ_MC_XFRC_MODE_SIMPLE 0 ++#define FSF_CZ_MC_XFRC_HASH_LBN 384 ++#define FSF_CZ_MC_XFRC_HASH_WIDTH 32 ++#define FSF_CZ_MC_XFRC_LAYER4_BYTE_MASK_LBN 256 ++#define FSF_CZ_MC_XFRC_LAYER4_BYTE_MASK_WIDTH 128 ++#define FSF_CZ_MC_XFRC_LAYER3_BYTE_MASK_LBN 128 ++#define FSF_CZ_MC_XFRC_LAYER3_BYTE_MASK_WIDTH 128 ++#define FSF_CZ_MC_XFRC_LAYER2_OR_SIMPLE_BYTE_MASK_LBN 0 ++#define FSF_CZ_MC_XFRC_LAYER2_OR_SIMPLE_BYTE_MASK_WIDTH 128 ++ ++/* RX_EV */ ++#define FSF_CZ_RX_EV_PKT_NOT_PARSED_LBN 58 ++#define FSF_CZ_RX_EV_PKT_NOT_PARSED_WIDTH 1 ++#define FSF_CZ_RX_EV_IPV6_PKT_LBN 57 ++#define FSF_CZ_RX_EV_IPV6_PKT_WIDTH 1 ++#define FSF_AZ_RX_EV_PKT_OK_LBN 56 ++#define FSF_AZ_RX_EV_PKT_OK_WIDTH 1 ++#define FSF_AZ_RX_EV_PAUSE_FRM_ERR_LBN 55 ++#define FSF_AZ_RX_EV_PAUSE_FRM_ERR_WIDTH 1 ++#define FSF_AZ_RX_EV_BUF_OWNER_ID_ERR_LBN 54 ++#define FSF_AZ_RX_EV_BUF_OWNER_ID_ERR_WIDTH 1 ++#define FSF_AZ_RX_EV_IP_FRAG_ERR_LBN 53 ++#define FSF_AZ_RX_EV_IP_FRAG_ERR_WIDTH 1 ++#define FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR_LBN 52 ++#define FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1 ++#define FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51 ++#define FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1 ++#define FSF_AZ_RX_EV_ETH_CRC_ERR_LBN 50 ++#define FSF_AZ_RX_EV_ETH_CRC_ERR_WIDTH 1 ++#define FSF_AZ_RX_EV_FRM_TRUNC_LBN 49 ++#define FSF_AZ_RX_EV_FRM_TRUNC_WIDTH 1 ++#define FSF_AA_RX_EV_DRIB_NIB_LBN 49 ++#define FSF_AA_RX_EV_DRIB_NIB_WIDTH 1 ++#define FSF_AZ_RX_EV_TOBE_DISC_LBN 47 ++#define FSF_AZ_RX_EV_TOBE_DISC_WIDTH 1 ++#define FSF_AZ_RX_EV_PKT_TYPE_LBN 44 ++#define FSF_AZ_RX_EV_PKT_TYPE_WIDTH 3 ++#define FSE_AZ_RX_EV_PKT_TYPE_VLAN_JUMBO 5 ++#define FSE_AZ_RX_EV_PKT_TYPE_VLAN_LLC 4 ++#define FSE_AZ_RX_EV_PKT_TYPE_VLAN 3 ++#define FSE_AZ_RX_EV_PKT_TYPE_JUMBO 2 ++#define FSE_AZ_RX_EV_PKT_TYPE_LLC 1 ++#define FSE_AZ_RX_EV_PKT_TYPE_ETH 0 ++#define FSF_AZ_RX_EV_HDR_TYPE_LBN 42 ++#define FSF_AZ_RX_EV_HDR_TYPE_WIDTH 2 ++#define FSE_AZ_RX_EV_HDR_TYPE_OTHER 3 ++#define FSE_AB_RX_EV_HDR_TYPE_IPV4_OTHER 2 ++#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_OTHER 2 ++#define FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP 1 ++#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP 1 ++#define FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP 0 ++#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP 0 ++#define FSF_AZ_RX_EV_DESC_Q_EMPTY_LBN 41 ++#define FSF_AZ_RX_EV_DESC_Q_EMPTY_WIDTH 1 ++#define FSF_AZ_RX_EV_MCAST_HASH_MATCH_LBN 40 ++#define FSF_AZ_RX_EV_MCAST_HASH_MATCH_WIDTH 1 ++#define FSF_AZ_RX_EV_MCAST_PKT_LBN 39 ++#define FSF_AZ_RX_EV_MCAST_PKT_WIDTH 1 ++#define FSF_AA_RX_EV_RECOVERY_FLAG_LBN 37 ++#define FSF_AA_RX_EV_RECOVERY_FLAG_WIDTH 1 ++#define FSF_AZ_RX_EV_Q_LABEL_LBN 32 ++#define FSF_AZ_RX_EV_Q_LABEL_WIDTH 5 ++#define FSF_AZ_RX_EV_JUMBO_CONT_LBN 31 ++#define FSF_AZ_RX_EV_JUMBO_CONT_WIDTH 1 ++#define FSF_AZ_RX_EV_PORT_LBN 30 ++#define FSF_AZ_RX_EV_PORT_WIDTH 1 ++#define FSF_AZ_RX_EV_BYTE_CNT_LBN 16 ++#define FSF_AZ_RX_EV_BYTE_CNT_WIDTH 14 ++#define FSF_AZ_RX_EV_SOP_LBN 15 ++#define FSF_AZ_RX_EV_SOP_WIDTH 1 ++#define FSF_AZ_RX_EV_ISCSI_PKT_OK_LBN 14 ++#define FSF_AZ_RX_EV_ISCSI_PKT_OK_WIDTH 1 ++#define FSF_AZ_RX_EV_ISCSI_DDIG_ERR_LBN 13 ++#define FSF_AZ_RX_EV_ISCSI_DDIG_ERR_WIDTH 1 ++#define FSF_AZ_RX_EV_ISCSI_HDIG_ERR_LBN 12 ++#define FSF_AZ_RX_EV_ISCSI_HDIG_ERR_WIDTH 1 ++#define FSF_AZ_RX_EV_DESC_PTR_LBN 0 ++#define FSF_AZ_RX_EV_DESC_PTR_WIDTH 12 ++ ++/* RX_KER_DESC */ ++#define FSF_AZ_RX_KER_BUF_SIZE_LBN 48 ++#define FSF_AZ_RX_KER_BUF_SIZE_WIDTH 14 ++#define FSF_AZ_RX_KER_BUF_REGION_LBN 46 ++#define FSF_AZ_RX_KER_BUF_REGION_WIDTH 2 ++#define FSF_AZ_RX_KER_BUF_ADDR_LBN 0 ++#define FSF_AZ_RX_KER_BUF_ADDR_WIDTH 46 ++ ++/* RX_USER_DESC */ ++#define FSF_AZ_RX_USER_2BYTE_OFFSET_LBN 20 ++#define FSF_AZ_RX_USER_2BYTE_OFFSET_WIDTH 12 ++#define FSF_AZ_RX_USER_BUF_ID_LBN 0 ++#define FSF_AZ_RX_USER_BUF_ID_WIDTH 20 ++ ++/* TX_EV */ ++#define FSF_AZ_TX_EV_PKT_ERR_LBN 38 ++#define FSF_AZ_TX_EV_PKT_ERR_WIDTH 1 ++#define FSF_AZ_TX_EV_PKT_TOO_BIG_LBN 37 ++#define FSF_AZ_TX_EV_PKT_TOO_BIG_WIDTH 1 ++#define FSF_AZ_TX_EV_Q_LABEL_LBN 32 ++#define FSF_AZ_TX_EV_Q_LABEL_WIDTH 5 ++#define FSF_AZ_TX_EV_PORT_LBN 16 ++#define FSF_AZ_TX_EV_PORT_WIDTH 1 ++#define FSF_AZ_TX_EV_WQ_FF_FULL_LBN 15 ++#define FSF_AZ_TX_EV_WQ_FF_FULL_WIDTH 1 ++#define FSF_AZ_TX_EV_BUF_OWNER_ID_ERR_LBN 14 ++#define FSF_AZ_TX_EV_BUF_OWNER_ID_ERR_WIDTH 1 ++#define FSF_AZ_TX_EV_COMP_LBN 12 ++#define FSF_AZ_TX_EV_COMP_WIDTH 1 ++#define FSF_AZ_TX_EV_DESC_PTR_LBN 0 ++#define FSF_AZ_TX_EV_DESC_PTR_WIDTH 12 ++ ++/* TX_KER_DESC */ ++#define FSF_AZ_TX_KER_CONT_LBN 62 ++#define FSF_AZ_TX_KER_CONT_WIDTH 1 ++#define FSF_AZ_TX_KER_BYTE_COUNT_LBN 48 ++#define FSF_AZ_TX_KER_BYTE_COUNT_WIDTH 14 ++#define FSF_AZ_TX_KER_BUF_REGION_LBN 46 ++#define FSF_AZ_TX_KER_BUF_REGION_WIDTH 2 ++#define FSF_AZ_TX_KER_BUF_ADDR_LBN 0 ++#define FSF_AZ_TX_KER_BUF_ADDR_WIDTH 46 ++ ++/* TX_USER_DESC */ ++#define FSF_AZ_TX_USER_SW_EV_EN_LBN 48 ++#define FSF_AZ_TX_USER_SW_EV_EN_WIDTH 1 ++#define FSF_AZ_TX_USER_CONT_LBN 46 ++#define FSF_AZ_TX_USER_CONT_WIDTH 1 ++#define FSF_AZ_TX_USER_BYTE_CNT_LBN 33 ++#define FSF_AZ_TX_USER_BYTE_CNT_WIDTH 13 ++#define FSF_AZ_TX_USER_BUF_ID_LBN 13 ++#define FSF_AZ_TX_USER_BUF_ID_WIDTH 20 ++#define FSF_AZ_TX_USER_BYTE_OFS_LBN 0 ++#define FSF_AZ_TX_USER_BYTE_OFS_WIDTH 13 ++ ++/* USER_EV */ ++#define FSF_CZ_USER_QID_LBN 32 ++#define FSF_CZ_USER_QID_WIDTH 10 ++#define FSF_CZ_USER_EV_REG_VALUE_LBN 0 ++#define FSF_CZ_USER_EV_REG_VALUE_WIDTH 32 ++ ++/************************************************************************** ++ * ++ * Falcon B0 PCIe core indirect registers ++ * ++ ************************************************************************** ++ */ ++ ++#define FPCR_BB_PCIE_DEVICE_CTRL_STAT 0x68 ++ ++#define FPCR_BB_PCIE_LINK_CTRL_STAT 0x70 ++ ++#define FPCR_BB_ACK_RPL_TIMER 0x700 ++#define FPCRF_BB_ACK_TL_LBN 0 ++#define FPCRF_BB_ACK_TL_WIDTH 16 ++#define FPCRF_BB_RPL_TL_LBN 16 ++#define FPCRF_BB_RPL_TL_WIDTH 16 ++ ++#define FPCR_BB_ACK_FREQ 0x70C ++#define FPCRF_BB_ACK_FREQ_LBN 0 ++#define FPCRF_BB_ACK_FREQ_WIDTH 7 ++ ++/************************************************************************** ++ * ++ * Pseudo-registers and fields ++ * ++ ************************************************************************** ++ */ ++ ++/* Interrupt acknowledge work-around register (A0/A1 only) */ ++#define FR_AA_WORK_AROUND_BROKEN_PCI_READS 0x0070 ++ ++/* EE_SPI_HCMD_REG: SPI host command register */ ++/* Values for the EE_SPI_HCMD_SF_SEL register field */ ++#define FFE_AB_SPI_DEVICE_EEPROM 0 ++#define FFE_AB_SPI_DEVICE_FLASH 1 ++ ++/* NIC_STAT_REG: NIC status register */ ++#define FRF_AB_STRAP_10G_LBN 2 ++#define FRF_AB_STRAP_10G_WIDTH 1 ++#define FRF_AA_STRAP_PCIE_LBN 0 ++#define FRF_AA_STRAP_PCIE_WIDTH 1 ++ ++/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */ ++#define FRF_AZ_FATAL_INTR_LBN 0 ++#define FRF_AZ_FATAL_INTR_WIDTH 12 ++ ++/* SRM_CFG_REG: SRAM configuration register */ ++/* We treat the number of SRAM banks and bank size as a single field */ ++#define FRF_AZ_SRM_NB_SZ_LBN FRF_AZ_SRM_BANK_SIZE_LBN ++#define FRF_AZ_SRM_NB_SZ_WIDTH \ ++ (FRF_AZ_SRM_BANK_SIZE_WIDTH + FRF_AZ_SRM_NUM_BANK_WIDTH) ++#define FFE_AB_SRM_NB1_SZ2M 0 ++#define FFE_AB_SRM_NB1_SZ4M 1 ++#define FFE_AB_SRM_NB1_SZ8M 2 ++#define FFE_AB_SRM_NB_SZ_DEF 3 ++#define FFE_AB_SRM_NB2_SZ4M 4 ++#define FFE_AB_SRM_NB2_SZ8M 5 ++#define FFE_AB_SRM_NB2_SZ16M 6 ++#define FFE_AB_SRM_NB_SZ_RES 7 ++ ++/* RX_DESC_UPD_REGP0: Receive descriptor update register. */ ++/* We write just the last dword of these registers */ ++#define FR_AZ_RX_DESC_UPD_DWORD_P0 \ ++ (BUILD_BUG_ON_ZERO(FR_AA_RX_DESC_UPD_KER != FR_BZ_RX_DESC_UPD_P0) + \ ++ FR_BZ_RX_DESC_UPD_P0 + 3 * 4) ++#define FRF_AZ_RX_DESC_WPTR_DWORD_LBN (FRF_AZ_RX_DESC_WPTR_LBN - 3 * 32) ++#define FRF_AZ_RX_DESC_WPTR_DWORD_WIDTH FRF_AZ_RX_DESC_WPTR_WIDTH ++ ++/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */ ++#define FR_AZ_TX_DESC_UPD_DWORD_P0 \ ++ (BUILD_BUG_ON_ZERO(FR_AA_TX_DESC_UPD_KER != FR_BZ_TX_DESC_UPD_P0) + \ ++ FR_BZ_TX_DESC_UPD_P0 + 3 * 4) ++#define FRF_AZ_TX_DESC_WPTR_DWORD_LBN (FRF_AZ_TX_DESC_WPTR_LBN - 3 * 32) ++#define FRF_AZ_TX_DESC_WPTR_DWORD_WIDTH FRF_AZ_TX_DESC_WPTR_WIDTH ++ ++/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */ ++#define FRF_AB_GMF_HSTFLTRFRM_PAUSE_LBN 12 ++#define FRF_AB_GMF_HSTFLTRFRM_PAUSE_WIDTH 1 ++ ++/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */ ++#define FRF_AB_GMF_HSTFLTRFRMDC_PAUSE_LBN 12 ++#define FRF_AB_GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1 ++ ++/* XM_TX_PARAM_REG: XGMAC transmit parameter register */ ++#define FRF_AB_XM_MAX_TX_FRM_SIZE_LBN FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN ++#define FRF_AB_XM_MAX_TX_FRM_SIZE_WIDTH (FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH + \ ++ FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH) ++ ++/* XM_RX_PARAM_REG: XGMAC receive parameter register */ ++#define FRF_AB_XM_MAX_RX_FRM_SIZE_LBN FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN ++#define FRF_AB_XM_MAX_RX_FRM_SIZE_WIDTH (FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH + \ ++ FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH) ++ ++/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */ ++/* Default values */ ++#define FFE_AB_XX_TXDRV_DEQ_DEF 0xe /* deq=.6 */ ++#define FFE_AB_XX_TXDRV_DTX_DEF 0x5 /* 1.25 */ ++#define FFE_AB_XX_SD_CTL_DRV_DEF 0 /* 20mA */ ++ ++/* XX_CORE_STAT_REG: XAUI XGXS core status register */ ++/* XGXS all-lanes status fields */ ++#define FRF_AB_XX_SYNC_STAT_LBN FRF_AB_XX_SYNC_STAT0_LBN ++#define FRF_AB_XX_SYNC_STAT_WIDTH 4 ++#define FRF_AB_XX_COMMA_DET_LBN FRF_AB_XX_COMMA_DET_CH0_LBN ++#define FRF_AB_XX_COMMA_DET_WIDTH 4 ++#define FRF_AB_XX_CHAR_ERR_LBN FRF_AB_XX_CHAR_ERR_CH0_LBN ++#define FRF_AB_XX_CHAR_ERR_WIDTH 4 ++#define FRF_AB_XX_DISPERR_LBN FRF_AB_XX_DISPERR_CH0_LBN ++#define FRF_AB_XX_DISPERR_WIDTH 4 ++#define FFE_AB_XX_STAT_ALL_LANES 0xf ++#define FRF_AB_XX_FORCE_SIG_LBN FRF_AB_XX_FORCE_SIG0_VAL_LBN ++#define FRF_AB_XX_FORCE_SIG_WIDTH 8 ++#define FFE_AB_XX_FORCE_SIG_ALL_LANES 0xff ++ ++/* DRIVER_EV */ ++/* Sub-fields of an RX flush completion event */ ++#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_LBN 12 ++#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1 ++#define FSF_AZ_DRIVER_EV_RX_DESCQ_ID_LBN 0 ++#define FSF_AZ_DRIVER_EV_RX_DESCQ_ID_WIDTH 12 ++ ++/* EVENT_ENTRY */ ++/* Magic number field for event test */ ++#define FSF_AZ_DRV_GEN_EV_MAGIC_LBN 0 ++#define FSF_AZ_DRV_GEN_EV_MAGIC_WIDTH 32 ++ ++/************************************************************************** ++ * ++ * Falcon MAC stats ++ * ++ ************************************************************************** ++ * ++ */ ++ ++#define GRxGoodOct_offset 0x0 ++#define GRxGoodOct_WIDTH 48 ++#define GRxBadOct_offset 0x8 ++#define GRxBadOct_WIDTH 48 ++#define GRxMissPkt_offset 0x10 ++#define GRxMissPkt_WIDTH 32 ++#define GRxFalseCRS_offset 0x14 ++#define GRxFalseCRS_WIDTH 32 ++#define GRxPausePkt_offset 0x18 ++#define GRxPausePkt_WIDTH 32 ++#define GRxBadPkt_offset 0x1C ++#define GRxBadPkt_WIDTH 32 ++#define GRxUcastPkt_offset 0x20 ++#define GRxUcastPkt_WIDTH 32 ++#define GRxMcastPkt_offset 0x24 ++#define GRxMcastPkt_WIDTH 32 ++#define GRxBcastPkt_offset 0x28 ++#define GRxBcastPkt_WIDTH 32 ++#define GRxGoodLt64Pkt_offset 0x2C ++#define GRxGoodLt64Pkt_WIDTH 32 ++#define GRxBadLt64Pkt_offset 0x30 ++#define GRxBadLt64Pkt_WIDTH 32 ++#define GRx64Pkt_offset 0x34 ++#define GRx64Pkt_WIDTH 32 ++#define GRx65to127Pkt_offset 0x38 ++#define GRx65to127Pkt_WIDTH 32 ++#define GRx128to255Pkt_offset 0x3C ++#define GRx128to255Pkt_WIDTH 32 ++#define GRx256to511Pkt_offset 0x40 ++#define GRx256to511Pkt_WIDTH 32 ++#define GRx512to1023Pkt_offset 0x44 ++#define GRx512to1023Pkt_WIDTH 32 ++#define GRx1024to15xxPkt_offset 0x48 ++#define GRx1024to15xxPkt_WIDTH 32 ++#define GRx15xxtoJumboPkt_offset 0x4C ++#define GRx15xxtoJumboPkt_WIDTH 32 ++#define GRxGtJumboPkt_offset 0x50 ++#define GRxGtJumboPkt_WIDTH 32 ++#define GRxFcsErr64to15xxPkt_offset 0x54 ++#define GRxFcsErr64to15xxPkt_WIDTH 32 ++#define GRxFcsErr15xxtoJumboPkt_offset 0x58 ++#define GRxFcsErr15xxtoJumboPkt_WIDTH 32 ++#define GRxFcsErrGtJumboPkt_offset 0x5C ++#define GRxFcsErrGtJumboPkt_WIDTH 32 ++#define GTxGoodBadOct_offset 0x80 ++#define GTxGoodBadOct_WIDTH 48 ++#define GTxGoodOct_offset 0x88 ++#define GTxGoodOct_WIDTH 48 ++#define GTxSglColPkt_offset 0x90 ++#define GTxSglColPkt_WIDTH 32 ++#define GTxMultColPkt_offset 0x94 ++#define GTxMultColPkt_WIDTH 32 ++#define GTxExColPkt_offset 0x98 ++#define GTxExColPkt_WIDTH 32 ++#define GTxDefPkt_offset 0x9C ++#define GTxDefPkt_WIDTH 32 ++#define GTxLateCol_offset 0xA0 ++#define GTxLateCol_WIDTH 32 ++#define GTxExDefPkt_offset 0xA4 ++#define GTxExDefPkt_WIDTH 32 ++#define GTxPausePkt_offset 0xA8 ++#define GTxPausePkt_WIDTH 32 ++#define GTxBadPkt_offset 0xAC ++#define GTxBadPkt_WIDTH 32 ++#define GTxUcastPkt_offset 0xB0 ++#define GTxUcastPkt_WIDTH 32 ++#define GTxMcastPkt_offset 0xB4 ++#define GTxMcastPkt_WIDTH 32 ++#define GTxBcastPkt_offset 0xB8 ++#define GTxBcastPkt_WIDTH 32 ++#define GTxLt64Pkt_offset 0xBC ++#define GTxLt64Pkt_WIDTH 32 ++#define GTx64Pkt_offset 0xC0 ++#define GTx64Pkt_WIDTH 32 ++#define GTx65to127Pkt_offset 0xC4 ++#define GTx65to127Pkt_WIDTH 32 ++#define GTx128to255Pkt_offset 0xC8 ++#define GTx128to255Pkt_WIDTH 32 ++#define GTx256to511Pkt_offset 0xCC ++#define GTx256to511Pkt_WIDTH 32 ++#define GTx512to1023Pkt_offset 0xD0 ++#define GTx512to1023Pkt_WIDTH 32 ++#define GTx1024to15xxPkt_offset 0xD4 ++#define GTx1024to15xxPkt_WIDTH 32 ++#define GTx15xxtoJumboPkt_offset 0xD8 ++#define GTx15xxtoJumboPkt_WIDTH 32 ++#define GTxGtJumboPkt_offset 0xDC ++#define GTxGtJumboPkt_WIDTH 32 ++#define GTxNonTcpUdpPkt_offset 0xE0 ++#define GTxNonTcpUdpPkt_WIDTH 16 ++#define GTxMacSrcErrPkt_offset 0xE4 ++#define GTxMacSrcErrPkt_WIDTH 16 ++#define GTxIpSrcErrPkt_offset 0xE8 ++#define GTxIpSrcErrPkt_WIDTH 16 ++#define GDmaDone_offset 0xEC ++#define GDmaDone_WIDTH 32 ++ ++#define XgRxOctets_offset 0x0 ++#define XgRxOctets_WIDTH 48 ++#define XgRxOctetsOK_offset 0x8 ++#define XgRxOctetsOK_WIDTH 48 ++#define XgRxPkts_offset 0x10 ++#define XgRxPkts_WIDTH 32 ++#define XgRxPktsOK_offset 0x14 ++#define XgRxPktsOK_WIDTH 32 ++#define XgRxBroadcastPkts_offset 0x18 ++#define XgRxBroadcastPkts_WIDTH 32 ++#define XgRxMulticastPkts_offset 0x1C ++#define XgRxMulticastPkts_WIDTH 32 ++#define XgRxUnicastPkts_offset 0x20 ++#define XgRxUnicastPkts_WIDTH 32 ++#define XgRxUndersizePkts_offset 0x24 ++#define XgRxUndersizePkts_WIDTH 32 ++#define XgRxOversizePkts_offset 0x28 ++#define XgRxOversizePkts_WIDTH 32 ++#define XgRxJabberPkts_offset 0x2C ++#define XgRxJabberPkts_WIDTH 32 ++#define XgRxUndersizeFCSerrorPkts_offset 0x30 ++#define XgRxUndersizeFCSerrorPkts_WIDTH 32 ++#define XgRxDropEvents_offset 0x34 ++#define XgRxDropEvents_WIDTH 32 ++#define XgRxFCSerrorPkts_offset 0x38 ++#define XgRxFCSerrorPkts_WIDTH 32 ++#define XgRxAlignError_offset 0x3C ++#define XgRxAlignError_WIDTH 32 ++#define XgRxSymbolError_offset 0x40 ++#define XgRxSymbolError_WIDTH 32 ++#define XgRxInternalMACError_offset 0x44 ++#define XgRxInternalMACError_WIDTH 32 ++#define XgRxControlPkts_offset 0x48 ++#define XgRxControlPkts_WIDTH 32 ++#define XgRxPausePkts_offset 0x4C ++#define XgRxPausePkts_WIDTH 32 ++#define XgRxPkts64Octets_offset 0x50 ++#define XgRxPkts64Octets_WIDTH 32 ++#define XgRxPkts65to127Octets_offset 0x54 ++#define XgRxPkts65to127Octets_WIDTH 32 ++#define XgRxPkts128to255Octets_offset 0x58 ++#define XgRxPkts128to255Octets_WIDTH 32 ++#define XgRxPkts256to511Octets_offset 0x5C ++#define XgRxPkts256to511Octets_WIDTH 32 ++#define XgRxPkts512to1023Octets_offset 0x60 ++#define XgRxPkts512to1023Octets_WIDTH 32 ++#define XgRxPkts1024to15xxOctets_offset 0x64 ++#define XgRxPkts1024to15xxOctets_WIDTH 32 ++#define XgRxPkts15xxtoMaxOctets_offset 0x68 ++#define XgRxPkts15xxtoMaxOctets_WIDTH 32 ++#define XgRxLengthError_offset 0x6C ++#define XgRxLengthError_WIDTH 32 ++#define XgTxPkts_offset 0x80 ++#define XgTxPkts_WIDTH 32 ++#define XgTxOctets_offset 0x88 ++#define XgTxOctets_WIDTH 48 ++#define XgTxMulticastPkts_offset 0x90 ++#define XgTxMulticastPkts_WIDTH 32 ++#define XgTxBroadcastPkts_offset 0x94 ++#define XgTxBroadcastPkts_WIDTH 32 ++#define XgTxUnicastPkts_offset 0x98 ++#define XgTxUnicastPkts_WIDTH 32 ++#define XgTxControlPkts_offset 0x9C ++#define XgTxControlPkts_WIDTH 32 ++#define XgTxPausePkts_offset 0xA0 ++#define XgTxPausePkts_WIDTH 32 ++#define XgTxPkts64Octets_offset 0xA4 ++#define XgTxPkts64Octets_WIDTH 32 ++#define XgTxPkts65to127Octets_offset 0xA8 ++#define XgTxPkts65to127Octets_WIDTH 32 ++#define XgTxPkts128to255Octets_offset 0xAC ++#define XgTxPkts128to255Octets_WIDTH 32 ++#define XgTxPkts256to511Octets_offset 0xB0 ++#define XgTxPkts256to511Octets_WIDTH 32 ++#define XgTxPkts512to1023Octets_offset 0xB4 ++#define XgTxPkts512to1023Octets_WIDTH 32 ++#define XgTxPkts1024to15xxOctets_offset 0xB8 ++#define XgTxPkts1024to15xxOctets_WIDTH 32 ++#define XgTxPkts1519toMaxOctets_offset 0xBC ++#define XgTxPkts1519toMaxOctets_WIDTH 32 ++#define XgTxUndersizePkts_offset 0xC0 ++#define XgTxUndersizePkts_WIDTH 32 ++#define XgTxOversizePkts_offset 0xC4 ++#define XgTxOversizePkts_WIDTH 32 ++#define XgTxNonTcpUdpPkt_offset 0xC8 ++#define XgTxNonTcpUdpPkt_WIDTH 16 ++#define XgTxMacSrcErrPkt_offset 0xCC ++#define XgTxMacSrcErrPkt_WIDTH 16 ++#define XgTxIpSrcErrPkt_offset 0xD0 ++#define XgTxIpSrcErrPkt_WIDTH 16 ++#define XgDmaDone_offset 0xD4 ++#define XgDmaDone_WIDTH 32 ++ ++#define FALCON_STATS_NOT_DONE 0x00000000 ++#define FALCON_STATS_DONE 0xffffffff ++ ++/************************************************************************** ++ * ++ * Falcon non-volatile configuration ++ * ++ ************************************************************************** ++ */ ++ ++/* Board configuration v2 (v1 is obsolete; later versions are compatible) */ ++struct falcon_nvconfig_board_v2 { ++ __le16 nports; ++ u8 port0_phy_addr; ++ u8 port0_phy_type; ++ u8 port1_phy_addr; ++ u8 port1_phy_type; ++ __le16 asic_sub_revision; ++ __le16 board_revision; ++} __packed; ++ ++/* Board configuration v3 extra information */ ++struct falcon_nvconfig_board_v3 { ++ __le32 spi_device_type[2]; ++} __packed; ++ ++/* Bit numbers for spi_device_type */ ++#define SPI_DEV_TYPE_SIZE_LBN 0 ++#define SPI_DEV_TYPE_SIZE_WIDTH 5 ++#define SPI_DEV_TYPE_ADDR_LEN_LBN 6 ++#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2 ++#define SPI_DEV_TYPE_ERASE_CMD_LBN 8 ++#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8 ++#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16 ++#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5 ++#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24 ++#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5 ++#define SPI_DEV_TYPE_FIELD(type, field) \ ++ (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field))) ++ ++#define FALCON_NVCONFIG_OFFSET 0x300 ++ ++#define FALCON_NVCONFIG_BOARD_MAGIC_NUM 0xFA1C ++struct falcon_nvconfig { ++ efx_oword_t ee_vpd_cfg_reg; /* 0x300 */ ++ u8 mac_address[2][8]; /* 0x310 */ ++ efx_oword_t pcie_sd_ctl0123_reg; /* 0x320 */ ++ efx_oword_t pcie_sd_ctl45_reg; /* 0x330 */ ++ efx_oword_t pcie_pcs_ctl_stat_reg; /* 0x340 */ ++ efx_oword_t hw_init_reg; /* 0x350 */ ++ efx_oword_t nic_stat_reg; /* 0x360 */ ++ efx_oword_t glb_ctl_reg; /* 0x370 */ ++ efx_oword_t srm_cfg_reg; /* 0x380 */ ++ efx_oword_t spare_reg; /* 0x390 */ ++ __le16 board_magic_num; /* 0x3A0 */ ++ __le16 board_struct_ver; ++ __le16 board_checksum; ++ struct falcon_nvconfig_board_v2 board_v2; ++ efx_oword_t ee_base_page_reg; /* 0x3B0 */ ++ struct falcon_nvconfig_board_v3 board_v3; /* 0x3C0 */ ++} __packed; ++ ++#endif /* EFX_REGS_H */ +diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c +index 98bff5a..a97c923 100644 +--- a/drivers/net/sfc/rx.c ++++ b/drivers/net/sfc/rx.c +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2005-2008 Solarflare Communications Inc. ++ * Copyright 2005-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -16,9 +16,8 @@ + #include + #include + #include "net_driver.h" +-#include "rx.h" + #include "efx.h" +-#include "falcon.h" ++#include "nic.h" + #include "selftest.h" + #include "workarounds.h" + +@@ -61,7 +60,7 @@ + * rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_LRO ? + * RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB) + */ +-static int rx_alloc_method = RX_ALLOC_METHOD_PAGE; ++static int rx_alloc_method = RX_ALLOC_METHOD_AUTO; + + #define RX_ALLOC_LEVEL_LRO 0x2000 + #define RX_ALLOC_LEVEL_MAX 0x3000 +@@ -293,8 +292,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, + * fill anyway. + */ + fill_level = (rx_queue->added_count - rx_queue->removed_count); +- EFX_BUG_ON_PARANOID(fill_level > +- rx_queue->efx->type->rxd_ring_mask + 1); ++ EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE); + + /* Don't fill if we don't need to */ + if (fill_level >= rx_queue->fast_fill_trigger) +@@ -316,8 +314,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, + retry: + /* Recalculate current fill level now that we have the lock */ + fill_level = (rx_queue->added_count - rx_queue->removed_count); +- EFX_BUG_ON_PARANOID(fill_level > +- rx_queue->efx->type->rxd_ring_mask + 1); ++ EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE); + space = rx_queue->fast_fill_limit - fill_level; + if (space < EFX_RX_BATCH) + goto out_unlock; +@@ -329,8 +326,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, + + do { + for (i = 0; i < EFX_RX_BATCH; ++i) { +- index = (rx_queue->added_count & +- rx_queue->efx->type->rxd_ring_mask); ++ index = rx_queue->added_count & EFX_RXQ_MASK; + rx_buf = efx_rx_buffer(rx_queue, index); + rc = efx_init_rx_buffer(rx_queue, rx_buf); + if (unlikely(rc)) +@@ -345,7 +341,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, + + out: + /* Send write pointer to card. */ +- falcon_notify_rx_desc(rx_queue); ++ efx_nic_notify_rx_desc(rx_queue); + + /* If the fast fill is running inside from the refill tasklet, then + * for SMP systems it may be running on a different CPU to +@@ -448,17 +444,23 @@ static void efx_rx_packet_lro(struct efx_channel *channel, + bool checksummed) + { + struct napi_struct *napi = &channel->napi_str; ++ gro_result_t gro_result; + + /* Pass the skb/page into the LRO engine */ + if (rx_buf->page) { +- struct sk_buff *skb = napi_get_frags(napi); ++ struct page *page = rx_buf->page; ++ struct sk_buff *skb; + ++ EFX_BUG_ON_PARANOID(rx_buf->skb); ++ rx_buf->page = NULL; ++ ++ skb = napi_get_frags(napi); + if (!skb) { +- put_page(rx_buf->page); +- goto out; ++ put_page(page); ++ return; + } + +- skb_shinfo(skb)->frags[0].page = rx_buf->page; ++ skb_shinfo(skb)->frags[0].page = page; + skb_shinfo(skb)->frags[0].page_offset = + efx_rx_buf_offset(rx_buf); + skb_shinfo(skb)->frags[0].size = rx_buf->len; +@@ -470,17 +472,24 @@ static void efx_rx_packet_lro(struct efx_channel *channel, + skb->ip_summed = + checksummed ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; + +- napi_gro_frags(napi); ++ skb_record_rx_queue(skb, channel->channel); + +-out: +- EFX_BUG_ON_PARANOID(rx_buf->skb); +- rx_buf->page = NULL; ++ gro_result = napi_gro_frags(napi); + } else { +- EFX_BUG_ON_PARANOID(!rx_buf->skb); +- EFX_BUG_ON_PARANOID(!checksummed); ++ struct sk_buff *skb = rx_buf->skb; + +- napi_gro_receive(napi, rx_buf->skb); ++ EFX_BUG_ON_PARANOID(!skb); ++ EFX_BUG_ON_PARANOID(!checksummed); + rx_buf->skb = NULL; ++ ++ gro_result = napi_gro_receive(napi, skb); ++ } ++ ++ if (gro_result == GRO_NORMAL) { ++ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB; ++ } else if (gro_result != GRO_DROP) { ++ channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO; ++ channel->irq_mod_score += 2; + } + } + +@@ -558,7 +567,7 @@ void __efx_rx_packet(struct efx_channel *channel, + if (unlikely(efx->loopback_selftest)) { + efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len); + efx_free_rx_buffer(efx, rx_buf); +- goto done; ++ return; + } + + if (rx_buf->skb) { +@@ -570,34 +579,28 @@ void __efx_rx_packet(struct efx_channel *channel, + * at the ethernet header */ + rx_buf->skb->protocol = eth_type_trans(rx_buf->skb, + efx->net_dev); ++ ++ skb_record_rx_queue(rx_buf->skb, channel->channel); + } + + if (likely(checksummed || rx_buf->page)) { + efx_rx_packet_lro(channel, rx_buf, checksummed); +- goto done; ++ return; + } + + /* We now own the SKB */ + skb = rx_buf->skb; + rx_buf->skb = NULL; +- +- EFX_BUG_ON_PARANOID(rx_buf->page); +- EFX_BUG_ON_PARANOID(rx_buf->skb); + EFX_BUG_ON_PARANOID(!skb); + + /* Set the SKB flags */ + skb->ip_summed = CHECKSUM_NONE; + +- skb_record_rx_queue(skb, channel->channel); +- + /* Pass the packet up */ + netif_receive_skb(skb); + + /* Update allocation strategy method */ + channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB; +- +-done: +- ; + } + + void efx_rx_strategy(struct efx_channel *channel) +@@ -632,12 +635,12 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) + EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue); + + /* Allocate RX buffers */ +- rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer); ++ rxq_size = EFX_RXQ_SIZE * sizeof(*rx_queue->buffer); + rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL); + if (!rx_queue->buffer) + return -ENOMEM; + +- rc = falcon_probe_rx(rx_queue); ++ rc = efx_nic_probe_rx(rx_queue); + if (rc) { + kfree(rx_queue->buffer); + rx_queue->buffer = NULL; +@@ -647,7 +650,6 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) + + void efx_init_rx_queue(struct efx_rx_queue *rx_queue) + { +- struct efx_nic *efx = rx_queue->efx; + unsigned int max_fill, trigger, limit; + + EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue); +@@ -660,7 +662,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) + rx_queue->min_overfill = -1U; + + /* Initialise limit fields */ +- max_fill = efx->type->rxd_ring_mask + 1 - EFX_RXD_HEAD_ROOM; ++ max_fill = EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM; + trigger = max_fill * min(rx_refill_threshold, 100U) / 100U; + limit = max_fill * min(rx_refill_limit, 100U) / 100U; + +@@ -669,7 +671,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) + rx_queue->fast_fill_limit = limit; + + /* Set up RX descriptor ring */ +- falcon_init_rx(rx_queue); ++ efx_nic_init_rx(rx_queue); + } + + void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) +@@ -679,11 +681,11 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) + + EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue); + +- falcon_fini_rx(rx_queue); ++ efx_nic_fini_rx(rx_queue); + + /* Release RX buffers NB start at index 0 not current HW ptr */ + if (rx_queue->buffer) { +- for (i = 0; i <= rx_queue->efx->type->rxd_ring_mask; i++) { ++ for (i = 0; i <= EFX_RXQ_MASK; i++) { + rx_buf = efx_rx_buffer(rx_queue, i); + efx_fini_rx_buffer(rx_queue, rx_buf); + } +@@ -704,7 +706,7 @@ void efx_remove_rx_queue(struct efx_rx_queue *rx_queue) + { + EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue); + +- falcon_remove_rx(rx_queue); ++ efx_nic_remove_rx(rx_queue); + + kfree(rx_queue->buffer); + rx_queue->buffer = NULL; +diff --git a/drivers/net/sfc/rx.h b/drivers/net/sfc/rx.h +deleted file mode 100644 +index 42ee755..0000000 +--- a/drivers/net/sfc/rx.h ++++ /dev/null +@@ -1,26 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2006 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +- +-#ifndef EFX_RX_H +-#define EFX_RX_H +- +-#include "net_driver.h" +- +-int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); +-void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); +-void efx_init_rx_queue(struct efx_rx_queue *rx_queue); +-void efx_fini_rx_queue(struct efx_rx_queue *rx_queue); +- +-void efx_rx_strategy(struct efx_channel *channel); +-void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue); +-void efx_rx_work(struct work_struct *data); +-void __efx_rx_packet(struct efx_channel *channel, +- struct efx_rx_buffer *rx_buf, bool checksummed); +- +-#endif /* EFX_RX_H */ +diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c +index 817c7ef..af39335 100644 +--- a/drivers/net/sfc/selftest.c ++++ b/drivers/net/sfc/selftest.c +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -20,14 +20,12 @@ + #include + #include + #include "net_driver.h" +-#include "ethtool.h" + #include "efx.h" +-#include "falcon.h" ++#include "nic.h" + #include "selftest.h" +-#include "boards.h" + #include "workarounds.h" + #include "spi.h" +-#include "falcon_io.h" ++#include "io.h" + #include "mdio_10g.h" + + /* +@@ -49,7 +47,7 @@ static const unsigned char payload_source[ETH_ALEN] = { + 0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b, + }; + +-static const char *payload_msg = ++static const char payload_msg[] = + "Hello world! This is an Efx loopback test in progress!"; + + /** +@@ -57,6 +55,7 @@ static const char *payload_msg = + * @flush: Drop all packets in efx_loopback_rx_packet + * @packet_count: Number of packets being used in this test + * @skbs: An array of skbs transmitted ++ * @offload_csum: Checksums are being offloaded + * @rx_good: RX good packet count + * @rx_bad: RX bad packet count + * @payload: Payload used in tests +@@ -65,10 +64,7 @@ struct efx_loopback_state { + bool flush; + int packet_count; + struct sk_buff **skbs; +- +- /* Checksums are being offloaded */ + bool offload_csum; +- + atomic_t rx_good; + atomic_t rx_bad; + struct efx_loopback_payload payload; +@@ -104,7 +100,7 @@ static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests) + } + + if (EFX_IS10G(efx)) { +- rc = efx_mdio_check_mmds(efx, efx->phy_op->mmds, 0); ++ rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0); + if (rc) + goto out; + } +@@ -117,23 +113,26 @@ out: + + static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) + { +- int rc; ++ int rc = 0; ++ ++ if (efx->type->test_nvram) { ++ rc = efx->type->test_nvram(efx); ++ tests->nvram = rc ? -1 : 1; ++ } + +- rc = falcon_read_nvram(efx, NULL); +- tests->nvram = rc ? -1 : 1; + return rc; + } + + static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) + { +- int rc; ++ int rc = 0; + +- /* Not supported on A-series silicon */ +- if (falcon_rev(efx) < FALCON_REV_B0) +- return 0; ++ /* Test register access */ ++ if (efx->type->test_registers) { ++ rc = efx->type->test_registers(efx); ++ tests->registers = rc ? -1 : 1; ++ } + +- rc = falcon_test_registers(efx); +- tests->registers = rc ? -1 : 1; + return rc; + } + +@@ -165,7 +164,7 @@ static int efx_test_interrupts(struct efx_nic *efx, + goto success; + } + +- falcon_generate_interrupt(efx); ++ efx_nic_generate_interrupt(efx); + + /* Wait for arrival of test interrupt. */ + EFX_LOG(efx, "waiting for test interrupt\n"); +@@ -177,8 +176,8 @@ static int efx_test_interrupts(struct efx_nic *efx, + return -ETIMEDOUT; + + success: +- EFX_LOG(efx, "test interrupt (mode %d) seen on CPU%d\n", +- efx->interrupt_mode, efx->last_irq_cpu); ++ EFX_LOG(efx, "%s test interrupt seen on CPU%d\n", INT_MODE(efx), ++ efx->last_irq_cpu); + tests->interrupt = 1; + return 0; + } +@@ -203,7 +202,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, + channel->eventq_magic = 0; + smp_wmb(); + +- falcon_generate_test_event(channel, magic); ++ efx_nic_generate_test_event(channel, magic); + + /* Wait for arrival of interrupt */ + count = 0; +@@ -254,9 +253,6 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, + if (!efx->phy_op->run_tests) + return 0; + +- EFX_BUG_ON_PARANOID(efx->phy_op->num_tests == 0 || +- efx->phy_op->num_tests > EFX_MAX_PHY_TESTS); +- + mutex_lock(&efx->mac_lock); + rc = efx->phy_op->run_tests(efx, tests->phy, flags); + mutex_unlock(&efx->mac_lock); +@@ -426,7 +422,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) + + if (efx_dev_registered(efx)) + netif_tx_lock_bh(efx->net_dev); +- rc = efx_xmit(efx, tx_queue, skb); ++ rc = efx_enqueue_skb(tx_queue, skb); + if (efx_dev_registered(efx)) + netif_tx_unlock_bh(efx->net_dev); + +@@ -439,7 +435,6 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) + kfree_skb(skb); + return -EPIPE; + } +- efx->net_dev->trans_start = jiffies; + } + + return 0; +@@ -527,7 +522,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, + + for (i = 0; i < 3; i++) { + /* Determine how many packets to send */ +- state->packet_count = (efx->type->txd_ring_mask + 1) / 3; ++ state->packet_count = EFX_TXQ_SIZE / 3; + state->packet_count = min(1 << (i << 2), state->packet_count); + state->skbs = kzalloc(sizeof(state->skbs[0]) * + state->packet_count, GFP_KERNEL); +@@ -568,14 +563,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, + return 0; + } + ++/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but ++ * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it ++ * to delay and retry. Therefore, it's safer to just poll directly. Wait ++ * for link up and any faults to dissipate. */ ++static int efx_wait_for_link(struct efx_nic *efx) ++{ ++ struct efx_link_state *link_state = &efx->link_state; ++ int count; ++ bool link_up; ++ ++ for (count = 0; count < 40; count++) { ++ schedule_timeout_uninterruptible(HZ / 10); ++ ++ if (efx->type->monitor != NULL) { ++ mutex_lock(&efx->mac_lock); ++ efx->type->monitor(efx); ++ mutex_unlock(&efx->mac_lock); ++ } else { ++ struct efx_channel *channel = &efx->channel[0]; ++ if (channel->work_pending) ++ efx_process_channel_now(channel); ++ } ++ ++ mutex_lock(&efx->mac_lock); ++ link_up = link_state->up; ++ if (link_up) ++ link_up = !efx->mac_op->check_fault(efx); ++ mutex_unlock(&efx->mac_lock); ++ ++ if (link_up) ++ return 0; ++ } ++ ++ return -ETIMEDOUT; ++} ++ + static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, + unsigned int loopback_modes) + { + enum efx_loopback_mode mode; + struct efx_loopback_state *state; + struct efx_tx_queue *tx_queue; +- bool link_up; +- int count, rc = 0; ++ int rc = 0; + + /* Set the port loopback_selftest member. From this point on + * all received packets will be dropped. Mark the state as +@@ -594,46 +624,23 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, + + /* Move the port into the specified loopback mode. */ + state->flush = true; ++ mutex_lock(&efx->mac_lock); + efx->loopback_mode = mode; +- efx_reconfigure_port(efx); +- +- /* Wait for the PHY to signal the link is up. Interrupts +- * are enabled for PHY's using LASI, otherwise we poll() +- * quickly */ +- count = 0; +- do { +- struct efx_channel *channel = &efx->channel[0]; ++ rc = __efx_reconfigure_port(efx); ++ mutex_unlock(&efx->mac_lock); ++ if (rc) { ++ EFX_ERR(efx, "unable to move into %s loopback\n", ++ LOOPBACK_MODE(efx)); ++ goto out; ++ } + +- efx->phy_op->poll(efx); +- schedule_timeout_uninterruptible(HZ / 10); +- if (channel->work_pending) +- efx_process_channel_now(channel); +- /* Wait for PHY events to be processed */ +- flush_workqueue(efx->workqueue); +- rmb(); +- +- /* We need both the phy and xaui links to be ok. +- * rather than relying on the falcon_xmac irq/poll +- * regime, just poll xaui directly */ +- link_up = efx->link_up; +- if (link_up && EFX_IS10G(efx) && +- !falcon_xaui_link_ok(efx)) +- link_up = false; +- +- } while ((++count < 20) && !link_up); +- +- /* The link should now be up. If it isn't, there is no point +- * in attempting a loopback test */ +- if (!link_up) { ++ rc = efx_wait_for_link(efx); ++ if (rc) { + EFX_ERR(efx, "loopback %s never came up\n", + LOOPBACK_MODE(efx)); +- rc = -EIO; + goto out; + } + +- EFX_LOG(efx, "link came up in %s loopback in %d iterations\n", +- LOOPBACK_MODE(efx), count); +- + /* Test every TX queue */ + efx_for_each_tx_queue(tx_queue, efx) { + state->offload_csum = (tx_queue->queue == +@@ -667,7 +674,6 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, + enum efx_loopback_mode loopback_mode = efx->loopback_mode; + int phy_mode = efx->phy_mode; + enum reset_type reset_method = RESET_TYPE_INVISIBLE; +- struct ethtool_cmd ecmd; + struct efx_channel *channel; + int rc_test = 0, rc_reset = 0, rc; + +@@ -720,21 +726,21 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, + mutex_unlock(&efx->mac_lock); + + /* free up all consumers of SRAM (including all the queues) */ +- efx_reset_down(efx, reset_method, &ecmd); ++ efx_reset_down(efx, reset_method); + + rc = efx_test_chip(efx, tests); + if (rc && !rc_test) + rc_test = rc; + + /* reset the chip to recover from the register test */ +- rc_reset = falcon_reset_hw(efx, reset_method); ++ rc_reset = efx->type->reset(efx, reset_method); + + /* Ensure that the phy is powered and out of loopback + * for the bist and loopback tests */ + efx->phy_mode &= ~PHY_MODE_LOW_POWER; + efx->loopback_mode = LOOPBACK_NONE; + +- rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0); ++ rc = efx_reset_up(efx, reset_method, rc_reset == 0); + if (rc && !rc_reset) + rc_reset = rc; + +@@ -753,10 +759,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, + rc_test = rc; + + /* restore the PHY to the previous state */ +- efx->loopback_mode = loopback_mode; ++ mutex_lock(&efx->mac_lock); + efx->phy_mode = phy_mode; + efx->port_inhibited = false; +- efx_ethtool_set_settings(efx->net_dev, &ecmd); ++ efx->loopback_mode = loopback_mode; ++ __efx_reconfigure_port(efx); ++ mutex_unlock(&efx->mac_lock); + + return rc_test; + } +diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c +deleted file mode 100644 +index 49eb91b..0000000 +--- a/drivers/net/sfc/sfe4001.c ++++ /dev/null +@@ -1,435 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2007-2008 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +- +-/***************************************************************************** +- * Support for the SFE4001 and SFN4111T NICs. +- * +- * The SFE4001 does not power-up fully at reset due to its high power +- * consumption. We control its power via a PCA9539 I/O expander. +- * Both boards have a MAX6647 temperature monitor which we expose to +- * the lm90 driver. +- * +- * This also provides minimal support for reflashing the PHY, which is +- * initiated by resetting it with the FLASH_CFG_1 pin pulled down. +- * On SFE4001 rev A2 and later this is connected to the 3V3X output of +- * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3. +- * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually +- * exclusive with the network device being open. +- */ +- +-#include +-#include +-#include "net_driver.h" +-#include "efx.h" +-#include "phy.h" +-#include "boards.h" +-#include "falcon.h" +-#include "falcon_hwdefs.h" +-#include "falcon_io.h" +-#include "mac.h" +-#include "workarounds.h" +- +-/************************************************************************** +- * +- * I2C IO Expander device +- * +- **************************************************************************/ +-#define PCA9539 0x74 +- +-#define P0_IN 0x00 +-#define P0_OUT 0x02 +-#define P0_INVERT 0x04 +-#define P0_CONFIG 0x06 +- +-#define P0_EN_1V0X_LBN 0 +-#define P0_EN_1V0X_WIDTH 1 +-#define P0_EN_1V2_LBN 1 +-#define P0_EN_1V2_WIDTH 1 +-#define P0_EN_2V5_LBN 2 +-#define P0_EN_2V5_WIDTH 1 +-#define P0_EN_3V3X_LBN 3 +-#define P0_EN_3V3X_WIDTH 1 +-#define P0_EN_5V_LBN 4 +-#define P0_EN_5V_WIDTH 1 +-#define P0_SHORTEN_JTAG_LBN 5 +-#define P0_SHORTEN_JTAG_WIDTH 1 +-#define P0_X_TRST_LBN 6 +-#define P0_X_TRST_WIDTH 1 +-#define P0_DSP_RESET_LBN 7 +-#define P0_DSP_RESET_WIDTH 1 +- +-#define P1_IN 0x01 +-#define P1_OUT 0x03 +-#define P1_INVERT 0x05 +-#define P1_CONFIG 0x07 +- +-#define P1_AFE_PWD_LBN 0 +-#define P1_AFE_PWD_WIDTH 1 +-#define P1_DSP_PWD25_LBN 1 +-#define P1_DSP_PWD25_WIDTH 1 +-#define P1_RESERVED_LBN 2 +-#define P1_RESERVED_WIDTH 2 +-#define P1_SPARE_LBN 4 +-#define P1_SPARE_WIDTH 4 +- +-/* Temperature Sensor */ +-#define MAX664X_REG_RSL 0x02 +-#define MAX664X_REG_WLHO 0x0B +- +-static void sfe4001_poweroff(struct efx_nic *efx) +-{ +- struct i2c_client *ioexp_client = efx->board_info.ioexp_client; +- struct i2c_client *hwmon_client = efx->board_info.hwmon_client; +- +- /* Turn off all power rails and disable outputs */ +- i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); +- i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff); +- i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); +- +- /* Clear any over-temperature alert */ +- i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); +-} +- +-static int sfe4001_poweron(struct efx_nic *efx) +-{ +- struct i2c_client *hwmon_client = efx->board_info.hwmon_client; +- struct i2c_client *ioexp_client = efx->board_info.ioexp_client; +- unsigned int i, j; +- int rc; +- u8 out; +- +- /* Clear any previous over-temperature alert */ +- rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); +- if (rc < 0) +- return rc; +- +- /* Enable port 0 and port 1 outputs on IO expander */ +- rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); +- if (rc) +- return rc; +- rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, +- 0xff & ~(1 << P1_SPARE_LBN)); +- if (rc) +- goto fail_on; +- +- /* If PHY power is on, turn it all off and wait 1 second to +- * ensure a full reset. +- */ +- rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT); +- if (rc < 0) +- goto fail_on; +- out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | +- (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | +- (0 << P0_EN_1V0X_LBN)); +- if (rc != out) { +- EFX_INFO(efx, "power-cycling PHY\n"); +- rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); +- if (rc) +- goto fail_on; +- schedule_timeout_uninterruptible(HZ); +- } +- +- for (i = 0; i < 20; ++i) { +- /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ +- out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | +- (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | +- (1 << P0_X_TRST_LBN)); +- if (efx->phy_mode & PHY_MODE_SPECIAL) +- out |= 1 << P0_EN_3V3X_LBN; +- +- rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); +- if (rc) +- goto fail_on; +- msleep(10); +- +- /* Turn on 1V power rail */ +- out &= ~(1 << P0_EN_1V0X_LBN); +- rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); +- if (rc) +- goto fail_on; +- +- EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i); +- +- /* In flash config mode, DSP does not turn on AFE, so +- * just wait 1 second. +- */ +- if (efx->phy_mode & PHY_MODE_SPECIAL) { +- schedule_timeout_uninterruptible(HZ); +- return 0; +- } +- +- for (j = 0; j < 10; ++j) { +- msleep(100); +- +- /* Check DSP has asserted AFE power line */ +- rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); +- if (rc < 0) +- goto fail_on; +- if (rc & (1 << P1_AFE_PWD_LBN)) +- return 0; +- } +- } +- +- EFX_INFO(efx, "timed out waiting for DSP boot\n"); +- rc = -ETIMEDOUT; +-fail_on: +- sfe4001_poweroff(efx); +- return rc; +-} +- +-static int sfn4111t_reset(struct efx_nic *efx) +-{ +- efx_oword_t reg; +- +- /* GPIO 3 and the GPIO register are shared with I2C, so block that */ +- i2c_lock_adapter(&efx->i2c_adap); +- +- /* Pull RST_N (GPIO 2) low then let it up again, setting the +- * FLASH_CFG_1 strap (GPIO 3) appropriately. Only change the +- * output enables; the output levels should always be 0 (low) +- * and we rely on external pull-ups. */ +- falcon_read(efx, ®, GPIO_CTL_REG_KER); +- EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, true); +- falcon_write(efx, ®, GPIO_CTL_REG_KER); +- msleep(1000); +- EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, false); +- EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, +- !!(efx->phy_mode & PHY_MODE_SPECIAL)); +- falcon_write(efx, ®, GPIO_CTL_REG_KER); +- msleep(1); +- +- i2c_unlock_adapter(&efx->i2c_adap); +- +- ssleep(1); +- return 0; +-} +- +-static ssize_t show_phy_flash_cfg(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); +- return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL)); +-} +- +-static ssize_t set_phy_flash_cfg(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); +- enum efx_phy_mode old_mode, new_mode; +- int err; +- +- rtnl_lock(); +- old_mode = efx->phy_mode; +- if (count == 0 || *buf == '0') +- new_mode = old_mode & ~PHY_MODE_SPECIAL; +- else +- new_mode = PHY_MODE_SPECIAL; +- if (old_mode == new_mode) { +- err = 0; +- } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { +- err = -EBUSY; +- } else { +- /* Reset the PHY, reconfigure the MAC and enable/disable +- * MAC stats accordingly. */ +- efx->phy_mode = new_mode; +- if (new_mode & PHY_MODE_SPECIAL) +- efx_stats_disable(efx); +- if (efx->board_info.type == EFX_BOARD_SFE4001) +- err = sfe4001_poweron(efx); +- else +- err = sfn4111t_reset(efx); +- efx_reconfigure_port(efx); +- if (!(new_mode & PHY_MODE_SPECIAL)) +- efx_stats_enable(efx); +- } +- rtnl_unlock(); +- +- return err ? err : count; +-} +- +-static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg); +- +-static void sfe4001_fini(struct efx_nic *efx) +-{ +- EFX_INFO(efx, "%s\n", __func__); +- +- device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); +- sfe4001_poweroff(efx); +- i2c_unregister_device(efx->board_info.ioexp_client); +- i2c_unregister_device(efx->board_info.hwmon_client); +-} +- +-static int sfe4001_check_hw(struct efx_nic *efx) +-{ +- s32 status; +- +- /* If XAUI link is up then do not monitor */ +- if (EFX_WORKAROUND_7884(efx) && efx->mac_up) +- return 0; +- +- /* Check the powered status of the PHY. Lack of power implies that +- * the MAX6647 has shut down power to it, probably due to a temp. +- * alarm. Reading the power status rather than the MAX6647 status +- * directly because the later is read-to-clear and would thus +- * start to power up the PHY again when polled, causing us to blip +- * the power undesirably. +- * We know we can read from the IO expander because we did +- * it during power-on. Assume failure now is bad news. */ +- status = i2c_smbus_read_byte_data(efx->board_info.ioexp_client, P1_IN); +- if (status >= 0 && +- (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) +- return 0; +- +- /* Use board power control, not PHY power control */ +- sfe4001_poweroff(efx); +- efx->phy_mode = PHY_MODE_OFF; +- +- return (status < 0) ? -EIO : -ERANGE; +-} +- +-static struct i2c_board_info sfe4001_hwmon_info = { +- I2C_BOARD_INFO("max6647", 0x4e), +-}; +- +-/* This board uses an I2C expander to provider power to the PHY, which needs to +- * be turned on before the PHY can be used. +- * Context: Process context, rtnl lock held +- */ +-int sfe4001_init(struct efx_nic *efx) +-{ +- int rc; +- +-#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE) +- efx->board_info.hwmon_client = +- i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info); +-#else +- efx->board_info.hwmon_client = +- i2c_new_dummy(&efx->i2c_adap, sfe4001_hwmon_info.addr); +-#endif +- if (!efx->board_info.hwmon_client) +- return -EIO; +- +- /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ +- rc = i2c_smbus_write_byte_data(efx->board_info.hwmon_client, +- MAX664X_REG_WLHO, 90); +- if (rc) +- goto fail_hwmon; +- +- efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); +- if (!efx->board_info.ioexp_client) { +- rc = -EIO; +- goto fail_hwmon; +- } +- +- /* 10Xpress has fixed-function LED pins, so there is no board-specific +- * blink code. */ +- efx->board_info.blink = tenxpress_phy_blink; +- +- efx->board_info.monitor = sfe4001_check_hw; +- efx->board_info.fini = sfe4001_fini; +- +- if (efx->phy_mode & PHY_MODE_SPECIAL) { +- /* PHY won't generate a 156.25 MHz clock and MAC stats fetch +- * will fail. */ +- efx_stats_disable(efx); +- } +- rc = sfe4001_poweron(efx); +- if (rc) +- goto fail_ioexp; +- +- rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); +- if (rc) +- goto fail_on; +- +- EFX_INFO(efx, "PHY is powered on\n"); +- return 0; +- +-fail_on: +- sfe4001_poweroff(efx); +-fail_ioexp: +- i2c_unregister_device(efx->board_info.ioexp_client); +-fail_hwmon: +- i2c_unregister_device(efx->board_info.hwmon_client); +- return rc; +-} +- +-static int sfn4111t_check_hw(struct efx_nic *efx) +-{ +- s32 status; +- +- /* If XAUI link is up then do not monitor */ +- if (EFX_WORKAROUND_7884(efx) && efx->mac_up) +- return 0; +- +- /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */ +- status = i2c_smbus_read_byte_data(efx->board_info.hwmon_client, +- MAX664X_REG_RSL); +- if (status < 0) +- return -EIO; +- if (status & 0x57) +- return -ERANGE; +- return 0; +-} +- +-static void sfn4111t_fini(struct efx_nic *efx) +-{ +- EFX_INFO(efx, "%s\n", __func__); +- +- device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); +- i2c_unregister_device(efx->board_info.hwmon_client); +-} +- +-static struct i2c_board_info sfn4111t_a0_hwmon_info = { +- I2C_BOARD_INFO("max6647", 0x4e), +-}; +- +-static struct i2c_board_info sfn4111t_r5_hwmon_info = { +- I2C_BOARD_INFO("max6646", 0x4d), +-}; +- +-int sfn4111t_init(struct efx_nic *efx) +-{ +- int i = 0; +- int rc; +- +- efx->board_info.hwmon_client = +- i2c_new_device(&efx->i2c_adap, +- (efx->board_info.minor < 5) ? +- &sfn4111t_a0_hwmon_info : +- &sfn4111t_r5_hwmon_info); +- if (!efx->board_info.hwmon_client) +- return -EIO; +- +- efx->board_info.blink = tenxpress_phy_blink; +- efx->board_info.monitor = sfn4111t_check_hw; +- efx->board_info.fini = sfn4111t_fini; +- +- rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); +- if (rc) +- goto fail_hwmon; +- +- do { +- if (efx->phy_mode & PHY_MODE_SPECIAL) { +- /* PHY may not generate a 156.25 MHz clock and MAC +- * stats fetch will fail. */ +- efx_stats_disable(efx); +- sfn4111t_reset(efx); +- } +- rc = sft9001_wait_boot(efx); +- if (rc == 0) +- return 0; +- efx->phy_mode = PHY_MODE_SPECIAL; +- } while (rc == -EINVAL && ++i < 2); +- +- device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); +-fail_hwmon: +- i2c_unregister_device(efx->board_info.hwmon_client); +- return rc; +-} +diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c +new file mode 100644 +index 0000000..de07a4f +--- /dev/null ++++ b/drivers/net/sfc/siena.c +@@ -0,0 +1,604 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2005-2006 Fen Systems Ltd. ++ * Copyright 2006-2009 Solarflare Communications Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation, incorporated herein by reference. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "net_driver.h" ++#include "bitfield.h" ++#include "efx.h" ++#include "nic.h" ++#include "mac.h" ++#include "spi.h" ++#include "regs.h" ++#include "io.h" ++#include "phy.h" ++#include "workarounds.h" ++#include "mcdi.h" ++#include "mcdi_pcol.h" ++ ++/* Hardware control for SFC9000 family including SFL9021 (aka Siena). */ ++ ++static void siena_init_wol(struct efx_nic *efx); ++ ++ ++static void siena_push_irq_moderation(struct efx_channel *channel) ++{ ++ efx_dword_t timer_cmd; ++ ++ if (channel->irq_moderation) ++ EFX_POPULATE_DWORD_2(timer_cmd, ++ FRF_CZ_TC_TIMER_MODE, ++ FFE_CZ_TIMER_MODE_INT_HLDOFF, ++ FRF_CZ_TC_TIMER_VAL, ++ channel->irq_moderation - 1); ++ else ++ EFX_POPULATE_DWORD_2(timer_cmd, ++ FRF_CZ_TC_TIMER_MODE, ++ FFE_CZ_TIMER_MODE_DIS, ++ FRF_CZ_TC_TIMER_VAL, 0); ++ efx_writed_page_locked(channel->efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0, ++ channel->channel); ++} ++ ++static void siena_push_multicast_hash(struct efx_nic *efx) ++{ ++ WARN_ON(!mutex_is_locked(&efx->mac_lock)); ++ ++ efx_mcdi_rpc(efx, MC_CMD_SET_MCAST_HASH, ++ efx->multicast_hash.byte, sizeof(efx->multicast_hash), ++ NULL, 0, NULL); ++} ++ ++static int siena_mdio_write(struct net_device *net_dev, ++ int prtad, int devad, u16 addr, u16 value) ++{ ++ struct efx_nic *efx = netdev_priv(net_dev); ++ uint32_t status; ++ int rc; ++ ++ rc = efx_mcdi_mdio_write(efx, efx->mdio_bus, prtad, devad, ++ addr, value, &status); ++ if (rc) ++ return rc; ++ if (status != MC_CMD_MDIO_STATUS_GOOD) ++ return -EIO; ++ ++ return 0; ++} ++ ++static int siena_mdio_read(struct net_device *net_dev, ++ int prtad, int devad, u16 addr) ++{ ++ struct efx_nic *efx = netdev_priv(net_dev); ++ uint16_t value; ++ uint32_t status; ++ int rc; ++ ++ rc = efx_mcdi_mdio_read(efx, efx->mdio_bus, prtad, devad, ++ addr, &value, &status); ++ if (rc) ++ return rc; ++ if (status != MC_CMD_MDIO_STATUS_GOOD) ++ return -EIO; ++ ++ return (int)value; ++} ++ ++/* This call is responsible for hooking in the MAC and PHY operations */ ++static int siena_probe_port(struct efx_nic *efx) ++{ ++ int rc; ++ ++ /* Hook in PHY operations table */ ++ efx->phy_op = &efx_mcdi_phy_ops; ++ ++ /* Set up MDIO structure for PHY */ ++ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; ++ efx->mdio.mdio_read = siena_mdio_read; ++ efx->mdio.mdio_write = siena_mdio_write; ++ ++ /* Fill out MDIO structure and loopback modes */ ++ rc = efx->phy_op->probe(efx); ++ if (rc != 0) ++ return rc; ++ ++ /* Initial assumption */ ++ efx->link_state.speed = 10000; ++ efx->link_state.fd = true; ++ efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; ++ ++ /* Allocate buffer for stats */ ++ rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, ++ MC_CMD_MAC_NSTATS * sizeof(u64)); ++ if (rc) ++ return rc; ++ EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n", ++ (u64)efx->stats_buffer.dma_addr, ++ efx->stats_buffer.addr, ++ (u64)virt_to_phys(efx->stats_buffer.addr)); ++ ++ efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 1); ++ ++ return 0; ++} ++ ++void siena_remove_port(struct efx_nic *efx) ++{ ++ efx_nic_free_buffer(efx, &efx->stats_buffer); ++} ++ ++static const struct efx_nic_register_test siena_register_tests[] = { ++ { FR_AZ_ADR_REGION, ++ EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, ++ { FR_CZ_USR_EV_CFG, ++ EFX_OWORD32(0x000103FF, 0x00000000, 0x00000000, 0x00000000) }, ++ { FR_AZ_RX_CFG, ++ EFX_OWORD32(0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000) }, ++ { FR_AZ_TX_CFG, ++ EFX_OWORD32(0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF) }, ++ { FR_AZ_TX_RESERVED, ++ EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, ++ { FR_AZ_SRM_TX_DC_CFG, ++ EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, ++ { FR_AZ_RX_DC_CFG, ++ EFX_OWORD32(0x00000003, 0x00000000, 0x00000000, 0x00000000) }, ++ { FR_AZ_RX_DC_PF_WM, ++ EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, ++ { FR_BZ_DP_CTRL, ++ EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, ++ { FR_BZ_RX_RSS_TKEY, ++ EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, ++ { FR_CZ_RX_RSS_IPV6_REG1, ++ EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, ++ { FR_CZ_RX_RSS_IPV6_REG2, ++ EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, ++ { FR_CZ_RX_RSS_IPV6_REG3, ++ EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000) }, ++}; ++ ++static int siena_test_registers(struct efx_nic *efx) ++{ ++ return efx_nic_test_registers(efx, siena_register_tests, ++ ARRAY_SIZE(siena_register_tests)); ++} ++ ++/************************************************************************** ++ * ++ * Device reset ++ * ++ ************************************************************************** ++ */ ++ ++static int siena_reset_hw(struct efx_nic *efx, enum reset_type method) ++{ ++ ++ if (method == RESET_TYPE_WORLD) ++ return efx_mcdi_reset_mc(efx); ++ else ++ return efx_mcdi_reset_port(efx); ++} ++ ++static int siena_probe_nvconfig(struct efx_nic *efx) ++{ ++ int rc; ++ ++ rc = efx_mcdi_get_board_cfg(efx, efx->mac_address, NULL); ++ if (rc) ++ return rc; ++ ++ return 0; ++} ++ ++static int siena_probe_nic(struct efx_nic *efx) ++{ ++ struct siena_nic_data *nic_data; ++ bool already_attached = 0; ++ int rc; ++ ++ /* Allocate storage for hardware specific data */ ++ nic_data = kzalloc(sizeof(struct siena_nic_data), GFP_KERNEL); ++ if (!nic_data) ++ return -ENOMEM; ++ efx->nic_data = nic_data; ++ ++ if (efx_nic_fpga_ver(efx) != 0) { ++ EFX_ERR(efx, "Siena FPGA not supported\n"); ++ rc = -ENODEV; ++ goto fail1; ++ } ++ ++ efx_mcdi_init(efx); ++ ++ /* Recover from a failed assertion before probing */ ++ rc = efx_mcdi_handle_assertion(efx); ++ if (rc) ++ goto fail1; ++ ++ rc = efx_mcdi_fwver(efx, &nic_data->fw_version, &nic_data->fw_build); ++ if (rc) { ++ EFX_ERR(efx, "Failed to read MCPU firmware version - " ++ "rc %d\n", rc); ++ goto fail1; /* MCPU absent? */ ++ } ++ ++ /* Let the BMC know that the driver is now in charge of link and ++ * filter settings. We must do this before we reset the NIC */ ++ rc = efx_mcdi_drv_attach(efx, true, &already_attached); ++ if (rc) { ++ EFX_ERR(efx, "Unable to register driver with MCPU\n"); ++ goto fail2; ++ } ++ if (already_attached) ++ /* Not a fatal error */ ++ EFX_ERR(efx, "Host already registered with MCPU\n"); ++ ++ /* Now we can reset the NIC */ ++ rc = siena_reset_hw(efx, RESET_TYPE_ALL); ++ if (rc) { ++ EFX_ERR(efx, "failed to reset NIC\n"); ++ goto fail3; ++ } ++ ++ siena_init_wol(efx); ++ ++ /* Allocate memory for INT_KER */ ++ rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); ++ if (rc) ++ goto fail4; ++ BUG_ON(efx->irq_status.dma_addr & 0x0f); ++ ++ EFX_LOG(efx, "INT_KER at %llx (virt %p phys %llx)\n", ++ (unsigned long long)efx->irq_status.dma_addr, ++ efx->irq_status.addr, ++ (unsigned long long)virt_to_phys(efx->irq_status.addr)); ++ ++ /* Read in the non-volatile configuration */ ++ rc = siena_probe_nvconfig(efx); ++ if (rc == -EINVAL) { ++ EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n"); ++ efx->phy_type = PHY_TYPE_NONE; ++ efx->mdio.prtad = MDIO_PRTAD_NONE; ++ } else if (rc) { ++ goto fail5; ++ } ++ ++ return 0; ++ ++fail5: ++ efx_nic_free_buffer(efx, &efx->irq_status); ++fail4: ++fail3: ++ efx_mcdi_drv_attach(efx, false, NULL); ++fail2: ++fail1: ++ kfree(efx->nic_data); ++ return rc; ++} ++ ++/* This call performs hardware-specific global initialisation, such as ++ * defining the descriptor cache sizes and number of RSS channels. ++ * It does not set up any buffers, descriptor rings or event queues. ++ */ ++static int siena_init_nic(struct efx_nic *efx) ++{ ++ efx_oword_t temp; ++ int rc; ++ ++ /* Recover from a failed assertion post-reset */ ++ rc = efx_mcdi_handle_assertion(efx); ++ if (rc) ++ return rc; ++ ++ /* Squash TX of packets of 16 bytes or less */ ++ efx_reado(efx, &temp, FR_AZ_TX_RESERVED); ++ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); ++ efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); ++ ++ /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16 ++ * descriptors (which is bad). ++ */ ++ efx_reado(efx, &temp, FR_AZ_TX_CFG); ++ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0); ++ EFX_SET_OWORD_FIELD(temp, FRF_CZ_TX_FILTER_EN_BIT, 1); ++ efx_writeo(efx, &temp, FR_AZ_TX_CFG); ++ ++ efx_reado(efx, &temp, FR_AZ_RX_CFG); ++ EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_DESC_PUSH_EN, 0); ++ EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_INGR_EN, 1); ++ efx_writeo(efx, &temp, FR_AZ_RX_CFG); ++ ++ if (efx_nic_rx_xoff_thresh >= 0 || efx_nic_rx_xon_thresh >= 0) ++ /* No MCDI operation has been defined to set thresholds */ ++ EFX_ERR(efx, "ignoring RX flow control thresholds\n"); ++ ++ /* Enable event logging */ ++ rc = efx_mcdi_log_ctrl(efx, true, false, 0); ++ if (rc) ++ return rc; ++ ++ /* Set destination of both TX and RX Flush events */ ++ EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); ++ efx_writeo(efx, &temp, FR_BZ_DP_CTRL); ++ ++ EFX_POPULATE_OWORD_1(temp, FRF_CZ_USREV_DIS, 1); ++ efx_writeo(efx, &temp, FR_CZ_USR_EV_CFG); ++ ++ efx_nic_init_common(efx); ++ return 0; ++} ++ ++static void siena_remove_nic(struct efx_nic *efx) ++{ ++ efx_nic_free_buffer(efx, &efx->irq_status); ++ ++ siena_reset_hw(efx, RESET_TYPE_ALL); ++ ++ /* Relinquish the device back to the BMC */ ++ if (efx_nic_has_mc(efx)) ++ efx_mcdi_drv_attach(efx, false, NULL); ++ ++ /* Tear down the private nic state */ ++ kfree(efx->nic_data); ++ efx->nic_data = NULL; ++} ++ ++#define STATS_GENERATION_INVALID ((u64)(-1)) ++ ++static int siena_try_update_nic_stats(struct efx_nic *efx) ++{ ++ u64 *dma_stats; ++ struct efx_mac_stats *mac_stats; ++ u64 generation_start; ++ u64 generation_end; ++ ++ mac_stats = &efx->mac_stats; ++ dma_stats = (u64 *)efx->stats_buffer.addr; ++ ++ generation_end = dma_stats[MC_CMD_MAC_GENERATION_END]; ++ if (generation_end == STATS_GENERATION_INVALID) ++ return 0; ++ rmb(); ++ ++#define MAC_STAT(M, D) \ ++ mac_stats->M = dma_stats[MC_CMD_MAC_ ## D] ++ ++ MAC_STAT(tx_bytes, TX_BYTES); ++ MAC_STAT(tx_bad_bytes, TX_BAD_BYTES); ++ mac_stats->tx_good_bytes = (mac_stats->tx_bytes - ++ mac_stats->tx_bad_bytes); ++ MAC_STAT(tx_packets, TX_PKTS); ++ MAC_STAT(tx_bad, TX_BAD_FCS_PKTS); ++ MAC_STAT(tx_pause, TX_PAUSE_PKTS); ++ MAC_STAT(tx_control, TX_CONTROL_PKTS); ++ MAC_STAT(tx_unicast, TX_UNICAST_PKTS); ++ MAC_STAT(tx_multicast, TX_MULTICAST_PKTS); ++ MAC_STAT(tx_broadcast, TX_BROADCAST_PKTS); ++ MAC_STAT(tx_lt64, TX_LT64_PKTS); ++ MAC_STAT(tx_64, TX_64_PKTS); ++ MAC_STAT(tx_65_to_127, TX_65_TO_127_PKTS); ++ MAC_STAT(tx_128_to_255, TX_128_TO_255_PKTS); ++ MAC_STAT(tx_256_to_511, TX_256_TO_511_PKTS); ++ MAC_STAT(tx_512_to_1023, TX_512_TO_1023_PKTS); ++ MAC_STAT(tx_1024_to_15xx, TX_1024_TO_15XX_PKTS); ++ MAC_STAT(tx_15xx_to_jumbo, TX_15XX_TO_JUMBO_PKTS); ++ MAC_STAT(tx_gtjumbo, TX_GTJUMBO_PKTS); ++ mac_stats->tx_collision = 0; ++ MAC_STAT(tx_single_collision, TX_SINGLE_COLLISION_PKTS); ++ MAC_STAT(tx_multiple_collision, TX_MULTIPLE_COLLISION_PKTS); ++ MAC_STAT(tx_excessive_collision, TX_EXCESSIVE_COLLISION_PKTS); ++ MAC_STAT(tx_deferred, TX_DEFERRED_PKTS); ++ MAC_STAT(tx_late_collision, TX_LATE_COLLISION_PKTS); ++ mac_stats->tx_collision = (mac_stats->tx_single_collision + ++ mac_stats->tx_multiple_collision + ++ mac_stats->tx_excessive_collision + ++ mac_stats->tx_late_collision); ++ MAC_STAT(tx_excessive_deferred, TX_EXCESSIVE_DEFERRED_PKTS); ++ MAC_STAT(tx_non_tcpudp, TX_NON_TCPUDP_PKTS); ++ MAC_STAT(tx_mac_src_error, TX_MAC_SRC_ERR_PKTS); ++ MAC_STAT(tx_ip_src_error, TX_IP_SRC_ERR_PKTS); ++ MAC_STAT(rx_bytes, RX_BYTES); ++ MAC_STAT(rx_bad_bytes, RX_BAD_BYTES); ++ mac_stats->rx_good_bytes = (mac_stats->rx_bytes - ++ mac_stats->rx_bad_bytes); ++ MAC_STAT(rx_packets, RX_PKTS); ++ MAC_STAT(rx_good, RX_GOOD_PKTS); ++ mac_stats->rx_bad = mac_stats->rx_packets - mac_stats->rx_good; ++ MAC_STAT(rx_pause, RX_PAUSE_PKTS); ++ MAC_STAT(rx_control, RX_CONTROL_PKTS); ++ MAC_STAT(rx_unicast, RX_UNICAST_PKTS); ++ MAC_STAT(rx_multicast, RX_MULTICAST_PKTS); ++ MAC_STAT(rx_broadcast, RX_BROADCAST_PKTS); ++ MAC_STAT(rx_lt64, RX_UNDERSIZE_PKTS); ++ MAC_STAT(rx_64, RX_64_PKTS); ++ MAC_STAT(rx_65_to_127, RX_65_TO_127_PKTS); ++ MAC_STAT(rx_128_to_255, RX_128_TO_255_PKTS); ++ MAC_STAT(rx_256_to_511, RX_256_TO_511_PKTS); ++ MAC_STAT(rx_512_to_1023, RX_512_TO_1023_PKTS); ++ MAC_STAT(rx_1024_to_15xx, RX_1024_TO_15XX_PKTS); ++ MAC_STAT(rx_15xx_to_jumbo, RX_15XX_TO_JUMBO_PKTS); ++ MAC_STAT(rx_gtjumbo, RX_GTJUMBO_PKTS); ++ mac_stats->rx_bad_lt64 = 0; ++ mac_stats->rx_bad_64_to_15xx = 0; ++ mac_stats->rx_bad_15xx_to_jumbo = 0; ++ MAC_STAT(rx_bad_gtjumbo, RX_JABBER_PKTS); ++ MAC_STAT(rx_overflow, RX_OVERFLOW_PKTS); ++ mac_stats->rx_missed = 0; ++ MAC_STAT(rx_false_carrier, RX_FALSE_CARRIER_PKTS); ++ MAC_STAT(rx_symbol_error, RX_SYMBOL_ERROR_PKTS); ++ MAC_STAT(rx_align_error, RX_ALIGN_ERROR_PKTS); ++ MAC_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS); ++ MAC_STAT(rx_internal_error, RX_INTERNAL_ERROR_PKTS); ++ mac_stats->rx_good_lt64 = 0; ++ ++ efx->n_rx_nodesc_drop_cnt = dma_stats[MC_CMD_MAC_RX_NODESC_DROPS]; ++ ++#undef MAC_STAT ++ ++ rmb(); ++ generation_start = dma_stats[MC_CMD_MAC_GENERATION_START]; ++ if (generation_end != generation_start) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++static void siena_update_nic_stats(struct efx_nic *efx) ++{ ++ while (siena_try_update_nic_stats(efx) == -EAGAIN) ++ cpu_relax(); ++} ++ ++static void siena_start_nic_stats(struct efx_nic *efx) ++{ ++ u64 *dma_stats = (u64 *)efx->stats_buffer.addr; ++ ++ dma_stats[MC_CMD_MAC_GENERATION_END] = STATS_GENERATION_INVALID; ++ ++ efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, ++ MC_CMD_MAC_NSTATS * sizeof(u64), 1, 0); ++} ++ ++static void siena_stop_nic_stats(struct efx_nic *efx) ++{ ++ efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 0); ++} ++ ++void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len) ++{ ++ struct siena_nic_data *nic_data = efx->nic_data; ++ snprintf(buf, len, "%u.%u.%u.%u", ++ (unsigned int)(nic_data->fw_version >> 48), ++ (unsigned int)(nic_data->fw_version >> 32 & 0xffff), ++ (unsigned int)(nic_data->fw_version >> 16 & 0xffff), ++ (unsigned int)(nic_data->fw_version & 0xffff)); ++} ++ ++/************************************************************************** ++ * ++ * Wake on LAN ++ * ++ ************************************************************************** ++ */ ++ ++static void siena_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol) ++{ ++ struct siena_nic_data *nic_data = efx->nic_data; ++ ++ wol->supported = WAKE_MAGIC; ++ if (nic_data->wol_filter_id != -1) ++ wol->wolopts = WAKE_MAGIC; ++ else ++ wol->wolopts = 0; ++ memset(&wol->sopass, 0, sizeof(wol->sopass)); ++} ++ ++ ++static int siena_set_wol(struct efx_nic *efx, u32 type) ++{ ++ struct siena_nic_data *nic_data = efx->nic_data; ++ int rc; ++ ++ if (type & ~WAKE_MAGIC) ++ return -EINVAL; ++ ++ if (type & WAKE_MAGIC) { ++ if (nic_data->wol_filter_id != -1) ++ efx_mcdi_wol_filter_remove(efx, ++ nic_data->wol_filter_id); ++ rc = efx_mcdi_wol_filter_set_magic(efx, efx->mac_address, ++ &nic_data->wol_filter_id); ++ if (rc) ++ goto fail; ++ ++ pci_wake_from_d3(efx->pci_dev, true); ++ } else { ++ rc = efx_mcdi_wol_filter_reset(efx); ++ nic_data->wol_filter_id = -1; ++ pci_wake_from_d3(efx->pci_dev, false); ++ if (rc) ++ goto fail; ++ } ++ ++ return 0; ++ fail: ++ EFX_ERR(efx, "%s failed: type=%d rc=%d\n", __func__, type, rc); ++ return rc; ++} ++ ++ ++static void siena_init_wol(struct efx_nic *efx) ++{ ++ struct siena_nic_data *nic_data = efx->nic_data; ++ int rc; ++ ++ rc = efx_mcdi_wol_filter_get_magic(efx, &nic_data->wol_filter_id); ++ ++ if (rc != 0) { ++ /* If it failed, attempt to get into a synchronised ++ * state with MC by resetting any set WoL filters */ ++ efx_mcdi_wol_filter_reset(efx); ++ nic_data->wol_filter_id = -1; ++ } else if (nic_data->wol_filter_id != -1) { ++ pci_wake_from_d3(efx->pci_dev, true); ++ } ++} ++ ++ ++/************************************************************************** ++ * ++ * Revision-dependent attributes used by efx.c and nic.c ++ * ++ ************************************************************************** ++ */ ++ ++struct efx_nic_type siena_a0_nic_type = { ++ .probe = siena_probe_nic, ++ .remove = siena_remove_nic, ++ .init = siena_init_nic, ++ .fini = efx_port_dummy_op_void, ++ .monitor = NULL, ++ .reset = siena_reset_hw, ++ .probe_port = siena_probe_port, ++ .remove_port = siena_remove_port, ++ .prepare_flush = efx_port_dummy_op_void, ++ .update_stats = siena_update_nic_stats, ++ .start_stats = siena_start_nic_stats, ++ .stop_stats = siena_stop_nic_stats, ++ .set_id_led = efx_mcdi_set_id_led, ++ .push_irq_moderation = siena_push_irq_moderation, ++ .push_multicast_hash = siena_push_multicast_hash, ++ .reconfigure_port = efx_mcdi_phy_reconfigure, ++ .get_wol = siena_get_wol, ++ .set_wol = siena_set_wol, ++ .resume_wol = siena_init_wol, ++ .test_registers = siena_test_registers, ++ .default_mac_ops = &efx_mcdi_mac_operations, ++ ++ .revision = EFX_REV_SIENA_A0, ++ .mem_map_size = (FR_CZ_MC_TREG_SMEM + ++ FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS), ++ .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, ++ .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, ++ .buf_tbl_base = FR_BZ_BUF_FULL_TBL, ++ .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL, ++ .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR, ++ .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), ++ .rx_buffer_padding = 0, ++ .max_interrupt_mode = EFX_INT_MODE_MSIX, ++ .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy ++ * interrupt handler only supports 32 ++ * channels */ ++ .tx_dc_base = 0x88000, ++ .rx_dc_base = 0x68000, ++ .offload_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM, ++ .reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT, ++}; +diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h +index 1b1ceb4..8bf4fce 100644 +--- a/drivers/net/sfc/spi.h ++++ b/drivers/net/sfc/spi.h +@@ -36,8 +36,6 @@ + + /** + * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device +- * @efx: The Efx controller that owns this device +- * @mtd: MTD state + * @device_id: Controller's id for the device + * @size: Size (in bytes) + * @addr_len: Number of address bytes in read/write commands +@@ -54,10 +52,6 @@ + * Write commands are limited to blocks with this size and alignment. + */ + struct efx_spi_device { +- struct efx_nic *efx; +-#ifdef CONFIG_SFC_MTD +- void *mtd; +-#endif + int device_id; + unsigned int size; + unsigned int addr_len; +@@ -67,12 +61,16 @@ struct efx_spi_device { + unsigned int block_size; + }; + +-int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command, ++int falcon_spi_cmd(struct efx_nic *efx, ++ const struct efx_spi_device *spi, unsigned int command, + int address, const void* in, void *out, size_t len); +-int falcon_spi_wait_write(const struct efx_spi_device *spi); +-int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, ++int falcon_spi_wait_write(struct efx_nic *efx, ++ const struct efx_spi_device *spi); ++int falcon_spi_read(struct efx_nic *efx, ++ const struct efx_spi_device *spi, loff_t start, + size_t len, size_t *retlen, u8 *buffer); +-int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, ++int falcon_spi_write(struct efx_nic *efx, ++ const struct efx_spi_device *spi, loff_t start, + size_t len, size_t *retlen, const u8 *buffer); + + /* +diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c +index f4d5090..ca11572 100644 +--- a/drivers/net/sfc/tenxpress.c ++++ b/drivers/net/sfc/tenxpress.c +@@ -1,6 +1,6 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2007-2008 Solarflare Communications Inc. ++ * Copyright 2007-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -12,10 +12,9 @@ + #include + #include "efx.h" + #include "mdio_10g.h" +-#include "falcon.h" ++#include "nic.h" + #include "phy.h" +-#include "falcon_hwdefs.h" +-#include "boards.h" ++#include "regs.h" + #include "workarounds.h" + #include "selftest.h" + +@@ -31,13 +30,13 @@ + #define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ + (1 << LOOPBACK_PCS) | \ + (1 << LOOPBACK_PMAPMD) | \ +- (1 << LOOPBACK_NETWORK)) ++ (1 << LOOPBACK_PHYXS_WS)) + + #define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) | \ + (1 << LOOPBACK_PHYXS) | \ + (1 << LOOPBACK_PCS) | \ + (1 << LOOPBACK_PMAPMD) | \ +- (1 << LOOPBACK_NETWORK)) ++ (1 << LOOPBACK_PHYXS_WS)) + + /* We complain if we fail to see the link partner as 10G capable this many + * times in a row (must be > 1 as sampling the autoneg. registers is racy) +@@ -84,9 +83,9 @@ + #define PMA_PMD_LED_FLASH (3) + #define PMA_PMD_LED_MASK 3 + /* All LEDs under hardware control */ +-#define PMA_PMD_LED_FULL_AUTO (0) ++#define SFT9001_PMA_PMD_LED_DEFAULT 0 + /* Green and Amber under hardware control, Red off */ +-#define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) ++#define SFX7101_PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) + + #define PMA_PMD_SPEED_ENABLE_REG 49192 + #define PMA_PMD_100TX_ADV_LBN 1 +@@ -200,15 +199,16 @@ static ssize_t set_phy_short_reach(struct device *dev, + const char *buf, size_t count) + { + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); ++ int rc; + + rtnl_lock(); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, + MDIO_PMA_10GBT_TXPWR_SHORT, + count != 0 && *buf != '0'); +- efx_reconfigure_port(efx); ++ rc = efx_reconfigure_port(efx); + rtnl_unlock(); + +- return count; ++ return rc < 0 ? rc : (ssize_t)count; + } + + static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach, +@@ -292,17 +292,36 @@ static int tenxpress_init(struct efx_nic *efx) + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG, + 1 << PMA_PMA_LED_ACTIVITY_LBN, true); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, +- PMA_PMD_LED_DEFAULT); ++ SFX7101_PMA_PMD_LED_DEFAULT); + } + + return 0; + } + ++static int sfx7101_phy_probe(struct efx_nic *efx) ++{ ++ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; ++ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; ++ efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS; ++ return 0; ++} ++ ++static int sft9001_phy_probe(struct efx_nic *efx) ++{ ++ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; ++ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; ++ efx->loopback_modes = (SFT9001_LOOPBACKS | FALCON_XMAC_LOOPBACKS | ++ FALCON_GMAC_LOOPBACKS); ++ return 0; ++} ++ + static int tenxpress_phy_init(struct efx_nic *efx) + { + struct tenxpress_phy_data *phy_data; + int rc = 0; + ++ falcon_board(efx)->type->init_phy(efx); ++ + phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); + if (!phy_data) + return -ENOMEM; +@@ -333,6 +352,15 @@ static int tenxpress_phy_init(struct efx_nic *efx) + if (rc < 0) + goto fail; + ++ /* Initialise advertising flags */ ++ efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | ++ ADVERTISED_10000baseT_Full); ++ if (efx->phy_type != PHY_TYPE_SFX7101) ++ efx->link_advertising |= (ADVERTISED_1000baseT_Full | ++ ADVERTISED_100baseT_Full); ++ efx_link_set_wanted_fc(efx, efx->wanted_fc); ++ efx_mdio_an_reconfigure(efx); ++ + if (efx->phy_type == PHY_TYPE_SFT9001B) { + rc = device_create_file(&efx->pci_dev->dev, + &dev_attr_phy_short_reach); +@@ -363,7 +391,7 @@ static int tenxpress_special_reset(struct efx_nic *efx) + /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so + * a special software reset can glitch the XGMAC sufficiently for stats + * requests to fail. */ +- efx_stats_disable(efx); ++ falcon_stop_nic_stats(efx); + + /* Initiate reset */ + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); +@@ -385,7 +413,7 @@ static int tenxpress_special_reset(struct efx_nic *efx) + /* Wait for the XGXS state machine to churn */ + mdelay(10); + out: +- efx_stats_enable(efx); ++ falcon_start_nic_stats(efx); + return rc; + } + +@@ -489,95 +517,76 @@ static void tenxpress_low_power(struct efx_nic *efx) + !!(efx->phy_mode & PHY_MODE_LOW_POWER)); + } + +-static void tenxpress_phy_reconfigure(struct efx_nic *efx) ++static int tenxpress_phy_reconfigure(struct efx_nic *efx) + { + struct tenxpress_phy_data *phy_data = efx->phy_data; +- struct ethtool_cmd ecmd; + bool phy_mode_change, loop_reset; + + if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { + phy_data->phy_mode = efx->phy_mode; +- return; ++ return 0; + } + +- tenxpress_low_power(efx); +- + phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && + phy_data->phy_mode != PHY_MODE_NORMAL); +- loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) || ++ loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) || + LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); + + if (loop_reset || phy_mode_change) { +- int rc; +- +- efx->phy_op->get_settings(efx, &ecmd); +- +- if (loop_reset || phy_mode_change) { +- tenxpress_special_reset(efx); +- +- /* Reset XAUI if we were in 10G, and are staying +- * in 10G. If we're moving into and out of 10G +- * then xaui will be reset anyway */ +- if (EFX_IS10G(efx)) +- falcon_reset_xaui(efx); +- } ++ tenxpress_special_reset(efx); + +- rc = efx->phy_op->set_settings(efx, &ecmd); +- WARN_ON(rc); ++ /* Reset XAUI if we were in 10G, and are staying ++ * in 10G. If we're moving into and out of 10G ++ * then xaui will be reset anyway */ ++ if (EFX_IS10G(efx)) ++ falcon_reset_xaui(efx); + } + ++ tenxpress_low_power(efx); + efx_mdio_transmit_disable(efx); + efx_mdio_phy_reconfigure(efx); + tenxpress_ext_loopback(efx); ++ efx_mdio_an_reconfigure(efx); + + phy_data->loopback_mode = efx->loopback_mode; + phy_data->phy_mode = efx->phy_mode; + +- if (efx->phy_type == PHY_TYPE_SFX7101) { +- efx->link_speed = 10000; +- efx->link_fd = true; +- efx->link_up = sfx7101_link_ok(efx); +- } else { +- efx->phy_op->get_settings(efx, &ecmd); +- efx->link_speed = ecmd.speed; +- efx->link_fd = ecmd.duplex == DUPLEX_FULL; +- efx->link_up = sft9001_link_ok(efx, &ecmd); +- } +- efx->link_fc = efx_mdio_get_pause(efx); ++ return 0; + } + +-/* Poll PHY for interrupt */ +-static void tenxpress_phy_poll(struct efx_nic *efx) ++static void ++tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); ++ ++/* Poll for link state changes */ ++static bool tenxpress_phy_poll(struct efx_nic *efx) + { +- struct tenxpress_phy_data *phy_data = efx->phy_data; +- bool change = false; ++ struct efx_link_state old_state = efx->link_state; + + if (efx->phy_type == PHY_TYPE_SFX7101) { +- bool link_ok = sfx7101_link_ok(efx); +- if (link_ok != efx->link_up) { +- change = true; +- } else { +- unsigned int link_fc = efx_mdio_get_pause(efx); +- if (link_fc != efx->link_fc) +- change = true; +- } +- sfx7101_check_bad_lp(efx, link_ok); +- } else if (efx->loopback_mode) { +- bool link_ok = sft9001_link_ok(efx, NULL); +- if (link_ok != efx->link_up) +- change = true; ++ efx->link_state.up = sfx7101_link_ok(efx); ++ efx->link_state.speed = 10000; ++ efx->link_state.fd = true; ++ efx->link_state.fc = efx_mdio_get_pause(efx); ++ ++ sfx7101_check_bad_lp(efx, efx->link_state.up); + } else { +- int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD, +- MDIO_PMA_LASI_STAT); +- if (status & MDIO_PMA_LASI_LSALARM) +- change = true; +- } ++ struct ethtool_cmd ecmd; + +- if (change) +- falcon_sim_phy_event(efx); ++ /* Check the LASI alarm first */ ++ if (efx->loopback_mode == LOOPBACK_NONE && ++ !(efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT) & ++ MDIO_PMA_LASI_LSALARM)) ++ return false; + +- if (phy_data->phy_mode != PHY_MODE_NORMAL) +- return; ++ tenxpress_get_settings(efx, &ecmd); ++ ++ efx->link_state.up = sft9001_link_ok(efx, &ecmd); ++ efx->link_state.speed = ecmd.speed; ++ efx->link_state.fd = (ecmd.duplex == DUPLEX_FULL); ++ efx->link_state.fc = efx_mdio_get_pause(efx); ++ } ++ ++ return !efx_link_state_equal(&efx->link_state, &old_state); + } + + static void tenxpress_phy_fini(struct efx_nic *efx) +@@ -604,18 +613,29 @@ static void tenxpress_phy_fini(struct efx_nic *efx) + } + + +-/* Set the RX and TX LEDs and Link LED flashing. The other LEDs +- * (which probably aren't wired anyway) are left in AUTO mode */ +-void tenxpress_phy_blink(struct efx_nic *efx, bool blink) ++/* Override the RX, TX and link LEDs */ ++void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) + { + int reg; + +- if (blink) +- reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) | +- (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) | +- (PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN); +- else +- reg = PMA_PMD_LED_DEFAULT; ++ switch (mode) { ++ case EFX_LED_OFF: ++ reg = (PMA_PMD_LED_OFF << PMA_PMD_LED_TX_LBN) | ++ (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) | ++ (PMA_PMD_LED_OFF << PMA_PMD_LED_LINK_LBN); ++ break; ++ case EFX_LED_ON: ++ reg = (PMA_PMD_LED_ON << PMA_PMD_LED_TX_LBN) | ++ (PMA_PMD_LED_ON << PMA_PMD_LED_RX_LBN) | ++ (PMA_PMD_LED_ON << PMA_PMD_LED_LINK_LBN); ++ break; ++ default: ++ if (efx->phy_type == PHY_TYPE_SFX7101) ++ reg = SFX7101_PMA_PMD_LED_DEFAULT; ++ else ++ reg = SFT9001_PMA_PMD_LED_DEFAULT; ++ break; ++ } + + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg); + } +@@ -624,6 +644,13 @@ static const char *const sfx7101_test_names[] = { + "bist" + }; + ++static const char *sfx7101_test_name(struct efx_nic *efx, unsigned int index) ++{ ++ if (index < ARRAY_SIZE(sfx7101_test_names)) ++ return sfx7101_test_names[index]; ++ return NULL; ++} ++ + static int + sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) + { +@@ -635,6 +662,9 @@ sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) + /* BIST is automatically run after a special software reset */ + rc = tenxpress_special_reset(efx); + results[0] = rc ? -1 : 1; ++ ++ efx_mdio_an_reconfigure(efx); ++ + return rc; + } + +@@ -650,14 +680,17 @@ static const char *const sft9001_test_names[] = { + "cable.pairD.length", + }; + ++static const char *sft9001_test_name(struct efx_nic *efx, unsigned int index) ++{ ++ if (index < ARRAY_SIZE(sft9001_test_names)) ++ return sft9001_test_names[index]; ++ return NULL; ++} ++ + static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) + { +- struct ethtool_cmd ecmd; + int rc = 0, rc2, i, ctrl_reg, res_reg; + +- if (flags & ETH_TEST_FL_OFFLINE) +- efx->phy_op->get_settings(efx, &ecmd); +- + /* Initialise cable diagnostic results to unknown failure */ + for (i = 1; i < 9; ++i) + results[i] = -1; +@@ -709,9 +742,7 @@ out: + if (!rc) + rc = rc2; + +- rc2 = efx->phy_op->set_settings(efx, &ecmd); +- if (!rc) +- rc = rc2; ++ efx_mdio_an_reconfigure(efx); + } + + return rc; +@@ -758,7 +789,7 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) + * but doesn't advertise the correct speed. So override it */ + if (efx->loopback_mode == LOOPBACK_GPHY) + ecmd->speed = SPEED_1000; +- else if (LOOPBACK_MASK(efx) & efx->phy_op->loopbacks) ++ else if (LOOPBACK_EXTERNAL(efx)) + ecmd->speed = SPEED_10000; + } + +@@ -788,35 +819,27 @@ static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) + } + + struct efx_phy_operations falcon_sfx7101_phy_ops = { +- .macs = EFX_XMAC, ++ .probe = sfx7101_phy_probe, + .init = tenxpress_phy_init, + .reconfigure = tenxpress_phy_reconfigure, + .poll = tenxpress_phy_poll, + .fini = tenxpress_phy_fini, +- .clear_interrupt = efx_port_dummy_op_void, + .get_settings = tenxpress_get_settings, + .set_settings = tenxpress_set_settings, + .set_npage_adv = sfx7101_set_npage_adv, +- .num_tests = ARRAY_SIZE(sfx7101_test_names), +- .test_names = sfx7101_test_names, ++ .test_name = sfx7101_test_name, + .run_tests = sfx7101_run_tests, +- .mmds = TENXPRESS_REQUIRED_DEVS, +- .loopbacks = SFX7101_LOOPBACKS, + }; + + struct efx_phy_operations falcon_sft9001_phy_ops = { +- .macs = EFX_GMAC | EFX_XMAC, ++ .probe = sft9001_phy_probe, + .init = tenxpress_phy_init, + .reconfigure = tenxpress_phy_reconfigure, + .poll = tenxpress_phy_poll, + .fini = tenxpress_phy_fini, +- .clear_interrupt = efx_port_dummy_op_void, + .get_settings = tenxpress_get_settings, + .set_settings = tenxpress_set_settings, + .set_npage_adv = sft9001_set_npage_adv, +- .num_tests = ARRAY_SIZE(sft9001_test_names), +- .test_names = sft9001_test_names, ++ .test_name = sft9001_test_name, + .run_tests = sft9001_run_tests, +- .mmds = TENXPRESS_REQUIRED_DEVS, +- .loopbacks = SFT9001_LOOPBACKS, + }; +diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c +index 489c4de..e669f94 100644 +--- a/drivers/net/sfc/tx.c ++++ b/drivers/net/sfc/tx.c +@@ -1,7 +1,7 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. +- * Copyright 2005-2008 Solarflare Communications Inc. ++ * Copyright 2005-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -12,12 +12,13 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include "net_driver.h" +-#include "tx.h" + #include "efx.h" +-#include "falcon.h" ++#include "nic.h" + #include "workarounds.h" + + /* +@@ -26,8 +27,7 @@ + * The tx_queue descriptor ring fill-level must fall below this value + * before we restart the netif queue + */ +-#define EFX_NETDEV_TX_THRESHOLD(_tx_queue) \ +- (_tx_queue->efx->type->txd_ring_mask / 2u) ++#define EFX_TXQ_THRESHOLD (EFX_TXQ_MASK / 2u) + + /* We want to be able to nest calls to netif_stop_queue(), since each + * channel can have an individual stop on the queue. +@@ -125,6 +125,24 @@ static void efx_tsoh_free(struct efx_tx_queue *tx_queue, + } + + ++static inline unsigned ++efx_max_tx_len(struct efx_nic *efx, dma_addr_t dma_addr) ++{ ++ /* Depending on the NIC revision, we can use descriptor ++ * lengths up to 8K or 8K-1. However, since PCI Express ++ * devices must split read requests at 4K boundaries, there is ++ * little benefit from using descriptors that cross those ++ * boundaries and we keep things simple by not doing so. ++ */ ++ unsigned len = (~dma_addr & 0xfff) + 1; ++ ++ /* Work around hardware bug for unaligned buffers. */ ++ if (EFX_WORKAROUND_5391(efx) && (dma_addr & 0xf)) ++ len = min_t(unsigned, len, 512 - (dma_addr & 0xf)); ++ ++ return len; ++} ++ + /* + * Add a socket buffer to a TX queue + * +@@ -135,11 +153,13 @@ static void efx_tsoh_free(struct efx_tx_queue *tx_queue, + * If any DMA mapping fails, any mapped fragments will be unmapped, + * the queue's insert pointer will be restored to its original value. + * ++ * This function is split out from efx_hard_start_xmit to allow the ++ * loopback test to direct packets via specific TX queues. ++ * + * Returns NETDEV_TX_OK or NETDEV_TX_BUSY + * You must hold netif_tx_lock() to call this function. + */ +-static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, +- struct sk_buff *skb) ++netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) + { + struct efx_nic *efx = tx_queue->efx; + struct pci_dev *pci_dev = efx->pci_dev; +@@ -147,7 +167,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, + skb_frag_t *fragment; + struct page *page; + int page_offset; +- unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign; ++ unsigned int len, unmap_len = 0, fill_level, insert_ptr; + dma_addr_t dma_addr, unmap_addr = 0; + unsigned int dma_len; + bool unmap_single; +@@ -156,7 +176,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, + + EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); + +- if (skb_shinfo((struct sk_buff *)skb)->gso_size) ++ if (skb_shinfo(skb)->gso_size) + return efx_enqueue_skb_tso(tx_queue, skb); + + /* Get size of the initial fragment */ +@@ -171,7 +191,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, + } + + fill_level = tx_queue->insert_count - tx_queue->old_read_count; +- q_space = efx->type->txd_ring_mask - 1 - fill_level; ++ q_space = EFX_TXQ_MASK - 1 - fill_level; + + /* Map for DMA. Use pci_map_single rather than pci_map_page + * since this is more efficient on machines with sparse +@@ -208,16 +228,14 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, + &tx_queue->read_count; + fill_level = (tx_queue->insert_count + - tx_queue->old_read_count); +- q_space = (efx->type->txd_ring_mask - 1 - +- fill_level); ++ q_space = EFX_TXQ_MASK - 1 - fill_level; + if (unlikely(q_space-- <= 0)) + goto stop; + smp_mb(); + --tx_queue->stopped; + } + +- insert_ptr = (tx_queue->insert_count & +- efx->type->txd_ring_mask); ++ insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK; + buffer = &tx_queue->buffer[insert_ptr]; + efx_tsoh_free(tx_queue, buffer); + EFX_BUG_ON_PARANOID(buffer->tsoh); +@@ -226,14 +244,10 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, + EFX_BUG_ON_PARANOID(!buffer->continuation); + EFX_BUG_ON_PARANOID(buffer->unmap_len); + +- dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1); +- if (likely(dma_len > len)) ++ dma_len = efx_max_tx_len(efx, dma_addr); ++ if (likely(dma_len >= len)) + dma_len = len; + +- misalign = (unsigned)dma_addr & efx->type->bug5391_mask; +- if (misalign && dma_len + misalign > 512) +- dma_len = 512 - misalign; +- + /* Fill out per descriptor fields */ + buffer->len = dma_len; + buffer->dma_addr = dma_addr; +@@ -266,7 +280,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, + buffer->continuation = false; + + /* Pass off to hardware */ +- falcon_push_buffers(tx_queue); ++ efx_nic_push_buffers(tx_queue); + + return NETDEV_TX_OK; + +@@ -276,7 +290,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, + skb_shinfo(skb)->nr_frags + 1); + + /* Mark the packet as transmitted, and free the SKB ourselves */ +- dev_kfree_skb_any((struct sk_buff *)skb); ++ dev_kfree_skb_any(skb); + goto unwind; + + stop: +@@ -289,7 +303,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, + /* Work backwards until we hit the original insert pointer value */ + while (tx_queue->insert_count != tx_queue->write_count) { + --tx_queue->insert_count; +- insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask; ++ insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK; + buffer = &tx_queue->buffer[insert_ptr]; + efx_dequeue_buffer(tx_queue, buffer); + buffer->len = 0; +@@ -318,10 +332,9 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, + { + struct efx_nic *efx = tx_queue->efx; + unsigned int stop_index, read_ptr; +- unsigned int mask = tx_queue->efx->type->txd_ring_mask; + +- stop_index = (index + 1) & mask; +- read_ptr = tx_queue->read_count & mask; ++ stop_index = (index + 1) & EFX_TXQ_MASK; ++ read_ptr = tx_queue->read_count & EFX_TXQ_MASK; + + while (read_ptr != stop_index) { + struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr]; +@@ -338,28 +351,10 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, + buffer->len = 0; + + ++tx_queue->read_count; +- read_ptr = tx_queue->read_count & mask; ++ read_ptr = tx_queue->read_count & EFX_TXQ_MASK; + } + } + +-/* Initiate a packet transmission on the specified TX queue. +- * Note that returning anything other than NETDEV_TX_OK will cause the +- * OS to free the skb. +- * +- * This function is split out from efx_hard_start_xmit to allow the +- * loopback test to direct packets via specific TX queues. It is +- * therefore a non-static inline, so as not to penalise performance +- * for non-loopback transmissions. +- * +- * Context: netif_tx_lock held +- */ +-inline netdev_tx_t efx_xmit(struct efx_nic *efx, +- struct efx_tx_queue *tx_queue, struct sk_buff *skb) +-{ +- /* Map fragments for DMA and add to TX queue */ +- return efx_enqueue_skb(tx_queue, skb); +-} +- + /* Initiate a packet transmission. We use one channel per CPU + * (sharing when we have more CPUs than channels). On Falcon, the TX + * completion events will be directed back to the CPU that transmitted +@@ -383,7 +378,7 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, + else + tx_queue = &efx->tx_queue[EFX_TX_QUEUE_NO_CSUM]; + +- return efx_xmit(efx, tx_queue, skb); ++ return efx_enqueue_skb(tx_queue, skb); + } + + void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) +@@ -391,7 +386,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) + unsigned fill_level; + struct efx_nic *efx = tx_queue->efx; + +- EFX_BUG_ON_PARANOID(index > efx->type->txd_ring_mask); ++ EFX_BUG_ON_PARANOID(index > EFX_TXQ_MASK); + + efx_dequeue_buffers(tx_queue, index); + +@@ -401,7 +396,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) + smp_mb(); + if (unlikely(tx_queue->stopped) && likely(efx->port_enabled)) { + fill_level = tx_queue->insert_count - tx_queue->read_count; +- if (fill_level < EFX_NETDEV_TX_THRESHOLD(tx_queue)) { ++ if (fill_level < EFX_TXQ_THRESHOLD) { + EFX_BUG_ON_PARANOID(!efx_dev_registered(efx)); + + /* Do this under netif_tx_lock(), to avoid racing +@@ -425,15 +420,15 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue) + EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue); + + /* Allocate software ring */ +- txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer); ++ txq_size = EFX_TXQ_SIZE * sizeof(*tx_queue->buffer); + tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL); + if (!tx_queue->buffer) + return -ENOMEM; +- for (i = 0; i <= efx->type->txd_ring_mask; ++i) ++ for (i = 0; i <= EFX_TXQ_MASK; ++i) + tx_queue->buffer[i].continuation = true; + + /* Allocate hardware ring */ +- rc = falcon_probe_tx(tx_queue); ++ rc = efx_nic_probe_tx(tx_queue); + if (rc) + goto fail; + +@@ -456,7 +451,7 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue) + BUG_ON(tx_queue->stopped); + + /* Set up TX descriptor ring */ +- falcon_init_tx(tx_queue); ++ efx_nic_init_tx(tx_queue); + } + + void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) +@@ -468,8 +463,7 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) + + /* Free any buffers left in the ring */ + while (tx_queue->read_count != tx_queue->write_count) { +- buffer = &tx_queue->buffer[tx_queue->read_count & +- tx_queue->efx->type->txd_ring_mask]; ++ buffer = &tx_queue->buffer[tx_queue->read_count & EFX_TXQ_MASK]; + efx_dequeue_buffer(tx_queue, buffer); + buffer->continuation = true; + buffer->len = 0; +@@ -483,7 +477,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) + EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue); + + /* Flush TX queue, remove descriptor ring */ +- falcon_fini_tx(tx_queue); ++ efx_nic_fini_tx(tx_queue); + + efx_release_tx_buffers(tx_queue); + +@@ -500,7 +494,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) + void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) + { + EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue); +- falcon_remove_tx(tx_queue); ++ efx_nic_remove_tx(tx_queue); + + kfree(tx_queue->buffer); + tx_queue->buffer = NULL; +@@ -539,6 +533,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) + #define ETH_HDR_LEN(skb) (skb_network_header(skb) - (skb)->data) + #define SKB_TCP_OFF(skb) PTR_DIFF(tcp_hdr(skb), (skb)->data) + #define SKB_IPV4_OFF(skb) PTR_DIFF(ip_hdr(skb), (skb)->data) ++#define SKB_IPV6_OFF(skb) PTR_DIFF(ipv6_hdr(skb), (skb)->data) + + /** + * struct tso_state - TSO state for an SKB +@@ -551,6 +546,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) + * @unmap_len: Length of SKB fragment + * @unmap_addr: DMA address of SKB fragment + * @unmap_single: DMA single vs page mapping flag ++ * @protocol: Network protocol (after any VLAN header) + * @header_len: Number of bytes of header + * @full_packet_size: Number of bytes to put in each outgoing segment + * +@@ -571,6 +567,7 @@ struct tso_state { + dma_addr_t unmap_addr; + bool unmap_single; + ++ __be16 protocol; + unsigned header_len; + int full_packet_size; + }; +@@ -578,9 +575,9 @@ struct tso_state { + + /* + * Verify that our various assumptions about sk_buffs and the conditions +- * under which TSO will be attempted hold true. ++ * under which TSO will be attempted hold true. Return the protocol number. + */ +-static void efx_tso_check_safe(struct sk_buff *skb) ++static __be16 efx_tso_check_protocol(struct sk_buff *skb) + { + __be16 protocol = skb->protocol; + +@@ -595,13 +592,22 @@ static void efx_tso_check_safe(struct sk_buff *skb) + if (protocol == htons(ETH_P_IP)) + skb_set_transport_header(skb, sizeof(*veh) + + 4 * ip_hdr(skb)->ihl); ++ else if (protocol == htons(ETH_P_IPV6)) ++ skb_set_transport_header(skb, sizeof(*veh) + ++ sizeof(struct ipv6hdr)); + } + +- EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IP)); +- EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); ++ if (protocol == htons(ETH_P_IP)) { ++ EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); ++ } else { ++ EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IPV6)); ++ EFX_BUG_ON_PARANOID(ipv6_hdr(skb)->nexthdr != NEXTHDR_TCP); ++ } + EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data) + + (tcp_hdr(skb)->doff << 2u)) > + skb_headlen(skb)); ++ ++ return protocol; + } + + +@@ -708,14 +714,14 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, + { + struct efx_tx_buffer *buffer; + struct efx_nic *efx = tx_queue->efx; +- unsigned dma_len, fill_level, insert_ptr, misalign; ++ unsigned dma_len, fill_level, insert_ptr; + int q_space; + + EFX_BUG_ON_PARANOID(len <= 0); + + fill_level = tx_queue->insert_count - tx_queue->old_read_count; + /* -1 as there is no way to represent all descriptors used */ +- q_space = efx->type->txd_ring_mask - 1 - fill_level; ++ q_space = EFX_TXQ_MASK - 1 - fill_level; + + while (1) { + if (unlikely(q_space-- <= 0)) { +@@ -731,7 +737,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, + *(volatile unsigned *)&tx_queue->read_count; + fill_level = (tx_queue->insert_count + - tx_queue->old_read_count); +- q_space = efx->type->txd_ring_mask - 1 - fill_level; ++ q_space = EFX_TXQ_MASK - 1 - fill_level; + if (unlikely(q_space-- <= 0)) { + *final_buffer = NULL; + return 1; +@@ -740,13 +746,13 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, + --tx_queue->stopped; + } + +- insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask; ++ insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK; + buffer = &tx_queue->buffer[insert_ptr]; + ++tx_queue->insert_count; + + EFX_BUG_ON_PARANOID(tx_queue->insert_count - + tx_queue->read_count > +- efx->type->txd_ring_mask); ++ EFX_TXQ_MASK); + + efx_tsoh_free(tx_queue, buffer); + EFX_BUG_ON_PARANOID(buffer->len); +@@ -757,12 +763,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, + + buffer->dma_addr = dma_addr; + +- /* Ensure we do not cross a boundary unsupported by H/W */ +- dma_len = (~dma_addr & efx->type->tx_dma_mask) + 1; +- +- misalign = (unsigned)dma_addr & efx->type->bug5391_mask; +- if (misalign && dma_len + misalign > 512) +- dma_len = 512 - misalign; ++ dma_len = efx_max_tx_len(efx, dma_addr); + + /* If there is enough space to send then do so */ + if (dma_len >= len) +@@ -792,8 +793,7 @@ static void efx_tso_put_header(struct efx_tx_queue *tx_queue, + { + struct efx_tx_buffer *buffer; + +- buffer = &tx_queue->buffer[tx_queue->insert_count & +- tx_queue->efx->type->txd_ring_mask]; ++ buffer = &tx_queue->buffer[tx_queue->insert_count & EFX_TXQ_MASK]; + efx_tsoh_free(tx_queue, buffer); + EFX_BUG_ON_PARANOID(buffer->len); + EFX_BUG_ON_PARANOID(buffer->unmap_len); +@@ -818,7 +818,7 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) + while (tx_queue->insert_count != tx_queue->write_count) { + --tx_queue->insert_count; + buffer = &tx_queue->buffer[tx_queue->insert_count & +- tx_queue->efx->type->txd_ring_mask]; ++ EFX_TXQ_MASK]; + efx_tsoh_free(tx_queue, buffer); + EFX_BUG_ON_PARANOID(buffer->skb); + buffer->len = 0; +@@ -850,7 +850,10 @@ static void tso_start(struct tso_state *st, const struct sk_buff *skb) + + PTR_DIFF(tcp_hdr(skb), skb->data)); + st->full_packet_size = st->header_len + skb_shinfo(skb)->gso_size; + +- st->ipv4_id = ntohs(ip_hdr(skb)->id); ++ if (st->protocol == htons(ETH_P_IP)) ++ st->ipv4_id = ntohs(ip_hdr(skb)->id); ++ else ++ st->ipv4_id = 0; + st->seqnum = ntohl(tcp_hdr(skb)->seq); + + EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg); +@@ -965,7 +968,6 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, + struct tso_state *st) + { + struct efx_tso_header *tsoh; +- struct iphdr *tsoh_iph; + struct tcphdr *tsoh_th; + unsigned ip_length; + u8 *header; +@@ -989,7 +991,6 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, + + header = TSOH_BUFFER(tsoh); + tsoh_th = (struct tcphdr *)(header + SKB_TCP_OFF(skb)); +- tsoh_iph = (struct iphdr *)(header + SKB_IPV4_OFF(skb)); + + /* Copy and update the headers. */ + memcpy(header, skb->data, st->header_len); +@@ -1007,11 +1008,22 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, + tsoh_th->fin = tcp_hdr(skb)->fin; + tsoh_th->psh = tcp_hdr(skb)->psh; + } +- tsoh_iph->tot_len = htons(ip_length); + +- /* Linux leaves suitable gaps in the IP ID space for us to fill. */ +- tsoh_iph->id = htons(st->ipv4_id); +- st->ipv4_id++; ++ if (st->protocol == htons(ETH_P_IP)) { ++ struct iphdr *tsoh_iph = ++ (struct iphdr *)(header + SKB_IPV4_OFF(skb)); ++ ++ tsoh_iph->tot_len = htons(ip_length); ++ ++ /* Linux leaves suitable gaps in the IP ID space for us to fill. */ ++ tsoh_iph->id = htons(st->ipv4_id); ++ st->ipv4_id++; ++ } else { ++ struct ipv6hdr *tsoh_iph = ++ (struct ipv6hdr *)(header + SKB_IPV6_OFF(skb)); ++ ++ tsoh_iph->payload_len = htons(ip_length - sizeof(*tsoh_iph)); ++ } + + st->packet_space = skb_shinfo(skb)->gso_size; + ++tx_queue->tso_packets; +@@ -1041,8 +1053,8 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, + int frag_i, rc, rc2 = NETDEV_TX_OK; + struct tso_state state; + +- /* Verify TSO is safe - these checks should never fail. */ +- efx_tso_check_safe(skb); ++ /* Find the packet protocol and sanity-check it */ ++ state.protocol = efx_tso_check_protocol(skb); + + EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); + +@@ -1092,14 +1104,14 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, + } + + /* Pass off to hardware */ +- falcon_push_buffers(tx_queue); ++ efx_nic_push_buffers(tx_queue); + + tx_queue->tso_bursts++; + return NETDEV_TX_OK; + + mem_err: + EFX_ERR(efx, "Out of memory for TSO headers, or PCI mapping error\n"); +- dev_kfree_skb_any((struct sk_buff *)skb); ++ dev_kfree_skb_any(skb); + goto unwind; + + stop: +@@ -1135,7 +1147,7 @@ static void efx_fini_tso(struct efx_tx_queue *tx_queue) + unsigned i; + + if (tx_queue->buffer) { +- for (i = 0; i <= tx_queue->efx->type->txd_ring_mask; ++i) ++ for (i = 0; i <= EFX_TXQ_MASK; ++i) + efx_tsoh_free(tx_queue, &tx_queue->buffer[i]); + } + +diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h +deleted file mode 100644 +index e367896..0000000 +--- a/drivers/net/sfc/tx.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2006 Fen Systems Ltd. +- * Copyright 2006-2008 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +- +-#ifndef EFX_TX_H +-#define EFX_TX_H +- +-#include "net_driver.h" +- +-int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); +-void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); +-void efx_init_tx_queue(struct efx_tx_queue *tx_queue); +-void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); +- +-netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, +- struct net_device *net_dev); +-void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); +- +-#endif /* EFX_TX_H */ +diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h +index c821c15..acd9c73 100644 +--- a/drivers/net/sfc/workarounds.h ++++ b/drivers/net/sfc/workarounds.h +@@ -1,6 +1,6 @@ + /**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2006-2008 Solarflare Communications Inc. ++ * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published +@@ -16,7 +16,9 @@ + */ + + #define EFX_WORKAROUND_ALWAYS(efx) 1 +-#define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1) ++#define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) ++#define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0) ++#define EFX_WORKAROUND_SIENA(efx) (efx_nic_rev(efx) == EFX_REV_SIENA_A0) + #define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) + #define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \ + (efx)->phy_type == PHY_TYPE_SFT9001B) +@@ -27,20 +29,22 @@ + #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS + /* Bit-bashed I2C reads cause performance drop */ + #define EFX_WORKAROUND_7884 EFX_WORKAROUND_10G +-/* TX pkt parser problem with <= 16 byte TXes */ +-#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS + /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor + * or a PCIe error (bug 11028) */ + #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS + /* Transmit flow control may get disabled */ +-#define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS +-/* Flush events can take a very long time to appear */ +-#define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS ++#define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB + /* Truncated IPv4 packets can confuse the TX packet parser */ +-#define EFX_WORKAROUND_15592 EFX_WORKAROUND_ALWAYS ++#define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB ++/* Legacy ISR read can return zero once */ ++#define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA ++/* Legacy interrupt storm when interrupt fifo fills */ ++#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA + + /* Spurious parity errors in TSORT buffers */ + #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A ++/* Unaligned read request >512 bytes after aligning may break TSORT */ ++#define EFX_WORKAROUND_5391 EFX_WORKAROUND_FALCON_A + /* iSCSI parsing errors */ + #define EFX_WORKAROUND_5583 EFX_WORKAROUND_FALCON_A + /* RX events go missing */ +diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c +deleted file mode 100644 +index e6b3d5e..0000000 +--- a/drivers/net/sfc/xfp_phy.c ++++ /dev/null +@@ -1,250 +0,0 @@ +-/**************************************************************************** +- * Driver for Solarflare Solarstorm network controllers and boards +- * Copyright 2006-2008 Solarflare Communications Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License version 2 as published +- * by the Free Software Foundation, incorporated herein by reference. +- */ +-/* +- * Driver for SFP+ and XFP optical PHYs plus some support specific to the +- * AMCC QT20xx adapters; see www.amcc.com for details +- */ +- +-#include +-#include +-#include "efx.h" +-#include "mdio_10g.h" +-#include "phy.h" +-#include "falcon.h" +- +-#define XFP_REQUIRED_DEVS (MDIO_DEVS_PCS | \ +- MDIO_DEVS_PMAPMD | \ +- MDIO_DEVS_PHYXS) +- +-#define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \ +- (1 << LOOPBACK_PMAPMD) | \ +- (1 << LOOPBACK_NETWORK)) +- +-/****************************************************************************/ +-/* Quake-specific MDIO registers */ +-#define MDIO_QUAKE_LED0_REG (0xD006) +- +-/* QT2025C only */ +-#define PCS_FW_HEARTBEAT_REG 0xd7ee +-#define PCS_FW_HEARTB_LBN 0 +-#define PCS_FW_HEARTB_WIDTH 8 +-#define PCS_UC8051_STATUS_REG 0xd7fd +-#define PCS_UC_STATUS_LBN 0 +-#define PCS_UC_STATUS_WIDTH 8 +-#define PCS_UC_STATUS_FW_SAVE 0x20 +-#define PMA_PMD_FTX_CTRL2_REG 0xc309 +-#define PMA_PMD_FTX_STATIC_LBN 13 +-#define PMA_PMD_VEND1_REG 0xc001 +-#define PMA_PMD_VEND1_LBTXD_LBN 15 +-#define PCS_VEND1_REG 0xc000 +-#define PCS_VEND1_LBTXD_LBN 5 +- +-void xfp_set_led(struct efx_nic *p, int led, int mode) +-{ +- int addr = MDIO_QUAKE_LED0_REG + led; +- efx_mdio_write(p, MDIO_MMD_PMAPMD, addr, mode); +-} +- +-struct xfp_phy_data { +- enum efx_phy_mode phy_mode; +-}; +- +-#define XFP_MAX_RESET_TIME 500 +-#define XFP_RESET_WAIT 10 +- +-static int qt2025c_wait_reset(struct efx_nic *efx) +-{ +- unsigned long timeout = jiffies + 10 * HZ; +- int reg, old_counter = 0; +- +- /* Wait for firmware heartbeat to start */ +- for (;;) { +- int counter; +- reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_FW_HEARTBEAT_REG); +- if (reg < 0) +- return reg; +- counter = ((reg >> PCS_FW_HEARTB_LBN) & +- ((1 << PCS_FW_HEARTB_WIDTH) - 1)); +- if (old_counter == 0) +- old_counter = counter; +- else if (counter != old_counter) +- break; +- if (time_after(jiffies, timeout)) +- return -ETIMEDOUT; +- msleep(10); +- } +- +- /* Wait for firmware status to look good */ +- for (;;) { +- reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG); +- if (reg < 0) +- return reg; +- if ((reg & +- ((1 << PCS_UC_STATUS_WIDTH) - 1) << PCS_UC_STATUS_LBN) >= +- PCS_UC_STATUS_FW_SAVE) +- break; +- if (time_after(jiffies, timeout)) +- return -ETIMEDOUT; +- msleep(100); +- } +- +- return 0; +-} +- +-static int xfp_reset_phy(struct efx_nic *efx) +-{ +- int rc; +- +- if (efx->phy_type == PHY_TYPE_QT2025C) { +- /* Wait for the reset triggered by falcon_reset_hw() +- * to complete */ +- rc = qt2025c_wait_reset(efx); +- if (rc < 0) +- goto fail; +- } else { +- /* Reset the PHYXS MMD. This is documented as doing +- * a complete soft reset. */ +- rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS, +- XFP_MAX_RESET_TIME / XFP_RESET_WAIT, +- XFP_RESET_WAIT); +- if (rc < 0) +- goto fail; +- } +- +- /* Wait 250ms for the PHY to complete bootup */ +- msleep(250); +- +- /* Check that all the MMDs we expect are present and responding. We +- * expect faults on some if the link is down, but not on the PHY XS */ +- rc = efx_mdio_check_mmds(efx, XFP_REQUIRED_DEVS, MDIO_DEVS_PHYXS); +- if (rc < 0) +- goto fail; +- +- efx->board_info.init_leds(efx); +- +- return rc; +- +- fail: +- EFX_ERR(efx, "PHY reset timed out\n"); +- return rc; +-} +- +-static int xfp_phy_init(struct efx_nic *efx) +-{ +- struct xfp_phy_data *phy_data; +- u32 devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); +- int rc; +- +- phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL); +- if (!phy_data) +- return -ENOMEM; +- efx->phy_data = phy_data; +- +- EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n", +- devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), +- efx_mdio_id_rev(devid)); +- +- phy_data->phy_mode = efx->phy_mode; +- +- rc = xfp_reset_phy(efx); +- +- EFX_INFO(efx, "PHY init %s.\n", +- rc ? "failed" : "successful"); +- if (rc < 0) +- goto fail; +- +- return 0; +- +- fail: +- kfree(efx->phy_data); +- efx->phy_data = NULL; +- return rc; +-} +- +-static void xfp_phy_clear_interrupt(struct efx_nic *efx) +-{ +- /* Read to clear link status alarm */ +- efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT); +-} +- +-static int xfp_link_ok(struct efx_nic *efx) +-{ +- return efx_mdio_links_ok(efx, XFP_REQUIRED_DEVS); +-} +- +-static void xfp_phy_poll(struct efx_nic *efx) +-{ +- int link_up = xfp_link_ok(efx); +- /* Simulate a PHY event if link state has changed */ +- if (link_up != efx->link_up) +- falcon_sim_phy_event(efx); +-} +- +-static void xfp_phy_reconfigure(struct efx_nic *efx) +-{ +- struct xfp_phy_data *phy_data = efx->phy_data; +- +- if (efx->phy_type == PHY_TYPE_QT2025C) { +- /* There are several different register bits which can +- * disable TX (and save power) on direct-attach cables +- * or optical transceivers, varying somewhat between +- * firmware versions. Only 'static mode' appears to +- * cover everything. */ +- mdio_set_flag( +- &efx->mdio, efx->mdio.prtad, MDIO_MMD_PMAPMD, +- PMA_PMD_FTX_CTRL2_REG, 1 << PMA_PMD_FTX_STATIC_LBN, +- efx->phy_mode & PHY_MODE_TX_DISABLED || +- efx->phy_mode & PHY_MODE_LOW_POWER || +- efx->loopback_mode == LOOPBACK_PCS || +- efx->loopback_mode == LOOPBACK_PMAPMD); +- } else { +- /* Reset the PHY when moving from tx off to tx on */ +- if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) && +- (phy_data->phy_mode & PHY_MODE_TX_DISABLED)) +- xfp_reset_phy(efx); +- +- efx_mdio_transmit_disable(efx); +- } +- +- efx_mdio_phy_reconfigure(efx); +- +- phy_data->phy_mode = efx->phy_mode; +- efx->link_up = xfp_link_ok(efx); +- efx->link_speed = 10000; +- efx->link_fd = true; +- efx->link_fc = efx->wanted_fc; +-} +- +-static void xfp_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +-{ +- mdio45_ethtool_gset(&efx->mdio, ecmd); +-} +- +-static void xfp_phy_fini(struct efx_nic *efx) +-{ +- /* Clobber the LED if it was blinking */ +- efx->board_info.blink(efx, false); +- +- /* Free the context block */ +- kfree(efx->phy_data); +- efx->phy_data = NULL; +-} +- +-struct efx_phy_operations falcon_xfp_phy_ops = { +- .macs = EFX_XMAC, +- .init = xfp_phy_init, +- .reconfigure = xfp_phy_reconfigure, +- .poll = xfp_phy_poll, +- .fini = xfp_phy_fini, +- .clear_interrupt = xfp_phy_clear_interrupt, +- .get_settings = xfp_phy_get_settings, +- .set_settings = efx_mdio_set_settings, +- .mmds = XFP_REQUIRED_DEVS, +- .loopbacks = XFP_LOOPBACKS, +-}; diff --git a/debian/patches/series/3 b/debian/patches/series/3 index 88abb1390..acc4cc73a 100644 --- a/debian/patches/series/3 +++ b/debian/patches/series/3 @@ -1,2 +1,6 @@ + features/all/input-alps-add-support-for-touchpads-with-4-directional-button.patch + features/all/input-alps-add-interleaved-protocol-support.patch ++ features/all/gro-Name-the-GRO-result-enumeration-type.patch ++ features/all/gro-Change-all-receive-functions-to-return-GRO-result.patch ++ features/all/ethtool-Add-reset-operation.patch ++ features/all/sfc-2.6.33-rc1.patch