diff options
author | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-04-01 12:05:27 +0000 |
---|---|---|
committer | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-04-01 12:05:27 +0000 |
commit | 23f27ea50bbe2cbdd0c260c7c6b78229a83d7996 (patch) | |
tree | a5cda6cdb0bffcdceb04c0066c69647b1bee39a8 | |
parent | 38b25a187b7c5a833e6d8e5ba215f25043d2d3ab (diff) |
[x86]: add a subtarget and drivers for the Intel Tolapai SoC
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@20648 3c298f89-4303-0410-b956-a3cf2f4a3e73
27 files changed, 13278 insertions, 1 deletions
diff --git a/package/ep80579-drivers/Makefile b/package/ep80579-drivers/Makefile new file mode 100644 index 0000000000..fac0fbbadf --- /dev/null +++ b/package/ep80579-drivers/Makefile @@ -0,0 +1,80 @@ +# +# Copyright (C) 2010 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=ep80579-drivers +PKG_VERSION:=1.0.34 +PKG_RELEASE:=1 + +PKG_SOURCE:=Embedded.L.1.0.34.ADI.R100.tar.gz +PKG_SOURCE_URL:=ftp://ftp.adiengineering.com/Archive/OcracokeIsland/Drivers/Linux/1.0.34/ +PKG_MD5SUM:=61df9778f8c1f919257d2f48a0bcb000 + +PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/ep80579-drivers/Default + DEPENDS:=@TARGET_x86 +endef + +define KernelPackage/ep80579-eth +$(call KernelPackage/ep80579-drivers/Default) + SUBMENU:=Network Devices + TITLE:=Intel EP80579 ethernet driver + FILES:= \ + $(PKG_BUILD_DIR)/Embedded/build/gcu.$(LINUX_KMOD_SUFFIX) \ + $(PKG_BUILD_DIR)/Embedded/build/iegbe.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,40,gcu iegbe) +endef + +define KernelPackage/ep80579-misc +$(call KernelPackage/ep80579-drivers/Default) + SUBMENU:=Other modules + TITLE:=Misc. Intel EP80579 drivers (DMA,, gpio) + FILES:= \ + $(PKG_BUILD_DIR)/Embedded/build/dma.$(LINUX_KMOD_SUFFIX) \ + $(PKG_BUILD_DIR)/Embedded/build/gpio.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,40,gpio dma) +endef + +define KernelPackage/ep80579-can +$(call KernelPackage/ep80579-drivers/Default) + SUBMENU:=Other modules + TITLE:=Intel EP80579 CAN driver + FILES:= \ + $(PKG_BUILD_DIR)/Embedded/build/timesync.$(LINUX_KMOD_SUFFIX) \ + $(PKG_BUILD_DIR)/Embedded/build/can.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,40,timesync can) +endef + +define Build/Prepare + rm -rf $(PKG_BUILD_DIR) + mkdir -p $(PKG_BUILD_DIR) + tar xzvf $(DL_DIR)/$(PKG_SOURCE) -C $(PKG_BUILD_DIR)/ + $(Build/Patch) +endef + +define Build/Compile + (cd $(PKG_BUILD_DIR)/Embedded; \ + $(MAKE) KERNEL_SOURCE_ROOT=$(LINUX_DIR) \ + KSRC=$(LINUX_DIR) \ + KOBJ=$(LINUX_DIR) \ + ENV_DIR=$(PKG_BUILD_DIR)/Embedded \ + all \ + ) +endef + +define KernelPackage/ep80579-eth/install +endef + +$(eval $(call KernelPackage,ep80579-can)) +$(eval $(call KernelPackage,ep80579-eth)) +$(eval $(call KernelPackage,ep80579-misc)) + diff --git a/package/ep80579-drivers/patches/001-igbe_update.patch b/package/ep80579-drivers/patches/001-igbe_update.patch new file mode 100644 index 0000000000..67560b8ded --- /dev/null +++ b/package/ep80579-drivers/patches/001-igbe_update.patch @@ -0,0 +1,11755 @@ +--- a/Embedded/src/GbE/gcu.h ++++ b/Embedded/src/GbE/gcu.h +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +--- a/Embedded/src/GbE/gcu_if.c ++++ b/Embedded/src/GbE/gcu_if.c +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +@@ -330,10 +330,17 @@ gcu_write_verify(uint32_t phy_num, uint3 + */ + void gcu_iegbe_resume(struct pci_dev *pdev) + { ++#if ( ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6) ) && \ ++ ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ) ) ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct gcu_adapter *adapter = netdev_priv(netdev); ++#endif ++ + GCU_DBG("%s\n", __func__); + + pci_restore_state(pdev); +- pci_enable_device(pdev); ++ if(!pci_enable_device(pdev)) ++ GCU_DBG("pci_enable_device failed!\n",); + + return; + } +@@ -348,6 +355,12 @@ EXPORT_SYMBOL(gcu_iegbe_resume); + */ + int gcu_iegbe_suspend(struct pci_dev *pdev, uint32_t state) + { ++#if ( ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6) ) && \ ++ ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ) ) ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct gcu_adapter *adapter = netdev_priv(netdev); ++#endif ++ + GCU_DBG("%s\n", __func__); + + pci_save_state(pdev); +--- a/Embedded/src/GbE/gcu_if.h ++++ b/Embedded/src/GbE/gcu_if.h +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +--- a/Embedded/src/GbE/gcu_main.c ++++ b/Embedded/src/GbE/gcu_main.c +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +@@ -94,6 +94,7 @@ static struct pci_driver gcu_driver = { + + static struct gcu_adapter *global_adapter = 0; + static spinlock_t global_adapter_spinlock = SPIN_LOCK_UNLOCKED; ++static unsigned long g_intflags = 0; + + MODULE_AUTHOR("Intel(R) Corporation"); + MODULE_DESCRIPTION("Global Configuration Unit Driver"); +@@ -124,7 +125,7 @@ gcu_init_module(void) + + printk(KERN_INFO "%s\n", gcu_copyright); + +- ret = pci_module_init(&gcu_driver); ++ ret = pci_register_driver(&gcu_driver); + if(ret >= 0) { + register_reboot_notifier(&gcu_notifier_reboot); + } +@@ -199,8 +200,6 @@ gcu_probe(struct pci_dev *pdev, + return -ENOMEM; + } + +- SET_MODULE_OWNER(adapter); +- + pci_set_drvdata(pdev, adapter); + + adapter->pdev = pdev; +@@ -238,7 +237,6 @@ gcu_probe(struct pci_dev *pdev, + return 0; + } + +- + /** + * gcu_probe_err - gcu_probe error handler + * @err: gcu_err_type +@@ -295,7 +293,7 @@ gcu_notify_reboot(struct notifier_block + case SYS_DOWN: + case SYS_HALT: + case SYS_POWER_OFF: +- while((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { ++ while((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { + if(pci_dev_driver(pdev) == &gcu_driver){ + gcu_suspend(pdev, 0x3); + } +@@ -318,6 +316,11 @@ static int + gcu_suspend(struct pci_dev *pdev, uint32_t state) + { + /*struct gcu_adapter *adapter = pci_get_drvdata(pdev); */ ++#if ( ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6) ) && \ ++ ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ) ) ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct gcu_adapter *adapter = netdev_priv(netdev); ++#endif + + GCU_DBG("%s\n", __func__); + +@@ -338,7 +341,6 @@ gcu_suspend(struct pci_dev *pdev, uint32 + return state; + } + +- + /** + * alloc_gcu_adapter + * +@@ -412,7 +414,7 @@ gcu_get_adapter(void) + return NULL; + } + +- spin_lock(&global_adapter_spinlock); ++ spin_lock_irqsave(&global_adapter_spinlock, g_intflags); + + return global_adapter; + } +@@ -437,7 +439,7 @@ gcu_release_adapter(const struct gcu_ada + *adapter = 0; + } + +- spin_unlock(&global_adapter_spinlock); ++ spin_unlock_irqrestore(&global_adapter_spinlock, g_intflags); + + return; + } +--- a/Embedded/src/GbE/gcu_reg.h ++++ b/Embedded/src/GbE/gcu_reg.h +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +--- a/Embedded/src/GbE/iegbe.7 ++++ b/Embedded/src/GbE/iegbe.7 +@@ -1,7 +1,7 @@ + + .\" GPL LICENSE SUMMARY + .\" +-.\" Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++.\" Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + .\" + .\" This program is free software; you can redistribute it and/or modify + .\" it under the terms of version 2 of the GNU General Public License as +@@ -21,7 +21,7 @@ + .\" Contact Information: + .\" Intel Corporation + .\" +-.\" version: Embedded.L.1.0.34 ++.\" version: Embedded.Release.Patch.L.1.0.7-5 + + .\" LICENSE + .\" +--- a/Embedded/src/GbE/iegbe_ethtool.c ++++ b/Embedded/src/GbE/iegbe_ethtool.c +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +@@ -132,22 +132,6 @@ static const struct iegbe_stats iegbe_gs + { "cpp_master", E1000_STAT(icr_cpp_master) }, + { "stat", E1000_STAT(icr_stat) }, + #endif +-#ifdef IEGBE_GBE_WORKAROUND +- { "txqec", E1000_STAT(stats.txqec) }, +- { "tx_next_to_clean", E1000_STAT(stats.tx_next_to_clean) }, +- { "tx_next_to_use", E1000_STAT(stats.tx_next_to_use) }, +- { "num_tx_queues", E1000_STAT(stats.num_tx_queues) }, +- +- { "num_rx_buf_alloc", E1000_STAT(stats.num_rx_buf_alloc) }, +- { "rx_next_to_clean", E1000_STAT(stats.rx_next_to_clean) }, +- { "rx_next_to_use", E1000_STAT(stats.rx_next_to_use) }, +- { "cc_gt_num_rx", E1000_STAT(stats.cc_gt_num_rx) }, +- { "tx_hnet", E1000_STAT(stats.tx_hnet) }, +- { "tx_hnentu", E1000_STAT(stats.tx_hnentu) }, +- { "RUC", E1000_STAT(stats.ruc) }, +- { "RFC", E1000_STAT(stats.rfc) }, +- +-#endif + }; + #define E1000_STATS_LEN \ + sizeof(iegbe_gstrings_stats) / sizeof(struct iegbe_stats) +@@ -158,7 +142,7 @@ static const char iegbe_gstrings_test[][ + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" + }; +-#define E1000_TEST_LEN (sizeof(iegbe_gstrings_test) / (ETH_GSTRING_LEN)) ++#define E1000_TEST_LEN (sizeof(iegbe_gstrings_test) / ETH_GSTRING_LEN) + #endif /* ETHTOOL_TEST */ + + #define E1000_REGS_LEN 0x20 +@@ -176,9 +160,7 @@ iegbe_get_settings(struct net_device *ne + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | +-#ifndef IEGBE_10_100_ONLY + SUPPORTED_1000baseT_Full| +-#endif + SUPPORTED_Autoneg | + SUPPORTED_TP); + +@@ -259,21 +241,13 @@ iegbe_set_settings(struct net_device *ne + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | +-#ifndef IEGBE_10_100_ONLY + ADVERTISED_1000baseT_Full| +-#endif +- + ADVERTISED_Autoneg | + ADVERTISED_TP; + ecmd->advertising = hw->autoneg_advertised; + } +- } else { +- uint16_t duplex; +- +- // ethtool uses DUPLEX_FULL/DUPLEX_HALF +- // the driver needs FULL_DUPLEX/HALF_DUPLEX +- duplex = (ecmd->duplex == DUPLEX_FULL) ? FULL_DUPLEX : HALF_DUPLEX; +- if(iegbe_set_spd_dplx(adapter, ecmd->speed + duplex)) ++ } else ++ if(iegbe_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)){ + return -EINVAL; + } + /* reset the link */ +@@ -728,8 +702,8 @@ iegbe_set_ringparam(struct net_device *n + struct iegbe_rx_ring *rxdr, *rx_old, *rx_new; + int i, err, tx_ring_size, rx_ring_size; + +- tx_ring_size = sizeof(struct iegbe_tx_ring) * adapter->num_queues; +- rx_ring_size = sizeof(struct iegbe_rx_ring) * adapter->num_queues; ++ tx_ring_size = sizeof(struct iegbe_tx_ring) * adapter->num_tx_queues; ++ rx_ring_size = sizeof(struct iegbe_rx_ring) * adapter->num_rx_queues; + + if (netif_running(adapter->netdev)){ + iegbe_down(adapter); +@@ -768,10 +742,10 @@ iegbe_set_ringparam(struct net_device *n + E1000_MAX_TXD : E1000_MAX_82544_TXD)); + E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); + +- for (i = 0; i < adapter->num_queues; i++) { +- txdr[i].count = txdr->count; +- rxdr[i].count = rxdr->count; +- } ++ for (i = 0; i < adapter->num_tx_queues; i++) ++ txdr[i].count = txdr->count; ++ for (i = 0; i < adapter->num_rx_queues; i++) ++ rxdr[i].count = rxdr->count; + + if(netif_running(adapter->netdev)) { + /* Try to get new resources before deleting old */ +@@ -950,8 +924,7 @@ iegbe_eeprom_test(struct iegbe_adapter * + + static irqreturn_t + iegbe_test_intr(int irq, +- void *data, +- struct pt_regs *regs) ++ void *data) + { + struct net_device *netdev = (struct net_device *) data; + struct iegbe_adapter *adapter = netdev_priv(netdev); +@@ -973,7 +946,7 @@ iegbe_intr_test(struct iegbe_adapter *ad + /* Hook up test interrupt handler just for this test */ + if(!request_irq(irq, &iegbe_test_intr, 0, netdev->name, netdev)) { + shared_int = FALSE; +- } else if(request_irq(irq, &iegbe_test_intr, SA_SHIRQ, ++ } else if(request_irq(irq, &iegbe_test_intr, IRQF_SHARED, + netdev->name, netdev)){ + *data = 1; + return -1; +@@ -1393,7 +1366,7 @@ iegbe_set_phy_loopback(struct iegbe_adap + * attempt this 10 times. + */ + while(iegbe_nonintegrated_phy_loopback(adapter) && +- count++ < 0xa) { }; ++ count++ < 0xa); + if(count < 0xb) { + return 0; + } +--- a/Embedded/src/GbE/iegbe.h ++++ b/Embedded/src/GbE/iegbe.h +@@ -1,7 +1,7 @@ + /******************************************************************************* + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -21,7 +21,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +@@ -127,9 +127,12 @@ struct iegbe_adapter; + #define E1000_MIN_RXD 80 + #define E1000_MAX_82544_RXD 4096 + ++#define MAXIMUM_ETHERNET_VLAN_SIZE 1522 + /* Supported Rx Buffer Sizes */ + #define E1000_RXBUFFER_128 128 /* Used for packet split */ + #define E1000_RXBUFFER_256 256 /* Used for packet split */ ++#define E1000_RXBUFFER_512 512 ++#define E1000_RXBUFFER_1024 1024 + #define E1000_RXBUFFER_2048 2048 + #define E1000_RXBUFFER_4096 4096 + #define E1000_RXBUFFER_8192 8192 +@@ -164,11 +167,9 @@ struct iegbe_adapter; + #define E1000_MASTER_SLAVE iegbe_ms_hw_default + #endif + +-#ifdef NETIF_F_HW_VLAN_TX +-#define E1000_MNG_VLAN_NONE -1 +-#endif ++#define E1000_MNG_VLAN_NONE (-1) + /* Number of packet split data buffers (not including the header buffer) */ +-#define PS_PAGE_BUFFERS MAX_PS_BUFFERS-1 ++#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) + + /* only works for sizes that are powers of 2 */ + #define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1))) +@@ -206,6 +207,7 @@ struct iegbe_tx_ring { + spinlock_t tx_lock; + uint16_t tdh; + uint16_t tdt; ++ boolean_t last_tx_tso; + uint64_t pkt; + }; + +@@ -228,6 +230,9 @@ struct iegbe_rx_ring { + struct iegbe_ps_page *ps_page; + struct iegbe_ps_page_dma *ps_page_dma; + ++ /* cpu for rx queue */ ++ int cpu; ++ + uint16_t rdh; + uint16_t rdt; + uint64_t pkt; +@@ -252,10 +257,8 @@ struct iegbe_adapter { + struct timer_list tx_fifo_stall_timer; + struct timer_list watchdog_timer; + struct timer_list phy_info_timer; +-#ifdef NETIF_F_HW_VLAN_TX + struct vlan_group *vlgrp; + uint16_t mng_vlan_id; +-#endif + uint32_t bd_number; + uint32_t rx_buffer_len; + uint32_t part_num; +@@ -265,8 +268,18 @@ struct iegbe_adapter { + uint16_t link_speed; + uint16_t link_duplex; + spinlock_t stats_lock; +- atomic_t irq_sem; +- struct work_struct tx_timeout_task; ++ spinlock_t tx_queue_lock; ++ unsigned int total_tx_bytes; ++ unsigned int total_tx_packets; ++ unsigned int total_rx_bytes; ++ unsigned int total_rx_packets; ++ /* Interrupt Throttle Rate */ ++ uint32_t itr; ++ uint32_t itr_setting; ++ uint16_t tx_itr; ++ uint16_t rx_itr; ++ ++ struct work_struct reset_task; + uint8_t fc_autoneg; + + #ifdef ETHTOOL_PHYS_ID +@@ -276,9 +289,8 @@ struct iegbe_adapter { + + /* TX */ + struct iegbe_tx_ring *tx_ring; /* One per active queue */ +-#ifdef CONFIG_E1000_MQ +- struct iegbe_tx_ring **cpu_tx_ring; /* per-cpu */ +-#endif ++ unsigned int restart_queue; ++ unsigned long tx_queue_len; + uint32_t txd_cmd; + uint32_t tx_int_delay; + uint32_t tx_abs_int_delay; +@@ -286,46 +298,33 @@ struct iegbe_adapter { + uint64_t gotcl_old; + uint64_t tpt_old; + uint64_t colc_old; ++ uint32_t tx_timeout_count; + uint32_t tx_fifo_head; + uint32_t tx_head_addr; + uint32_t tx_fifo_size; ++ uint8_t tx_timeout_factor; + atomic_t tx_fifo_stall; + boolean_t pcix_82544; + boolean_t detect_tx_hung; + + /* RX */ +-#ifdef CONFIG_E1000_NAPI +- boolean_t (*clean_rx) (struct iegbe_adapter *adapter, ++ bool (*clean_rx)(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring, + int *work_done, int work_to_do); +-#else +- boolean_t (*clean_rx) (struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring); +-#endif +- +-#ifdef IEGBE_GBE_WORKAROUND + void (*alloc_rx_buf) (struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring, +- int cleaned_count); +-#else +- void (*alloc_rx_buf) (struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring); +-#endif +- ++ struct iegbe_rx_ring *rx_ring, ++ int cleaned_count); + struct iegbe_rx_ring *rx_ring; /* One per active queue */ +-#ifdef CONFIG_E1000_NAPI ++ struct napi_struct napi; + struct net_device *polling_netdev; /* One per active queue */ +-#endif +-#ifdef CONFIG_E1000_MQ +- struct net_device **cpu_netdev; /* per-cpu */ +- struct call_async_data_struct rx_sched_call_data; +- int cpu_for_queue[4]; +-#endif +- int num_queues; ++ ++ int num_tx_queues; ++ int num_rx_queues; + + uint64_t hw_csum_err; + uint64_t hw_csum_good; + uint64_t rx_hdr_split; ++ uint32_t alloc_rx_buff_failed; + uint32_t rx_int_delay; + uint32_t rx_abs_int_delay; + boolean_t rx_csum; +@@ -334,8 +333,6 @@ struct iegbe_adapter { + uint64_t gorcl_old; + uint16_t rx_ps_bsize0; + +- /* Interrupt Throttle Rate */ +- uint32_t itr; + + /* OS defined structs */ + struct net_device *netdev; +@@ -378,7 +375,21 @@ struct iegbe_adapter { + #ifdef CONFIG_PCI_MSI + boolean_t have_msi; + #endif +-#define IEGBE_INTD_DISABLE 0x0400 ++ /* to not mess up cache alignment, always add to the bottom */ ++ boolean_t tso_force; ++ boolean_t smart_power_down; /* phy smart power down */ ++ boolean_t quad_port_a; ++ unsigned long flags; ++ uint32_t eeprom_wol; ++ int bars; ++ int need_ioport; + }; ++ ++enum iegbe_state_t { ++ __E1000_TESTING, ++ __E1000_RESETTING, ++ __E1000_DOWN ++}; ++#define IEGBE_INTD_DISABLE 0x0400 + #endif /* _IEGBE_H_ */ + +--- a/Embedded/src/GbE/iegbe_hw.c ++++ b/Embedded/src/GbE/iegbe_hw.c +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +@@ -2115,7 +2115,7 @@ iegbe_config_mac_to_phy(struct iegbe_hw + + ret_val = iegbe_oem_set_trans_gasket(hw); + if(ret_val){ +- return ret_val; ++ return ret_val; + } + ret_val = iegbe_oem_phy_is_full_duplex( + hw, (int *) &is_FullDuplex); +@@ -2164,7 +2164,7 @@ iegbe_config_mac_to_phy(struct iegbe_hw + } + /* Write the configured values back to the Device Control Reg. */ + E1000_WRITE_REG(hw, CTRL, ctrl); +- return E1000_SUCCESS; ++ return ret_val; + } + + /***************************************************************************** +@@ -2684,7 +2684,7 @@ iegbe_check_for_link(struct iegbe_hw *hw + + if(hw->autoneg_failed == 0) { + hw->autoneg_failed = 1; +- return 0; ++ return E1000_SUCCESS; + } + DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n"); + +@@ -5875,7 +5875,7 @@ iegbe_get_cable_length(struct iegbe_hw * + max_agc = cur_agc; + } + } +- ++ + /* This is to fix a Klockwork defect, that the array index might + * be out of bounds. 113 is table size */ + if (cur_agc < 0x71){ +--- a/Embedded/src/GbE/iegbe_hw.h ++++ b/Embedded/src/GbE/iegbe_hw.h +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +@@ -299,7 +299,7 @@ void iegbe_set_media_type(struct iegbe_h + /* Link Configuration */ + int32_t iegbe_setup_link(struct iegbe_hw *hw); + int32_t iegbe_phy_setup_autoneg(struct iegbe_hw *hw); +-void iegbe_config_collision_dist(struct iegbe_hw *hw); ++void iegbe_config_collision_dist(struct iegbe_hw *hw); + int32_t iegbe_config_fc_after_link_up(struct iegbe_hw *hw); + int32_t iegbe_check_for_link(struct iegbe_hw *hw); + int32_t iegbe_get_speed_and_duplex(struct iegbe_hw *hw, uint16_t * speed, uint16_t * duplex); +@@ -588,14 +588,6 @@ uint8_t iegbe_arc_subsystem_valid(struct + * o LSC = Link Status Change + */ + +-#ifdef IEGBE_GBE_WORKAROUND +-#define IMS_ENABLE_MASK ( \ +- E1000_IMS_RXT0 | \ +- E1000_IMS_TXQE | \ +- E1000_IMS_RXDMT0 | \ +- E1000_IMS_RXSEQ | \ +- E1000_IMS_LSC) +-#else + #define IMS_ENABLE_MASK ( \ + E1000_IMS_RXT0 | \ + E1000_IMS_TXDW | \ +@@ -606,8 +598,7 @@ uint8_t iegbe_arc_subsystem_valid(struct + E1000_ICR_PB | \ + E1000_ICR_CPP_TARGET | \ + E1000_ICR_CPP_MASTER | \ +- E1000_IMS_LSC) +-#endif ++ E1000_ICR_LSC) + + /* Number of high/low register pairs in the RAR. The RAR (Receive Address + * Registers) holds the directed and multicast addresses that we monitor. We +@@ -923,10 +914,15 @@ struct iegbe_ffvt_entry { + #define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ + #define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ + #define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ +-// Register conflict, does not exist for ICP_xxxx hardware +-// #define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ + #define E1000_CTRL_AUX 0x000E0 /* Aux Control -RW */ ++#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ + #define E1000_RCTL 0x00100 /* RX Control - RW */ ++#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */ ++#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */ ++#define E1000_RDBAH1 0x02904 /* RX Descriptor Base Address High (1) - RW */ ++#define E1000_RDLEN1 0x02908 /* RX Descriptor Length (1) - RW */ ++#define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */ ++#define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */ + #define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ + #define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ + #define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ +@@ -1282,8 +1278,6 @@ struct iegbe_ffvt_entry { + #define E1000_82542_FFMT E1000_FFMT + #define E1000_82542_FFVT E1000_FFVT + #define E1000_82542_HOST_IF E1000_HOST_IF +-// Register conflict with ICP_xxxx hardware, no IAM +-// #define E1000_82542_IAM E1000_IAM + #define E1000_82542_EEMNGCTL E1000_EEMNGCTL + #define E1000_82542_PSRCTL E1000_PSRCTL + #define E1000_82542_RAID E1000_RAID +@@ -1329,6 +1323,7 @@ struct iegbe_hw_stats { + uint64_t algnerrc; + uint64_t symerrs; + uint64_t rxerrc; ++ uint64_t txerrc; + uint64_t mpc; + uint64_t scc; + uint64_t ecol; +@@ -1363,6 +1358,7 @@ struct iegbe_hw_stats { + uint64_t ruc; + uint64_t rfc; + uint64_t roc; ++ uint64_t rlerrc; + uint64_t rjc; + uint64_t mgprc; + uint64_t mgpdc; +@@ -1392,19 +1388,6 @@ struct iegbe_hw_stats { + uint64_t ictxqmtc; + uint64_t icrxdmtc; + uint64_t icrxoc; +-#ifdef IEGBE_GBE_WORKAROUND +- u64 txqec; +- u64 tx_next_to_clean; +- u64 tx_next_to_use; +- u64 cc_gt_num_rx; +- u64 tx_hnet; +- u64 tx_hnentu; +- u64 num_tx_queues; +- +- u64 num_rx_buf_alloc; +- u64 rx_next_to_clean; +- u64 rx_next_to_use; +-#endif + }; + + /* Structure containing variables used by the shared code (iegbe_hw.c) */ +@@ -1484,6 +1467,7 @@ struct iegbe_hw { + boolean_t ifs_params_forced; + boolean_t in_ifs_mode; + boolean_t mng_reg_access_disabled; ++ boolean_t rx_needs_kicking; + boolean_t icp_xxxx_is_link_up; + }; + +@@ -2358,17 +2342,23 @@ struct iegbe_host_command_info { + #define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH 0x000000FF + #define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH 0x0000FF00 + #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH 0x00FF0000 ++#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 ++#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 + + /* PBA constants */ ++#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */ + #define E1000_PBA_12K 0x000C /* 12KB, default Rx allocation */ + #define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ ++#define E1000_PBA_20K 0x0014 + #define E1000_PBA_22K 0x0016 + #define E1000_PBA_24K 0x0018 + #define E1000_PBA_30K 0x001E + #define E1000_PBA_32K 0x0020 ++#define E1000_PBA_34K 0x0022 + #define E1000_PBA_38K 0x0026 + #define E1000_PBA_40K 0x0028 + #define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ ++#define E1000_PBS_16K E1000_PBA_16K + + /* Flow Control Constants */ + #define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 +@@ -2899,7 +2889,7 @@ struct iegbe_host_command_info { + #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID + #define M88E1011_I_REV_4 0x04 + #define M88E1111_I_PHY_ID 0x01410CC2 +-#define M88E1141_E_PHY_ID 0x01410CD4 ++#define M88E1141_E_PHY_ID 0x01410CD0 + #define L1LXT971A_PHY_ID 0x001378E0 + + /* Miscellaneous PHY bit definitions. */ +--- a/Embedded/src/GbE/iegbe_main.c ++++ b/Embedded/src/GbE/iegbe_main.c +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +@@ -42,103 +42,15 @@ GPL LICENSE SUMMARY + + #include "iegbe.h" + #include "gcu_if.h" +- +-/* Change Log +- * 6.0.58 4/20/05 +- * o iegbe_set_spd_dplx tests for compatible speed/duplex specification +- * for fiber adapters +- * 6.0.57 4/19/05 +- * o Added code to fix register test failure for devices >= 82571 +- * +- * 6.0.52 3/15/05 +- * o Added stats_lock around iegbe_read_phy_reg commands to avoid concurrent +- * calls, one from mii_ioctl and other from within update_stats while +- * processing MIIREG ioctl. +- * +- * 6.1.2 4/13/05 +- * o Fixed ethtool diagnostics +- * o Enabled flow control to take default eeprom settings +- * o Added stats_lock around iegbe_read_phy_reg commands to avoid concurrent +- * calls, one from mii_ioctl and other from within update_stats while processing +- * MIIREG ioctl. +- * 6.0.55 3/23/05 +- * o Support for MODULE_VERSION +- * o Fix APM setting for 82544 based adapters +- * 6.0.54 3/26/05 +- * o Added a timer to expire packets that were deferred for cleanup +- * 6.0.52 3/15/05 +- * o Added stats_lock around iegbe_read_phy_reg commands to avoid concurrent +- * calls, one from mii_ioctl and other from within update_stats while +- * processing MIIREG ioctl. +- * 6.0.47 3/2/05 +- * o Added enhanced functionality to the loopback diags to wrap the +- * descriptor rings +- * o Added manageability vlan filtering workaround. +- * +- * 6.0.44+ 2/15/05 +- * o Added code to handle raw packet based DHCP packets +- * o Added code to fix the errata 10 buffer overflow issue +- * o Sync up with WR01-05 +- * o applied Anton's patch to resolve tx hang in hardware +- * o iegbe timeouts with early writeback patch +- * o Removed Queensport IDs +- * o fixed driver panic if MAC receives a bad large packets when packet +- * split is enabled +- * o Applied Andrew Mortons patch - iegbe stops working after resume +- * 5.2.29 12/24/03 +- * o Bug fix: Endianess issue causing ethtool diags to fail on ppc. +- * o Bug fix: Use pdev->irq instead of netdev->irq for MSI support. +- * o Report driver message on user override of InterruptThrottleRate module +- * parameter. +- * o Bug fix: Change I/O address storage from uint32_t to unsigned long. +- * o Feature: Added ethtool RINGPARAM support. +- * o Feature: Added netpoll support. +- * o Bug fix: Race between Tx queue and Tx clean fixed with a spin lock. +- * o Bug fix: Allow 1000/Full setting for autoneg param for fiber connections. +- * Jon D Mason [jonmason@us.ibm.com]. +- * +- * 5.2.22 10/15/03 +- * o Bug fix: SERDES devices might be connected to a back-plane switch that +- * doesn't support auto-neg, so add the capability to force 1000/Full. +- * Also, since forcing 1000/Full, sample RxSynchronize bit to detect link +- * state. +- * o Bug fix: Flow control settings for hi/lo watermark didn't consider +- * changes in the RX FIFO size, which could occur with Jumbo Frames or with +- * the reduced FIFO in 82547. +- * o Bug fix: Better propagation of error codes. +- * [Janice Girouard (janiceg -a-t- us.ibm.com)] +- * o Bug fix: hang under heavy Tx stress when running out of Tx descriptors; +- * wasn't clearing context descriptor when backing out of send because of +- * no-resource condition. +- * o Bug fix: check netif_running in dev->poll so we don't have to hang in +- * dev->close until all polls are finished. [Rober Olsson +- * (robert.olsson@data.slu.se)]. +- * o Revert TxDescriptor ring size back to 256 since change to 1024 wasn't +- * accepted into the kernel. +- * +- * 5.2.16 8/8/03 +- */ +- +-#ifdef IEGBE_GBE_WORKAROUND +-#define IEGBE_GBE_WORKAROUND_NUM_RX_DESCRIPTORS 1 +-#endif ++#include <linux/ipv6.h> ++#include <net/ip6_checksum.h> + + char iegbe_driver_name[] = "iegbe"; + char iegbe_driver_string[] = "Gigabit Ethernet Controller Driver"; +-#ifndef CONFIG_E1000_NAPI +-#define DRIVERNAPI +-#else +-#define DRIVERNAPI "-NAPI" +-#endif +-#define DRV_VERSION "0.8.0"DRIVERNAPI ++#define DRV_VERSION "1.0.0-K28-NAPI" + char iegbe_driver_version[] = DRV_VERSION; +-char iegbe_copyright[] = "Copyright (c) 1999-2007 Intel Corporation."; ++char iegbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation."; + +-#define E1000_FIFO_HDR 0x10 +-#define E1000_82547_PAD_LEN 0x3E0 +-#define MINIMUM_DHCP_PACKET_SIZE 282 +-#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) +-#define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 + + /* iegbe_pci_tbl - PCI Device ID Table + * +@@ -148,95 +60,48 @@ char iegbe_copyright[] = "Copyright (c) + * {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} + */ + static struct pci_device_id iegbe_pci_tbl[] = { +-/* INTEL_E1000_ETHERNET_DEVICE(0x1000), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1001), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1004), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1008), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1009), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x100C), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x100D), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x100E), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x100F), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1010), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1011), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1012), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1013), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1014), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1015), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1016), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1017), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1018), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1019), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x101A), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x101D), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x101E), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1026), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1027), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1028), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x105E), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x105F), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1060), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1075), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1076), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1077), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1078), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x1079), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x107A), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x107B), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x107C), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x107D), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x107E), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x107F), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x108A), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x108B), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x108C), */ +-/* INTEL_E1000_ETHERNET_DEVICE(0x109A), */ +- INTEL_E1000_ETHERNET_DEVICE(0x5040), +- INTEL_E1000_ETHERNET_DEVICE(0x5041), +- INTEL_E1000_ETHERNET_DEVICE(0x5042), +- INTEL_E1000_ETHERNET_DEVICE(0x5043), +- INTEL_E1000_ETHERNET_DEVICE(0x5044), +- INTEL_E1000_ETHERNET_DEVICE(0x5045), +- INTEL_E1000_ETHERNET_DEVICE(0x5046), +- INTEL_E1000_ETHERNET_DEVICE(0x5047), +- INTEL_E1000_ETHERNET_DEVICE(0x5048), +- INTEL_E1000_ETHERNET_DEVICE(0x5049), +- INTEL_E1000_ETHERNET_DEVICE(0x504A), +- INTEL_E1000_ETHERNET_DEVICE(0x504B), +- /* required last entry */ ++ INTEL_E1000_ETHERNET_DEVICE(0x5040), ++ INTEL_E1000_ETHERNET_DEVICE(0x5041), ++ INTEL_E1000_ETHERNET_DEVICE(0x5042), ++ INTEL_E1000_ETHERNET_DEVICE(0x5043), ++ INTEL_E1000_ETHERNET_DEVICE(0x5044), ++ INTEL_E1000_ETHERNET_DEVICE(0x5045), ++ INTEL_E1000_ETHERNET_DEVICE(0x5046), ++ INTEL_E1000_ETHERNET_DEVICE(0x5047), ++ INTEL_E1000_ETHERNET_DEVICE(0x5048), ++ INTEL_E1000_ETHERNET_DEVICE(0x5049), ++ INTEL_E1000_ETHERNET_DEVICE(0x504A), ++ INTEL_E1000_ETHERNET_DEVICE(0x504B), ++ /* required last entry */ + {0,} + }; + + MODULE_DEVICE_TABLE(pci, iegbe_pci_tbl); + +-DEFINE_SPINLOCK(print_lock); + + int iegbe_up(struct iegbe_adapter *adapter); + void iegbe_down(struct iegbe_adapter *adapter); ++void iegbe_reinit_locked(struct iegbe_adapter *adapter); + void iegbe_reset(struct iegbe_adapter *adapter); + int iegbe_set_spd_dplx(struct iegbe_adapter *adapter, uint16_t spddplx); + int iegbe_setup_all_tx_resources(struct iegbe_adapter *adapter); + int iegbe_setup_all_rx_resources(struct iegbe_adapter *adapter); + void iegbe_free_all_tx_resources(struct iegbe_adapter *adapter); + void iegbe_free_all_rx_resources(struct iegbe_adapter *adapter); +-int iegbe_setup_tx_resources(struct iegbe_adapter *adapter, ++static int iegbe_setup_tx_resources(struct iegbe_adapter *adapter, + struct iegbe_tx_ring *txdr); +-int iegbe_setup_rx_resources(struct iegbe_adapter *adapter, ++static int iegbe_setup_rx_resources(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rxdr); +-void iegbe_free_tx_resources(struct iegbe_adapter *adapter, ++static void iegbe_free_tx_resources(struct iegbe_adapter *adapter, + struct iegbe_tx_ring *tx_ring); +-void iegbe_free_rx_resources(struct iegbe_adapter *adapter, ++static void iegbe_free_rx_resources(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring); + void iegbe_update_stats(struct iegbe_adapter *adapter); +- + static int iegbe_init_module(void); + static void iegbe_exit_module(void); + static int iegbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent); + static void __devexit iegbe_remove(struct pci_dev *pdev); + static int iegbe_alloc_queues(struct iegbe_adapter *adapter); +-#ifdef CONFIG_E1000_MQ +-static void iegbe_setup_queue_mapping(struct iegbe_adapter *adapter); +-#endif + static int iegbe_sw_init(struct iegbe_adapter *adapter); + static int iegbe_open(struct net_device *netdev); + static int iegbe_close(struct net_device *netdev); +@@ -249,7 +114,8 @@ static void iegbe_clean_tx_ring(struct i + struct iegbe_tx_ring *tx_ring); + static void iegbe_clean_rx_ring(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring); +-static void iegbe_set_multi(struct net_device *netdev); ++ ++static void iegbe_set_rx_mode(struct net_device *netdev); + static void iegbe_update_phy_info(unsigned long data); + static void iegbe_watchdog(unsigned long data); + static void iegbe_82547_tx_fifo_stall(unsigned long data); +@@ -257,66 +123,46 @@ static int iegbe_xmit_frame(struct sk_bu + static struct net_device_stats * iegbe_get_stats(struct net_device *netdev); + static int iegbe_change_mtu(struct net_device *netdev, int new_mtu); + static int iegbe_set_mac(struct net_device *netdev, void *p); +-static irqreturn_t iegbe_intr(int irq, void *data, struct pt_regs *regs); ++static irqreturn_t iegbe_intr(int irq, void *data); + +-void iegbe_tasklet(unsigned long); ++static irqreturn_t iegbe_intr_msi(int irq, void *data); + +-#ifndef IEGBE_GBE_WORKAROUND +-static boolean_t iegbe_clean_tx_irq(struct iegbe_adapter *adapter, ++static bool iegbe_clean_tx_irq(struct iegbe_adapter *adapter, + struct iegbe_tx_ring *tx_ring); +-#endif +- +-#ifdef CONFIG_E1000_NAPI +-static int iegbe_clean(struct net_device *poll_dev, int *budget); +-static boolean_t iegbe_clean_rx_irq(struct iegbe_adapter *adapter, ++static int iegbe_clean(struct napi_struct *napi, int budget); ++static bool iegbe_clean_rx_irq(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring, + int *work_done, int work_to_do); +-static boolean_t iegbe_clean_rx_irq_ps(struct iegbe_adapter *adapter, ++static bool iegbe_clean_rx_irq_ps(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring, + int *work_done, int work_to_do); +-#else +-static boolean_t iegbe_clean_rx_irq(struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring); +-static boolean_t iegbe_clean_rx_irq_ps(struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring); +-#endif + +-#ifdef IEGBE_GBE_WORKAROUND ++ + static void iegbe_alloc_rx_buffers(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring, + int cleaned_count); + static void iegbe_alloc_rx_buffers_ps(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring, + int cleaned_count); +-#else +-static void iegbe_alloc_rx_buffers(struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring); +-static void iegbe_alloc_rx_buffers_ps(struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring); +-#endif ++ + + static int iegbe_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); +-#ifdef SIOCGMIIPHY + static int iegbe_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, +- int cmd); +-#endif ++ int cmd); + void set_ethtool_ops(struct net_device *netdev); + extern int ethtool_ioctl(struct ifreq *ifr); + static void iegbe_enter_82542_rst(struct iegbe_adapter *adapter); + static void iegbe_leave_82542_rst(struct iegbe_adapter *adapter); + static void iegbe_tx_timeout(struct net_device *dev); +-static void iegbe_tx_timeout_task(struct net_device *dev); ++static void iegbe_reset_task(struct work_struct *work); + static void iegbe_smartspeed(struct iegbe_adapter *adapter); + static inline int iegbe_82547_fifo_workaround(struct iegbe_adapter *adapter, +- struct sk_buff *skb); ++ struct sk_buff *skb); + +-#ifdef NETIF_F_HW_VLAN_TX +-static void iegbe_vlan_rx_register(struct net_device *netdev, +- struct vlan_group *grp); ++static void iegbe_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); + static void iegbe_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); + static void iegbe_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); + static void iegbe_restore_vlan(struct iegbe_adapter *adapter); +-#endif + + static int iegbe_notify_reboot(struct notifier_block *, + unsigned long event, +@@ -331,15 +177,17 @@ static int iegbe_resume(struct pci_dev * + static void iegbe_netpoll (struct net_device *netdev); + #endif + +-#ifdef CONFIG_E1000_MQ +-/* for multiple Rx queues */ ++#define COPYBREAK_DEFAULT 256 ++static unsigned int copybreak __read_mostly = COPYBREAK_DEFAULT; ++module_param(copybreak, uint, 0644); ++MODULE_PARM_DESC(copybreak, ++ "Maximum size of packet that is copied to a new buffer on receive"); + void iegbe_rx_schedule(void *data); +-#endif + + struct notifier_block iegbe_notifier_reboot = { +- .notifier_call = iegbe_notify_reboot, +- .next = NULL, +- .priority = 0 ++ .notifier_call = iegbe_notify_reboot, ++ .next = NULL, ++ .priority = 0 + }; + + /* Exported from other modules */ +@@ -347,14 +195,14 @@ struct notifier_block iegbe_notifier_reb + extern void iegbe_check_options(struct iegbe_adapter *adapter); + + static struct pci_driver iegbe_driver = { +- .name = iegbe_driver_name, +- .id_table = iegbe_pci_tbl, +- .probe = iegbe_probe, +- .remove = __devexit_p(iegbe_remove), +- /* Power Managment Hooks */ ++ .name = iegbe_driver_name, ++ .id_table = iegbe_pci_tbl, ++ .probe = iegbe_probe, ++ .remove = __devexit_p(iegbe_remove), ++ /* Power Managment Hooks */ + #ifdef CONFIG_PM +- .suspend = iegbe_suspend, +- .resume = iegbe_resume ++ .suspend = iegbe_suspend, ++ .resume = iegbe_resume + #endif + }; + +@@ -364,46 +212,17 @@ MODULE_LICENSE("GPL"); + MODULE_VERSION(DRV_VERSION); + + static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE; +-module_param(debug, int, 0); ++module_param(debug, int, 0x0); + MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +-static uint8_t gcu_suspend = 0; +-static uint8_t gcu_resume = 0; ++static uint8_t gcu_suspend = 0x0; ++static uint8_t gcu_resume = 0x0; + struct pci_dev *gcu = NULL; + +-unsigned long tasklet_data; +-DECLARE_TASKLET(iegbe_reset_tasklet, iegbe_tasklet, (unsigned long) &tasklet_data); + + /** + * iegbe_iegbe_tasklet -* + **/ +-void iegbe_tasklet(unsigned long data) +-{ +- char* err_msg = "TEST"; +- uint32_t *icr = (uint32_t*) data; +- uint32_t gbe = *icr & 0x000000FF; +- if( *icr & E1000_ICR_RX_DESC_FIFO_PAR) { /* 21 */ +- err_msg = "DMA Transmit Descriptor 2-bit ECC Error!"; +- } +- if( *icr & E1000_ICR_TX_DESC_FIFO_PAR) { /* 20 */ +- err_msg = "DMA Receive Descriptor 2-bit ECC Error!"; +- } +- if( *icr & E1000_ICR_PB) { /* 23 */ +- err_msg = "DMA Packet Buffer 2-bit ECC Error!"; +- } +- if( *icr & E1000_ICR_CPP_TARGET) { /* 27 */ +- err_msg = "Statistic Register ECC Error!"; +- } +- if( *icr & E1000_ICR_CPP_MASTER) { +- err_msg = "CPP Error!"; +- } +- spin_lock(&print_lock); +- printk("IEGBE%d: System Reset due to: %s\n", gbe, err_msg); +- dump_stack(); +- spin_unlock(&print_lock); +- panic(err_msg); +- return; +-} + /** + * iegbe_init_module - Driver Registration Routine + * +@@ -411,21 +230,24 @@ void iegbe_tasklet(unsigned long data) + * loaded. All it does is register with the PCI subsystem. + **/ + +-static int __init +-iegbe_init_module(void) ++static int __init iegbe_init_module(void) + { +- int ret; ++ int ret; + + printk(KERN_INFO "%s - version %s\n", +- iegbe_driver_string, iegbe_driver_version); ++ iegbe_driver_string, iegbe_driver_version); + +- printk(KERN_INFO "%s\n", iegbe_copyright); ++ printk(KERN_INFO "%s\n", iegbe_copyright); + +- ret = pci_module_init(&iegbe_driver); +- if(ret >= 0) { +- register_reboot_notifier(&iegbe_notifier_reboot); +- } +- return ret; ++ ret = pci_register_driver(&iegbe_driver); ++ if (copybreak != COPYBREAK_DEFAULT) { ++ if (copybreak == 0) ++ printk(KERN_INFO "iegbe: copybreak disabled\n"); ++ else ++ printk(KERN_INFO "iegbe: copybreak enabled for " ++ "packets <= %u bytes\n", copybreak); ++ } ++ return ret; + } + + module_init(iegbe_init_module); +@@ -437,29 +259,51 @@ module_init(iegbe_init_module); + * from memory. + **/ + +-static void __exit +-iegbe_exit_module(void) ++static void __exit iegbe_exit_module(void) + { +- +- unregister_reboot_notifier(&iegbe_notifier_reboot); +- pci_unregister_driver(&iegbe_driver); ++ pci_unregister_driver(&iegbe_driver); + } + + module_exit(iegbe_exit_module); + ++static int iegbe_request_irq(struct iegbe_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ irq_handler_t handler = iegbe_intr; ++ int irq_flags = IRQF_SHARED; ++ int err; ++ adapter->have_msi = !pci_enable_msi(adapter->pdev); ++ if (adapter->have_msi) { ++ handler = iegbe_intr_msi; ++ irq_flags = 0; ++ } ++ err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name, ++ netdev); ++ if (err) { ++ if (adapter->have_msi) ++ pci_disable_msi(adapter->pdev); ++ DPRINTK(PROBE, ERR, ++ "Unable to allocate interrupt Error: %d\n", err); ++ } ++ return err; ++} ++static void iegbe_free_irq(struct iegbe_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ free_irq(adapter->pdev->irq, netdev); ++ if (adapter->have_msi) ++ pci_disable_msi(adapter->pdev); ++} + /** + * iegbe_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + **/ + +-static inline void +-iegbe_irq_disable(struct iegbe_adapter *adapter) ++static void iegbe_irq_disable(struct iegbe_adapter *adapter) + { +- +- atomic_inc(&adapter->irq_sem); +- E1000_WRITE_REG(&adapter->hw, IMC, ~0); +- E1000_WRITE_FLUSH(&adapter->hw); +- synchronize_irq(adapter->pdev->irq); ++ E1000_WRITE_REG(&adapter->hw, IMC, ~0); ++ E1000_WRITE_FLUSH(&adapter->hw); ++ synchronize_irq(adapter->pdev->irq); + } + + /** +@@ -470,244 +314,414 @@ iegbe_irq_disable(struct iegbe_adapter * + static inline void + iegbe_irq_enable(struct iegbe_adapter *adapter) + { +- +- if(likely(atomic_dec_and_test(&adapter->irq_sem))) { +- E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK); +- E1000_WRITE_FLUSH(&adapter->hw); +- } ++ E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK); ++ E1000_WRITE_FLUSH(&adapter->hw); + } +-#ifdef NETIF_F_HW_VLAN_TX +-void +-iegbe_update_mng_vlan(struct iegbe_adapter *adapter) +-{ +- struct net_device *netdev = adapter->netdev; +- uint16_t vid = adapter->hw.mng_cookie.vlan_id; +- uint16_t old_vid = adapter->mng_vlan_id; + +- if(adapter->vlgrp) { +- if(!adapter->vlgrp->vlan_devices[vid]) { +- if(adapter->hw.mng_cookie.status & +- E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) { +- iegbe_vlan_rx_add_vid(netdev, vid); +- adapter->mng_vlan_id = vid; +- } else { +- adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; +- } +- if((old_vid != (uint16_t)E1000_MNG_VLAN_NONE) && +- (vid != old_vid) && +- !adapter->vlgrp->vlan_devices[old_vid]) { +- iegbe_vlan_rx_kill_vid(netdev, old_vid); +- } +- } +-} ++static void iegbe_update_mng_vlan(struct iegbe_adapter *adapter) ++{ ++ struct iegbe_hw *hw = &adapter->hw; ++ struct net_device *netdev = adapter->netdev; ++ u16 vid = hw->mng_cookie.vlan_id; ++ u16 old_vid = adapter->mng_vlan_id; ++ if (adapter->vlgrp) { ++ if (!vlan_group_get_device(adapter->vlgrp, vid)) { ++ if (hw->mng_cookie.status & ++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) { ++ iegbe_vlan_rx_add_vid(netdev, vid); ++ adapter->mng_vlan_id = vid; ++ } else ++ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; ++ ++ if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && ++ (vid != old_vid) && ++ !vlan_group_get_device(adapter->vlgrp, old_vid)) ++ iegbe_vlan_rx_kill_vid(netdev, old_vid); ++ } else ++ adapter->mng_vlan_id = vid; ++ } + } +-#endif + +-int +-iegbe_up(struct iegbe_adapter *adapter) ++/** ++ * iegbe_configure - configure the hardware for RX and TX ++ * @adapter = private board structure ++ **/ ++static void iegbe_configure(struct iegbe_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; +- int i, err; +- uint16_t pci_cmd; +- +- /* hardware has been reset, we need to reload some things */ +- +- /* Reset the PHY if it was previously powered down */ +- if(adapter->hw.media_type == iegbe_media_type_copper +- || (adapter->hw.media_type == iegbe_media_type_oem +- && iegbe_oem_phy_is_copper(&adapter->hw))) { +- uint16_t mii_reg; +- iegbe_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); +- if(mii_reg & MII_CR_POWER_DOWN){ +- iegbe_phy_reset(&adapter->hw); +- } +- } ++ int i; + +- iegbe_set_multi(netdev); ++ iegbe_set_rx_mode(netdev); + +-#ifdef NETIF_F_HW_VLAN_TX + iegbe_restore_vlan(adapter); +-#endif + + iegbe_configure_tx(adapter); + iegbe_setup_rctl(adapter); + iegbe_configure_rx(adapter); ++ /* call E1000_DESC_UNUSED which always leaves ++ * at least 1 descriptor unused to make sure ++ * next_to_use != next_to_clean */ ++ for (i = 0; i < adapter->num_rx_queues; i++) { ++ struct iegbe_rx_ring *ring = &adapter->rx_ring[i]; ++ adapter->alloc_rx_buf(adapter, ring, ++ E1000_DESC_UNUSED(ring)); ++ } + +-#ifdef IEGBE_GBE_WORKAROUND +- for (i = 0; i < adapter->num_queues; i++) +- adapter->alloc_rx_buf(adapter, &adapter->rx_ring[i], +- IEGBE_GBE_WORKAROUND_NUM_RX_DESCRIPTORS + 1); +-#else +- for (i = 0; i < adapter->num_queues; i++) +- adapter->alloc_rx_buf(adapter, &adapter->rx_ring[i]); +-#endif ++ adapter->tx_queue_len = netdev->tx_queue_len; ++} + +-#ifdef CONFIG_PCI_MSI +- if(adapter->hw.mac_type > iegbe_82547_rev_2 +- || adapter->hw.mac_type == iegbe_icp_xxxx) { +- adapter->have_msi = TRUE; +- if((err = pci_enable_msi(adapter->pdev))) { +- DPRINTK(PROBE, ERR, +- "Unable to allocate MSI interrupt Error: %d\n", err); +- adapter->have_msi = FALSE; +- } +- } +- pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd); +- pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd | IEGBE_INTD_DISABLE); ++int iegbe_up(struct iegbe_adapter *adapter) ++{ ++ /* hardware has been reset, we need to reload some things */ ++ iegbe_configure(adapter); + +-#endif +- if((err = request_irq(adapter->pdev->irq, &iegbe_intr, +- SA_SHIRQ | SA_SAMPLE_RANDOM, +- netdev->name, netdev))) { +- DPRINTK(PROBE, ERR, +- "Unable to allocate interrupt Error: %d\n", err); +- return err; +- } ++ clear_bit(__E1000_DOWN, &adapter->flags); + +- mod_timer(&adapter->watchdog_timer, jiffies); ++ napi_enable(&adapter->napi); + +-#ifdef CONFIG_E1000_NAPI +- netif_poll_enable(netdev); +-#endif + iegbe_irq_enable(adapter); + ++ adapter->hw.get_link_status = 0x1; + return 0; + } + +-void +-iegbe_down(struct iegbe_adapter *adapter) +-{ +- struct net_device *netdev = adapter->netdev; +- +- iegbe_irq_disable(adapter); +-#ifdef CONFIG_E1000_MQ +- while (atomic_read(&adapter->rx_sched_call_data.count) != 0) { }; +-#endif +- free_irq(adapter->pdev->irq, netdev); +-#ifdef CONFIG_PCI_MSI +- if((adapter->hw.mac_type > iegbe_82547_rev_2 +- || adapter->hw.mac_type == iegbe_icp_xxxx) +- && adapter->have_msi == TRUE) { +- pci_disable_msi(adapter->pdev); +- } +-#endif +- del_timer_sync(&adapter->tx_fifo_stall_timer); +- del_timer_sync(&adapter->watchdog_timer); +- del_timer_sync(&adapter->phy_info_timer); ++/** ++ * iegbe_power_up_phy - restore link in case the phy was powered down ++ * @adapter: address of board private structure ++ * ++ * The phy may be powered down to save power and turn off link when the ++ * driver is unloaded and wake on lan is not enabled (among others) ++ * *** this routine MUST be followed by a call to iegbe_reset *** ++ * ++ **/ + +-#ifdef CONFIG_E1000_NAPI +- netif_poll_disable(netdev); +-#endif +- adapter->link_speed = 0; +- adapter->link_duplex = 0; +- netif_carrier_off(netdev); +- netif_stop_queue(netdev); ++void iegbe_power_up_phy(struct iegbe_adapter *adapter) ++{ ++ struct iegbe_hw *hw = &adapter->hw; ++ u16 mii_reg = 0; + +- iegbe_reset(adapter); +- iegbe_clean_all_tx_rings(adapter); +- iegbe_clean_all_rx_rings(adapter); ++ /* Just clear the power down bit to wake the phy back up */ ++ if (hw->media_type == iegbe_media_type_copper) { ++ /* according to the manual, the phy will retain its ++ * settings across a power-down/up cycle */ ++ iegbe_read_phy_reg(hw, PHY_CTRL, &mii_reg); ++ mii_reg &= ~MII_CR_POWER_DOWN; ++ iegbe_write_phy_reg(hw, PHY_CTRL, mii_reg); ++ } ++} + +- /* If WoL is not enabled and management mode is not IAMT +- * or if WoL is not enabled and OEM PHY is copper based, +- * power down the PHY so no link is implied when interface is down */ +- if(!adapter->wol +- && ((adapter->hw.mac_type >= iegbe_82540 +- && adapter->hw.media_type == iegbe_media_type_copper +- && !iegbe_check_mng_mode(&adapter->hw) +- && !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN)) +- || (adapter->hw.media_type == iegbe_media_type_oem +- && iegbe_oem_phy_is_copper(&adapter->hw)))){ ++static void iegbe_power_down_phy(struct iegbe_adapter *adapter) ++{ ++ struct iegbe_hw *hw = &adapter->hw; + +- uint16_t mii_reg; +- iegbe_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); ++ /* Power down the PHY so no link is implied when interface is down * ++ * The PHY cannot be powered down if any of the following is true * ++ * (a) WoL is enabled ++ * (b) AMT is active ++ * (c) SoL/IDER session is active */ ++ if (!adapter->wol && hw->mac_type >= iegbe_82540 && ++ hw->media_type == iegbe_media_type_copper) { ++ u16 mii_reg = 0; ++ ++ switch (hw->mac_type) { ++ case iegbe_82540: ++ case iegbe_82545: ++ case iegbe_82545_rev_3: ++ case iegbe_82546: ++ case iegbe_82546_rev_3: ++ case iegbe_82541: ++ case iegbe_82541_rev_2: ++ case iegbe_82547: ++ case iegbe_82547_rev_2: ++ if (E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) ++ goto out; ++ break; ++ case iegbe_82571: ++ case iegbe_82572: ++ case iegbe_82573: ++ if (iegbe_check_mng_mode(hw) || ++ iegbe_check_phy_reset_block(hw)) ++ goto out; ++ break; ++ default: ++ goto out; ++ } ++ iegbe_read_phy_reg(hw, PHY_CTRL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; +- iegbe_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg); ++ iegbe_write_phy_reg(hw, PHY_CTRL, mii_reg); + mdelay(1); + } ++out: ++ return; + } + +-void +-iegbe_reset(struct iegbe_adapter *adapter) ++void iegbe_down(struct iegbe_adapter *adapter) + { +- struct net_device *netdev = adapter->netdev; +- uint32_t pba, manc; +- uint16_t fc_high_water_mark = E1000_FC_HIGH_DIFF; +- uint16_t fc_low_water_mark = E1000_FC_LOW_DIFF; ++ struct net_device *netdev = adapter->netdev; + ++ /* signal that we're down so the interrupt handler does not ++ * reschedule our watchdog timer */ ++ set_bit(__E1000_DOWN, &adapter->flags); + +- /* Repartition Pba for greater than 9k mtu +- * To take effect CTRL.RST is required. +- */ ++ napi_disable(&adapter->napi); + +- switch (adapter->hw.mac_type) { +- case iegbe_82547: +- case iegbe_82547_rev_2: +- pba = E1000_PBA_30K; +- break; +- case iegbe_82571: +- case iegbe_82572: +- pba = E1000_PBA_38K; +- break; +- case iegbe_82573: +- pba = E1000_PBA_12K; ++ iegbe_irq_disable(adapter); ++ ++ del_timer_sync(&adapter->tx_fifo_stall_timer); ++ del_timer_sync(&adapter->watchdog_timer); ++ del_timer_sync(&adapter->phy_info_timer); ++ ++ netdev->tx_queue_len = adapter->tx_queue_len; ++ adapter->link_speed = 0; ++ adapter->link_duplex = 0; ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ ++ iegbe_reset(adapter); ++ iegbe_clean_all_tx_rings(adapter); ++ iegbe_clean_all_rx_rings(adapter); ++} ++void iegbe_reinit_locked(struct iegbe_adapter *adapter) ++{ ++ WARN_ON(in_interrupt()); ++ while (test_and_set_bit(__E1000_RESETTING, &adapter->flags)) ++ msleep(1); ++ iegbe_down(adapter); ++ iegbe_up(adapter); ++ clear_bit(__E1000_RESETTING, &adapter->flags); ++} ++ ++void iegbe_reset(struct iegbe_adapter *adapter) ++{ ++ struct iegbe_hw *hw = &adapter->hw; ++ u32 pba = 0, tx_space, min_tx_space, min_rx_space; ++ u16 fc_high_water_mark = E1000_FC_HIGH_DIFF; ++ bool legacy_pba_adjust = false; ++ ++ /* Repartition Pba for greater than 9k mtu ++ * To take effect CTRL.RST is required. ++ */ ++ ++ switch (hw->mac_type) { ++ case iegbe_82542_rev2_0: ++ case iegbe_82542_rev2_1: ++ case iegbe_82543: ++ case iegbe_82544: ++ case iegbe_82540: ++ case iegbe_82541: ++ case iegbe_82541_rev_2: ++ case iegbe_icp_xxxx: ++ legacy_pba_adjust = true; ++ pba = E1000_PBA_48K; + break; +- default: ++ case iegbe_82545: ++ case iegbe_82545_rev_3: ++ case iegbe_82546: ++ case iegbe_82546_rev_3: + pba = E1000_PBA_48K; + break; +- } ++ case iegbe_82547: ++ case iegbe_82573: ++ case iegbe_82547_rev_2: ++ legacy_pba_adjust = true; ++ pba = E1000_PBA_30K; ++ break; ++ case iegbe_82571: ++ case iegbe_82572: ++ case iegbe_undefined: ++ case iegbe_num_macs: ++ break; ++ } ++ ++ if (legacy_pba_adjust) { ++ if (adapter->netdev->mtu > E1000_RXBUFFER_8192) ++ pba -= 8; /* allocate more FIFO for Tx */ ++ /* send an XOFF when there is enough space in the ++ * Rx FIFO to hold one extra full size Rx packet ++ */ + +- if((adapter->hw.mac_type != iegbe_82573) && +- (adapter->rx_buffer_len > E1000_RXBUFFER_8192)) { +- pba -= 0x8; /* allocate more FIFO for Tx */ +- /* send an XOFF when there is enough space in the +- * Rx FIFO to hold one extra full size Rx packet +- */ +- fc_high_water_mark = netdev->mtu + ENET_HEADER_SIZE + +- ETHERNET_FCS_SIZE + 0x1; +- fc_low_water_mark = fc_high_water_mark + 0x8; +- } + ++ if (hw->mac_type == iegbe_82547) { ++ adapter->tx_fifo_head = 0; ++ adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT; ++ adapter->tx_fifo_size = ++ (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT; ++ atomic_set(&adapter->tx_fifo_stall, 0); ++ } ++ } else if (hw->max_frame_size > MAXIMUM_ETHERNET_FRAME_SIZE) { ++ E1000_WRITE_REG(&adapter->hw, PBA, pba); ++ ++ /* To maintain wire speed transmits, the Tx FIFO should be ++ * large enough to accomodate two full transmit packets, ++ * rounded up to the next 1KB and expressed in KB. Likewise, ++ * the Rx FIFO should be large enough to accomodate at least ++ * one full receive packet and is similarly rounded up and ++ * expressed in KB. */ ++ pba = E1000_READ_REG(&adapter->hw, PBA); ++ /* upper 16 bits has Tx packet buffer allocation size in KB */ ++ tx_space = pba >> 16; ++ /* lower 16 bits has Rx packet buffer allocation size in KB */ ++ pba &= 0xffff; ++ /* don't include ethernet FCS because hardware appends/strips */ ++ min_rx_space = adapter->netdev->mtu + ENET_HEADER_SIZE + ++ VLAN_TAG_SIZE; ++ min_tx_space = min_rx_space; ++ min_tx_space *= 2; ++ min_tx_space = ALIGN(min_tx_space, 1024); ++ min_tx_space >>= 10; ++ min_rx_space = ALIGN(min_rx_space, 1024); ++ min_rx_space >>= 10; ++ ++ /* If current Tx allocation is less than the min Tx FIFO size, ++ * and the min Tx FIFO size is less than the current Rx FIFO ++ * allocation, take space away from current Rx allocation */ ++ if (tx_space < min_tx_space && ++ ((min_tx_space - tx_space) < pba)) { ++ pba = pba - (min_tx_space - tx_space); ++ ++ /* PCI/PCIx hardware has PBA alignment constraints */ ++ switch (hw->mac_type) { ++ case iegbe_82545 ... iegbe_82546_rev_3: ++ pba &= ~(E1000_PBA_8K - 1); ++ break; ++ default: ++ break; ++ } + +- if(adapter->hw.mac_type == iegbe_82547) { +- adapter->tx_fifo_head = 0; +- adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT; +- adapter->tx_fifo_size = +- (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT; +- atomic_set(&adapter->tx_fifo_stall, 0); ++ /* if short on rx space, rx wins and must trump tx ++ * adjustment or use Early Receive if available */ ++ if (pba < min_rx_space) { ++ switch (hw->mac_type) { ++ case iegbe_82573: ++ /* ERT enabled in iegbe_configure_rx */ ++ break; ++ default: ++ pba = min_rx_space; ++ break; ++ } ++ } ++ } + } + + E1000_WRITE_REG(&adapter->hw, PBA, pba); + + /* flow control settings */ +- adapter->hw.fc_high_water = (pba << E1000_PBA_BYTES_SHIFT) - +- fc_high_water_mark; +- adapter->hw.fc_low_water = (pba << E1000_PBA_BYTES_SHIFT) - +- fc_low_water_mark; +- adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME; +- adapter->hw.fc_send_xon = 1; +- adapter->hw.fc = adapter->hw.original_fc; ++ /* Set the FC high water mark to 90% of the FIFO size. ++ * Required to clear last 3 LSB */ ++ fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8; ++ /* We can't use 90% on small FIFOs because the remainder ++ * would be less than 1 full frame. In this case, we size ++ * it to allow at least a full frame above the high water ++ * mark. */ ++ if (pba < E1000_PBA_16K) ++ fc_high_water_mark = (pba * 1024) - 1600; ++ ++ hw->fc_high_water = fc_high_water_mark; ++ hw->fc_low_water = fc_high_water_mark - 8; ++ hw->fc_pause_time = E1000_FC_PAUSE_TIME; ++ hw->fc_send_xon = 1; ++ hw->fc = hw->original_fc; + + /* Allow time for pending master requests to run */ +- iegbe_reset_hw(&adapter->hw); +- if(adapter->hw.mac_type >= iegbe_82544){ ++ iegbe_reset_hw(hw); ++ if (hw->mac_type >= iegbe_82544) + E1000_WRITE_REG(&adapter->hw, WUC, 0); +- } +- if(iegbe_init_hw(&adapter->hw)) { ++ ++ if (iegbe_init_hw(hw)) + DPRINTK(PROBE, ERR, "Hardware Error\n"); +- } +-#ifdef NETIF_F_HW_VLAN_TX + iegbe_update_mng_vlan(adapter); +-#endif ++ ++ /* if (adapter->hwflags & HWFLAGS_PHY_PWR_BIT) { */ ++ if (hw->mac_type >= iegbe_82544 && ++ hw->mac_type <= iegbe_82547_rev_2 && ++ hw->autoneg == 1 && ++ hw->autoneg_advertised == ADVERTISE_1000_FULL) { ++ u32 ctrl = E1000_READ_REG(&adapter->hw, CTRL); ++ /* clear phy power management bit if we are in gig only mode, ++ * which if enabled will attempt negotiation to 100Mb, which ++ * can cause a loss of link at power off or driver unload */ ++ ctrl &= ~E1000_CTRL_SWDPIN3; ++ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); ++ } ++ + /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ + E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE); + +- iegbe_reset_adaptive(&adapter->hw); +- iegbe_phy_get_info(&adapter->hw, &adapter->phy_info); +- if(adapter->en_mng_pt) { +- manc = E1000_READ_REG(&adapter->hw, MANC); +- manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST); +- E1000_WRITE_REG(&adapter->hw, MANC, manc); ++ iegbe_reset_adaptive(hw); ++ iegbe_phy_get_info(hw, &adapter->phy_info); ++ ++ if (!adapter->smart_power_down && ++ (hw->mac_type == iegbe_82571 || ++ hw->mac_type == iegbe_82572)) { ++ u16 phy_data = 0; ++ /* speed up time to link by disabling smart power down, ignore ++ * the return value of this function because there is nothing ++ * different we would do if it failed */ ++ iegbe_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, ++ &phy_data); ++ phy_data &= ~IGP02E1000_PM_SPD; ++ iegbe_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, ++ phy_data); ++ } ++ ++} ++ ++/** ++ * Dump the eeprom for users having checksum issues ++ **/ ++static void iegbe_dump_eeprom(struct iegbe_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct ethtool_eeprom eeprom; ++ const struct ethtool_ops *ops = netdev->ethtool_ops; ++ u8 *data; ++ int i; ++ u16 csum_old, csum_new = 0; ++ ++ eeprom.len = ops->get_eeprom_len(netdev); ++ eeprom.offset = 0; ++ ++ data = kmalloc(eeprom.len, GFP_KERNEL); ++ if (!data) { ++ printk(KERN_ERR "Unable to allocate memory to dump EEPROM" ++ " data\n"); ++ return; + } ++ ++ ops->get_eeprom(netdev, &eeprom, data); ++ ++ csum_old = (data[EEPROM_CHECKSUM_REG * 2]) + ++ (data[EEPROM_CHECKSUM_REG * 2 + 1] << 8); ++ for (i = 0; i < EEPROM_CHECKSUM_REG * 2; i += 2) ++ csum_new += data[i] + (data[i + 1] << 8); ++ csum_new = EEPROM_SUM - csum_new; ++ ++ printk(KERN_ERR "/*********************/\n"); ++ printk(KERN_ERR "Current EEPROM Checksum : 0x%04x\n", csum_old); ++ printk(KERN_ERR "Calculated : 0x%04x\n", csum_new); ++ ++ printk(KERN_ERR "Offset Values\n"); ++ printk(KERN_ERR "======== ======\n"); ++ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, data, 128, 0); ++ ++ printk(KERN_ERR "Include this output when contacting your support " ++ "provider.\n"); ++ printk(KERN_ERR "This is not a software error! Something bad " ++ "happened to your hardware or\n"); ++ printk(KERN_ERR "EEPROM image. Ignoring this " ++ "problem could result in further problems,\n"); ++ printk(KERN_ERR "possibly loss of data, corruption or system hangs!\n"); ++ printk(KERN_ERR "The MAC Address will be reset to 00:00:00:00:00:00, " ++ "which is invalid\n"); ++ printk(KERN_ERR "and requires you to set the proper MAC " ++ "address manually before continuing\n"); ++ printk(KERN_ERR "to enable this network device.\n"); ++ printk(KERN_ERR "Please inspect the EEPROM dump and report the issue " ++ "to your hardware vendor\n"); ++ printk(KERN_ERR "or Intel Customer Support.\n"); ++ printk(KERN_ERR "/*********************/\n"); ++ ++ kfree(data); + } + + /** +@@ -721,184 +735,166 @@ iegbe_reset(struct iegbe_adapter *adapte + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ +- +-static int __devinit +-iegbe_probe(struct pci_dev *pdev, ++static int __devinit iegbe_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { +- struct net_device *netdev; +- struct iegbe_adapter *adapter; +- unsigned long mmio_start, mmio_len; +- uint32_t ctrl_ext; +- uint32_t swsm; ++ struct net_device *netdev; ++ struct iegbe_adapter *adapter; ++ struct iegbe_hw *hw; + + static int cards_found = 0; ++ int i, err, pci_using_dac; ++ u16 eeprom_data = 0; ++ u16 eeprom_apme_mask = E1000_EEPROM_APME; ++ int bars; ++ DECLARE_MAC_BUF(mac); + +- int i, err, pci_using_dac; +- uint16_t eeprom_data = 0; +- uint16_t eeprom_apme_mask = E1000_EEPROM_APME; ++ bars = pci_select_bars(pdev, IORESOURCE_MEM); ++ err = pci_enable_device(pdev); + ++ if (err) ++ return err; + +- if((err = pci_enable_device(pdev))) { +- return err; +- } +- if(!(err = pci_set_dma_mask(pdev, PCI_DMA_64BIT))) { ++ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && ++ !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { + pci_using_dac = 1; +- } else { +- if((err = pci_set_dma_mask(pdev, PCI_DMA_32BIT))) { +- E1000_ERR("No usable DMA configuration, aborting\n"); +- return err; +- } ++ } else { ++ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); ++ if (err) { ++ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); ++ if (err) { ++ E1000_ERR("No usable DMA configuration, " ++ "aborting\n"); ++ goto err_dma; ++ } ++ } + pci_using_dac = 0; +- } +- +- if((err = pci_request_regions(pdev, iegbe_driver_name))) { +- return err; + } +- pci_set_master(pdev); + +- netdev = alloc_etherdev(sizeof(struct iegbe_adapter)); +- if(!netdev) { +- err = -ENOMEM; +- goto err_alloc_etherdev; +- } ++ err = pci_request_selected_regions(pdev, bars, iegbe_driver_name); ++ if (err) ++ goto err_pci_reg; ++ ++ pci_set_master(pdev); ++ ++ err = -ENOMEM; ++ netdev = alloc_etherdev(sizeof(struct iegbe_adapter)); ++ if (!netdev) ++ goto err_alloc_etherdev; + +- SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + +- pci_set_drvdata(pdev, netdev); +- adapter = netdev_priv(netdev); +- adapter->netdev = netdev; +- adapter->pdev = pdev; +- adapter->hw.back = adapter; +- adapter->msg_enable = (0x1 << debug) - 0x1; +- +- mmio_start = pci_resource_start(pdev, BAR_0); +- mmio_len = pci_resource_len(pdev, BAR_0); +- +- adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); +- if(!adapter->hw.hw_addr) { +- err = -EIO; +- goto err_ioremap; +- } +- +- for(i = BAR_1; i <= BAR_5; i++) { +- if(pci_resource_len(pdev, i) == 0) { +- continue; +- } +- if(pci_resource_flags(pdev, i) & IORESOURCE_IO) { +- adapter->hw.io_base = pci_resource_start(pdev, i); +- break; +- } +- } +- +- netdev->open = &iegbe_open; +- netdev->stop = &iegbe_close; +- netdev->hard_start_xmit = &iegbe_xmit_frame; +- netdev->get_stats = &iegbe_get_stats; +- netdev->set_multicast_list = &iegbe_set_multi; ++ pci_set_drvdata(pdev, netdev); ++ adapter = netdev_priv(netdev); ++ adapter->netdev = netdev; ++ adapter->pdev = pdev; ++ adapter->msg_enable = (1 << debug) - 1; ++ adapter->bars = bars; ++ ++ hw = &adapter->hw; ++ hw->back = adapter; ++ ++ err = -EIO; ++ hw->hw_addr = ioremap(pci_resource_start(pdev, BAR_0), ++ pci_resource_len(pdev, BAR_0)); ++ if (!hw->hw_addr) ++ goto err_ioremap; ++ ++ netdev->open = &iegbe_open; ++ netdev->stop = &iegbe_close; ++ netdev->hard_start_xmit = &iegbe_xmit_frame; ++ netdev->get_stats = &iegbe_get_stats; ++ netdev->set_rx_mode = &iegbe_set_rx_mode; + netdev->set_mac_address = &iegbe_set_mac; +- netdev->change_mtu = &iegbe_change_mtu; +- netdev->do_ioctl = &iegbe_ioctl; ++ netdev->change_mtu = &iegbe_change_mtu; ++ netdev->do_ioctl = &iegbe_ioctl; + set_ethtool_ops(netdev); +-#ifdef HAVE_TX_TIMEOUT +- netdev->tx_timeout = &iegbe_tx_timeout; +- netdev->watchdog_timeo = 0x5 * HZ; +-#endif +-#ifdef CONFIG_E1000_NAPI +- netdev->poll = &iegbe_clean; +- netdev->weight = 0x40; +-#endif +-#ifdef NETIF_F_HW_VLAN_TX +- netdev->vlan_rx_register = iegbe_vlan_rx_register; +- netdev->vlan_rx_add_vid = iegbe_vlan_rx_add_vid; +- netdev->vlan_rx_kill_vid = iegbe_vlan_rx_kill_vid; +-#endif ++ netdev->tx_timeout = &iegbe_tx_timeout; ++ netdev->watchdog_timeo = 5 * HZ; ++ netif_napi_add(netdev, &adapter->napi, iegbe_clean, 64); ++ netdev->vlan_rx_register = iegbe_vlan_rx_register; ++ netdev->vlan_rx_add_vid = iegbe_vlan_rx_add_vid; ++ netdev->vlan_rx_kill_vid = iegbe_vlan_rx_kill_vid; + #ifdef CONFIG_NET_POLL_CONTROLLER +- netdev->poll_controller = iegbe_netpoll; ++ netdev->poll_controller = iegbe_netpoll; + #endif +- strcpy(netdev->name, pci_name(pdev)); ++ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); + +- netdev->mem_start = mmio_start; +- netdev->mem_end = mmio_start + mmio_len; +- netdev->base_addr = adapter->hw.io_base; + +- adapter->bd_number = cards_found; ++ adapter->bd_number = cards_found; + +- /* setup the private structure */ ++ /* setup the private structure */ + +- if((err = iegbe_sw_init(adapter))) { +- goto err_sw_init; +- } +- if((err = iegbe_check_phy_reset_block(&adapter->hw))) { +- DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n"); +- } +-#ifdef MAX_SKB_FRAGS +- if(adapter->hw.mac_type >= iegbe_82543) { +-#ifdef NETIF_F_HW_VLAN_TX +- netdev->features = NETIF_F_SG | +- NETIF_F_HW_CSUM | +- NETIF_F_HW_VLAN_TX | +- NETIF_F_HW_VLAN_RX | +- NETIF_F_HW_VLAN_FILTER; +-#else +- netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM; +-#endif +- } ++ err = iegbe_sw_init(adapter); ++ if (err) ++ goto err_sw_init; ++ err = -EIO; ++ if (iegbe_check_phy_reset_block(hw)) ++ DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n"); + +-#ifdef NETIF_F_TSO +- if((adapter->hw.mac_type >= iegbe_82544) && +- (adapter->hw.mac_type != iegbe_82547)) { +- netdev->features |= NETIF_F_TSO; +- } +-#ifdef NETIF_F_TSO_IPV6 +- if(adapter->hw.mac_type > iegbe_82547_rev_2) { +- netdev->features |= NETIF_F_TSO_IPV6; +- } +-#endif +-#endif +- if(pci_using_dac) { +- netdev->features |= NETIF_F_HIGHDMA; ++ if (hw->mac_type >= iegbe_82543) { ++ netdev->features = NETIF_F_SG | ++ NETIF_F_HW_CSUM | ++ NETIF_F_HW_VLAN_TX | ++ NETIF_F_HW_VLAN_RX | ++ NETIF_F_HW_VLAN_FILTER; + } +-#endif +-#ifdef NETIF_F_LLTX +- netdev->features |= NETIF_F_LLTX; +-#endif + +- adapter->en_mng_pt = iegbe_enable_mng_pass_thru(&adapter->hw); ++ if ((hw->mac_type >= iegbe_82544) && ++ (hw->mac_type != iegbe_82547)) ++ netdev->features |= NETIF_F_TSO; + +- /* before reading the EEPROM, reset the controller to +- * put the device in a known good starting state */ ++ if (hw->mac_type > iegbe_82547_rev_2) ++ netdev->features |= NETIF_F_TSO6; ++ if (pci_using_dac) ++ netdev->features |= NETIF_F_HIGHDMA; ++ ++ netdev->features |= NETIF_F_LLTX; + +- iegbe_reset_hw(&adapter->hw); ++ adapter->en_mng_pt = iegbe_enable_mng_pass_thru(hw); + +- /* make sure the EEPROM is good */ +- if(iegbe_validate_eeprom_checksum(&adapter->hw) < 0) { +- DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n"); +- err = -EIO; ++ /* initialize eeprom parameters */ ++ ++ if (iegbe_init_eeprom_params(hw)) { ++ E1000_ERR("EEPROM initialization failed\n"); + goto err_eeprom; + } + +- /* copy the MAC address out of the EEPROM */ ++ /* before reading the EEPROM, reset the controller to ++ * put the device in a known good starting state */ + +- if(iegbe_read_mac_addr(&adapter->hw)) { +- DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); +- } +- memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); ++ iegbe_reset_hw(hw); + +- if(!is_valid_ether_addr(netdev->dev_addr)) { +- DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); +- err = -EIO; +- goto err_eeprom; +- } ++ /* make sure the EEPROM is good */ ++ if (iegbe_validate_eeprom_checksum(hw) < 0) { ++ DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n"); ++ iegbe_dump_eeprom(adapter); ++ /* ++ * set MAC address to all zeroes to invalidate and temporary ++ * disable this device for the user. This blocks regular ++ * traffic while still permitting ethtool ioctls from reaching ++ * the hardware as well as allowing the user to run the ++ * interface after manually setting a hw addr using ++ * `ip set address` ++ */ ++ memset(hw->mac_addr, 0, netdev->addr_len); ++ } else { ++ /* copy the MAC address out of the EEPROM */ ++ if (iegbe_read_mac_addr(hw)) ++ DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); ++ } ++ /* don't block initalization here due to bad MAC address */ ++ memcpy(netdev->dev_addr, hw->mac_addr, netdev->addr_len); ++ memcpy(netdev->perm_addr, hw->mac_addr, netdev->addr_len); + +- iegbe_read_part_num(&adapter->hw, &(adapter->part_num)); ++ if (!is_valid_ether_addr(netdev->perm_addr)) ++ DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); + +- iegbe_get_bus_info(&adapter->hw); ++ iegbe_get_bus_info(hw); + + init_timer(&adapter->tx_fifo_stall_timer); + adapter->tx_fifo_stall_timer.function = &iegbe_82547_tx_fifo_stall; +- adapter->tx_fifo_stall_timer.data = (unsigned long) adapter; ++ adapter->tx_fifo_stall_timer.data = (unsigned long)adapter; + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &iegbe_watchdog; +@@ -906,75 +902,50 @@ iegbe_probe(struct pci_dev *pdev, + + init_timer(&adapter->phy_info_timer); + adapter->phy_info_timer.function = &iegbe_update_phy_info; +- adapter->phy_info_timer.data = (unsigned long) adapter; +- +- INIT_WORK(&adapter->tx_timeout_task, +- (void (*)(void *))iegbe_tx_timeout_task, netdev); ++ adapter->phy_info_timer.data = (unsigned long)adapter; + +- /* we're going to reset, so assume we have no link for now */ +- +- netif_carrier_off(netdev); +- netif_stop_queue(netdev); ++ INIT_WORK(&adapter->reset_task, iegbe_reset_task); + +- iegbe_check_options(adapter); ++ iegbe_check_options(adapter); + +- /* Initial Wake on LAN setting +- * If APM wake is enabled in the EEPROM, +- * enable the ACPI Magic Packet filter +- */ ++ /* Initial Wake on LAN setting ++ * If APM wake is enabled in the EEPROM, ++ * enable the ACPI Magic Packet filter ++ */ + +- switch(adapter->hw.mac_type) { +- case iegbe_82542_rev2_0: +- case iegbe_82542_rev2_1: +- case iegbe_82543: +- break; +- case iegbe_82544: +- iegbe_read_eeprom(&adapter->hw, +- EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data); +- eeprom_apme_mask = E1000_EEPROM_82544_APM; +- break; ++ switch(adapter->hw.mac_type) { ++ case iegbe_82542_rev2_0: ++ case iegbe_82542_rev2_1: ++ case iegbe_82543: ++ break; ++ case iegbe_82544: ++ iegbe_read_eeprom(&adapter->hw, ++ EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data); ++ eeprom_apme_mask = E1000_EEPROM_82544_APM; ++ break; + case iegbe_icp_xxxx: +- iegbe_read_eeprom(&adapter->hw, +- EEPROM_INIT_CONTROL3_ICP_xxxx(adapter->bd_number), +- 1, &eeprom_data); +- eeprom_apme_mask = EEPROM_CTRL3_APME_ICP_xxxx; +- break; +- case iegbe_82546: +- case iegbe_82546_rev_3: +- if((E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1) +- && (adapter->hw.media_type == iegbe_media_type_copper)) { +- iegbe_read_eeprom(&adapter->hw, +- EEPROM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); +- break; +- } +- /* Fall Through */ +- default: +- iegbe_read_eeprom(&adapter->hw, +- EEPROM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); +- break; +- } ++ iegbe_read_eeprom(&adapter->hw, ++ EEPROM_INIT_CONTROL3_ICP_xxxx(adapter->bd_number), ++ 1, &eeprom_data); ++ eeprom_apme_mask = EEPROM_CTRL3_APME_ICP_xxxx; ++ break; ++ case iegbe_82546: ++ case iegbe_82546_rev_3: ++ if((E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1) ++ && (adapter->hw.media_type == iegbe_media_type_copper)) { ++ iegbe_read_eeprom(&adapter->hw, ++ EEPROM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); ++ break; ++ } ++ /* Fall Through */ ++ default: ++ iegbe_read_eeprom(&adapter->hw, ++ EEPROM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); ++ break; ++ } + if(eeprom_data & eeprom_apme_mask) { +- adapter->wol |= E1000_WUFC_MAG; ++ adapter->wol |= E1000_WUFC_MAG; + } +- /* reset the hardware with the new settings */ +- iegbe_reset(adapter); +- +- /* Let firmware know the driver has taken over */ +- switch(adapter->hw.mac_type) { +- case iegbe_82571: +- case iegbe_82572: +- ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); +- E1000_WRITE_REG(&adapter->hw, CTRL_EXT, +- ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); +- break; +- case iegbe_82573: +- swsm = E1000_READ_REG(&adapter->hw, SWSM); +- E1000_WRITE_REG(&adapter->hw, SWSM, +- swsm | E1000_SWSM_DRV_LOAD); +- break; +- default: +- break; +- } + + /* The ICP_xxxx device has multiple, duplicate interrupt + * registers, so disable all but the first one +@@ -987,24 +958,40 @@ iegbe_probe(struct pci_dev *pdev, + E1000_WRITE_REG(&adapter->hw, IMC2, ~0UL); + } + +- strcpy(netdev->name, "eth%d"); +- if((err = register_netdev(netdev))) { +- goto err_register; +- } ++ iegbe_reset(adapter); ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ strcpy(netdev->name, "eth%d"); ++ err = register_netdev(netdev); ++ if (err) ++ goto err_register; ++ + DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n"); + +- cards_found++; +- return 0; ++ cards_found++; ++ return 0; + + err_register: +-err_sw_init: + err_eeprom: +- iounmap(adapter->hw.hw_addr); ++ if (!iegbe_check_phy_reset_block(hw)) ++ iegbe_phy_hw_reset(hw); ++ if (hw->flash_address) ++ iounmap(hw->flash_address); ++ for (i = 0; i < adapter->num_rx_queues; i++) ++ dev_put(&adapter->polling_netdev[i]); ++ kfree(adapter->tx_ring); ++ kfree(adapter->rx_ring); ++ kfree(adapter->polling_netdev); ++err_sw_init: ++ iounmap(hw->hw_addr); + err_ioremap: +- free_netdev(netdev); ++ free_netdev(netdev); + err_alloc_etherdev: +- pci_release_regions(pdev); +- return err; ++ pci_release_selected_regions(pdev, bars); ++err_pci_reg: ++err_dma: ++ pci_disable_device(pdev); ++ return err; + } + + /** +@@ -1020,64 +1007,36 @@ err_alloc_etherdev: + static void __devexit + iegbe_remove(struct pci_dev *pdev) + { +- struct net_device *netdev = pci_get_drvdata(pdev); +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- uint32_t ctrl_ext; +- uint32_t manc, swsm; +-#ifdef CONFIG_E1000_NAPI +- int i; +-#endif +- +- if(adapter->hw.mac_type >= iegbe_82540 +- && adapter->hw.mac_type != iegbe_icp_xxxx +- && adapter->hw.media_type == iegbe_media_type_copper) { +- manc = E1000_READ_REG(&adapter->hw, MANC); +- if(manc & E1000_MANC_SMBUS_EN) { +- manc |= E1000_MANC_ARP_EN; +- E1000_WRITE_REG(&adapter->hw, MANC, manc); +- } +- } +- +- switch(adapter->hw.mac_type) { +- case iegbe_82571: +- case iegbe_82572: +- ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); +- E1000_WRITE_REG(&adapter->hw, CTRL_EXT, +- ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); +- break; +- case iegbe_82573: +- swsm = E1000_READ_REG(&adapter->hw, SWSM); +- E1000_WRITE_REG(&adapter->hw, SWSM, +- swsm & ~E1000_SWSM_DRV_LOAD); +- break; +- +- default: +- break; +- } ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ uint32_t manc; ++ int i; ++ ++ if(adapter->hw.mac_type >= iegbe_82540 ++ && adapter->hw.mac_type != iegbe_icp_xxxx ++ && adapter->hw.media_type == iegbe_media_type_copper) { ++ manc = E1000_READ_REG(&adapter->hw, MANC); ++ if(manc & E1000_MANC_SMBUS_EN) { ++ manc |= E1000_MANC_ARP_EN; ++ E1000_WRITE_REG(&adapter->hw, MANC, manc); ++ } ++ } + +- unregister_netdev(netdev); +-#ifdef CONFIG_E1000_NAPI +- for (i = 0; i < adapter->num_queues; i++) ++ unregister_netdev(netdev); ++ for (i = 0x0; i < adapter->num_rx_queues; i++) + dev_put(&adapter->polling_netdev[i]); +-#endif + + if(!iegbe_check_phy_reset_block(&adapter->hw)) { +- iegbe_phy_hw_reset(&adapter->hw); ++ iegbe_phy_hw_reset(&adapter->hw); + } +- kfree(adapter->tx_ring); +- kfree(adapter->rx_ring); +-#ifdef CONFIG_E1000_NAPI +- kfree(adapter->polling_netdev); +-#endif ++ kfree(adapter->tx_ring); ++ kfree(adapter->rx_ring); ++ kfree(adapter->polling_netdev); + +- iounmap(adapter->hw.hw_addr); +- pci_release_regions(pdev); ++ iounmap(adapter->hw.hw_addr); ++ pci_release_regions(pdev); + +-#ifdef CONFIG_E1000_MQ +- free_percpu(adapter->cpu_netdev); +- free_percpu(adapter->cpu_tx_ring); +-#endif +- free_netdev(netdev); ++ free_netdev(netdev); + } + + /** +@@ -1092,118 +1051,78 @@ iegbe_remove(struct pci_dev *pdev) + static int __devinit + iegbe_sw_init(struct iegbe_adapter *adapter) + { +- struct iegbe_hw *hw = &adapter->hw; +- struct net_device *netdev = adapter->netdev; +- struct pci_dev *pdev = adapter->pdev; +-#ifdef CONFIG_E1000_NAPI +- int i; +-#endif ++ struct iegbe_hw *hw = &adapter->hw; ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ int i; + +- /* PCI config space info */ ++ /* PCI config space info */ + +- hw->vendor_id = pdev->vendor; +- hw->device_id = pdev->device; +- hw->subsystem_vendor_id = pdev->subsystem_vendor; +- hw->subsystem_id = pdev->subsystem_device; ++ hw->vendor_id = pdev->vendor; ++ hw->device_id = pdev->device; ++ hw->subsystem_vendor_id = pdev->subsystem_vendor; ++ hw->subsystem_id = pdev->subsystem_device; + +- pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); ++ pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + +- pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word); ++ pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word); + +- adapter->rx_buffer_len = E1000_RXBUFFER_2048; +- adapter->rx_ps_bsize0 = E1000_RXBUFFER_256; +- hw->max_frame_size = netdev->mtu + +- ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; +- hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE; ++ adapter->rx_buffer_len = E1000_RXBUFFER_2048; ++ adapter->rx_ps_bsize0 = E1000_RXBUFFER_256; ++ hw->max_frame_size = netdev->mtu + ++ ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; ++ hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE; + +- /* identify the MAC */ ++ /* identify the MAC */ + +- if(iegbe_set_mac_type(hw)) { ++ if (iegbe_set_mac_type(hw)) { + DPRINTK(PROBE, ERR, "Unknown MAC Type\n"); + return -EIO; + } + +- /* initialize eeprom parameters */ +- +- if(iegbe_init_eeprom_params(hw)) { +- E1000_ERR("EEPROM initialization failed\n"); +- return -EIO; +- } +- +- switch(hw->mac_type) { +- default: +- break; +- case iegbe_82541: +- case iegbe_82547: +- case iegbe_82541_rev_2: +- case iegbe_82547_rev_2: +- hw->phy_init_script = 0x1; +- break; +- } +- +- iegbe_set_media_type(hw); ++ iegbe_set_media_type(hw); + +- hw->wait_autoneg_complete = FALSE; +- hw->tbi_compatibility_en = TRUE; +- hw->adaptive_ifs = TRUE; ++ hw->wait_autoneg_complete = FALSE; ++ hw->tbi_compatibility_en = TRUE; ++ hw->adaptive_ifs = TRUE; + +- /* Copper options */ ++ /* Copper options */ + +- if(hw->media_type == iegbe_media_type_copper ++ if(hw->media_type == iegbe_media_type_copper + || (hw->media_type == iegbe_media_type_oem + && iegbe_oem_phy_is_copper(&adapter->hw))) { +- hw->mdix = AUTO_ALL_MODES; +- hw->disable_polarity_correction = FALSE; +- hw->master_slave = E1000_MASTER_SLAVE; +- } ++ hw->mdix = AUTO_ALL_MODES; ++ hw->disable_polarity_correction = FALSE; ++ hw->master_slave = E1000_MASTER_SLAVE; ++ } + +-#ifdef CONFIG_E1000_MQ +- /* Number of supported queues */ +- switch (hw->mac_type) { +- case iegbe_82571: +- case iegbe_82572: +- adapter->num_queues = 0x2; +- break; +- default: +- adapter->num_queues = 0x1; +- break; +- } +- adapter->num_queues = min(adapter->num_queues, num_online_cpus()); +-#else +- adapter->num_queues = 0x1; +-#endif ++ adapter->num_tx_queues = 0x1; ++ adapter->num_rx_queues = 0x1; + + if (iegbe_alloc_queues(adapter)) { + DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n"); + return -ENOMEM; + } + +-#ifdef CONFIG_E1000_NAPI +- for (i = 0; i < adapter->num_queues; i++) { ++ for (i = 0; i < adapter->num_rx_queues; i++) { + adapter->polling_netdev[i].priv = adapter; +- adapter->polling_netdev[i].poll = &iegbe_clean; +- adapter->polling_netdev[i].weight = 0x40; + dev_hold(&adapter->polling_netdev[i]); + set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); + } +-#endif +- +-#ifdef CONFIG_E1000_MQ +- iegbe_setup_queue_mapping(adapter); +-#endif ++ spin_lock_init(&adapter->tx_queue_lock); + + /* +- * for ICP_XXXX style controllers, it is necessary to keep +- * track of the last known state of the link to determine if +- * the link experienced a change in state when iegbe_watchdog +- * fires +- */ +- adapter->hw.icp_xxxx_is_link_up = FALSE; ++ * for ICP_XXXX style controllers, it is necessary to keep ++ * track of the last known state of the link to determine if ++ * the link experienced a change in state when iegbe_watchdog ++ * fires ++ */ ++ adapter->hw.icp_xxxx_is_link_up = FALSE; + +- atomic_set(&adapter->irq_sem, 1); +- spin_lock_init(&adapter->stats_lock); ++ spin_lock_init(&adapter->stats_lock); + +- return 0; ++ set_bit(__E1000_DOWN, &adapter->flags); ++ return 0x0; + } + + /** +@@ -1218,71 +1137,31 @@ iegbe_sw_init(struct iegbe_adapter *adap + static int __devinit + iegbe_alloc_queues(struct iegbe_adapter *adapter) + { +- int size; + +- size = sizeof(struct iegbe_tx_ring) * adapter->num_queues; +- adapter->tx_ring = kmalloc(size, GFP_KERNEL); +- if (!adapter->tx_ring){ ++ ++ adapter->tx_ring = kcalloc(adapter->num_tx_queues, ++ sizeof(struct iegbe_tx_ring), GFP_KERNEL); ++ if (!adapter->tx_ring) + return -ENOMEM; +- } +- memset(adapter->tx_ring, 0, size); + +- size = sizeof(struct iegbe_rx_ring) * adapter->num_queues; +- adapter->rx_ring = kmalloc(size, GFP_KERNEL); ++ adapter->rx_ring = kcalloc(adapter->num_rx_queues, ++ sizeof(struct iegbe_rx_ring), GFP_KERNEL); + if (!adapter->rx_ring) { + kfree(adapter->tx_ring); + return -ENOMEM; + } +- memset(adapter->rx_ring, 0, size); + +-#ifdef CONFIG_E1000_NAPI +- size = sizeof(struct net_device) * adapter->num_queues; +- adapter->polling_netdev = kmalloc(size, GFP_KERNEL); ++ adapter->polling_netdev = kcalloc(adapter->num_rx_queues, ++ sizeof(struct net_device), ++ GFP_KERNEL); + if (!adapter->polling_netdev) { + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + return -ENOMEM; + } +- memset(adapter->polling_netdev, 0, size); +-#endif +- +- return E1000_SUCCESS; +-} + +-#ifdef CONFIG_E1000_MQ +-static void __devinit +-iegbe_setup_queue_mapping(struct iegbe_adapter *adapter) +-{ +- int i, cpu; +- +- adapter->rx_sched_call_data.func = iegbe_rx_schedule; +- adapter->rx_sched_call_data.info = adapter->netdev; +- cpus_clear(adapter->rx_sched_call_data.cpumask); +- +- adapter->cpu_netdev = alloc_percpu(struct net_device *); +- adapter->cpu_tx_ring = alloc_percpu(struct iegbe_tx_ring *); +- +- lock_cpu_hotplug(); +- i = 0; +- for_each_online_cpu(cpu) { +- *per_cpu_ptr(adapter->cpu_tx_ring, cpu) = +- &adapter->tx_ring[i % adapter->num_queues]; +- /* This is incomplete because we'd like to assign separate +- * physical cpus to these netdev polling structures and +- * avoid saturating a subset of cpus. +- */ +- if (i < adapter->num_queues) { +- *per_cpu_ptr(adapter->cpu_netdev, cpu) = +- &adapter->polling_netdev[i]; +- adapter->cpu_for_queue[i] = cpu; +- } else { +- *per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL; +- } +- i++; +- } +- unlock_cpu_hotplug(); ++ return E1000_SUCCESS; + } +-#endif + + /** + * iegbe_open - Called when a network interface is made active +@@ -1300,40 +1179,62 @@ iegbe_setup_queue_mapping(struct iegbe_a + static int + iegbe_open(struct net_device *netdev) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- int err; ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct iegbe_hw *hw = &adapter->hw; ++ int err; ++ + ++ /* allocate receive descriptors */ ++ if (test_bit(__E1000_TESTING, &adapter->flags)) ++ return -EBUSY; + +- /* allocate receive descriptors */ ++ /* allocate transmit descriptors */ ++ err = iegbe_setup_all_tx_resources(adapter); ++ if (err) ++ goto err_setup_tx; + +- if ((err = iegbe_setup_all_rx_resources(adapter))) { ++ err = iegbe_setup_all_rx_resources(adapter); ++ if (err) + goto err_setup_rx; +- } +- /* allocate transmit descriptors */ +- if ((err = iegbe_setup_all_tx_resources(adapter))) { +- goto err_setup_tx; +- } +- if ((err = iegbe_up(adapter))) { +- goto err_up; +- } +-#ifdef NETIF_F_HW_VLAN_TX +- adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; +- if ((adapter->hw.mng_cookie.status & +- E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { +- iegbe_update_mng_vlan(adapter); +- } +-#endif + +- return E1000_SUCCESS; ++ iegbe_power_up_phy(adapter); ++ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; ++ if ((hw->mng_cookie.status & ++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { ++ iegbe_update_mng_vlan(adapter); ++ } ++ ++ /* before we allocate an interrupt, we must be ready to handle it. ++ * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt ++ * as soon as we call pci_request_irq, so we have to setup our ++ * clean_rx handler before we do so. */ ++ iegbe_configure(adapter); ++ err = iegbe_request_irq(adapter); ++ if (err) ++ goto err_req_irq; + +-err_up: +- iegbe_free_all_tx_resources(adapter); +-err_setup_tx: +- iegbe_free_all_rx_resources(adapter); ++ /* From here on the code is the same as iegbe_up() */ ++ clear_bit(__E1000_DOWN, &adapter->flags); ++ ++ napi_enable(&adapter->napi); ++ ++ iegbe_irq_enable(adapter); ++ ++ netif_start_queue(netdev); ++ ++ /* fire a link status change interrupt to start the watchdog */ ++ ++ return E1000_SUCCESS; ++ ++err_req_irq: ++ iegbe_power_down_phy(adapter); ++ iegbe_free_all_rx_resources(adapter); + err_setup_rx: +- iegbe_reset(adapter); ++ iegbe_free_all_tx_resources(adapter); ++err_setup_tx: ++ iegbe_reset(adapter); + +- return err; ++ return err; + } + + /** +@@ -1348,22 +1249,25 @@ err_setup_rx: + * hardware, and all transmit and receive resources are freed. + **/ + +-static int +-iegbe_close(struct net_device *netdev) ++static int iegbe_close(struct net_device *netdev) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- +- iegbe_down(adapter); +- +- iegbe_free_all_tx_resources(adapter); +- iegbe_free_all_rx_resources(adapter); ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct iegbe_hw *hw = &adapter->hw; + +-#ifdef NETIF_F_HW_VLAN_TX +- if((adapter->hw.mng_cookie.status & +- E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { ++ WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags)); ++ iegbe_down(adapter); ++ iegbe_power_down_phy(adapter); ++ iegbe_free_irq(adapter); ++ ++ iegbe_free_all_tx_resources(adapter); ++ iegbe_free_all_rx_resources(adapter); ++ ++ if ((hw->mng_cookie.status & ++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && ++ !(adapter->vlgrp && ++ vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) { + iegbe_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + } +-#endif + return 0; + } + +@@ -1375,19 +1279,19 @@ iegbe_close(struct net_device *netdev) + **/ + static inline boolean_t + iegbe_check_64k_bound(struct iegbe_adapter *adapter, +- void *start, unsigned long len) ++ void *start, unsigned long len) + { +- unsigned long begin = (unsigned long) start; +- unsigned long end = begin + len; ++ unsigned long begin = (unsigned long) start; ++ unsigned long end = begin + len; + +- /* First rev 82545 and 82546 need to not allow any memory +- * write location to cross 64k boundary due to errata 23 */ +- if(adapter->hw.mac_type == iegbe_82545 || +- adapter->hw.mac_type == iegbe_82546) { +- return ((begin ^ (end - 1)) >> 0x10) != 0 ? FALSE : TRUE; +- } ++ /* First rev 82545 and 82546 need to not allow any memory ++ * write location to cross 64k boundary due to errata 23 */ ++ if(adapter->hw.mac_type == iegbe_82545 || ++ adapter->hw.mac_type == iegbe_82546) { ++ return ((begin ^ (end - 1)) >> 0x10) != 0x0 ? FALSE : TRUE; ++ } + +- return TRUE; ++ return TRUE; + } + + /** +@@ -1398,102 +1302,98 @@ iegbe_check_64k_bound(struct iegbe_adapt + * Return 0 on success, negative on failure + **/ + +-int +-iegbe_setup_tx_resources(struct iegbe_adapter *adapter, ++static int iegbe_setup_tx_resources(struct iegbe_adapter *adapter, + struct iegbe_tx_ring *txdr) + { +- struct pci_dev *pdev = adapter->pdev; +- int size; ++ struct pci_dev *pdev = adapter->pdev; ++ int size; + +- size = sizeof(struct iegbe_buffer) * txdr->count; +- txdr->buffer_info = vmalloc(size); +- if (!txdr->buffer_info) { +- DPRINTK(PROBE, ERR, +- "Unable to allocate memory for the transmit descriptor ring\n"); +- return -ENOMEM; +- } ++ size = sizeof(struct iegbe_buffer) * txdr->count; ++ txdr->buffer_info = vmalloc(size); ++ if (!txdr->buffer_info) { ++ DPRINTK(PROBE, ERR, ++ "Unable to allocate memory for the transmit descriptor ring\n"); ++ return -ENOMEM; ++ } + memset(txdr->buffer_info, 0, size); +- memset(&txdr->previous_buffer_info, 0, sizeof(struct iegbe_buffer)); + +- /* round up to nearest 4K */ ++ /* round up to nearest 4K */ + +- txdr->size = txdr->count * sizeof(struct iegbe_tx_desc); +- E1000_ROUNDUP(txdr->size, 0x1000); ++ txdr->size = txdr->count * sizeof(struct iegbe_tx_desc); ++ txdr->size = ALIGN(txdr->size, 4096); + +- txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); +- if (!txdr->desc) { ++ txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); ++ if (!txdr->desc) { + setup_tx_desc_die: +- vfree(txdr->buffer_info); +- DPRINTK(PROBE, ERR, +- "Unable to allocate memory for the transmit descriptor ring\n"); +- return -ENOMEM; +- } +- +- /* Fix for errata 23, can't cross 64kB boundary */ +- if (!iegbe_check_64k_bound(adapter, txdr->desc, txdr->size)) { +- void *olddesc = txdr->desc; +- dma_addr_t olddma = txdr->dma; +- DPRINTK(TX_ERR, ERR, "txdr align check failed: %u bytes " +- "at %p\n", txdr->size, txdr->desc); +- /* Try again, without freeing the previous */ +- txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); +- /* Failed allocation, critical failure */ +- if (!txdr->desc) { +- pci_free_consistent(pdev, txdr->size, olddesc, olddma); +- goto setup_tx_desc_die; +- } ++ vfree(txdr->buffer_info); ++ DPRINTK(PROBE, ERR, ++ "Unable to allocate memory for the transmit descriptor ring\n"); ++ return -ENOMEM; ++ } ++ ++ /* Fix for errata 23, can't cross 64kB boundary */ ++ if (!iegbe_check_64k_bound(adapter, txdr->desc, txdr->size)) { ++ void *olddesc = txdr->desc; ++ dma_addr_t olddma = txdr->dma; ++ DPRINTK(TX_ERR, ERR, "txdr align check failed: %u bytes " ++ "at %p\n", txdr->size, txdr->desc); ++ /* Try again, without freeing the previous */ ++ txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); ++ /* Failed allocation, critical failure */ ++ if (!txdr->desc) { ++ pci_free_consistent(pdev, txdr->size, olddesc, olddma); ++ goto setup_tx_desc_die; ++ } + +- if (!iegbe_check_64k_bound(adapter, txdr->desc, txdr->size)) { +- /* give up */ +- pci_free_consistent(pdev, txdr->size, txdr->desc, +- txdr->dma); +- pci_free_consistent(pdev, txdr->size, olddesc, olddma); +- DPRINTK(PROBE, ERR, +- "Unable to allocate aligned memory " +- "for the transmit descriptor ring\n"); +- vfree(txdr->buffer_info); +- return -ENOMEM; +- } else { +- /* Free old allocation, new allocation was successful */ +- pci_free_consistent(pdev, txdr->size, olddesc, olddma); +- } +- } ++ if (!iegbe_check_64k_bound(adapter, txdr->desc, txdr->size)) { ++ /* give up */ ++ pci_free_consistent(pdev, txdr->size, txdr->desc, ++ txdr->dma); ++ pci_free_consistent(pdev, txdr->size, olddesc, olddma); ++ DPRINTK(PROBE, ERR, ++ "Unable to allocate aligned memory " ++ "for the transmit descriptor ring\n"); ++ vfree(txdr->buffer_info); ++ return -ENOMEM; ++ } else { ++ /* Free old allocation, new allocation was successful */ ++ pci_free_consistent(pdev, txdr->size, olddesc, olddma); ++ } ++ } + memset(txdr->desc, 0, txdr->size); + + txdr->next_to_use = 0; + txdr->next_to_clean = 0; +- spin_lock_init(&txdr->tx_lock); ++ spin_lock_init(&txdr->tx_lock); + + return 0; + } + + /** + * iegbe_setup_all_tx_resources - wrapper to allocate Tx resources +- * (Descriptors) for all queues ++ * (Descriptors) for all queues + * @adapter: board private structure + * +- * If this function returns with an error, then it's possible one or +- * more of the rings is populated (while the rest are not). It is the +- * callers duty to clean those orphaned rings. +- * + * Return 0 on success, negative on failure + **/ + +-int +-iegbe_setup_all_tx_resources(struct iegbe_adapter *adapter) ++int iegbe_setup_all_tx_resources(struct iegbe_adapter *adapter) + { + int i, err = 0; + +- for (i = 0; i < adapter->num_queues; i++) { ++ for (i = 0; i < adapter->num_tx_queues; i++) { + err = iegbe_setup_tx_resources(adapter, &adapter->tx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Tx Queue %u failed\n", i); ++ for (i-- ; i >= 0; i--) ++ iegbe_free_tx_resources(adapter, ++ &adapter->tx_ring[i]); + break; + } + } + +- return err; ++ return err; + } + + /** +@@ -1512,113 +1412,108 @@ iegbe_configure_tx(struct iegbe_adapter + + /* Setup the HW Tx Head and Tail descriptor pointers */ + +- switch (adapter->num_queues) { ++ switch (adapter->num_tx_queues) { + case 0x2: + tdba = adapter->tx_ring[0x1].dma; + tdlen = adapter->tx_ring[0x1].count * +- sizeof(struct iegbe_tx_desc); +- E1000_WRITE_REG(hw, TDBAL1, (tdba & 0x00000000ffffffffULL)); ++ sizeof(struct iegbe_tx_desc); ++ E1000_WRITE_REG(hw, TDBAL1, (tdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, TDBAH1, (tdba >> 0x20)); +- E1000_WRITE_REG(hw, TDLEN1, tdlen); +- E1000_WRITE_REG(hw, TDH1, 0); +- E1000_WRITE_REG(hw, TDT1, 0); ++ E1000_WRITE_REG(hw, TDLEN1, tdlen); ++ E1000_WRITE_REG(hw, TDH1, 0x0); ++ E1000_WRITE_REG(hw, TDT1, 0x0); + adapter->tx_ring[0x1].tdh = E1000_TDH1; + adapter->tx_ring[0x1].tdt = E1000_TDT1; +- /* Fall Through */ ++ /* Fall Through */ + case 0x1: +- default: +- tdba = adapter->tx_ring[0].dma; +- tdlen = adapter->tx_ring[0].count * +- sizeof(struct iegbe_tx_desc); +- E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL)); ++ default: ++ tdba = adapter->tx_ring[0x0].dma; ++ tdlen = adapter->tx_ring[0x0].count * ++ sizeof(struct iegbe_tx_desc); ++ E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, TDBAH, (tdba >> 0x20)); +- E1000_WRITE_REG(hw, TDLEN, tdlen); +- E1000_WRITE_REG(hw, TDH, 0); +- E1000_WRITE_REG(hw, TDT, 0); +- adapter->tx_ring[0].tdh = E1000_TDH; +- adapter->tx_ring[0].tdt = E1000_TDT; +- break; +- } +- +- /* Set the default values for the Tx Inter Packet Gap timer */ +- +- switch (hw->mac_type) { +- case iegbe_82542_rev2_0: +- case iegbe_82542_rev2_1: +- tipg = DEFAULT_82542_TIPG_IPGT; +- tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; +- tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; +- break; +- default: +- switch(hw->media_type) { +- case iegbe_media_type_fiber: +- case iegbe_media_type_internal_serdes: +- tipg = DEFAULT_82543_TIPG_IPGT_FIBER; +- break; +- case iegbe_media_type_copper: +- tipg = DEFAULT_82543_TIPG_IPGT_COPPER; +- break; +- case iegbe_media_type_oem: +- default: ++ E1000_WRITE_REG(hw, TDLEN, tdlen); ++ E1000_WRITE_REG(hw, TDH, 0x0); ++ E1000_WRITE_REG(hw, TDT, 0x0); ++ adapter->tx_ring[0x0].tdh = E1000_TDH; ++ adapter->tx_ring[0x0].tdt = E1000_TDT; ++ break; ++ } ++ ++ /* Set the default values for the Tx Inter Packet Gap timer */ ++ ++ switch (hw->mac_type) { ++ case iegbe_82542_rev2_0: ++ case iegbe_82542_rev2_1: ++ tipg = DEFAULT_82542_TIPG_IPGT; ++ tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; ++ tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; ++ break; ++ default: ++ switch(hw->media_type) { ++ case iegbe_media_type_fiber: ++ case iegbe_media_type_internal_serdes: ++ tipg = DEFAULT_82543_TIPG_IPGT_FIBER; ++ break; ++ case iegbe_media_type_copper: ++ tipg = DEFAULT_82543_TIPG_IPGT_COPPER; ++ break; ++ case iegbe_media_type_oem: ++ default: + tipg = (0xFFFFFFFFUL >> (sizeof(tipg)*0x8 - + E1000_TIPG_IPGR1_SHIFT)) +- & iegbe_oem_get_tipg(&adapter->hw); +- break; +- } +- tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; +- tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; +- } +- E1000_WRITE_REG(hw, TIPG, tipg); ++ & iegbe_oem_get_tipg(&adapter->hw); ++ break; ++ } ++ tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; ++ tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; ++ } ++ E1000_WRITE_REG(hw, TIPG, tipg); + +- /* Set the Tx Interrupt Delay register */ ++ /* Set the Tx Interrupt Delay register */ + +- E1000_WRITE_REG(hw, TIDV, adapter->tx_int_delay); ++ E1000_WRITE_REG(hw, TIDV, adapter->tx_int_delay); + if (hw->mac_type >= iegbe_82540) { +- E1000_WRITE_REG(hw, TADV, adapter->tx_abs_int_delay); ++ E1000_WRITE_REG(hw, TADV, adapter->tx_abs_int_delay); + } +- /* Program the Transmit Control Register */ ++ /* Program the Transmit Control Register */ + +- tctl = E1000_READ_REG(hw, TCTL); ++ tctl = E1000_READ_REG(hw, TCTL); + +- tctl &= ~E1000_TCTL_CT; +- tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | E1000_TCTL_RTLC | +- (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); ++ tctl &= ~E1000_TCTL_CT; ++ tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | E1000_TCTL_RTLC | ++ (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); + +- E1000_WRITE_REG(hw, TCTL, tctl); ++ E1000_WRITE_REG(hw, TCTL, tctl); + +- if (hw->mac_type == iegbe_82571 || hw->mac_type == iegbe_82572) { +- tarc = E1000_READ_REG(hw, TARC0); ++ if (hw->mac_type == iegbe_82571 || hw->mac_type == iegbe_82572) { ++ tarc = E1000_READ_REG(hw, TARC0); + tarc |= ((0x1 << 0x19) | (0x1 << 0x15)); +- E1000_WRITE_REG(hw, TARC0, tarc); +- tarc = E1000_READ_REG(hw, TARC1); ++ E1000_WRITE_REG(hw, TARC0, tarc); ++ tarc = E1000_READ_REG(hw, TARC1); + tarc |= (0x1 << 0x19); + if (tctl & E1000_TCTL_MULR) { + tarc &= ~(0x1 << 0x1c); + } else { + tarc |= (0x1 << 0x1c); + } +- E1000_WRITE_REG(hw, TARC1, tarc); +- } ++ E1000_WRITE_REG(hw, TARC1, tarc); ++ } + +- iegbe_config_collision_dist(hw); ++ iegbe_config_collision_dist(hw); + +- /* Setup Transmit Descriptor Settings for eop descriptor */ +- adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | +- E1000_TXD_CMD_IFCS; ++ /* Setup Transmit Descriptor Settings for eop descriptor */ ++ adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | ++ E1000_TXD_CMD_IFCS; + + if (hw->mac_type < iegbe_82543) { +- adapter->txd_cmd |= E1000_TXD_CMD_RPS; ++ adapter->txd_cmd |= E1000_TXD_CMD_RPS; + } else { +-#ifdef IEGBE_GBE_WORKAROUND +- /* Disable the RS bit in the Tx descriptor */ +- adapter->txd_cmd &= ~E1000_TXD_CMD_RS; +-#else +- adapter->txd_cmd |= E1000_TXD_CMD_RS; +-#endif ++ adapter->txd_cmd |= E1000_TXD_CMD_RS; + } +- /* Cache if we're 82544 running in PCI-X because we'll +- * need this to apply a workaround later in the send path. */ +- if (hw->mac_type == iegbe_82544 && ++ /* Cache if we're 82544 running in PCI-X because we'll ++ * need this to apply a workaround later in the send path. */ ++ if (hw->mac_type == iegbe_82544 && + hw->bus_type == iegbe_bus_type_pcix) { + adapter->pcix_82544 = 0x1; + } +@@ -1632,96 +1527,95 @@ iegbe_configure_tx(struct iegbe_adapter + * Returns 0 on success, negative on failure + **/ + +-int +-iegbe_setup_rx_resources(struct iegbe_adapter *adapter, ++static int iegbe_setup_rx_resources(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rxdr) + { +- struct pci_dev *pdev = adapter->pdev; +- int size, desc_len; +- +- size = sizeof(struct iegbe_buffer) * rxdr->count; +- rxdr->buffer_info = vmalloc(size); +- if (!rxdr->buffer_info) { +- DPRINTK(PROBE, ERR, +- "Unable to allocate memory for the receive descriptor ring\n"); +- return -ENOMEM; +- } +- memset(rxdr->buffer_info, 0, size); +- +- size = sizeof(struct iegbe_ps_page) * rxdr->count; +- rxdr->ps_page = kmalloc(size, GFP_KERNEL); +- if (!rxdr->ps_page) { +- vfree(rxdr->buffer_info); +- DPRINTK(PROBE, ERR, +- "Unable to allocate memory for the receive descriptor ring\n"); +- return -ENOMEM; +- } +- memset(rxdr->ps_page, 0, size); +- +- size = sizeof(struct iegbe_ps_page_dma) * rxdr->count; +- rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL); +- if (!rxdr->ps_page_dma) { +- vfree(rxdr->buffer_info); +- kfree(rxdr->ps_page); +- DPRINTK(PROBE, ERR, +- "Unable to allocate memory for the receive descriptor ring\n"); +- return -ENOMEM; +- } +- memset(rxdr->ps_page_dma, 0, size); ++ struct iegbe_hw *hw = &adapter->hw; ++ struct pci_dev *pdev = adapter->pdev; ++ int size, desc_len; + +- if (adapter->hw.mac_type <= iegbe_82547_rev_2) { +- desc_len = sizeof(struct iegbe_rx_desc); +- } else { +- desc_len = sizeof(union iegbe_rx_desc_packet_split); ++ size = sizeof(struct iegbe_buffer) * rxdr->count; ++ rxdr->buffer_info = vmalloc(size); ++ if (!rxdr->buffer_info) { ++ DPRINTK(PROBE, ERR, ++ "Unable to allocate memory for the receive descriptor ring\n"); ++ return -ENOMEM; + } +- /* Round up to nearest 4K */ +- +- rxdr->size = rxdr->count * desc_len; +- E1000_ROUNDUP(rxdr->size, 0x1000); +- +- rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); ++ memset(rxdr->buffer_info, 0, size); + +- if (!rxdr->desc) { +- DPRINTK(PROBE, ERR, +- "Unable to allocate memory for the receive descriptor ring\n"); ++ rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct iegbe_ps_page), ++ GFP_KERNEL); ++ if (!rxdr->ps_page) { ++ vfree(rxdr->buffer_info); ++ DPRINTK(PROBE, ERR, ++ "Unable to allocate memory for the receive descriptor ring\n"); ++ return -ENOMEM; ++ } ++ ++ rxdr->ps_page_dma = kcalloc(rxdr->count, ++ sizeof(struct iegbe_ps_page_dma), ++ GFP_KERNEL); ++ if (!rxdr->ps_page_dma) { ++ vfree(rxdr->buffer_info); ++ kfree(rxdr->ps_page); ++ DPRINTK(PROBE, ERR, ++ "Unable to allocate memory for the receive descriptor ring\n"); ++ return -ENOMEM; ++ } ++ ++ if (hw->mac_type <= iegbe_82547_rev_2) ++ desc_len = sizeof(struct iegbe_rx_desc); ++ else ++ desc_len = sizeof(union iegbe_rx_desc_packet_split); ++ ++ /* Round up to nearest 4K */ ++ ++ rxdr->size = rxdr->count * desc_len; ++ rxdr->size = ALIGN(rxdr->size, 4096); ++ ++ rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); ++ ++ if (!rxdr->desc) { ++ DPRINTK(PROBE, ERR, ++ "Unable to allocate memory for the receive descriptor ring\n"); + setup_rx_desc_die: +- vfree(rxdr->buffer_info); +- kfree(rxdr->ps_page); +- kfree(rxdr->ps_page_dma); +- return -ENOMEM; +- } +- +- /* Fix for errata 23, can't cross 64kB boundary */ +- if (!iegbe_check_64k_bound(adapter, rxdr->desc, rxdr->size)) { +- void *olddesc = rxdr->desc; +- dma_addr_t olddma = rxdr->dma; +- DPRINTK(RX_ERR, ERR, "rxdr align check failed: %u bytes " +- "at %p\n", rxdr->size, rxdr->desc); +- /* Try again, without freeing the previous */ +- rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); +- /* Failed allocation, critical failure */ +- if (!rxdr->desc) { +- pci_free_consistent(pdev, rxdr->size, olddesc, olddma); +- DPRINTK(PROBE, ERR, +- "Unable to allocate memory " +- "for the receive descriptor ring\n"); +- goto setup_rx_desc_die; +- } ++ vfree(rxdr->buffer_info); ++ kfree(rxdr->ps_page); ++ kfree(rxdr->ps_page_dma); ++ return -ENOMEM; ++ } ++ ++ /* Fix for errata 23, can't cross 64kB boundary */ ++ if (!iegbe_check_64k_bound(adapter, rxdr->desc, rxdr->size)) { ++ void *olddesc = rxdr->desc; ++ dma_addr_t olddma = rxdr->dma; ++ DPRINTK(RX_ERR, ERR, "rxdr align check failed: %u bytes " ++ "at %p\n", rxdr->size, rxdr->desc); ++ /* Try again, without freeing the previous */ ++ rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); ++ /* Failed allocation, critical failure */ ++ if (!rxdr->desc) { ++ pci_free_consistent(pdev, rxdr->size, olddesc, olddma); ++ DPRINTK(PROBE, ERR, ++ "Unable to allocate memory " ++ "for the receive descriptor ring\n"); ++ goto setup_rx_desc_die; ++ } + +- if (!iegbe_check_64k_bound(adapter, rxdr->desc, rxdr->size)) { +- /* give up */ +- pci_free_consistent(pdev, rxdr->size, rxdr->desc, +- rxdr->dma); +- pci_free_consistent(pdev, rxdr->size, olddesc, olddma); +- DPRINTK(PROBE, ERR, +- "Unable to allocate aligned memory " +- "for the receive descriptor ring\n"); +- goto setup_rx_desc_die; +- } else { +- /* Free old allocation, new allocation was successful */ +- pci_free_consistent(pdev, rxdr->size, olddesc, olddma); +- } +- } ++ if (!iegbe_check_64k_bound(adapter, rxdr->desc, rxdr->size)) { ++ /* give up */ ++ pci_free_consistent(pdev, rxdr->size, rxdr->desc, ++ rxdr->dma); ++ pci_free_consistent(pdev, rxdr->size, olddesc, olddma); ++ DPRINTK(PROBE, ERR, ++ "Unable to allocate aligned memory " ++ "for the receive descriptor ring\n"); ++ goto setup_rx_desc_die; ++ } else { ++ /* Free old allocation, new allocation was successful */ ++ pci_free_consistent(pdev, rxdr->size, olddesc, olddma); ++ } ++ } + memset(rxdr->desc, 0, rxdr->size); + + rxdr->next_to_clean = 0; +@@ -1732,7 +1626,7 @@ setup_rx_desc_die: + + /** + * iegbe_setup_all_rx_resources - wrapper to allocate Rx resources +- * (Descriptors) for all queues ++ * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or +@@ -1742,21 +1636,23 @@ setup_rx_desc_die: + * Return 0 on success, negative on failure + **/ + +-int +-iegbe_setup_all_rx_resources(struct iegbe_adapter *adapter) ++int iegbe_setup_all_rx_resources(struct iegbe_adapter *adapter) + { + int i, err = 0; + +- for (i = 0; i < adapter->num_queues; i++) { ++ for (i = 0; i < adapter->num_rx_queues; i++) { + err = iegbe_setup_rx_resources(adapter, &adapter->rx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Rx Queue %u failed\n", i); ++ for (i-- ; i >= 0; i--) ++ iegbe_free_rx_resources(adapter, ++ &adapter->rx_ring[i]); + break; + } + } + +- return err; ++ return err; + } + + /** +@@ -1765,105 +1661,104 @@ iegbe_setup_all_rx_resources(struct iegb + **/ + #define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ + (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) +-static void +-iegbe_setup_rctl(struct iegbe_adapter *adapter) ++static void iegbe_setup_rctl(struct iegbe_adapter *adapter) + { +- uint32_t rctl, rfctl; +- uint32_t psrctl = 0; +-#ifdef CONFIG_E1000_PACKET_SPLIT +- uint32_t pages = 0; +-#endif +- +- rctl = E1000_READ_REG(&adapter->hw, RCTL); +- +- rctl &= ~(0x3 << E1000_RCTL_MO_SHIFT); +- +- rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | +- E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | +- (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); +- +- if(adapter->hw.tbi_compatibility_on == 0x1) { +- rctl |= E1000_RCTL_SBP; +- } else { +- rctl &= ~E1000_RCTL_SBP; +- } +- if(adapter->netdev->mtu <= ETH_DATA_LEN) { +- rctl &= ~E1000_RCTL_LPE; +- } else { +- rctl |= E1000_RCTL_LPE; +- } +- /* Setup buffer sizes */ +- if(adapter->hw.mac_type >= iegbe_82571) { +- /* We can now specify buffers in 1K increments. +- * BSIZE and BSEX are ignored in this case. */ +- rctl |= adapter->rx_buffer_len << 0x11; +- } else { +- rctl &= ~E1000_RCTL_SZ_4096; +- rctl |= E1000_RCTL_BSEX; +- switch (adapter->rx_buffer_len) { +- case E1000_RXBUFFER_2048: +- default: +- rctl |= E1000_RCTL_SZ_2048; ++ struct iegbe_hw *hw = &adapter->hw; ++ u32 rctl, rfctl; ++ u32 psrctl = 0; ++#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT ++ u32 pages = 0; ++#endif ++ ++ rctl = E1000_READ_REG(&adapter->hw, RCTL); ++ ++ rctl &= ~(3 << E1000_RCTL_MO_SHIFT); ++ ++ rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | ++ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | ++ (hw->mc_filter_type << E1000_RCTL_MO_SHIFT); ++ ++ if (hw->tbi_compatibility_on == 1) ++ rctl |= E1000_RCTL_SBP; ++ else ++ rctl &= ~E1000_RCTL_SBP; ++ ++ if (adapter->netdev->mtu <= ETH_DATA_LEN) ++ rctl &= ~E1000_RCTL_LPE; ++ else ++ rctl |= E1000_RCTL_LPE; ++ ++ /* Setup buffer sizes */ ++ /* We can now specify buffers in 1K increments. ++ * BSIZE and BSEX are ignored in this case. */ ++ rctl &= ~E1000_RCTL_SZ_4096; ++ rctl |= E1000_RCTL_BSEX; ++ switch (adapter->rx_buffer_len) { ++ case E1000_RXBUFFER_256: ++ rctl |= E1000_RCTL_SZ_256; + rctl &= ~E1000_RCTL_BSEX; + break; +- case E1000_RXBUFFER_4096: +- rctl |= E1000_RCTL_SZ_4096; +- break; +- case E1000_RXBUFFER_8192: +- rctl |= E1000_RCTL_SZ_8192; +- break; +- case E1000_RXBUFFER_16384: +- rctl |= E1000_RCTL_SZ_16384; +- break; +- } +- } ++ case E1000_RXBUFFER_2048: ++ default: ++ rctl |= E1000_RCTL_SZ_2048; ++ rctl &= ~E1000_RCTL_BSEX; ++ break; ++ case E1000_RXBUFFER_4096: ++ rctl |= E1000_RCTL_SZ_4096; ++ break; ++ case E1000_RXBUFFER_8192: ++ rctl |= E1000_RCTL_SZ_8192; ++ break; ++ case E1000_RXBUFFER_16384: ++ rctl |= E1000_RCTL_SZ_16384; ++ break; ++ } + +-#ifdef CONFIG_E1000_PACKET_SPLIT +- /* 82571 and greater support packet-split where the protocol +- * header is placed in skb->data and the packet data is +- * placed in pages hanging off of skb_shinfo(skb)->nr_frags. +- * In the case of a non-split, skb->data is linearly filled, +- * followed by the page buffers. Therefore, skb->data is +- * sized to hold the largest protocol header. +- */ +- pages = PAGE_USE_COUNT(adapter->netdev->mtu); +- if ((adapter->hw.mac_type > iegbe_82547_rev_2) && (pages <= 0x3) && +- PAGE_SIZE <= 0x4000) { +- adapter->rx_ps_pages = pages; +- } else { ++#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT ++ /* 82571 and greater support packet-split where the protocol ++ * header is placed in skb->data and the packet data is ++ * placed in pages hanging off of skb_shinfo(skb)->nr_frags. ++ * In the case of a non-split, skb->data is linearly filled, ++ * followed by the page buffers. Therefore, skb->data is ++ * sized to hold the largest protocol header. ++ */ ++ pages = PAGE_USE_COUNT(adapter->netdev->mtu); ++ if ((hw->mac_type >= iegbe_82571) && (pages <= 3) && ++ PAGE_SIZE <= 16384 && (rctl & E1000_RCTL_LPE)) ++ adapter->rx_ps_pages = pages; ++ else + adapter->rx_ps_pages = 0; +- } + #endif +- if (adapter->rx_ps_pages) { +- /* Configure extra packet-split registers */ +- rfctl = E1000_READ_REG(&adapter->hw, RFCTL); +- rfctl |= E1000_RFCTL_EXTEN; +- /* disable IPv6 packet split support */ +- rfctl |= E1000_RFCTL_IPV6_DIS; +- E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl); +- +- rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC; +- +- psrctl |= adapter->rx_ps_bsize0 >> +- E1000_PSRCTL_BSIZE0_SHIFT; +- +- switch (adapter->rx_ps_pages) { +- case 0x3: +- psrctl |= PAGE_SIZE << +- E1000_PSRCTL_BSIZE3_SHIFT; +- case 0x2: +- psrctl |= PAGE_SIZE << +- E1000_PSRCTL_BSIZE2_SHIFT; +- case 0x1: +- psrctl |= PAGE_SIZE >> +- E1000_PSRCTL_BSIZE1_SHIFT; +- break; +- } ++ if (adapter->rx_ps_pages) { ++ /* Configure extra packet-split registers */ ++ rfctl = E1000_READ_REG(&adapter->hw, RFCTL); ++ rfctl |= E1000_RFCTL_EXTEN; ++ /* disable IPv6 packet split support */ ++ rfctl |= (E1000_RFCTL_IPV6_EX_DIS | ++ E1000_RFCTL_NEW_IPV6_EXT_DIS); ++ ++ rctl |= E1000_RCTL_DTYP_PS; ++ ++ psrctl |= adapter->rx_ps_bsize0 >> ++ E1000_PSRCTL_BSIZE0_SHIFT; ++ ++ switch (adapter->rx_ps_pages) { ++ case 3: ++ psrctl |= PAGE_SIZE << ++ E1000_PSRCTL_BSIZE3_SHIFT; ++ case 2: ++ psrctl |= PAGE_SIZE << ++ E1000_PSRCTL_BSIZE2_SHIFT; ++ case 1: ++ psrctl |= PAGE_SIZE >> ++ E1000_PSRCTL_BSIZE1_SHIFT; ++ break; ++ } + +- E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl); +- } ++ E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl); ++ } + +- E1000_WRITE_REG(&adapter->hw, RCTL, rctl); ++ E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + } + + /** +@@ -1873,145 +1768,87 @@ iegbe_setup_rctl(struct iegbe_adapter *a + * Configure the Rx unit of the MAC after a reset. + **/ + +-static void +-iegbe_configure_rx(struct iegbe_adapter *adapter) ++static void iegbe_configure_rx(struct iegbe_adapter *adapter) + { +- uint64_t rdba; +- struct iegbe_hw *hw = &adapter->hw; +- uint32_t rdlen, rctl, rxcsum, ctrl_ext; +-#ifdef CONFIG_E1000_MQ +- uint32_t reta, mrqc; +- int i; +-#endif ++ u64 rdba; ++ struct iegbe_hw *hw = &adapter->hw; ++ u32 rdlen, rctl, rxcsum, ctrl_ext; + +- if (adapter->rx_ps_pages) { ++ if (adapter->rx_ps_pages) { + rdlen = adapter->rx_ring[0].count * +- sizeof(union iegbe_rx_desc_packet_split); +- adapter->clean_rx = iegbe_clean_rx_irq_ps; +- adapter->alloc_rx_buf = iegbe_alloc_rx_buffers_ps; +- } else { ++ sizeof(union iegbe_rx_desc_packet_split); ++ adapter->clean_rx = iegbe_clean_rx_irq_ps; ++ adapter->alloc_rx_buf = iegbe_alloc_rx_buffers_ps; ++ } else { + rdlen = adapter->rx_ring[0].count * +- sizeof(struct iegbe_rx_desc); +- adapter->clean_rx = iegbe_clean_rx_irq; +- adapter->alloc_rx_buf = iegbe_alloc_rx_buffers; +- } ++ sizeof(struct iegbe_rx_desc); ++ adapter->clean_rx = iegbe_clean_rx_irq; ++ adapter->alloc_rx_buf = iegbe_alloc_rx_buffers; ++ } + +- /* disable receives while setting up the descriptors */ +- rctl = E1000_READ_REG(hw, RCTL); +- E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); ++ /* disable receives while setting up the descriptors */ ++ rctl = E1000_READ_REG(hw, RCTL); ++ E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); + +- /* set the Receive Delay Timer Register */ +- E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay); ++ /* set the Receive Delay Timer Register */ ++ E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay); + +- if (hw->mac_type >= iegbe_82540) { +- E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay); +- if(adapter->itr > 0x1) { +- E1000_WRITE_REG(hw, ITR, +- 0x3b9aca00 / (adapter->itr * 0x100)); ++ if (hw->mac_type >= iegbe_82540) { ++ E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay); ++ if (adapter->itr_setting != 0) ++ E1000_WRITE_REG(&adapter->hw, ITR, 1000000000 / (adapter->itr * 256)); + } +- } + +- if (hw->mac_type >= iegbe_82571) { +- /* Reset delay timers after every interrupt */ +- ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); +- ctrl_ext |= E1000_CTRL_EXT_CANC; +- E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); +- E1000_WRITE_FLUSH(hw); +- } ++ if (hw->mac_type >= iegbe_82571) { ++ /* Reset delay timers after every interrupt */ ++ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); ++ ctrl_ext |= E1000_CTRL_EXT_CANC; ++ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); ++ E1000_WRITE_FLUSH(hw); ++ } + + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring */ +- switch (adapter->num_queues) { +-#ifdef CONFIG_E1000_MQ +- case 0x2: +- rdba = adapter->rx_ring[0x1].dma; +- E1000_WRITE_REG(hw, RDBAL1, (rdba & 0x00000000ffffffffULL)); +- E1000_WRITE_REG(hw, RDBAH1, (rdba >> 0x20)); +- E1000_WRITE_REG(hw, RDLEN1, rdlen); +- E1000_WRITE_REG(hw, RDH1, 0); +- E1000_WRITE_REG(hw, RDT1, 0); +- adapter->rx_ring[1].rdh = E1000_RDH1; +- adapter->rx_ring[1].rdt = E1000_RDT1; +- /* Fall Through */ +-#endif +- case 0x1: +- default: ++ switch (adapter->num_rx_queues) { ++ case 1: ++ default: + rdba = adapter->rx_ring[0].dma; +- E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL)); ++ E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, RDBAH, (rdba >> 0x20)); +- E1000_WRITE_REG(hw, RDLEN, rdlen); +- E1000_WRITE_REG(hw, RDH, 0); +- E1000_WRITE_REG(hw, RDT, 0); +- adapter->rx_ring[0].rdh = E1000_RDH; +- adapter->rx_ring[0].rdt = E1000_RDT; +- break; +- } ++ E1000_WRITE_REG(hw, RDLEN, rdlen); ++ adapter->rx_ring[0].rdh = ((hw->mac_type >= iegbe_82543) ? E1000_RDH : E1000_82542_RDH); ++ adapter->rx_ring[0].rdt = ((hw->mac_type >= iegbe_82543) ? E1000_RDT : E1000_82542_RDT); ++ break; ++ } + +-#ifdef CONFIG_E1000_MQ +- if (adapter->num_queues > 0x1) { +- uint32_t random[0xa]; +- +- get_random_bytes(&random[0], FORTY); +- +- if (hw->mac_type <= iegbe_82572) { +- E1000_WRITE_REG(hw, RSSIR, 0); +- E1000_WRITE_REG(hw, RSSIM, 0); +- } + +- switch (adapter->num_queues) { +- case 0x2: +- default: +- reta = 0x00800080; +- mrqc = E1000_MRQC_ENABLE_RSS_2Q; +- break; +- } +- +- /* Fill out redirection table */ +- for (i = 0; i < 0x20; i++) +- E1000_WRITE_REG_ARRAY(hw, RETA, i, reta); +- /* Fill out hash function seeds */ +- for (i = 0; i < 0xa; i++) +- E1000_WRITE_REG_ARRAY(hw, RSSRK, i, random[i]); +- +- mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 | +- E1000_MRQC_RSS_FIELD_IPV4_TCP); +- E1000_WRITE_REG(hw, MRQC, mrqc); +- } +- +- /* Multiqueue and packet checksumming are mutually exclusive. */ +- if (hw->mac_type >= iegbe_82571) { +- rxcsum = E1000_READ_REG(hw, RXCSUM); +- rxcsum |= E1000_RXCSUM_PCSD; +- E1000_WRITE_REG(hw, RXCSUM, rxcsum); +- } +- +-#else ++ /* Enable 82543 Receive Checksum Offload for TCP and UDP */ ++ if (hw->mac_type >= iegbe_82543) { ++ rxcsum = E1000_READ_REG(hw, RXCSUM); ++ if(adapter->rx_csum == TRUE) { ++ rxcsum |= E1000_RXCSUM_TUOFL; ++ ++ /* Enable 82571 IPv4 payload checksum for UDP fragments ++ * Must be used in conjunction with packet-split. */ ++ if ((hw->mac_type >= iegbe_82571) && ++ (adapter->rx_ps_pages)) { ++ rxcsum |= E1000_RXCSUM_IPPCSE; ++ } ++ } else { ++ rxcsum &= ~E1000_RXCSUM_TUOFL; ++ /* don't need to clear IPPCSE as it defaults to 0 */ ++ } ++ E1000_WRITE_REG(hw, RXCSUM, rxcsum); ++ } + +- /* Enable 82543 Receive Checksum Offload for TCP and UDP */ +- if (hw->mac_type >= iegbe_82543) { +- rxcsum = E1000_READ_REG(hw, RXCSUM); +- if(adapter->rx_csum == TRUE) { +- rxcsum |= E1000_RXCSUM_TUOFL; +- +- /* Enable 82571 IPv4 payload checksum for UDP fragments +- * Must be used in conjunction with packet-split. */ +- if ((hw->mac_type >= iegbe_82571) && +- (adapter->rx_ps_pages)) { +- rxcsum |= E1000_RXCSUM_IPPCSE; +- } +- } else { +- rxcsum &= ~E1000_RXCSUM_TUOFL; +- /* don't need to clear IPPCSE as it defaults to 0 */ +- } +- E1000_WRITE_REG(hw, RXCSUM, rxcsum); +- } +-#endif /* CONFIG_E1000_MQ */ ++ /* enable early receives on 82573, only takes effect if using > 2048 ++ * byte total frame size. for example only for jumbo frames */ ++#define E1000_ERT_2048 0x100 ++ if (hw->mac_type == iegbe_82573) ++ E1000_WRITE_REG(&adapter->hw, ERT, E1000_ERT_2048); + +- if (hw->mac_type == iegbe_82573) { +- E1000_WRITE_REG(hw, ERT, 0x0100); +- } + /* Enable Receives */ +- E1000_WRITE_REG(hw, RCTL, rctl); ++ E1000_WRITE_REG(hw, RCTL, rctl); + } + + /** +@@ -2022,20 +1859,19 @@ iegbe_configure_rx(struct iegbe_adapter + * Free all transmit software resources + **/ + +-void +-iegbe_free_tx_resources(struct iegbe_adapter *adapter, ++static void iegbe_free_tx_resources(struct iegbe_adapter *adapter, + struct iegbe_tx_ring *tx_ring) + { +- struct pci_dev *pdev = adapter->pdev; ++ struct pci_dev *pdev = adapter->pdev; + +- iegbe_clean_tx_ring(adapter, tx_ring); ++ iegbe_clean_tx_ring(adapter, tx_ring); + +- vfree(tx_ring->buffer_info); +- tx_ring->buffer_info = NULL; ++ vfree(tx_ring->buffer_info); ++ tx_ring->buffer_info = NULL; + +- pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma); ++ pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma); + +- tx_ring->desc = NULL; ++ tx_ring->desc = NULL; + } + + /** +@@ -2048,85 +1884,29 @@ iegbe_free_tx_resources(struct iegbe_ada + void + iegbe_free_all_tx_resources(struct iegbe_adapter *adapter) + { +- int i; ++ int i; + +- for (i = 0; i < adapter->num_queues; i++) ++ for (i = 0x0; i < adapter->num_tx_queues; i++) + iegbe_free_tx_resources(adapter, &adapter->tx_ring[i]); + } + + static inline void + iegbe_unmap_and_free_tx_resource(struct iegbe_adapter *adapter, +- struct iegbe_buffer *buffer_info) +-{ +- if(buffer_info->dma) { +- pci_unmap_page(adapter->pdev, +- buffer_info->dma, +- buffer_info->length, +- PCI_DMA_TODEVICE); +- buffer_info->dma = 0; +- } +- if(buffer_info->skb) { +- dev_kfree_skb_any(buffer_info->skb); +- buffer_info->skb = NULL; +- } +-} +- +-#ifdef IEGBE_GBE_WORKAROUND +-/** +- * iegbe_clean_tx_ring_partial - Free Tx Buffers without using the DD +- * bit in the descriptor +- * @adapter: board private structure +- * @tx_ring: ring to be cleaned +- **/ +-static void iegbe_clean_tx_ring_partial(struct iegbe_adapter *adapter, +- struct iegbe_tx_ring *tx_ring) ++ struct iegbe_buffer *buffer_info) + { +- struct iegbe_buffer *buffer_info; +- struct iegbe_tx_desc *tx_desc; +- struct net_device *netdev = adapter->netdev; +- unsigned int i; +- unsigned tail; +- unsigned head; +- int cleaned = FALSE; +- +- tail = readl(adapter->hw.hw_addr + tx_ring->tdt); +- head = readl(adapter->hw.hw_addr + tx_ring->tdh); +- +- if (head != tail) { +- adapter->stats.tx_hnet++; +- } +- if (head != tx_ring->next_to_use) { +- adapter->stats.tx_hnentu++; +- } +- /* Free all the Tx ring sk_buffs from next_to_clean up until +- * the current head pointer +- */ +- i = tx_ring->next_to_clean; +- while(i != head) { +- cleaned = TRUE; +- tx_desc = E1000_TX_DESC(*tx_ring, i); +- +- buffer_info = &tx_ring->buffer_info[i]; +- iegbe_unmap_and_free_tx_resource(adapter, buffer_info); +- +- tx_desc->upper.data = 0; +- +- if (unlikely(++i == tx_ring->count)) { i = 0; } +- +- } +- tx_ring->next_to_clean = head; +- +- spin_lock(&tx_ring->tx_lock); +- +- /* Wake up the queue if it's currently stopped */ +- if (unlikely(cleaned && netif_queue_stopped(netdev) && +- netif_carrier_ok(netdev))) { +- netif_wake_queue(netdev); ++ if(buffer_info->dma) { ++ pci_unmap_page(adapter->pdev, ++ buffer_info->dma, ++ buffer_info->length, ++ PCI_DMA_TODEVICE); ++ buffer_info->dma = 0x0; ++ } ++ if(buffer_info->skb) { ++ dev_kfree_skb_any(buffer_info->skb); ++ buffer_info->skb = NULL; + } +- +- spin_unlock(&tx_ring->tx_lock); + } +-#endif ++ + + /** + * iegbe_clean_tx_ring - Free Tx Buffers +@@ -2134,38 +1914,34 @@ static void iegbe_clean_tx_ring_partial( + * @tx_ring: ring to be cleaned + **/ + +-static void +-iegbe_clean_tx_ring(struct iegbe_adapter *adapter, ++static void iegbe_clean_tx_ring(struct iegbe_adapter *adapter, + struct iegbe_tx_ring *tx_ring) + { +- struct iegbe_buffer *buffer_info; +- unsigned long size; +- unsigned int i; +- +- /* Free all the Tx ring sk_buffs */ ++ struct iegbe_hw *hw = &adapter->hw; ++ struct iegbe_buffer *buffer_info; ++ unsigned long size; ++ unsigned int i; + +- if (likely(tx_ring->previous_buffer_info.skb != NULL)) { +- iegbe_unmap_and_free_tx_resource(adapter, +- &tx_ring->previous_buffer_info); +- } ++ /* Free all the Tx ring sk_buffs */ + + for (i = 0; i < tx_ring->count; i++) { +- buffer_info = &tx_ring->buffer_info[i]; +- iegbe_unmap_and_free_tx_resource(adapter, buffer_info); +- } ++ buffer_info = &tx_ring->buffer_info[i]; ++ iegbe_unmap_and_free_tx_resource(adapter, buffer_info); ++ } + +- size = sizeof(struct iegbe_buffer) * tx_ring->count; ++ size = sizeof(struct iegbe_buffer) * tx_ring->count; + memset(tx_ring->buffer_info, 0, size); + +- /* Zero out the descriptor ring */ ++ /* Zero out the descriptor ring */ + + memset(tx_ring->desc, 0, tx_ring->size); + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; ++ tx_ring->last_tx_tso = 0; + +- writel(0, adapter->hw.hw_addr + tx_ring->tdh); +- writel(0, adapter->hw.hw_addr + tx_ring->tdt); ++ writel(0, hw->hw_addr + tx_ring->tdh); ++ writel(0, hw->hw_addr + tx_ring->tdt); + } + + /** +@@ -2173,12 +1949,11 @@ iegbe_clean_tx_ring(struct iegbe_adapter + * @adapter: board private structure + **/ + +-static void +-iegbe_clean_all_tx_rings(struct iegbe_adapter *adapter) ++static void iegbe_clean_all_tx_rings(struct iegbe_adapter *adapter) + { +- int i; ++ int i; + +- for (i = 0; i < adapter->num_queues; i++) ++ for (i = 0; i < adapter->num_tx_queues; i++) + iegbe_clean_tx_ring(adapter, &adapter->tx_ring[i]); + } + +@@ -2190,24 +1965,23 @@ iegbe_clean_all_tx_rings(struct iegbe_ad + * Free all receive software resources + **/ + +-void +-iegbe_free_rx_resources(struct iegbe_adapter *adapter, ++static void iegbe_free_rx_resources(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring) + { +- struct pci_dev *pdev = adapter->pdev; ++ struct pci_dev *pdev = adapter->pdev; + +- iegbe_clean_rx_ring(adapter, rx_ring); ++ iegbe_clean_rx_ring(adapter, rx_ring); + +- vfree(rx_ring->buffer_info); +- rx_ring->buffer_info = NULL; +- kfree(rx_ring->ps_page); +- rx_ring->ps_page = NULL; +- kfree(rx_ring->ps_page_dma); +- rx_ring->ps_page_dma = NULL; ++ vfree(rx_ring->buffer_info); ++ rx_ring->buffer_info = NULL; ++ kfree(rx_ring->ps_page); ++ rx_ring->ps_page = NULL; ++ kfree(rx_ring->ps_page_dma); ++ rx_ring->ps_page_dma = NULL; + +- pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); ++ pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); + +- rx_ring->desc = NULL; ++ rx_ring->desc = NULL; + } + + /** +@@ -2217,12 +1991,11 @@ iegbe_free_rx_resources(struct iegbe_ada + * Free all receive software resources + **/ + +-void +-iegbe_free_all_rx_resources(struct iegbe_adapter *adapter) ++void iegbe_free_all_rx_resources(struct iegbe_adapter *adapter) + { +- int i; ++ int i; + +- for (i = 0; i < adapter->num_queues; i++) ++ for (i = 0; i < adapter->num_rx_queues; i++) + iegbe_free_rx_resources(adapter, &adapter->rx_ring[i]); + } + +@@ -2232,60 +2005,59 @@ iegbe_free_all_rx_resources(struct iegbe + * @rx_ring: ring to free buffers from + **/ + +-static void +-iegbe_clean_rx_ring(struct iegbe_adapter *adapter, ++static void iegbe_clean_rx_ring(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring) + { +- struct iegbe_buffer *buffer_info; +- struct iegbe_ps_page *ps_page; +- struct iegbe_ps_page_dma *ps_page_dma; +- struct pci_dev *pdev = adapter->pdev; +- unsigned long size; +- unsigned int i, j; +- +- /* Free all the Rx ring sk_buffs */ ++ struct iegbe_hw *hw = &adapter->hw; ++ struct iegbe_buffer *buffer_info; ++ struct iegbe_ps_page *ps_page; ++ struct iegbe_ps_page_dma *ps_page_dma; ++ struct pci_dev *pdev = adapter->pdev; ++ unsigned long size; ++ unsigned int i, j; ++ ++ /* Free all the Rx ring sk_buffs */ ++ ++ for (i = 0; i < rx_ring->count; i++) { ++ buffer_info = &rx_ring->buffer_info[i]; ++ if(buffer_info->skb) { ++ pci_unmap_single(pdev, ++ buffer_info->dma, ++ buffer_info->length, ++ PCI_DMA_FROMDEVICE); + +- for(i = 0; i < rx_ring->count; i++) { +- buffer_info = &rx_ring->buffer_info[i]; +- if(buffer_info->skb) { +- ps_page = &rx_ring->ps_page[i]; +- ps_page_dma = &rx_ring->ps_page_dma[i]; +- pci_unmap_single(pdev, +- buffer_info->dma, +- buffer_info->length, +- PCI_DMA_FROMDEVICE); +- +- dev_kfree_skb(buffer_info->skb); +- buffer_info->skb = NULL; +- +- for(j = 0; j < adapter->rx_ps_pages; j++) { +- if(!ps_page->ps_page[j]) { break; } +- pci_unmap_single(pdev, +- ps_page_dma->ps_page_dma[j], +- PAGE_SIZE, PCI_DMA_FROMDEVICE); +- ps_page_dma->ps_page_dma[j] = 0; +- put_page(ps_page->ps_page[j]); +- ps_page->ps_page[j] = NULL; +- } ++ dev_kfree_skb(buffer_info->skb); ++ buffer_info->skb = NULL; + } +- } ++ ps_page = &rx_ring->ps_page[i]; ++ ps_page_dma = &rx_ring->ps_page_dma[i]; ++ for (j = 0; j < adapter->rx_ps_pages; j++) { ++ if (!ps_page->ps_page[j]) break; ++ pci_unmap_page(pdev, ++ ps_page_dma->ps_page_dma[j], ++ PAGE_SIZE, PCI_DMA_FROMDEVICE); ++ ps_page_dma->ps_page_dma[j] = 0; ++ put_page(ps_page->ps_page[j]); ++ ps_page->ps_page[j] = NULL; ++ } ++ } + +- size = sizeof(struct iegbe_buffer) * rx_ring->count; ++ size = sizeof(struct iegbe_buffer) * rx_ring->count; + memset(rx_ring->buffer_info, 0, size); +- size = sizeof(struct iegbe_ps_page) * rx_ring->count; ++ size = sizeof(struct iegbe_ps_page) * rx_ring->count; + memset(rx_ring->ps_page, 0, size); +- size = sizeof(struct iegbe_ps_page_dma) * rx_ring->count; ++ size = sizeof(struct iegbe_ps_page_dma) * rx_ring->count; + memset(rx_ring->ps_page_dma, 0, size); + +- /* Zero out the descriptor ring */ ++ /* Zero out the descriptor ring */ + + memset(rx_ring->desc, 0, rx_ring->size); + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + +- writel(0, adapter->hw.hw_addr + rx_ring->rdh); +- writel(0, adapter->hw.hw_addr + rx_ring->rdt); ++ writel(0, hw->hw_addr + rx_ring->rdh); ++ writel(0, hw->hw_addr + rx_ring->rdt); + } + + /** +@@ -2293,60 +2065,54 @@ iegbe_clean_rx_ring(struct iegbe_adapter + * @adapter: board private structure + **/ + +-static void +-iegbe_clean_all_rx_rings(struct iegbe_adapter *adapter) ++static void iegbe_clean_all_rx_rings(struct iegbe_adapter *adapter) + { +- int i; ++ int i; + +- for (i = 0; i < adapter->num_queues; i++) ++ for (i = 0; i < adapter->num_rx_queues; i++) + iegbe_clean_rx_ring(adapter, &adapter->rx_ring[i]); + } + + /* The 82542 2.0 (revision 2) needs to have the receive unit in reset + * and memory write and invalidate disabled for certain operations + */ +-static void +-iegbe_enter_82542_rst(struct iegbe_adapter *adapter) ++static void iegbe_enter_82542_rst(struct iegbe_adapter *adapter) + { +- struct net_device *netdev = adapter->netdev; +- uint32_t rctl; ++ struct net_device *netdev = adapter->netdev; ++ uint32_t rctl; + +- iegbe_pci_clear_mwi(&adapter->hw); ++ iegbe_pci_clear_mwi(&adapter->hw); + +- rctl = E1000_READ_REG(&adapter->hw, RCTL); +- rctl |= E1000_RCTL_RST; +- E1000_WRITE_REG(&adapter->hw, RCTL, rctl); +- E1000_WRITE_FLUSH(&adapter->hw); ++ rctl = E1000_READ_REG(&adapter->hw, RCTL); ++ rctl |= E1000_RCTL_RST; ++ E1000_WRITE_REG(&adapter->hw, RCTL, rctl); ++ E1000_WRITE_FLUSH(&adapter->hw); + mdelay(0x5); + + if(netif_running(netdev)) { +- iegbe_clean_all_rx_rings(adapter); +-} ++ iegbe_clean_all_rx_rings(adapter); ++ } + } + + static void + iegbe_leave_82542_rst(struct iegbe_adapter *adapter) + { +- struct net_device *netdev = adapter->netdev; +- uint32_t rctl; ++ struct net_device *netdev = adapter->netdev; ++ uint32_t rctl; + +- rctl = E1000_READ_REG(&adapter->hw, RCTL); +- rctl &= ~E1000_RCTL_RST; +- E1000_WRITE_REG(&adapter->hw, RCTL, rctl); +- E1000_WRITE_FLUSH(&adapter->hw); ++ rctl = E1000_READ_REG(&adapter->hw, RCTL); ++ rctl &= ~E1000_RCTL_RST; ++ E1000_WRITE_REG(&adapter->hw, RCTL, rctl); ++ E1000_WRITE_FLUSH(&adapter->hw); + mdelay(0x5); + + if(adapter->hw.pci_cmd_word & PCI_COMMAND_INVALIDATE) { +- iegbe_pci_set_mwi(&adapter->hw); ++ iegbe_pci_set_mwi(&adapter->hw); + } + if(netif_running(netdev)) { ++ struct iegbe_rx_ring *ring = &adapter->rx_ring[0x0]; + iegbe_configure_rx(adapter); +-#ifdef IEGBE_GBE_WORKAROUND +- iegbe_alloc_rx_buffers(adapter, &adapter->rx_ring[0], +- IEGBE_GBE_WORKAROUND_NUM_RX_DESCRIPTORS + 1); +-#else +- iegbe_alloc_rx_buffers(adapter, &adapter->rx_ring[0]); +-#endif ++ adapter->alloc_rx_buf(adapter, ring, E1000_DESC_UNUSED(ring)); + } + } + +@@ -2358,133 +2124,153 @@ iegbe_leave_82542_rst(struct iegbe_adapt + * Returns 0 on success, negative on failure + **/ + +-static int +-iegbe_set_mac(struct net_device *netdev, void *p) ++static int iegbe_set_mac(struct net_device *netdev, void *p) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- struct sockaddr *addr = p; ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct sockaddr *addr = p; + + if(!is_valid_ether_addr(addr->sa_data)) { +- return -EADDRNOTAVAIL; ++ return -EADDRNOTAVAIL; + } +- /* 82542 2.0 needs to be in reset to write receive address registers */ ++ /* 82542 2.0 needs to be in reset to write receive address registers */ + + if(adapter->hw.mac_type == iegbe_82542_rev2_0) { +- iegbe_enter_82542_rst(adapter); ++ iegbe_enter_82542_rst(adapter); + } +- memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); +- memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); ++ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ++ memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); + +- iegbe_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); ++ iegbe_rar_set(&adapter->hw, adapter->hw.mac_addr, 0x0); + +- /* With 82571 controllers, LAA may be overwritten (with the default) +- * due to controller reset from the other port. */ +- if (adapter->hw.mac_type == iegbe_82571) { +- /* activate the work around */ ++ /* With 82571 controllers, LAA may be overwritten (with the default) ++ * due to controller reset from the other port. */ ++ if (adapter->hw.mac_type == iegbe_82571) { ++ /* activate the work around */ + adapter->hw.laa_is_present = 0x1; + +- /* Hold a copy of the LAA in RAR[14] This is done so that +- * between the time RAR[0] gets clobbered and the time it +- * gets fixed (in iegbe_watchdog), the actual LAA is in one +- * of the RARs and no incoming packets directed to this port +- * are dropped. Eventaully the LAA will be in RAR[0] and +- * RAR[14] */ +- iegbe_rar_set(&adapter->hw, adapter->hw.mac_addr, ++ /* Hold a copy of the LAA in RAR[14] This is done so that ++ * between the time RAR[0] gets clobbered and the time it ++ * gets fixed (in iegbe_watchdog), the actual LAA is in one ++ * of the RARs and no incoming packets directed to this port ++ * are dropped. Eventaully the LAA will be in RAR[0] and ++ * RAR[14] */ ++ iegbe_rar_set(&adapter->hw, adapter->hw.mac_addr, + E1000_RAR_ENTRIES - 0x1); +- } ++ } + + if(adapter->hw.mac_type == iegbe_82542_rev2_0) { +- iegbe_leave_82542_rst(adapter); ++ iegbe_leave_82542_rst(adapter); + } +- return 0; ++ return 0x0; + } + + /** +- * iegbe_set_multi - Multicast and Promiscuous mode set ++ * iegbe_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set + * @netdev: network interface device structure + * +- * The set_multi entry point is called whenever the multicast address +- * list or the network interface flags are updated. This routine is +- * responsible for configuring the hardware for proper multicast, ++ * The set_rx_mode entry point is called whenever the unicast or multicast ++ * address lists or the network interface flags are updated. This routine is ++ * responsible for configuring the hardware for proper unicast, multicast, + * promiscuous mode, and all-multi behavior. + **/ + +-static void +-iegbe_set_multi(struct net_device *netdev) ++static void iegbe_set_rx_mode(struct net_device *netdev) + { + struct iegbe_adapter *adapter = netdev_priv(netdev); + struct iegbe_hw *hw = &adapter->hw; +- struct dev_mc_list *mc_ptr; +- uint32_t rctl; +- uint32_t hash_value; ++ struct dev_addr_list *uc_ptr; ++ struct dev_addr_list *mc_ptr; ++ u32 rctl; ++ u32 hash_value; + int i, rar_entries = E1000_RAR_ENTRIES; ++int mta_reg_count = E1000_NUM_MTA_REGISTERS; + + /* reserve RAR[14] for LAA over-write work-around */ +- if (adapter->hw.mac_type == iegbe_82571) { ++ if (hw->mac_type == iegbe_82571) + rar_entries--; +- } ++ + /* Check for Promiscuous and All Multicast modes */ + +- rctl = E1000_READ_REG(hw, RCTL); ++ rctl = E1000_READ_REG(&adapter->hw, RCTL); + + if (netdev->flags & IFF_PROMISC) { + rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); +- } else if (netdev->flags & IFF_ALLMULTI) { +- rctl |= E1000_RCTL_MPE; +- rctl &= ~E1000_RCTL_UPE; ++ rctl &= ~E1000_RCTL_VFE; + } else { +- rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); ++ if (netdev->flags & IFF_ALLMULTI) { ++ rctl |= E1000_RCTL_MPE; ++ } else { ++ rctl &= ~E1000_RCTL_MPE; ++ } ++ } ++ ++ uc_ptr = NULL; ++ if (netdev->uc_count > rar_entries - 1) { ++ rctl |= E1000_RCTL_UPE; ++ } else if (!(netdev->flags & IFF_PROMISC)) { ++ rctl &= ~E1000_RCTL_UPE; ++ uc_ptr = netdev->uc_list; + } + +- E1000_WRITE_REG(hw, RCTL, rctl); ++ E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + + /* 82542 2.0 needs to be in reset to write receive address registers */ + +- if (hw->mac_type == iegbe_82542_rev2_0) { ++ if (hw->mac_type == iegbe_82542_rev2_0) + iegbe_enter_82542_rst(adapter); +- } +- /* load the first 14 multicast address into the exact filters 1-14 ++ ++ /* load the first 14 addresses into the exact filters 1-14. Unicast ++ * addresses take precedence to avoid disabling unicast filtering ++ * when possible. ++ * + * RAR 0 is used for the station MAC adddress + * if there are not 14 addresses, go ahead and clear the filters + * -- with 82571 controllers only 0-13 entries are filled here + */ + mc_ptr = netdev->mc_list; + +- for (i = 0x1; i < rar_entries; i++) { +- if (mc_ptr) { +- iegbe_rar_set(hw, mc_ptr->dmi_addr, i); ++ for (i = 1; i < rar_entries; i++) { ++ if (uc_ptr) { ++ iegbe_rar_set(hw, uc_ptr->da_addr, i); ++ uc_ptr = uc_ptr->next; ++ } else if (mc_ptr) { ++ iegbe_rar_set(hw, mc_ptr->da_addr, i); + mc_ptr = mc_ptr->next; + } else { +- E1000_WRITE_REG_ARRAY(hw, RA, i << 0x1, 0); +- E1000_WRITE_REG_ARRAY(hw, RA, (i << 0x1) + 0x1, 0); ++ E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0); ++ E1000_WRITE_FLUSH(&adapter->hw); ++ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0); ++ E1000_WRITE_FLUSH(&adapter->hw); + } + } ++ WARN_ON(uc_ptr != NULL); + + /* clear the old settings from the multicast hash table */ + +- for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++) ++ for (i = 0; i < mta_reg_count; i++) { + E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); ++ E1000_WRITE_FLUSH(&adapter->hw); ++ } + + /* load any remaining addresses into the hash table */ + + for (; mc_ptr; mc_ptr = mc_ptr->next) { +- hash_value = iegbe_hash_mc_addr(hw, mc_ptr->dmi_addr); ++ hash_value = iegbe_hash_mc_addr(hw, mc_ptr->da_addr); + iegbe_mta_set(hw, hash_value); + } + +- if (hw->mac_type == iegbe_82542_rev2_0) { ++ if (hw->mac_type == iegbe_82542_rev2_0) + iegbe_leave_82542_rst(adapter); + } +-} + + /* Need to wait a few seconds after link up to get diagnostic information from + * the phy */ + +-static void +-iegbe_update_phy_info(unsigned long data) ++static void iegbe_update_phy_info(unsigned long data) + { +- struct iegbe_adapter *adapter = (struct iegbe_adapter *) data; +- iegbe_phy_get_info(&adapter->hw, &adapter->phy_info); ++ struct iegbe_adapter *adapter = (struct iegbe_adapter *) data; ++ struct iegbe_hw *hw = &adapter->hw; ++ iegbe_phy_get_info(hw, &adapter->phy_info); + } + + /** +@@ -2492,54 +2278,54 @@ iegbe_update_phy_info(unsigned long data + * @data: pointer to adapter cast into an unsigned long + **/ + +-static void +-iegbe_82547_tx_fifo_stall(unsigned long data) ++static void iegbe_82547_tx_fifo_stall(unsigned long data) + { +- struct iegbe_adapter *adapter = (struct iegbe_adapter *) data; +- struct net_device *netdev = adapter->netdev; +- uint32_t tctl; ++ struct iegbe_adapter *adapter = (struct iegbe_adapter *) data; ++ struct net_device *netdev = adapter->netdev; ++ u32 tctl; + +- if(atomic_read(&adapter->tx_fifo_stall)) { +- if((E1000_READ_REG(&adapter->hw, TDT) == +- E1000_READ_REG(&adapter->hw, TDH)) && +- (E1000_READ_REG(&adapter->hw, TDFT) == +- E1000_READ_REG(&adapter->hw, TDFH)) && +- (E1000_READ_REG(&adapter->hw, TDFTS) == +- E1000_READ_REG(&adapter->hw, TDFHS))) { +- tctl = E1000_READ_REG(&adapter->hw, TCTL); +- E1000_WRITE_REG(&adapter->hw, TCTL, +- tctl & ~E1000_TCTL_EN); +- E1000_WRITE_REG(&adapter->hw, TDFT, +- adapter->tx_head_addr); +- E1000_WRITE_REG(&adapter->hw, TDFH, +- adapter->tx_head_addr); +- E1000_WRITE_REG(&adapter->hw, TDFTS, +- adapter->tx_head_addr); +- E1000_WRITE_REG(&adapter->hw, TDFHS, +- adapter->tx_head_addr); +- E1000_WRITE_REG(&adapter->hw, TCTL, tctl); +- E1000_WRITE_FLUSH(&adapter->hw); +- +- adapter->tx_fifo_head = 0; +- atomic_set(&adapter->tx_fifo_stall, 0); +- netif_wake_queue(netdev); +- } else { ++ if(atomic_read(&adapter->tx_fifo_stall)) { ++ if((E1000_READ_REG(&adapter->hw, TDT) == ++ E1000_READ_REG(&adapter->hw, TDH)) && ++ (E1000_READ_REG(&adapter->hw, TDFT) == ++ E1000_READ_REG(&adapter->hw, TDFH)) && ++ (E1000_READ_REG(&adapter->hw, TDFTS) == ++ E1000_READ_REG(&adapter->hw, TDFHS))) { ++ tctl = E1000_READ_REG(&adapter->hw, TCTL); ++ E1000_WRITE_REG(&adapter->hw, TCTL, ++ tctl & ~E1000_TCTL_EN); ++ E1000_WRITE_REG(&adapter->hw, TDFT, ++ adapter->tx_head_addr); ++ E1000_WRITE_REG(&adapter->hw, TDFH, ++ adapter->tx_head_addr); ++ E1000_WRITE_REG(&adapter->hw, TDFTS, ++ adapter->tx_head_addr); ++ E1000_WRITE_REG(&adapter->hw, TDFHS, ++ adapter->tx_head_addr); ++ E1000_WRITE_REG(&adapter->hw, TCTL, tctl); ++ E1000_WRITE_FLUSH(&adapter->hw); ++ ++ adapter->tx_fifo_head = 0x0; ++ atomic_set(&adapter->tx_fifo_stall, 0x0); ++ netif_wake_queue(netdev); ++ } else { + mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 0x1); +- } +- } ++ } ++ } + } + ++ + /** + * iegbe_watchdog - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ +-static void +-iegbe_watchdog(unsigned long data) ++static void iegbe_watchdog(unsigned long data) + { +- struct iegbe_adapter *adapter = (struct iegbe_adapter *) data; +- struct net_device *netdev = adapter->netdev; +- struct iegbe_tx_ring *txdr = &adapter->tx_ring[0]; +- uint32_t link; ++ struct iegbe_adapter *adapter = (struct iegbe_adapter *) data; ++ struct iegbe_hw *hw = &adapter->hw; ++ struct net_device *netdev = adapter->netdev; ++ struct iegbe_tx_ring *txdr = adapter->tx_ring; ++ u32 link, tctl; + + /* + * Test the PHY for link status on icp_xxxx MACs. +@@ -2547,123 +2333,305 @@ iegbe_watchdog(unsigned long data) + * in the adapter->hw structure, then set hw->get_link_status = 1 + */ + if(adapter->hw.mac_type == iegbe_icp_xxxx) { +- int isUp = 0; ++ int isUp = 0x0; + int32_t ret_val; + + ret_val = iegbe_oem_phy_is_link_up(&adapter->hw, &isUp); + if(ret_val != E1000_SUCCESS) { +- isUp = 0; +- } ++ isUp = 0x0; ++ } + if(isUp != adapter->hw.icp_xxxx_is_link_up) { + adapter->hw.get_link_status = 0x1; + } + } + +- iegbe_check_for_link(&adapter->hw); +- if (adapter->hw.mac_type == iegbe_82573) { +- iegbe_enable_tx_pkt_filtering(&adapter->hw); ++ iegbe_check_for_link(&adapter->hw); ++ if (adapter->hw.mac_type == iegbe_82573) { ++ iegbe_enable_tx_pkt_filtering(&adapter->hw); + #ifdef NETIF_F_HW_VLAN_TX + if (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id) { +- iegbe_update_mng_vlan(adapter); ++ iegbe_update_mng_vlan(adapter); + } + #endif +- } ++ } + +- if ((adapter->hw.media_type == iegbe_media_type_internal_serdes) && +- !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE)) { +- link = !adapter->hw.serdes_link_down; +- } else { ++ if ((adapter->hw.media_type == iegbe_media_type_internal_serdes) && ++ !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE)) { ++ link = !adapter->hw.serdes_link_down; ++ } else { + +- if(adapter->hw.mac_type != iegbe_icp_xxxx) { +- link = E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU; +- } else { +- int isUp = 0; ++ if(adapter->hw.mac_type != iegbe_icp_xxxx) { ++ link = E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU; ++ } else { ++ int isUp = 0x0; + if(iegbe_oem_phy_is_link_up(&adapter->hw, &isUp) != E1000_SUCCESS) { +- isUp = 0; ++ isUp = 0x0; + } +- link = isUp; +- } +- } ++ link = isUp; ++ } ++ } + +- if (link) { +- if (!netif_carrier_ok(netdev)) { +- iegbe_get_speed_and_duplex(&adapter->hw, +- &adapter->link_speed, +- &adapter->link_duplex); +- +- DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s\n", +- adapter->link_speed, +- adapter->link_duplex == FULL_DUPLEX ? +- "Full Duplex" : "Half Duplex"); ++ if (link) { ++ if (!netif_carrier_ok(netdev)) { ++ u32 ctrl; ++ bool txb2b = true; ++ iegbe_get_speed_and_duplex(hw, ++ &adapter->link_speed, ++ &adapter->link_duplex); + +- netif_carrier_on(netdev); +- netif_wake_queue(netdev); +- mod_timer(&adapter->phy_info_timer, jiffies + 0x2 * HZ); ++ ctrl = E1000_READ_REG(&adapter->hw, CTRL); ++ DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, " ++ "Flow Control: %s\n", ++ adapter->link_speed, ++ adapter->link_duplex == FULL_DUPLEX ? ++ "Full Duplex" : "Half Duplex", ++ ((ctrl & E1000_CTRL_TFCE) && (ctrl & ++ E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl & ++ E1000_CTRL_RFCE) ? "RX" : ((ctrl & ++ E1000_CTRL_TFCE) ? "TX" : "None" ))); ++ ++ /* tweak tx_queue_len according to speed/duplex ++ * and adjust the timeout factor */ ++ netdev->tx_queue_len = adapter->tx_queue_len; ++ adapter->tx_timeout_factor = 1; ++ switch (adapter->link_speed) { ++ case SPEED_10: ++ txb2b = false; ++ netdev->tx_queue_len = 10; ++ adapter->tx_timeout_factor = 8; ++ break; ++ case SPEED_100: ++ txb2b = false; ++ netdev->tx_queue_len = 100; ++ break; ++ } ++ if ((hw->mac_type == iegbe_82571 || ++ hw->mac_type == iegbe_82572) && ++ !txb2b) { ++ u32 tarc0; ++ tarc0 = E1000_READ_REG(&adapter->hw, TARC0); ++ tarc0 &= ~(1 << 21); ++ E1000_WRITE_REG(&adapter->hw, TARC0, tarc0); ++ } ++ /* disable TSO for pcie and 10/100 speeds, to avoid ++ * some hardware issues */ ++ if (!adapter->tso_force && ++ hw->bus_type == iegbe_bus_type_pci_express){ ++ switch (adapter->link_speed) { ++ case SPEED_10: ++ case SPEED_100: ++ DPRINTK(PROBE,INFO, ++ "10/100 speed: disabling TSO\n"); ++ netdev->features &= ~NETIF_F_TSO; ++ netdev->features &= ~NETIF_F_TSO6; ++ break; ++ case SPEED_1000: ++ netdev->features |= NETIF_F_TSO; ++ netdev->features |= NETIF_F_TSO6; ++ break; ++ default: ++ break; ++ } ++ } ++ tctl = E1000_READ_REG(&adapter->hw, TCTL); ++ tctl |= E1000_TCTL_EN; ++ E1000_WRITE_REG(&adapter->hw, TCTL, tctl); ++ netif_carrier_on(netdev); ++ netif_wake_queue(netdev); ++ mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); + adapter->smartspeed = 0; ++ } else { ++ if (hw->rx_needs_kicking) { ++ u32 rctl = E1000_READ_REG(&adapter->hw, RCTL); ++ E1000_WRITE_REG(&adapter->hw, RCTL, rctl | E1000_RCTL_EN); ++ } + } +- } else { +- if (netif_carrier_ok(netdev)) { ++ } else { ++ if (netif_carrier_ok(netdev)) { + adapter->link_speed = 0; + adapter->link_duplex = 0; +- DPRINTK(LINK, INFO, "NIC Link is Down\n"); +- netif_carrier_off(netdev); +- netif_stop_queue(netdev); +- mod_timer(&adapter->phy_info_timer, jiffies + 0x2 * HZ); +- } ++ DPRINTK(LINK, INFO, "NIC Link is Down\n"); ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); ++ } + +- iegbe_smartspeed(adapter); +- } ++ iegbe_smartspeed(adapter); ++ } ++ ++ iegbe_update_stats(adapter); ++ ++ hw->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; ++ adapter->tpt_old = adapter->stats.tpt; ++ hw->collision_delta = adapter->stats.colc - adapter->colc_old; ++ adapter->colc_old = adapter->stats.colc; ++ ++ adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old; ++ adapter->gorcl_old = adapter->stats.gorcl; ++ adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old; ++ adapter->gotcl_old = adapter->stats.gotcl; ++ ++ iegbe_update_adaptive(hw); ++ ++ if (!netif_carrier_ok(netdev)) { ++ if (E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { ++ /* We've lost link, so the controller stops DMA, ++ * but we've got queued Tx work that's never going ++ * to get done, so reset controller to flush Tx. ++ * (Do the reset outside of interrupt context). */ ++ adapter->tx_timeout_count++; ++ schedule_work(&adapter->reset_task); ++ } ++ } ++ ++ /* Cause software interrupt to ensure rx ring is cleaned */ ++ E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0); ++ ++ /* Force detection of hung controller every watchdog period */ ++ adapter->detect_tx_hung = TRUE; ++ ++ /* With 82571 controllers, LAA may be overwritten due to controller ++ * reset from the other port. Set the appropriate LAA in RAR[0] */ ++ if (adapter->hw.mac_type == iegbe_82571 && adapter->hw.laa_is_present) { ++ iegbe_rar_set(&adapter->hw, adapter->hw.mac_addr, 0x0); ++ } ++ /* Reset the timer */ ++ mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ)); ++} ++ ++enum latency_range { ++ lowest_latency = 0, ++ low_latency = 1, ++ bulk_latency = 2, ++ latency_invalid = 255 ++}; + +- iegbe_update_stats(adapter); ++/** ++ * iegbe_update_itr - update the dynamic ITR value based on statistics ++ * Stores a new ITR value based on packets and byte ++ * counts during the last interrupt. The advantage of per interrupt ++ * computation is faster updates and more accurate ITR for the current ++ * traffic pattern. Constants in this function were computed ++ * based on theoretical maximum wire speed and thresholds were set based ++ * on testing data as well as attempting to minimize response time ++ * while increasing bulk throughput. ++ * this functionality is controlled by the InterruptThrottleRate module ++ * parameter (see iegbe_param.c) ++ * @adapter: pointer to adapter ++ * @itr_setting: current adapter->itr ++ * @packets: the number of packets during this measurement interval ++ * @bytes: the number of bytes during this measurement interval ++ **/ ++static unsigned int iegbe_update_itr(struct iegbe_adapter *adapter, ++ u16 itr_setting, int packets, int bytes) ++{ ++ unsigned int retval = itr_setting; ++ struct iegbe_hw *hw = &adapter->hw; + +- adapter->hw.tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; +- adapter->tpt_old = adapter->stats.tpt; +- adapter->hw.collision_delta = adapter->stats.colc - adapter->colc_old; +- adapter->colc_old = adapter->stats.colc; +- +- adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old; +- adapter->gorcl_old = adapter->stats.gorcl; +- adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old; +- adapter->gotcl_old = adapter->stats.gotcl; +- +- iegbe_update_adaptive(&adapter->hw); +- +- if (adapter->num_queues == 0x1 && !netif_carrier_ok(netdev)) { +- if (E1000_DESC_UNUSED(txdr) + 0x1 < txdr->count) { +- /* We've lost link, so the controller stops DMA, +- * but we've got queued Tx work that's never going +- * to get done, so reset controller to flush Tx. +- * (Do the reset outside of interrupt context). */ +- schedule_work(&adapter->tx_timeout_task); ++ if (unlikely(hw->mac_type < iegbe_82540)) ++ goto update_itr_done; ++ ++ if (packets == 0) ++ goto update_itr_done; ++ ++ switch (itr_setting) { ++ case lowest_latency: ++ /* jumbo frames get bulk treatment*/ ++ if (bytes/packets > 8000) ++ retval = bulk_latency; ++ else if ((packets < 5) && (bytes > 512)) ++ retval = low_latency; ++ break; ++ case low_latency: /* 50 usec aka 20000 ints/s */ ++ if (bytes > 10000) { ++ /* jumbo frames need bulk latency setting */ ++ if (bytes/packets > 8000) ++ retval = bulk_latency; ++ else if ((packets < 10) || ((bytes/packets) > 1200)) ++ retval = bulk_latency; ++ else if ((packets > 35)) ++ retval = lowest_latency; ++ } else if (bytes/packets > 2000) ++ retval = bulk_latency; ++ else if (packets <= 2 && bytes < 512) ++ retval = lowest_latency; ++ break; ++ case bulk_latency: /* 250 usec aka 4000 ints/s */ ++ if (bytes > 25000) { ++ if (packets > 35) ++ retval = low_latency; ++ } else if (bytes < 6000) { ++ retval = low_latency; + } ++ break; + } + +- /* Dynamic mode for Interrupt Throttle Rate (ITR) */ +- if (adapter->hw.mac_type >= iegbe_82540 && adapter->itr == 0x1) { +- /* Symmetric Tx/Rx gets a reduced ITR=2000; Total +- * asymmetrical Tx or Rx gets ITR=8000; everyone +- * else is between 2000-8000. */ +- uint32_t goc = (adapter->gotcl + adapter->gorcl) / 0x2710; +- uint32_t dif = (adapter->gotcl > adapter->gorcl ? +- adapter->gotcl - adapter->gorcl : +- adapter->gorcl - adapter->gotcl) / 0x2710; +- uint32_t itr = goc > 0 ? (dif * 0x1770 / goc + 0x7d0) : 0x1f40; +- E1000_WRITE_REG(&adapter->hw, ITR, 0x3b9aca00 / (itr * 0x100)); +- } ++update_itr_done: ++ return retval; ++} + +- /* Cause software interrupt to ensure rx ring is cleaned */ +- E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0); ++static void iegbe_set_itr(struct iegbe_adapter *adapter) ++{ ++ struct iegbe_hw *hw = &adapter->hw; ++ u16 current_itr; ++ u32 new_itr = adapter->itr; + +- /* Force detection of hung controller every watchdog period */ +- adapter->detect_tx_hung = TRUE; ++ if (unlikely(hw->mac_type < iegbe_82540)) ++ return; + +- /* With 82571 controllers, LAA may be overwritten due to controller +- * reset from the other port. Set the appropriate LAA in RAR[0] */ +- if (adapter->hw.mac_type == iegbe_82571 && adapter->hw.laa_is_present) { +- iegbe_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); +- } +- /* Reset the timer */ +- mod_timer(&adapter->watchdog_timer, jiffies + 0x2 * HZ); ++ /* for non-gigabit speeds, just fix the interrupt rate at 4000 */ ++ if (unlikely(adapter->link_speed != SPEED_1000)) { ++ current_itr = 0; ++ new_itr = 4000; ++ goto set_itr_now; ++ } ++ ++ adapter->tx_itr = iegbe_update_itr(adapter, ++ adapter->tx_itr, ++ adapter->total_tx_packets, ++ adapter->total_tx_bytes); ++ /* conservative mode (itr 3) eliminates the lowest_latency setting */ ++ if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency) ++ adapter->tx_itr = low_latency; ++ ++ adapter->rx_itr = iegbe_update_itr(adapter, ++ adapter->rx_itr, ++ adapter->total_rx_packets, ++ adapter->total_rx_bytes); ++ /* conservative mode (itr 3) eliminates the lowest_latency setting */ ++ if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency) ++ adapter->rx_itr = low_latency; ++ ++ current_itr = max(adapter->rx_itr, adapter->tx_itr); ++ ++ switch (current_itr) { ++ /* counts and packets in update_itr are dependent on these numbers */ ++ case lowest_latency: ++ new_itr = 70000; ++ break; ++ case low_latency: ++ new_itr = 20000; /* aka hwitr = ~200 */ ++ break; ++ case bulk_latency: ++ new_itr = 4000; ++ break; ++ default: ++ break; ++ } ++ ++set_itr_now: ++ if (new_itr != adapter->itr) { ++ /* this attempts to bias the interrupt rate towards Bulk ++ * by adding intermediate steps when interrupt rate is ++ * increasing */ ++ new_itr = new_itr > adapter->itr ? ++ min(adapter->itr + (new_itr >> 2), new_itr) : ++ new_itr; ++ adapter->itr = new_itr; ++ E1000_WRITE_REG(&adapter->hw, ITR, 1000000000 / (new_itr * 256)); ++ } ++ ++ return; + } + + #define E1000_TX_FLAGS_CSUM 0x00000001 +@@ -2673,55 +2641,48 @@ iegbe_watchdog(unsigned long data) + #define E1000_TX_FLAGS_VLAN_MASK 0xffff0000 + #define E1000_TX_FLAGS_VLAN_SHIFT 16 + +-static inline int +-iegbe_tso(struct iegbe_adapter *adapter, struct iegbe_tx_ring *tx_ring, +- struct sk_buff *skb) ++static int iegbe_tso(struct iegbe_adapter *adapter, ++ struct iegbe_tx_ring *tx_ring, struct sk_buff *skb) + { +-#ifdef NETIF_F_TSO + struct iegbe_context_desc *context_desc; ++ struct iegbe_buffer *buffer_info; + unsigned int i; +- uint32_t cmd_length = 0; +- uint16_t ipcse = 0, tucse, mss; +- uint8_t ipcss, ipcso, tucss, tucso, hdr_len; ++ u32 cmd_length = 0; ++ u16 ipcse = 0, tucse, mss; ++ u8 ipcss, ipcso, tucss, tucso, hdr_len; + int err; + + if (skb_is_gso(skb)) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); +- if (err) { ++ if (err) + return err; + } +- } + +- hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 0x2)); ++ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + mss = skb_shinfo(skb)->gso_size; + if (skb->protocol == htons(ETH_P_IP)) { +- skb->nh.iph->tot_len = 0; +- skb->nh.iph->check = 0; +- skb->h.th->check = +- ~csum_tcpudp_magic(skb->nh.iph->saddr, +- skb->nh.iph->daddr, +- 0, +- IPPROTO_TCP, +- 0); ++ struct iphdr *iph = ip_hdr(skb); ++ iph->tot_len = 0; ++ iph->check = 0; ++ tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, ++ iph->daddr, 0, ++ IPPROTO_TCP, ++ 0); + cmd_length = E1000_TXD_CMD_IP; +- ipcse = skb->h.raw - skb->data - 0x1; +-#ifdef NETIF_F_TSO_IPV6 +- } else if (skb->protocol == ntohs(ETH_P_IPV6)) { +- skb->nh.ipv6h->payload_len = 0; +- skb->h.th->check = +- ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, +- &skb->nh.ipv6h->daddr, +- 0, +- IPPROTO_TCP, +- 0); ++ ipcse = skb_transport_offset(skb) - 1; ++ } else if (skb->protocol == htons(ETH_P_IPV6)) { ++ ipv6_hdr(skb)->payload_len = 0; ++ tcp_hdr(skb)->check = ++ ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr, ++ 0, IPPROTO_TCP, 0); + ipcse = 0; +-#endif + } +- ipcss = skb->nh.raw - skb->data; +- ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data; +- tucss = skb->h.raw - skb->data; +- tucso = (void *)&(skb->h.th->check) - (void *)skb->data; ++ ipcss = skb_network_offset(skb); ++ ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data; ++ tucss = skb_transport_offset(skb); ++ tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data; + tucse = 0; + + cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | +@@ -2729,6 +2690,7 @@ iegbe_tso(struct iegbe_adapter *adapter, + + i = tx_ring->next_to_use; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); ++ buffer_info = &tx_ring->buffer_info[i]; + + context_desc->lower_setup.ip_fields.ipcss = ipcss; + context_desc->lower_setup.ip_fields.ipcso = ipcso; +@@ -2740,205 +2702,218 @@ iegbe_tso(struct iegbe_adapter *adapter, + context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; + context_desc->cmd_and_length = cpu_to_le32(cmd_length); + +- if (++i == tx_ring->count) { i = 0; } ++ buffer_info->time_stamp = jiffies; ++ buffer_info->next_to_watch = i; ++ ++ if (++i == tx_ring->count) i = 0; + tx_ring->next_to_use = i; + +- return TRUE; ++ return true; + } +-#endif +- +- return FALSE; ++ return false; + } + +-static inline boolean_t +-iegbe_tx_csum(struct iegbe_adapter *adapter, struct iegbe_tx_ring *tx_ring, +- struct sk_buff *skb) ++static bool iegbe_tx_csum(struct iegbe_adapter *adapter, ++ struct iegbe_tx_ring *tx_ring, struct sk_buff *skb) + { + struct iegbe_context_desc *context_desc; ++ struct iegbe_buffer *buffer_info; + unsigned int i; +- uint8_t css; ++ u8 css; + +- if (likely(skb->ip_summed == CHECKSUM_HW)) { +- css = skb->h.raw - skb->data; ++ if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { ++ css = skb_transport_offset(skb); + +- i = tx_ring->next_to_use; +- context_desc = E1000_CONTEXT_DESC(*tx_ring, i); ++ i = tx_ring->next_to_use; ++ buffer_info = &tx_ring->buffer_info[i]; ++ context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + ++ context_desc->lower_setup.ip_config = 0; + context_desc->upper_setup.tcp_fields.tucss = css; +- context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; ++ context_desc->upper_setup.tcp_fields.tucso = ++ css + skb->csum_offset; + context_desc->upper_setup.tcp_fields.tucse = 0; + context_desc->tcp_seg_setup.data = 0; + context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); + +- if (unlikely(++i == tx_ring->count)) { i = 0; } ++ buffer_info->time_stamp = jiffies; ++ buffer_info->next_to_watch = i; ++ ++ if (unlikely(++i == tx_ring->count)) i = 0; + tx_ring->next_to_use = i; + +- return TRUE; ++ return true; + } + +- return FALSE; ++ return false; + } + +-#define E1000_MAX_TXD_PWR 12 +-#define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR) ++#define E1000_MAX_TXD_PWR 12 ++#define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR) + +-static inline int +-iegbe_tx_map(struct iegbe_adapter *adapter, struct iegbe_tx_ring *tx_ring, +- struct sk_buff *skb, unsigned int first, unsigned int max_per_txd, +- unsigned int nr_frags, unsigned int mss) ++static int iegbe_tx_map(struct iegbe_adapter *adapter, ++ struct iegbe_tx_ring *tx_ring, ++ struct sk_buff *skb, unsigned int first, ++ unsigned int max_per_txd, unsigned int nr_frags, ++ unsigned int mss) + { +- struct iegbe_buffer *buffer_info; +- unsigned int len = skb->len; ++ struct iegbe_hw *hw = &adapter->hw; ++ struct iegbe_buffer *buffer_info; ++ unsigned int len = skb->len; + unsigned int offset = 0, size, count = 0, i; +-#ifdef MAX_SKB_FRAGS +- unsigned int f; +- len -= skb->data_len; +-#endif ++ unsigned int f; ++ len -= skb->data_len; + +- i = tx_ring->next_to_use; ++ i = tx_ring->next_to_use; ++ ++ while(len) { ++ buffer_info = &tx_ring->buffer_info[i]; ++ size = min(len, max_per_txd); ++ /* Workaround for Controller erratum -- ++ * descriptor for non-tso packet in a linear SKB that follows a ++ * tso gets written back prematurely before the data is fully ++ * DMA'd to the controller */ ++ if (!skb->data_len && tx_ring->last_tx_tso && ++ !skb_is_gso(skb)) { ++ tx_ring->last_tx_tso = 0; ++ size -= 4; ++ } + +- while(len) { +- buffer_info = &tx_ring->buffer_info[i]; +- size = min(len, max_per_txd); +-#ifdef NETIF_F_TSO + /* Workaround for premature desc write-backs + * in TSO mode. Append 4-byte sentinel desc */ +- if(unlikely(mss && !nr_frags && size == len && size > 0x8)) { +- size -= 0x4; ++ if (unlikely(mss && !nr_frags && size == len && size > 8)) ++ size -= 4; ++ /* work-around for errata 10 and it applies ++ * to all controllers in PCI-X mode ++ * The fix is to make sure that the first descriptor of a ++ * packet is smaller than 2048 - 16 - 16 (or 2016) bytes ++ */ ++ if (unlikely((hw->bus_type == iegbe_bus_type_pcix) && ++ (size > 2015) && count == 0)) ++ size = 2015; ++ ++ /* Workaround for potential 82544 hang in PCI-X. Avoid ++ * terminating buffers within evenly-aligned dwords. */ ++ if(unlikely(adapter->pcix_82544 && ++ !((unsigned long)(skb->data + offset + size - 1) & 4) && ++ size > 4)) ++ size -= 4; ++ ++ buffer_info->length = size; ++ buffer_info->dma = ++ pci_map_single(adapter->pdev, ++ skb->data + offset, ++ size, ++ PCI_DMA_TODEVICE); ++ buffer_info->time_stamp = jiffies; ++ buffer_info->next_to_watch = i; ++ ++ len -= size; ++ offset += size; ++ count++; ++ if (unlikely(++i == tx_ring->count)) i = 0; ++ } ++ ++ for (f = 0; f < nr_frags; f++) { ++ struct skb_frag_struct *frag; ++ ++ frag = &skb_shinfo(skb)->frags[f]; ++ len = frag->size; ++ offset = frag->page_offset; ++ ++ while(len) { ++ buffer_info = &tx_ring->buffer_info[i]; ++ size = min(len, max_per_txd); ++ /* Workaround for premature desc write-backs ++ * in TSO mode. Append 4-byte sentinel desc */ ++ if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8)) ++ size -= 4; ++ /* Workaround for potential 82544 hang in PCI-X. ++ * Avoid terminating buffers within evenly-aligned ++ * dwords. */ ++ if(unlikely(adapter->pcix_82544 && ++ !((unsigned long)(frag->page+offset+size-1) & 4) && ++ size > 4)) ++ size -= 4; ++ ++ buffer_info->length = size; ++ buffer_info->dma = ++ pci_map_page(adapter->pdev, ++ frag->page, ++ offset, ++ size, ++ PCI_DMA_TODEVICE); ++ buffer_info->time_stamp = jiffies; ++ buffer_info->next_to_watch = i; ++ ++ len -= size; ++ offset += size; ++ count++; ++ if (unlikely(++i == tx_ring->count)) i = 0; + } +-#endif +- /* work-around for errata 10 and it applies +- * to all controllers in PCI-X mode +- * The fix is to make sure that the first descriptor of a +- * packet is smaller than 2048 - 16 - 16 (or 2016) bytes +- */ +- if(unlikely((adapter->hw.bus_type == iegbe_bus_type_pcix) && +- (size > 0x7df) && count == 0)) { +- size = 0x7df; +- } +- /* Workaround for potential 82544 hang in PCI-X. Avoid +- * terminating buffers within evenly-aligned dwords. */ +- if(unlikely(adapter->pcix_82544 && +- !((unsigned long)(skb->data + offset + size - 0x8) & 0x4) && +- size > 0x4)) { +- size -= 0x4; +- } +- buffer_info->length = size; +- buffer_info->dma = +- pci_map_single(adapter->pdev, +- skb->data + offset, +- size, +- PCI_DMA_TODEVICE); +- buffer_info->time_stamp = jiffies; +- +- len -= size; +- offset += size; +- count++; +- if(unlikely(++i == tx_ring->count)) { i = 0; } +- } +- +-#ifdef MAX_SKB_FRAGS +- for(f = 0; f < nr_frags; f++) { +- struct skb_frag_struct *frag; +- +- frag = &skb_shinfo(skb)->frags[f]; +- len = frag->size; +- offset = frag->page_offset; +- +- while(len) { +- buffer_info = &tx_ring->buffer_info[i]; +- size = min(len, max_per_txd); +-#ifdef NETIF_F_TSO +- /* Workaround for premature desc write-backs +- * in TSO mode. Append 4-byte sentinel desc */ +- if(unlikely(mss && f == (nr_frags-0x1) && +- size == len && size > 0x8)) { +- size -= 0x4; +- } +-#endif +- /* Workaround for potential 82544 hang in PCI-X. +- * Avoid terminating buffers within evenly-aligned +- * dwords. */ +- if(unlikely(adapter->pcix_82544 && +- !((unsigned long)(frag->page+offset+size-0x1) & 0x4) && +- size > 0x4)) { +- size -= 0x4; +- } +- buffer_info->length = size; +- buffer_info->dma = +- pci_map_page(adapter->pdev, +- frag->page, +- offset, +- size, +- PCI_DMA_TODEVICE); +- buffer_info->time_stamp = jiffies; +- +- len -= size; +- offset += size; +- count++; +- if(unlikely(++i == tx_ring->count)) { i = 0; } +- } +- } +-#endif ++ } + +- i = (i == 0) ? tx_ring->count - 0x1 : i - 0x1; +- tx_ring->buffer_info[i].skb = skb; +- tx_ring->buffer_info[first].next_to_watch = i; ++ i = (i == 0) ? tx_ring->count - 1 : i - 1; ++ tx_ring->buffer_info[i].skb = skb; ++ tx_ring->buffer_info[first].next_to_watch = i; + +- return count; ++ return count; + } + +-static inline void +-iegbe_tx_queue(struct iegbe_adapter *adapter, struct iegbe_tx_ring *tx_ring, +- int tx_flags, int count) ++static void iegbe_tx_queue(struct iegbe_adapter *adapter, ++ struct iegbe_tx_ring *tx_ring, int tx_flags, ++ int count) + { ++ struct iegbe_hw *hw = &adapter->hw; + struct iegbe_tx_desc *tx_desc = NULL; + struct iegbe_buffer *buffer_info; +- uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; ++ u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; + unsigned int i; + +- if(likely(tx_flags & E1000_TX_FLAGS_TSO)) { ++ if (likely(tx_flags & E1000_TX_FLAGS_TSO)) { + txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | + E1000_TXD_CMD_TSE; +- txd_upper |= E1000_TXD_POPTS_TXSM << 0x8; ++ txd_upper |= E1000_TXD_POPTS_TXSM << 8; + +- if(likely(tx_flags & E1000_TX_FLAGS_IPV4)) { +- txd_upper |= E1000_TXD_POPTS_IXSM << 0x8; +- } ++ if (likely(tx_flags & E1000_TX_FLAGS_IPV4)) ++ txd_upper |= E1000_TXD_POPTS_IXSM << 8; + } + +- if(likely(tx_flags & E1000_TX_FLAGS_CSUM)) { ++ if (likely(tx_flags & E1000_TX_FLAGS_CSUM)) { + txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; +- txd_upper |= E1000_TXD_POPTS_TXSM << 0x8; +- } +- +- if(unlikely(tx_flags & E1000_TX_FLAGS_VLAN)) { +- txd_lower |= E1000_TXD_CMD_VLE; +- txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); ++ txd_upper |= E1000_TXD_POPTS_TXSM << 8; + } + +- i = tx_ring->next_to_use; ++ if(unlikely(tx_flags & E1000_TX_FLAGS_VLAN)) { ++ txd_lower |= E1000_TXD_CMD_VLE; ++ txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); ++ } + +- while(count--) { +- buffer_info = &tx_ring->buffer_info[i]; +- tx_desc = E1000_TX_DESC(*tx_ring, i); +- tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); +- tx_desc->lower.data = +- cpu_to_le32(txd_lower | buffer_info->length); +- tx_desc->upper.data = cpu_to_le32(txd_upper); +- if(unlikely(++i == tx_ring->count)) { i = 0; } +- } +- if(tx_desc != NULL) { +- tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); +- } +- /* Force memory writes to complete before letting h/w +- * know there are new descriptors to fetch. (Only +- * applicable for weak-ordered memory model archs, +- * such as IA-64). */ +- wmb(); ++ i = tx_ring->next_to_use; + +- tx_ring->next_to_use = i; +- writel(i, adapter->hw.hw_addr + tx_ring->tdt); ++ while(count--) { ++ buffer_info = &tx_ring->buffer_info[i]; ++ tx_desc = E1000_TX_DESC(*tx_ring, i); ++ tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); ++ tx_desc->lower.data = ++ cpu_to_le32(txd_lower | buffer_info->length); ++ tx_desc->upper.data = cpu_to_le32(txd_upper); ++ if (unlikely(++i == tx_ring->count)) i = 0; ++ } ++ ++ tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); ++ ++ /* Force memory writes to complete before letting h/w ++ * know there are new descriptors to fetch. (Only ++ * applicable for weak-ordered memory model archs, ++ * such as IA-64). */ ++ wmb(); ++ ++ tx_ring->next_to_use = i; ++ writel(i, hw->hw_addr + tx_ring->tdt); ++ /* we need this if more than one processor can write to our tail ++ * at a time, it syncronizes IO on IA64/Altix systems */ ++ mmiowb(); + } + + /** +@@ -2950,113 +2925,132 @@ iegbe_tx_queue(struct iegbe_adapter *ada + * to the beginning of the Tx FIFO. + **/ + +-static inline int +-iegbe_82547_fifo_workaround(struct iegbe_adapter *adapter, struct sk_buff *skb) ++#define E1000_FIFO_HDR 0x10 ++#define E1000_82547_PAD_LEN 0x3E0 ++static int iegbe_82547_fifo_workaround(struct iegbe_adapter *adapter, ++ struct sk_buff *skb) + { +- uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head; +- uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR; ++ u32 fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head; ++ u32 skb_fifo_len = skb->len + E1000_FIFO_HDR; + +- E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR); ++ skb_fifo_len = ALIGN(skb_fifo_len, E1000_FIFO_HDR); + +- if(adapter->link_duplex != HALF_DUPLEX) { +- goto no_fifo_stall_required; +- } +- if(atomic_read(&adapter->tx_fifo_stall)) { +- return 1; ++ if (adapter->link_duplex != HALF_DUPLEX) ++ goto no_fifo_stall_required; ++ ++ if (atomic_read(&adapter->tx_fifo_stall)) ++ return 1; ++ ++ if(skb_fifo_len >= (E1000_82547_PAD_LEN + fifo_space)) { ++ atomic_set(&adapter->tx_fifo_stall, 1); ++ return 1; + } +- if(skb_fifo_len >= (E1000_82547_PAD_LEN + fifo_space)) { +- atomic_set(&adapter->tx_fifo_stall, 0x1); +- return 1; +- } + + no_fifo_stall_required: +- adapter->tx_fifo_head += skb_fifo_len; +- if(adapter->tx_fifo_head >= adapter->tx_fifo_size) { +- adapter->tx_fifo_head -= adapter->tx_fifo_size; +- } ++ adapter->tx_fifo_head += skb_fifo_len; ++ if (adapter->tx_fifo_head >= adapter->tx_fifo_size) ++ adapter->tx_fifo_head -= adapter->tx_fifo_size; + return 0; + } + +-static inline int +-iegbe_transfer_dhcp_info(struct iegbe_adapter *adapter, struct sk_buff *skb) ++#define MINIMUM_DHCP_PACKET_SIZE 282 ++static int iegbe_transfer_dhcp_info(struct iegbe_adapter *adapter, ++ struct sk_buff *skb) + { + struct iegbe_hw *hw = &adapter->hw; +- uint16_t length, offset; +-#ifdef NETIF_F_HW_VLAN_TX +- if(vlan_tx_tag_present(skb)) { +- if(!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) && +- ( adapter->hw.mng_cookie.status & +- E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) ) { ++ u16 length, offset; ++ if (vlan_tx_tag_present(skb)) { ++ if (!((vlan_tx_tag_get(skb) == hw->mng_cookie.vlan_id) && ++ ( hw->mng_cookie.status & ++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) ) + return 0; + } +- } +-#endif +- if(htons(ETH_P_IP) == skb->protocol) { +- const struct iphdr *ip = skb->nh.iph; +- if(IPPROTO_UDP == ip->protocol) { +- struct udphdr *udp = (struct udphdr *)(skb->h.uh); +- if(ntohs(udp->dest) == 0x43) { /* 0x43 = 67 */ +- offset = (uint8_t *)udp + 0x8 - skb->data; +- length = skb->len - offset; +- +- return iegbe_mng_write_dhcp_info(hw, +- (uint8_t *)udp + 0x8, length); +- } +- } +- } else if((skb->len > MINIMUM_DHCP_PACKET_SIZE) && (!skb->protocol)) { +- struct ethhdr *eth = (struct ethhdr *) skb->data; +- if((htons(ETH_P_IP) == eth->h_proto)) { ++ if (skb->len > MINIMUM_DHCP_PACKET_SIZE) { ++ struct ethhdr *eth = (struct ethhdr *)skb->data; ++ if ((htons(ETH_P_IP) == eth->h_proto)) { + const struct iphdr *ip = +- (struct iphdr *)((uint8_t *)skb->data+0xe); +- if(IPPROTO_UDP == ip->protocol) { ++ (struct iphdr *)((u8 *)skb->data+14); ++ if (IPPROTO_UDP == ip->protocol) { + struct udphdr *udp = +- (struct udphdr *)((uint8_t *)ip + +- (ip->ihl << 0x2)); +- if(ntohs(udp->dest) == 0x43) { +- offset = (uint8_t *)udp + 0x8 - skb->data; ++ (struct udphdr *)((u8 *)ip + ++ (ip->ihl << 2)); ++ if (ntohs(udp->dest) == 67) { ++ offset = (u8 *)udp + 8 - skb->data; + length = skb->len - offset; + + return iegbe_mng_write_dhcp_info(hw, +- (uint8_t *)udp + 0x8, ++ (u8 *)udp + 8, + length); +- } ++ } + } + } + } + return 0; + } + +-static int +-iegbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) ++static int __iegbe_maybe_stop_tx(struct net_device *netdev, int size) ++{ ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct iegbe_tx_ring *tx_ring = adapter->tx_ring; ++ ++ netif_stop_queue(netdev); ++ /* Herbert's original patch had: ++ * smp_mb__after_netif_stop_queue(); ++ * but since that doesn't exist yet, just open code it. */ ++ smp_mb(); ++ ++ /* We need to check again in a case another CPU has just ++ * made room available. */ ++ if (likely(E1000_DESC_UNUSED(tx_ring) < size)) ++ return -EBUSY; ++ ++ /* A reprieve! */ ++ netif_start_queue(netdev); ++ ++adapter->restart_queue; ++ return 0; ++} ++ ++static int iegbe_maybe_stop_tx(struct net_device *netdev, ++ struct iegbe_tx_ring *tx_ring, int size) ++{ ++ if (likely(E1000_DESC_UNUSED(tx_ring) >= size)) ++ return 0; ++ return __iegbe_maybe_stop_tx(netdev, size); ++} ++ ++#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) ++static int iegbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) + { + struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct iegbe_hw *hw = &adapter->hw; + struct iegbe_tx_ring *tx_ring; + unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD; + unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; + unsigned int tx_flags = 0; +- unsigned int len = skb->len; ++ unsigned int len = skb->len - skb->data_len; + unsigned long flags = 0; +- unsigned int nr_frags = 0; +- unsigned int mss = 0; ++ unsigned int nr_frags; ++ unsigned int mss; + int count = 0; +- int tso; +-#ifdef MAX_SKB_FRAGS ++ int tso; + unsigned int f; +- len -= skb->data_len; +-#endif + +-#ifdef CONFIG_E1000_MQ +- tx_ring = *per_cpu_ptr(adapter->cpu_tx_ring, smp_processor_id()); +-#else ++ /* This goes back to the question of how to logically map a tx queue ++ * to a flow. Right now, performance is impacted slightly negatively ++ * if using multiple tx queues. If the stack breaks away from a ++ * single qdisc implementation, we can look at this again. */ + tx_ring = adapter->tx_ring; +-#endif + + if (unlikely(skb->len <= 0)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + +-#ifdef NETIF_F_TSO ++ /* 82571 and newer doesn't need the workaround that limited descriptor ++ * length to 4kB */ ++ if (hw->mac_type >= iegbe_82571) ++ max_per_txd = 8192; ++ + mss = skb_shinfo(skb)->gso_size; + /* The controller does a simple calculation to + * make sure there is enough room in the FIFO before +@@ -3064,164 +3058,150 @@ iegbe_xmit_frame(struct sk_buff *skb, st + * 4 = ceil(buffer len/mss). To make sure we don't + * overrun the FIFO, adjust the max buffer len if mss + * drops. */ +- if(mss) { +- max_per_txd = min(mss << 0x2, max_per_txd); +- max_txd_pwr = fls(max_per_txd) - 0x1; ++ if (mss) { ++ u8 hdr_len; ++ max_per_txd = min(mss << 2, max_per_txd); ++ max_txd_pwr = fls(max_per_txd) - 1; ++ ++ /* TSO Workaround for 82571/2/3 Controllers -- if skb->data ++ * points to just header, pull a few bytes of payload from ++ * frags into skb->data */ ++ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); ++ if (skb->data_len && hdr_len == len) { ++ switch (hw->mac_type) { ++ case iegbe_82544: ++ /* Make sure we have room to chop off 4 bytes, ++ * and that the end alignment will work out to ++ * this hardware's requirements ++ * NOTE: this is a TSO only workaround ++ * if end byte alignment not correct move us ++ * into the next dword */ ++ break; ++ /* fall through */ ++ case iegbe_82571: ++ case iegbe_82572: ++ case iegbe_82573: ++ break; ++ default: ++ /* do nothing */ ++ break; ++ } ++ } + } + +- if((mss) || (skb->ip_summed == CHECKSUM_HW)) { ++ /* reserve a descriptor for the offload context */ ++ if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL)) + count++; +- } + count++; +-#else +- if(skb->ip_summed == CHECKSUM_HW) { ++ ++ /* Controller Erratum workaround */ ++ if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb)) + count++; +- { +-#endif ++ + count += TXD_USE_COUNT(len, max_txd_pwr); + +- if(adapter->pcix_82544) { ++ if (adapter->pcix_82544) + count++; +- } ++ + /* work-around for errata 10 and it applies to all controllers + * in PCI-X mode, so add one more descriptor to the count + */ +- if(unlikely((adapter->hw.bus_type == iegbe_bus_type_pcix) && +- (len > 0x7df))) { ++ if (unlikely((hw->bus_type == iegbe_bus_type_pcix) && ++ (len > 2015))) + count++; +- } +-#ifdef MAX_SKB_FRAGS ++ + nr_frags = skb_shinfo(skb)->nr_frags; +- for(f = 0; f < nr_frags; f++) ++ for (f = 0; f < nr_frags; f++) + count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, + max_txd_pwr); +- if(adapter->pcix_82544) { ++ if (adapter->pcix_82544) + count += nr_frags; +- } +-#ifdef NETIF_F_TSO +- /* TSO Workaround for 82571/2 Controllers -- if skb->data +- * points to just header, pull a few bytes of payload from +- * frags into skb->data */ +- if (skb_is_gso(skb)) { +- uint8_t hdr_len; +- hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 0x2)); +- if (skb->data_len && (hdr_len < (skb->len - skb->data_len)) && +- (adapter->hw.mac_type == iegbe_82571 || +- adapter->hw.mac_type == iegbe_82572)) { +- unsigned int pull_size; +- pull_size = min((unsigned int)0x4, skb->data_len); +- if (!__pskb_pull_tail(skb, pull_size)) { +- printk(KERN_ERR "__pskb_pull_tail failed.\n"); +- dev_kfree_skb_any(skb); +- return -EFAULT; +- } +- } +- } +-#endif +-#endif + +- if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == iegbe_82573) ) { ++ ++ if (hw->tx_pkt_filtering && ++ (hw->mac_type == iegbe_82573)) + iegbe_transfer_dhcp_info(adapter, skb); +- } +-#ifdef NETIF_F_LLTX +- local_irq_save(flags); +- if (!spin_trylock(&tx_ring->tx_lock)) { ++ ++ if (!spin_trylock_irqsave(&tx_ring->tx_lock, flags)) + /* Collision - tell upper layer to requeue */ +- local_irq_restore(flags); + return NETDEV_TX_LOCKED; +- } +-#else +- spin_lock_irqsave(&tx_ring->tx_lock, flags); +-#endif + + /* need: count + 2 desc gap to keep tail from touching + * head, otherwise try next time */ +- if (unlikely(E1000_DESC_UNUSED(tx_ring) < count + 0x2)) { +- netif_stop_queue(netdev); ++ if (unlikely(iegbe_maybe_stop_tx(netdev, tx_ring, count + 2))) { + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); + return NETDEV_TX_BUSY; + } + +- if(unlikely(adapter->hw.mac_type == iegbe_82547)) { +- if(unlikely(iegbe_82547_fifo_workaround(adapter, skb))) { ++ if (unlikely(hw->mac_type == iegbe_82547)) { ++ if (unlikely(iegbe_82547_fifo_workaround(adapter, skb))) { + netif_stop_queue(netdev); +- mod_timer(&adapter->tx_fifo_stall_timer, jiffies); ++ mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); + return NETDEV_TX_BUSY; + } + } + +-#ifndef NETIF_F_LLTX +- spin_unlock_irqrestore(&tx_ring->tx_lock, flags); +-#endif +- +-#ifdef NETIF_F_HW_VLAN_TX +- if(unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) { ++ if (unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) { + tx_flags |= E1000_TX_FLAGS_VLAN; + tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); + } +-#endif + + first = tx_ring->next_to_use; + + tso = iegbe_tso(adapter, tx_ring, skb); + if (tso < 0) { + dev_kfree_skb_any(skb); +-#ifdef NETIF_F_LLTX + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); +-#endif + return NETDEV_TX_OK; + } + +- if (likely(tso)) { ++ if (likely(tso)) { ++ tx_ring->last_tx_tso = 1; + tx_flags |= E1000_TX_FLAGS_TSO; +- } else if (likely(iegbe_tx_csum(adapter, tx_ring, skb))) { ++ } else if (likely(iegbe_tx_csum(adapter, tx_ring, skb))) + tx_flags |= E1000_TX_FLAGS_CSUM; +- } ++ + /* Old method was to assume IPv4 packet by default if TSO was enabled. + * 82571 hardware supports TSO capabilities for IPv6 as well... + * no longer assume, we must. */ +- if (likely(skb->protocol == ntohs(ETH_P_IP))) { ++ if (likely(skb->protocol == htons(ETH_P_IP))) + tx_flags |= E1000_TX_FLAGS_IPV4; +- } ++ + iegbe_tx_queue(adapter, tx_ring, tx_flags, + iegbe_tx_map(adapter, tx_ring, skb, first, + max_per_txd, nr_frags, mss)); + + netdev->trans_start = jiffies; + +-#ifdef NETIF_F_LLTX + /* Make sure there is space in the ring for the next send. */ +- if (unlikely(E1000_DESC_UNUSED(tx_ring) < MAX_SKB_FRAGS + 0x2)) { +- netif_stop_queue(netdev); +- } +- spin_unlock_irqrestore(&tx_ring->tx_lock, flags); +-#endif ++ iegbe_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2); + ++ spin_unlock_irqrestore(&tx_ring->tx_lock, flags); + return NETDEV_TX_OK; + } + ++ + /** + * iegbe_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ + +-static void +-iegbe_tx_timeout(struct net_device *netdev) ++static void iegbe_tx_timeout(struct net_device *netdev) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct iegbe_adapter *adapter = netdev_priv(netdev); + +- /* Do the reset outside of interrupt context */ +- schedule_work(&adapter->tx_timeout_task); ++ /* Do the reset outside of interrupt context */ ++ adapter->tx_timeout_count++; ++ schedule_work(&adapter->reset_task); + } + +-static void +-iegbe_tx_timeout_task(struct net_device *netdev) ++static void iegbe_reset_task(struct work_struct *work) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct iegbe_adapter *adapter = ++ container_of(work, struct iegbe_adapter, reset_task); + +- iegbe_down(adapter); +- iegbe_up(adapter); ++ iegbe_reinit_locked(adapter); + } + + /** +@@ -3232,13 +3212,12 @@ iegbe_tx_timeout_task(struct net_device + * The statistics are actually updated from the timer callback. + **/ + +-static struct net_device_stats * +-iegbe_get_stats(struct net_device *netdev) ++static struct net_device_stats *iegbe_get_stats(struct net_device *netdev) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct iegbe_adapter *adapter = netdev_priv(netdev); + +- iegbe_update_stats(adapter); +- return &adapter->net_stats; ++ /* only return the current stats */ ++ return &adapter->net_stats; + } + + /** +@@ -3249,67 +3228,55 @@ iegbe_get_stats(struct net_device *netde + * Returns 0 on success, negative on failure + **/ + +-static int +-iegbe_change_mtu(struct net_device *netdev, int new_mtu) ++static int iegbe_change_mtu(struct net_device *netdev, int new_mtu) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct iegbe_hw *hw = &adapter->hw; ++ int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + +- if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || +- (max_frame > MAX_JUMBO_FRAME_SIZE)) { +- DPRINTK(PROBE, ERR, "Invalid MTU setting\n"); +- return -EINVAL; +- } ++ if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || ++ (max_frame > MAX_JUMBO_FRAME_SIZE)) { ++ DPRINTK(PROBE, ERR, "Invalid MTU setting\n"); ++ return -EINVAL; ++ } + ++ /* Adapter-specific max frame size limits. */ ++ switch (hw->mac_type) { ++ case iegbe_undefined ... iegbe_82542_rev2_1: ++ if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { ++ DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n"); ++ return -EINVAL; ++ } ++ break; ++ case iegbe_82571: ++ case iegbe_82572: + #define MAX_STD_JUMBO_FRAME_SIZE 9234 +- /* might want this to be bigger enum check... */ +- /* 82571 controllers limit jumbo frame size to 10500 bytes */ +- if ((adapter->hw.mac_type == iegbe_82571 || +- adapter->hw.mac_type == iegbe_82572) && +- max_frame > MAX_STD_JUMBO_FRAME_SIZE) { +- DPRINTK(PROBE, ERR, "MTU > 9216 bytes not supported " +- "on 82571 and 82572 controllers.\n"); +- return -EINVAL; +- } +- +- if(adapter->hw.mac_type == iegbe_82573 && +- max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { +- DPRINTK(PROBE, ERR, "Jumbo Frames not supported " +- "on 82573\n"); +- return -EINVAL; +- } +- +- if(adapter->hw.mac_type > iegbe_82547_rev_2) { +- adapter->rx_buffer_len = max_frame; +- E1000_ROUNDUP(adapter->rx_buffer_len, 0x1024); +- } else { +- if(unlikely((adapter->hw.mac_type < iegbe_82543) && +- (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE))) { +- DPRINTK(PROBE, ERR, "Jumbo Frames not supported " +- "on 82542\n"); +- return -EINVAL; +- +- } else { +- if(max_frame <= E1000_RXBUFFER_2048) { +- adapter->rx_buffer_len = E1000_RXBUFFER_2048; +- } else if(max_frame <= E1000_RXBUFFER_4096) { +- adapter->rx_buffer_len = E1000_RXBUFFER_4096; +- } else if(max_frame <= E1000_RXBUFFER_8192) { +- adapter->rx_buffer_len = E1000_RXBUFFER_8192; +- } else if(max_frame <= E1000_RXBUFFER_16384) { +- adapter->rx_buffer_len = E1000_RXBUFFER_16384; +- } ++ if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { ++ DPRINTK(PROBE, ERR, "MTU > 9216 not supported.\n"); ++ return -EINVAL; + } ++ break; ++ default: ++ break; + } ++ if (max_frame <= E1000_RXBUFFER_256) ++ adapter->rx_buffer_len = E1000_RXBUFFER_256; ++ else if (max_frame <= E1000_RXBUFFER_2048) ++ adapter->rx_buffer_len = E1000_RXBUFFER_2048; ++ else if (max_frame <= E1000_RXBUFFER_4096) ++ adapter->rx_buffer_len = E1000_RXBUFFER_4096; ++ else if (max_frame <= E1000_RXBUFFER_8192) ++ adapter->rx_buffer_len = E1000_RXBUFFER_8192; ++ else if (max_frame <= E1000_RXBUFFER_16384) ++ adapter->rx_buffer_len = E1000_RXBUFFER_16384; + +- netdev->mtu = new_mtu; ++ /* adjust allocation if LPE protects us, and we aren't using SBP */ + +- if(netif_running(netdev)) { +- iegbe_down(adapter); +- iegbe_up(adapter); +- } ++ netdev->mtu = new_mtu; ++ hw->max_frame_size = max_frame; + +- adapter->hw.max_frame_size = max_frame; ++ if (netif_running(netdev)) ++ iegbe_reinit_locked(adapter); + + return 0; + } +@@ -3319,224 +3286,189 @@ iegbe_change_mtu(struct net_device *netd + * @adapter: board private structure + **/ + +-void +-iegbe_update_stats(struct iegbe_adapter *adapter) ++void iegbe_update_stats(struct iegbe_adapter *adapter) + { +- struct iegbe_hw *hw = &adapter->hw; +- unsigned long flags = 0; +- uint16_t phy_tmp; ++ struct iegbe_hw *hw = &adapter->hw; ++ unsigned long flags = 0x0; ++ uint16_t phy_tmp; + + #define PHY_IDLE_ERROR_COUNT_MASK 0x00FF + +- spin_lock_irqsave(&adapter->stats_lock, flags); ++ spin_lock_irqsave(&adapter->stats_lock, flags); + +- /* these counters are modified from iegbe_adjust_tbi_stats, +- * called from the interrupt context, so they must only +- * be written while holding adapter->stats_lock +- */ ++ /* these counters are modified from iegbe_adjust_tbi_stats, ++ * called from the interrupt context, so they must only ++ * be written while holding adapter->stats_lock ++ */ + +- adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS); +- adapter->stats.gprc += E1000_READ_REG(hw, GPRC); +- adapter->stats.gorcl += E1000_READ_REG(hw, GORCL); +- adapter->stats.gorch += E1000_READ_REG(hw, GORCH); +- adapter->stats.bprc += E1000_READ_REG(hw, BPRC); +- adapter->stats.mprc += E1000_READ_REG(hw, MPRC); +- adapter->stats.roc += E1000_READ_REG(hw, ROC); +- adapter->stats.prc64 += E1000_READ_REG(hw, PRC64); +- adapter->stats.prc127 += E1000_READ_REG(hw, PRC127); +- adapter->stats.prc255 += E1000_READ_REG(hw, PRC255); +- adapter->stats.prc511 += E1000_READ_REG(hw, PRC511); +- adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023); +- adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522); +- +- adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS); +- adapter->stats.mpc += E1000_READ_REG(hw, MPC); +- adapter->stats.scc += E1000_READ_REG(hw, SCC); +- adapter->stats.ecol += E1000_READ_REG(hw, ECOL); +- adapter->stats.mcc += E1000_READ_REG(hw, MCC); +- adapter->stats.latecol += E1000_READ_REG(hw, LATECOL); +- adapter->stats.dc += E1000_READ_REG(hw, DC); +- adapter->stats.sec += E1000_READ_REG(hw, SEC); +- adapter->stats.rlec += E1000_READ_REG(hw, RLEC); +- adapter->stats.xonrxc += E1000_READ_REG(hw, XONRXC); +- adapter->stats.xontxc += E1000_READ_REG(hw, XONTXC); +- adapter->stats.xoffrxc += E1000_READ_REG(hw, XOFFRXC); +- adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC); +- adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC); +- adapter->stats.gptc += E1000_READ_REG(hw, GPTC); +- adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL); +- adapter->stats.gotch += E1000_READ_REG(hw, GOTCH); +- adapter->stats.rnbc += E1000_READ_REG(hw, RNBC); +- adapter->stats.ruc += E1000_READ_REG(hw, RUC); +- adapter->stats.rfc += E1000_READ_REG(hw, RFC); +- adapter->stats.rjc += E1000_READ_REG(hw, RJC); +- adapter->stats.torl += E1000_READ_REG(hw, TORL); +- adapter->stats.torh += E1000_READ_REG(hw, TORH); +- adapter->stats.totl += E1000_READ_REG(hw, TOTL); +- adapter->stats.toth += E1000_READ_REG(hw, TOTH); +- adapter->stats.tpr += E1000_READ_REG(hw, TPR); +- adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64); +- adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127); +- adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255); +- adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511); +- adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023); +- adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522); +- adapter->stats.mptc += E1000_READ_REG(hw, MPTC); +- adapter->stats.bptc += E1000_READ_REG(hw, BPTC); +- +- /* used for adaptive IFS */ +- +- hw->tx_packet_delta = E1000_READ_REG(hw, TPT); +- adapter->stats.tpt += hw->tx_packet_delta; +- hw->collision_delta = E1000_READ_REG(hw, COLC); +- adapter->stats.colc += hw->collision_delta; +- +- if(hw->mac_type >= iegbe_82543) { +- adapter->stats.algnerrc += E1000_READ_REG(hw, ALGNERRC); +- adapter->stats.rxerrc += E1000_READ_REG(hw, RXERRC); +- adapter->stats.tncrs += E1000_READ_REG(hw, TNCRS); +- adapter->stats.cexterr += E1000_READ_REG(hw, CEXTERR); +- adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC); +- adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC); +- } +- if(hw->mac_type > iegbe_82547_rev_2) { +- adapter->stats.iac += E1000_READ_REG(hw, IAC); +- adapter->stats.icrxoc += E1000_READ_REG(hw, ICRXOC); +- adapter->stats.icrxptc += E1000_READ_REG(hw, ICRXPTC); +- adapter->stats.icrxatc += E1000_READ_REG(hw, ICRXATC); +- adapter->stats.ictxptc += E1000_READ_REG(hw, ICTXPTC); +- adapter->stats.ictxatc += E1000_READ_REG(hw, ICTXATC); +- adapter->stats.ictxqec += E1000_READ_REG(hw, ICTXQEC); +- adapter->stats.ictxqmtc += E1000_READ_REG(hw, ICTXQMTC); +- adapter->stats.icrxdmtc += E1000_READ_REG(hw, ICRXDMTC); +- } +- +- /* Fill out the OS statistics structure */ +- +- adapter->net_stats.rx_packets = adapter->stats.gprc; +- adapter->net_stats.tx_packets = adapter->stats.gptc; +- adapter->net_stats.rx_bytes = adapter->stats.gorcl; +- adapter->net_stats.tx_bytes = adapter->stats.gotcl; +- adapter->net_stats.multicast = adapter->stats.mprc; +- adapter->net_stats.collisions = adapter->stats.colc; +- +- /* Rx Errors */ +- +- adapter->net_stats.rx_errors = adapter->stats.rxerrc + +- adapter->stats.crcerrs + adapter->stats.algnerrc + +- adapter->stats.rlec + adapter->stats.mpc + +- adapter->stats.cexterr; +- adapter->net_stats.rx_dropped = adapter->stats.mpc; +- adapter->net_stats.rx_length_errors = adapter->stats.rlec; +- adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; +- adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; +- adapter->net_stats.rx_fifo_errors = adapter->stats.mpc; +- adapter->net_stats.rx_missed_errors = adapter->stats.mpc; +- +- /* Tx Errors */ +- +- adapter->net_stats.tx_errors = adapter->stats.ecol + +- adapter->stats.latecol; +- adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; +- adapter->net_stats.tx_window_errors = adapter->stats.latecol; +- adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs; ++ adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS); ++ adapter->stats.gprc += E1000_READ_REG(hw, GPRC); ++ adapter->stats.gorcl += E1000_READ_REG(hw, GORCL); ++ adapter->stats.gorch += E1000_READ_REG(hw, GORCH); ++ adapter->stats.bprc += E1000_READ_REG(hw, BPRC); ++ adapter->stats.mprc += E1000_READ_REG(hw, MPRC); ++ adapter->stats.roc += E1000_READ_REG(hw, ROC); ++ adapter->stats.prc64 += E1000_READ_REG(hw, PRC64); ++ adapter->stats.prc127 += E1000_READ_REG(hw, PRC127); ++ adapter->stats.prc255 += E1000_READ_REG(hw, PRC255); ++ adapter->stats.prc511 += E1000_READ_REG(hw, PRC511); ++ adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023); ++ adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522); ++ ++ adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS); ++ adapter->stats.mpc += E1000_READ_REG(hw, MPC); ++ adapter->stats.scc += E1000_READ_REG(hw, SCC); ++ adapter->stats.ecol += E1000_READ_REG(hw, ECOL); ++ adapter->stats.mcc += E1000_READ_REG(hw, MCC); ++ adapter->stats.latecol += E1000_READ_REG(hw, LATECOL); ++ adapter->stats.dc += E1000_READ_REG(hw, DC); ++ adapter->stats.sec += E1000_READ_REG(hw, SEC); ++ adapter->stats.rlec += E1000_READ_REG(hw, RLEC); ++ adapter->stats.xonrxc += E1000_READ_REG(hw, XONRXC); ++ adapter->stats.xontxc += E1000_READ_REG(hw, XONTXC); ++ adapter->stats.xoffrxc += E1000_READ_REG(hw, XOFFRXC); ++ adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC); ++ adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC); ++ adapter->stats.gptc += E1000_READ_REG(hw, GPTC); ++ adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL); ++ adapter->stats.gotch += E1000_READ_REG(hw, GOTCH); ++ adapter->stats.rnbc += E1000_READ_REG(hw, RNBC); ++ adapter->stats.ruc += E1000_READ_REG(hw, RUC); ++ adapter->stats.rfc += E1000_READ_REG(hw, RFC); ++ adapter->stats.rjc += E1000_READ_REG(hw, RJC); ++ adapter->stats.torl += E1000_READ_REG(hw, TORL); ++ adapter->stats.torh += E1000_READ_REG(hw, TORH); ++ adapter->stats.totl += E1000_READ_REG(hw, TOTL); ++ adapter->stats.toth += E1000_READ_REG(hw, TOTH); ++ adapter->stats.tpr += E1000_READ_REG(hw, TPR); ++ adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64); ++ adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127); ++ adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255); ++ adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511); ++ adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023); ++ adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522); ++ adapter->stats.mptc += E1000_READ_REG(hw, MPTC); ++ adapter->stats.bptc += E1000_READ_REG(hw, BPTC); ++ ++ /* used for adaptive IFS */ ++ ++ hw->tx_packet_delta = E1000_READ_REG(hw, TPT); ++ adapter->stats.tpt += hw->tx_packet_delta; ++ hw->collision_delta = E1000_READ_REG(hw, COLC); ++ adapter->stats.colc += hw->collision_delta; ++ ++ if(hw->mac_type >= iegbe_82543) { ++ adapter->stats.algnerrc += E1000_READ_REG(hw, ALGNERRC); ++ adapter->stats.rxerrc += E1000_READ_REG(hw, RXERRC); ++ adapter->stats.tncrs += E1000_READ_REG(hw, TNCRS); ++ adapter->stats.cexterr += E1000_READ_REG(hw, CEXTERR); ++ adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC); ++ adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC); ++ } ++ if(hw->mac_type > iegbe_82547_rev_2) { ++ adapter->stats.iac += E1000_READ_REG(hw, IAC); ++ adapter->stats.icrxoc += E1000_READ_REG(hw, ICRXOC); ++ adapter->stats.icrxptc += E1000_READ_REG(hw, ICRXPTC); ++ adapter->stats.icrxatc += E1000_READ_REG(hw, ICRXATC); ++ adapter->stats.ictxptc += E1000_READ_REG(hw, ICTXPTC); ++ adapter->stats.ictxatc += E1000_READ_REG(hw, ICTXATC); ++ adapter->stats.ictxqec += E1000_READ_REG(hw, ICTXQEC); ++ adapter->stats.ictxqmtc += E1000_READ_REG(hw, ICTXQMTC); ++ adapter->stats.icrxdmtc += E1000_READ_REG(hw, ICRXDMTC); ++ } ++ ++ /* Fill out the OS statistics structure */ ++ ++ adapter->net_stats.rx_packets = adapter->stats.gprc; ++ adapter->net_stats.tx_packets = adapter->stats.gptc; ++ adapter->net_stats.rx_bytes = adapter->stats.gorcl; ++ adapter->net_stats.tx_bytes = adapter->stats.gotcl; ++ adapter->net_stats.multicast = adapter->stats.mprc; ++ adapter->net_stats.collisions = adapter->stats.colc; ++ ++ /* Rx Errors */ ++ ++ adapter->net_stats.rx_errors = adapter->stats.rxerrc + ++ adapter->stats.crcerrs + adapter->stats.algnerrc + ++ adapter->stats.rlec + adapter->stats.mpc + ++ adapter->stats.cexterr; ++ adapter->net_stats.rx_dropped = adapter->stats.mpc; ++ adapter->net_stats.rx_length_errors = adapter->stats.rlec; ++ adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; ++ adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; ++ adapter->net_stats.rx_fifo_errors = adapter->stats.mpc; ++ adapter->net_stats.rx_missed_errors = adapter->stats.mpc; ++ ++ /* Tx Errors */ ++ ++ adapter->net_stats.tx_errors = adapter->stats.ecol + ++ adapter->stats.latecol; ++ adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; ++ adapter->net_stats.tx_window_errors = adapter->stats.latecol; ++ adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs; + +- /* Tx Dropped needs to be maintained elsewhere */ ++ /* Tx Dropped needs to be maintained elsewhere */ + +- /* Phy Stats */ ++ /* Phy Stats */ + +- if(hw->media_type == iegbe_media_type_copper ++ if(hw->media_type == iegbe_media_type_copper + || (hw->media_type == iegbe_media_type_oem + && iegbe_oem_phy_is_copper(&adapter->hw))) { +- if((adapter->link_speed == SPEED_1000) && +- (!iegbe_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { +- phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; +- adapter->phy_stats.idle_errors += phy_tmp; +- } ++ if((adapter->link_speed == SPEED_1000) && ++ (!iegbe_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { ++ phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; ++ adapter->phy_stats.idle_errors += phy_tmp; ++ } + +- if((hw->mac_type <= iegbe_82546) && +- (hw->phy_type == iegbe_phy_m88) && ++ if((hw->mac_type <= iegbe_82546) && ++ (hw->phy_type == iegbe_phy_m88) && + !iegbe_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp)) { +- adapter->phy_stats.receive_errors += phy_tmp; +- } ++ adapter->phy_stats.receive_errors += phy_tmp; ++ } + } + +- spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); + } + +-#ifdef CONFIG_E1000_MQ +-void +-iegbe_rx_schedule(void *data) ++/** ++ * iegbe_intr_msi - Interrupt Handler ++ * @irq: interrupt number ++ * @data: pointer to a network interface device structure ++ **/ ++ ++static irqreturn_t iegbe_intr_msi(int irq, void *data) + { +- struct net_device *poll_dev, *netdev = data; +- struct iegbe_adapter *adapter = netdev->priv; +- int this_cpu = get_cpu(); +- +- poll_dev = *per_cpu_ptr(adapter->cpu_netdev, this_cpu); +- if (poll_dev == NULL) { +- put_cpu(); +- return; ++ struct net_device *netdev = data; ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct iegbe_hw *hw = &adapter->hw; ++ u32 icr = E1000_READ_REG(&adapter->hw, ICR); ++ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { ++ hw->get_link_status = 1; ++ if (!test_bit(__E1000_DOWN, &adapter->flags)) ++ mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + +- if (likely(netif_rx_schedule_prep(poll_dev))) { +- __netif_rx_schedule(poll_dev); +- } else { +- iegbe_irq_enable(adapter); +- } +- put_cpu(); +-} +-#endif +- +-#ifdef IEGBE_GBE_WORKAROUND +-/* +- * Check for tx hang condition. This is the condition where a +- * decsriptor is in the hardware and hasn't been processed for a +- * while. This code is similar to the check in iegbe_clean_rx_irq() +- */ +-static void +-iegbe_tx_hang_check(struct iegbe_adapter *adapter, +- struct iegbe_tx_ring *tx_ring) +-{ +- struct net_device *netdev = adapter->netdev; +- unsigned int i; ++ if(unlikely(icr & (E1000_ICR_RX_DESC_FIFO_PAR ++ | E1000_ICR_TX_DESC_FIFO_PAR ++ | E1000_ICR_PB ++ | E1000_ICR_CPP_TARGET ++ | E1000_ICR_CPP_MASTER ))) { + +- /* Check for a hang condition using the buffer currently at the Tx +- head pointer */ +- i = readl(adapter->hw.hw_addr + tx_ring->tdh); +- +- if (adapter->detect_tx_hung) { +- /* Detect a transmit hang in hardware, this serializes the +- * check with the clearing of time_stamp and movement of i */ +- adapter->detect_tx_hung = FALSE; +- +- if (tx_ring->buffer_info[i].dma && +- time_after(jiffies, tx_ring->buffer_info[i].time_stamp + HZ) +- && !(E1000_READ_REG(&adapter->hw, STATUS) & +- E1000_STATUS_TXOFF)) { +- +- /* detected Tx unit hang */ +- DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" +- " TDH <%x>\n" +- " TDT <%x>\n" +- " next_to_use <%x>\n" +- " next_to_clean <%x>\n" +- "buffer_info[tdh]\n" +- " dma <%zx>\n" +- " time_stamp <%lx>\n" +- " jiffies <%lx>\n", +- readl(adapter->hw.hw_addr + tx_ring->tdh), +- readl(adapter->hw.hw_addr + tx_ring->tdt), +- tx_ring->next_to_use, +- tx_ring->next_to_clean, +- (size_t)tx_ring->buffer_info[i].dma, +- tx_ring->buffer_info[i].time_stamp, +- jiffies); +- netif_stop_queue(netdev); +- } ++ iegbe_irq_disable(adapter); ++ printk("Critical error! ICR = 0x%x\n", icr); ++ return IRQ_HANDLED; + } +-} ++ if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { ++ adapter->total_tx_bytes = 0; ++ adapter->total_tx_packets = 0; ++ adapter->total_rx_bytes = 0; ++ adapter->total_rx_packets = 0; ++ __netif_rx_schedule(netdev, &adapter->napi); ++ } else ++ iegbe_irq_enable(adapter); + +-#endif ++ return IRQ_HANDLED; ++} + + /** + * iegbe_intr - Interrupt Handler +@@ -3546,364 +3478,208 @@ iegbe_tx_hang_check(struct iegbe_adapter + **/ + + static irqreturn_t +-iegbe_intr(int irq, void *data, struct pt_regs *regs) ++iegbe_intr(int irq, void *data) + { +- struct net_device *netdev = data; +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- struct iegbe_hw *hw = &adapter->hw; +- uint32_t rctl, tctl; +- uint32_t icr = E1000_READ_REG(hw, ICR); +-#ifndef CONFIG_E1000_NAPI +- uint32_t i; +-#ifdef IEGBE_GBE_WORKAROUND +- int rx_cleaned; +-#endif +-#endif ++ struct net_device *netdev = data; ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct iegbe_hw *hw = &adapter->hw; ++ u32 icr = E1000_READ_REG(&adapter->hw, ICR); + +- if(unlikely(!icr)) { ++ if (unlikely(!icr)) + return IRQ_NONE; /* Not our interrupt */ +- } ++ ++ /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is ++ * not set, then the adapter didn't send an interrupt */ ++ if (unlikely(hw->mac_type >= iegbe_82571 && ++ !(icr & E1000_ICR_INT_ASSERTED))) ++ return IRQ_NONE; ++ ++ + if(unlikely(icr & (E1000_ICR_RX_DESC_FIFO_PAR +- | E1000_ICR_TX_DESC_FIFO_PAR +- | E1000_ICR_PB +- | E1000_ICR_CPP_TARGET +- | E1000_ICR_CPP_MASTER ))) { ++ | E1000_ICR_TX_DESC_FIFO_PAR ++ | E1000_ICR_PB ++ | E1000_ICR_CPP_TARGET ++ | E1000_ICR_CPP_MASTER ))) { + + iegbe_irq_disable(adapter); +- tctl = E1000_READ_REG(&adapter->hw, TCTL); +- rctl = E1000_READ_REG(&adapter->hw, RCTL); +- E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_TCTL_EN); +- E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN); +- +- tasklet_data = (unsigned long) (icr + adapter->bd_number); +- tasklet_schedule(&iegbe_reset_tasklet); +- +- return IRQ_HANDLED; +- } +- +-#ifdef CONFIG_E1000_NAPI +- atomic_inc(&adapter->irq_sem); +-#ifdef IEGBE_GBE_WORKAROUND +- /* Ensure that the TXQE interrupt is enabled in NAPI mode */ +- E1000_WRITE_REG(hw, IMC, ~E1000_IMS_TXQE); +-#else +- E1000_WRITE_REG(hw, IMC, ~0); +-#endif +- E1000_WRITE_FLUSH(hw); +-#ifdef CONFIG_E1000_MQ +- if (atomic_read(&adapter->rx_sched_call_data.count) == 0) { +- cpu_set(adapter->cpu_for_queue[0], +- adapter->rx_sched_call_data.cpumask); +- for (i = 1; i < adapter->num_queues; i++) { +- cpu_set(adapter->cpu_for_queue[i], +- adapter->rx_sched_call_data.cpumask); +- atomic_inc(&adapter->irq_sem); +- } +- atomic_set(&adapter->rx_sched_call_data.count, i); +- smp_call_async_mask(&adapter->rx_sched_call_data); +- } else { +- DEBUGOUT("call_data.count == %u\n", +- atomic_read(&adapter->rx_sched_call_data.count)); ++ printk("Critical error! ICR = 0x%x\n", icr); ++ return IRQ_HANDLED; + } +-#else +- if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0]))) { +- __netif_rx_schedule(&adapter->polling_netdev[0]); +- } else { +- iegbe_irq_enable(adapter); +- } +-#endif +- +-#ifdef IEGBE_GBE_WORKAROUND +- /* Clean the Tx ring */ +- for (i = 0; i < E1000_MAX_INTR; i++) { +- adapter->stats.rx_next_to_clean = adapter->rx_ring->next_to_clean; +- adapter->stats.rx_next_to_use = adapter->rx_ring->next_to_use; +- +- adapter->stats.tx_next_to_clean = adapter->tx_ring->next_to_clean; +- adapter->stats.tx_next_to_use = adapter->tx_ring->next_to_use; +- +- /* Only clean Tx descriptors for a TXQE interrupt */ +- if(icr & E1000_ICR_TXQE) { +- adapter->stats.txqec++; +- iegbe_clean_tx_ring_partial(adapter, adapter->tx_ring); +- } +- else { +- iegbe_tx_hang_check(adapter, adapter->tx_ring); +- } +- } + +-#endif /*IEGBE_GBE_WORKAROUND */ +- +-#else +- /* Writing IMC and IMS is needed for 82547. +- * Due to Hub Link bus being occupied, an interrupt +- * de-assertion message is not able to be sent. +- * When an interrupt assertion message is generated later, +- * two messages are re-ordered and sent out. +- * That causes APIC to think 82547 is in de-assertion +- * state, while 82547 is in assertion state, resulting +- * in dead lock. Writing IMC forces 82547 into +- * de-assertion state. +- */ +- if (hw->mac_type == iegbe_82547 || hw->mac_type == iegbe_82547_rev_2) { +- atomic_inc(&adapter->irq_sem); +- E1000_WRITE_REG(hw, IMC, ~0); +- } +- +-#ifdef IEGBE_GBE_WORKAROUND +- +- for (i = 0; i < E1000_MAX_INTR; i++) { +- rx_cleaned = adapter->clean_rx(adapter, adapter->rx_ring); +- adapter->stats.rx_next_to_clean = adapter->rx_ring->next_to_clean; +- adapter->stats.rx_next_to_use = adapter->rx_ring->next_to_use; +- +- adapter->stats.tx_next_to_clean = adapter->tx_ring->next_to_clean; +- adapter->stats.tx_next_to_use = adapter->tx_ring->next_to_use; +- +- /* Only clean Tx descriptors for a TXQE interrupt */ +- if(icr & E1000_ICR_TXQE) { +- adapter->stats.txqec++; +- iegbe_clean_tx_ring_partial(adapter, adapter->tx_ring); +- } +- else { +- iegbe_tx_hang_check(adapter, adapter->tx_ring); +- } +- if(!rx_cleaned) { +- break; +- } ++ /* Interrupt Auto-Mask...upon reading ICR, interrupts are masked. No ++ * need for the IMC write */ ++ if (unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) { ++ hw->get_link_status = 1; ++ /* guard against interrupt when we're going down */ ++ if (!test_bit(__E1000_DOWN, &adapter->flags)) ++ mod_timer(&adapter->watchdog_timer, jiffies + 1); ++ + } + +-#else +- for (i = 0; i < E1000_MAX_INTR; i++) +- if(unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & +- !iegbe_clean_tx_irq(adapter, adapter->tx_ring))) { +- break; +- } +-#endif +- +- if (hw->mac_type == iegbe_82547 || hw->mac_type == iegbe_82547_rev_2) { +- iegbe_irq_enable(adapter); +- } +-#endif +-#ifdef E1000_COUNT_ICR +- adapter->icr_txdw += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_txqe += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_lsc += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_rxseq += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_rxdmt += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_rxo += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_rxt += icr & 0x01UL; +- if(hw->mac_type != iegbe_icp_xxxx) { +- icr >>= 0x2; +- adapter->icr_mdac += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_rxcfg += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_gpi += icr & 0x01UL; +- } else { +- icr >>= 0x4; +- } +- if(hw->mac_type == iegbe_icp_xxxx) { +- icr >>= 0xc; +- adapter->icr_pb += icr & 0x01UL; +- icr >>= 0x3; +- adapter->icr_intmem_icp_xxxx += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_cpp_target += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_cpp_master += icr & 0x01UL; +- icr >>= 0x1; +- adapter->icr_stat += icr & 0x01UL; ++ if (unlikely(hw->mac_type < iegbe_82571)) { ++ E1000_WRITE_REG(&adapter->hw, IMC, ~0); ++ E1000_WRITE_FLUSH(&adapter->hw); + } +-#endif ++ if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { ++ adapter->total_tx_bytes = 0; ++ adapter->total_tx_packets = 0; ++ adapter->total_rx_bytes = 0; ++ adapter->total_rx_packets = 0; ++ __netif_rx_schedule(netdev, &adapter->napi); ++ } else ++ /* this really should not happen! if it does it is basically a ++ * bug, but not a hard error, so enable ints and continue */ ++ iegbe_irq_enable(adapter); + + return IRQ_HANDLED; + } + +-#ifdef CONFIG_E1000_NAPI + /** + * iegbe_clean - NAPI Rx polling callback + * @adapter: board private structure + **/ +- +-static int +-iegbe_clean(struct net_device *poll_dev, int *budget) ++static int iegbe_clean(struct napi_struct *napi, int budget) + { +- struct iegbe_adapter *adapter; +- int work_to_do = min(*budget, poll_dev->quota); +- int tx_cleaned, i = 0, work_done = 0; ++ struct iegbe_adapter *adapter = container_of(napi, struct iegbe_adapter, napi); ++ struct net_device *poll_dev = adapter->netdev; ++ int tx_cleaned = 0, work_done = 0; + + /* Must NOT use netdev_priv macro here. */ + adapter = poll_dev->priv; + +- /* Keep link state information with original netdev */ +- if (!netif_carrier_ok(adapter->netdev)) { +- goto quit_polling; +- } +- while (poll_dev != &adapter->polling_netdev[i]) { +- i++; +- if (unlikely(i == adapter->num_queues)) { +- BUG(); +- } +- } +- +-#ifdef IEGBE_GBE_WORKAROUND +- /* Tx descriptors are cleaned in iegbe_intr(). No need to clean +- them here */ +- tx_cleaned = FALSE; +-#else +- tx_cleaned = iegbe_clean_tx_irq(adapter, &adapter->tx_ring[i]); +-#endif +- adapter->clean_rx(adapter, &adapter->rx_ring[i], +- &work_done, work_to_do); +- +- *budget -= work_done; +- poll_dev->quota -= work_done; +- +- /* If no Tx and not enough Rx work done, exit the polling mode */ +- if((!tx_cleaned && (work_done == 0)) || +- !netif_running(adapter->netdev)) { +-quit_polling: +- netif_rx_complete(poll_dev); ++ /* iegbe_clean is called per-cpu. This lock protects ++ * tx_ring[0] from being cleaned by multiple cpus ++ * simultaneously. A failure obtaining the lock means ++ * tx_ring[0] is currently being cleaned anyway. */ ++ if (spin_trylock(&adapter->tx_queue_lock)) { ++ tx_cleaned = iegbe_clean_tx_irq(adapter, ++ &adapter->tx_ring[0]); ++ spin_unlock(&adapter->tx_queue_lock); ++ } ++ ++ adapter->clean_rx(adapter, &adapter->rx_ring[0], ++ &work_done, budget); ++ ++ if (tx_cleaned) ++ work_done = budget; ++ ++ /* If budget not fully consumed, exit the polling mode */ ++ if (work_done < budget) { ++ if (likely(adapter->itr_setting & 3)) ++ iegbe_set_itr(adapter); ++ netif_rx_complete(poll_dev, napi); + iegbe_irq_enable(adapter); +- return 0; + } + +- return 1; ++ return work_done; + } + +-#endif +- +- +-#ifndef IEGBE_GBE_WORKAROUND + /** + * iegbe_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + **/ +- +-static boolean_t +-iegbe_clean_tx_irq(struct iegbe_adapter *adapter, ++static bool iegbe_clean_tx_irq(struct iegbe_adapter *adapter, + struct iegbe_tx_ring *tx_ring) + { +- struct net_device *netdev = adapter->netdev; +- struct iegbe_tx_desc *tx_desc, *eop_desc; +- struct iegbe_buffer *buffer_info; +- unsigned int i, eop; +- boolean_t cleaned = FALSE; ++ struct iegbe_hw *hw = &adapter->hw; ++ struct net_device *netdev = adapter->netdev; ++ struct iegbe_tx_desc *tx_desc, *eop_desc; ++ struct iegbe_buffer *buffer_info; ++ unsigned int i, eop; ++ unsigned int count = 0; ++ bool cleaned = false; ++ unsigned int total_tx_bytes=0, total_tx_packets=0; + +- i = tx_ring->next_to_clean; +- eop = tx_ring->buffer_info[i].next_to_watch; +- eop_desc = E1000_TX_DESC(*tx_ring, eop); ++ i = tx_ring->next_to_clean; ++ eop = tx_ring->buffer_info[i].next_to_watch; ++ eop_desc = E1000_TX_DESC(*tx_ring, eop); + + while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { +- /* Premature writeback of Tx descriptors clear (free buffers +- * and unmap pci_mapping) previous_buffer_info */ +- if (likely(tx_ring->previous_buffer_info.skb != NULL)) { +- iegbe_unmap_and_free_tx_resource(adapter, +- &tx_ring->previous_buffer_info); +- } +- +- for (cleaned = FALSE; !cleaned; ) { +- tx_desc = E1000_TX_DESC(*tx_ring, i); +- buffer_info = &tx_ring->buffer_info[i]; +- cleaned = (i == eop); +- +-#ifdef NETIF_F_TSO +- if (!(netdev->features & NETIF_F_TSO)) { +-#endif +- iegbe_unmap_and_free_tx_resource(adapter, +- buffer_info); +-#ifdef NETIF_F_TSO +- } else { +- if (cleaned) { +- memcpy(&tx_ring->previous_buffer_info, +- buffer_info, +- sizeof(struct iegbe_buffer)); +- memset(buffer_info, 0, +- sizeof(struct iegbe_buffer)); +- } else { +- iegbe_unmap_and_free_tx_resource( +- adapter, buffer_info); +- } +- } +-#endif +- +- tx_desc->buffer_addr = 0; +- tx_desc->lower.data = 0; ++ for (cleaned = false; !cleaned; ) { ++ tx_desc = E1000_TX_DESC(*tx_ring, i); ++ buffer_info = &tx_ring->buffer_info[i]; ++ cleaned = (i == eop); ++ ++ if (cleaned) { ++ struct sk_buff *skb = buffer_info->skb; ++ unsigned int segs = 0, bytecount; ++ segs = skb_shinfo(skb)->gso_segs ?: 1; ++ bytecount = ((segs - 1) * skb_headlen(skb)) + ++ skb->len; ++ total_tx_packets += segs; ++ total_tx_bytes += bytecount; ++ } ++ iegbe_unmap_and_free_tx_resource(adapter, buffer_info); + tx_desc->upper.data = 0; + +- if (unlikely(++i == tx_ring->count)) { i = 0; } +- } +- +- tx_ring->pkt++; ++ if (unlikely(++i == tx_ring->count)) i = 0; ++ } + +- eop = tx_ring->buffer_info[i].next_to_watch; +- eop_desc = E1000_TX_DESC(*tx_ring, eop); +- } ++ eop = tx_ring->buffer_info[i].next_to_watch; ++ eop_desc = E1000_TX_DESC(*tx_ring, eop); ++#define E1000_TX_WEIGHT 64 ++ /* weight of a sort for tx, to avoid endless transmit cleanup */ ++ if (count++ == E1000_TX_WEIGHT) ++ break; ++ } + + tx_ring->next_to_clean = i; + +- spin_lock(&tx_ring->tx_lock); ++#define TX_WAKE_THRESHOLD 32 + +- if (unlikely(cleaned && netif_queue_stopped(netdev) && +- netif_carrier_ok(netdev))) { +- netif_wake_queue(netdev); +- } +- spin_unlock(&tx_ring->tx_lock); +- +- if (adapter->detect_tx_hung) { +- /* Detect a transmit hang in hardware, this serializes the +- * check with the clearing of time_stamp and movement of i */ +- adapter->detect_tx_hung = FALSE; +- +- if (tx_ring->buffer_info[i].dma && +- time_after(jiffies, tx_ring->buffer_info[i].time_stamp + HZ) +- && !(E1000_READ_REG(&adapter->hw, STATUS) & +- E1000_STATUS_TXOFF)) { +- +- /* detected Tx unit hang */ +- i = tx_ring->next_to_clean; +- eop = tx_ring->buffer_info[i].next_to_watch; +- eop_desc = E1000_TX_DESC(*tx_ring, eop); +- DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" +- " TDH <%x>\n" +- " TDT <%x>\n" +- " next_to_use <%x>\n" +- " next_to_clean <%x>\n" +- "buffer_info[next_to_clean]\n" +- " dma <%zx>\n" +- " time_stamp <%lx>\n" +- " next_to_watch <%x>\n" +- " jiffies <%lx>\n" +- " next_to_watch.status <%x>\n", +- readl(adapter->hw.hw_addr + tx_ring->tdh), +- readl(adapter->hw.hw_addr + tx_ring->tdt), +- tx_ring->next_to_use, +- i, +- (size_t)tx_ring->buffer_info[i].dma, +- tx_ring->buffer_info[i].time_stamp, +- eop, +- jiffies, +- eop_desc->upper.fields.status); +- netif_stop_queue(netdev); ++ if (unlikely(cleaned && netif_carrier_ok(netdev) && ++ E1000_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) { ++ /* Make sure that anybody stopping the queue after this ++ * sees the new next_to_clean. ++ */ ++ smp_mb(); ++ if (netif_queue_stopped(netdev)) { ++ netif_wake_queue(netdev); ++ ++adapter->restart_queue; + } + } +-#ifdef NETIF_F_TSO +- if (unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) && +- time_after(jiffies, tx_ring->previous_buffer_info.time_stamp + HZ))) { +- iegbe_unmap_and_free_tx_resource( +- adapter, &tx_ring->previous_buffer_info); ++ ++ if (adapter->detect_tx_hung) { ++ /* Detect a transmit hang in hardware, this serializes the ++ * check with the clearing of time_stamp and movement of i */ ++ adapter->detect_tx_hung = false; ++ ++ if (tx_ring->buffer_info[eop].dma && ++ time_after(jiffies, tx_ring->buffer_info[eop].time_stamp + ++ (adapter->tx_timeout_factor * HZ)) ++ && !(E1000_READ_REG(hw, STATUS) & E1000_STATUS_TXOFF)) { ++ ++ /* detected Tx unit hang */ ++ DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" ++ " Tx Queue <%lu>\n" ++ " TDH <%x>\n" ++ " TDT <%x>\n" ++ " next_to_use <%x>\n" ++ " next_to_clean <%x>\n" ++ "buffer_info[next_to_clean]\n" ++ " time_stamp <%lx>\n" ++ " next_to_watch <%x>\n" ++ " jiffies <%lx>\n" ++ " next_to_watch.status <%x>\n", ++ (unsigned long)((tx_ring - adapter->tx_ring) / ++ sizeof(struct iegbe_tx_ring)), ++ readl(hw->hw_addr + tx_ring->tdh), ++ readl(hw->hw_addr + tx_ring->tdt), ++ tx_ring->next_to_use, ++ tx_ring->next_to_clean, ++ tx_ring->buffer_info[eop].time_stamp, ++ eop, ++ jiffies, ++ eop_desc->upper.fields.status); ++ netif_stop_queue(netdev); ++ } + } +-#endif +- return cleaned; ++ adapter->total_tx_bytes += total_tx_bytes; ++ adapter->total_tx_packets += total_tx_packets; ++ adapter->net_stats.tx_bytes += total_tx_bytes; ++ adapter->net_stats.tx_packets += total_tx_packets; ++ return cleaned; + } +-#endif + + /** + * iegbe_rx_checksum - Receive Checksum Offload for 82543 +@@ -3913,192 +3689,193 @@ iegbe_clean_tx_irq(struct iegbe_adapter + * @sk_buff: socket buffer with received data + **/ + +-static inline void +-iegbe_rx_checksum(struct iegbe_adapter *adapter, +- uint32_t status_err, uint32_t csum, +- struct sk_buff *skb) ++static void iegbe_rx_checksum(struct iegbe_adapter *adapter, u32 status_err, ++ u32 csum, struct sk_buff *skb) + { +- uint16_t status = (uint16_t)status_err; +- uint8_t errors = (uint8_t)(status_err >> 0x18); ++ struct iegbe_hw *hw = &adapter->hw; ++ u16 status = (u16)status_err; ++ u8 errors = (u8)(status_err >> 24); + skb->ip_summed = CHECKSUM_NONE; + +- /* 82543 or newer only */ +- if(unlikely(adapter->hw.mac_type < iegbe_82543)) { return; } +- /* Ignore Checksum bit is set */ +- if(unlikely(status & E1000_RXD_STAT_IXSM)) { return; } +- /* TCP/UDP checksum error bit is set */ +- if(unlikely(errors & E1000_RXD_ERR_TCPE)) { +- /* let the stack verify checksum errors */ +- adapter->hw_csum_err++; +- return; +- } +- /* TCP/UDP Checksum has not been calculated */ +- if(adapter->hw.mac_type <= iegbe_82547_rev_2) { +- if(!(status & E1000_RXD_STAT_TCPCS)) { +- return; ++ /* 82543 or newer only */ ++ if (unlikely(hw->mac_type < iegbe_82543)) return; ++ /* Ignore Checksum bit is set */ ++ if (unlikely(status & E1000_RXD_STAT_IXSM)) return; ++ /* TCP/UDP checksum error bit is set */ ++ if(unlikely(errors & E1000_RXD_ERR_TCPE)) { ++ /* let the stack verify checksum errors */ ++ adapter->hw_csum_err++; ++ return; ++ } ++ /* TCP/UDP Checksum has not been calculated */ ++ if (hw->mac_type <= iegbe_82547_rev_2) { ++ if (!(status & E1000_RXD_STAT_TCPCS)) ++ return; ++ } else { ++ if (!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) ++ return; + } +- } else { +- if(!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) { +- return; +- } ++ /* It must be a TCP or UDP packet with a valid checksum */ ++ if(likely(status & E1000_RXD_STAT_TCPCS)) { ++ /* TCP checksum is good */ ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else if (hw->mac_type > iegbe_82547_rev_2) { ++ /* IP fragment with UDP payload */ ++ /* Hardware complements the payload checksum, so we undo it ++ * and then put the value in host order for further stack use. ++ */ ++ __sum16 sum = (__force __sum16)htons(csum); ++ skb->csum = csum_unfold(~sum); ++ skb->ip_summed = CHECKSUM_COMPLETE; + } +- /* It must be a TCP or UDP packet with a valid checksum */ +- if(likely(status & E1000_RXD_STAT_TCPCS)) { +- /* TCP checksum is good */ +- skb->ip_summed = CHECKSUM_UNNECESSARY; +- } else if(adapter->hw.mac_type > iegbe_82547_rev_2) { +- /* IP fragment with UDP payload */ +- /* Hardware complements the payload checksum, so we undo it +- * and then put the value in host order for further stack use. +- */ +- csum = ntohl(csum ^ 0xFFFF); +- skb->csum = csum; +- skb->ip_summed = CHECKSUM_HW; +- } +- adapter->hw_csum_good++; ++ adapter->hw_csum_good++; + } + + /** + * iegbe_clean_rx_irq - Send received data up the network stack; legacy + * @adapter: board private structure + **/ +- +-static boolean_t +-#ifdef CONFIG_E1000_NAPI +-iegbe_clean_rx_irq(struct iegbe_adapter *adapter, ++static bool iegbe_clean_rx_irq(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring, + int *work_done, int work_to_do) +-#else +-iegbe_clean_rx_irq(struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring) +-#endif + { +- struct net_device *netdev = adapter->netdev; +- struct pci_dev *pdev = adapter->pdev; +- struct iegbe_rx_desc *rx_desc; +- struct iegbe_buffer *buffer_info; +- struct sk_buff *skb; +- unsigned long flags = 0; +- uint32_t length; +- uint8_t last_byte; +- unsigned int i; +- boolean_t cleaned = FALSE; +- +-#ifdef IEGBE_GBE_WORKAROUND +- /* Need to keep track of the amount of Rx descriptors that we +- cleaned to ensure that we don't supply too many back to the +- hardware */ +- int cleaned_count = 0; +-#endif +- +- i = rx_ring->next_to_clean; +- rx_desc = E1000_RX_DESC(*rx_ring, i); +- +- while(rx_desc->status & E1000_RXD_STAT_DD) { +- buffer_info = &rx_ring->buffer_info[i]; +-#ifdef CONFIG_E1000_NAPI +- if(*work_done >= work_to_do) { +- break; +- } +- (*work_done)++; +-#endif +- cleaned = TRUE; ++ struct iegbe_hw *hw = &adapter->hw; ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ struct iegbe_rx_desc *rx_desc, *next_rxd; ++ struct iegbe_buffer *buffer_info, *next_buffer; ++ unsigned long flags; ++ u32 length; ++ u8 last_byte; ++ unsigned int i; ++ int cleaned_count = 0; ++ bool cleaned = false; ++ unsigned int total_rx_bytes=0, total_rx_packets=0; + +-#ifdef IEGBE_GBE_WORKAROUND +- cleaned_count++; +-#endif ++ i = rx_ring->next_to_clean; ++ rx_desc = E1000_RX_DESC(*rx_ring, i); ++ buffer_info = &rx_ring->buffer_info[i]; + +- pci_unmap_single(pdev, +- buffer_info->dma, +- buffer_info->length, +- PCI_DMA_FROMDEVICE); ++ while(rx_desc->status & E1000_RXD_STAT_DD) { ++ struct sk_buff *skb; ++ u8 status; ++ if (*work_done >= work_to_do) ++ break; ++ (*work_done)++; + ++ status = rx_desc->status; + skb = buffer_info->skb; +- length = le16_to_cpu(rx_desc->length); ++ buffer_info->skb = NULL; ++ prefetch(skb->data - NET_IP_ALIGN); ++ if (++i == rx_ring->count) i = 0; ++ next_rxd = E1000_RX_DESC(*rx_ring, i); ++ prefetch(next_rxd); ++ next_buffer = &rx_ring->buffer_info[i]; ++ cleaned = true; ++ cleaned_count++; ++ pci_unmap_single(pdev, ++ buffer_info->dma, ++ buffer_info->length, ++ PCI_DMA_FROMDEVICE); ++ ++ length = le16_to_cpu(rx_desc->length); ++ ++ if (unlikely(!(status & E1000_RXD_STAT_EOP))) { ++ /* All receives must fit into a single buffer */ ++ E1000_DBG("%s: Receive packet consumed multiple" ++ " buffers\n", netdev->name); ++ buffer_info->skb = skb; ++ goto next_desc; ++ } + +- if(unlikely(!(rx_desc->status & E1000_RXD_STAT_EOP))) { +- /* All receives must fit into a single buffer */ +- E1000_DBG("%s: Receive packet consumed multiple" +- " buffers\n", netdev->name); +- dev_kfree_skb_irq(skb); +- goto next_desc; +- } ++ if(unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { ++ last_byte = *(skb->data + length - 1); ++ if (TBI_ACCEPT(hw, status, rx_desc->errors, length, ++ last_byte)) { ++ spin_lock_irqsave(&adapter->stats_lock, flags); ++ iegbe_tbi_adjust_stats(hw, &adapter->stats, ++ length, skb->data); ++ spin_unlock_irqrestore(&adapter->stats_lock, ++ flags); ++ length--; ++ } else { ++ buffer_info->skb = skb; ++ goto next_desc; ++ } ++ } + +- if(unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { +- last_byte = *(skb->data + length - 0x1); +- if(TBI_ACCEPT(&adapter->hw, rx_desc->status, +- rx_desc->errors, length, last_byte)) { +- spin_lock_irqsave(&adapter->stats_lock, flags); +- iegbe_tbi_adjust_stats(&adapter->hw, +- &adapter->stats, +- length, skb->data); +- spin_unlock_irqrestore(&adapter->stats_lock, +- flags); +- length--; +- } else { +- dev_kfree_skb_irq(skb); +- goto next_desc; ++ /* adjust length to remove Ethernet CRC, this must be ++ * done after the TBI_ACCEPT workaround above */ ++ length -= 4; ++ ++ /* probably a little skewed due to removing CRC */ ++ total_rx_bytes += length; ++ total_rx_packets++; ++ ++ /* code added for copybreak, this should improve ++ * performance for small packets with large amounts ++ * of reassembly being done in the stack */ ++ if (length < copybreak) { ++ struct sk_buff *new_skb = ++ netdev_alloc_skb(netdev, length + NET_IP_ALIGN); ++ if (new_skb) { ++ skb_reserve(new_skb, NET_IP_ALIGN); ++ skb_copy_to_linear_data_offset(new_skb, ++ -NET_IP_ALIGN, ++ (skb->data - ++ NET_IP_ALIGN), ++ (length + ++ NET_IP_ALIGN)); ++ /* save the skb in buffer_info as good */ ++ buffer_info->skb = skb; ++ skb = new_skb; + } ++ /* else just continue with the old one */ + } +- +- /* Good Receive */ +- skb_put(skb, length - ETHERNET_FCS_SIZE); ++ /* Good Receive */ ++ skb_put(skb, length); + + /* Receive Checksum Offload */ + iegbe_rx_checksum(adapter, +- (uint32_t)(rx_desc->status) | +- ((uint32_t)(rx_desc->errors) << 0x18), +- rx_desc->csum, skb); ++ (u32)(status) | ++ ((u32)(rx_desc->errors) << 24), ++ le16_to_cpu(rx_desc->csum), skb); ++ + skb->protocol = eth_type_trans(skb, netdev); +-#ifdef CONFIG_E1000_NAPI +-#ifdef NETIF_F_HW_VLAN_TX +- if(unlikely(adapter->vlgrp && +- (rx_desc->status & E1000_RXD_STAT_VP))) { ++ ++ if (unlikely(adapter->vlgrp && ++ (status & E1000_RXD_STAT_VP))) { + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, +- le16_to_cpu(rx_desc->special) & +- E1000_RXD_SPC_VLAN_MASK); ++ le16_to_cpu(rx_desc->special)); + } else { + netif_receive_skb(skb); + } +-#else +- netif_receive_skb(skb); +-#endif +-#else /* CONFIG_E1000_NAPI */ +-#ifdef NETIF_F_HW_VLAN_TX +- if(unlikely(adapter->vlgrp && +- (rx_desc->status & E1000_RXD_STAT_VP))) { +- vlan_hwaccel_rx(skb, adapter->vlgrp, +- le16_to_cpu(rx_desc->special) & +- E1000_RXD_SPC_VLAN_MASK); +- } else { +- netif_rx(skb); +- } +-#else +- netif_rx(skb); +-#endif +-#endif /* CONFIG_E1000_NAPI */ ++ + netdev->last_rx = jiffies; +- rx_ring->pkt++; + + next_desc: + rx_desc->status = 0; +- buffer_info->skb = NULL; +- if(unlikely(++i == rx_ring->count)) { i = 0; } + +- rx_desc = E1000_RX_DESC(*rx_ring, i); ++ /* return some buffers to hardware, one at a time is too slow */ ++ if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) { ++ adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); ++ cleaned_count = 0; ++ } ++ ++ /* use prefetched values */ ++ rx_desc = next_rxd; ++ buffer_info = next_buffer; + } + rx_ring->next_to_clean = i; + +-#ifdef IEGBE_GBE_WORKAROUND +- /* Only allocate the number of buffers that we have actually +- cleaned! */ +- if (cleaned_count) { +- adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); +- } +-#else +- adapter->alloc_rx_buf(adapter, rx_ring); +-#endif +- ++ cleaned_count = E1000_DESC_UNUSED(rx_ring); ++ if (cleaned_count) ++ adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); ++ ++ adapter->total_rx_packets += total_rx_packets; ++ adapter->total_rx_bytes += total_rx_bytes; ++ adapter->net_stats.rx_bytes += total_rx_bytes; ++ adapter->net_stats.rx_packets += total_rx_packets; + return cleaned; + } + +@@ -4107,161 +3884,153 @@ next_desc: + * @adapter: board private structure + **/ + +-static boolean_t +-#ifdef CONFIG_E1000_NAPI +-iegbe_clean_rx_irq_ps(struct iegbe_adapter *adapter, ++static bool iegbe_clean_rx_irq_ps(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring, + int *work_done, int work_to_do) +-#else +-iegbe_clean_rx_irq_ps(struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring) +-#endif + { +- union iegbe_rx_desc_packet_split *rx_desc; +- struct net_device *netdev = adapter->netdev; +- struct pci_dev *pdev = adapter->pdev; +- struct iegbe_buffer *buffer_info; +- struct iegbe_ps_page *ps_page; +- struct iegbe_ps_page_dma *ps_page_dma; +- struct sk_buff *skb; +- unsigned int i, j; +- uint32_t length, staterr; +- boolean_t cleaned = FALSE; +- +-#ifdef IEGBE_GBE_WORKAROUND +- /* Need to keep track of the amount of Rx descriptors that we +- cleaned to ensure that we don't supply too many back to the +- hardware */ +- int cleaned_count = 0; +-#endif +- +- i = rx_ring->next_to_clean; +- rx_desc = E1000_RX_DESC_PS(*rx_ring, i); +- staterr = le32_to_cpu(rx_desc->wb.middle.status_error); +- +- while(staterr & E1000_RXD_STAT_DD) { +- buffer_info = &rx_ring->buffer_info[i]; +- ps_page = &rx_ring->ps_page[i]; +- ps_page_dma = &rx_ring->ps_page_dma[i]; +-#ifdef CONFIG_E1000_NAPI +- if(unlikely(*work_done >= work_to_do)) { +- break; +- } +- (*work_done)++; +-#endif +- cleaned = TRUE; +- +-#ifdef IEGBE_GBE_WORKAROUND +- cleaned_count++; +-#endif ++ union iegbe_rx_desc_packet_split *rx_desc, *next_rxd; ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ struct iegbe_buffer *buffer_info, *next_buffer; ++ struct iegbe_ps_page *ps_page; ++ struct iegbe_ps_page_dma *ps_page_dma; ++ struct sk_buff *skb; ++ unsigned int i, j; ++ u32 length, staterr; ++ int cleaned_count = 0; ++ bool cleaned = false; ++ unsigned int total_rx_bytes=0, total_rx_packets=0; ++ ++ i = rx_ring->next_to_clean; ++ rx_desc = E1000_RX_DESC_PS(*rx_ring, i); ++ staterr = le32_to_cpu(rx_desc->wb.middle.status_error); ++ buffer_info = &rx_ring->buffer_info[i]; + +- pci_unmap_single(pdev, buffer_info->dma, +- buffer_info->length, +- PCI_DMA_FROMDEVICE); ++ while(staterr & E1000_RXD_STAT_DD) { ++ ps_page = &rx_ring->ps_page[i]; ++ ps_page_dma = &rx_ring->ps_page_dma[i]; ++ ++ if (unlikely(*work_done >= work_to_do)) ++ break; ++ (*work_done)++; + + skb = buffer_info->skb; ++ prefetch(skb->data - NET_IP_ALIGN); ++ if (++i == rx_ring->count) i = 0; ++ next_rxd = E1000_RX_DESC_PS(*rx_ring, i); ++ prefetch(next_rxd); ++ next_buffer = &rx_ring->buffer_info[i]; ++ cleaned = true; ++ cleaned_count++; ++ pci_unmap_single(pdev, buffer_info->dma, ++ buffer_info->length, ++ PCI_DMA_FROMDEVICE); ++ ++ if(unlikely(!(staterr & E1000_RXD_STAT_EOP))) { ++ E1000_DBG("%s: Packet Split buffers didn't pick up" ++ " the full packet\n", netdev->name); ++ dev_kfree_skb_irq(skb); ++ goto next_desc; ++ } + +- if(unlikely(!(staterr & E1000_RXD_STAT_EOP))) { +- E1000_DBG("%s: Packet Split buffers didn't pick up" +- " the full packet\n", netdev->name); +- dev_kfree_skb_irq(skb); +- goto next_desc; +- } +- +- if(unlikely(staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK)) { +- dev_kfree_skb_irq(skb); +- goto next_desc; +- } +- +- length = le16_to_cpu(rx_desc->wb.middle.length0); ++ if(unlikely(staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK)) { ++ dev_kfree_skb_irq(skb); ++ goto next_desc; ++ } + +- if(unlikely(!length)) { +- E1000_DBG("%s: Last part of the packet spanning" +- " multiple descriptors\n", netdev->name); +- dev_kfree_skb_irq(skb); +- goto next_desc; +- } ++ length = le16_to_cpu(rx_desc->wb.middle.length0); + +- /* Good Receive */ +- skb_put(skb, length); +- +- for(j = 0; j < adapter->rx_ps_pages; j++) { +- if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j]))) { +- break; +- } +- pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j], +- PAGE_SIZE, PCI_DMA_FROMDEVICE); +- ps_page_dma->ps_page_dma[j] = 0; +- skb_shinfo(skb)->frags[j].page = +- ps_page->ps_page[j]; +- ps_page->ps_page[j] = NULL; +- skb_shinfo(skb)->frags[j].page_offset = 0; +- skb_shinfo(skb)->frags[j].size = length; +- skb_shinfo(skb)->nr_frags++; +- skb->len += length; +- skb->data_len += length; +- } ++ if(unlikely(!length)) { ++ E1000_DBG("%s: Last part of the packet spanning" ++ " multiple descriptors\n", netdev->name); ++ dev_kfree_skb_irq(skb); ++ goto next_desc; ++ } + +- iegbe_rx_checksum(adapter, staterr, +- rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); +- skb->protocol = eth_type_trans(skb, netdev); ++ /* Good Receive */ ++ skb_put(skb, length); + +- if(likely(rx_desc->wb.upper.header_status & +- E1000_RXDPS_HDRSTAT_HDRSP)) { +- adapter->rx_hdr_split++; +-#ifdef HAVE_RX_ZERO_COPY +- skb_shinfo(skb)->zero_copy = TRUE; +-#endif +- } +-#ifdef CONFIG_E1000_NAPI +-#ifdef NETIF_F_HW_VLAN_TX +- if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { +- vlan_hwaccel_receive_skb(skb, adapter->vlgrp, +- le16_to_cpu(rx_desc->wb.middle.vlan) & +- E1000_RXD_SPC_VLAN_MASK); +- } else { +- netif_receive_skb(skb); +- } +-#else +- netif_receive_skb(skb); +-#endif +-#else /* CONFIG_E1000_NAPI */ +-#ifdef NETIF_F_HW_VLAN_TX +- if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { +- vlan_hwaccel_rx(skb, adapter->vlgrp, +- le16_to_cpu(rx_desc->wb.middle.vlan) & +- E1000_RXD_SPC_VLAN_MASK); +- } else { +- netif_rx(skb); +- } +-#else +- netif_rx(skb); +-#endif +-#endif /* CONFIG_E1000_NAPI */ +- netdev->last_rx = jiffies; +- rx_ring->pkt++; ++ { ++ int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]); ++ if (l1 && (l1 <= copybreak) && ((length + l1) <= adapter->rx_ps_bsize0)) { ++ u8 *vaddr; ++ pci_dma_sync_single_for_cpu(pdev, ++ ps_page_dma->ps_page_dma[0], ++ PAGE_SIZE, ++ PCI_DMA_FROMDEVICE); ++ vaddr = kmap_atomic(ps_page->ps_page[0], ++ KM_SKB_DATA_SOFTIRQ); ++ memcpy(skb_tail_pointer(skb), vaddr, l1); ++ kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); ++ pci_dma_sync_single_for_device(pdev, ++ ps_page_dma->ps_page_dma[0], ++ PAGE_SIZE, PCI_DMA_FROMDEVICE); ++ l1 -= 4; ++ skb_put(skb, l1); ++ goto copydone; ++ } /* if */ ++ } ++ for (j = 0; j < adapter->rx_ps_pages; j++) { ++ length = le16_to_cpu(rx_desc->wb.upper.length[j]); ++ if (!length) ++ break; ++ pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j], ++ PAGE_SIZE, PCI_DMA_FROMDEVICE); ++ ps_page_dma->ps_page_dma[j] = 0; ++ skb_fill_page_desc(skb, j, ps_page->ps_page[j], 0, ++ length); ++ ps_page->ps_page[j] = NULL; ++ skb->len += length; ++ skb->data_len += length; ++ skb->truesize += length; ++ } + +-next_desc: +- rx_desc->wb.middle.status_error &= ~0xFF; +- buffer_info->skb = NULL; +- if(unlikely(++i == rx_ring->count)) { i = 0; } ++ pskb_trim(skb, skb->len - 4); ++copydone: ++ total_rx_bytes += skb->len; ++ total_rx_packets++; ++ iegbe_rx_checksum(adapter, staterr, ++ le16_to_cpu(rx_desc->wb.lower.hi_dword.csum_ip.csum), skb); ++ skb->protocol = eth_type_trans(skb, netdev); ++ ++ if(likely(rx_desc->wb.upper.header_status & ++ cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))) ++ adapter->rx_hdr_split++; ++ ++ if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { ++ vlan_hwaccel_receive_skb(skb, adapter->vlgrp, ++ le16_to_cpu(rx_desc->wb.middle.vlan)); ++ } else { ++ netif_receive_skb(skb); ++ } + +- rx_desc = E1000_RX_DESC_PS(*rx_ring, i); +- staterr = le32_to_cpu(rx_desc->wb.middle.status_error); +- } +- rx_ring->next_to_clean = i; ++ netdev->last_rx = jiffies; + +-#ifdef IEGBE_GBE_WORKAROUND +- /* Only allocate the number of buffers that we have actually +- cleaned! */ +- if (cleaned_count) { +- adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); +- } +-#else +- adapter->alloc_rx_buf(adapter, rx_ring); +-#endif ++next_desc: ++ rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF); ++ buffer_info->skb = NULL; + +- return cleaned; ++ if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) { ++ adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); ++ cleaned_count = 0; ++ } ++ ++ /* use prefetched values */ ++ rx_desc = next_rxd; ++ buffer_info = next_buffer; ++ staterr = le32_to_cpu(rx_desc->wb.middle.status_error); ++ } ++ rx_ring->next_to_clean = i; ++ ++ cleaned_count = E1000_DESC_UNUSED(rx_ring); ++ if (cleaned_count) ++ adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); ++ ++ adapter->total_rx_packets += total_rx_packets; ++ adapter->total_rx_bytes += total_rx_bytes; ++ adapter->net_stats.rx_bytes += total_rx_bytes; ++ adapter->net_stats.rx_packets += total_rx_packets; ++ return cleaned; + } + + /** +@@ -4269,142 +4038,115 @@ next_desc: + * @adapter: address of board private structure + **/ + +-#ifdef IEGBE_GBE_WORKAROUND +-static void +-iegbe_alloc_rx_buffers(struct iegbe_adapter *adapter, ++ ++static void iegbe_alloc_rx_buffers(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring, + int cleaned_count) +-#else +-static void +-iegbe_alloc_rx_buffers(struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring) +-#endif + { +- struct net_device *netdev = adapter->netdev; +- struct pci_dev *pdev = adapter->pdev; +- struct iegbe_rx_desc *rx_desc; +- struct iegbe_buffer *buffer_info; +- struct sk_buff *skb; +- unsigned int i; +- unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN; +- +- i = rx_ring->next_to_use; +- buffer_info = &rx_ring->buffer_info[i]; ++ struct iegbe_hw *hw = &adapter->hw; ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ struct iegbe_rx_desc *rx_desc; ++ struct iegbe_buffer *buffer_info; ++ struct sk_buff *skb; ++ unsigned int i; ++ unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN; + +-#ifdef IEGBE_GBE_WORKAROUND +- if (cleaned_count > IEGBE_GBE_WORKAROUND_NUM_RX_DESCRIPTORS) { +- adapter->stats.cc_gt_num_rx++; +- } +- while(cleaned_count-- && !buffer_info->skb) { +-#else +- while(!buffer_info->skb) { +-#endif +- skb = dev_alloc_skb(bufsz); ++ i = rx_ring->next_to_use; ++ buffer_info = &rx_ring->buffer_info[i]; + +- if(unlikely(!skb)) { +- /* Better luck next round */ +- break; +- } ++ while (cleaned_count--) { ++ skb = buffer_info->skb; ++ if (skb) { ++ skb_trim(skb, 0); ++ goto map_skb; ++ } ++ skb = netdev_alloc_skb(netdev, bufsz); ++ ++ if(unlikely(!skb)) { ++ /* Better luck next round */ ++ adapter->alloc_rx_buff_failed++; ++ break; ++ } + +- /* Fix for errata 23, can't cross 64kB boundary */ +- if(!iegbe_check_64k_bound(adapter, skb->data, bufsz)) { +- struct sk_buff *oldskb = skb; +- DPRINTK(RX_ERR, ERR, "skb align check failed: %u bytes " +- "at %p\n", bufsz, skb->data); +- /* Try again, without freeing the previous */ +- skb = dev_alloc_skb(bufsz); +- /* Failed allocation, critical failure */ +- if(!skb) { +- dev_kfree_skb(oldskb); +- break; +- } ++ /* Fix for errata 23, can't cross 64kB boundary */ ++ if(!iegbe_check_64k_bound(adapter, skb->data, bufsz)) { ++ struct sk_buff *oldskb = skb; ++ DPRINTK(RX_ERR, ERR, "skb align check failed: %u bytes " ++ "at %p\n", bufsz, skb->data); ++ /* Try again, without freeing the previous */ ++ skb = netdev_alloc_skb(netdev, bufsz); ++ /* Failed allocation, critical failure */ ++ if(!skb) { ++ dev_kfree_skb(oldskb); ++ break; ++ } + +- if(!iegbe_check_64k_bound(adapter, skb->data, bufsz)) { +- /* give up */ +- dev_kfree_skb(skb); +- dev_kfree_skb(oldskb); +- break; /* while !buffer_info->skb */ +- } else { +- /* Use new allocation */ +- dev_kfree_skb(oldskb); ++ if(!iegbe_check_64k_bound(adapter, skb->data, bufsz)) { ++ /* give up */ ++ dev_kfree_skb(skb); ++ dev_kfree_skb(oldskb); ++ break; /* while !buffer_info->skb */ + } +- } +- /* Make buffer alignment 2 beyond a 16 byte boundary +- * this will result in a 16 byte aligned IP header after +- * the 14 byte MAC header is removed +- */ +- skb_reserve(skb, NET_IP_ALIGN); +- +- skb->dev = netdev; +- +- buffer_info->skb = skb; +- buffer_info->length = adapter->rx_buffer_len; +- buffer_info->dma = pci_map_single(pdev, +- skb->data, +- adapter->rx_buffer_len, +- PCI_DMA_FROMDEVICE); +- +- /* Fix for errata 23, can't cross 64kB boundary */ +- if(!iegbe_check_64k_bound(adapter, +- (void *)(unsigned long)buffer_info->dma, +- adapter->rx_buffer_len)) { +- DPRINTK(RX_ERR, ERR, +- "dma align check failed: %u bytes at %p\n", +- adapter->rx_buffer_len, +- (void *)(unsigned long)buffer_info->dma); +- dev_kfree_skb(skb); +- buffer_info->skb = NULL; +- +- pci_unmap_single(pdev, buffer_info->dma, +- adapter->rx_buffer_len, +- PCI_DMA_FROMDEVICE); +- +- break; /* while !buffer_info->skb */ +- } +- rx_desc = E1000_RX_DESC(*rx_ring, i); +- rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); +- +-#ifdef IEGBE_GBE_WORKAROUND_DISABLED +- adapter->stats.num_rx_buf_alloc++; ++ /* Use new allocation */ ++ dev_kfree_skb(oldskb); ++ } ++ /* Make buffer alignment 2 beyond a 16 byte boundary ++ * this will result in a 16 byte aligned IP header after ++ * the 14 byte MAC header is removed ++ */ ++ skb_reserve(skb, NET_IP_ALIGN); ++ ++ ++ buffer_info->skb = skb; ++ buffer_info->length = adapter->rx_buffer_len; ++map_skb: ++ buffer_info->dma = pci_map_single(pdev, ++ skb->data, ++ adapter->rx_buffer_len, ++ PCI_DMA_FROMDEVICE); ++ ++ /* Fix for errata 23, can't cross 64kB boundary */ ++ if(!iegbe_check_64k_bound(adapter, ++ (void *)(unsigned long)buffer_info->dma, ++ adapter->rx_buffer_len)) { ++ DPRINTK(RX_ERR, ERR, ++ "dma align check failed: %u bytes at %p\n", ++ adapter->rx_buffer_len, ++ (void *)(unsigned long)buffer_info->dma); ++ dev_kfree_skb(skb); ++ buffer_info->skb = NULL; ++ ++ pci_unmap_single(pdev, buffer_info->dma, ++ adapter->rx_buffer_len, ++ PCI_DMA_FROMDEVICE); + +- /* Force memory writes to complete before letting h/w +- * know there are new descriptors to fetch. (Only +- * applicable for weak-ordered memory model archs, +- * such as IA-64). */ +- wmb(); +- writel(i, adapter->hw.hw_addr + rx_ring->rdt); ++ break; /* while !buffer_info->skb */ ++ } ++ rx_desc = E1000_RX_DESC(*rx_ring, i); ++ rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + +-#endif +-#ifndef IEGBE_GBE_WORKAROUND +- if(unlikely((i & ~(E1000_RX_BUFFER_WRITE - 0x1)) == i)) { +- /* Force memory writes to complete before letting h/w +- * know there are new descriptors to fetch. (Only +- * applicable for weak-ordered memory model archs, +- * such as IA-64). */ +- wmb(); +- writel(i, adapter->hw.hw_addr + rx_ring->rdt); +- } +-#endif +- if(unlikely(++i == rx_ring->count)) { i = 0; } +- buffer_info = &rx_ring->buffer_info[i]; +- } ++ /* Force memory writes to complete before letting h/w ++ * know there are new descriptors to fetch. (Only ++ * applicable for weak-ordered memory model archs, ++ * such as IA-64). */ ++ if (unlikely(++i == rx_ring->count)) ++ i = 0; ++ buffer_info = &rx_ring->buffer_info[i]; ++ } + +-#ifdef IEGBE_GBE_WORKAROUND + if (likely(rx_ring->next_to_use != i)) { +- rx_ring->next_to_use = i; +- if (unlikely(i-- == 0)) { +- i = (rx_ring->count - 0x1); +- } ++ rx_ring->next_to_use = i; ++ if (unlikely(i-- == 0)) ++ i = (rx_ring->count - 1); ++ + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); +- writel(i, adapter->hw.hw_addr + rx_ring->rdt); ++ writel(i, hw->hw_addr + rx_ring->rdt); + } +-#else +- rx_ring->next_to_use = i; +-#endif + } + + /** +@@ -4412,49 +4154,41 @@ iegbe_alloc_rx_buffers(struct iegbe_adap + * @adapter: address of board private structure + **/ + +-#ifdef IEGBE_GBE_WORKAROUND +-static void +-iegbe_alloc_rx_buffers_ps(struct iegbe_adapter *adapter, ++ ++static void iegbe_alloc_rx_buffers_ps(struct iegbe_adapter *adapter, + struct iegbe_rx_ring *rx_ring, + int cleaned_count) +-#else +-static void +-iegbe_alloc_rx_buffers_ps(struct iegbe_adapter *adapter, +- struct iegbe_rx_ring *rx_ring) +-#endif + { +- struct net_device *netdev = adapter->netdev; +- struct pci_dev *pdev = adapter->pdev; +- union iegbe_rx_desc_packet_split *rx_desc; +- struct iegbe_buffer *buffer_info; +- struct iegbe_ps_page *ps_page; +- struct iegbe_ps_page_dma *ps_page_dma; +- struct sk_buff *skb; +- unsigned int i, j; +- +- i = rx_ring->next_to_use; +- buffer_info = &rx_ring->buffer_info[i]; +- ps_page = &rx_ring->ps_page[i]; +- ps_page_dma = &rx_ring->ps_page_dma[i]; ++ struct iegbe_hw *hw = &adapter->hw; ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ union iegbe_rx_desc_packet_split *rx_desc; ++ struct iegbe_buffer *buffer_info; ++ struct iegbe_ps_page *ps_page; ++ struct iegbe_ps_page_dma *ps_page_dma; ++ struct sk_buff *skb; ++ unsigned int i, j; ++ ++ i = rx_ring->next_to_use; ++ buffer_info = &rx_ring->buffer_info[i]; ++ ps_page = &rx_ring->ps_page[i]; ++ ps_page_dma = &rx_ring->ps_page_dma[i]; + +-#ifdef IEGBE_GBE_WORKAROUND +- while(cleaned_count-- && !buffer_info->skb) { +-#else +- while(!buffer_info->skb) { +-#endif +- rx_desc = E1000_RX_DESC_PS(*rx_ring, i); ++ while (cleaned_count--) { ++ rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + + for (j = 0; j < PS_PAGE_BUFFERS; j++) { +- if (j < adapter->rx_ps_pages) { +- if (likely(!ps_page->ps_page[j])) { +- ps_page->ps_page[j] = +- alloc_page(GFP_ATOMIC); ++ if (j < adapter->rx_ps_pages) { ++ if (likely(!ps_page->ps_page[j])) { ++ ps_page->ps_page[j] = ++ alloc_page(GFP_ATOMIC); + if (unlikely(!ps_page->ps_page[j])) { +- goto no_buffers; ++ adapter->alloc_rx_buff_failed++; ++ goto no_buffers; + } +- ps_page_dma->ps_page_dma[j] = +- pci_map_page(pdev, +- ps_page->ps_page[j], ++ ps_page_dma->ps_page_dma[j] = ++ pci_map_page(pdev, ++ ps_page->ps_page[j], + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + } +@@ -4462,26 +4196,26 @@ iegbe_alloc_rx_buffers_ps(struct iegbe_a + * change because each write-back erases + * this info. + */ +- rx_desc->read.buffer_addr[j+0x1] = ++ rx_desc->read.buffer_addr[j+1] = + cpu_to_le64(ps_page_dma->ps_page_dma[j]); +- } else { +- rx_desc->read.buffer_addr[j+0x1] = ~0; +- } ++ } else ++ rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0); + } + +- skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN); ++ skb = netdev_alloc_skb(netdev, ++ adapter->rx_ps_bsize0 + NET_IP_ALIGN); + +- if (unlikely(!skb)) { ++ if (unlikely(!skb)) { ++ adapter->alloc_rx_buff_failed++; + break; +- } ++ } ++ + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + +- skb->dev = netdev; +- + buffer_info->skb = skb; + buffer_info->length = adapter->rx_ps_bsize0; + buffer_info->dma = pci_map_single(pdev, skb->data, +@@ -4490,27 +4224,28 @@ iegbe_alloc_rx_buffers_ps(struct iegbe_a + + rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma); + +- if (unlikely((i & ~(E1000_RX_BUFFER_WRITE - 0x1)) == i)) { +- /* Force memory writes to complete before letting h/w +- * know there are new descriptors to fetch. (Only +- * applicable for weak-ordered memory model archs, +- * such as IA-64). */ +- wmb(); +- /* Hardware increments by 16 bytes, but packet split +- * descriptors are 32 bytes...so we increment tail +- * twice as much. +- */ +- writel(i<<1, adapter->hw.hw_addr + rx_ring->rdt); +- } +- +- if (unlikely(++i == rx_ring->count)) { i = 0; } ++ if (unlikely(++i == rx_ring->count)) i = 0; + buffer_info = &rx_ring->buffer_info[i]; + ps_page = &rx_ring->ps_page[i]; + ps_page_dma = &rx_ring->ps_page_dma[i]; + } + + no_buffers: +- rx_ring->next_to_use = i; ++ if (likely(rx_ring->next_to_use != i)) { ++ rx_ring->next_to_use = i; ++ if (unlikely(i-- == 0)) i = (rx_ring->count - 1); ++ ++ /* Force memory writes to complete before letting h/w ++ * know there are new descriptors to fetch. (Only ++ * applicable for weak-ordered memory model archs, ++ * such as IA-64). */ ++ wmb(); ++ /* Hardware increments by 16 bytes, but packet split ++ * descriptors are 32 bytes...so we increment tail ++ * twice as much. ++ */ ++ writel(i<<1, hw->hw_addr + rx_ring->rdt); ++ } + } + + /** +@@ -4521,52 +4256,52 @@ no_buffers: + static void + iegbe_smartspeed(struct iegbe_adapter *adapter) + { +- uint16_t phy_status; +- uint16_t phy_ctrl; ++ uint16_t phy_status; ++ uint16_t phy_ctrl; + +- if((adapter->hw.phy_type != iegbe_phy_igp) || !adapter->hw.autoneg || ++ if((adapter->hw.phy_type != iegbe_phy_igp) || !adapter->hw.autoneg || + !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL)) { +- return; ++ return; + } +- if(adapter->smartspeed == 0) { +- /* If Master/Slave config fault is asserted twice, +- * we assume back-to-back */ +- iegbe_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status); ++ if(adapter->smartspeed == 0x0) { ++ /* If Master/Slave config fault is asserted twice, ++ * we assume back-to-back */ ++ iegbe_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status); + if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) { return; } +- iegbe_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status); ++ iegbe_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status); + if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) { return; } +- iegbe_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl); +- if(phy_ctrl & CR_1000T_MS_ENABLE) { +- phy_ctrl &= ~CR_1000T_MS_ENABLE; +- iegbe_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, +- phy_ctrl); +- adapter->smartspeed++; +- if(!iegbe_phy_setup_autoneg(&adapter->hw) && +- !iegbe_read_phy_reg(&adapter->hw, PHY_CTRL, +- &phy_ctrl)) { +- phy_ctrl |= (MII_CR_AUTO_NEG_EN | +- MII_CR_RESTART_AUTO_NEG); +- iegbe_write_phy_reg(&adapter->hw, PHY_CTRL, +- phy_ctrl); +- } +- } +- return; +- } else if(adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) { +- /* If still no link, perhaps using 2/3 pair cable */ +- iegbe_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl); +- phy_ctrl |= CR_1000T_MS_ENABLE; +- iegbe_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_ctrl); +- if(!iegbe_phy_setup_autoneg(&adapter->hw) && +- !iegbe_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_ctrl)) { +- phy_ctrl |= (MII_CR_AUTO_NEG_EN | +- MII_CR_RESTART_AUTO_NEG); +- iegbe_write_phy_reg(&adapter->hw, PHY_CTRL, phy_ctrl); +- } +- } +- /* Restart process after E1000_SMARTSPEED_MAX iterations */ ++ iegbe_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl); ++ if(phy_ctrl & CR_1000T_MS_ENABLE) { ++ phy_ctrl &= ~CR_1000T_MS_ENABLE; ++ iegbe_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, ++ phy_ctrl); ++ adapter->smartspeed++; ++ if(!iegbe_phy_setup_autoneg(&adapter->hw) && ++ !iegbe_read_phy_reg(&adapter->hw, PHY_CTRL, ++ &phy_ctrl)) { ++ phy_ctrl |= (MII_CR_AUTO_NEG_EN | ++ MII_CR_RESTART_AUTO_NEG); ++ iegbe_write_phy_reg(&adapter->hw, PHY_CTRL, ++ phy_ctrl); ++ } ++ } ++ return; ++ } else if(adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) { ++ /* If still no link, perhaps using 2/3 pair cable */ ++ iegbe_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl); ++ phy_ctrl |= CR_1000T_MS_ENABLE; ++ iegbe_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_ctrl); ++ if(!iegbe_phy_setup_autoneg(&adapter->hw) && ++ !iegbe_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_ctrl)) { ++ phy_ctrl |= (MII_CR_AUTO_NEG_EN | ++ MII_CR_RESTART_AUTO_NEG); ++ iegbe_write_phy_reg(&adapter->hw, PHY_CTRL, phy_ctrl); ++ } ++ } ++ /* Restart process after E1000_SMARTSPEED_MAX iterations */ + if(adapter->smartspeed++ == E1000_SMARTSPEED_MAX) { +- adapter->smartspeed = 0; +-} ++ adapter->smartspeed = 0x0; ++ } + } + + /** +@@ -4576,23 +4311,22 @@ iegbe_smartspeed(struct iegbe_adapter *a + * @cmd: + **/ + +-static int +-iegbe_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) ++static int iegbe_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) + { +- switch (cmd) { ++ switch (cmd) { + #ifdef SIOCGMIIPHY +- case SIOCGMIIPHY: +- case SIOCGMIIREG: +- case SIOCSMIIREG: +- return iegbe_mii_ioctl(netdev, ifr, cmd); ++ case SIOCGMIIPHY: ++ case SIOCGMIIREG: ++ case SIOCSMIIREG: ++ return iegbe_mii_ioctl(netdev, ifr, cmd); + #endif + #ifdef ETHTOOL_OPS_COMPAT +- case SIOCETHTOOL: +- return ethtool_ioctl(ifr); ++ case SIOCETHTOOL: ++ return ethtool_ioctl(ifr); + #endif +- default: +- return -EOPNOTSUPP; +- } ++ default: ++ return -EOPNOTSUPP; ++ } + } + + #ifdef SIOCGMIIPHY +@@ -4603,534 +4337,510 @@ iegbe_ioctl(struct net_device *netdev, s + * @cmd: + **/ + +-static int +-iegbe_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) ++static int iegbe_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, ++ int cmd) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- struct mii_ioctl_data *data = if_mii(ifr); +- int retval; +- uint16_t mii_reg; +- uint16_t spddplx; +- unsigned long flags; +- +- if((adapter->hw.media_type == iegbe_media_type_oem && +- !iegbe_oem_phy_is_copper(&adapter->hw)) || +- adapter->hw.media_type == iegbe_media_type_fiber || +- adapter->hw.media_type == iegbe_media_type_internal_serdes ) { +- return -EOPNOTSUPP; +- } +- switch (cmd) { +- case SIOCGMIIPHY: +- data->phy_id = adapter->hw.phy_addr; +- break; +- case SIOCGMIIREG: ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ struct mii_ioctl_data *data = if_mii(ifr); ++ int retval; ++ uint16_t mii_reg; ++ uint16_t spddplx; ++ unsigned long flags = 0; ++ ++ if((adapter->hw.media_type == iegbe_media_type_oem ++ && !iegbe_oem_phy_is_copper(&adapter->hw)) ++ ||adapter->hw.media_type != iegbe_media_type_copper) { ++ return -EOPNOTSUPP; ++ } ++ switch (cmd) { ++ case SIOCGMIIPHY: ++ data->phy_id = adapter->hw.phy_addr; ++ break; ++ case SIOCGMIIREG: + if(!capable(CAP_NET_ADMIN)) { +- return -EPERM; ++ return -EPERM; + } +- spin_lock_irqsave(&adapter->stats_lock, flags); +- if(iegbe_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, +- &data->val_out)) { +- spin_unlock_irqrestore(&adapter->stats_lock, flags); +- return -EIO; +- } +- spin_unlock_irqrestore(&adapter->stats_lock, flags); +- break; +- case SIOCSMIIREG: ++ spin_lock_irqsave(&adapter->stats_lock, flags); ++ if(iegbe_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, ++ &data->val_out)) { ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ return -EIO; ++ } ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ break; ++ case SIOCSMIIREG: + if(!capable(CAP_NET_ADMIN)){ +- return -EPERM; ++ return -EPERM; + } + if(data->reg_num & ~(0x1F)) { +- return -EFAULT; ++ return -EFAULT; + } +- mii_reg = data->val_in; +- spin_lock_irqsave(&adapter->stats_lock, flags); +- if(iegbe_write_phy_reg(&adapter->hw, data->reg_num, +- mii_reg)) { +- spin_unlock_irqrestore(&adapter->stats_lock, flags); +- return -EIO; +- } +- switch(adapter->hw.phy_type) { +- case iegbe_phy_m88: +- switch (data->reg_num) { +- case PHY_CTRL: ++ mii_reg = data->val_in; ++ spin_lock_irqsave(&adapter->stats_lock, flags); ++ if(iegbe_write_phy_reg(&adapter->hw, data->reg_num, ++ mii_reg)) { ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ return -EIO; ++ } ++ switch(adapter->hw.phy_type) { ++ case iegbe_phy_m88: ++ switch (data->reg_num) { ++ case PHY_CTRL: + if(mii_reg & MII_CR_POWER_DOWN) { +- break; ++ break; + } +- if(mii_reg & MII_CR_AUTO_NEG_EN) { +- adapter->hw.autoneg = 1; +- adapter->hw.autoneg_advertised = 0x2F; +- } else { ++ if(mii_reg & MII_CR_AUTO_NEG_EN) { ++ adapter->hw.autoneg = 1; ++ adapter->hw.autoneg_advertised = 0x2F; ++ } else { + if(mii_reg & 0x40){ +- spddplx = SPEED_1000; ++ spddplx = SPEED_1000; + } else if(mii_reg & 0x2000) { +- spddplx = SPEED_100; ++ spddplx = SPEED_100; + } else { +- spddplx = SPEED_10; ++ spddplx = SPEED_10; + } +- spddplx += (mii_reg & 0x100) +- ? FULL_DUPLEX : +- HALF_DUPLEX; +- retval = iegbe_set_spd_dplx(adapter, +- spddplx); +- if(retval) { +- spin_unlock_irqrestore( +- &adapter->stats_lock, +- flags); +- return retval; +- } +- } +- if(netif_running(adapter->netdev)) { +- iegbe_down(adapter); +- iegbe_up(adapter); ++ spddplx += (mii_reg & 0x100) ++ ? FULL_DUPLEX : ++ HALF_DUPLEX; ++ retval = iegbe_set_spd_dplx(adapter, ++ spddplx); ++ if(retval) { ++ spin_unlock_irqrestore( ++ &adapter->stats_lock, ++ flags); ++ return retval; ++ } ++ } ++ if(netif_running(adapter->netdev)) { ++ iegbe_down(adapter); ++ iegbe_up(adapter); + } else { +- iegbe_reset(adapter); ++ iegbe_reset(adapter); + } +- break; +- case M88E1000_PHY_SPEC_CTRL: +- case M88E1000_EXT_PHY_SPEC_CTRL: +- if(iegbe_phy_reset(&adapter->hw)) { +- spin_unlock_irqrestore( +- &adapter->stats_lock, flags); +- return -EIO; +- } +- break; +- } +- break; ++ break; ++ case M88E1000_PHY_SPEC_CTRL: ++ case M88E1000_EXT_PHY_SPEC_CTRL: ++ if(iegbe_phy_reset(&adapter->hw)) { ++ spin_unlock_irqrestore( ++ &adapter->stats_lock, flags); ++ return -EIO; ++ } ++ break; ++ } ++ break; + +- case iegbe_phy_oem: +- retval = iegbe_oem_mii_ioctl(adapter, flags, ifr, cmd); +- if(retval) { +- spin_unlock_irqrestore( +- &adapter->stats_lock, flags); +- return retval; +- } +- break; ++ case iegbe_phy_oem: ++ retval = iegbe_oem_mii_ioctl(adapter, flags, ifr, cmd); ++ if(retval) { ++ spin_unlock_irqrestore( ++ &adapter->stats_lock, flags); ++ return retval; ++ } ++ break; + +- default: +- switch (data->reg_num) { +- case PHY_CTRL: ++ default: ++ switch (data->reg_num) { ++ case PHY_CTRL: + if(mii_reg & MII_CR_POWER_DOWN) { +- break; ++ break; + } +- if(netif_running(adapter->netdev)) { +- iegbe_down(adapter); +- iegbe_up(adapter); ++ if(netif_running(adapter->netdev)) { ++ iegbe_down(adapter); ++ iegbe_up(adapter); + } else { +- iegbe_reset(adapter); ++ iegbe_reset(adapter); + } +- break; +- } +- } +- spin_unlock_irqrestore(&adapter->stats_lock, flags); +- break; +- default: +- return -EOPNOTSUPP; +- } +- return E1000_SUCCESS; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return E1000_SUCCESS; + } + #endif + +-void +-iegbe_pci_set_mwi(struct iegbe_hw *hw) ++void iegbe_pci_set_mwi(struct iegbe_hw *hw) + { +- struct iegbe_adapter *adapter = hw->back; +-#ifdef HAVE_PCI_SET_MWI +- int ret_val = pci_set_mwi(adapter->pdev); +- +- if(ret_val) { +- DPRINTK(PROBE, ERR, "Error in setting MWI\n"); +- } +-#else +- pci_write_config_word(adapter->pdev, PCI_COMMAND, +- adapter->hw.pci_cmd_word | +- PCI_COMMAND_INVALIDATE); +-#endif ++ struct iegbe_adapter *adapter = hw->back; ++ int ret_val = pci_set_mwi(adapter->pdev); ++ ++ if (ret_val) ++ DPRINTK(PROBE, ERR, "Error in setting MWI\n"); + } + +-void +-iegbe_pci_clear_mwi(struct iegbe_hw *hw) ++void iegbe_pci_clear_mwi(struct iegbe_hw *hw) + { +- struct iegbe_adapter *adapter = hw->back; ++ struct iegbe_adapter *adapter = hw->back; + +-#ifdef HAVE_PCI_SET_MWI +- pci_clear_mwi(adapter->pdev); +-#else +- pci_write_config_word(adapter->pdev, PCI_COMMAND, +- adapter->hw.pci_cmd_word & +- ~PCI_COMMAND_INVALIDATE); +-#endif ++ pci_clear_mwi(adapter->pdev); + } + + void + iegbe_read_pci_cfg(struct iegbe_hw *hw, uint32_t reg, uint16_t *value) + { +- struct iegbe_adapter *adapter = hw->back; ++ struct iegbe_adapter *adapter = hw->back; + +- pci_read_config_word(adapter->pdev, reg, value); ++ pci_read_config_word(adapter->pdev, reg, value); + } + + void + iegbe_write_pci_cfg(struct iegbe_hw *hw, uint32_t reg, uint16_t *value) + { +- struct iegbe_adapter *adapter = hw->back; ++ struct iegbe_adapter *adapter = hw->back; + +- pci_write_config_word(adapter->pdev, reg, *value); ++ pci_write_config_word(adapter->pdev, reg, *value); + } + + uint32_t + iegbe_io_read(struct iegbe_hw *hw, unsigned long port) + { +- return inl(port); ++ return inl(port); + } + + void + iegbe_io_write(struct iegbe_hw *hw, unsigned long port, uint32_t value) + { +- outl(value, port); ++ outl(value, port); + } + +-#ifdef NETIF_F_HW_VLAN_TX +-static void +-iegbe_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) ++static void iegbe_vlan_rx_register(struct net_device *netdev, ++ struct vlan_group *grp) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- uint32_t ctrl, rctl; +- +- iegbe_irq_disable(adapter); +- adapter->vlgrp = grp; +- +- if(grp) { +- /* enable VLAN tag insert/strip */ +- ctrl = E1000_READ_REG(&adapter->hw, CTRL); +- ctrl |= E1000_CTRL_VME; +- E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); +- +- /* enable VLAN receive filtering */ +- rctl = E1000_READ_REG(&adapter->hw, RCTL); +- rctl |= E1000_RCTL_VFE; +- rctl &= ~E1000_RCTL_CFIEN; +- E1000_WRITE_REG(&adapter->hw, RCTL, rctl); +- iegbe_update_mng_vlan(adapter); +- } else { +- /* disable VLAN tag insert/strip */ +- ctrl = E1000_READ_REG(&adapter->hw, CTRL); +- ctrl &= ~E1000_CTRL_VME; +- E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ uint32_t ctrl, rctl; + +- /* disable VLAN filtering */ +- rctl = E1000_READ_REG(&adapter->hw, RCTL); +- rctl &= ~E1000_RCTL_VFE; +- E1000_WRITE_REG(&adapter->hw, RCTL, rctl); +- if(adapter->mng_vlan_id != (uint16_t)E1000_MNG_VLAN_NONE) { +- iegbe_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); +- adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; +- } +- } ++ if (!test_bit(__E1000_DOWN, &adapter->flags)) ++ iegbe_irq_disable(adapter); ++ adapter->vlgrp = grp; ++ ++ if(grp) { ++ /* enable VLAN tag insert/strip */ ++ ctrl = E1000_READ_REG(&adapter->hw, CTRL); ++ ctrl |= E1000_CTRL_VME; ++ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); ++ ++ /* enable VLAN receive filtering */ ++ rctl = E1000_READ_REG(&adapter->hw, RCTL); ++ rctl |= E1000_RCTL_VFE; ++ rctl &= ~E1000_RCTL_CFIEN; ++ E1000_WRITE_REG(&adapter->hw, RCTL, rctl); ++ iegbe_update_mng_vlan(adapter); ++ } else { ++ /* disable VLAN tag insert/strip */ ++ ctrl = E1000_READ_REG(&adapter->hw, CTRL); ++ ctrl &= ~E1000_CTRL_VME; ++ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); ++ ++ /* disable VLAN filtering */ ++ rctl = E1000_READ_REG(&adapter->hw, RCTL); ++ rctl &= ~E1000_RCTL_VFE; ++ E1000_WRITE_REG(&adapter->hw, RCTL, rctl); ++ if(adapter->mng_vlan_id != (uint16_t)E1000_MNG_VLAN_NONE) { ++ iegbe_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); ++ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; ++ } ++ } + +- iegbe_irq_enable(adapter); ++ if (!test_bit(__E1000_DOWN, &adapter->flags)) ++ iegbe_irq_enable(adapter); + } + +-static void +-iegbe_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid) ++static void iegbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- uint32_t vfta, index; +- if((adapter->hw.mng_cookie.status & +- E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ uint32_t vfta, index; ++ if((adapter->hw.mng_cookie.status & ++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && + (vid == adapter->mng_vlan_id)) { +- return; ++ return; + } +- /* add VID to filter table */ ++ /* add VID to filter table */ + index = (vid >> 0x5) & 0x7F; +- vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); ++ vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); + vfta |= (0x1 << (vid & 0x1F)); +- iegbe_write_vfta(&adapter->hw, index, vfta); ++ iegbe_write_vfta(&adapter->hw, index, vfta); + } + +-static void +-iegbe_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid) ++static void iegbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) + { + struct iegbe_adapter *adapter = netdev_priv(netdev); +- uint32_t vfta, index; ++ u32 vfta, index; + ++ if (!test_bit(__E1000_DOWN, &adapter->flags)) + iegbe_irq_disable(adapter); +- +- if(adapter->vlgrp) { +- adapter->vlgrp->vlan_devices[vid] = NULL; +- } ++ vlan_group_set_device(adapter->vlgrp, vid, NULL); ++ if (!test_bit(__E1000_DOWN, &adapter->flags)) + iegbe_irq_enable(adapter); + +- if((adapter->hw.mng_cookie.status & +- E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && +- (vid == adapter->mng_vlan_id)) { +- return; +- } + /* remove VID from filter table */ +- index = (vid >> 0x5) & 0x7F; ++ index = (vid >> 0x5) & 0x7F; + vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); +- vfta &= ~(0x1 << (vid & 0x1F)); ++ vfta &= ~(0x1 << (vid & 0x1F)); + iegbe_write_vfta(&adapter->hw, index, vfta); + } + +-static void +-iegbe_restore_vlan(struct iegbe_adapter *adapter) ++static void iegbe_restore_vlan(struct iegbe_adapter *adapter) + { + iegbe_vlan_rx_register(adapter->netdev, adapter->vlgrp); + +- if(adapter->vlgrp) { +- uint16_t vid; +- for(vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { +- if(!adapter->vlgrp->vlan_devices[vid]) { ++ if (adapter->vlgrp) { ++ u16 vid; ++ for (vid = 0x0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { ++ if (!vlan_group_get_device(adapter->vlgrp, vid)) + continue; +- } + iegbe_vlan_rx_add_vid(adapter->netdev, vid); + } + } + } +-#endif + +-int +-iegbe_set_spd_dplx(struct iegbe_adapter *adapter, uint16_t spddplx) ++ ++int iegbe_set_spd_dplx(struct iegbe_adapter *adapter, u16 spddplx) + { +- adapter->hw.autoneg = 0; ++ adapter->hw.autoneg = 0x0; + +- /* Fiber NICs only allow 1000 gbps Full duplex */ +- if((adapter->hw.media_type == iegbe_media_type_fiber ++ /* Fiber NICs only allow 1000 gbps Full duplex */ ++ if((adapter->hw.media_type == iegbe_media_type_fiber + || (adapter->hw.media_type == iegbe_media_type_oem + && !iegbe_oem_phy_is_copper(&adapter->hw))) +- && spddplx != (SPEED_1000 + FULL_DUPLEX)) { +- DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n"); +- return -EINVAL; +- } +- +- switch(spddplx) { +- case SPEED_10 + HALF_DUPLEX: +- adapter->hw.forced_speed_duplex = iegbe_10_half; +- break; +- case SPEED_10 + FULL_DUPLEX: +- adapter->hw.forced_speed_duplex = iegbe_10_full; +- break; +- case SPEED_100 + HALF_DUPLEX: +- adapter->hw.forced_speed_duplex = iegbe_100_half; +- break; +- case SPEED_100 + FULL_DUPLEX: +- adapter->hw.forced_speed_duplex = iegbe_100_full; +- break; +- case SPEED_1000 + FULL_DUPLEX: ++ && spddplx != (SPEED_1000 + DUPLEX_FULL)) { ++ DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n"); ++ return -EINVAL; ++ } ++ ++ switch(spddplx) { ++ case SPEED_10 + DUPLEX_HALF: ++ adapter->hw.forced_speed_duplex = iegbe_10_half; ++ break; ++ case SPEED_10 + DUPLEX_FULL: ++ adapter->hw.forced_speed_duplex = iegbe_10_full; ++ break; ++ case SPEED_100 + DUPLEX_HALF: ++ adapter->hw.forced_speed_duplex = iegbe_100_half; ++ break; ++ case SPEED_100 + DUPLEX_FULL: ++ adapter->hw.forced_speed_duplex = iegbe_100_full; ++ break; ++ case SPEED_1000 + DUPLEX_FULL: + adapter->hw.autoneg = 0x1; +- adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; +- break; +- case SPEED_1000 + HALF_DUPLEX: /* not supported */ +- default: +- DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n"); +- return -EINVAL; +- } +- return 0; ++ adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; ++ break; ++ case SPEED_1000 + DUPLEX_HALF: /* not supported */ ++ default: ++ DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n"); ++ return -EINVAL; ++ } ++ return 0x0; + } + + static int + iegbe_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) + { +- struct pci_dev *pdev = NULL; ++ struct pci_dev *pdev = NULL; + pm_message_t state = {0x3}; + + +- switch(event) { +- case SYS_DOWN: +- case SYS_HALT: +- case SYS_POWER_OFF: +- while((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { ++ switch(event) { ++ case SYS_DOWN: ++ case SYS_HALT: ++ case SYS_POWER_OFF: ++ while((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { + if(pci_dev_driver(pdev) == &iegbe_driver) { +- iegbe_suspend(pdev, state); +- } +- } ++ iegbe_suspend(pdev, state); ++ } ++ } + } +- return NOTIFY_DONE; ++ return NOTIFY_DONE; + } + + static int + iegbe_suspend(struct pci_dev *pdev, pm_message_t state) + { +- struct net_device *netdev = pci_get_drvdata(pdev); +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- uint32_t ctrl, ctrl_ext, rctl, manc, status, swsm; +- uint32_t wufc = adapter->wol; +- uint16_t cmd_word; ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ uint32_t ctrl, ctrl_ext, rctl, manc, status, swsm; ++ uint32_t wufc = adapter->wol; ++ uint16_t cmd_word; + +- netif_device_detach(netdev); ++ netif_device_detach(netdev); + + if(netif_running(netdev)) { +- iegbe_down(adapter); ++ WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags)); ++ iegbe_down(adapter); + } +- /* +- * ICP_XXXX style MACs do not have a link up bit in +- * the STATUS register, query the PHY directly +- */ +- if(adapter->hw.mac_type != iegbe_icp_xxxx) { +- status = E1000_READ_REG(&adapter->hw, STATUS); ++ /* ++ * ICP_XXXX style MACs do not have a link up bit in ++ * the STATUS register, query the PHY directly ++ */ ++ if(adapter->hw.mac_type != iegbe_icp_xxxx) { ++ status = E1000_READ_REG(&adapter->hw, STATUS); + if(status & E1000_STATUS_LU) { +- wufc &= ~E1000_WUFC_LNKC; ++ wufc &= ~E1000_WUFC_LNKC; + } +- } else { +- int isUp = 0; ++ } else { ++ int isUp = 0x0; + if(iegbe_oem_phy_is_link_up(&adapter->hw, &isUp) != E1000_SUCCESS) { +- isUp = 0; ++ isUp = 0x0; + } + if(isUp) { +- wufc &= ~E1000_WUFC_LNKC; +- } ++ wufc &= ~E1000_WUFC_LNKC; ++ } + } + +- if(wufc) { +- iegbe_setup_rctl(adapter); +- iegbe_set_multi(netdev); +- +- /* turn on all-multi mode if wake on multicast is enabled */ +- if(adapter->wol & E1000_WUFC_MC) { +- rctl = E1000_READ_REG(&adapter->hw, RCTL); +- rctl |= E1000_RCTL_MPE; +- E1000_WRITE_REG(&adapter->hw, RCTL, rctl); +- } ++ if(wufc) { ++ iegbe_setup_rctl(adapter); ++ iegbe_set_rx_mode(netdev); ++ ++ /* turn on all-multi mode if wake on multicast is enabled */ ++ if(adapter->wol & E1000_WUFC_MC) { ++ rctl = E1000_READ_REG(&adapter->hw, RCTL); ++ rctl |= E1000_RCTL_MPE; ++ E1000_WRITE_REG(&adapter->hw, RCTL, rctl); ++ } + +- if(adapter->hw.mac_type >= iegbe_82540) { +- ctrl = E1000_READ_REG(&adapter->hw, CTRL); +- /* advertise wake from D3Cold */ +- #define E1000_CTRL_ADVD3WUC 0x00100000 +- /* phy power management enable */ +- ctrl |= E1000_CTRL_ADVD3WUC | +- (adapter->hw.mac_type != iegbe_icp_xxxx +- ? E1000_CTRL_EN_PHY_PWR_MGMT : 0); ++ if(adapter->hw.mac_type >= iegbe_82540) { ++ ctrl = E1000_READ_REG(&adapter->hw, CTRL); ++ /* advertise wake from D3Cold */ ++ #define E1000_CTRL_ADVD3WUC 0x00100000 ++ /* phy power management enable */ ++ #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 ++ ctrl |= E1000_CTRL_ADVD3WUC | ++ (adapter->hw.mac_type != iegbe_icp_xxxx ++ ? E1000_CTRL_EN_PHY_PWR_MGMT : 0x0); + +- E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); +- } ++ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); ++ } + +- if(adapter->hw.media_type == iegbe_media_type_fiber || +- adapter->hw.media_type == iegbe_media_type_internal_serdes) { +- /* keep the laser running in D3 */ +- ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); +- ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA; +- E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ctrl_ext); +- } ++ if(adapter->hw.media_type == iegbe_media_type_fiber || ++ adapter->hw.media_type == iegbe_media_type_internal_serdes) { ++ /* keep the laser running in D3 */ ++ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); ++ ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA; ++ E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ctrl_ext); ++ } + + /* Allow OEM PHYs (if any exist) to keep the laser + *running in D3 */ + iegbe_oem_fiber_live_in_suspend(&adapter->hw); + +- /* Allow time for pending master requests to run */ +- iegbe_disable_pciex_master(&adapter->hw); ++ /* Allow time for pending master requests to run */ ++ iegbe_disable_pciex_master(&adapter->hw); + +- E1000_WRITE_REG(&adapter->hw, WUC, E1000_WUC_PME_EN); +- E1000_WRITE_REG(&adapter->hw, WUFC, wufc); ++ E1000_WRITE_REG(&adapter->hw, WUC, E1000_WUC_PME_EN); ++ E1000_WRITE_REG(&adapter->hw, WUFC, wufc); + pci_enable_wake(pdev, 0x3, 0x1); + pci_enable_wake(pdev, 0x4, 0x1); /* 4 == D3 cold */ +- } else { +- E1000_WRITE_REG(&adapter->hw, WUC, 0); +- E1000_WRITE_REG(&adapter->hw, WUFC, 0); +- pci_enable_wake(pdev, 0x3, 0); +- pci_enable_wake(pdev, 0x4, 0); /* 4 == D3 cold */ +- } ++ } else { ++ E1000_WRITE_REG(&adapter->hw, WUC, 0x0); ++ E1000_WRITE_REG(&adapter->hw, WUFC, 0x0); ++ pci_enable_wake(pdev, 0x3, 0x0); ++ pci_enable_wake(pdev, 0x4, 0x0); /* 4 == D3 cold */ ++ } + +- pci_save_state(pdev); +- +- if(adapter->hw.mac_type >= iegbe_82540 +- && adapter->hw.mac_type != iegbe_icp_xxxx +- && adapter->hw.media_type == iegbe_media_type_copper) { +- manc = E1000_READ_REG(&adapter->hw, MANC); +- if(manc & E1000_MANC_SMBUS_EN) { +- manc |= E1000_MANC_ARP_EN; +- E1000_WRITE_REG(&adapter->hw, MANC, manc); ++ pci_save_state(pdev); ++ ++ if(adapter->hw.mac_type >= iegbe_82540 ++ && adapter->hw.mac_type != iegbe_icp_xxxx ++ && adapter->hw.media_type == iegbe_media_type_copper) { ++ manc = E1000_READ_REG(&adapter->hw, MANC); ++ if(manc & E1000_MANC_SMBUS_EN) { ++ manc |= E1000_MANC_ARP_EN; ++ E1000_WRITE_REG(&adapter->hw, MANC, manc); + pci_enable_wake(pdev, 0x3, 0x1); + pci_enable_wake(pdev, 0x4, 0x1); /* 4 == D3 cold */ +- } +- } ++ } ++ } + +- switch(adapter->hw.mac_type) { +- case iegbe_82571: +- case iegbe_82572: +- ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); +- E1000_WRITE_REG(&adapter->hw, CTRL_EXT, +- ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); +- break; +- case iegbe_82573: +- swsm = E1000_READ_REG(&adapter->hw, SWSM); +- E1000_WRITE_REG(&adapter->hw, SWSM, +- swsm & ~E1000_SWSM_DRV_LOAD); +- break; +- default: +- break; +- } ++ switch(adapter->hw.mac_type) { ++ case iegbe_82571: ++ case iegbe_82572: ++ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); ++ E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ++ ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); ++ break; ++ case iegbe_82573: ++ swsm = E1000_READ_REG(&adapter->hw, SWSM); ++ E1000_WRITE_REG(&adapter->hw, SWSM, ++ swsm & ~E1000_SWSM_DRV_LOAD); ++ break; ++ default: ++ break; ++ } + +- pci_disable_device(pdev); +- if(adapter->hw.mac_type == iegbe_icp_xxxx) { +- /* +- * ICP xxxx devices are not true PCI devices, in the context +- * of power management, disabling the bus mastership is not +- * sufficient to disable the device, it is also necessary to +- * disable IO, Memory, and Interrupts if they are enabled. +- */ +- pci_read_config_word(pdev, PCI_COMMAND, &cmd_word); ++ pci_disable_device(pdev); ++ if(adapter->hw.mac_type == iegbe_icp_xxxx) { ++ /* ++ * ICP xxxx devices are not true PCI devices, in the context ++ * of power management, disabling the bus mastership is not ++ * sufficient to disable the device, it is also necessary to ++ * disable IO, Memory, and Interrupts if they are enabled. ++ */ ++ pci_read_config_word(pdev, PCI_COMMAND, &cmd_word); + if(cmd_word & PCI_COMMAND_IO) { +- cmd_word &= ~PCI_COMMAND_IO; ++ cmd_word &= ~PCI_COMMAND_IO; + } + if(cmd_word & PCI_COMMAND_MEMORY) { +- cmd_word &= ~PCI_COMMAND_MEMORY; ++ cmd_word &= ~PCI_COMMAND_MEMORY; + } + if(cmd_word & PCI_COMMAND_INTX_DISABLE) { +- cmd_word &= ~PCI_COMMAND_INTX_DISABLE; ++ cmd_word &= ~PCI_COMMAND_INTX_DISABLE; + } +- pci_write_config_word(pdev, PCI_COMMAND, cmd_word); +- } ++ pci_write_config_word(pdev, PCI_COMMAND, cmd_word); ++ } + +- state.event = (state.event > 0) ? 0x3 : 0; +- pci_set_power_state(pdev, state.event); +- if(gcu_suspend == 0) ++ state.event = (state.event > 0x0) ? 0x3 : 0x0; ++ pci_set_power_state(pdev, state.event); ++ if(gcu_suspend == 0x0) + { + if(gcu == NULL) { +- gcu = pci_find_device(PCI_VENDOR_ID_INTEL, GCU_DEVID, NULL); +- } ++ gcu = pci_get_device(PCI_VENDOR_ID_INTEL, GCU_DEVID, NULL); ++ } + gcu_iegbe_suspend(gcu, 0x3); +- gcu_suspend = 1; +- gcu_resume = 0; ++ gcu_suspend = 0x1; ++ gcu_resume = 0x0; + } +- return 0; ++ return 0x0; + } + + #ifdef CONFIG_PM + static int + iegbe_resume(struct pci_dev *pdev) + { +- struct net_device *netdev = pci_get_drvdata(pdev); +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- uint32_t manc, ret_val, swsm; +- uint32_t ctrl_ext; ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ uint32_t manc, ret_val, swsm; ++ uint32_t ctrl_ext; + int offset; + uint32_t vdid; + +- if(gcu_resume == 0) ++ if(gcu_resume == 0x0) + { + if(gcu == NULL) { +- gcu = pci_find_device(PCI_VENDOR_ID_INTEL, GCU_DEVID, NULL); ++ gcu = pci_get_device(PCI_VENDOR_ID_INTEL, GCU_DEVID, NULL); + pci_read_config_dword(gcu, 0x00, &vdid); +- } +- ++ } ++ + if(gcu) { + gcu_iegbe_resume(gcu); +- gcu_resume = 1; +- gcu_suspend = 0; ++ gcu_resume = 0x1; ++ gcu_suspend = 0x0; + } else { + printk("Unable to resume GCU!\n"); +- } ++ } + } + pci_set_power_state(pdev, 0x0); +- pci_restore_state(pdev); +- ret_val = pci_enable_device(pdev); +- pci_set_master(pdev); ++ pci_restore_state(pdev); ++ ret_val = pci_enable_device(pdev); ++ pci_set_master(pdev); + + pci_enable_wake(pdev, 0x3, 0x0); + pci_enable_wake(pdev, 0x4, 0x0); /* 4 == D3 cold */ + +- iegbe_reset(adapter); +- E1000_WRITE_REG(&adapter->hw, WUS, ~0); ++ iegbe_reset(adapter); ++ E1000_WRITE_REG(&adapter->hw, WUS, ~0); + offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_ST) + + PCI_ST_SMIA_OFFSET; + pci_write_config_dword(adapter->pdev, offset, 0x00000006); +@@ -5138,51 +4848,52 @@ iegbe_resume(struct pci_dev *pdev) + E1000_WRITE_REG(&adapter->hw, IMC2, ~0UL); + + if(netif_running(netdev)) { +- iegbe_up(adapter); ++ iegbe_up(adapter); + } +- netif_device_attach(netdev); +- +- if(adapter->hw.mac_type >= iegbe_82540 +- && adapter->hw.mac_type != iegbe_icp_xxxx +- && adapter->hw.media_type == iegbe_media_type_copper) { +- manc = E1000_READ_REG(&adapter->hw, MANC); +- manc &= ~(E1000_MANC_ARP_EN); +- E1000_WRITE_REG(&adapter->hw, MANC, manc); +- } ++ netif_device_attach(netdev); + +- switch(adapter->hw.mac_type) { +- case iegbe_82571: +- case iegbe_82572: +- ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); +- E1000_WRITE_REG(&adapter->hw, CTRL_EXT, +- ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); +- break; +- case iegbe_82573: +- swsm = E1000_READ_REG(&adapter->hw, SWSM); +- E1000_WRITE_REG(&adapter->hw, SWSM, +- swsm | E1000_SWSM_DRV_LOAD); +- break; +- default: +- break; +- } ++ if(adapter->hw.mac_type >= iegbe_82540 ++ && adapter->hw.mac_type != iegbe_icp_xxxx ++ && adapter->hw.media_type == iegbe_media_type_copper) { ++ manc = E1000_READ_REG(&adapter->hw, MANC); ++ manc &= ~(E1000_MANC_ARP_EN); ++ E1000_WRITE_REG(&adapter->hw, MANC, manc); ++ } ++ ++ switch(adapter->hw.mac_type) { ++ case iegbe_82571: ++ case iegbe_82572: ++ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); ++ E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ++ ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); ++ break; ++ case iegbe_82573: ++ swsm = E1000_READ_REG(&adapter->hw, SWSM); ++ E1000_WRITE_REG(&adapter->hw, SWSM, ++ swsm | E1000_SWSM_DRV_LOAD); ++ break; ++ default: ++ break; ++ } ++#endif + +- return 0; ++ return 0x0; + } +-#endif ++ + #ifdef CONFIG_NET_POLL_CONTROLLER + /* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ +-static void +-iegbe_netpoll(struct net_device *netdev) ++static void iegbe_netpoll(struct net_device *netdev) + { +- struct iegbe_adapter *adapter = netdev_priv(netdev); +- disable_irq(adapter->pdev->irq); +- iegbe_intr(adapter->pdev->irq, netdev, NULL); +- enable_irq(adapter->pdev->irq); ++ struct iegbe_adapter *adapter = netdev_priv(netdev); ++ disable_irq(adapter->pdev->irq); ++ iegbe_intr(adapter->pdev->irq, netdev); ++ enable_irq(adapter->pdev->irq); + } + #endif + ++ + /* iegbe_main.c */ +--- a/Embedded/src/GbE/iegbe_oem_phy.c ++++ b/Embedded/src/GbE/iegbe_oem_phy.c +@@ -2,31 +2,31 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + +- This program is free software; you can redistribute it and/or modify ++ This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + +- You should have received a copy of the GNU General Public License +- along with this program; if not, write to the Free Software ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- The full GNU General Public License is included in this distribution ++ The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +- Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226 ++ Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226 + + *****************************************************************************/ + /************************************************************************** +@@ -65,11 +65,6 @@ static int32_t iegbe_oem_link_m88_setup( + static int32_t iegbe_oem_set_phy_mode(struct iegbe_hw *hw); + static int32_t iegbe_oem_detect_phy(struct iegbe_hw *hw); + +-/* Define specific BCM functions */ +-static int32_t iegbe_oem_link_bcm5481_setup(struct iegbe_hw *hw); +-static int32_t bcm5481_read_18sv (struct iegbe_hw *hw, int sv, uint16_t *data); +-static int32_t oi_phy_setup (struct iegbe_hw *hw); +- + /** + * iegbe_oem_setup_link + * @hw: iegbe_hw struct containing device specific information +@@ -84,7 +79,7 @@ iegbe_oem_setup_link(struct iegbe_hw *hw + { + #ifdef EXTERNAL_MDIO + +- /* ++ /* + * see iegbe_setup_copper_link() as the primary example. Look at both + * the M88 and IGP functions that are called for ideas, possibly for + * power management. +@@ -102,14 +97,14 @@ iegbe_oem_setup_link(struct iegbe_hw *hw + } + /* AFU: add test to exit out if improper phy type + */ +- /* relevent parts of iegbe_copper_link_preconfig */ +- ctrl = E1000_READ_REG(hw, CTRL); +- ctrl |= E1000_CTRL_SLU; +- ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); +- E1000_WRITE_REG(hw, CTRL, ctrl); +- ++ /* relevent parts of iegbe_copper_link_preconfig */ ++ ctrl = E1000_READ_REG(hw, CTRL); ++ ctrl |= E1000_CTRL_SLU; ++ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); ++ E1000_WRITE_REG(hw, CTRL, ctrl); ++ + /* this is required for *hw init */ +- ret_val = iegbe_oem_detect_phy(hw); ++ ret_val = iegbe_oem_detect_phy(hw); + if(ret_val) { + return ret_val; + } +@@ -119,23 +114,13 @@ iegbe_oem_setup_link(struct iegbe_hw *hw + } + + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- return E1000_SUCCESS; +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + ret_val = iegbe_oem_link_m88_setup(hw); +- if(ret_val) { +- return ret_val; +- } +- break; +- case BCM5481_PHY_ID: +- ret_val = iegbe_oem_link_bcm5481_setup(hw); +- if(ret_val) { +- return ret_val; ++ if(ret_val) { ++ return ret_val; + } +- break; ++ break; + default: + DEBUGOUT("Invalid PHY ID\n"); + return -E1000_ERR_PHY_TYPE; +@@ -143,16 +128,16 @@ iegbe_oem_setup_link(struct iegbe_hw *hw + + if(hw->autoneg) { + ret_val = iegbe_copper_link_autoneg(hw); +- if(ret_val) { +- return ret_val; +- } ++ if(ret_val) { ++ return ret_val; + } ++ } + else { + DEBUGOUT("Forcing speed and duplex\n"); + ret_val = iegbe_phy_force_speed_duplex(hw); + } +- +- /* ++ ++ /* + * Check link status. Wait up to 100 microseconds for link to become + * valid. + */ +@@ -194,51 +179,6 @@ iegbe_oem_setup_link(struct iegbe_hw *hw + #endif /* ifdef EXTERNAL_MDIO */ + } + +-/** +- * iegbe_oem_link_bcm5481_setup +- * @hw: iegbe_hw struct containing device specific information +- * +- * Returns E1000_SUCCESS, negative E1000 error code on failure +- * +- * copied verbatim from iegbe_oem_link_m88_setup +- **/ +-static int32_t +-iegbe_oem_link_bcm5481_setup(struct iegbe_hw *hw) +-{ +- int32_t ret_val; +- uint16_t phy_data; +- +- //DEBUGFUNC(__func__); +- +- if(!hw) +- return -1; +- +- /* phy_reset_disable is set in iegbe_oem_set_phy_mode */ +- if(hw->phy_reset_disable) +- return E1000_SUCCESS; +- +- // Enable MDIX in extended control reg. +- ret_val = iegbe_oem_read_phy_reg_ex(hw, BCM5481_ECTRL, &phy_data); +- if(ret_val) +- { +- DEBUGOUT("Unable to read BCM5481_ECTRL register\n"); +- return ret_val; +- } +- +- phy_data &= ~BCM5481_ECTRL_DISMDIX; +- ret_val = iegbe_oem_write_phy_reg_ex(hw, BCM5481_ECTRL, phy_data); +- if(ret_val) +- { +- DEBUGOUT("Unable to write BCM5481_ECTRL register\n"); +- return ret_val; +- } +- +- ret_val = oi_phy_setup (hw); +- if (ret_val) +- return ret_val; +- +- return E1000_SUCCESS; +-} + + /** + * iegbe_oem_link_m88_setup +@@ -253,7 +193,7 @@ static int32_t + iegbe_oem_link_m88_setup(struct iegbe_hw *hw) + { + int32_t ret_val; +- uint16_t phy_data; ++ uint16_t phy_data = 0; + + DEBUGFUNC1("%s",__func__); + +@@ -261,7 +201,7 @@ iegbe_oem_link_m88_setup(struct iegbe_hw + return -1; + } + +- ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, + &phy_data); + phy_data |= 0x00000008; + ret_val = iegbe_oem_write_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, phy_data); +@@ -279,7 +219,7 @@ iegbe_oem_link_m88_setup(struct iegbe_hw + + phy_data &= ~M88E1000_PSCR_ASSERT_CRS_ON_TX; + +- /* ++ /* + * Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds +@@ -305,7 +245,7 @@ iegbe_oem_link_m88_setup(struct iegbe_hw + break; + } + +- /* ++ /* + * Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity +@@ -316,25 +256,25 @@ iegbe_oem_link_m88_setup(struct iegbe_hw + + if(hw->disable_polarity_correction == 1) { + phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; +- } ++ } + ret_val = iegbe_oem_write_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if(ret_val) { + DEBUGOUT("Unable to write M88E1000_PHY_SPEC_CTRL register\n"); + return ret_val; + } + +- /* ++ /* + * Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ +- ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_EXT_PHY_SPEC_CTRL, ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read M88E1000_EXT_PHY_SPEC_CTRL register\n"); + return ret_val; + } + +- /* ++ /* + * For Truxton, it is necessary to add RGMII tx and rx + * timing delay though the EXT_PHY_SPEC_CTRL register + */ +@@ -350,13 +290,13 @@ iegbe_oem_link_m88_setup(struct iegbe_hw + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); + } +- ret_val = iegbe_oem_write_phy_reg_ex(hw, M88E1000_EXT_PHY_SPEC_CTRL, ++ ret_val = iegbe_oem_write_phy_reg_ex(hw, M88E1000_EXT_PHY_SPEC_CTRL, + phy_data); + if(ret_val) { + DEBUGOUT("Unable to read M88E1000_EXT_PHY_SPEC_CTRL register\n"); + return ret_val; + } +- ++ + + /* SW Reset the PHY so all changes take effect */ + ret_val = iegbe_phy_hw_reset(hw); +@@ -371,7 +311,7 @@ iegbe_oem_link_m88_setup(struct iegbe_hw + /** + * iegbe_oem_force_mdi + * @hw: iegbe_hw struct containing device specific information +- * @resetPhy: returns true if after calling this function the ++ * @resetPhy: returns true if after calling this function the + * PHY requires a reset + * + * Returns E1000_SUCCESS, negative E1000 error code on failure +@@ -379,7 +319,7 @@ iegbe_oem_link_m88_setup(struct iegbe_hw + * This is called from iegbe_phy_force_speed_duplex, which is + * called from iegbe_oem_setup_link. + **/ +-int32_t ++int32_t + iegbe_oem_force_mdi(struct iegbe_hw *hw, int *resetPhy) + { + #ifdef EXTERNAL_MDIO +@@ -393,35 +333,30 @@ iegbe_oem_force_mdi(struct iegbe_hw *hw, + return -1; + } + +- /* ++ /* + * a boolean to indicate if the phy needs to be reset +- * ++ * + * Make note that the M88 phy is what'll be used on Truxton + * see iegbe_phy_force_speed_duplex, which does the following for M88 + */ + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- case BCM5481_PHY_ID: +- DEBUGOUT("WARNING: An empty iegbe_oem_force_mdi() has been called!\n"); +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- ret_val = iegbe_oem_read_phy_reg_ex(hw, +- M88E1000_PHY_SPEC_CTRL, ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, ++ M88E1000_PHY_SPEC_CTRL, + &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read M88E1000_PHY_SPEC_CTRL register\n"); + return ret_val; + } +- ++ + /* +- * Clear Auto-Crossover to force MDI manually. M88E1000 requires ++ * Clear Auto-Crossover to force MDI manually. M88E1000 requires + * MDI forced whenever speed are duplex are forced. + */ +- ++ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; +- ret_val = iegbe_oem_write_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, ++ ret_val = iegbe_oem_write_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, + phy_data); + if(ret_val) { + DEBUGOUT("Unable to write M88E1000_PHY_SPEC_CTRL register\n"); +@@ -458,7 +393,7 @@ iegbe_oem_force_mdi(struct iegbe_hw *hw, + * This is called from iegbe_phy_force_speed_duplex, which is + * called from iegbe_oem_setup_link. + **/ +-int32_t ++int32_t + iegbe_oem_phy_reset_dsp(struct iegbe_hw *hw) + { + #ifdef EXTERNAL_MDIO +@@ -478,10 +413,8 @@ iegbe_oem_phy_reset_dsp(struct iegbe_hw + * no-op. + */ + switch (hw->phy_id) { +- case M88E1000_I_PHY_ID: +- case M88E1141_E_PHY_ID: +- case BCM5481_PHY_ID: +- case BCM5395S_PHY_ID: ++ case M88E1000_I_PHY_ID: ++ case M88E1141_E_PHY_ID: + DEBUGOUT("No DSP to reset on OEM PHY\n"); + break; + default: +@@ -508,7 +441,7 @@ iegbe_oem_phy_reset_dsp(struct iegbe_hw + * This is called from iegbe_phy_force_speed_duplex, which is + * called from iegbe_oem_setup_link. + **/ +-int32_t ++int32_t + iegbe_oem_cleanup_after_phy_reset(struct iegbe_hw *hw) + { + #ifdef EXTERNAL_MDIO +@@ -520,29 +453,24 @@ iegbe_oem_cleanup_after_phy_reset(struct + + if(!hw) { + return -1; +- } ++ } + +- /* ++ /* + * Make note that the M88 phy is what'll be used on Truxton. + * see iegbe_phy_force_speed_duplex, which does the following for M88 + */ + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- case BCM5481_PHY_ID: +- DEBUGOUT("WARNING: An empty iegbe_oem_cleanup_after_phy_reset() has been called!\n"); +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + /* +- * Because we reset the PHY above, we need to re-force ++ * Because we reset the PHY above, we need to re-force + * TX_CLK in the Extended PHY Specific Control Register to + * 25MHz clock. This value defaults back to a 2.5MHz clock + * when the PHY is reset. + */ + + ret_val = iegbe_oem_read_phy_reg_ex(hw, +- M88E1000_EXT_PHY_SPEC_CTRL, ++ M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read M88E1000_EXT_SPEC_CTRL register\n"); +@@ -550,22 +478,23 @@ iegbe_oem_cleanup_after_phy_reset(struct + } + + phy_data |= M88E1000_EPSCR_TX_CLK_25; +- ret_val = iegbe_oem_write_phy_reg_ex(hw, +- M88E1000_EXT_PHY_SPEC_CTRL, ++ ret_val = iegbe_oem_write_phy_reg_ex(hw, ++ M88E1000_EXT_PHY_SPEC_CTRL, + phy_data); + if(ret_val) { +- DEBUGOUT("Unable to write M88E1000_EXT_PHY_SPEC_CTRL register\n"); ++ DEBUGOUT("Unable to write M88E1000_EXT_PHY_SPEC_CTRL " ++ "register\n"); + return ret_val; + } + + /* + * In addition, because of the s/w reset above, we need to enable +- * CRX on TX. This must be set for both full and half duplex ++ * CRX on TX. This must be set for both full and half duplex + * operation. + */ + +- ret_val = iegbe_oem_read_phy_reg_ex(hw, +- M88E1000_PHY_SPEC_CTRL, ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, ++ M88E1000_PHY_SPEC_CTRL, + &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read M88E1000_PHY_SPEC_CTRL register\n"); +@@ -573,12 +502,12 @@ iegbe_oem_cleanup_after_phy_reset(struct + } + + phy_data &= ~M88E1000_PSCR_ASSERT_CRS_ON_TX; +- ret_val = iegbe_oem_write_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, ++ ret_val = iegbe_oem_write_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, + phy_data); + if(ret_val) { + DEBUGOUT("Unable to write M88E1000_PHY_SPEC_CTRL register\n"); + return ret_val; +- } ++ } + break; + default: + DEBUGOUT("Invalid PHY ID\n"); +@@ -604,12 +533,12 @@ iegbe_oem_cleanup_after_phy_reset(struct + * This is called from iegbe_oem_setup_link which is + * called from iegbe_setup_link. + **/ +-static int32_t ++static int32_t + iegbe_oem_set_phy_mode(struct iegbe_hw *hw) + { + /* + * it is unclear if it is necessary to set the phy mode. Right now only +- * one MAC 82545 Rev 3 does it, but the other MACs like Tolapai do not. ++ * one MAC 82545 Rev 3 does it, but the other MACs like tola do not. + * Leave the functionality off for now until it is determined that Tolapai + * needs it as well. + */ +@@ -638,41 +567,37 @@ iegbe_oem_set_phy_mode(struct iegbe_hw * + #ifndef skip_set_mode + DEBUGOUT("No need to call oem_set_phy_mode on Truxton\n"); + #else +- /* ++ /* + * Make note that the M88 phy is what'll be used on Truxton. + * + * use iegbe_set_phy_mode as example + */ + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- case BCM5481_PHY_ID: +- DEBUGOUT("WARNING: An empty iegbe_oem_set_phy_mode() has been called!\n"); +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- ret_val = iegbe_read_eeprom(hw, +- EEPROM_PHY_CLASS_WORD, +- 1, ++ ret_val = iegbe_read_eeprom(hw, ++ EEPROM_PHY_CLASS_WORD, ++ 1, + &eeprom_data); + if(ret_val) { + return ret_val; + } + +- if((eeprom_data != EEPROM_RESERVED_WORD) && +- (eeprom_data & EEPROM_PHY_CLASS_A)) ++ if((eeprom_data != EEPROM_RESERVED_WORD) && ++ (eeprom_data & EEPROM_PHY_CLASS_A)) + { +- ret_val = iegbe_oem_write_phy_reg_ex(hw, +- M88E1000_PHY_PAGE_SELECT, +- 0x000B); ++ ret_val = iegbe_oem_write_phy_reg_ex(hw, ++ M88E1000_PHY_PAGE_SELECT, ++ 0x000B); + if(ret_val) { +- DEBUGOUT("Unable to write to M88E1000_PHY_PAGE_SELECT register on PHY\n"); ++ DEBUGOUT("Unable to write to M88E1000_PHY_PAGE_SELECT " ++ "register on PHY\n"); + return ret_val; + } + +- ret_val = iegbe_oem_write_phy_reg_ex(hw, +- M88E1000_PHY_GEN_CONTROL, +- 0x8104); ++ ret_val = iegbe_oem_write_phy_reg_ex(hw, ++ M88E1000_PHY_GEN_CONTROL, ++ 0x8104); + if(ret_val) { + DEBUGOUT("Unable to write to M88E1000_PHY_GEN_CONTROL" + "register on PHY\n"); +@@ -687,11 +612,12 @@ iegbe_oem_set_phy_mode(struct iegbe_hw * + return -E1000_ERR_PHY_TYPE; + } + #endif +- ++ + return E1000_SUCCESS; + + } + ++ + /** + * iegbe_oem_detect_phy + * @hw: iegbe_hw struct containing device specific information +@@ -702,7 +628,7 @@ iegbe_oem_set_phy_mode(struct iegbe_hw * + * + * This borrows heavily from iegbe_detect_gig_phy + **/ +-static int32_t ++static int32_t + iegbe_oem_detect_phy(struct iegbe_hw *hw) + { + int32_t ret_val; +@@ -715,33 +641,20 @@ iegbe_oem_detect_phy(struct iegbe_hw *hw + } + hw->phy_type = iegbe_phy_oem; + +-{ +- // If MAC2 (BCM5395 switch), manually detect the phy +- struct iegbe_adapter *adapter; +- uint32_t device_number; +- adapter = (struct iegbe_adapter *) hw->back; +- device_number = PCI_SLOT(adapter->pdev->devfn); +- if (device_number == ICP_XXXX_MAC_2) { +- hw->phy_id = BCM5395S_PHY_ID; +- hw->phy_revision = 0; +- return E1000_SUCCESS; +- } +-} +- +- + ret_val = iegbe_oem_read_phy_reg_ex(hw, PHY_ID1, &phy_id_high); + if(ret_val) { + DEBUGOUT("Unable to read PHY register PHY_ID1\n"); + return ret_val; + } +- ++ + usec_delay(0x14); + ret_val = iegbe_oem_read_phy_reg_ex(hw, PHY_ID2, &phy_id_low); + if(ret_val) { + DEBUGOUT("Unable to read PHY register PHY_ID2\n"); + return ret_val; + } +- hw->phy_id = (uint32_t) ((phy_id_high << 0x10) + phy_id_low); ++ hw->phy_id = (uint32_t) ((phy_id_high << 0x10) + ++ (phy_id_low & PHY_REVISION_MASK)); + hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK; + + return E1000_SUCCESS; +@@ -753,15 +666,15 @@ iegbe_oem_detect_phy(struct iegbe_hw *hw + * @hw: iegbe_hw struct containing device specific information + * + * Returns the value of the Inter Packet Gap (IPG) Transmit Time (IPGT) in the +- * Transmit IPG register appropriate for the given PHY. This field is only 10 ++ * Transmit IPG register appropriate for the given PHY. This field is only 10 + * bits wide. + * + * In the original iegbe code, only the IPGT field varied between media types. +- * If the OEM phy requires setting IPG Receive Time 1 & 2 Registers, it would ++ * If the OEM phy requires setting IPG Receive Time 1 & 2 Registers, it would + * be required to modify the iegbe_config_tx() function to accomdate the change + * + **/ +-uint32_t ++uint32_t + iegbe_oem_get_tipg(struct iegbe_hw *hw) + { + #ifdef EXTERNAL_MDIO +@@ -777,15 +690,13 @@ iegbe_oem_get_tipg(struct iegbe_hw *hw) + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- case BCM5481_PHY_ID: +- case BCM5395S_PHY_ID: + phy_num = DEFAULT_ICP_XXXX_TIPG_IPGT; + break; + default: + DEBUGOUT("Invalid PHY ID\n"); + return DEFAULT_ICP_XXXX_TIPG_IPGT; + } +- ++ + return phy_num; + + #else /* ifdef EXTERNAL_MDIO */ +@@ -803,15 +714,15 @@ iegbe_oem_get_tipg(struct iegbe_hw *hw) + * iegbe_oem_phy_is_copper + * @hw: iegbe_hw struct containing device specific information + * +- * Test for media type within the iegbe driver is common, so this is a simple +- * test for copper PHYs. The ICP_XXXX family of controllers initially only +- * supported copper interconnects (no TBI (ten bit interface) for Fiber +- * existed). If future revs support either Fiber or an internal SERDES, it +- * may become necessary to evaluate where this function is used to go beyond ++ * Test for media type within the iegbe driver is common, so this is a simple ++ * test for copper PHYs. The ICP_XXXX family of controllers initially only ++ * supported copper interconnects (no TBI (ten bit interface) for Fiber ++ * existed). If future revs support either Fiber or an internal SERDES, it ++ * may become necessary to evaluate where this function is used to go beyond + * determining whether or not media type is just copper. + * + **/ +-int ++int + iegbe_oem_phy_is_copper(struct iegbe_hw *hw) + { + #ifdef EXTERNAL_MDIO +@@ -827,23 +738,21 @@ iegbe_oem_phy_is_copper(struct iegbe_hw + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- case BCM5481_PHY_ID: +- case BCM5395S_PHY_ID: + isCopper = TRUE; + break; + default: + DEBUGOUT("Invalid PHY ID\n"); + return -E1000_ERR_PHY_TYPE; + } +- ++ + return isCopper; + + #else /* ifdef EXTERNAL_MDIO */ + +- /* ++ /* + * caught between returning true or false. True allows it to + * be entered into && statements w/o ill effect, but false +- * would make more sense ++ * would make more sense + */ + DEBUGOUT("Invalid value for transceiver type, return FALSE\n"); + return FALSE; +@@ -856,19 +765,19 @@ iegbe_oem_phy_is_copper(struct iegbe_hw + * iegbe_oem_get_phy_dev_number + * @hw: iegbe_hw struct containing device specific information + * +- * For ICP_XXXX family of devices, there are 3 MACs, each of which may +- * have a different PHY (and indeed a different media interface). This +- * function is used to indicate which of the MAC/PHY pairs we are interested ++ * For ICP_XXXX family of devices, there are 3 MACs, each of which may ++ * have a different PHY (and indeed a different media interface). This ++ * function is used to indicate which of the MAC/PHY pairs we are interested + * in. +- * ++ * + **/ +-uint32_t ++uint32_t + iegbe_oem_get_phy_dev_number(struct iegbe_hw *hw) + { + #ifdef EXTERNAL_MDIO + +- /* +- * for ICP_XXXX family of devices, the three network interfaces are ++ /* ++ * for ICP_XXXX family of devices, the three network interfaces are + * differentiated by their PCI device number, where the three share + * the same PCI bus + */ +@@ -886,15 +795,15 @@ iegbe_oem_get_phy_dev_number(struct iegb + + switch(device_number) + { +- case ICP_XXXX_MAC_0: ++ case ICP_XXXX_MAC_0: ++ hw->phy_addr = 0x00; ++ break; ++ case ICP_XXXX_MAC_1: + hw->phy_addr = 0x01; + break; +- case ICP_XXXX_MAC_1: ++ case ICP_XXXX_MAC_2: + hw->phy_addr = 0x02; + break; +- case ICP_XXXX_MAC_2: +- hw->phy_addr = 0x00; +- break; + default: hw->phy_addr = 0x00; + } + return hw->phy_addr; +@@ -915,7 +824,7 @@ iegbe_oem_get_phy_dev_number(struct iegb + * @cmd: the original IOCTL command that instigated the call chain. + * + * This function abstracts out the code necessary to service the +- * SIOCSMIIREG case within the iegbe_mii_ioctl() for oem PHYs. ++ * SIOCSMIIREG case within the iegbe_mii_ioctl() for oem PHYs. + * iegbe_mii_ioctl() was implemented for copper phy's only and this + * function will only be called if iegbe_oem_phy_is_copper() returns true for + * a given MAC. Note that iegbe_mii_ioctl() has a compile flag +@@ -924,14 +833,14 @@ iegbe_oem_get_phy_dev_number(struct iegb + * NOTE: a spinlock is in effect for the duration of this call. It is + * imperative that a negative value be returned on any error, so + * the spinlock can be released properly. +- * ++ * + **/ + int + iegbe_oem_mii_ioctl(struct iegbe_adapter *adapter, unsigned long flags, + struct ifreq *ifr, int cmd) + { + #ifdef EXTERNAL_MDIO +- ++ + struct mii_ioctl_data *data = if_mii(ifr); + uint16_t mii_reg = data->val_in; + uint16_t spddplx; +@@ -942,12 +851,6 @@ iegbe_oem_mii_ioctl(struct iegbe_adapter + if(!adapter || !ifr) { + return -1; + } +- +- // If MAC2 (BCM5395 switch) then leave now +- if ((PCI_SLOT(adapter->pdev->devfn)) == ICP_XXXX_MAC_2) { +- return -1; +- } +- + switch (data->reg_num) { + case PHY_CTRL: + if(mii_reg & MII_CR_POWER_DOWN) { +@@ -956,7 +859,7 @@ iegbe_oem_mii_ioctl(struct iegbe_adapter + if(mii_reg & MII_CR_AUTO_NEG_EN) { + adapter->hw.autoneg = 1; + adapter->hw.autoneg_advertised = ICP_XXXX_AUTONEG_ADV_DEFAULT; +- } ++ } + else { + if(mii_reg & 0x40) { + spddplx = SPEED_1000; +@@ -976,7 +879,7 @@ iegbe_oem_mii_ioctl(struct iegbe_adapter + if(netif_running(adapter->netdev)) { + iegbe_down(adapter); + iegbe_up(adapter); +- } ++ } + else { + iegbe_reset(adapter); + } +@@ -1043,10 +946,10 @@ void iegbe_oem_fiber_live_in_suspend(str + * Note: The call to iegbe_get_regs() assumed an array of 24 elements + * where the last 11 are passed to this function. If the array + * that is passed to the calling function has its size or element +- * defintions changed, this function becomes broken. ++ * defintions changed, this function becomes broken. + * + **/ +-void iegbe_oem_get_phy_regs(struct iegbe_adapter *adapter, uint32_t *data, ++void iegbe_oem_get_phy_regs(struct iegbe_adapter *adapter, uint32_t *data, + uint32_t data_len) + { + #define EXPECTED_ARRAY_LEN 11 +@@ -1062,13 +965,13 @@ void iegbe_oem_get_phy_regs(struct iegbe + * Use the corrected_length variable to make sure we don't exceed that + * length + */ +- corrected_len = data_len>EXPECTED_ARRAY_LEN ++ corrected_len = data_len>EXPECTED_ARRAY_LEN + ? EXPECTED_ARRAY_LEN : data_len; + memset(data, 0, corrected_len*sizeof(uint32_t)); + + #ifdef EXTERNAL_MDIO + +- /* ++ /* + * Fill data[] with... + * + * [0] = cable length +@@ -1084,16 +987,11 @@ void iegbe_oem_get_phy_regs(struct iegbe + * [10] = mdix mode + */ + switch (adapter->hw.phy_id) { +- case BCM5395S_PHY_ID: +- case BCM5481_PHY_ID: +- DEBUGOUT("WARNING: An empty iegbe_oem_get_phy_regs() has been called!\n"); +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + if(corrected_len > 0) { +- iegbe_oem_read_phy_reg_ex(&adapter->hw, +- M88E1000_PHY_SPEC_STATUS, ++ iegbe_oem_read_phy_reg_ex(&adapter->hw, ++ M88E1000_PHY_SPEC_STATUS, + (uint16_t *) &data[0]); + } + if(corrected_len > 0x1){ +@@ -1106,7 +1004,7 @@ void iegbe_oem_get_phy_regs(struct iegbe + data[0x3] = 0x0; /* Dummy (to align w/ IGP phy reg dump) */ + } + if(corrected_len > 0x4) { +- iegbe_oem_read_phy_reg_ex(&adapter->hw, M88E1000_PHY_SPEC_CTRL, ++ iegbe_oem_read_phy_reg_ex(&adapter->hw, M88E1000_PHY_SPEC_CTRL, + (uint16_t *) &data[0x4]); + } + if(corrected_len > 0x5) { +@@ -1144,7 +1042,7 @@ void iegbe_oem_get_phy_regs(struct iegbe + * This is called from iegbe_set_phy_loopback in response from call from + * ethtool to place the PHY into loopback mode. + **/ +-int ++int + iegbe_oem_phy_loopback(struct iegbe_adapter *adapter) + { + #ifdef EXTERNAL_MDIO +@@ -1165,23 +1063,18 @@ iegbe_oem_phy_loopback(struct iegbe_adap + * was that nonintegrated called iegbe_phy_reset_clk_and_crs(), + * hopefully this won't matter as CRS required for half-duplex + * operation and this is set to full duplex. +- * ++ * + * Make note that the M88 phy is what'll be used on Truxton + * Loopback configuration is the same for each of the supported PHYs. + */ + switch (adapter->hw.phy_id) { +- case BCM5395S_PHY_ID: +- DEBUGOUT("WARNING: An empty iegbe_oem_phy_loopback() has been called!\n"); +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- case BCM5481_PHY_ID: + + adapter->hw.autoneg = FALSE; + + /* turn off Auto-MDI/MDIX */ +- /*ret_val = iegbe_oem_write_phy_reg_ex(&adapter->hw, ++ /*ret_val = iegbe_oem_write_phy_reg_ex(&adapter->hw, + M88E1000_PHY_SPEC_CTRL, 0x0808); + if(ret_val) + { +@@ -1206,10 +1099,10 @@ iegbe_oem_phy_loopback(struct iegbe_adap + DEBUGOUT("Unable to write to register PHY_CTRL\n"); + return ret_val; + } +- +- ++ ++ + /* force 1000, set loopback */ +- /*ret_val = ++ /*ret_val = + iegbe_oem_write_phy_reg_ex(&adapter->hw, PHY_CTRL, 0x4140); */ + ret_val = iegbe_oem_write_phy_reg_ex(&adapter->hw, PHY_CTRL, 0x6100); + if(ret_val) { +@@ -1228,21 +1121,21 @@ iegbe_oem_phy_loopback(struct iegbe_adap + E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg); + + /* +- * Write out to PHY registers 29 and 30 to disable the Receiver. ++ * Write out to PHY registers 29 and 30 to disable the Receiver. + * This directly lifted from iegbe_phy_disable_receiver(). +- * ++ * + * The code is currently commented out as for the M88 used in + * Truxton, registers 29 and 30 are unutilized. Leave in, just +- * in case we are on the receiving end of an 'undocumented' ++ * in case we are on the receiving end of an 'undocumented' + * feature + */ +- /* ++ /* + * iegbe_oem_write_phy_reg_ex(&adapter->hw, 29, 0x001F); + * iegbe_oem_write_phy_reg_ex(&adapter->hw, 30, 0x8FFC); + * iegbe_oem_write_phy_reg_ex(&adapter->hw, 29, 0x001A); + * iegbe_oem_write_phy_reg_ex(&adapter->hw, 30, 0x8FF0); + */ +- ++ + break; + default: + DEBUGOUT("Invalid PHY ID\n"); +@@ -1268,15 +1161,15 @@ iegbe_oem_phy_loopback(struct iegbe_adap + * ethtool to place the PHY out of loopback mode. This handles the OEM + * specific part of loopback cleanup. + **/ +-void ++void + iegbe_oem_loopback_cleanup(struct iegbe_adapter *adapter) + { + #ifdef EXTERNAL_MDIO + +- /* +- * This borrows liberally from iegbe_loopback_cleanup(). ++ /* ++ * This borrows liberally from iegbe_loopback_cleanup(). + * making note that the M88 phy is what'll be used on Truxton +- * ++ * + * Loopback cleanup is the same for all supported PHYs. + */ + int32_t ret_val; +@@ -1289,38 +1182,32 @@ iegbe_oem_loopback_cleanup(struct iegbe_ + } + + switch (adapter->hw.phy_id) { +- case BCM5395S_PHY_ID: +- DEBUGOUT("WARNING: An empty iegbe_oem_loopback_cleanup() has been called!\n"); +- return; +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- case BCM5481_PHY_ID: + default: + adapter->hw.autoneg = TRUE; +- +- ret_val = iegbe_oem_read_phy_reg_ex(&adapter->hw, PHY_CTRL, ++ ++ ret_val = iegbe_oem_read_phy_reg_ex(&adapter->hw, PHY_CTRL, + &phy_reg); + if(ret_val) { + DEBUGOUT("Unable to read to register PHY_CTRL\n"); + return; + } +- ++ + if(phy_reg & MII_CR_LOOPBACK) { + phy_reg &= ~MII_CR_LOOPBACK; +- +- ret_val = iegbe_oem_write_phy_reg_ex(&adapter->hw, PHY_CTRL, ++ ++ ret_val = iegbe_oem_write_phy_reg_ex(&adapter->hw, PHY_CTRL, + phy_reg); + if(ret_val) { + DEBUGOUT("Unable to write to register PHY_CTRL\n"); + return; + } +- ++ + iegbe_phy_reset(&adapter->hw); + } + } +- ++ + #endif /* ifdef EXTERNAL_MDIO */ + return; + +@@ -1336,7 +1223,7 @@ iegbe_oem_loopback_cleanup(struct iegbe_ + * Called by iegbe_check_downshift(), checks the PHY to see if it running + * at as speed slower than its maximum. + **/ +-uint32_t ++uint32_t + iegbe_oem_phy_speed_downgraded(struct iegbe_hw *hw, uint16_t *isDowngraded) + { + #ifdef EXTERNAL_MDIO +@@ -1356,24 +1243,19 @@ iegbe_oem_phy_speed_downgraded(struct ie + */ + + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- case BCM5481_PHY_ID: +- *isDowngraded = 0; +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, + &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read register M88E1000_PHY_SPEC_STATUS\n"); + return ret_val; + } +- +- *isDowngraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) ++ ++ *isDowngraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) + >> M88E1000_PSSR_DOWNSHIFT_SHIFT; +- +- break; ++ ++ break; + default: + DEBUGOUT("Invalid PHY ID\n"); + return 1; +@@ -1388,7 +1270,7 @@ iegbe_oem_phy_speed_downgraded(struct ie + } + + *isDowngraded = 0; +- return 0; ++ return 0; + + #endif /* ifdef EXTERNAL_MDIO */ + } +@@ -1403,7 +1285,7 @@ iegbe_oem_phy_speed_downgraded(struct ie + * Called by iegbe_check_downshift(), checks the PHY to see if it running + * at as speed slower than its maximum. + **/ +-int32_t ++int32_t + iegbe_oem_check_polarity(struct iegbe_hw *hw, uint16_t *polarity) + { + #ifdef EXTERNAL_MDIO +@@ -1417,33 +1299,27 @@ iegbe_oem_check_polarity(struct iegbe_hw + return -1; + } + +- /* ++ /* + * borrow liberally from iegbe_check_polarity. + * Make note that the M88 phy is what'll be used on Truxton + */ + + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- case BCM5481_PHY_ID: +- *polarity = 0; +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + /* return the Polarity bit in the Status register. */ +- ret_val = iegbe_oem_read_phy_reg_ex(hw, +- M88E1000_PHY_SPEC_STATUS, ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, ++ M88E1000_PHY_SPEC_STATUS, + &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read register M88E1000_PHY_SPEC_STATUS\n"); + return ret_val; + } + +- *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) ++ *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) + >> M88E1000_PSSR_REV_POLARITY_SHIFT; +- +- break; +- ++ ++ break; + default: + DEBUGOUT("Invalid PHY ID\n"); + return -E1000_ERR_PHY_TYPE; +@@ -1472,7 +1348,7 @@ iegbe_oem_check_polarity(struct iegbe_hw + * the MAC with the PHY. It turns out on ICP_XXXX, this is not + * done automagically. + **/ +-int32_t ++int32_t + iegbe_oem_phy_is_full_duplex(struct iegbe_hw *hw, int *isFD) + { + #ifdef EXTERNAL_MDIO +@@ -1485,40 +1361,22 @@ iegbe_oem_phy_is_full_duplex(struct iegb + if(!hw || !isFD) { + return -1; + } +- /* ++ /* + * Make note that the M88 phy is what'll be used on Truxton + * see iegbe_config_mac_to_phy + */ +- ++ + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- /* Always full duplex */ +- *isFD = 1; +- break; +- +- case BCM5481_PHY_ID: +- ret_val = iegbe_read_phy_reg(hw, BCM5481_ASTAT, &phy_data); +- if(ret_val) return ret_val; +- +- switch (BCM5481_ASTAT_HCD(phy_data)) { +- case BCM5481_ASTAT_1KBTFD: +- case BCM5481_ASTAT_100BTXFD: +- *isFD = 1; +- break; +- default: +- *isFD = 0; +- } +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); +- if(ret_val) { +- DEBUGOUT("Unable to read register M88E1000_PHY_SPEC_STATUS\n"); +- return ret_val; +- } ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, ++ &phy_data); ++ if(ret_val) { ++ DEBUGOUT("Unable to read register M88E1000_PHY_SPEC_STATUS\n"); ++ return ret_val; ++ } + *isFD = (phy_data & M88E1000_PSSR_DPLX) != 0; +- ++ + break; + default: + DEBUGOUT("Invalid PHY ID\n"); +@@ -1546,7 +1404,7 @@ iegbe_oem_phy_is_full_duplex(struct iegb + * the MAC with the PHY. It turns out on ICP_XXXX, this is not + * done automagically. + **/ +-int32_t ++int32_t + iegbe_oem_phy_is_speed_1000(struct iegbe_hw *hw, int *is1000) + { + #ifdef EXTERNAL_MDIO +@@ -1565,28 +1423,10 @@ iegbe_oem_phy_is_speed_1000(struct iegbe + */ + + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- /* Always 1000mb */ +- *is1000 = 1; +- break; +- +- case BCM5481_PHY_ID: +- ret_val = iegbe_read_phy_reg(hw, BCM5481_ASTAT, &phy_data); +- if(ret_val) return ret_val; +- +- switch (BCM5481_ASTAT_HCD(phy_data)) { +- case BCM5481_ASTAT_1KBTFD: +- case BCM5481_ASTAT_1KBTHD: +- *is1000 = 1; +- break; +- default: +- *is1000 = 0; +- } +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, ++ &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read register M88E1000_PHY_SPEC_STATUS\n"); + return ret_val; +@@ -1638,28 +1478,9 @@ iegbe_oem_phy_is_speed_100(struct iegbe_ + * see iegbe_config_mac_to_phy + */ + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- /* Always 1000Mb, never 100mb */ +- *is100 = 0; +- break; +- +- case BCM5481_PHY_ID: +- ret_val = iegbe_read_phy_reg(hw, BCM5481_ASTAT, &phy_data); +- if(ret_val) return ret_val; +- +- switch (BCM5481_ASTAT_HCD(phy_data)) { +- case BCM5481_ASTAT_100BTXFD: +- case BCM5481_ASTAT_100BTXHD: +- *is100 = 1; +- break; +- default: +- *is100 = 0; +- } +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- ret_val = iegbe_oem_read_phy_reg_ex(hw, ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, + M88E1000_PHY_SPEC_STATUS, + &phy_data); + if(ret_val) { +@@ -1714,29 +1535,24 @@ iegbe_oem_phy_get_info(struct iegbe_hw * + * see iegbe_phy_m88_get_info + */ + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- case BCM5481_PHY_ID: +- DEBUGOUT("WARNING: An empty iegbe_oem_phy_get_info() has been called!\n"); +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- /* The downshift status is checked only once, after link is +- * established and it stored in the hw->speed_downgraded parameter.*/ ++ /* The downshift status is checked only once, after link is ++ * established and it stored in the hw->speed_downgraded parameter.*/ + phy_info->downshift = (iegbe_downshift)hw->speed_downgraded; +- +- ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, ++ ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, + &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read register M88E1000_PHY_SPEC_CTRL\n"); + return ret_val; + } + +- phy_info->extended_10bt_distance = +- (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) ++ phy_info->extended_10bt_distance = ++ (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) + >> M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; + phy_info->polarity_correction = +- (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) ++ (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) + >> M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; + + /* Check polarity status */ +@@ -1747,11 +1563,11 @@ iegbe_oem_phy_get_info(struct iegbe_hw * + + phy_info->cable_polarity = polarity; + +- ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, + &phy_data); + if(ret_val) { +- DEBUGOUT("Unable to read register M88E1000_PHY_SPEC_STATUS\n"); +- return ret_val; ++ DEBUGOUT("Unable to read register M88E1000_PHY_SPEC_STATUS\n"); ++ return ret_val; + } + + phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) +@@ -1761,24 +1577,24 @@ iegbe_oem_phy_get_info(struct iegbe_hw * + /* Cable Length Estimation and Local/Remote Receiver Information + * are only valid at 1000 Mbps. + */ +- phy_info->cable_length = ++ phy_info->cable_length = + (phy_data & M88E1000_PSSR_CABLE_LENGTH) + >> M88E1000_PSSR_CABLE_LENGTH_SHIFT; + +- ret_val = iegbe_oem_read_phy_reg_ex(hw, PHY_1000T_STATUS, ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, PHY_1000T_STATUS, + &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read register PHY_1000T_STATUS\n"); + return ret_val; + } + +- phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) ++ phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) + >> SR_1000T_LOCAL_RX_STATUS_SHIFT; +- +- phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) ++ ++ phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) + >> SR_1000T_REMOTE_RX_STATUS_SHIFT; + } +- ++ + break; + default: + DEBUGOUT("Invalid PHY ID\n"); +@@ -1801,7 +1617,7 @@ iegbe_oem_phy_get_info(struct iegbe_hw * + * This function will perform a software initiated reset of + * the PHY + **/ +-int32_t ++int32_t + iegbe_oem_phy_hw_reset(struct iegbe_hw *hw) + { + #ifdef EXTERNAL_MDIO +@@ -1815,18 +1631,13 @@ iegbe_oem_phy_hw_reset(struct iegbe_hw * + return -1; + } + /* +- * This code pretty much copies the default case from ++ * This code pretty much copies the default case from + * iegbe_phy_reset() as that is what is appropriate for +- * the M88 used in truxton. ++ * the M88 used in truxton. + */ + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- DEBUGOUT("WARNING: An empty iegbe_oem_phy_hw_reset() has been called!\n"); +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- case BCM5481_PHY_ID: + ret_val = iegbe_oem_read_phy_reg_ex(hw, PHY_CTRL, &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read register PHY_CTRL\n"); +@@ -1864,7 +1675,7 @@ iegbe_oem_phy_hw_reset(struct iegbe_hw * + * to perform and post reset initialiation. Not all PHYs require + * this, which is why it was split off as a seperate function. + **/ +-void ++void + iegbe_oem_phy_init_script(struct iegbe_hw *hw) + { + #ifdef EXTERNAL_MDIO +@@ -1877,19 +1688,17 @@ iegbe_oem_phy_init_script(struct iegbe_h + + /* call the GCU func that can do any phy specific init + * functions after a reset +- * ++ * + * Make note that the M88 phy is what'll be used on Truxton + * +- * The closest thing is in iegbe_phy_init_script, however this is ++ * The closest thing is in iegbe_phy_init_script, however this is + * for the IGP style of phy. This is probably a no-op for truxton + * but may be needed by OEM's later on +- * ++ * + */ + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- case BCM5481_PHY_ID: +- case BCM5395S_PHY_ID: + DEBUGOUT("Nothing to do for OEM PHY Init"); + break; + default: +@@ -1926,13 +1735,8 @@ iegbe_oem_read_phy_reg_ex(struct iegbe_h + return -1; + } + +- if (hw->phy_id == BCM5395S_PHY_ID) { +- DEBUGOUT("WARNING: iegbe_oem_read_phy_reg_ex() has been unexpectedly called!\n"); +- return -1; +- } +- + /* call the GCU func that will read the phy +- * ++ * + * Make note that the M88 phy is what'll be used on Truxton. + * + * The closest thing is in iegbe_read_phy_reg_ex. +@@ -1940,7 +1744,7 @@ iegbe_oem_read_phy_reg_ex(struct iegbe_h + * NOTE: this is 1 (of 2) functions that is truly dependant on the + * gcu module + */ +- ++ + ret_val = gcu_read_eth_phy(iegbe_oem_get_phy_dev_number(hw), + reg_addr, phy_data); + if(ret_val) { +@@ -1962,10 +1766,10 @@ iegbe_oem_read_phy_reg_ex(struct iegbe_h + * + * Returns E1000_SUCCESS, negative E1000 error code on failure + * +- * This is called from iegbe_config_mac_to_phy. Various supported ++ * This is called from iegbe_config_mac_to_phy. Various supported + * Phys may require the RGMII/RMII Translation gasket be set to RMII. + **/ +-int32_t ++int32_t + iegbe_oem_set_trans_gasket(struct iegbe_hw *hw) + { + #ifdef EXTERNAL_MDIO +@@ -1978,17 +1782,12 @@ iegbe_oem_set_trans_gasket(struct iegbe_ + } + + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- case BCM5481_PHY_ID: +- DEBUGOUT("WARNING: An empty iegbe_oem_set_trans_gasket() has been called!\n"); +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + /* Gasket set correctly for Marvell Phys, so nothing to do */ + break; + /* Add your PHY_ID here if your device requires an RMII interface +- case YOUR_PHY_ID: ++ case YOUR_PHY_ID: + ctrl_aux_reg = E1000_READ_REG(hw, CTRL_AUX); + ctrl_aux_reg |= E1000_CTRL_AUX_ICP_xxxx_MII_TGS; // Set the RGMII_RMII bit + */ +@@ -2032,7 +1831,7 @@ iegbe_oem_write_phy_reg_ex(struct iegbe_ + return -1; + } + /* call the GCU func that will write to the phy +- * ++ * + * Make note that the M88 phy is what'll be used on Truxton. + * + * The closest thing is in iegbe_write_phy_reg_ex +@@ -2062,11 +1861,11 @@ iegbe_oem_write_phy_reg_ex(struct iegbe_ + * @hw struct iegbe_hw hardware specific data + * + * iegbe_reset_hw is called to reset the MAC. If, for +- * some reason the PHY needs to be reset as well, this ++ * some reason the PHY needs to be reset as well, this + * should return TRUE and then iegbe_oem_phy_hw_reset() + * will be called. + **/ +-int ++int + iegbe_oem_phy_needs_reset_with_mac(struct iegbe_hw *hw) + { + #ifdef EXTERNAL_MDIO +@@ -2079,16 +1878,14 @@ iegbe_oem_phy_needs_reset_with_mac(struc + return FALSE; + } + +- /* ++ /* + * From the original iegbe driver, the M88 +- * PHYs did not seem to need this reset, ++ * PHYs did not seem to need this reset, + * so returning FALSE. + */ + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- case BCM5481_PHY_ID: +- case BCM5395S_PHY_ID: + ret_val = FALSE; + break; + default: +@@ -2116,7 +1913,7 @@ iegbe_oem_phy_needs_reset_with_mac(struc + * tweaking of the PHY, for PHYs that support a DSP. + * + **/ +-int32_t ++int32_t + iegbe_oem_config_dsp_after_link_change(struct iegbe_hw *hw, + int link_up) + { +@@ -2138,8 +1935,6 @@ iegbe_oem_config_dsp_after_link_change(s + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- case BCM5481_PHY_ID: +- case BCM5395S_PHY_ID: + DEBUGOUT("No DSP to configure on OEM PHY"); + break; + default: +@@ -2165,7 +1960,7 @@ iegbe_oem_config_dsp_after_link_change(s + * + * + **/ +-int32_t ++int32_t + iegbe_oem_get_cable_length(struct iegbe_hw *hw, + uint16_t *min_length, + uint16_t *max_length) +@@ -2177,21 +1972,15 @@ iegbe_oem_get_cable_length(struct iegbe_ + uint16_t phy_data; + + DEBUGFUNC1("%s",__func__); +- ++ + if(!hw || !min_length || !max_length) { + return -1; + } + + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- case BCM5481_PHY_ID: +- *min_length = 0; +- *max_length = iegbe_igp_cable_length_150; +- break; +- + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- ret_val = iegbe_oem_read_phy_reg_ex(hw, ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, + M88E1000_PHY_SPEC_STATUS, + &phy_data); + if(ret_val) { +@@ -2246,13 +2035,13 @@ iegbe_oem_get_cable_length(struct iegbe_ + /** + * iegbe_oem_phy_is_link_up + * @hw iegbe_hw struct containing device specific information +- * @isUp a boolean returning true if link is up ++ * @isUp a boolean returning true if link is up + * + * This is called as part of iegbe_config_mac_to_phy() to align + * the MAC with the PHY. It turns out on ICP_XXXX, this is not + * done automagically. + **/ +-int32_t ++int32_t + iegbe_oem_phy_is_link_up(struct iegbe_hw *hw, int *isUp) + { + #ifdef EXTERNAL_MDIO +@@ -2266,35 +2055,19 @@ iegbe_oem_phy_is_link_up(struct iegbe_hw + if(!hw || !isUp) { + return -1; + } +- /* ++ /* + * Make note that the M88 phy is what'll be used on Truxton + * see iegbe_config_mac_to_phy + */ + + switch (hw->phy_id) { +- case BCM5395S_PHY_ID: +- /* Link always up */ +- *isUp = TRUE; +- return E1000_SUCCESS; +- break; +- +- case BCM5481_PHY_ID: +- iegbe_oem_read_phy_reg_ex(hw, BCM5481_ESTAT, &phy_data); +- ret_val = iegbe_oem_read_phy_reg_ex(hw, BCM5481_ESTAT, &phy_data); +- if(ret_val) +- { +- DEBUGOUT("Unable to read PHY register BCM5481_ESTAT\n"); +- return ret_val; +- } +- statusMask = BCM5481_ESTAT_LINK; +- break; +- +- case M88E1000_I_PHY_ID: ++ case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: +- iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); +- ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); ++ iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, ++ &phy_data); + statusMask = M88E1000_PSSR_LINK; +- break; ++ break; + default: + DEBUGOUT("Invalid PHY ID\n"); + return -E1000_ERR_PHY_TYPE; +@@ -2319,213 +2092,3 @@ iegbe_oem_phy_is_link_up(struct iegbe_hw + #endif /* ifdef EXTERNAL_MDIO */ + } + +- +- +-//----- +-// Read BCM5481 expansion register +-// +-int32_t +-bcm5481_read_ex (struct iegbe_hw *hw, uint16_t reg, uint16_t *data) +-{ +- int ret; +- uint16_t selector; +- uint16_t reg_data; +- +- // Get the current value of bits 15:12 +- ret = iegbe_oem_read_phy_reg_ex (hw, 0x15, &selector); +- if (ret) +- return ret; +- +- // Select the expansion register +- selector &= 0xf000; +- selector |= (0xf << 8) | (reg); +- iegbe_oem_write_phy_reg_ex (hw, 0x17, selector); +- +- // Read the expansion register +- ret = iegbe_oem_read_phy_reg_ex (hw, 0x15, ®_data); +- +- // De-select the expansion registers. +- selector &= 0xf000; +- iegbe_oem_write_phy_reg_ex (hw, 0x17, selector); +- +- if (ret) +- return ret; +- +- *data = reg_data; +- return ret; +-} +- +-//----- +-// Read reg 0x18 sub-register +-// +-static int32_t +-bcm5481_read_18sv (struct iegbe_hw *hw, int sv, uint16_t *data) +-{ +- int ret; +- uint16_t tmp_data; +- +- // Select reg 0x18, sv +- tmp_data = ((sv & BCM5481_R18H_SV_MASK) << 12) | BCM5481_R18H_SV_MCTRL; +- ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R18H, tmp_data); +- if(ret) +- return ret; +- +- // Read reg 0x18, sv +- ret = iegbe_oem_read_phy_reg_ex (hw, BCM5481_R18H, &tmp_data); +- if(ret) +- return ret; +- +- *data = tmp_data; +- return ret; +-} +- +-//----- +-// Read reg 0x1C sub-register +-// +-int32_t +-bcm5481_read_1csv (struct iegbe_hw *hw, int sv, uint16_t *data) +-{ +- int ret; +- uint16_t tmp_data; +- +- // Select reg 0x1c, sv +- tmp_data = ((sv & BCM5481_R1CH_SV_MASK) << BCM5481_R1CH_SV_SHIFT); +- +- ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R1CH, tmp_data); +- if(ret) +- return ret; +- +- // Read reg 0x1c, sv +- ret = iegbe_oem_read_phy_reg_ex (hw, BCM5481_R1CH, &tmp_data); +- if(ret) +- return ret; +- +- *data = tmp_data; +- return ret; +-} +- +-//----- +-// Read-modify-write a 0x1C register. +-// +-// hw - hardware access info. +-// reg - 0x1C register to modify. +-// data - bits which should be set. +-// mask - the '1' bits in this argument will be cleared in the data +-// read from 'reg' then 'data' will be or'd in and the result +-// will be written to 'reg'. +- +-int32_t +-bcm5481_rmw_1csv (struct iegbe_hw *hw, uint16_t reg, uint16_t data, uint16_t mask) +-{ +- int32_t ret; +- uint16_t reg_data; +- +- ret = 0; +- +- ret = bcm5481_read_1csv (hw, reg, ®_data); +- if (ret) +- { +- DEBUGOUT("Unable to read BCM5481 1CH register\n"); +- printk (KERN_ERR "Unable to read BCM5481 1CH register [0x%x]\n", reg); +- return ret; +- } +- +- reg_data &= ~mask; +- reg_data |= (BCM5481_R1CH_WE | data); +- +- ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R1CH, reg_data); +- if(ret) +- { +- DEBUGOUT("Unable to write BCM5481 1CH register\n"); +- printk (KERN_ERR "Unable to write BCM5481 1CH register\n"); +- return ret; +- } +- +- return ret; +-} +- +-int32_t +-oi_phy_setup (struct iegbe_hw *hw) +-{ +- int ret; +- uint16_t pmii_data; +- uint16_t mctrl_data; +- uint16_t cacr_data; +- uint16_t sc1_data; +- uint16_t lctl_data; +- +- ret = 0; +- +- // Set low power mode via reg 0x18, sv010, bit 6 +- // Do a read-modify-write on reg 0x18, sv010 register to preserve existing bits. +- ret = bcm5481_read_18sv (hw, BCM5481_R18H_SV_PMII, &pmii_data); +- if (ret) +- { +- DEBUGOUT("Unable to read BCM5481_R18H_SV_PMII register\n"); +- printk (KERN_ERR "Unable to read BCM5481_R18H_SV_PMII register\n"); +- return ret; +- } +- +- // Set the LPM bit in the data just read and write back to sv010 +- // The shadow register select bits [2:0] are set by reading the sv010 +- // register. +- pmii_data |= BCM5481_R18H_SV010_LPM; +- ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R18H, pmii_data); +- if(ret) +- { +- DEBUGOUT("Unable to write BCM5481_R18H register\n"); +- printk (KERN_ERR "Unable to write BCM5481_R18H register\n"); +- return ret; +- } +- +- +- // Set the RGMII RXD to RXC skew bit in reg 0x18, sv111 +- +- if (bcm5481_read_18sv (hw, BCM5481_R18H_SV_MCTRL, &mctrl_data)) +- { +- DEBUGOUT("Unable to read BCM5481_R18H_SV_MCTRL register\n"); +- printk (KERN_ERR "Unable to read BCM5481_R18H_SV_MCTRL register\n"); +- return ret; +- } +- mctrl_data |= (BCM5481_R18H_WE | BCM5481_R18H_SV111_SKEW); +- +- ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R18H, mctrl_data); +- if(ret) +- { +- DEBUGOUT("Unable to write BCM5481_R18H register\n"); +- printk (KERN_ERR "Unable to write BCM5481_R18H register\n"); +- return ret; +- } +- +- +- // Enable RGMII transmit clock delay in reg 0x1c, sv00011 +- ret = bcm5481_read_1csv (hw, BCM5481_R1CH_CACR, &cacr_data); +- if (ret) +- { +- DEBUGOUT("Unable to read BCM5481_R1CH_CACR register\n"); +- printk (KERN_ERR "Unable to read BCM5481_R1CH_CACR register\n"); +- return ret; +- } +- +- cacr_data |= (BCM5481_R1CH_WE | BCM5481_R1CH_CACR_TCD); +- +- ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R1CH, cacr_data); +- if(ret) +- { +- DEBUGOUT("Unable to write BCM5481_R1CH register\n"); +- printk (KERN_ERR "Unable to write BCM5481_R1CH register\n"); +- return ret; +- } +- +- // Enable dual link speed indication (0x1c, sv 00010, bit 2) +- ret = bcm5481_rmw_1csv (hw, BCM5481_R1CH_SC1, BCM5481_R1CH_SC1_LINK, BCM5481_R1CH_SC1_LINK); +- if (ret) +- return ret; +- +- // Enable link and activity on ACTIVITY LED (0x1c, sv 01001, bit 4=1, bit 3=0) +- ret = bcm5481_rmw_1csv (hw, BCM5481_R1CH_LCTRL, BCM5481_R1CH_LCTRL_ALEN, BCM5481_R1CH_LCTRL_ALEN | BCM5481_R1CH_LCTRL_AEN); +- if (ret) +- return ret; +- +- return ret; +-} +--- a/Embedded/src/GbE/iegbe_oem_phy.h ++++ b/Embedded/src/GbE/iegbe_oem_phy.h +@@ -2,31 +2,31 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + +- This program is free software; you can redistribute it and/or modify ++ This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + +- You should have received a copy of the GNU General Public License +- along with this program; if not, write to the Free Software ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- The full GNU General Public License is included in this distribution ++ The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: +- +- Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226 ++ ++ Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226 + + *******************************************************************************/ + #ifndef _IEGBE_OEM_PHY_H_ +@@ -45,10 +45,10 @@ int32_t iegbe_oem_set_trans_gasket(struc + uint32_t iegbe_oem_get_tipg(struct iegbe_hw *hw); + int iegbe_oem_phy_is_copper(struct iegbe_hw *hw); + uint32_t iegbe_oem_get_phy_dev_number(struct iegbe_hw *hw); +-int iegbe_oem_mii_ioctl(struct iegbe_adapter *adapter, unsigned long flags, ++int iegbe_oem_mii_ioctl(struct iegbe_adapter *adapter, unsigned long flags, + struct ifreq *ifr, int cmd); + void iegbe_oem_fiber_live_in_suspend(struct iegbe_hw *hw); +-void iegbe_oem_get_phy_regs(struct iegbe_adapter *adapter, uint32_t *data, ++void iegbe_oem_get_phy_regs(struct iegbe_adapter *adapter, uint32_t *data, + uint32_t data_length); + int iegbe_oem_phy_loopback(struct iegbe_adapter *adapter); + void iegbe_oem_loopback_cleanup(struct iegbe_adapter *adapter); +@@ -94,81 +94,14 @@ int32_t iegbe_oem_phy_is_link_up(struct + #define ICP_XXXX_MAC_2 2 + + #define DEFAULT_ICP_XXXX_TIPG_IPGT 8 /* Inter Packet Gap Transmit Time */ +-#define ICP_XXXX_TIPG_IPGT_MASK 0x000003FFUL +-#define BCM5481_PHY_ID 0x0143BCA2 +-#define BCM5395S_PHY_ID 0x0143BCF0 ++#define ICP_XXXX_TIPG_IPGT_MASK 0x000003FFUL + + /* Miscellaneous defines */ + #ifdef IEGBE_10_100_ONLY +- #define ICP_XXXX_AUTONEG_ADV_DEFAULT 0x0F ++ #define ICP_XXXX_AUTONEG_ADV_DEFAULT 0x0F + #else + #define ICP_XXXX_AUTONEG_ADV_DEFAULT 0x2F + #endif + +-//----- +-// BCM5481 specifics +- +-#define BCM5481_ECTRL (0x10) +-#define BCM5481_ESTAT (0x11) +-#define BCM5481_RXERR (0x12) +-#define BCM5481_EXPRW (0x15) +-#define BCM5481_EXPACC (0x17) +-#define BCM5481_ASTAT (0x19) +-#define BCM5481_R18H (0x18) +-#define BCM5481_R1CH (0x1c) +- +-//----- +-// indirect register access via register 18h +- +-#define BCM5481_R18H_SV_MASK (7) // Mask for SV bits. +-#define BCM5481_R18H_SV_ACTRL (0) // SV000 Aux. control +-#define BCM5481_R18H_SV_10BT (1) // SV001 10Base-T +-#define BCM5481_R18H_SV_PMII (2) // SV010 Power/MII control +-#define BCM5481_R18H_SV_MTEST (4) // SV100 Misc. test +-#define BCM5481_R18H_SV_MCTRL (7) // SV111 Misc. control +- +-#define BCM5481_R18H_SV001_POL (1 << 13) // Polarity +-#define BCM5481_R18H_SV010_LPM (1 << 6) +-#define BCM5481_R18H_SV111_SKEW (1 << 8) +-#define BCM5481_R18H_WE (1 << 15) // Write enable +- +-// 0x1c registers +-#define BCM5481_R1CH_SV_SHIFT (10) +-#define BCM5481_R1CH_SV_MASK (0x1f) +-#define BCM5481_R1CH_SC1 (0x02) // sv00010 Spare control 1 +-#define BCM5481_R1CH_CACR (0x03) // sv00011 Clock alignment control +-#define BCM5481_R1CH_LCTRL (0x09) // sv01001 LED control +-#define BCM5481_R1CH_LEDS1 (0x0d) // sv01101 LED selector 1 +- +-// 0x1c common +-#define BCM5481_R1CH_WE (1 << 15) // Write enable +- +-// 0x1c, sv 00010 +-#define BCM5481_R1CH_SC1_LINK (1 << 2) // sv00010 Linkspeed +- +-// 0x1c, sv 00011 +-#define BCM5481_R1CH_CACR_TCD (1 << 9) // sv00011 RGMII tx clock delay +- +-// 0x1c, sv 01001 +-#define BCM5481_R1CH_LCTRL_ALEN (1 << 4) // Activity/Link enable on ACTIVITY LED +-#define BCM5481_R1CH_LCTRL_AEN (1 << 3) // Activity enable on ACTIVITY LED +- +- +-#define BCM5481_ECTRL_DISMDIX (1 <<14) +- +-#define BCM5481_MCTRL_AUTOMDIX (1 <<9) +- +-#define BCM5481_ESTAT_LINK (1 << 8) +- +-#define BCM5481_ASTAT_ANC (1 << 15) +-#define BCM5481_ASTAT_ANHCD (7 << 8) +-#define BCM5481_ASTAT_HCD(x) ((x >> 8) & 7) +-#define BCM5481_ASTAT_1KBTFD (0x7) +-#define BCM5481_ASTAT_1KBTHD (0x6) +-#define BCM5481_ASTAT_100BTXFD (0x5) +-#define BCM5481_ASTAT_100BTXHD (0x3) +- +-// end BCM5481 specifics +- + #endif /* ifndef _IEGBE_OEM_PHY_H_ */ +- ++ +--- a/Embedded/src/GbE/iegbe_osdep.h ++++ b/Embedded/src/GbE/iegbe_osdep.h +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +--- a/Embedded/src/GbE/iegbe_param.c ++++ b/Embedded/src/GbE/iegbe_param.c +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +@@ -239,11 +239,7 @@ E1000_PARAM(InterruptThrottleRate, "Inte + #define MAX_TXABSDELAY 0xFFFF + #define MIN_TXABSDELAY 0 + +-#ifdef IEGBE_GBE_WORKAROUND +-#define DEFAULT_ITR 0 +-#else + #define DEFAULT_ITR 8000 +-#endif + + + #define MAX_ITR 100000 +@@ -373,7 +369,7 @@ iegbe_check_options(struct iegbe_adapter + tx_ring->count = opt.def; + } + #endif +- for (i = 0; i < adapter->num_queues; i++) ++ for (i = 0; i < adapter->num_tx_queues; i++) + tx_ring[i].count = tx_ring->count; + } + { /* Receive Descriptor Count */ +@@ -403,7 +399,7 @@ iegbe_check_options(struct iegbe_adapter + rx_ring->count = opt.def; + } + #endif +- for (i = 0; i < adapter->num_queues; i++) ++ for (i = 0; i < adapter->num_rx_queues; i++) + rx_ring[i].count = rx_ring->count; + } + { /* Checksum Offload Enable/Disable */ +--- a/Embedded/src/GbE/kcompat.c ++++ b/Embedded/src/GbE/kcompat.c +@@ -1,8 +1,8 @@ +-/************************************************************
+-
++/************************************************************ ++ + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,183 +22,192 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 +-
+- Contact Information:
+-
+- Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226
+-
+-**************************************************************/
+-/**************************************************************************
+- * @ingroup KCOMPAT_GENERAL
+- *
+- * @file kcompat.c
+- *
+- * @description
+- *
+- *
+- **************************************************************************/
+-#include "kcompat.h"
+-
+-/*************************************************************/
+-/* 2.4.13 => 2.4.3 */
+-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(0x2,0x4,0xd) )
+-
+-/**************************************/
+-/* PCI DMA MAPPING */
+-
+-#if defined(CONFIG_HIGHMEM)
+-
+-#ifndef PCI_DRAM_OFFSET
+-#define PCI_DRAM_OFFSET 0
+-#endif
+-
+-u64 _kc_pci_map_page(struct pci_dev *dev,
+- struct page *page,
+- unsigned long offset,
+- size_t size,
+- int direction)
+-{
+- u64 ret_val;
+- ret_val = (((u64)(page - mem_map) << PAGE_SHIFT) + offset +
+- PCI_DRAM_OFFSET);
+- return ret_val;
+-}
+-
+-#else /* CONFIG_HIGHMEM */
+-
+-u64 _kc_pci_map_page(struct pci_dev *dev,
+- struct page *page,
+- unsigned long offset,
+- size_t size,
+- int direction)
+-{
+- return pci_map_single(dev, (void *)page_address(page) + offset,
+- size, direction);
+-}
+-
+-#endif /* CONFIG_HIGHMEM */
+-
+-void _kc_pci_unmap_page(struct pci_dev *dev,
+- u64 dma_addr,
+- size_t size,
+- int direction)
+-{
+- return pci_unmap_single(dev, dma_addr, size, direction);
+-}
+-
+-#endif /* 2.4.13 => 2.4.3 */
+-
+-
+-/*****************************************************************************/
+-/* 2.4.3 => 2.4.0 */
+-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(0x2,0x4,0x3) )
+-
+-/**************************************/
+-/* PCI DRIVER API */
+-
+-int _kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask)
+-{
+- if(!pci_dma_supported(dev, mask)) {
+- return -EIO;
+- }
+- dev->dma_mask = mask;
+- return 0;
+-}
+-
+-int _kc_pci_request_regions(struct pci_dev *dev, char *res_name)
+-{
+- int i;
+-
+- for (i = 0; i < 0x6; i++) {
+- if (pci_resource_len(dev, i) == 0) {
+- continue;
+- }
+- if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
+- if (!request_region(pci_resource_start(dev, i),
+- pci_resource_len(dev, i), res_name)) {
+- pci_release_regions(dev);
+- return -EBUSY;
+- }
+- } else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) {
+- if (!request_mem_region(pci_resource_start(dev, i),
+- pci_resource_len(dev, i),
+- res_name)) {
+- pci_release_regions(dev);
+- return -EBUSY;
+- }
+- }
+- }
+- return 0;
+-}
+-
+-void _kc_pci_release_regions(struct pci_dev *dev)
+-{
+- int i;
+-
+- for (i = 0; i < 0x6; i++) {
+- if (pci_resource_len(dev, i) == 0) {
+- continue;
+- }
+- if (pci_resource_flags(dev, i) & IORESOURCE_IO){
+- release_region(pci_resource_start(dev, i),
+- pci_resource_len(dev, i));
+- } else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) {
+- release_mem_region(pci_resource_start(dev, i),
+- pci_resource_len(dev, i));
+- }
+- }
+-}
+-
+-/**************************************/
+-/* NETWORK DRIVER API */
+-
+-struct net_device * _kc_alloc_etherdev(int sizeof_priv)
+-{
+- struct net_device *dev;
+- int alloc_size;
+-
+- alloc_size = sizeof(*dev) + sizeof_priv + IFNAMSIZ + 0x1f;
+-
+- dev = kmalloc(alloc_size, GFP_KERNEL);
+-
+- if (!dev) { return NULL; }
+-
+- memset(dev, 0, alloc_size);
+-
+- if (sizeof_priv) {
+- dev->priv = (void *) (((unsigned long)(dev + 1) + 0x1f) & ~0x1f);
+- }
+- dev->name[0] = '\0';
+-
+- ether_setup(dev);
+-
+- return dev;
+-}
+-
+-int _kc_is_valid_ether_addr(u8 *addr)
+-{
+- const char zaddr[0x6] = {0,};
+-
+- return !(addr[0]&1) && memcmp( addr, zaddr, 0x6);
+-}
+-
+-#endif /* 2.4.3 => 2.4.0 */
+-
+-
+-/*****************************************************************/
+-/* 2.4.6 => 2.4.3 */
+-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(0x2,0x4,0x6) )
+-
+-int _kc_pci_set_power_state(struct pci_dev *dev, int state)
+-{ return 0; }
+-int _kc_pci_save_state(struct pci_dev *dev, u32 *buffer)
+-{ return 0; }
+-int _kc_pci_restore_state(struct pci_dev *pdev, u32 *buffer)
+-{ return 0; }
+-int _kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable)
+-{ return 0; }
+-
+-#endif /* 2.4.6 => 2.4.3 */
+-
+-
++ version: Embedded.Release.Patch.L.1.0.7-5 ++ ++ Contact Information: ++ ++ Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226 ++ ++**************************************************************/ ++/************************************************************************** ++ * @ingroup KCOMPAT_GENERAL ++ * ++ * @file kcompat.c ++ * ++ * @description ++ * ++ * ++ **************************************************************************/ ++#include "kcompat.h" ++ ++/*************************************************************/ ++/* 2.4.13 => 2.4.3 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(0x2,0x4,0xd) ) ++ ++/**************************************/ ++/* PCI DMA MAPPING */ ++ ++#if defined(CONFIG_HIGHMEM) ++ ++#ifndef PCI_DRAM_OFFSET ++#define PCI_DRAM_OFFSET 0 ++#endif ++ ++u64 _kc_pci_map_page(struct pci_dev *dev, ++ struct page *page, ++ unsigned long offset, ++ size_t size, ++ int direction) ++{ ++ u64 ret_val; ++ ret_val = (((u64)(page - mem_map) << PAGE_SHIFT) + offset + ++ PCI_DRAM_OFFSET); ++ return ret_val; ++} ++ ++#else /* CONFIG_HIGHMEM */ ++ ++u64 _kc_pci_map_page(struct pci_dev *dev, ++ struct page *page, ++ unsigned long offset, ++ size_t size, ++ int direction) ++{ ++ return pci_map_single(dev, (void *)page_address(page) + offset, ++ size, direction); ++} ++ ++#endif /* CONFIG_HIGHMEM */ ++ ++void _kc_pci_unmap_page(struct pci_dev *dev, ++ u64 dma_addr, ++ size_t size, ++ int direction) ++{ ++ return pci_unmap_single(dev, dma_addr, size, direction); ++} ++ ++#endif /* 2.4.13 => 2.4.3 */ ++ ++ ++/*****************************************************************************/ ++/* 2.4.3 => 2.4.0 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(0x2,0x4,0x3) ) ++ ++/**************************************/ ++/* PCI DRIVER API */ ++ ++int _kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) ++{ ++ if(!pci_dma_supported(dev, mask)) { ++ return -EIO; ++ } ++ dev->dma_mask = mask; ++ return 0; ++} ++ ++int _kc_pci_request_regions(struct pci_dev *dev, char *res_name) ++{ ++ int i; ++ ++ for (i = 0; i < 0x6; i++) { ++ if (pci_resource_len(dev, i) == 0) { ++ continue; ++ } ++ if (pci_resource_flags(dev, i) & IORESOURCE_IO) { ++ if (!request_region(pci_resource_start(dev, i), ++ pci_resource_len(dev, i), res_name)) { ++ pci_release_regions(dev); ++ return -EBUSY; ++ } ++ } else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) { ++ if (!request_mem_region(pci_resource_start(dev, i), ++ pci_resource_len(dev, i), ++ res_name)) { ++ pci_release_regions(dev); ++ return -EBUSY; ++ } ++ } ++ } ++ return 0; ++} ++ ++void _kc_pci_release_regions(struct pci_dev *dev) ++{ ++ int i; ++ ++ for (i = 0; i < 0x6; i++) { ++ if (pci_resource_len(dev, i) == 0) { ++ continue; ++ } ++ if (pci_resource_flags(dev, i) & IORESOURCE_IO){ ++ release_region(pci_resource_start(dev, i), ++ pci_resource_len(dev, i)); ++ } else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) { ++ release_mem_region(pci_resource_start(dev, i), ++ pci_resource_len(dev, i)); ++ } ++ } ++} ++ ++/**************************************/ ++/* NETWORK DRIVER API */ ++ ++struct net_device * _kc_alloc_etherdev(int sizeof_priv) ++{ ++ struct net_device *dev; ++ int alloc_size; ++ ++ alloc_size = sizeof(*dev) + sizeof_priv + IFNAMSIZ + 0x1f; ++ ++ dev = kmalloc(alloc_size, GFP_KERNEL); ++ ++ if (!dev) { return NULL; } ++ ++ memset(dev, 0, alloc_size); ++ ++ if (sizeof_priv) { ++ dev->priv = (void *) (((unsigned long)(dev + 1) + 0x1f) & ~0x1f); ++ } ++ dev->name[0] = '\0'; ++ ++ ether_setup(dev); ++ ++ return dev; ++} ++ ++int _kc_is_valid_ether_addr(u8 *addr) ++{ ++ const char zaddr[0x6] = {0,}; ++ ++ return !(addr[0]&1) && memcmp( addr, zaddr, 0x6); ++} ++ ++#endif /* 2.4.3 => 2.4.0 */ ++ ++ ++/*****************************************************************/ ++/* 2.4.6 => 2.4.3 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(0x2,0x4,0x6) ) ++ ++int _kc_pci_set_power_state(struct pci_dev *dev, int state) ++{ return 0; } ++int _kc_pci_save_state(struct pci_dev *dev, u32 *buffer) ++{ return 0; } ++int _kc_pci_restore_state(struct pci_dev *pdev, u32 *buffer) ++{ return 0; } ++int _kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable) ++{ return 0; } ++ ++#endif /* 2.4.6 => 2.4.3 */ ++ ++ ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,24) ) ++ ++void dump_stack(void) ++{ ++} ++ ++#endif /* 2.4.24 */ ++ +--- a/Embedded/src/GbE/kcompat_ethtool.c ++++ b/Embedded/src/GbE/kcompat_ethtool.c +@@ -2,7 +2,7 @@ + /* + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ + * Contact Information: + * Intel Corporation + * +- * version: Embedded.L.1.0.34 ++ * version: Embedded.Release.Patch.L.1.0.7-5 + */ + + /************************************************************************** +@@ -779,6 +779,7 @@ static int ethtool_get_stats(struct net_ + } + + /* The main entry point in this file. Called from net/core/dev.c */ ++ + #define ETHTOOL_OPS_COMPAT + int ethtool_ioctl(struct ifreq *ifr) + { +--- a/Embedded/src/GbE/kcompat.h ++++ b/Embedded/src/GbE/kcompat.h +@@ -2,7 +2,7 @@ + + GPL LICENSE SUMMARY + +- Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as +@@ -22,7 +22,7 @@ GPL LICENSE SUMMARY + Contact Information: + Intel Corporation + +- version: Embedded.L.1.0.34 ++ version: Embedded.Release.Patch.L.1.0.7-5 + + Contact Information: + +@@ -69,15 +69,6 @@ GPL LICENSE SUMMARY + #define CONFIG_NET_POLL_CONTROLLER + #endif + +-#ifdef E1000_NAPI +-#undef CONFIG_E1000_NAPI +-#define CONFIG_E1000_NAPI +-#endif +- +-#ifdef E1000_NO_NAPI +-#undef CONFIG_E1000_NAPI +-#endif +- + #ifndef module_param + #define module_param(v,t,p) MODULE_PARM(v, "i"); + #endif +@@ -554,35 +545,14 @@ extern void _kc_pci_unmap_page(struct pc + #endif + + /*****************************************************************************/ +-/* 2.4.23 => 2.4.22 */ +-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) ) +-#ifdef CONFIG_E1000_NAPI +-#ifndef netif_poll_disable +-#define netif_poll_disable(x) _kc_netif_poll_disable(x) +-static inline void _kc_netif_poll_disable(struct net_device *netdev) +-{ +- while (test_and_set_bit(__LINK_STATE_RX_SCHED, &netdev->state)) { +- /* No hurry */ +- current->state = TASK_INTERRUPTIBLE; +- schedule_timeout(1); +- } +-} +-#endif +-#ifndef netif_poll_enable +-#define netif_poll_enable(x) _kc_netif_poll_enable(x) +-static inline void _kc_netif_poll_enable(struct net_device *netdev) +-{ +- clear_bit(__LINK_STATE_RX_SCHED, &netdev->state); +-} +-#endif +-#endif +-#endif +- +-/*****************************************************************************/ + /* 2.5.28 => 2.4.23 */ + #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28) ) + ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) ) ++static inline void _kc_synchronize_irq(void) { barrier(); } ++#else + static inline void _kc_synchronize_irq() { synchronize_irq(); } ++#endif /* 2.4.23 */ + #undef synchronize_irq + #define synchronize_irq(X) _kc_synchronize_irq() + +@@ -747,6 +717,37 @@ static inline struct mii_ioctl_data *_kc + #define skb_header_cloned(x) 0 + #endif /* SKB_DATAREF_SHIFT not defined */ + ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ) ++ ++#define ioread32(addr) readl(addr) ++#define iowrite32(val,addr) writel(val,addr) ++ ++#endif /* 2.6.10 */ ++ ++#ifndef DEFINE_SPINLOCK ++#define DEFINE_SPINLOCK(s) spinlock_t s = SPIN_LOCK_UNLOCKED ++#endif /* DEFINE_SPINLOCK */ ++ ++#ifndef PCI_COMMAND_INTX_DISABLE ++#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ ++#endif /* PCI_COMMAND_INTX_DISABLE */ ++ ++#ifndef ETH_GSTRING_LEN ++#define ETH_GSTRING_LEN 32 ++#endif /* ETH_GSTRING_LEN */ ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,24) ) ++ ++extern void dump_stack(void); ++ ++#undef register_reboot_notifier ++#define register_reboot_notifier(a) ++ ++#undef unregister_reboot_notifier ++#define unregister_reboot_notifier(a) ++ ++#endif /* 2.4.24 */ ++ + #endif /* _KCOMPAT_H_ */ + + +--- a/Embedded/src/GbE/Makefile ++++ b/Embedded/src/GbE/Makefile +@@ -1,6 +1,6 @@ + # GPL LICENSE SUMMARY + # +-# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++# Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + # + # This program is free software; you can redistribute it and/or modify + # it under the terms of version 2 of the GNU General Public License as +@@ -20,7 +20,7 @@ + # Contact Information: + # Intel Corporation + # +-# version: Embedded.L.1.0.34 ++# version: Embedded.Release.Patch.L.1.0.7-5 + + ########################################################################### + # Driver files +@@ -35,6 +35,8 @@ MDIO_PHONY_CFILES = gcu.c + MDIO_CFILES = gcu_main.c gcu_if.c + MDIO_HFILES = gcu.h gcu_if.h gcu_reg.h kcompat.h + ++KVER=$(shell uname -r) ++ + # + # Variables: + # KSRC (path to kernel source to build against) +@@ -50,45 +52,16 @@ MDIO_HFILES = gcu.h gcu_if.h gcu_reg.h k + + # set KSRC, KOBJ, and EXTERNAL_MDIO to default values of not already set + # +-KOBJ ?= /usr/src/kernels/linux +-KSRC ?= /usr/src/kernels/linux ++#KOBJ=/usr/src/kernels/linux ++#KSRC=/usr/src/kernels/linux ++#KSRC=$(KOBJ) + EXTERNAL_MDIO ?= 1 + GBE_NAME = iegbe + GCU_NAME = gcu + +-# By default the workaround for the IEGBE writeback issue is enabled +-# +-IEGBE_GBE_WORKAROUND ?= 0 +- +-# If the platform only supports 10/100 this variable needs to be set +-# so the default advertisement is set appropriately. +-# By default, this variable will be disabled. +-# +-IEGBE_10_100_ONLY ?= 0 +- +-# check for version.h and autoconf.h for running kernel in /boot (SUSE) +-ifneq (,$(wildcard /boot/vmlinuz.version.h)) +- VERSION_FILE := /boot/vmlinuz.version.h +- CONFIG_FILE := /boot/vmlinuz.autoconf.h +- KVER := $(shell $(CC) $(CFLAGS) -E -dM $(VERSION_FILE) | \ +- grep UTS_RELEASE | awk '{ print $$3 }' | sed 's/\"//g') +- ifeq ($(KVER),$(shell uname -r)) +- # set up include path to override headers from kernel source +- x:=$(shell rm -rf include) +- x:=$(shell mkdir -p include/linux) +- x:=$(shell cp /boot/vmlinuz.version.h include/linux/version.h) +- x:=$(shell cp /boot/vmlinuz.autoconf.h include/linux/autoconf.h) +- CFLAGS += -I./include +- else +- VERSION_FILE := $(KOBJ)/include/linux/version.h +- UTS_REL_FILE := $(KSRC)/include/linux/utsrelease.h +- CONFIG_FILE := $(KOBJ)/include/linux/autoconf.h +- endif +-else +- VERSION_FILE := $(KOBJ)/include/linux/version.h +- UTS_REL_FILE := $(KSRC)/include/linux/utsrelease.h +- CONFIG_FILE := $(KOBJ)/include/linux/autoconf.h +-endif ++VERSION_FILE := $(KSRC)/include/linux/version.h ++UTS_REL_FILE := $(KSRC)/include/linux/utsrelease.h ++CONFIG_FILE := $(KSRC)/include/linux/autoconf.h + + ifeq (,$(wildcard $(VERSION_FILE))) + $(error Linux kernel source not configured - missing version.h) +@@ -98,83 +71,8 @@ ifeq (,$(wildcard $(CONFIG_FILE))) + $(error Linux kernel source not configured - missing autoconf.h) + endif + +-# as of 2.6.16, kernel define UTS_RELEASE has been moved to utsrelease.h +-# so check that file for kernel version string instead of version.h +-USE_UTS_REL := $(shell [ -f $(UTS_REL_FILE) ] && echo "1") +- +-# pick a compiler +-ifneq (,$(findstring egcs-2.91.66, $(shell cat /proc/version))) +- CC := kgcc gcc cc +-else +- CC := gcc cc +-endif +-test_cc = $(shell $(cc) --version > /dev/null 2>&1 && echo $(cc)) +-CC := $(foreach cc, $(CC), $(test_cc)) +-CC := $(firstword $(CC)) +-ifeq (,$(CC)) +- $(error Compiler not found) +-endif +- +-# we need to know what platform the driver is being built on +-# some additional features are only built on Intel platforms +-ARCH := $(shell uname -m | sed 's/i.86/i386/') +-ifeq ($(ARCH),alpha) +- CFLAGS += -ffixed-8 -mno-fp-regs +-endif +-ifeq ($(ARCH),x86_64) +- CFLAGS += -mcmodel=kernel -mno-red-zone +-endif +-ifeq ($(ARCH),ppc) +- CFLAGS += -msoft-float +-endif +-ifeq ($(ARCH),ppc64) +- CFLAGS += -m64 -msoft-float +- LDFLAGS += -melf64ppc +-endif +- +-# standard flags for module builds +-CFLAGS += -DLINUX -D__KERNEL__ -DMODULE -O2 -pipe -Wall +-CFLAGS += -I$(KSRC)/include -I. +-CFLAGS += $(shell [ -f $(KSRC)/include/linux/modversions.h ] && \ +- echo "-DMODVERSIONS -DEXPORT_SYMTAB \ +- -include $(KSRC)/include/linux/modversions.h") +- +-ifeq ($(IEGBE_GBE_WORKAROUND), 1) +-CFLAGS += -DIEGBE_GBE_WORKAROUND -DE1000_NO_NAPI +-endif +- +-ifeq ($(IEGBE_10_100_ONLY), 1) +-CFLAGS += -DIEGBE_10_100_ONLY +-endif +- +-CFLAGS += $(CFLAGS_EXTRA) +-#ifeq (,$(shell echo $(CFLAGS_EXTRA) | grep NAPI)) +-#CFLAGS += -DE1000_NO_NAPI +-#CFLAGS_EXTRA += -DE1000_NO_NAPI +-#endif +- +-RHC := $(KSRC)/include/linux/rhconfig.h +-ifneq (,$(wildcard $(RHC))) +- # 7.3 typo in rhconfig.h +- ifneq (,$(shell $(CC) $(CFLAGS) -E -dM $(RHC) | grep __module__bigmem)) +- CFLAGS += -D__module_bigmem +- endif +-endif +- +-# get the kernel version - we use this to find the correct install path +-ifeq ($(USE_UTS_REL), 1) +- KVER := $(shell $(CC) $(CFLAGS) -E -dM $(UTS_REL_FILE) | grep UTS_RELEASE | \ +- awk '{ print $$3 }' | sed 's/\"//g') +-else +- KVER := $(shell $(CC) $(CFLAGS) -E -dM $(VERSION_FILE) | grep UTS_RELEASE | \ +- awk '{ print $$3 }' | sed 's/\"//g') +-endif +- +-KKVER := $(shell echo $(KVER) | \ +- awk '{ if ($$0 ~ /2\.[6-9]\./) print "1"; else print "0"}') +-ifeq ($(KKVER), 0) +- $(error *** Aborting the build. \ +- *** This driver is not supported on kernel versions older than 2.6.18) ++ifeq (,$(wildcard $(UTS_REL_FILE))) ++ $(error Linux kernel source not configured - missing utsrelease.h) + endif + + # set the install path +@@ -202,11 +100,11 @@ ifneq ($(SMP),$(shell uname -a | grep SM + endif + + ifeq ($(SMP),1) +- CFLAGS += -D__SMP__ ++ EXTRA_CFLAGS += -D__SMP__ + endif + + ifeq ($(EXTERNAL_MDIO), 1) +- CFLAGS += -DEXTERNAL_MDIO ++ EXTRA_CFLAGS += -DEXTERNAL_MDIO + endif + + ########################################################################### +@@ -223,7 +121,6 @@ MANSECTION = 7 + MANFILE = $(TARGET:.ko=.$(MANSECTION)) + + ifneq ($(PATCHLEVEL),) +- EXTRA_CFLAGS += $(CFLAGS_EXTRA) + obj-m += $(TARGET:.ko=.o) + iegbe-objs := $(CFILES:.c=.o) + ifeq ($(EXTERNAL_MDIO),1) +--- a/filelist ++++ b/filelist +@@ -1,41 +1,3 @@ +-Embedded/Makefile +-Embedded/environment.mk +-Embedded/src/1588/1588.c +-Embedded/src/1588/1588.h +-Embedded/src/1588/IxTimeSyncAcc_p.h +-Embedded/src/1588/Makefile +-Embedded/src/1588/ixtimesyncacc.c +-Embedded/src/1588/ixtimesyncacc.h +-Embedded/src/1588/linux_ioctls.h +-Embedded/src/CAN/Makefile +-Embedded/src/CAN/can_fifo.c +-Embedded/src/CAN/can_fifo.h +-Embedded/src/CAN/can_ioctl.h +-Embedded/src/CAN/can_main.c +-Embedded/src/CAN/can_main.h +-Embedded/src/CAN/can_port.h +-Embedded/src/CAN/icp_can.c +-Embedded/src/CAN/icp_can.h +-Embedded/src/CAN/icp_can_regs.h +-Embedded/src/CAN/icp_can_types.h +-Embedded/src/CAN/icp_can_user.h +-Embedded/src/EDMA/Makefile +-Embedded/src/EDMA/dma.h +-Embedded/src/EDMA/dma_api.h +-Embedded/src/EDMA/dma_client_api.c +-Embedded/src/EDMA/dma_common.c +-Embedded/src/EDMA/dma_internals.h +-Embedded/src/EDMA/dma_linux.c +-Embedded/src/EDMA/os/os.c +-Embedded/src/EDMA/os/os.h +-Embedded/src/EDMA/os/os_list.c +-Embedded/src/EDMA/os/os_list.h +-Embedded/src/EDMA/os/os_types.h +-Embedded/src/GPIO/Makefile +-Embedded/src/GPIO/common.h +-Embedded/src/GPIO/gpio.h +-Embedded/src/GPIO/gpio_ref.c +-Embedded/src/GPIO/linux_ioctls.h + Embedded/src/GbE/Makefile + Embedded/src/GbE/gcu.h + Embedded/src/GbE/gcu_if.c +@@ -55,16 +17,6 @@ Embedded/src/GbE/iegbe_param.c + Embedded/src/GbE/kcompat.c + Embedded/src/GbE/kcompat.h + Embedded/src/GbE/kcompat_ethtool.c +-Embedded/src/WDT/Makefile +-Embedded/src/WDT/iwdt.c +-Embedded/src/WDT/iwdt.h +-Embedded/src/patches/Intel_EP80579_RHEL5.patch +-Embedded/src/patches/pci.ids_RHEL5.patch + LICENSE.GPL +-build_system/build_files/Core/ia.mk +-build_system/build_files/OS/linux_2.6.mk +-build_system/build_files/OS/linux_2.6_kernel_space_rules.mk +-build_system/build_files/common.mk +-build_system/build_files/rules.mk + filelist + versionfile +--- a/versionfile ++++ b/versionfile +@@ -1,4 +1,4 @@ +-PACKAGE_TYPE=Embedded ++PACKAGE_TYPE=Embedded.Release.Patch + + PACKAGE_OS=L + +@@ -6,4 +6,6 @@ PACKAGE_VERSION_MAJOR_NUMBER=1 + + PACKAGE_VERSION_MINOR_NUMBER=0 + +-PACKAGE_VERSION_PATCH_NUMBER=34 ++PACKAGE_VERSION_PATCH_NUMBER=7 ++ ++PACKAGE_VERSION_BUILD_NUMBER=5 diff --git a/package/ep80579-drivers/patches/002-cflags_cleanup.patch b/package/ep80579-drivers/patches/002-cflags_cleanup.patch new file mode 100644 index 0000000000..f897527956 --- /dev/null +++ b/package/ep80579-drivers/patches/002-cflags_cleanup.patch @@ -0,0 +1,22 @@ +--- a/build_system/build_files/common.mk ++++ b/build_system/build_files/common.mk +@@ -122,7 +122,7 @@ CC=$(COMPILER) + LD=$(LINKER) + AR=$(ARCHIVER) + +-CFLAGS+=-O2 ++#CFLAGS+=-O2 + + + PWD= $(shell pwd) +--- a/build_system/build_files/OS/linux_2.6.mk ++++ b/build_system/build_files/OS/linux_2.6.mk +@@ -80,7 +80,7 @@ endif + + + ifeq ($(OS_LEVEL), kernel_space) +-CFLAGS+= ++#CFLAGS+= + endif + + diff --git a/package/ep80579-drivers/patches/003-new_irqf_constants.patch b/package/ep80579-drivers/patches/003-new_irqf_constants.patch new file mode 100644 index 0000000000..af231f2184 --- /dev/null +++ b/package/ep80579-drivers/patches/003-new_irqf_constants.patch @@ -0,0 +1,53 @@ +--- a/Embedded/src/1588/1588.c ++++ b/Embedded/src/1588/1588.c +@@ -291,7 +291,7 @@ int pci_probe(struct pci_dev *dev, const + + } + +- if ( request_irq(dev->irq, ×ync_isr, SA_SHIRQ, DRIVERNAME, ++ if ( request_irq(dev->irq, ×ync_isr, IRQF_SHARED, DRIVERNAME, + &g_drvr_data) ) + { + printk("%s-pci_probe: irq\n", DRIVERNAME); +--- a/Embedded/src/CAN/can_main.c ++++ b/Embedded/src/CAN/can_main.c +@@ -424,7 +424,7 @@ int can_open(struct inode *inode, struct + err = request_irq(
+ can_os->irq,
+ can_irq_handler,
+- SA_SHIRQ,
++ IRQF_SHARED,
+ iminor(can_os->inode) ? CAN_PROC_1 : CAN_PROC_0,
+ &(g_can_os[iminor(can_os->inode)])
+ );
+--- a/Embedded/src/EDMA/dma_linux.c ++++ b/Embedded/src/EDMA/dma_linux.c +@@ -367,7 +367,7 @@ int32_t edma_resume(struct pci_dev *dev) + return -ENODEV; + } + +- if (request_irq(dev->irq, &edma_irq_handler, SA_SHIRQ, ++ if (request_irq(dev->irq, &edma_irq_handler, IRQF_SHARED, + g_char_drvr_name, dev) ) + { + +@@ -829,7 +829,7 @@ int32_t edma_probe(struct pci_dev * dev, + /* + * Obtain a (shared) Interrupt Request (IRQ) Line from the OS. + */ +- if (request_irq(dev->irq, &edma_irq_handler, SA_SHIRQ, ++ if (request_irq(dev->irq, &edma_irq_handler, IRQF_SHARED, + g_char_drvr_name, dev) ) + { + +--- a/Embedded/src/WDT/iwdt.c ++++ b/Embedded/src/WDT/iwdt.c +@@ -1461,7 +1461,7 @@ static int __init wdt_init_one(struct pc + + /* Request irq only if wdt_irq is other than 0 */ + if (wdt_irq) { +- if (request_irq(wdt_irq, wdt_isr, SA_INTERRUPT | SA_SHIRQ, ++ if (request_irq(wdt_irq, wdt_isr, IRQF_DISABLED | IRQF_SHARED, + "iwdt", &wdt_miscdev)) { + printk("IRQ %d is not free.\n", wdt_irq); + return -EIO; diff --git a/package/ep80579-drivers/patches/100-iegbe_netdev_ops.patch b/package/ep80579-drivers/patches/100-iegbe_netdev_ops.patch new file mode 100644 index 0000000000..ab23da63ff --- /dev/null +++ b/package/ep80579-drivers/patches/100-iegbe_netdev_ops.patch @@ -0,0 +1,56 @@ +--- a/Embedded/src/GbE/iegbe_main.c ++++ b/Embedded/src/GbE/iegbe_main.c +@@ -724,6 +724,26 @@ static void iegbe_dump_eeprom(struct ieg + kfree(data); + } + ++static const struct net_device_ops iegbe_netdev_ops = { ++ .ndo_open = iegbe_open, ++ .ndo_stop = iegbe_close, ++ .ndo_start_xmit = iegbe_xmit_frame, ++ .ndo_get_stats = iegbe_get_stats, ++ .ndo_set_rx_mode = iegbe_set_rx_mode, ++ .ndo_set_mac_address = iegbe_set_mac, ++ .ndo_tx_timeout = iegbe_tx_timeout, ++ .ndo_change_mtu = iegbe_change_mtu, ++ .ndo_do_ioctl = iegbe_ioctl, ++ .ndo_validate_addr = eth_validate_addr, ++ ++ .ndo_vlan_rx_register = iegbe_vlan_rx_register, ++ .ndo_vlan_rx_add_vid = iegbe_vlan_rx_add_vid, ++ .ndo_vlan_rx_kill_vid = iegbe_vlan_rx_kill_vid, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = iegbe_netpoll, ++#endif ++}; ++ + /** + * iegbe_probe - Device Initialization Routine + * @pdev: PCI device information struct +@@ -800,24 +820,11 @@ static int __devinit iegbe_probe(struct + if (!hw->hw_addr) + goto err_ioremap; + +- netdev->open = &iegbe_open; +- netdev->stop = &iegbe_close; +- netdev->hard_start_xmit = &iegbe_xmit_frame; +- netdev->get_stats = &iegbe_get_stats; +- netdev->set_rx_mode = &iegbe_set_rx_mode; +- netdev->set_mac_address = &iegbe_set_mac; +- netdev->change_mtu = &iegbe_change_mtu; +- netdev->do_ioctl = &iegbe_ioctl; ++ netdev->netdev_ops = &iegbe_netdev_ops; + set_ethtool_ops(netdev); +- netdev->tx_timeout = &iegbe_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; + netif_napi_add(netdev, &adapter->napi, iegbe_clean, 64); +- netdev->vlan_rx_register = iegbe_vlan_rx_register; +- netdev->vlan_rx_add_vid = iegbe_vlan_rx_add_vid; +- netdev->vlan_rx_kill_vid = iegbe_vlan_rx_kill_vid; +-#ifdef CONFIG_NET_POLL_CONTROLLER +- netdev->poll_controller = iegbe_netpoll; +-#endif ++ + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); + + diff --git a/package/ep80579-drivers/patches/101-iegbe_fix_napi_interface.patch b/package/ep80579-drivers/patches/101-iegbe_fix_napi_interface.patch new file mode 100644 index 0000000000..921d464bad --- /dev/null +++ b/package/ep80579-drivers/patches/101-iegbe_fix_napi_interface.patch @@ -0,0 +1,41 @@ +--- a/Embedded/src/GbE/iegbe_main.c ++++ b/Embedded/src/GbE/iegbe_main.c +@@ -3465,12 +3465,12 @@ static irqreturn_t iegbe_intr_msi(int ir + printk("Critical error! ICR = 0x%x\n", icr); + return IRQ_HANDLED; + } +- if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { ++ if (likely(napi_schedule_prep(&adapter->napi))) { + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; +- __netif_rx_schedule(netdev, &adapter->napi); ++ __napi_schedule(&adapter->napi); + } else + iegbe_irq_enable(adapter); + +@@ -3527,12 +3527,12 @@ iegbe_intr(int irq, void *data) + E1000_WRITE_REG(&adapter->hw, IMC, ~0); + E1000_WRITE_FLUSH(&adapter->hw); + } +- if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { ++ if (likely(napi_schedule_prep(&adapter->napi))) { + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; +- __netif_rx_schedule(netdev, &adapter->napi); ++ __napi_schedule(&adapter->napi); + } else + /* this really should not happen! if it does it is basically a + * bug, but not a hard error, so enable ints and continue */ +@@ -3574,7 +3574,7 @@ static int iegbe_clean(struct napi_struc + if (work_done < budget) { + if (likely(adapter->itr_setting & 3)) + iegbe_set_itr(adapter); +- netif_rx_complete(poll_dev, napi); ++ napi_complete(napi); + iegbe_irq_enable(adapter); + } + diff --git a/package/ep80579-drivers/patches/102-iegbe_nuke_polling_netdev.patch b/package/ep80579-drivers/patches/102-iegbe_nuke_polling_netdev.patch new file mode 100644 index 0000000000..7147449c24 --- /dev/null +++ b/package/ep80579-drivers/patches/102-iegbe_nuke_polling_netdev.patch @@ -0,0 +1,103 @@ +--- a/Embedded/src/GbE/iegbe.h ++++ b/Embedded/src/GbE/iegbe.h +@@ -316,7 +316,6 @@ struct iegbe_adapter { + int cleaned_count); + struct iegbe_rx_ring *rx_ring; /* One per active queue */ + struct napi_struct napi; +- struct net_device *polling_netdev; /* One per active queue */ + + int num_tx_queues; + int num_rx_queues; +--- a/Embedded/src/GbE/iegbe_main.c ++++ b/Embedded/src/GbE/iegbe_main.c +@@ -763,7 +763,7 @@ static int __devinit iegbe_probe(struct + struct iegbe_hw *hw; + + static int cards_found = 0; +- int i, err, pci_using_dac; ++ int err, pci_using_dac; + u16 eeprom_data = 0; + u16 eeprom_apme_mask = E1000_EEPROM_APME; + int bars; +@@ -984,11 +984,8 @@ err_eeprom: + iegbe_phy_hw_reset(hw); + if (hw->flash_address) + iounmap(hw->flash_address); +- for (i = 0; i < adapter->num_rx_queues; i++) +- dev_put(&adapter->polling_netdev[i]); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); +- kfree(adapter->polling_netdev); + err_sw_init: + iounmap(hw->hw_addr); + err_ioremap: +@@ -1017,7 +1014,6 @@ iegbe_remove(struct pci_dev *pdev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct iegbe_adapter *adapter = netdev_priv(netdev); + uint32_t manc; +- int i; + + if(adapter->hw.mac_type >= iegbe_82540 + && adapter->hw.mac_type != iegbe_icp_xxxx +@@ -1030,15 +1026,11 @@ iegbe_remove(struct pci_dev *pdev) + } + + unregister_netdev(netdev); +- for (i = 0x0; i < adapter->num_rx_queues; i++) +- dev_put(&adapter->polling_netdev[i]); +- + if(!iegbe_check_phy_reset_block(&adapter->hw)) { + iegbe_phy_hw_reset(&adapter->hw); + } + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); +- kfree(adapter->polling_netdev); + + iounmap(adapter->hw.hw_addr); + pci_release_regions(pdev); +@@ -1061,7 +1053,6 @@ iegbe_sw_init(struct iegbe_adapter *adap + struct iegbe_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; +- int i; + + /* PCI config space info */ + +@@ -1111,11 +1102,6 @@ iegbe_sw_init(struct iegbe_adapter *adap + return -ENOMEM; + } + +- for (i = 0; i < adapter->num_rx_queues; i++) { +- adapter->polling_netdev[i].priv = adapter; +- dev_hold(&adapter->polling_netdev[i]); +- set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); +- } + spin_lock_init(&adapter->tx_queue_lock); + + /* +@@ -1137,8 +1123,7 @@ iegbe_sw_init(struct iegbe_adapter *adap + * @adapter: board private structure to initialize + * + * We allocate one ring per queue at run-time since we don't know the +- * number of queues at compile-time. The polling_netdev array is +- * intended for Multiqueue, but should work fine with a single queue. ++ * number of queues at compile-time. + **/ + + static int __devinit +@@ -1158,15 +1143,6 @@ iegbe_alloc_queues(struct iegbe_adapter + return -ENOMEM; + } + +- adapter->polling_netdev = kcalloc(adapter->num_rx_queues, +- sizeof(struct net_device), +- GFP_KERNEL); +- if (!adapter->polling_netdev) { +- kfree(adapter->tx_ring); +- kfree(adapter->rx_ring); +- return -ENOMEM; +- } +- + return E1000_SUCCESS; + } + diff --git a/package/ep80579-drivers/patches/103-iegbe_convert_unicast_addr_list.patch b/package/ep80579-drivers/patches/103-iegbe_convert_unicast_addr_list.patch new file mode 100644 index 0000000000..71d2d54e6b --- /dev/null +++ b/package/ep80579-drivers/patches/103-iegbe_convert_unicast_addr_list.patch @@ -0,0 +1,60 @@ +--- a/Embedded/src/GbE/iegbe_main.c ++++ b/Embedded/src/GbE/iegbe_main.c +@@ -2161,7 +2161,8 @@ static void iegbe_set_rx_mode(struct net + { + struct iegbe_adapter *adapter = netdev_priv(netdev); + struct iegbe_hw *hw = &adapter->hw; +- struct dev_addr_list *uc_ptr; ++ struct netdev_hw_addr *ha; ++ bool use_uc = false; + struct dev_addr_list *mc_ptr; + u32 rctl; + u32 hash_value; +@@ -2187,12 +2188,11 @@ int mta_reg_count = E1000_NUM_MTA_REGIST + } + } + +- uc_ptr = NULL; + if (netdev->uc_count > rar_entries - 1) { + rctl |= E1000_RCTL_UPE; + } else if (!(netdev->flags & IFF_PROMISC)) { + rctl &= ~E1000_RCTL_UPE; +- uc_ptr = netdev->uc_list; ++ use_uc = true; + } + + E1000_WRITE_REG(&adapter->hw, RCTL, rctl); +@@ -2210,13 +2210,20 @@ int mta_reg_count = E1000_NUM_MTA_REGIST + * if there are not 14 addresses, go ahead and clear the filters + * -- with 82571 controllers only 0-13 entries are filled here + */ ++ i = 1; ++ if (use_uc) ++ list_for_each_entry(ha, &netdev->uc_list, list) { ++ if (i == rar_entries) ++ break; ++ iegbe_rar_set(hw, ha->addr, i++); ++ } ++ ++ WARN_ON(i == rar_entries); ++ + mc_ptr = netdev->mc_list; + +- for (i = 1; i < rar_entries; i++) { +- if (uc_ptr) { +- iegbe_rar_set(hw, uc_ptr->da_addr, i); +- uc_ptr = uc_ptr->next; +- } else if (mc_ptr) { ++ for (; i < rar_entries; i++) { ++ if (mc_ptr) { + iegbe_rar_set(hw, mc_ptr->da_addr, i); + mc_ptr = mc_ptr->next; + } else { +@@ -2226,7 +2233,6 @@ int mta_reg_count = E1000_NUM_MTA_REGIST + E1000_WRITE_FLUSH(&adapter->hw); + } + } +- WARN_ON(uc_ptr != NULL); + + /* clear the old settings from the multicast hash table */ + diff --git a/package/ep80579-drivers/patches/104-iegbe_group_address_list_and_its_count.patch b/package/ep80579-drivers/patches/104-iegbe_group_address_list_and_its_count.patch new file mode 100644 index 0000000000..c6eced6a5c --- /dev/null +++ b/package/ep80579-drivers/patches/104-iegbe_group_address_list_and_its_count.patch @@ -0,0 +1,20 @@ +--- a/Embedded/src/GbE/iegbe_main.c ++++ b/Embedded/src/GbE/iegbe_main.c +@@ -2188,7 +2188,7 @@ int mta_reg_count = E1000_NUM_MTA_REGIST + } + } + +- if (netdev->uc_count > rar_entries - 1) { ++ if (netdev->uc.count > rar_entries - 1) { + rctl |= E1000_RCTL_UPE; + } else if (!(netdev->flags & IFF_PROMISC)) { + rctl &= ~E1000_RCTL_UPE; +@@ -2212,7 +2212,7 @@ int mta_reg_count = E1000_NUM_MTA_REGIST + */ + i = 1; + if (use_uc) +- list_for_each_entry(ha, &netdev->uc_list, list) { ++ list_for_each_entry(ha, &netdev->uc.list, list) { + if (i == rar_entries) + break; + iegbe_rar_set(hw, ha->addr, i++); diff --git a/package/ep80579-drivers/patches/105-iegbe_new_dma_masks.patch b/package/ep80579-drivers/patches/105-iegbe_new_dma_masks.patch new file mode 100644 index 0000000000..c7a103b448 --- /dev/null +++ b/package/ep80579-drivers/patches/105-iegbe_new_dma_masks.patch @@ -0,0 +1,20 @@ +--- a/Embedded/src/GbE/iegbe_main.c ++++ b/Embedded/src/GbE/iegbe_main.c +@@ -775,13 +775,13 @@ static int __devinit iegbe_probe(struct + if (err) + return err; + +- if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && +- !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { ++ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && ++ !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { + pci_using_dac = 1; + } else { +- err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); ++ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { +- err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); ++ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { + E1000_ERR("No usable DMA configuration, " + "aborting\n"); diff --git a/package/ep80579-drivers/patches/106-iegbe_new_irqf_constant.patch b/package/ep80579-drivers/patches/106-iegbe_new_irqf_constant.patch new file mode 100644 index 0000000000..a08e8c7697 --- /dev/null +++ b/package/ep80579-drivers/patches/106-iegbe_new_irqf_constant.patch @@ -0,0 +1,12 @@ +--- a/Embedded/src/GbE/iegbe_ethtool.c ++++ b/Embedded/src/GbE/iegbe_ethtool.c +@@ -944,7 +944,8 @@ iegbe_intr_test(struct iegbe_adapter *ad + *data = 0; + + /* Hook up test interrupt handler just for this test */ +- if(!request_irq(irq, &iegbe_test_intr, 0, netdev->name, netdev)) { ++ if(!request_irq(irq, &iegbe_test_intr, IRQF_PROBE_SHARED, netdev->name, ++ netdev)) { + shared_int = FALSE; + } else if(request_irq(irq, &iegbe_test_intr, IRQF_SHARED, + netdev->name, netdev)){ diff --git a/package/ep80579-drivers/patches/150-ocracoke_island.patch b/package/ep80579-drivers/patches/150-ocracoke_island.patch new file mode 100644 index 0000000000..34c11daac1 --- /dev/null +++ b/package/ep80579-drivers/patches/150-ocracoke_island.patch @@ -0,0 +1,747 @@ +--- a/Embedded/src/GbE/iegbe_oem_phy.c ++++ b/Embedded/src/GbE/iegbe_oem_phy.c +@@ -65,6 +65,10 @@ static int32_t iegbe_oem_link_m88_setup( + static int32_t iegbe_oem_set_phy_mode(struct iegbe_hw *hw); + static int32_t iegbe_oem_detect_phy(struct iegbe_hw *hw); + ++static int32_t iegbe_oem_link_bcm5481_setup(struct iegbe_hw *hw); ++static int32_t bcm5481_read_18sv (struct iegbe_hw *hw, int sv, uint16_t *data); ++static int32_t oi_phy_setup (struct iegbe_hw *hw); ++ + /** + * iegbe_oem_setup_link + * @hw: iegbe_hw struct containing device specific information +@@ -114,6 +118,10 @@ iegbe_oem_setup_link(struct iegbe_hw *hw + } + + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ return E1000_SUCCESS; ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + ret_val = iegbe_oem_link_m88_setup(hw); +@@ -121,6 +129,12 @@ iegbe_oem_setup_link(struct iegbe_hw *hw + return ret_val; + } + break; ++ case BCM5481_PHY_ID: ++ ret_val = iegbe_oem_link_bcm5481_setup(hw); ++ if(ret_val) { ++ return ret_val; ++ } ++ break; + default: + DEBUGOUT("Invalid PHY ID\n"); + return -E1000_ERR_PHY_TYPE; +@@ -179,6 +193,51 @@ iegbe_oem_setup_link(struct iegbe_hw *hw + #endif /* ifdef EXTERNAL_MDIO */ + } + ++/** ++ * iegbe_oem_link_bcm5481_setup ++ * @hw: iegbe_hw struct containing device specific information ++ * ++ * Returns E1000_SUCCESS, negative E1000 error code on failure ++ * ++ * copied verbatim from iegbe_oem_link_m88_setup ++ **/ ++static int32_t ++iegbe_oem_link_bcm5481_setup(struct iegbe_hw *hw) ++{ ++ int32_t ret_val; ++ uint16_t phy_data; ++ ++ //DEBUGFUNC(__func__); ++ ++ if(!hw) ++ return -1; ++ ++ /* phy_reset_disable is set in iegbe_oem_set_phy_mode */ ++ if(hw->phy_reset_disable) ++ return E1000_SUCCESS; ++ ++ // Enable MDIX in extended control reg. ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, BCM5481_ECTRL, &phy_data); ++ if(ret_val) ++ { ++ DEBUGOUT("Unable to read BCM5481_ECTRL register\n"); ++ return ret_val; ++ } ++ ++ phy_data &= ~BCM5481_ECTRL_DISMDIX; ++ ret_val = iegbe_oem_write_phy_reg_ex(hw, BCM5481_ECTRL, phy_data); ++ if(ret_val) ++ { ++ DEBUGOUT("Unable to write BCM5481_ECTRL register\n"); ++ return ret_val; ++ } ++ ++ ret_val = oi_phy_setup (hw); ++ if (ret_val) ++ return ret_val; ++ ++ return E1000_SUCCESS; ++} + + /** + * iegbe_oem_link_m88_setup +@@ -340,6 +399,11 @@ iegbe_oem_force_mdi(struct iegbe_hw *hw, + * see iegbe_phy_force_speed_duplex, which does the following for M88 + */ + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ case BCM5481_PHY_ID: ++ DEBUGOUT("WARNING: An empty iegbe_oem_force_mdi() has been called!\n"); ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + ret_val = iegbe_oem_read_phy_reg_ex(hw, +@@ -415,6 +479,8 @@ iegbe_oem_phy_reset_dsp(struct iegbe_hw + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: ++ case BCM5481_PHY_ID: ++ case BCM5395S_PHY_ID: + DEBUGOUT("No DSP to reset on OEM PHY\n"); + break; + default: +@@ -460,6 +526,11 @@ iegbe_oem_cleanup_after_phy_reset(struct + * see iegbe_phy_force_speed_duplex, which does the following for M88 + */ + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ case BCM5481_PHY_ID: ++ DEBUGOUT("WARNING: An empty iegbe_oem_cleanup_after_phy_reset() has been called!\n"); ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + /* +@@ -573,6 +644,11 @@ iegbe_oem_set_phy_mode(struct iegbe_hw * + * use iegbe_set_phy_mode as example + */ + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ case BCM5481_PHY_ID: ++ DEBUGOUT("WARNING: An empty iegbe_oem_set_phy_mode() has been called!\n"); ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + ret_val = iegbe_read_eeprom(hw, +@@ -641,6 +717,19 @@ iegbe_oem_detect_phy(struct iegbe_hw *hw + } + hw->phy_type = iegbe_phy_oem; + ++{ ++ // If MAC2 (BCM5395 switch), manually detect the phy ++ struct iegbe_adapter *adapter; ++ uint32_t device_number; ++ adapter = (struct iegbe_adapter *) hw->back; ++ device_number = PCI_SLOT(adapter->pdev->devfn); ++ if (device_number == ICP_XXXX_MAC_2) { ++ hw->phy_id = BCM5395S_PHY_ID; ++ hw->phy_revision = 0; ++ return E1000_SUCCESS; ++ } ++} ++ + ret_val = iegbe_oem_read_phy_reg_ex(hw, PHY_ID1, &phy_id_high); + if(ret_val) { + DEBUGOUT("Unable to read PHY register PHY_ID1\n"); +@@ -690,6 +779,8 @@ iegbe_oem_get_tipg(struct iegbe_hw *hw) + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: ++ case BCM5481_PHY_ID: ++ case BCM5395S_PHY_ID: + phy_num = DEFAULT_ICP_XXXX_TIPG_IPGT; + break; + default: +@@ -738,6 +829,8 @@ iegbe_oem_phy_is_copper(struct iegbe_hw + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: ++ case BCM5481_PHY_ID: ++ case BCM5395S_PHY_ID: + isCopper = TRUE; + break; + default: +@@ -796,13 +889,13 @@ iegbe_oem_get_phy_dev_number(struct iegb + switch(device_number) + { + case ICP_XXXX_MAC_0: +- hw->phy_addr = 0x00; ++ hw->phy_addr = 0x01; + break; + case ICP_XXXX_MAC_1: +- hw->phy_addr = 0x01; ++ hw->phy_addr = 0x02; + break; + case ICP_XXXX_MAC_2: +- hw->phy_addr = 0x02; ++ hw->phy_addr = 0x00; + break; + default: hw->phy_addr = 0x00; + } +@@ -851,6 +944,12 @@ iegbe_oem_mii_ioctl(struct iegbe_adapter + if(!adapter || !ifr) { + return -1; + } ++ ++ // If MAC2 (BCM5395 switch) then leave now ++ if ((PCI_SLOT(adapter->pdev->devfn)) == ICP_XXXX_MAC_2) { ++ return -1; ++ } ++ + switch (data->reg_num) { + case PHY_CTRL: + if(mii_reg & MII_CR_POWER_DOWN) { +@@ -987,6 +1086,11 @@ void iegbe_oem_get_phy_regs(struct iegbe + * [10] = mdix mode + */ + switch (adapter->hw.phy_id) { ++ case BCM5395S_PHY_ID: ++ case BCM5481_PHY_ID: ++ DEBUGOUT("WARNING: An empty iegbe_oem_get_phy_regs() has been called!\n"); ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + if(corrected_len > 0) { +@@ -1068,8 +1172,13 @@ iegbe_oem_phy_loopback(struct iegbe_adap + * Loopback configuration is the same for each of the supported PHYs. + */ + switch (adapter->hw.phy_id) { ++ case BCM5395S_PHY_ID: ++ DEBUGOUT("WARNING: An empty iegbe_oem_phy_loopback() has been called!\n"); ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: ++ case BCM5481_PHY_ID: + + adapter->hw.autoneg = FALSE; + +@@ -1182,8 +1291,14 @@ iegbe_oem_loopback_cleanup(struct iegbe_ + } + + switch (adapter->hw.phy_id) { ++ case BCM5395S_PHY_ID: ++ DEBUGOUT("WARNING: An empty iegbe_oem_loopback_cleanup() has been called!\n"); ++ return; ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: ++ case BCM5481_PHY_ID: + default: + adapter->hw.autoneg = TRUE; + +@@ -1243,6 +1358,11 @@ iegbe_oem_phy_speed_downgraded(struct ie + */ + + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ case BCM5481_PHY_ID: ++ *isDowngraded = 0; ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, +@@ -1305,6 +1425,11 @@ iegbe_oem_check_polarity(struct iegbe_hw + */ + + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ case BCM5481_PHY_ID: ++ *polarity = 0; ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + /* return the Polarity bit in the Status register. */ +@@ -1367,6 +1492,25 @@ iegbe_oem_phy_is_full_duplex(struct iegb + */ + + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ /* Always full duplex */ ++ *isFD = 1; ++ break; ++ ++ case BCM5481_PHY_ID: ++ ret_val = iegbe_read_phy_reg(hw, BCM5481_ASTAT, &phy_data); ++ if(ret_val) return ret_val; ++ ++ switch (BCM5481_ASTAT_HCD(phy_data)) { ++ case BCM5481_ASTAT_1KBTFD: ++ case BCM5481_ASTAT_100BTXFD: ++ *isFD = 1; ++ break; ++ default: ++ *isFD = 0; ++ } ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, +@@ -1423,6 +1567,25 @@ iegbe_oem_phy_is_speed_1000(struct iegbe + */ + + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ /* Always 1000mb */ ++ *is1000 = 1; ++ break; ++ ++ case BCM5481_PHY_ID: ++ ret_val = iegbe_read_phy_reg(hw, BCM5481_ASTAT, &phy_data); ++ if(ret_val) return ret_val; ++ ++ switch (BCM5481_ASTAT_HCD(phy_data)) { ++ case BCM5481_ASTAT_1KBTFD: ++ case BCM5481_ASTAT_1KBTHD: ++ *is1000 = 1; ++ break; ++ default: ++ *is1000 = 0; ++ } ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, +@@ -1478,6 +1641,25 @@ iegbe_oem_phy_is_speed_100(struct iegbe_ + * see iegbe_config_mac_to_phy + */ + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ /* Always 1000Mb, never 100mb */ ++ *is100 = 0; ++ break; ++ ++ case BCM5481_PHY_ID: ++ ret_val = iegbe_read_phy_reg(hw, BCM5481_ASTAT, &phy_data); ++ if(ret_val) return ret_val; ++ ++ switch (BCM5481_ASTAT_HCD(phy_data)) { ++ case BCM5481_ASTAT_100BTXFD: ++ case BCM5481_ASTAT_100BTXHD: ++ *is100 = 1; ++ break; ++ default: ++ *is100 = 0; ++ } ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + ret_val = iegbe_oem_read_phy_reg_ex(hw, +@@ -1535,6 +1717,11 @@ iegbe_oem_phy_get_info(struct iegbe_hw * + * see iegbe_phy_m88_get_info + */ + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ case BCM5481_PHY_ID: ++ DEBUGOUT("WARNING: An empty iegbe_oem_phy_get_info() has been called!\n"); ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + /* The downshift status is checked only once, after link is +@@ -1636,8 +1823,13 @@ iegbe_oem_phy_hw_reset(struct iegbe_hw * + * the M88 used in truxton. + */ + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ DEBUGOUT("WARNING: An empty iegbe_oem_phy_hw_reset() has been called!\n"); ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: ++ case BCM5481_PHY_ID: + ret_val = iegbe_oem_read_phy_reg_ex(hw, PHY_CTRL, &phy_data); + if(ret_val) { + DEBUGOUT("Unable to read register PHY_CTRL\n"); +@@ -1699,6 +1891,8 @@ iegbe_oem_phy_init_script(struct iegbe_h + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: ++ case BCM5481_PHY_ID: ++ case BCM5395S_PHY_ID: + DEBUGOUT("Nothing to do for OEM PHY Init"); + break; + default: +@@ -1735,6 +1929,11 @@ iegbe_oem_read_phy_reg_ex(struct iegbe_h + return -1; + } + ++ if (hw->phy_id == BCM5395S_PHY_ID) { ++ DEBUGOUT("WARNING: iegbe_oem_read_phy_reg_ex() has been unexpectedly called!\n"); ++ return -1; ++ } ++ + /* call the GCU func that will read the phy + * + * Make note that the M88 phy is what'll be used on Truxton. +@@ -1782,6 +1981,11 @@ iegbe_oem_set_trans_gasket(struct iegbe_ + } + + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ case BCM5481_PHY_ID: ++ DEBUGOUT("WARNING: An empty iegbe_oem_set_trans_gasket() has been called!\n"); ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + /* Gasket set correctly for Marvell Phys, so nothing to do */ +@@ -1886,6 +2090,8 @@ iegbe_oem_phy_needs_reset_with_mac(struc + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: ++ case BCM5481_PHY_ID: ++ case BCM5395S_PHY_ID: + ret_val = FALSE; + break; + default: +@@ -1935,6 +2141,8 @@ iegbe_oem_config_dsp_after_link_change(s + switch (hw->phy_id) { + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: ++ case BCM5481_PHY_ID: ++ case BCM5395S_PHY_ID: + DEBUGOUT("No DSP to configure on OEM PHY"); + break; + default: +@@ -1978,6 +2186,12 @@ iegbe_oem_get_cable_length(struct iegbe_ + } + + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ case BCM5481_PHY_ID: ++ *min_length = 0; ++ *max_length = iegbe_igp_cable_length_150; ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + ret_val = iegbe_oem_read_phy_reg_ex(hw, +@@ -2061,6 +2275,23 @@ iegbe_oem_phy_is_link_up(struct iegbe_hw + */ + + switch (hw->phy_id) { ++ case BCM5395S_PHY_ID: ++ /* Link always up */ ++ *isUp = TRUE; ++ return E1000_SUCCESS; ++ break; ++ ++ case BCM5481_PHY_ID: ++ iegbe_oem_read_phy_reg_ex(hw, BCM5481_ESTAT, &phy_data); ++ ret_val = iegbe_oem_read_phy_reg_ex(hw, BCM5481_ESTAT, &phy_data); ++ if(ret_val) ++ { ++ DEBUGOUT("Unable to read PHY register BCM5481_ESTAT\n"); ++ return ret_val; ++ } ++ statusMask = BCM5481_ESTAT_LINK; ++ break; ++ + case M88E1000_I_PHY_ID: + case M88E1141_E_PHY_ID: + iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); +@@ -2092,3 +2323,210 @@ iegbe_oem_phy_is_link_up(struct iegbe_hw + #endif /* ifdef EXTERNAL_MDIO */ + } + ++ ++ ++//----- ++// Read BCM5481 expansion register ++// ++int32_t ++bcm5481_read_ex (struct iegbe_hw *hw, uint16_t reg, uint16_t *data) ++{ ++ int ret; ++ uint16_t selector; ++ uint16_t reg_data; ++ ++ // Get the current value of bits 15:12 ++ ret = iegbe_oem_read_phy_reg_ex (hw, 0x15, &selector); ++ if (ret) ++ return ret; ++ ++ // Select the expansion register ++ selector &= 0xf000; ++ selector |= (0xf << 8) | (reg); ++ iegbe_oem_write_phy_reg_ex (hw, 0x17, selector); ++ ++ // Read the expansion register ++ ret = iegbe_oem_read_phy_reg_ex (hw, 0x15, ®_data); ++ ++ // De-select the expansion registers. ++ selector &= 0xf000; ++ iegbe_oem_write_phy_reg_ex (hw, 0x17, selector); ++ ++ if (ret) ++ return ret; ++ ++ *data = reg_data; ++ return ret; ++} ++ ++//----- ++// Read reg 0x18 sub-register ++// ++static int32_t ++bcm5481_read_18sv (struct iegbe_hw *hw, int sv, uint16_t *data) ++{ ++ int ret; ++ uint16_t tmp_data; ++ ++ // Select reg 0x18, sv ++ tmp_data = ((sv & BCM5481_R18H_SV_MASK) << 12) | BCM5481_R18H_SV_MCTRL; ++ ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R18H, tmp_data); ++ if(ret) ++ return ret; ++ ++ // Read reg 0x18, sv ++ ret = iegbe_oem_read_phy_reg_ex (hw, BCM5481_R18H, &tmp_data); ++ if(ret) ++ return ret; ++ ++ *data = tmp_data; ++ return ret; ++} ++ ++//----- ++// Read reg 0x1C sub-register ++// ++int32_t ++bcm5481_read_1csv (struct iegbe_hw *hw, int sv, uint16_t *data) ++{ ++ int ret; ++ uint16_t tmp_data; ++ ++ // Select reg 0x1c, sv ++ tmp_data = ((sv & BCM5481_R1CH_SV_MASK) << BCM5481_R1CH_SV_SHIFT); ++ ++ ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R1CH, tmp_data); ++ if(ret) ++ return ret; ++ ++ // Read reg 0x1c, sv ++ ret = iegbe_oem_read_phy_reg_ex (hw, BCM5481_R1CH, &tmp_data); ++ if(ret) ++ return ret; ++ ++ *data = tmp_data; ++ return ret; ++} ++ ++//----- ++// Read-modify-write a 0x1C register. ++// ++// hw - hardware access info. ++// reg - 0x1C register to modify. ++// data - bits which should be set. ++// mask - the '1' bits in this argument will be cleared in the data ++// read from 'reg' then 'data' will be or'd in and the result ++// will be written to 'reg'. ++ ++int32_t ++bcm5481_rmw_1csv (struct iegbe_hw *hw, uint16_t reg, uint16_t data, uint16_t mask) ++{ ++ int32_t ret; ++ uint16_t reg_data; ++ ++ ret = 0; ++ ++ ret = bcm5481_read_1csv (hw, reg, ®_data); ++ if (ret) ++ { ++ DEBUGOUT("Unable to read BCM5481 1CH register\n"); ++ printk (KERN_ERR "Unable to read BCM5481 1CH register [0x%x]\n", reg); ++ return ret; ++ } ++ ++ reg_data &= ~mask; ++ reg_data |= (BCM5481_R1CH_WE | data); ++ ++ ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R1CH, reg_data); ++ if(ret) ++ { ++ DEBUGOUT("Unable to write BCM5481 1CH register\n"); ++ printk (KERN_ERR "Unable to write BCM5481 1CH register\n"); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++int32_t ++oi_phy_setup (struct iegbe_hw *hw) ++{ ++ int ret; ++ uint16_t pmii_data; ++ uint16_t mctrl_data; ++ uint16_t cacr_data; ++ ++ ret = 0; ++ ++ // Set low power mode via reg 0x18, sv010, bit 6 ++ // Do a read-modify-write on reg 0x18, sv010 register to preserve existing bits. ++ ret = bcm5481_read_18sv (hw, BCM5481_R18H_SV_PMII, &pmii_data); ++ if (ret) ++ { ++ DEBUGOUT("Unable to read BCM5481_R18H_SV_PMII register\n"); ++ printk (KERN_ERR "Unable to read BCM5481_R18H_SV_PMII register\n"); ++ return ret; ++ } ++ ++ // Set the LPM bit in the data just read and write back to sv010 ++ // The shadow register select bits [2:0] are set by reading the sv010 ++ // register. ++ pmii_data |= BCM5481_R18H_SV010_LPM; ++ ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R18H, pmii_data); ++ if(ret) ++ { ++ DEBUGOUT("Unable to write BCM5481_R18H register\n"); ++ printk (KERN_ERR "Unable to write BCM5481_R18H register\n"); ++ return ret; ++ } ++ ++ ++ // Set the RGMII RXD to RXC skew bit in reg 0x18, sv111 ++ ++ if (bcm5481_read_18sv (hw, BCM5481_R18H_SV_MCTRL, &mctrl_data)) ++ { ++ DEBUGOUT("Unable to read BCM5481_R18H_SV_MCTRL register\n"); ++ printk (KERN_ERR "Unable to read BCM5481_R18H_SV_MCTRL register\n"); ++ return ret; ++ } ++ mctrl_data |= (BCM5481_R18H_WE | BCM5481_R18H_SV111_SKEW); ++ ++ ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R18H, mctrl_data); ++ if(ret) ++ { ++ DEBUGOUT("Unable to write BCM5481_R18H register\n"); ++ printk (KERN_ERR "Unable to write BCM5481_R18H register\n"); ++ return ret; ++ } ++ ++ // Enable RGMII transmit clock delay in reg 0x1c, sv00011 ++ ret = bcm5481_read_1csv (hw, BCM5481_R1CH_CACR, &cacr_data); ++ if (ret) ++ { ++ DEBUGOUT("Unable to read BCM5481_R1CH_CACR register\n"); ++ printk (KERN_ERR "Unable to read BCM5481_R1CH_CACR register\n"); ++ return ret; ++ } ++ ++ cacr_data |= (BCM5481_R1CH_WE | BCM5481_R1CH_CACR_TCD); ++ ++ ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R1CH, cacr_data); ++ if(ret) ++ { ++ DEBUGOUT("Unable to write BCM5481_R1CH register\n"); ++ printk (KERN_ERR "Unable to write BCM5481_R1CH register\n"); ++ return ret; ++ } ++ ++ // Enable dual link speed indication (0x1c, sv 00010, bit 2) ++ ret = bcm5481_rmw_1csv (hw, BCM5481_R1CH_SC1, BCM5481_R1CH_SC1_LINK, BCM5481_R1CH_SC1_LINK); ++ if (ret) ++ return ret; ++ ++ // Enable link and activity on ACTIVITY LED (0x1c, sv 01001, bit 4=1, bit 3=0) ++ ret = bcm5481_rmw_1csv (hw, BCM5481_R1CH_LCTRL, BCM5481_R1CH_LCTRL_ALEN, BCM5481_R1CH_LCTRL_ALEN | BCM5481_R1CH_LCTRL_AEN); ++ if (ret) ++ return ret; ++ ++ return ret; ++} +--- a/Embedded/src/GbE/iegbe_oem_phy.h ++++ b/Embedded/src/GbE/iegbe_oem_phy.h +@@ -95,6 +95,8 @@ int32_t iegbe_oem_phy_is_link_up(struct + + #define DEFAULT_ICP_XXXX_TIPG_IPGT 8 /* Inter Packet Gap Transmit Time */ + #define ICP_XXXX_TIPG_IPGT_MASK 0x000003FFUL ++#define BCM5481_PHY_ID 0x0143BCA0 ++#define BCM5395S_PHY_ID 0x0143BCF0 + + /* Miscellaneous defines */ + #ifdef IEGBE_10_100_ONLY +@@ -103,5 +105,65 @@ int32_t iegbe_oem_phy_is_link_up(struct + #define ICP_XXXX_AUTONEG_ADV_DEFAULT 0x2F + #endif + ++/* BCM5481 specifics */ ++ ++#define BCM5481_ECTRL (0x10) ++#define BCM5481_ESTAT (0x11) ++#define BCM5481_RXERR (0x12) ++#define BCM5481_EXPRW (0x15) ++#define BCM5481_EXPACC (0x17) ++#define BCM5481_ASTAT (0x19) ++#define BCM5481_R18H (0x18) ++#define BCM5481_R1CH (0x1c) ++ ++/* indirect register access via register 18h */ ++ ++#define BCM5481_R18H_SV_MASK (7) // Mask for SV bits. ++#define BCM5481_R18H_SV_ACTRL (0) // SV000 Aux. control ++#define BCM5481_R18H_SV_10BT (1) // SV001 10Base-T ++#define BCM5481_R18H_SV_PMII (2) // SV010 Power/MII control ++#define BCM5481_R18H_SV_MTEST (4) // SV100 Misc. test ++#define BCM5481_R18H_SV_MCTRL (7) // SV111 Misc. control ++ ++#define BCM5481_R18H_SV001_POL (1 << 13) // Polarity ++#define BCM5481_R18H_SV010_LPM (1 << 6) ++#define BCM5481_R18H_SV111_SKEW (1 << 8) ++#define BCM5481_R18H_WE (1 << 15) // Write enable ++ ++// 0x1c registers ++#define BCM5481_R1CH_SV_SHIFT (10) ++#define BCM5481_R1CH_SV_MASK (0x1f) ++#define BCM5481_R1CH_SC1 (0x02) // sv00010 Spare control 1 ++#define BCM5481_R1CH_CACR (0x03) // sv00011 Clock alignment control ++#define BCM5481_R1CH_LCTRL (0x09) // sv01001 LED control ++#define BCM5481_R1CH_LEDS1 (0x0d) // sv01101 LED selector 1 ++ ++// 0x1c common ++#define BCM5481_R1CH_WE (1 << 15) // Write enable ++ ++// 0x1c, sv 00010 ++#define BCM5481_R1CH_SC1_LINK (1 << 2) // sv00010 Linkspeed ++ ++// 0x1c, sv 00011 ++#define BCM5481_R1CH_CACR_TCD (1 << 9) // sv00011 RGMII tx clock delay ++ ++// 0x1c, sv 01001 ++#define BCM5481_R1CH_LCTRL_ALEN (1 << 4) // Activity/Link enable on ACTIVITY LED ++#define BCM5481_R1CH_LCTRL_AEN (1 << 3) // Activity enable on ACTIVITY LED ++ ++#define BCM5481_ECTRL_DISMDIX (1 <<14) ++ ++#define BCM5481_MCTRL_AUTOMDIX (1 <<9) ++ ++#define BCM5481_ESTAT_LINK (1 << 8) ++ ++#define BCM5481_ASTAT_ANC (1 << 15) ++#define BCM5481_ASTAT_ANHCD (7 << 8) ++#define BCM5481_ASTAT_HCD(x) ((x >> 8) & 7) ++#define BCM5481_ASTAT_1KBTFD (0x7) ++#define BCM5481_ASTAT_1KBTHD (0x6) ++#define BCM5481_ASTAT_100BTXFD (0x5) ++#define BCM5481_ASTAT_100BTXHD (0x3) ++ + #endif /* ifndef _IEGBE_OEM_PHY_H_ */ + diff --git a/package/ep80579-drivers/patches/200-can_fix_ioctl_numbers.patch b/package/ep80579-drivers/patches/200-can_fix_ioctl_numbers.patch new file mode 100644 index 0000000000..2919466251 --- /dev/null +++ b/package/ep80579-drivers/patches/200-can_fix_ioctl_numbers.patch @@ -0,0 +1,11 @@ +--- a/Embedded/src/CAN/icp_can_user.h ++++ b/Embedded/src/CAN/icp_can_user.h +@@ -63,6 +63,8 @@ + #ifndef __ICP_CAN_USER_H__ + #define __ICP_CAN_USER_H__ + ++#include <linux/ioctl.h> ++ + /***************************************************************************** + * Device IO control codes. + *****************************************************************************/ diff --git a/package/ep80579-drivers/patches/210-can_include_linux_fs_h.patch b/package/ep80579-drivers/patches/210-can_include_linux_fs_h.patch new file mode 100644 index 0000000000..26c53dcea4 --- /dev/null +++ b/package/ep80579-drivers/patches/210-can_include_linux_fs_h.patch @@ -0,0 +1,11 @@ +--- a/Embedded/src/CAN/can_main.c ++++ b/Embedded/src/CAN/can_main.c +@@ -70,6 +70,8 @@ +
+ #include "can_main.h"
+ #include "can_ioctl.h"
++#include <linux/fs.h> ++ +
+ MODULE_AUTHOR("Intel(R) Corporation");
+ MODULE_DESCRIPTION("Controller Area Network Driver");
diff --git a/package/ep80579-drivers/patches/220-can_fix_irq_request.patch b/package/ep80579-drivers/patches/220-can_fix_irq_request.patch new file mode 100644 index 0000000000..2950cc79e5 --- /dev/null +++ b/package/ep80579-drivers/patches/220-can_fix_irq_request.patch @@ -0,0 +1,23 @@ +--- a/Embedded/src/CAN/can_main.c ++++ b/Embedded/src/CAN/can_main.c +@@ -654,7 +654,7 @@ int can_dev_io(struct inode *inode, stru + /*****************************************************************************
+ * Interrupt handler.
+ *****************************************************************************/
+-irqreturn_t can_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t can_irq_handler(int irq, void *dev_id)
+ {
+ can_os_t *can_os = (can_os_t *) dev_id;
+ unsigned int int_status;
+--- a/Embedded/src/CAN/can_main.h ++++ b/Embedded/src/CAN/can_main.h +@@ -165,8 +165,7 @@ int can_dev_io( + + irqreturn_t can_irq_handler( + int irq, +- void *dev_id, +- struct pt_regs *regs); ++ void *dev_id); + + void can_tasklet( + unsigned long arg diff --git a/package/ep80579-drivers/patches/230-can_remove_driver_data_direct_access.patch b/package/ep80579-drivers/patches/230-can_remove_driver_data_direct_access.patch new file mode 100644 index 0000000000..57e9c8fc05 --- /dev/null +++ b/package/ep80579-drivers/patches/230-can_remove_driver_data_direct_access.patch @@ -0,0 +1,41 @@ +diff -Nur a/Embedded/src/CAN/can_main.c b/Embedded/src/CAN/can_main.c +--- a/Embedded/src/CAN/can_main.c 2009-11-30 10:44:39.044269751 +0100 ++++ b/Embedded/src/CAN/can_main.c 2009-11-30 10:54:41.434355642 +0100 +@@ -213,8 +213,8 @@ + spin_lock_init(&(g_can_os[can_num].int_spinlock));
+ spin_lock_init(&(g_can_os[can_num].open_spinlock));
+
+- dev->dev.driver_data = (void *) &(g_can_os[can_num]);
+- if (!dev->dev.driver_data)
++ dev_set_drvdata(&dev->dev, (void *) &(g_can_os[can_num]));
++ if (!dev_get_drvdata(&dev->dev))
+ {
+ printk("Couldn't create CAN device %d. Exiting.\n",
+ dev->device);
+@@ -236,7 +236,7 @@ + *****************************************************************************/
+ void can_pci_remove(struct pci_dev *dev)
+ {
+- can_os_t *can_os = dev->dev.driver_data;
++ can_os_t *can_os = dev_get_drvdata(&dev->dev);
+
+ iounmap(can_os->pci_remap);
+ icp_can_destroy(can_os->can);
+@@ -250,7 +250,7 @@ + {
+ unsigned int i;
+ unsigned int int_status;
+- can_os_t *can_os = dev->dev.driver_data;
++ can_os_t *can_os = dev_get_drvdata(&dev->dev);
+ int err;
+
+ /* Indicate that we are suspending */
+@@ -321,7 +321,7 @@ + int can_pci_resume(struct pci_dev *dev)
+ {
+ unsigned int i;
+- can_os_t *can_os = dev->dev.driver_data;
++ can_os_t *can_os = dev_get_drvdata(&dev->dev);
+
+ /* Restore PCI CFG space */
+ pci_restore_state(dev);
diff --git a/package/ep80579-drivers/patches/300-wdt_compile_fix.patch b/package/ep80579-drivers/patches/300-wdt_compile_fix.patch new file mode 100644 index 0000000000..59242b80b3 --- /dev/null +++ b/package/ep80579-drivers/patches/300-wdt_compile_fix.patch @@ -0,0 +1,59 @@ +--- a/Embedded/src/WDT/iwdt.c ++++ b/Embedded/src/WDT/iwdt.c +@@ -180,19 +180,19 @@ MODULE_PARM_DESC(wdt_scale, "Intel WDT s + module_param(wdt_intr_type, byte, WDT_INT_TYPE_IRQ); + MODULE_PARM_DESC(wdt_intr_type, "Intel WDT interrupt type (default SERIRQ)."); + +-module_param(wdt_margin1, uint, TIMER_MARGIN); ++module_param(wdt_margin1, uint, 0); + MODULE_PARM_DESC(wdt_margin1, "First stage Intel WDT timeout in steps of 1 ms by default."); + +-module_param(wdt_margin2, uint, TIMER_MARGIN); ++module_param(wdt_margin2, uint, 0); + MODULE_PARM_DESC(wdt_margin2, "Second stage Intel WDT timeout in steps of 1 ms by default."); + + module_param(nowayout, int, 0); + MODULE_PARM_DESC(nowayout, "Intel WDT can't be stopped once started (default=0)"); + +-module_param(wdt_index_port, int, 0x4E); ++module_param(wdt_index_port, int, 0); + MODULE_PARM_DESC(wdt_index_port, "WDT Index Port (default 0x4e)"); + +-module_param(wdt_data_port, int, 0x4E); ++module_param(wdt_data_port, int, 0); + MODULE_PARM_DESC(wdt_data_port, "WDT Data Port (default 0x4f)"); + + static int wdt_get_iobase(struct pci_dev *dev, u16 *iobase, int *irq); +@@ -218,7 +218,7 @@ static ssize_t wdt_write(struct file *fi + size_t count, loff_t * pos); + static int wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +-static irqreturn_t wdt_isr(int irq, void *dev_id, struct pt_regs *regs); ++static irqreturn_t wdt_isr(int irq, void *dev_id); + static void __exit wdt_cleanup(void); + static int __init wdt_init(void); + static int __init wdt_init_one(struct pci_dev *dev, +@@ -255,7 +255,7 @@ static struct pci_driver wdt_driver = { + name: "iwdt", + id_table: lpc_pci_tbl, + probe: wdt_init_one, +- remove: __devexit(wdt_remove_one), ++ remove: __devexit_p(wdt_remove_one), + suspend: wdt_pci_suspend, + resume: wdt_pci_resume, + }; +@@ -1393,12 +1393,12 @@ static int wdt_ioctl(struct inode *inode + + /* + * Function Name: wdt_isr() +- * Parameter: int irq - irq number, void *dev_id, struct pt_regs *regs ++ * Parameter: int irq - irq number, void *dev_id + * Return Value:: IRQ_NONE - if the interrupt is not for wdt. + * IRQ_HANDLED - if it is for wdt. + * Description: This is the interrupt service routine of the WDT. + */ +-static irqreturn_t wdt_isr(int irq, void *dev_id, struct pt_regs *regs) ++static irqreturn_t wdt_isr(int irq, void *dev_id) + { + u8 val; + diff --git a/package/ep80579-drivers/patches/400-edma_fix_irq_request_warning.patch b/package/ep80579-drivers/patches/400-edma_fix_irq_request_warning.patch new file mode 100644 index 0000000000..d858aff1ff --- /dev/null +++ b/package/ep80579-drivers/patches/400-edma_fix_irq_request_warning.patch @@ -0,0 +1,22 @@ +--- a/Embedded/src/EDMA/dma_linux.c ++++ b/Embedded/src/EDMA/dma_linux.c +@@ -149,8 +149,7 @@ int32_t edma_suspend (struct pci_dev *de + int32_t edma_resume(struct pci_dev *dev); + int32_t initialize_edma_device(struct edma_device *device); + +-static irqreturn_t edma_irq_handler(int32_t irq, void * dev_id, +- struct pt_regs * regs); ++static irqreturn_t edma_irq_handler(int32_t irq, void * dev_id); + + /* Prototypes - Misc. */ + +@@ -429,8 +428,7 @@ int32_t edma_release(struct inode * inod + * Return Values: HANDLED = 1, NOT_HANDLED = 0 + *****************************************************************************/ + +-static irqreturn_t edma_irq_handler(int32_t irq, void * dev_id, +- struct pt_regs * regs) ++static irqreturn_t edma_irq_handler(int32_t irq, void * dev_id) + { + + uint32_t clear_bits; diff --git a/package/ep80579-drivers/patches/500-1588_fix_irq_request_warning.patch b/package/ep80579-drivers/patches/500-1588_fix_irq_request_warning.patch new file mode 100644 index 0000000000..f3f9acb1e0 --- /dev/null +++ b/package/ep80579-drivers/patches/500-1588_fix_irq_request_warning.patch @@ -0,0 +1,22 @@ +--- a/Embedded/src/1588/1588.c ++++ b/Embedded/src/1588/1588.c +@@ -631,7 +631,7 @@ int restore_interrupts(void) + IRQ_NONE => this device did not interrupt + + ******************************************************************************/ +-irqreturn_t timesync_isr(int irq, void *dev_id, struct pt_regs *regs) ++irqreturn_t timesync_isr(int irq, void *dev_id) + { + if ( !ixTimeSyncAccEventAmmsFlagGet() && !ixTimeSyncAccEventAsmsFlagGet()&& + !ixTimeSyncAccEventAtmFlagGet() && !ixTimeSyncAccEventPpsmFlagGet()&& +--- a/Embedded/src/1588/1588.h ++++ b/Embedded/src/1588/1588.h +@@ -128,7 +128,7 @@ int pci_suspend(struct pci_dev *dev, pm_ + int pci_resume(struct pci_dev *dev);
+ int pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+ void pci_remove(struct pci_dev *dev);
+-irqreturn_t timesync_isr(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t timesync_isr(int irq, void *dev_id);
+
+ // private functions
+ int save_reg_state(void);
diff --git a/package/ep80579-drivers/patches/600-2.6.27_includes.patch b/package/ep80579-drivers/patches/600-2.6.27_includes.patch new file mode 100644 index 0000000000..c11275ece6 --- /dev/null +++ b/package/ep80579-drivers/patches/600-2.6.27_includes.patch @@ -0,0 +1,22 @@ +--- a/Embedded/src/CAN/can_main.h ++++ b/Embedded/src/CAN/can_main.h +@@ -65,7 +65,7 @@ + + #include <linux/interrupt.h> + #include <linux/pci.h> +-#include <asm/semaphore.h> ++#include <linux/semaphore.h> + #include <linux/spinlock.h> + #include <linux/cdev.h> + #include <asm/uaccess.h> +--- a/Embedded/src/EDMA/dma_linux.c ++++ b/Embedded/src/EDMA/dma_linux.c +@@ -87,7 +87,7 @@ + #include <linux/fcntl.h> /* O_ACCMODE */ + #include <asm/system.h> /* cli, *_flags */ + #include <asm/uaccess.h> /* copy_to_user */ +-#include <asm/semaphore.h> ++#include <linux/semaphore.h> + #include <asm/io.h> /* inb(), outb() */ + #include <linux/kmod.h> + #include <linux/ioport.h> /* request_region */ diff --git a/package/ep80579-drivers/patches/601-2.6.32_includes.patch b/package/ep80579-drivers/patches/601-2.6.32_includes.patch new file mode 100644 index 0000000000..680bbf11ba --- /dev/null +++ b/package/ep80579-drivers/patches/601-2.6.32_includes.patch @@ -0,0 +1,33 @@ +diff -Nur a/Embedded/src/1588/1588.c b/Embedded/src/1588/1588.c +--- a/Embedded/src/1588/1588.c 2009-11-10 14:20:46.563322192 +0100 ++++ b/Embedded/src/1588/1588.c 2009-11-30 10:44:22.144270452 +0100 +@@ -72,6 +72,7 @@ + * + ****************************************************************************/ + ++#include <linux/sched.h> + #include "1588.h" + + MODULE_AUTHOR("Intel(R) Corporation"); +diff -Nur a/Embedded/src/CAN/can_main.c b/Embedded/src/CAN/can_main.c +--- a/Embedded/src/CAN/can_main.c 2009-11-10 14:20:46.563322192 +0100 ++++ b/Embedded/src/CAN/can_main.c 2009-11-30 10:44:39.044269751 +0100 +@@ -68,6 +68,7 @@ + *
+ **************************************************************************/
+
++#include <linux/sched.h> + #include "can_main.h"
+ #include "can_ioctl.h"
+
+diff -Nur a/Embedded/src/WDT/iwdt.c b/Embedded/src/WDT/iwdt.c +--- a/Embedded/src/WDT/iwdt.c 2009-11-10 14:20:46.563322192 +0100 ++++ b/Embedded/src/WDT/iwdt.c 2009-11-30 10:44:54.024262744 +0100 +@@ -137,6 +137,7 @@ + #include <linux/watchdog.h> + #include <linux/miscdevice.h> + #include <linux/interrupt.h> ++#include <linux/sched.h> + #include "iwdt.h" + + MODULE_AUTHOR("Intel(R) Corporation"); diff --git a/package/ep80579-drivers/patches/700-iegbe_kcompat_2.6.30.patch b/package/ep80579-drivers/patches/700-iegbe_kcompat_2.6.30.patch new file mode 100644 index 0000000000..ca8c1bb9ea --- /dev/null +++ b/package/ep80579-drivers/patches/700-iegbe_kcompat_2.6.30.patch @@ -0,0 +1,31 @@ +--- a/Embedded/src/GbE/kcompat.h ++++ b/Embedded/src/GbE/kcompat.h +@@ -46,12 +46,6 @@ GPL LICENSE SUMMARY + #include <linux/sched.h> + #include <asm/io.h> + +-#ifndef IRQ_HANDLED +-#define irqreturn_t void +-#define IRQ_HANDLED +-#define IRQ_NONE +-#endif +- + #ifndef SET_NETDEV_DEV + #define SET_NETDEV_DEV(net, pdev) + #endif +@@ -748,6 +742,15 @@ extern void dump_stack(void); + + #endif /* 2.4.24 */ + ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) ) ++#ifndef IRQ_HANDLED ++#define irqreturn_t void ++#define IRQ_HANDLED ++#define IRQ_NONE ++#endif ++#endif /* < 2.6.30 */ ++ + #endif /* _KCOMPAT_H_ */ + + diff --git a/package/ep80579-drivers/patches/701-iegbe_poll_dev.patch b/package/ep80579-drivers/patches/701-iegbe_poll_dev.patch new file mode 100644 index 0000000000..63a1326853 --- /dev/null +++ b/package/ep80579-drivers/patches/701-iegbe_poll_dev.patch @@ -0,0 +1,11 @@ +--- a/Embedded/src/GbE/iegbe_main.c ++++ b/Embedded/src/GbE/iegbe_main.c +@@ -3534,7 +3534,7 @@ static int iegbe_clean(struct napi_struc + int tx_cleaned = 0, work_done = 0; + + /* Must NOT use netdev_priv macro here. */ +- adapter = poll_dev->priv; ++ adapter = netdev_priv(poll_dev); + + /* iegbe_clean is called per-cpu. This lock protects + * tx_ring[0] from being cleaned by multiple cpus diff --git a/target/linux/generic-2.6/config-2.6.32 b/target/linux/generic-2.6/config-2.6.32 index a9c4bfb824..b869c9ae97 100644 --- a/target/linux/generic-2.6/config-2.6.32 +++ b/target/linux/generic-2.6/config-2.6.32 @@ -550,6 +550,7 @@ CONFIG_EXPERIMENTAL=y # CONFIG_EXT4_DEBUG is not set # CONFIG_EXT4DEV_FS is not set # CONFIG_EXT4_FS is not set +# CONFIG_EXT4_FS_XATTR is not set CONFIG_EXTRA_FIRMWARE="" CONFIG_EXTRA_TARGETS="" # CONFIG_EZX_PCAP is not set diff --git a/target/linux/x86/Makefile b/target/linux/x86/Makefile index cd7c1b5c01..4cf011af78 100644 --- a/target/linux/x86/Makefile +++ b/target/linux/x86/Makefile @@ -10,7 +10,7 @@ ARCH:=i386 BOARD:=x86 BOARDNAME:=x86 FEATURES:=squashfs jffs2 ext2 vdi vmdk pcmcia tgz -SUBTARGETS=generic olpc xen_domu +SUBTARGETS=generic olpc xen_domu ep80579 LINUX_VERSION:=2.6.32.10 diff --git a/target/linux/x86/ep80579/config-default b/target/linux/x86/ep80579/config-default new file mode 100644 index 0000000000..2a89b4fe6f --- /dev/null +++ b/target/linux/x86/ep80579/config-default @@ -0,0 +1,12 @@ +CONFIG_ATA=y +CONFIG_BLK_DEV_SD=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHPTE is not set +# CONFIG_MTD is not set +# CONFIG_NOHIGHMEM is not set +CONFIG_SATA_AHCI=y +# CONFIG_SQUASHFS is not set +CONFIG_ITCO_WDT=y +# CONFIG_ITCO_VENDOR_SUPPORT is not set +CONFIG_LOG_BUF_SHIFT=17 diff --git a/target/linux/x86/ep80579/target.mk b/target/linux/x86/ep80579/target.mk new file mode 100644 index 0000000000..00fe1abc3d --- /dev/null +++ b/target/linux/x86/ep80579/target.mk @@ -0,0 +1,9 @@ +BOARDNAME:=Intel EP80579 +DEFAULT_PACKAGES += kmod-ep80579-can kmod-ep80579-eth kmod-ep80579-misc \ + kmod-usb-core kmod-usb2 kmod-usb-hid kmod-usb-uhci + +define Target/Description + Build firmware images for Intel EP80579 based boards + (e.g : ADI Engineering Ocracoke Island) +endef + |