From eae01a254d659e02b25533ef99c601eee0a56fe3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=2E=C3=87a=C4=9Flar=20Onur?= Date: Tue, 9 Feb 2010 20:58:17 +0000 Subject: [PATCH] revert back to .14 --- delta-ptrace-fix01.diff | 11 +- kernel-2.6.spec | 17 +- linux-2.6-010-e1000e.patch | 26683 + linux-2.6-020-build-id.patch | 215 + linux-2.6-030-netns.patch | 707332 ++++++++++++++++ linux-2.6-040-i_mutex-check.patch | 19 + linux-2.6-050-getline.patch | 31 + linux-2.6-100-build-nonintconfig.patch | 160 +- linux-2.6-210-vserver-cpu-sched.patch | 94 + linux-2.6-510-ipod.patch | 79 +- linux-2.6-521-packet-tagging.patch | 49 +- linux-2.6-525-sknid-elevator.patch | 57 +- linux-2.6-540-oom-kill.patch | 98 +- linux-2.6-620-kdb.patch | 53878 ++ linux-2.6-630-sched-fix.patch | 45 + linux-2.6-670-gcc43.patch | 14 + linux-2.6-680-htb-hysteresis-tso.patch | 83 +- linux-2.6-700-egre.patch | 12 + linux-2.6-710-avoid-64bits-addr-pcmcia.patch | 29 +- planetlab-2.6.27-i686.config | 5 +- planetlab-2.6.27-x86_64.config | 4 +- sources | 4 +- wextoolbox-2.6.27-i686.config | 4 +- wextoolbox-2.6.27-x86_64.config | 4 +- 24 files changed, 788651 insertions(+), 276 deletions(-) create mode 100644 linux-2.6-010-e1000e.patch create mode 100644 linux-2.6-020-build-id.patch create mode 100644 linux-2.6-030-netns.patch create mode 100644 linux-2.6-040-i_mutex-check.patch create mode 100644 linux-2.6-050-getline.patch create mode 100644 linux-2.6-210-vserver-cpu-sched.patch create mode 100644 linux-2.6-620-kdb.patch create mode 100644 linux-2.6-630-sched-fix.patch create mode 100644 linux-2.6-670-gcc43.patch diff --git a/delta-ptrace-fix01.diff b/delta-ptrace-fix01.diff index de0a81b3a..86545bc12 100644 --- a/delta-ptrace-fix01.diff +++ b/delta-ptrace-fix01.diff @@ -1,9 +1,8 @@ -Index: linux-2.6.27.y/kernel/ptrace.c -=================================================================== ---- linux-2.6.27.y.orig/kernel/ptrace.c -+++ linux-2.6.27.y/kernel/ptrace.c -@@ -140,7 +140,7 @@ int __ptrace_may_access(struct task_stru - dumpable = get_dumpable(task->mm); +diff -Nurp linux-2.6.22.19-vs2.3.0.34.8/kernel/ptrace.c linux-2.6.22.19-vs2.3.0.34.9/kernel/ptrace.c +--- linux-2.6.22.19-vs2.3.0.34.8/kernel/ptrace.c 2008-03-15 08:16:10.000000000 -0400 ++++ linux-2.6.22.19-vs2.3.0.34.9/kernel/ptrace.c 2008-07-23 12:32:11.000000000 -0400 +@@ -146,7 +146,7 @@ static int may_attach(struct task_struct + dumpable = task->mm->dumpable; if (!dumpable && !capable(CAP_SYS_PTRACE)) return -EPERM; - if (!vx_check(task->xid, VS_ADMIN_P|VS_IDENT)) diff --git a/kernel-2.6.spec b/kernel-2.6.spec index 9cde68950..bf9b324b8 100644 --- a/kernel-2.6.spec +++ b/kernel-2.6.spec @@ -30,11 +30,11 @@ Summary: The Linux kernel (the core of the Linux operating system) # adding some text to the end of the version number. # %define sublevel 27 -%define patchlevel 45 +%define patchlevel 14 %define kversion 2.6.%{sublevel} %define rpmversion 2.6.%{sublevel}%{?patchlevel:.%{patchlevel}} -%define vsversion 2.3.0.36.8 +%define vsversion 2.3.0.36.4 # Will go away when VServer supports NetNS in mainline. Currently, it must be # updated every time the PL kernel is updated. @@ -139,12 +139,10 @@ Source30: %{pldistro}-%{kversion}-i686-xenU.config %if "0%{patchlevel}" Patch000: ftp://ftp.kernel.org/pub/linux/kernel/v2.6/patch-%{rpmversion}.bz2 %endif - -Patch100: linux-2.6-100-build-nonintconfig.patch +Patch050: linux-2.6-050-getline.patch # Linux-VServer -Patch200: patch-2.6.27.39-vs%{vsversion}.diff -Patch220: delta-ptrace-fix01.diff +Patch200: patch-%{rpmversion}-vs%{vsversion}.diff # IP sets Patch250: linux-2.6-250-ipsets.patch @@ -171,7 +169,7 @@ Patch591: linux-2.6-591-chopstix-intern.patch Patch640: linux-2.6-640-netlink-audit-hack.patch Patch650: linux-2.6-650-hangcheck-reboot.patch Patch660: linux-2.6-660-nmi-watchdog-default.patch -Patch680: linux-2.6-680-htb-hysteresis-tso.patch +# Patch680: linux-2.6-680-htb-hysteresis-tso.patch # Patch690: linux-2.6-690-web100.patch Patch700: linux-2.6-700-egre.patch Patch710: linux-2.6-710-avoid-64bits-addr-pcmcia.patch @@ -336,7 +334,7 @@ KERNEL_PREVIOUS=vanilla %ApplyPatch 0 %endif -%ApplyPatch 100 +%ApplyPatch 50 # vserver patch %ApplyPatch 200 @@ -365,7 +363,6 @@ KERNEL_PREVIOUS=vanilla %ApplyPatch 640 %ApplyPatch 650 %ApplyPatch 660 -%ApplyPatch 680 %ApplyPatch 700 %ApplyPatch 710 @@ -431,7 +428,7 @@ BuildKernel() { #Arch=`head -1 .config | cut -b 3-` echo USING ARCH=$Arch - make -s ARCH=$Arch nonint_oldconfig < /dev/null > /dev/null + make -s ARCH=$Arch oldconfig < /dev/null > /dev/null make -s ARCH=$Arch %{?_smp_mflags} $MakeTarget make -s ARCH=$Arch %{?_smp_mflags} modules || exit 1 %if %{headers} diff --git a/linux-2.6-010-e1000e.patch b/linux-2.6-010-e1000e.patch new file mode 100644 index 000000000..b5e3baedd --- /dev/null +++ b/linux-2.6-010-e1000e.patch @@ -0,0 +1,26683 @@ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_80003es2lan.c linux-2.6.22-10/drivers/net/e1000e/e1000_80003es2lan.c +--- linux-2.6.22-0/drivers/net/e1000e/e1000_80003es2lan.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_80003es2lan.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,1545 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++/* e1000_80003es2lan ++ */ ++ ++#include "e1000_hw.h" ++ ++static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_acquire_mac_csr_80003es2lan(struct e1000_hw *hw); ++static void e1000_release_phy_80003es2lan(struct e1000_hw *hw); ++static void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw); ++static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, ++ u32 offset, ++ u16 *data); ++static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, ++ u32 offset, ++ u16 data); ++static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset, ++ u16 words, u16 *data); ++static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed, ++ u16 *duplex); ++static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw); ++static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); ++static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex); ++static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw); ++static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 *data); ++static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 data); ++static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw); ++static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw); ++static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); ++static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw); ++static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw); ++ ++/* ++ * A table for the GG82563 cable length where the range is defined ++ * with a lower bound at "index" and the upper bound at ++ * "index + 5". ++ */ ++static const u16 e1000_gg82563_cable_length_table[] = ++ { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF }; ++#define GG82563_CABLE_LENGTH_TABLE_SIZE \ ++ (sizeof(e1000_gg82563_cable_length_table) / \ ++ sizeof(e1000_gg82563_cable_length_table[0])) ++ ++/** ++ * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs. ++ * @hw: pointer to the HW structure ++ * ++ * This is a function pointer entry point called by the api module. ++ **/ ++static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_init_phy_params_80003es2lan"); ++ ++ if (hw->phy.media_type != e1000_media_type_copper) { ++ phy->type = e1000_phy_none; ++ goto out; ++ } else { ++ phy->ops.power_up = e1000_power_up_phy_copper; ++ phy->ops.power_down = e1000_power_down_phy_copper_80003es2lan; ++ } ++ ++ phy->addr = 1; ++ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; ++ phy->reset_delay_us = 100; ++ phy->type = e1000_phy_gg82563; ++ ++ phy->ops.acquire = e1000_acquire_phy_80003es2lan; ++ phy->ops.check_polarity = e1000_check_polarity_m88; ++ phy->ops.check_reset_block = e1000_check_reset_block_generic; ++ phy->ops.commit = e1000_phy_sw_reset_generic; ++ phy->ops.get_cfg_done = e1000_get_cfg_done_80003es2lan; ++ phy->ops.get_info = e1000_get_phy_info_m88; ++ phy->ops.release = e1000_release_phy_80003es2lan; ++ phy->ops.reset = e1000_phy_hw_reset_generic; ++ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic; ++ ++ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan; ++ phy->ops.get_cable_length = e1000_get_cable_length_80003es2lan; ++ phy->ops.read_reg = e1000_read_phy_reg_gg82563_80003es2lan; ++ phy->ops.write_reg = e1000_write_phy_reg_gg82563_80003es2lan; ++ ++ phy->ops.cfg_on_link_up = e1000_cfg_on_link_up_80003es2lan; ++ ++ /* This can only be done after all function pointers are setup. */ ++ ret_val = e1000_get_phy_id(hw); ++ ++ /* Verify phy id */ ++ if (phy->id != GG82563_E_PHY_ID) { ++ ret_val = -E1000_ERR_PHY; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs. ++ * @hw: pointer to the HW structure ++ * ++ * This is a function pointer entry point called by the api module. ++ **/ ++static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ u32 eecd = E1000_READ_REG(hw, E1000_EECD); ++ u16 size; ++ ++ DEBUGFUNC("e1000_init_nvm_params_80003es2lan"); ++ ++ nvm->opcode_bits = 8; ++ nvm->delay_usec = 1; ++ switch (nvm->override) { ++ case e1000_nvm_override_spi_large: ++ nvm->page_size = 32; ++ nvm->address_bits = 16; ++ break; ++ case e1000_nvm_override_spi_small: ++ nvm->page_size = 8; ++ nvm->address_bits = 8; ++ break; ++ default: ++ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; ++ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; ++ break; ++ } ++ ++ nvm->type = e1000_nvm_eeprom_spi; ++ ++ size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> ++ E1000_EECD_SIZE_EX_SHIFT); ++ ++ /* ++ * Added to a constant, "size" becomes the left-shift value ++ * for setting word_size. ++ */ ++ size += NVM_WORD_SIZE_BASE_SHIFT; ++ ++ /* EEPROM access above 16k is unsupported */ ++ if (size > 14) ++ size = 14; ++ nvm->word_size = 1 << size; ++ ++ /* Function Pointers */ ++ nvm->ops.acquire = e1000_acquire_nvm_80003es2lan; ++ nvm->ops.read = e1000_read_nvm_eerd; ++ nvm->ops.release = e1000_release_nvm_80003es2lan; ++ nvm->ops.update = e1000_update_nvm_checksum_generic; ++ nvm->ops.valid_led_default = e1000_valid_led_default_generic; ++ nvm->ops.validate = e1000_validate_nvm_checksum_generic; ++ nvm->ops.write = e1000_write_nvm_80003es2lan; ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs. ++ * @hw: pointer to the HW structure ++ * ++ * This is a function pointer entry point called by the api module. ++ **/ ++static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_init_mac_params_80003es2lan"); ++ ++ /* Set media type */ ++ switch (hw->device_id) { ++ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: ++ hw->phy.media_type = e1000_media_type_internal_serdes; ++ break; ++ default: ++ hw->phy.media_type = e1000_media_type_copper; ++ break; ++ } ++ ++ /* Set mta register count */ ++ mac->mta_reg_count = 128; ++ /* Set rar entry count */ ++ mac->rar_entry_count = E1000_RAR_ENTRIES; ++ /* Set if part includes ASF firmware */ ++ mac->asf_firmware_present = true; ++ /* Set if manageability features are enabled. */ ++ mac->arc_subsystem_valid = ++ (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK) ++ ? true : false; ++ ++ /* Function pointers */ ++ ++ /* bus type/speed/width */ ++ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic; ++ /* reset */ ++ mac->ops.reset_hw = e1000_reset_hw_80003es2lan; ++ /* hw initialization */ ++ mac->ops.init_hw = e1000_init_hw_80003es2lan; ++ /* link setup */ ++ mac->ops.setup_link = e1000_setup_link_generic; ++ /* physical interface link setup */ ++ mac->ops.setup_physical_interface = ++ (hw->phy.media_type == e1000_media_type_copper) ++ ? e1000_setup_copper_link_80003es2lan ++ : e1000_setup_fiber_serdes_link_generic; ++ /* check for link */ ++ switch (hw->phy.media_type) { ++ case e1000_media_type_copper: ++ mac->ops.check_for_link = e1000_check_for_copper_link_generic; ++ break; ++ case e1000_media_type_fiber: ++ mac->ops.check_for_link = e1000_check_for_fiber_link_generic; ++ break; ++ case e1000_media_type_internal_serdes: ++ mac->ops.check_for_link = e1000_check_for_serdes_link_generic; ++ break; ++ default: ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ break; ++ } ++ /* check management mode */ ++ mac->ops.check_mng_mode = e1000_check_mng_mode_generic; ++ /* multicast address update */ ++ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; ++ /* writing VFTA */ ++ mac->ops.write_vfta = e1000_write_vfta_generic; ++ /* clearing VFTA */ ++ mac->ops.clear_vfta = e1000_clear_vfta_generic; ++ /* setting MTA */ ++ mac->ops.mta_set = e1000_mta_set_generic; ++ /* read mac address */ ++ mac->ops.read_mac_addr = e1000_read_mac_addr_80003es2lan; ++ /* blink LED */ ++ mac->ops.blink_led = e1000_blink_led_generic; ++ /* setup LED */ ++ mac->ops.setup_led = e1000_setup_led_generic; ++ /* cleanup LED */ ++ mac->ops.cleanup_led = e1000_cleanup_led_generic; ++ /* turn on/off LED */ ++ mac->ops.led_on = e1000_led_on_generic; ++ mac->ops.led_off = e1000_led_off_generic; ++ /* remove device */ ++ mac->ops.remove_device = e1000_remove_device_generic; ++ /* clear hardware counters */ ++ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan; ++ /* link info */ ++ mac->ops.get_link_up_info = e1000_get_link_up_info_80003es2lan; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_init_function_pointers_80003es2lan - Init ESB2 func ptrs. ++ * @hw: pointer to the HW structure ++ * ++ * The only function explicitly called by the api module to initialize ++ * all function pointers and parameters. ++ **/ ++void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw) ++{ ++ DEBUGFUNC("e1000_init_function_pointers_80003es2lan"); ++ ++ e1000_init_mac_ops_generic(hw); ++ e1000_init_nvm_ops_generic(hw); ++ hw->mac.ops.init_params = e1000_init_mac_params_80003es2lan; ++ hw->nvm.ops.init_params = e1000_init_nvm_params_80003es2lan; ++ hw->phy.ops.init_params = e1000_init_phy_params_80003es2lan; ++ e1000_get_bus_info_pcie_generic(hw); ++} ++ ++/** ++ * e1000_acquire_phy_80003es2lan - Acquire rights to access PHY ++ * @hw: pointer to the HW structure ++ * ++ * A wrapper to acquire access rights to the correct PHY. This is a ++ * function pointer entry point called by the api module. ++ **/ ++static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw) ++{ ++ u16 mask; ++ ++ DEBUGFUNC("e1000_acquire_phy_80003es2lan"); ++ ++ mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; ++ return e1000_acquire_swfw_sync_80003es2lan(hw, mask); ++} ++ ++/** ++ * e1000_release_phy_80003es2lan - Release rights to access PHY ++ * @hw: pointer to the HW structure ++ * ++ * A wrapper to release access rights to the correct PHY. This is a ++ * function pointer entry point called by the api module. ++ **/ ++static void e1000_release_phy_80003es2lan(struct e1000_hw *hw) ++{ ++ u16 mask; ++ ++ DEBUGFUNC("e1000_release_phy_80003es2lan"); ++ ++ mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; ++ e1000_release_swfw_sync_80003es2lan(hw, mask); ++} ++ ++ ++/** ++ * e1000_acquire_mac_csr_80003es2lan - Acquire rights to access Kumeran register ++ * @hw: pointer to the HW structure ++ * ++ * Acquire the semaphore to access the Kumeran interface. ++ * ++ **/ ++static s32 e1000_acquire_mac_csr_80003es2lan(struct e1000_hw *hw) ++{ ++ u16 mask; ++ ++ DEBUGFUNC("e1000_acquire_mac_csr_80003es2lan"); ++ ++ mask = E1000_SWFW_CSR_SM; ++ ++ return e1000_acquire_swfw_sync_80003es2lan(hw, mask); ++} ++ ++/** ++ * e1000_release_mac_csr_80003es2lan - Release rights to access Kumeran Register ++ * @hw: pointer to the HW structure ++ * ++ * Release the semaphore used to access the Kumeran interface ++ **/ ++static void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw) ++{ ++ u16 mask; ++ ++ DEBUGFUNC("e1000_release_mac_csr_80003es2lan"); ++ ++ mask = E1000_SWFW_CSR_SM; ++ ++ e1000_release_swfw_sync_80003es2lan(hw, mask); ++} ++ ++/** ++ * e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM ++ * @hw: pointer to the HW structure ++ * ++ * Acquire the semaphore to access the EEPROM. This is a function ++ * pointer entry point called by the api module. ++ **/ ++static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw) ++{ ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_acquire_nvm_80003es2lan"); ++ ++ ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_acquire_nvm_generic(hw); ++ ++ if (ret_val) ++ e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_release_nvm_80003es2lan - Relinquish rights to access NVM ++ * @hw: pointer to the HW structure ++ * ++ * Release the semaphore used to access the EEPROM. This is a ++ * function pointer entry point called by the api module. ++ **/ ++static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw) ++{ ++ DEBUGFUNC("e1000_release_nvm_80003es2lan"); ++ ++ e1000_release_nvm_generic(hw); ++ e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); ++} ++ ++/** ++ * e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore ++ * @hw: pointer to the HW structure ++ * @mask: specifies which semaphore to acquire ++ * ++ * Acquire the SW/FW semaphore to access the PHY or NVM. The mask ++ * will also specify which port we're acquiring the lock for. ++ **/ ++static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) ++{ ++ u32 swfw_sync; ++ u32 swmask = mask; ++ u32 fwmask = mask << 16; ++ s32 ret_val = E1000_SUCCESS; ++ s32 i = 0, timeout = 50; ++ ++ DEBUGFUNC("e1000_acquire_swfw_sync_80003es2lan"); ++ ++ while (i < timeout) { ++ if (e1000_get_hw_semaphore_generic(hw)) { ++ ret_val = -E1000_ERR_SWFW_SYNC; ++ goto out; ++ } ++ ++ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); ++ if (!(swfw_sync & (fwmask | swmask))) ++ break; ++ ++ /* ++ * Firmware currently using resource (fwmask) ++ * or other software thread using resource (swmask) ++ */ ++ e1000_put_hw_semaphore_generic(hw); ++ msec_delay_irq(5); ++ i++; ++ } ++ ++ if (i == timeout) { ++ DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n"); ++ ret_val = -E1000_ERR_SWFW_SYNC; ++ goto out; ++ } ++ ++ swfw_sync |= swmask; ++ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); ++ ++ e1000_put_hw_semaphore_generic(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore ++ * @hw: pointer to the HW structure ++ * @mask: specifies which semaphore to acquire ++ * ++ * Release the SW/FW semaphore used to access the PHY or NVM. The mask ++ * will also specify which port we're releasing the lock for. ++ **/ ++static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) ++{ ++ u32 swfw_sync; ++ ++ DEBUGFUNC("e1000_release_swfw_sync_80003es2lan"); ++ ++ while (e1000_get_hw_semaphore_generic(hw) != E1000_SUCCESS); ++ /* Empty */ ++ ++ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); ++ swfw_sync &= ~mask; ++ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); ++ ++ e1000_put_hw_semaphore_generic(hw); ++} ++ ++/** ++ * e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register ++ * @hw: pointer to the HW structure ++ * @offset: offset of the register to read ++ * @data: pointer to the data returned from the operation ++ * ++ * Read the GG82563 PHY register. This is a function pointer entry ++ * point called by the api module. ++ **/ ++static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, ++ u32 offset, u16 *data) ++{ ++ s32 ret_val; ++ u32 page_select; ++ u16 temp; ++ ++ DEBUGFUNC("e1000_read_phy_reg_gg82563_80003es2lan"); ++ ++ ret_val = e1000_acquire_phy_80003es2lan(hw); ++ if (ret_val) ++ goto out; ++ ++ /* Select Configuration Page */ ++ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { ++ page_select = GG82563_PHY_PAGE_SELECT; ++ } else { ++ /* ++ * Use Alternative Page Select register to access ++ * registers 30 and 31 ++ */ ++ page_select = GG82563_PHY_PAGE_SELECT_ALT; ++ } ++ ++ temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); ++ ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp); ++ if (ret_val) { ++ e1000_release_phy_80003es2lan(hw); ++ goto out; ++ } ++ ++ /* ++ * The "ready" bit in the MDIC register may be incorrectly set ++ * before the device has completed the "Page Select" MDI ++ * transaction. So we wait 200us after each MDI command... ++ */ ++ usec_delay(200); ++ ++ /* ...and verify the command was successful. */ ++ ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); ++ ++ if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { ++ ret_val = -E1000_ERR_PHY; ++ e1000_release_phy_80003es2lan(hw); ++ goto out; ++ } ++ ++ usec_delay(200); ++ ++ ret_val = e1000_read_phy_reg_mdic(hw, ++ MAX_PHY_REG_ADDRESS & offset, ++ data); ++ ++ usec_delay(200); ++ e1000_release_phy_80003es2lan(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register ++ * @hw: pointer to the HW structure ++ * @offset: offset of the register to read ++ * @data: value to write to the register ++ * ++ * Write to the GG82563 PHY register. This is a function pointer entry ++ * point called by the api module. ++ **/ ++static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, ++ u32 offset, u16 data) ++{ ++ s32 ret_val; ++ u32 page_select; ++ u16 temp; ++ ++ DEBUGFUNC("e1000_write_phy_reg_gg82563_80003es2lan"); ++ ++ ret_val = e1000_acquire_phy_80003es2lan(hw); ++ if (ret_val) ++ goto out; ++ ++ /* Select Configuration Page */ ++ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { ++ page_select = GG82563_PHY_PAGE_SELECT; ++ } else { ++ /* ++ * Use Alternative Page Select register to access ++ * registers 30 and 31 ++ */ ++ page_select = GG82563_PHY_PAGE_SELECT_ALT; ++ } ++ ++ temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); ++ ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp); ++ if (ret_val) { ++ e1000_release_phy_80003es2lan(hw); ++ goto out; ++ } ++ ++ ++ /* ++ * The "ready" bit in the MDIC register may be incorrectly set ++ * before the device has completed the "Page Select" MDI ++ * transaction. So we wait 200us after each MDI command... ++ */ ++ usec_delay(200); ++ ++ /* ...and verify the command was successful. */ ++ ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); ++ ++ if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { ++ ret_val = -E1000_ERR_PHY; ++ e1000_release_phy_80003es2lan(hw); ++ goto out; ++ } ++ ++ usec_delay(200); ++ ++ ret_val = e1000_write_phy_reg_mdic(hw, ++ MAX_PHY_REG_ADDRESS & offset, ++ data); ++ ++ usec_delay(200); ++ e1000_release_phy_80003es2lan(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_nvm_80003es2lan - Write to ESB2 NVM ++ * @hw: pointer to the HW structure ++ * @offset: offset of the register to read ++ * @words: number of words to write ++ * @data: buffer of data to write to the NVM ++ * ++ * Write "words" of data to the ESB2 NVM. This is a function ++ * pointer entry point called by the api module. ++ **/ ++static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset, ++ u16 words, u16 *data) ++{ ++ DEBUGFUNC("e1000_write_nvm_80003es2lan"); ++ ++ return e1000_write_nvm_spi(hw, offset, words, data); ++} ++ ++/** ++ * e1000_get_cfg_done_80003es2lan - Wait for configuration to complete ++ * @hw: pointer to the HW structure ++ * ++ * Wait a specific amount of time for manageability processes to complete. ++ * This is a function pointer entry point called by the phy module. ++ **/ ++static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw) ++{ ++ s32 timeout = PHY_CFG_TIMEOUT; ++ s32 ret_val = E1000_SUCCESS; ++ u32 mask = E1000_NVM_CFG_DONE_PORT_0; ++ ++ DEBUGFUNC("e1000_get_cfg_done_80003es2lan"); ++ ++ if (hw->bus.func == 1) ++ mask = E1000_NVM_CFG_DONE_PORT_1; ++ ++ while (timeout) { ++ if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask) ++ break; ++ msec_delay(1); ++ timeout--; ++ } ++ if (!timeout) { ++ DEBUGOUT("MNG configuration cycle has not completed.\n"); ++ ret_val = -E1000_ERR_RESET; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex ++ * @hw: pointer to the HW structure ++ * ++ * Force the speed and duplex settings onto the PHY. This is a ++ * function pointer entry point called by the phy module. ++ **/ ++static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 phy_data; ++ bool link; ++ ++ DEBUGFUNC("e1000_phy_force_speed_duplex_80003es2lan"); ++ ++ if (!(hw->phy.ops.read_reg)) ++ goto out; ++ ++ /* ++ * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI ++ * forced whenever speed and duplex are forced. ++ */ ++ ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO; ++ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data); ++ if (ret_val) ++ goto out; ++ ++ DEBUGOUT1("GG82563 PSCR: %X\n", phy_data); ++ ++ ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ e1000_phy_force_speed_duplex_setup(hw, &phy_data); ++ ++ /* Reset the phy to commit changes. */ ++ phy_data |= MII_CR_RESET; ++ ++ ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_data); ++ if (ret_val) ++ goto out; ++ ++ usec_delay(1); ++ ++ if (hw->phy.autoneg_wait_to_complete) { ++ DEBUGOUT("Waiting for forced speed/duplex link " ++ "on GG82563 phy.\n"); ++ ++ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT, ++ 100000, &link); ++ if (ret_val) ++ goto out; ++ ++ if (!link) { ++ /* ++ * We didn't get link. ++ * Reset the DSP and cross our fingers. ++ */ ++ ret_val = e1000_phy_reset_dsp_generic(hw); ++ if (ret_val) ++ goto out; ++ } ++ ++ /* Try once more */ ++ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT, ++ 100000, &link); ++ if (ret_val) ++ goto out; ++ } ++ ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Resetting the phy means we need to verify the TX_CLK corresponds ++ * to the link speed. 10Mbps -> 2.5MHz, else 25MHz. ++ */ ++ phy_data &= ~GG82563_MSCR_TX_CLK_MASK; ++ if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED) ++ phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5; ++ else ++ phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25; ++ ++ /* ++ * In addition, we must re-enable CRS on Tx for both half and full ++ * duplex. ++ */ ++ phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; ++ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_cable_length_80003es2lan - Set approximate cable length ++ * @hw: pointer to the HW structure ++ * ++ * Find the approximate cable length as measured by the GG82563 PHY. ++ * This is a function pointer entry point called by the phy module. ++ **/ ++static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ u16 phy_data, index; ++ ++ DEBUGFUNC("e1000_get_cable_length_80003es2lan"); ++ ++ if (!(hw->phy.ops.read_reg)) ++ goto out; ++ ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_DSP_DISTANCE, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ index = phy_data & GG82563_DSPD_CABLE_LENGTH; ++ phy->min_cable_length = e1000_gg82563_cable_length_table[index]; ++ phy->max_cable_length = e1000_gg82563_cable_length_table[index+5]; ++ ++ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_link_up_info_80003es2lan - Report speed and duplex ++ * @hw: pointer to the HW structure ++ * @speed: pointer to speed buffer ++ * @duplex: pointer to duplex buffer ++ * ++ * Retrieve the current speed and duplex configuration. ++ * This is a function pointer entry point called by the api module. ++ **/ ++static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed, ++ u16 *duplex) ++{ ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_get_link_up_info_80003es2lan"); ++ ++ if (hw->phy.media_type == e1000_media_type_copper) { ++ ret_val = e1000_get_speed_and_duplex_copper_generic(hw, ++ speed, ++ duplex); ++ } else { ++ ret_val = e1000_get_speed_and_duplex_fiber_serdes_generic(hw, ++ speed, ++ duplex); ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_reset_hw_80003es2lan - Reset the ESB2 controller ++ * @hw: pointer to the HW structure ++ * ++ * Perform a global reset to the ESB2 controller. ++ * This is a function pointer entry point called by the api module. ++ **/ ++static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) ++{ ++ u32 ctrl, icr; ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_reset_hw_80003es2lan"); ++ ++ /* ++ * Prevent the PCI-E bus from sticking if there is no TLP connection ++ * on the last TLP read/write transaction when MAC is reset. ++ */ ++ ret_val = e1000_disable_pcie_master_generic(hw); ++ if (ret_val) { ++ DEBUGOUT("PCI-E Master disable polling has failed.\n"); ++ } ++ ++ DEBUGOUT("Masking off all interrupts\n"); ++ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); ++ ++ E1000_WRITE_REG(hw, E1000_RCTL, 0); ++ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); ++ E1000_WRITE_FLUSH(hw); ++ ++ msec_delay(10); ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ++ ret_val = e1000_acquire_phy_80003es2lan(hw); ++ DEBUGOUT("Issuing a global reset to MAC\n"); ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); ++ e1000_release_phy_80003es2lan(hw); ++ ++ ret_val = e1000_get_auto_rd_done_generic(hw); ++ if (ret_val) ++ /* We don't want to continue accessing MAC registers. */ ++ goto out; ++ ++ /* Clear any pending interrupt events. */ ++ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); ++ icr = E1000_READ_REG(hw, E1000_ICR); ++ ++ e1000_check_alt_mac_addr_generic(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_init_hw_80003es2lan - Initialize the ESB2 controller ++ * @hw: pointer to the HW structure ++ * ++ * Initialize the hw bits, LED, VFTA, MTA, link and hw counters. ++ * This is a function pointer entry point called by the api module. ++ **/ ++static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ u32 reg_data; ++ s32 ret_val; ++ u16 i; ++ ++ DEBUGFUNC("e1000_init_hw_80003es2lan"); ++ ++ e1000_initialize_hw_bits_80003es2lan(hw); ++ ++ /* Initialize identification LED */ ++ ret_val = e1000_id_led_init_generic(hw); ++ if (ret_val) { ++ DEBUGOUT("Error initializing identification LED\n"); ++ /* This is not fatal and we should not stop init due to this */ ++ } ++ ++ /* Disabling VLAN filtering */ ++ DEBUGOUT("Initializing the IEEE VLAN\n"); ++ mac->ops.clear_vfta(hw); ++ ++ /* Setup the receive address. */ ++ e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); ++ ++ /* Zero out the Multicast HASH table */ ++ DEBUGOUT("Zeroing the MTA\n"); ++ for (i = 0; i < mac->mta_reg_count; i++) ++ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); ++ ++ /* Setup link and flow control */ ++ ret_val = mac->ops.setup_link(hw); ++ ++ /* Set the transmit descriptor write-back policy */ ++ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0)); ++ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | ++ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; ++ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data); ++ ++ /* ...for both queues. */ ++ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1)); ++ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | ++ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; ++ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data); ++ ++ /* Enable retransmit on late collisions */ ++ reg_data = E1000_READ_REG(hw, E1000_TCTL); ++ reg_data |= E1000_TCTL_RTLC; ++ E1000_WRITE_REG(hw, E1000_TCTL, reg_data); ++ ++ /* Configure Gigabit Carry Extend Padding */ ++ reg_data = E1000_READ_REG(hw, E1000_TCTL_EXT); ++ reg_data &= ~E1000_TCTL_EXT_GCEX_MASK; ++ reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN; ++ E1000_WRITE_REG(hw, E1000_TCTL_EXT, reg_data); ++ ++ /* Configure Transmit Inter-Packet Gap */ ++ reg_data = E1000_READ_REG(hw, E1000_TIPG); ++ reg_data &= ~E1000_TIPG_IPGT_MASK; ++ reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; ++ E1000_WRITE_REG(hw, E1000_TIPG, reg_data); ++ ++ reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001); ++ reg_data &= ~0x00100000; ++ E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data); ++ ++ /* ++ * Clear all of the statistics registers (clear on read). It is ++ * important that we do this after we have tried to establish link ++ * because the symbol error count will increment wildly if there ++ * is no link. ++ */ ++ e1000_clear_hw_cntrs_80003es2lan(hw); ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2 ++ * @hw: pointer to the HW structure ++ * ++ * Initializes required hardware-dependent bits needed for normal operation. ++ **/ ++static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw) ++{ ++ u32 reg; ++ ++ DEBUGFUNC("e1000_initialize_hw_bits_80003es2lan"); ++ ++ if (hw->mac.disable_hw_init_bits) ++ goto out; ++ ++ /* Transmit Descriptor Control 0 */ ++ reg = E1000_READ_REG(hw, E1000_TXDCTL(0)); ++ reg |= (1 << 22); ++ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg); ++ ++ /* Transmit Descriptor Control 1 */ ++ reg = E1000_READ_REG(hw, E1000_TXDCTL(1)); ++ reg |= (1 << 22); ++ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg); ++ ++ /* Transmit Arbitration Control 0 */ ++ reg = E1000_READ_REG(hw, E1000_TARC(0)); ++ reg &= ~(0xF << 27); /* 30:27 */ ++ if (hw->phy.media_type != e1000_media_type_copper) ++ reg &= ~(1 << 20); ++ E1000_WRITE_REG(hw, E1000_TARC(0), reg); ++ ++ /* Transmit Arbitration Control 1 */ ++ reg = E1000_READ_REG(hw, E1000_TARC(1)); ++ if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR) ++ reg &= ~(1 << 28); ++ else ++ reg |= (1 << 28); ++ E1000_WRITE_REG(hw, E1000_TARC(1), reg); ++ ++out: ++ return; ++} ++ ++/** ++ * e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link ++ * @hw: pointer to the HW structure ++ * ++ * Setup some GG82563 PHY registers for obtaining link ++ **/ ++static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u32 ctrl_ext; ++ u16 data; ++ ++ DEBUGFUNC("e1000_copper_link_setup_gg82563_80003es2lan"); ++ ++ if (!phy->reset_disable) { ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data |= GG82563_MSCR_ASSERT_CRS_ON_TX; ++ /* Use 25MHz for both link down and 1000Base-T for Tx clock. */ ++ data |= GG82563_MSCR_TX_CLK_1000MBPS_25; ++ ++ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, ++ data); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Options: ++ * MDI/MDI-X = 0 (default) ++ * 0 - Auto for all speeds ++ * 1 - MDI mode ++ * 2 - MDI-X mode ++ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) ++ */ ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL, &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; ++ ++ switch (phy->mdix) { ++ case 1: ++ data |= GG82563_PSCR_CROSSOVER_MODE_MDI; ++ break; ++ case 2: ++ data |= GG82563_PSCR_CROSSOVER_MODE_MDIX; ++ break; ++ case 0: ++ default: ++ data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; ++ break; ++ } ++ ++ /* ++ * Options: ++ * disable_polarity_correction = 0 (default) ++ * Automatic Correction for Reversed Cable Polarity ++ * 0 - Disabled ++ * 1 - Enabled ++ */ ++ data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; ++ if (phy->disable_polarity_correction) ++ data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE; ++ ++ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, data); ++ if (ret_val) ++ goto out; ++ ++ /* SW Reset the PHY so all changes take effect */ ++ ret_val = hw->phy.ops.commit(hw); ++ if (ret_val) { ++ DEBUGOUT("Error Resetting the PHY\n"); ++ goto out; ++ } ++ ++ } ++ ++ /* Bypass Rx and Tx FIFO's */ ++ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, ++ E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL, ++ E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS | ++ E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS); ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_read_kmrn_reg_80003es2lan(hw, ++ E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, ++ &data); ++ if (ret_val) ++ goto out; ++ data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE; ++ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, ++ E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, ++ data); ++ if (ret_val) ++ goto out; ++ ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL_2, &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG; ++ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL_2, data); ++ if (ret_val) ++ goto out; ++ ++ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); ++ ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK); ++ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); ++ ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, &data); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Do not init these registers when the HW is in IAMT mode, since the ++ * firmware will have already initialized them. We only initialize ++ * them if the HW is not in IAMT mode. ++ */ ++ if (!(hw->mac.ops.check_mng_mode(hw))) { ++ /* Enable Electrical Idle on the PHY */ ++ data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; ++ ret_val = hw->phy.ops.write_reg(hw, ++ GG82563_PHY_PWR_MGMT_CTRL, ++ data); ++ if (ret_val) ++ goto out; ++ ret_val = hw->phy.ops.read_reg(hw, ++ GG82563_PHY_KMRN_MODE_CTRL, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; ++ ret_val = hw->phy.ops.write_reg(hw, ++ GG82563_PHY_KMRN_MODE_CTRL, ++ data); ++ ++ if (ret_val) ++ goto out; ++ } ++ ++ /* ++ * Workaround: Disable padding in Kumeran interface in the MAC ++ * and in the PHY to avoid CRC errors. ++ */ ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_INBAND_CTRL, &data); ++ if (ret_val) ++ goto out; ++ ++ data |= GG82563_ICR_DIS_PADDING; ++ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_INBAND_CTRL, data); ++ if (ret_val) ++ goto out; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2 ++ * @hw: pointer to the HW structure ++ * ++ * Essentially a wrapper for setting up all things "copper" related. ++ * This is a function pointer entry point called by the mac module. ++ **/ ++static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw) ++{ ++ u32 ctrl; ++ s32 ret_val; ++ u16 reg_data; ++ ++ DEBUGFUNC("e1000_setup_copper_link_80003es2lan"); ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ctrl |= E1000_CTRL_SLU; ++ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ ++ /* ++ * Set the mac to wait the maximum time between each ++ * iteration and increase the max iterations when ++ * polling the phy; this fixes erroneous timeouts at 10Mbps. ++ */ ++ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4), ++ 0xFFFF); ++ if (ret_val) ++ goto out; ++ ret_val = e1000_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9), ++ ®_data); ++ if (ret_val) ++ goto out; ++ reg_data |= 0x3F; ++ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9), ++ reg_data); ++ if (ret_val) ++ goto out; ++ ret_val = e1000_read_kmrn_reg_80003es2lan(hw, ++ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, ++ ®_data); ++ if (ret_val) ++ goto out; ++ reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING; ++ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, ++ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, ++ reg_data); ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_setup_copper_link_generic(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_cfg_on_link_up_80003es2lan - es2 link configuration after link-up ++ * @hw: pointer to the HW structure ++ * @duplex: current duplex setting ++ * ++ * Configure the KMRN interface by applying last minute quirks for ++ * 10/100 operation. ++ **/ ++static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 speed; ++ u16 duplex; ++ ++ DEBUGFUNC("e1000_configure_on_link_up"); ++ ++ if (hw->phy.media_type == e1000_media_type_copper) { ++ ++ ret_val = e1000_get_speed_and_duplex_copper_generic(hw, ++ &speed, ++ &duplex); ++ if (ret_val) ++ goto out; ++ ++ if (speed == SPEED_1000) ++ ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw); ++ else ++ ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, duplex); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation ++ * @hw: pointer to the HW structure ++ * @duplex: current duplex setting ++ * ++ * Configure the KMRN interface by applying last minute quirks for ++ * 10/100 operation. ++ **/ ++static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u32 tipg; ++ u32 i = 0; ++ u16 reg_data, reg_data2; ++ ++ DEBUGFUNC("e1000_configure_kmrn_for_10_100"); ++ ++ reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT; ++ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, ++ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, ++ reg_data); ++ if (ret_val) ++ goto out; ++ ++ /* Configure Transmit Inter-Packet Gap */ ++ tipg = E1000_READ_REG(hw, E1000_TIPG); ++ tipg &= ~E1000_TIPG_IPGT_MASK; ++ tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN; ++ E1000_WRITE_REG(hw, E1000_TIPG, tipg); ++ ++ ++ do { ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ++ ®_data); ++ if (ret_val) ++ goto out; ++ ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ++ ®_data2); ++ if (ret_val) ++ goto out; ++ i++; ++ } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY)); ++ ++ if (duplex == HALF_DUPLEX) ++ reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER; ++ else ++ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; ++ ++ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation ++ * @hw: pointer to the HW structure ++ * ++ * Configure the KMRN interface by applying last minute quirks for ++ * gigabit operation. ++ **/ ++static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 reg_data, reg_data2; ++ u32 tipg; ++ u32 i = 0; ++ ++ DEBUGFUNC("e1000_configure_kmrn_for_1000"); ++ ++ reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT; ++ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, ++ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, ++ reg_data); ++ if (ret_val) ++ goto out; ++ ++ /* Configure Transmit Inter-Packet Gap */ ++ tipg = E1000_READ_REG(hw, E1000_TIPG); ++ tipg &= ~E1000_TIPG_IPGT_MASK; ++ tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; ++ E1000_WRITE_REG(hw, E1000_TIPG, tipg); ++ ++ ++ do { ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ++ ®_data); ++ if (ret_val) ++ goto out; ++ ++ ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ++ ®_data2); ++ if (ret_val) ++ goto out; ++ i++; ++ } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY)); ++ ++ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; ++ ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_kmrn_reg_80003es2lan - Read kumeran register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to be read ++ * @data: pointer to the read data ++ * ++ * Acquire semaphore, then read the PHY register at offset ++ * using the kumeran interface. The information retrieved is stored in data. ++ * Release the semaphore before exiting. ++ **/ ++s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 *data) ++{ ++ u32 kmrnctrlsta; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_read_kmrn_reg_80003es2lan"); ++ ++ ret_val = e1000_acquire_mac_csr_80003es2lan(hw); ++ if (ret_val) ++ goto out; ++ ++ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & ++ E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; ++ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); ++ ++ usec_delay(2); ++ ++ kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA); ++ *data = (u16)kmrnctrlsta; ++ ++ e1000_release_mac_csr_80003es2lan(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_kmrn_reg_80003es2lan - Write kumeran register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to write to ++ * @data: data to write at register offset ++ * ++ * Acquire semaphore, then write the data to PHY register ++ * at the offset using the kumeran interface. Release semaphore ++ * before exiting. ++ **/ ++s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 data) ++{ ++ u32 kmrnctrlsta; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_write_kmrn_reg_80003es2lan"); ++ ++ ret_val = e1000_acquire_mac_csr_80003es2lan(hw); ++ if (ret_val) ++ goto out; ++ ++ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & ++ E1000_KMRNCTRLSTA_OFFSET) | data; ++ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); ++ ++ usec_delay(2); ++ ++ e1000_release_mac_csr_80003es2lan(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_mac_addr_80003es2lan - Read device MAC address ++ * @hw: pointer to the HW structure ++ **/ ++static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_read_mac_addr_80003es2lan"); ++ if (e1000_check_alt_mac_addr_generic(hw)) ++ ret_val = e1000_read_mac_addr_generic(hw); ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down ++ * @hw: pointer to the HW structure ++ * ++ * In the case of a PHY power down to save power, or to turn off link during a ++ * driver unload, or wake on lan is not enabled, remove the link. ++ **/ ++static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw) ++{ ++ /* If the management interface is not enabled, then power down */ ++ if (!(hw->mac.ops.check_mng_mode(hw) || ++ hw->phy.ops.check_reset_block(hw))) ++ e1000_power_down_phy_copper(hw); ++ ++ return; ++} ++ ++/** ++ * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters ++ * @hw: pointer to the HW structure ++ * ++ * Clears the hardware counters by reading the counter registers. ++ **/ ++static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) ++{ ++ volatile u32 temp; ++ ++ DEBUGFUNC("e1000_clear_hw_cntrs_80003es2lan"); ++ ++ e1000_clear_hw_cntrs_base_generic(hw); ++ ++ temp = E1000_READ_REG(hw, E1000_PRC64); ++ temp = E1000_READ_REG(hw, E1000_PRC127); ++ temp = E1000_READ_REG(hw, E1000_PRC255); ++ temp = E1000_READ_REG(hw, E1000_PRC511); ++ temp = E1000_READ_REG(hw, E1000_PRC1023); ++ temp = E1000_READ_REG(hw, E1000_PRC1522); ++ temp = E1000_READ_REG(hw, E1000_PTC64); ++ temp = E1000_READ_REG(hw, E1000_PTC127); ++ temp = E1000_READ_REG(hw, E1000_PTC255); ++ temp = E1000_READ_REG(hw, E1000_PTC511); ++ temp = E1000_READ_REG(hw, E1000_PTC1023); ++ temp = E1000_READ_REG(hw, E1000_PTC1522); ++ ++ temp = E1000_READ_REG(hw, E1000_ALGNERRC); ++ temp = E1000_READ_REG(hw, E1000_RXERRC); ++ temp = E1000_READ_REG(hw, E1000_TNCRS); ++ temp = E1000_READ_REG(hw, E1000_CEXTERR); ++ temp = E1000_READ_REG(hw, E1000_TSCTC); ++ temp = E1000_READ_REG(hw, E1000_TSCTFC); ++ ++ temp = E1000_READ_REG(hw, E1000_MGTPRC); ++ temp = E1000_READ_REG(hw, E1000_MGTPDC); ++ temp = E1000_READ_REG(hw, E1000_MGTPTC); ++ ++ temp = E1000_READ_REG(hw, E1000_IAC); ++ temp = E1000_READ_REG(hw, E1000_ICRXOC); ++ ++ temp = E1000_READ_REG(hw, E1000_ICRXPTC); ++ temp = E1000_READ_REG(hw, E1000_ICRXATC); ++ temp = E1000_READ_REG(hw, E1000_ICTXPTC); ++ temp = E1000_READ_REG(hw, E1000_ICTXATC); ++ temp = E1000_READ_REG(hw, E1000_ICTXQEC); ++ temp = E1000_READ_REG(hw, E1000_ICTXQMTC); ++ temp = E1000_READ_REG(hw, E1000_ICRXDMTC); ++} +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_80003es2lan.h linux-2.6.22-10/drivers/net/e1000e/e1000_80003es2lan.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_80003es2lan.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_80003es2lan.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,95 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _E1000_80003ES2LAN_H_ ++#define _E1000_80003ES2LAN_H_ ++ ++#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00 ++#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02 ++#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10 ++#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE 0x1F ++ ++#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008 ++#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800 ++#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010 ++ ++#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004 ++#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 ++#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000 ++ ++#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ ++#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000 ++ ++#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8 ++#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9 ++ ++/* GG82563 PHY Specific Status Register (Page 0, Register 16 */ ++#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disabled */ ++#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060 ++#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */ ++#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */ ++#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */ ++ ++/* PHY Specific Control Register 2 (Page 0, Register 26) */ ++#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 ++ /* 1=Reverse Auto-Negotiation */ ++ ++/* MAC Specific Control Register (Page 2, Register 21) */ ++/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */ ++#define GG82563_MSCR_TX_CLK_MASK 0x0007 ++#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004 ++#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005 ++#define GG82563_MSCR_TX_CLK_1000MBPS_2_5 0x0006 ++#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007 ++ ++#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */ ++ ++/* DSP Distance Register (Page 5, Register 26) */ ++/* ++ * 0 = <50M ++ * 1 = 50-80M ++ * 2 = 80-100M ++ * 3 = 110-140M ++ * 4 = >140M ++ */ ++#define GG82563_DSPD_CABLE_LENGTH 0x0007 ++ ++/* Kumeran Mode Control Register (Page 193, Register 16) */ ++#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800 ++ ++/* Max number of times Kumeran read/write should be validated */ ++#define GG82563_MAX_KMRN_RETRY 0x5 ++ ++/* Power Management Control Register (Page 193, Register 20) */ ++#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 ++ /* 1=Enable SERDES Electrical Idle */ ++ ++/* In-Band Control Register (Page 194, Register 18) */ ++#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */ ++ ++#endif +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_82571.c linux-2.6.22-10/drivers/net/e1000e/e1000_82571.c +--- linux-2.6.22-0/drivers/net/e1000e/e1000_82571.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_82571.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,1538 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++/* e1000_82571 ++ * e1000_82572 ++ * e1000_82573 ++ * e1000_82574 ++ */ ++ ++#include "e1000_hw.h" ++ ++static s32 e1000_init_phy_params_82571(struct e1000_hw *hw); ++static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw); ++static s32 e1000_init_mac_params_82571(struct e1000_hw *hw); ++static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw); ++static void e1000_release_nvm_82571(struct e1000_hw *hw); ++static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, ++ u16 words, u16 *data); ++static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw); ++static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw); ++static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw); ++static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, ++ bool active); ++static s32 e1000_reset_hw_82571(struct e1000_hw *hw); ++static s32 e1000_init_hw_82571(struct e1000_hw *hw); ++static void e1000_clear_vfta_82571(struct e1000_hw *hw); ++static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); ++static s32 e1000_led_on_82574(struct e1000_hw *hw); ++static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw, ++ u8 *mc_addr_list, u32 mc_addr_count, ++ u32 rar_used_count, u32 rar_count); ++static s32 e1000_setup_link_82571(struct e1000_hw *hw); ++static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); ++static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); ++static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data); ++static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); ++static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw); ++static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); ++static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); ++static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); ++static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw); ++static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, ++ u16 words, u16 *data); ++static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw); ++static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw); ++ ++struct e1000_dev_spec_82571 { ++ bool laa_is_present; ++}; ++ ++/** ++ * e1000_init_phy_params_82571 - Init PHY func ptrs. ++ * @hw: pointer to the HW structure ++ * ++ * This is a function pointer entry point called by the api module. ++ **/ ++static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_init_phy_params_82571"); ++ ++ if (hw->phy.media_type != e1000_media_type_copper) { ++ phy->type = e1000_phy_none; ++ goto out; ++ } ++ ++ phy->addr = 1; ++ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; ++ phy->reset_delay_us = 100; ++ ++ phy->ops.acquire = e1000_get_hw_semaphore_82571; ++ phy->ops.check_polarity = e1000_check_polarity_igp; ++ phy->ops.check_reset_block = e1000_check_reset_block_generic; ++ phy->ops.release = e1000_put_hw_semaphore_82571; ++ phy->ops.reset = e1000_phy_hw_reset_generic; ++ phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82571; ++ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic; ++ phy->ops.power_up = e1000_power_up_phy_copper; ++ phy->ops.power_down = e1000_power_down_phy_copper_82571; ++ ++ switch (hw->mac.type) { ++ case e1000_82571: ++ case e1000_82572: ++ phy->type = e1000_phy_igp_2; ++ phy->ops.get_cfg_done = e1000_get_cfg_done_82571; ++ phy->ops.get_info = e1000_get_phy_info_igp; ++ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp; ++ phy->ops.get_cable_length = e1000_get_cable_length_igp_2; ++ phy->ops.read_reg = e1000_read_phy_reg_igp; ++ phy->ops.write_reg = e1000_write_phy_reg_igp; ++ ++ /* This uses above function pointers */ ++ ret_val = e1000_get_phy_id_82571(hw); ++ ++ /* Verify PHY ID */ ++ if (phy->id != IGP01E1000_I_PHY_ID) { ++ ret_val = -E1000_ERR_PHY; ++ goto out; ++ } ++ break; ++ case e1000_82573: ++ phy->type = e1000_phy_m88; ++ phy->ops.get_cfg_done = e1000_get_cfg_done_generic; ++ phy->ops.get_info = e1000_get_phy_info_m88; ++ phy->ops.commit = e1000_phy_sw_reset_generic; ++ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; ++ phy->ops.get_cable_length = e1000_get_cable_length_m88; ++ phy->ops.read_reg = e1000_read_phy_reg_m88; ++ phy->ops.write_reg = e1000_write_phy_reg_m88; ++ ++ /* This uses above function pointers */ ++ ret_val = e1000_get_phy_id_82571(hw); ++ ++ /* Verify PHY ID */ ++ if (phy->id != M88E1111_I_PHY_ID) { ++ ret_val = -E1000_ERR_PHY; ++ DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id); ++ goto out; ++ } ++ break; ++ case e1000_82574: ++ phy->type = e1000_phy_bm; ++ phy->ops.get_cfg_done = e1000_get_cfg_done_generic; ++ phy->ops.get_info = e1000_get_phy_info_m88; ++ phy->ops.commit = e1000_phy_sw_reset_generic; ++ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; ++ phy->ops.get_cable_length = e1000_get_cable_length_m88; ++ phy->ops.read_reg = e1000_read_phy_reg_bm2; ++ phy->ops.write_reg = e1000_write_phy_reg_bm2; ++ ++ /* This uses above function pointers */ ++ ret_val = e1000_get_phy_id_82571(hw); ++ /* Verify PHY ID */ ++ if (phy->id != BME1000_E_PHY_ID_R2) { ++ ret_val = -E1000_ERR_PHY; ++ DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id); ++ goto out; ++ } ++ break; ++ default: ++ ret_val = -E1000_ERR_PHY; ++ goto out; ++ break; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_init_nvm_params_82571 - Init NVM func ptrs. ++ * @hw: pointer to the HW structure ++ * ++ * This is a function pointer entry point called by the api module. ++ **/ ++static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ u32 eecd = E1000_READ_REG(hw, E1000_EECD); ++ u16 size; ++ ++ DEBUGFUNC("e1000_init_nvm_params_82571"); ++ ++ nvm->opcode_bits = 8; ++ nvm->delay_usec = 1; ++ switch (nvm->override) { ++ case e1000_nvm_override_spi_large: ++ nvm->page_size = 32; ++ nvm->address_bits = 16; ++ break; ++ case e1000_nvm_override_spi_small: ++ nvm->page_size = 8; ++ nvm->address_bits = 8; ++ break; ++ default: ++ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; ++ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; ++ break; ++ } ++ ++ switch (hw->mac.type) { ++ case e1000_82573: ++ case e1000_82574: ++ if (((eecd >> 15) & 0x3) == 0x3) { ++ nvm->type = e1000_nvm_flash_hw; ++ nvm->word_size = 2048; ++ /* ++ * Autonomous Flash update bit must be cleared due ++ * to Flash update issue. ++ */ ++ eecd &= ~E1000_EECD_AUPDEN; ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ break; ++ } ++ /* Fall Through */ ++ default: ++ nvm->type = e1000_nvm_eeprom_spi; ++ size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> ++ E1000_EECD_SIZE_EX_SHIFT); ++ /* ++ * Added to a constant, "size" becomes the left-shift value ++ * for setting word_size. ++ */ ++ size += NVM_WORD_SIZE_BASE_SHIFT; ++ ++ /* EEPROM access above 16k is unsupported */ ++ if (size > 14) ++ size = 14; ++ nvm->word_size = 1 << size; ++ break; ++ } ++ ++ /* Function Pointers */ ++ nvm->ops.acquire = e1000_acquire_nvm_82571; ++ nvm->ops.read = e1000_read_nvm_eerd; ++ nvm->ops.release = e1000_release_nvm_82571; ++ nvm->ops.update = e1000_update_nvm_checksum_82571; ++ nvm->ops.validate = e1000_validate_nvm_checksum_82571; ++ nvm->ops.valid_led_default = e1000_valid_led_default_82571; ++ nvm->ops.write = e1000_write_nvm_82571; ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_init_mac_params_82571 - Init MAC func ptrs. ++ * @hw: pointer to the HW structure ++ * ++ * This is a function pointer entry point called by the api module. ++ **/ ++static s32 e1000_init_mac_params_82571(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_init_mac_params_82571"); ++ ++ /* Set media type */ ++ switch (hw->device_id) { ++ case E1000_DEV_ID_82571EB_FIBER: ++ case E1000_DEV_ID_82572EI_FIBER: ++ case E1000_DEV_ID_82571EB_QUAD_FIBER: ++ hw->phy.media_type = e1000_media_type_fiber; ++ break; ++ case E1000_DEV_ID_82571EB_SERDES: ++ case E1000_DEV_ID_82571EB_SERDES_DUAL: ++ case E1000_DEV_ID_82571EB_SERDES_QUAD: ++ case E1000_DEV_ID_82572EI_SERDES: ++ hw->phy.media_type = e1000_media_type_internal_serdes; ++ break; ++ default: ++ hw->phy.media_type = e1000_media_type_copper; ++ break; ++ } ++ ++ /* Set mta register count */ ++ mac->mta_reg_count = 128; ++ /* Set rar entry count */ ++ mac->rar_entry_count = E1000_RAR_ENTRIES; ++ /* Set if part includes ASF firmware */ ++ mac->asf_firmware_present = true; ++ /* Set if manageability features are enabled. */ ++ mac->arc_subsystem_valid = ++ (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK) ++ ? true : false; ++ ++ /* Function pointers */ ++ ++ /* bus type/speed/width */ ++ mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic; ++ /* reset */ ++ mac->ops.reset_hw = e1000_reset_hw_82571; ++ /* hw initialization */ ++ mac->ops.init_hw = e1000_init_hw_82571; ++ /* link setup */ ++ mac->ops.setup_link = e1000_setup_link_82571; ++ /* physical interface link setup */ ++ mac->ops.setup_physical_interface = ++ (hw->phy.media_type == e1000_media_type_copper) ++ ? e1000_setup_copper_link_82571 ++ : e1000_setup_fiber_serdes_link_82571; ++ /* check for link */ ++ switch (hw->phy.media_type) { ++ case e1000_media_type_copper: ++ mac->ops.check_for_link = e1000_check_for_copper_link_generic; ++ break; ++ case e1000_media_type_fiber: ++ mac->ops.check_for_link = e1000_check_for_fiber_link_generic; ++ break; ++ case e1000_media_type_internal_serdes: ++ mac->ops.check_for_link = e1000_check_for_serdes_link_generic; ++ break; ++ default: ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ break; ++ } ++ /* check management mode */ ++ switch (hw->mac.type) { ++ case e1000_82574: ++ mac->ops.check_mng_mode = e1000_check_mng_mode_82574; ++ break; ++ default: ++ mac->ops.check_mng_mode = e1000_check_mng_mode_generic; ++ break; ++ } ++ /* multicast address update */ ++ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_82571; ++ /* writing VFTA */ ++ mac->ops.write_vfta = e1000_write_vfta_generic; ++ /* clearing VFTA */ ++ mac->ops.clear_vfta = e1000_clear_vfta_82571; ++ /* setting MTA */ ++ mac->ops.mta_set = e1000_mta_set_generic; ++ /* read mac address */ ++ mac->ops.read_mac_addr = e1000_read_mac_addr_82571; ++ /* blink LED */ ++ mac->ops.blink_led = e1000_blink_led_generic; ++ /* setup LED */ ++ mac->ops.setup_led = e1000_setup_led_generic; ++ /* cleanup LED */ ++ mac->ops.cleanup_led = e1000_cleanup_led_generic; ++ /* turn on/off LED */ ++ switch (hw->mac.type) { ++ case e1000_82574: ++ mac->ops.led_on = e1000_led_on_82574; ++ break; ++ default: ++ mac->ops.led_on = e1000_led_on_generic; ++ break; ++ } ++ mac->ops.led_off = e1000_led_off_generic; ++ /* remove device */ ++ mac->ops.remove_device = e1000_remove_device_generic; ++ /* clear hardware counters */ ++ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82571; ++ /* link info */ ++ mac->ops.get_link_up_info = ++ (hw->phy.media_type == e1000_media_type_copper) ++ ? e1000_get_speed_and_duplex_copper_generic ++ : e1000_get_speed_and_duplex_fiber_serdes_generic; ++ ++ hw->dev_spec_size = sizeof(struct e1000_dev_spec_82571); ++ ++ /* Device-specific structure allocation */ ++ ret_val = e1000_alloc_zeroed_dev_spec_struct(hw, hw->dev_spec_size); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_init_function_pointers_82571 - Init func ptrs. ++ * @hw: pointer to the HW structure ++ * ++ * The only function explicitly called by the api module to initialize ++ * all function pointers and parameters. ++ **/ ++void e1000_init_function_pointers_82571(struct e1000_hw *hw) ++{ ++ DEBUGFUNC("e1000_init_function_pointers_82571"); ++ ++ e1000_init_mac_ops_generic(hw); ++ e1000_init_nvm_ops_generic(hw); ++ hw->mac.ops.init_params = e1000_init_mac_params_82571; ++ hw->nvm.ops.init_params = e1000_init_nvm_params_82571; ++ hw->phy.ops.init_params = e1000_init_phy_params_82571; ++} ++ ++/** ++ * e1000_get_phy_id_82571 - Retrieve the PHY ID and revision ++ * @hw: pointer to the HW structure ++ * ++ * Reads the PHY registers and stores the PHY ID and possibly the PHY ++ * revision in the hardware structure. ++ **/ ++static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ u16 phy_id = 0; ++ ++ DEBUGFUNC("e1000_get_phy_id_82571"); ++ ++ switch (hw->mac.type) { ++ case e1000_82571: ++ case e1000_82572: ++ /* ++ * The 82571 firmware may still be configuring the PHY. ++ * In this case, we cannot access the PHY until the ++ * configuration is done. So we explicitly set the ++ * PHY ID. ++ */ ++ phy->id = IGP01E1000_I_PHY_ID; ++ break; ++ case e1000_82573: ++ ret_val = e1000_get_phy_id(hw); ++ break; ++ case e1000_82574: ++ ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); ++ if (ret_val) ++ goto out; ++ ++ phy->id = (u32)(phy_id << 16); ++ usec_delay(20); ++ ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id); ++ if (ret_val) ++ goto out; ++ ++ phy->id |= (u32)(phy_id); ++ phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); ++ break; ++ default: ++ ret_val = -E1000_ERR_PHY; ++ break; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_hw_semaphore_82571 - Acquire hardware semaphore ++ * @hw: pointer to the HW structure ++ * ++ * Acquire the HW semaphore to access the PHY or NVM ++ **/ ++static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) ++{ ++ u32 swsm; ++ s32 ret_val = E1000_SUCCESS; ++ s32 timeout = hw->nvm.word_size + 1; ++ s32 i = 0; ++ ++ DEBUGFUNC("e1000_get_hw_semaphore_82571"); ++ ++ /* Get the FW semaphore. */ ++ for (i = 0; i < timeout; i++) { ++ swsm = E1000_READ_REG(hw, E1000_SWSM); ++ E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); ++ ++ /* Semaphore acquired if bit latched */ ++ if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI) ++ break; ++ ++ usec_delay(50); ++ } ++ ++ if (i == timeout) { ++ /* Release semaphores */ ++ e1000_put_hw_semaphore_generic(hw); ++ DEBUGOUT("Driver can't access the NVM\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_put_hw_semaphore_82571 - Release hardware semaphore ++ * @hw: pointer to the HW structure ++ * ++ * Release hardware semaphore used to access the PHY or NVM ++ **/ ++static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) ++{ ++ u32 swsm; ++ ++ DEBUGFUNC("e1000_put_hw_semaphore_82571"); ++ ++ swsm = E1000_READ_REG(hw, E1000_SWSM); ++ ++ swsm &= ~E1000_SWSM_SWESMBI; ++ ++ E1000_WRITE_REG(hw, E1000_SWSM, swsm); ++} ++ ++/** ++ * e1000_acquire_nvm_82571 - Request for access to the EEPROM ++ * @hw: pointer to the HW structure ++ * ++ * To gain access to the EEPROM, first we must obtain a hardware semaphore. ++ * Then for non-82573 hardware, set the EEPROM access request bit and wait ++ * for EEPROM access grant bit. If the access grant bit is not set, release ++ * hardware semaphore. ++ **/ ++static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw) ++{ ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_acquire_nvm_82571"); ++ ++ ret_val = e1000_get_hw_semaphore_82571(hw); ++ if (ret_val) ++ goto out; ++ ++ if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574) ++ ret_val = e1000_acquire_nvm_generic(hw); ++ ++ if (ret_val) ++ e1000_put_hw_semaphore_82571(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_release_nvm_82571 - Release exclusive access to EEPROM ++ * @hw: pointer to the HW structure ++ * ++ * Stop any current commands to the EEPROM and clear the EEPROM request bit. ++ **/ ++static void e1000_release_nvm_82571(struct e1000_hw *hw) ++{ ++ DEBUGFUNC("e1000_release_nvm_82571"); ++ ++ e1000_release_nvm_generic(hw); ++ e1000_put_hw_semaphore_82571(hw); ++} ++ ++/** ++ * e1000_write_nvm_82571 - Write to EEPROM using appropriate interface ++ * @hw: pointer to the HW structure ++ * @offset: offset within the EEPROM to be written to ++ * @words: number of words to write ++ * @data: 16 bit word(s) to be written to the EEPROM ++ * ++ * For non-82573 silicon, write data to EEPROM at offset using SPI interface. ++ * ++ * If e1000_update_nvm_checksum is not called after this function, the ++ * EEPROM will most likely contain an invalid checksum. ++ **/ ++static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words, ++ u16 *data) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_write_nvm_82571"); ++ ++ switch (hw->mac.type) { ++ case e1000_82573: ++ case e1000_82574: ++ ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data); ++ break; ++ case e1000_82571: ++ case e1000_82572: ++ ret_val = e1000_write_nvm_spi(hw, offset, words, data); ++ break; ++ default: ++ ret_val = -E1000_ERR_NVM; ++ break; ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_update_nvm_checksum_82571 - Update EEPROM checksum ++ * @hw: pointer to the HW structure ++ * ++ * Updates the EEPROM checksum by reading/adding each word of the EEPROM ++ * up to the checksum. Then calculates the EEPROM checksum and writes the ++ * value to the EEPROM. ++ **/ ++static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) ++{ ++ u32 eecd; ++ s32 ret_val; ++ u16 i; ++ ++ DEBUGFUNC("e1000_update_nvm_checksum_82571"); ++ ++ ret_val = e1000_update_nvm_checksum_generic(hw); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * If our nvm is an EEPROM, then we're done ++ * otherwise, commit the checksum to the flash NVM. ++ */ ++ if (hw->nvm.type != e1000_nvm_flash_hw) ++ goto out; ++ ++ /* Check for pending operations. */ ++ for (i = 0; i < E1000_FLASH_UPDATES; i++) { ++ msec_delay(1); ++ if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_FLUPD) == 0) ++ break; ++ } ++ ++ if (i == E1000_FLASH_UPDATES) { ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ /* Reset the firmware if using STM opcode. */ ++ if ((E1000_READ_REG(hw, E1000_FLOP) & 0xFF00) == E1000_STM_OPCODE) { ++ /* ++ * The enabling of and the actual reset must be done ++ * in two write cycles. ++ */ ++ E1000_WRITE_REG(hw, E1000_HICR, E1000_HICR_FW_RESET_ENABLE); ++ E1000_WRITE_FLUSH(hw); ++ E1000_WRITE_REG(hw, E1000_HICR, E1000_HICR_FW_RESET); ++ } ++ ++ /* Commit the write to flash */ ++ eecd = E1000_READ_REG(hw, E1000_EECD) | E1000_EECD_FLUPD; ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ ++ for (i = 0; i < E1000_FLASH_UPDATES; i++) { ++ msec_delay(1); ++ if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_FLUPD) == 0) ++ break; ++ } ++ ++ if (i == E1000_FLASH_UPDATES) { ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum ++ * @hw: pointer to the HW structure ++ * ++ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM ++ * and then verifies that the sum of the EEPROM is equal to 0xBABA. ++ **/ ++static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw) ++{ ++ DEBUGFUNC("e1000_validate_nvm_checksum_82571"); ++ ++ if (hw->nvm.type == e1000_nvm_flash_hw) ++ e1000_fix_nvm_checksum_82571(hw); ++ ++ return e1000_validate_nvm_checksum_generic(hw); ++} ++ ++/** ++ * e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon ++ * @hw: pointer to the HW structure ++ * @offset: offset within the EEPROM to be written to ++ * @words: number of words to write ++ * @data: 16 bit word(s) to be written to the EEPROM ++ * ++ * After checking for invalid values, poll the EEPROM to ensure the previous ++ * command has completed before trying to write the next word. After write ++ * poll for completion. ++ * ++ * If e1000_update_nvm_checksum is not called after this function, the ++ * EEPROM will most likely contain an invalid checksum. ++ **/ ++static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, ++ u16 words, u16 *data) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ u32 i, eewr = 0; ++ s32 ret_val = 0; ++ ++ DEBUGFUNC("e1000_write_nvm_eewr_82571"); ++ ++ /* ++ * A check for invalid values: offset too large, too many words, ++ * and not enough words. ++ */ ++ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || ++ (words == 0)) { ++ DEBUGOUT("nvm parameter(s) out of bounds\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ for (i = 0; i < words; i++) { ++ eewr = (data[i] << E1000_NVM_RW_REG_DATA) | ++ ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | ++ E1000_NVM_RW_REG_START; ++ ++ ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE); ++ if (ret_val) ++ break; ++ ++ E1000_WRITE_REG(hw, E1000_EEWR, eewr); ++ ++ ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE); ++ if (ret_val) ++ break; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_cfg_done_82571 - Poll for configuration done ++ * @hw: pointer to the HW structure ++ * ++ * Reads the management control register for the config done bit to be set. ++ **/ ++static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw) ++{ ++ s32 timeout = PHY_CFG_TIMEOUT; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_get_cfg_done_82571"); ++ ++ while (timeout) { ++ if (E1000_READ_REG(hw, E1000_EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0) ++ break; ++ msec_delay(1); ++ timeout--; ++ } ++ if (!timeout) { ++ DEBUGOUT("MNG configuration cycle has not completed.\n"); ++ ret_val = -E1000_ERR_RESET; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state ++ * @hw: pointer to the HW structure ++ * @active: true to enable LPLU, false to disable ++ * ++ * Sets the LPLU D0 state according to the active flag. When activating LPLU ++ * this function also disables smart speed and vice versa. LPLU will not be ++ * activated unless the device autonegotiation advertisement meets standards ++ * of either 10 or 10/100 or 10/100/1000 at all duplexes. This is a function ++ * pointer entry point only called by PHY setup routines. ++ **/ ++static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ u16 data; ++ ++ DEBUGFUNC("e1000_set_d0_lplu_state_82571"); ++ ++ if (!(phy->ops.read_reg)) ++ goto out; ++ ++ ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data); ++ if (ret_val) ++ goto out; ++ ++ if (active) { ++ data |= IGP02E1000_PM_D0_LPLU; ++ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, ++ data); ++ if (ret_val) ++ goto out; ++ ++ /* When LPLU is enabled, we should disable SmartSpeed */ ++ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ data &= ~IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ } else { ++ data &= ~IGP02E1000_PM_D0_LPLU; ++ ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, ++ data); ++ /* ++ * LPLU and SmartSpeed are mutually exclusive. LPLU is used ++ * during Dx states where the power conservation is most ++ * important. During driver activity we should enable ++ * SmartSpeed, so performance is maintained. ++ */ ++ if (phy->smart_speed == e1000_smart_speed_on) { ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data |= IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ } else if (phy->smart_speed == e1000_smart_speed_off) { ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_reset_hw_82571 - Reset hardware ++ * @hw: pointer to the HW structure ++ * ++ * This resets the hardware into a known state. This is a ++ * function pointer entry point called by the api module. ++ **/ ++static s32 e1000_reset_hw_82571(struct e1000_hw *hw) ++{ ++ u32 ctrl, extcnf_ctrl, ctrl_ext, icr; ++ s32 ret_val; ++ u16 i = 0; ++ ++ DEBUGFUNC("e1000_reset_hw_82571"); ++ ++ /* ++ * Prevent the PCI-E bus from sticking if there is no TLP connection ++ * on the last TLP read/write transaction when MAC is reset. ++ */ ++ ret_val = e1000_disable_pcie_master_generic(hw); ++ if (ret_val) { ++ DEBUGOUT("PCI-E Master disable polling has failed.\n"); ++ } ++ ++ DEBUGOUT("Masking off all interrupts\n"); ++ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); ++ ++ E1000_WRITE_REG(hw, E1000_RCTL, 0); ++ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); ++ E1000_WRITE_FLUSH(hw); ++ ++ msec_delay(10); ++ ++ /* ++ * Must acquire the MDIO ownership before MAC reset. ++ * Ownership defaults to firmware after a reset. ++ */ ++ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { ++ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); ++ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; ++ ++ do { ++ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); ++ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); ++ ++ if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) ++ break; ++ ++ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; ++ ++ msec_delay(2); ++ i++; ++ } while (i < MDIO_OWNERSHIP_TIMEOUT); ++ } ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ++ DEBUGOUT("Issuing a global reset to MAC\n"); ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); ++ ++ if (hw->nvm.type == e1000_nvm_flash_hw) { ++ usec_delay(10); ++ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); ++ ctrl_ext |= E1000_CTRL_EXT_EE_RST; ++ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); ++ E1000_WRITE_FLUSH(hw); ++ } ++ ++ ret_val = e1000_get_auto_rd_done_generic(hw); ++ if (ret_val) ++ /* We don't want to continue accessing MAC registers. */ ++ goto out; ++ ++ /* ++ * Phy configuration from NVM just starts after EECD_AUTO_RD is set. ++ * Need to wait for Phy configuration completion before accessing ++ * NVM and Phy. ++ */ ++ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) ++ msec_delay(25); ++ ++ /* Clear any pending interrupt events. */ ++ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); ++ icr = E1000_READ_REG(hw, E1000_ICR); ++ ++ if (!(e1000_check_alt_mac_addr_generic(hw))) ++ e1000_set_laa_state_82571(hw, true); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_init_hw_82571 - Initialize hardware ++ * @hw: pointer to the HW structure ++ * ++ * This inits the hardware readying it for operation. ++ **/ ++static s32 e1000_init_hw_82571(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ u32 reg_data; ++ s32 ret_val; ++ u16 i, rar_count = mac->rar_entry_count; ++ ++ DEBUGFUNC("e1000_init_hw_82571"); ++ ++ e1000_initialize_hw_bits_82571(hw); ++ ++ /* Initialize identification LED */ ++ ret_val = e1000_id_led_init_generic(hw); ++ if (ret_val) { ++ DEBUGOUT("Error initializing identification LED\n"); ++ /* This is not fatal and we should not stop init due to this */ ++ } ++ ++ /* Disabling VLAN filtering */ ++ DEBUGOUT("Initializing the IEEE VLAN\n"); ++ mac->ops.clear_vfta(hw); ++ ++ /* Setup the receive address. */ ++ /* ++ * If, however, a locally administered address was assigned to the ++ * 82571, we must reserve a RAR for it to work around an issue where ++ * resetting one port will reload the MAC on the other port. ++ */ ++ if (e1000_get_laa_state_82571(hw)) ++ rar_count--; ++ e1000_init_rx_addrs_generic(hw, rar_count); ++ ++ /* Zero out the Multicast HASH table */ ++ DEBUGOUT("Zeroing the MTA\n"); ++ for (i = 0; i < mac->mta_reg_count; i++) ++ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); ++ ++ /* Setup link and flow control */ ++ ret_val = mac->ops.setup_link(hw); ++ ++ /* Set the transmit descriptor write-back policy */ ++ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0)); ++ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | ++ E1000_TXDCTL_FULL_TX_DESC_WB | ++ E1000_TXDCTL_COUNT_DESC; ++ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data); ++ ++ /* ...for both queues. */ ++ if (mac->type != e1000_82573 && mac->type != e1000_82574) { ++ reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1)); ++ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | ++ E1000_TXDCTL_FULL_TX_DESC_WB | ++ E1000_TXDCTL_COUNT_DESC; ++ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data); ++ } else { ++ e1000_enable_tx_pkt_filtering_generic(hw); ++ reg_data = E1000_READ_REG(hw, E1000_GCR); ++ reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; ++ E1000_WRITE_REG(hw, E1000_GCR, reg_data); ++ } ++ ++ /* ++ * Clear all of the statistics registers (clear on read). It is ++ * important that we do this after we have tried to establish link ++ * because the symbol error count will increment wildly if there ++ * is no link. ++ */ ++ e1000_clear_hw_cntrs_82571(hw); ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits ++ * @hw: pointer to the HW structure ++ * ++ * Initializes required hardware-dependent bits needed for normal operation. ++ **/ ++static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) ++{ ++ u32 reg; ++ ++ DEBUGFUNC("e1000_initialize_hw_bits_82571"); ++ ++ if (hw->mac.disable_hw_init_bits) ++ goto out; ++ ++ /* Transmit Descriptor Control 0 */ ++ reg = E1000_READ_REG(hw, E1000_TXDCTL(0)); ++ reg |= (1 << 22); ++ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg); ++ ++ /* Transmit Descriptor Control 1 */ ++ reg = E1000_READ_REG(hw, E1000_TXDCTL(1)); ++ reg |= (1 << 22); ++ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg); ++ ++ /* Transmit Arbitration Control 0 */ ++ reg = E1000_READ_REG(hw, E1000_TARC(0)); ++ reg &= ~(0xF << 27); /* 30:27 */ ++ switch (hw->mac.type) { ++ case e1000_82571: ++ case e1000_82572: ++ reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26); ++ break; ++ default: ++ break; ++ } ++ E1000_WRITE_REG(hw, E1000_TARC(0), reg); ++ ++ /* Transmit Arbitration Control 1 */ ++ reg = E1000_READ_REG(hw, E1000_TARC(1)); ++ switch (hw->mac.type) { ++ case e1000_82571: ++ case e1000_82572: ++ reg &= ~((1 << 29) | (1 << 30)); ++ reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26); ++ if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR) ++ reg &= ~(1 << 28); ++ else ++ reg |= (1 << 28); ++ E1000_WRITE_REG(hw, E1000_TARC(1), reg); ++ break; ++ default: ++ break; ++ } ++ ++ /* Device Control */ ++ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { ++ reg = E1000_READ_REG(hw, E1000_CTRL); ++ reg &= ~(1 << 29); ++ E1000_WRITE_REG(hw, E1000_CTRL, reg); ++ } ++ ++ /* Extended Device Control */ ++ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { ++ reg = E1000_READ_REG(hw, E1000_CTRL_EXT); ++ reg &= ~(1 << 23); ++ reg |= (1 << 22); ++ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); ++ } ++ ++ /* PCI-Ex Control Register */ ++ if (hw->mac.type == e1000_82574) { ++ reg = E1000_READ_REG(hw, E1000_GCR); ++ reg |= (1 << 22); ++ E1000_WRITE_REG(hw, E1000_GCR, reg); ++ } ++ ++out: ++ return; ++} ++ ++/** ++ * e1000_clear_vfta_82571 - Clear VLAN filter table ++ * @hw: pointer to the HW structure ++ * ++ * Clears the register array which contains the VLAN filter table by ++ * setting all the values to 0. ++ **/ ++static void e1000_clear_vfta_82571(struct e1000_hw *hw) ++{ ++ u32 offset; ++ u32 vfta_value = 0; ++ u32 vfta_offset = 0; ++ u32 vfta_bit_in_reg = 0; ++ ++ DEBUGFUNC("e1000_clear_vfta_82571"); ++ ++ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { ++ if (hw->mng_cookie.vlan_id != 0) { ++ /* ++ * The VFTA is a 4096b bit-field, each identifying ++ * a single VLAN ID. The following operations ++ * determine which 32b entry (i.e. offset) into the ++ * array we want to set the VLAN ID (i.e. bit) of ++ * the manageability unit. ++ */ ++ vfta_offset = (hw->mng_cookie.vlan_id >> ++ E1000_VFTA_ENTRY_SHIFT) & ++ E1000_VFTA_ENTRY_MASK; ++ vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id & ++ E1000_VFTA_ENTRY_BIT_SHIFT_MASK); ++ } ++ } ++ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { ++ /* ++ * If the offset we want to clear is the same offset of the ++ * manageability VLAN ID, then clear all bits except that of ++ * the manageability unit. ++ */ ++ vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0; ++ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value); ++ E1000_WRITE_FLUSH(hw); ++ } ++} ++ ++/** ++ * e1000_check_mng_mode_82574 - Check manageability is enabled ++ * @hw: pointer to the HW structure ++ * ++ * Reads the NVM Initialization Control Word 2 and returns true ++ * (>0) if any manageability is enabled, else false (0). ++ **/ ++static bool e1000_check_mng_mode_82574(struct e1000_hw *hw) ++{ ++ u16 data; ++ ++ DEBUGFUNC("e1000_check_mng_mode_82574"); ++ ++ hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &data); ++ return ((data & E1000_NVM_INIT_CTRL2_MNGM) != 0); ++} ++ ++/** ++ * e1000_led_on_82574 - Turn LED on ++ * @hw: pointer to the HW structure ++ * ++ * Turn LED on. ++ **/ ++static s32 e1000_led_on_82574(struct e1000_hw *hw) ++{ ++ u32 ctrl; ++ u32 i; ++ ++ DEBUGFUNC("e1000_led_on_82574"); ++ ++ ctrl = hw->mac.ledctl_mode2; ++ if (!(E1000_STATUS_LU & E1000_READ_REG(hw, E1000_STATUS))) { ++ /* ++ * If no link, then turn LED on by setting the invert bit ++ * for each LED that's "on" (0x0E) in ledctl_mode2. ++ */ ++ for (i = 0; i < 4; i++) ++ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == ++ E1000_LEDCTL_MODE_LED_ON) ++ ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8)); ++ } ++ E1000_WRITE_REG(hw, E1000_LEDCTL, ctrl); ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_update_mc_addr_list_82571 - Update Multicast addresses ++ * @hw: pointer to the HW structure ++ * @mc_addr_list: array of multicast addresses to program ++ * @mc_addr_count: number of multicast addresses to program ++ * @rar_used_count: the first RAR register free to program ++ * @rar_count: total number of supported Receive Address Registers ++ * ++ * Updates the Receive Address Registers and Multicast Table Array. ++ * The caller must have a packed mc_addr_list of multicast addresses. ++ * The parameter rar_count will usually be hw->mac.rar_entry_count ++ * unless there are workarounds that change this. ++ **/ ++static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw, ++ u8 *mc_addr_list, u32 mc_addr_count, ++ u32 rar_used_count, u32 rar_count) ++{ ++ DEBUGFUNC("e1000_update_mc_addr_list_82571"); ++ ++ if (e1000_get_laa_state_82571(hw)) ++ rar_count--; ++ ++ e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count, ++ rar_used_count, rar_count); ++} ++ ++/** ++ * e1000_setup_link_82571 - Setup flow control and link settings ++ * @hw: pointer to the HW structure ++ * ++ * Determines which flow control settings to use, then configures flow ++ * control. Calls the appropriate media-specific link configuration ++ * function. Assuming the adapter has a valid link partner, a valid link ++ * should be established. Assumes the hardware has previously been reset ++ * and the transmitter and receiver are not enabled. ++ **/ ++static s32 e1000_setup_link_82571(struct e1000_hw *hw) ++{ ++ DEBUGFUNC("e1000_setup_link_82571"); ++ ++ /* ++ * 82573 does not have a word in the NVM to determine ++ * the default flow control setting, so we explicitly ++ * set it to full. ++ */ ++ if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && ++ hw->fc.type == e1000_fc_default) ++ hw->fc.type = e1000_fc_full; ++ ++ return e1000_setup_link_generic(hw); ++} ++ ++/** ++ * e1000_setup_copper_link_82571 - Configure copper link settings ++ * @hw: pointer to the HW structure ++ * ++ * Configures the link for auto-neg or forced speed and duplex. Then we check ++ * for link, once link is established calls to configure collision distance ++ * and flow control are called. ++ **/ ++static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw) ++{ ++ u32 ctrl, led_ctrl; ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_setup_copper_link_82571"); ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ctrl |= E1000_CTRL_SLU; ++ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ ++ switch (hw->phy.type) { ++ case e1000_phy_m88: ++ case e1000_phy_bm: ++ ret_val = e1000_copper_link_setup_m88(hw); ++ break; ++ case e1000_phy_igp_2: ++ ret_val = e1000_copper_link_setup_igp(hw); ++ /* Setup activity LED */ ++ led_ctrl = E1000_READ_REG(hw, E1000_LEDCTL); ++ led_ctrl &= IGP_ACTIVITY_LED_MASK; ++ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); ++ E1000_WRITE_REG(hw, E1000_LEDCTL, led_ctrl); ++ break; ++ default: ++ ret_val = -E1000_ERR_PHY; ++ break; ++ } ++ ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_setup_copper_link_generic(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes ++ * @hw: pointer to the HW structure ++ * ++ * Configures collision distance and flow control for fiber and serdes links. ++ * Upon successful setup, poll for link. ++ **/ ++static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) ++{ ++ DEBUGFUNC("e1000_setup_fiber_serdes_link_82571"); ++ ++ switch (hw->mac.type) { ++ case e1000_82571: ++ case e1000_82572: ++ /* ++ * If SerDes loopback mode is entered, there is no form ++ * of reset to take the adapter out of that mode. So we ++ * have to explicitly take the adapter out of loopback ++ * mode. This prevents drivers from twiddling their thumbs ++ * if another tool failed to take it out of loopback mode. ++ */ ++ E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK); ++ break; ++ default: ++ break; ++ } ++ ++ return e1000_setup_fiber_serdes_link_generic(hw); ++} ++ ++/** ++ * e1000_valid_led_default_82571 - Verify a valid default LED config ++ * @hw: pointer to the HW structure ++ * @data: pointer to the NVM (EEPROM) ++ * ++ * Read the EEPROM for the current default LED configuration. If the ++ * LED configuration is not valid, set to a valid LED configuration. ++ **/ ++static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data) ++{ ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_valid_led_default_82571"); ++ ++ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error\n"); ++ goto out; ++ } ++ ++ if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && ++ *data == ID_LED_RESERVED_F746) ++ *data = ID_LED_DEFAULT_82573; ++ else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) ++ *data = ID_LED_DEFAULT; ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_laa_state_82571 - Get locally administered address state ++ * @hw: pointer to the HW structure ++ * ++ * Retrieve and return the current locally administered address state. ++ **/ ++bool e1000_get_laa_state_82571(struct e1000_hw *hw) ++{ ++ struct e1000_dev_spec_82571 *dev_spec; ++ bool state = false; ++ ++ DEBUGFUNC("e1000_get_laa_state_82571"); ++ ++ if (hw->mac.type != e1000_82571) ++ goto out; ++ ++ dev_spec = (struct e1000_dev_spec_82571 *)hw->dev_spec; ++ ++ state = dev_spec->laa_is_present; ++ ++out: ++ return state; ++} ++ ++/** ++ * e1000_set_laa_state_82571 - Set locally administered address state ++ * @hw: pointer to the HW structure ++ * @state: enable/disable locally administered address ++ * ++ * Enable/Disable the current locally administered address state. ++ **/ ++void e1000_set_laa_state_82571(struct e1000_hw *hw, bool state) ++{ ++ struct e1000_dev_spec_82571 *dev_spec; ++ ++ DEBUGFUNC("e1000_set_laa_state_82571"); ++ ++ if (hw->mac.type != e1000_82571) ++ goto out; ++ ++ dev_spec = (struct e1000_dev_spec_82571 *)hw->dev_spec; ++ ++ dev_spec->laa_is_present = state; ++ ++ /* If workaround is activated... */ ++ if (state) { ++ /* ++ * 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, the actual LAA is in one of the RARs and no ++ * incoming packets directed to this port are dropped. ++ * Eventually the LAA will be in RAR[0] and RAR[14]. ++ */ ++ e1000_rar_set_generic(hw, hw->mac.addr, ++ hw->mac.rar_entry_count - 1); ++ } ++ ++out: ++ return; ++} ++ ++/** ++ * e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum ++ * @hw: pointer to the HW structure ++ * ++ * Verifies that the EEPROM has completed the update. After updating the ++ * EEPROM, we need to check bit 15 in work 0x23 for the checksum fix. If ++ * the checksum fix is not implemented, we need to set the bit and update ++ * the checksum. Otherwise, if bit 15 is set and the checksum is incorrect, ++ * we need to return bad checksum. ++ **/ ++static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ s32 ret_val = E1000_SUCCESS; ++ u16 data; ++ ++ DEBUGFUNC("e1000_fix_nvm_checksum_82571"); ++ ++ if (nvm->type != e1000_nvm_flash_hw) ++ goto out; ++ ++ /* ++ * Check bit 4 of word 10h. If it is 0, firmware is done updating ++ * 10h-12h. Checksum may need to be fixed. ++ */ ++ ret_val = nvm->ops.read(hw, 0x10, 1, &data); ++ if (ret_val) ++ goto out; ++ ++ if (!(data & 0x10)) { ++ /* ++ * Read 0x23 and check bit 15. This bit is a 1 ++ * when the checksum has already been fixed. If ++ * the checksum is still wrong and this bit is a ++ * 1, we need to return bad checksum. Otherwise, ++ * we need to set this bit to a 1 and update the ++ * checksum. ++ */ ++ ret_val = nvm->ops.read(hw, 0x23, 1, &data); ++ if (ret_val) ++ goto out; ++ ++ if (!(data & 0x8000)) { ++ data |= 0x8000; ++ ret_val = nvm->ops.write(hw, 0x23, 1, &data); ++ if (ret_val) ++ goto out; ++ ret_val = nvm->ops.update(hw); ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_mac_addr_82571 - Read device MAC address ++ * @hw: pointer to the HW structure ++ **/ ++static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_read_mac_addr_82571"); ++ if (e1000_check_alt_mac_addr_generic(hw)) ++ ret_val = e1000_read_mac_addr_generic(hw); ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_power_down_phy_copper_82571 - Remove link during PHY power down ++ * @hw: pointer to the HW structure ++ * ++ * In the case of a PHY power down to save power, or to turn off link during a ++ * driver unload, or wake on lan is not enabled, remove the link. ++ **/ ++static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ struct e1000_mac_info *mac = &hw->mac; ++ ++ if (!(phy->ops.check_reset_block)) ++ return; ++ ++ /* If the management interface is not enabled, then power down */ ++ if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw))) ++ e1000_power_down_phy_copper(hw); ++ ++ return; ++} ++ ++/** ++ * e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters ++ * @hw: pointer to the HW structure ++ * ++ * Clears the hardware counters by reading the counter registers. ++ **/ ++static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw) ++{ ++ volatile u32 temp; ++ ++ DEBUGFUNC("e1000_clear_hw_cntrs_82571"); ++ ++ e1000_clear_hw_cntrs_base_generic(hw); ++ temp = E1000_READ_REG(hw, E1000_PRC64); ++ temp = E1000_READ_REG(hw, E1000_PRC127); ++ temp = E1000_READ_REG(hw, E1000_PRC255); ++ temp = E1000_READ_REG(hw, E1000_PRC511); ++ temp = E1000_READ_REG(hw, E1000_PRC1023); ++ temp = E1000_READ_REG(hw, E1000_PRC1522); ++ temp = E1000_READ_REG(hw, E1000_PTC64); ++ temp = E1000_READ_REG(hw, E1000_PTC127); ++ temp = E1000_READ_REG(hw, E1000_PTC255); ++ temp = E1000_READ_REG(hw, E1000_PTC511); ++ temp = E1000_READ_REG(hw, E1000_PTC1023); ++ temp = E1000_READ_REG(hw, E1000_PTC1522); ++ ++ temp = E1000_READ_REG(hw, E1000_ALGNERRC); ++ temp = E1000_READ_REG(hw, E1000_RXERRC); ++ temp = E1000_READ_REG(hw, E1000_TNCRS); ++ temp = E1000_READ_REG(hw, E1000_CEXTERR); ++ temp = E1000_READ_REG(hw, E1000_TSCTC); ++ temp = E1000_READ_REG(hw, E1000_TSCTFC); ++ ++ temp = E1000_READ_REG(hw, E1000_MGTPRC); ++ temp = E1000_READ_REG(hw, E1000_MGTPDC); ++ temp = E1000_READ_REG(hw, E1000_MGTPTC); ++ ++ temp = E1000_READ_REG(hw, E1000_IAC); ++ temp = E1000_READ_REG(hw, E1000_ICRXOC); ++ ++ temp = E1000_READ_REG(hw, E1000_ICRXPTC); ++ temp = E1000_READ_REG(hw, E1000_ICRXATC); ++ temp = E1000_READ_REG(hw, E1000_ICTXPTC); ++ temp = E1000_READ_REG(hw, E1000_ICTXATC); ++ temp = E1000_READ_REG(hw, E1000_ICTXQEC); ++ temp = E1000_READ_REG(hw, E1000_ICTXQMTC); ++ temp = E1000_READ_REG(hw, E1000_ICRXDMTC); ++} +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_82571.h linux-2.6.22-10/drivers/net/e1000e/e1000_82571.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_82571.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_82571.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,53 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _E1000_82571_H_ ++#define _E1000_82571_H_ ++ ++#define ID_LED_RESERVED_F746 0xF746 ++#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \ ++ (ID_LED_OFF1_ON2 << 8) | \ ++ (ID_LED_DEF1_DEF2 << 4) | \ ++ (ID_LED_DEF1_DEF2)) ++ ++#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 ++ ++/* Intr Throttling - RW */ ++#define E1000_EITR_82574(_n) (0x000E8 + (0x4 * (_n))) ++ ++#define E1000_EIAC_82574 0x000DC /* Ext. Interrupt Auto Clear - RW */ ++#define E1000_EIAC_MASK_82574 0x01F00000 ++ ++#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */ ++ ++#define E1000_RXCFGL 0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */ ++ ++bool e1000_get_laa_state_82571(struct e1000_hw *hw); ++void e1000_set_laa_state_82571(struct e1000_hw *hw, bool state); ++ ++#endif +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_defines.h linux-2.6.22-10/drivers/net/e1000e/e1000_defines.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_defines.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_defines.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,1437 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _E1000_DEFINES_H_ ++#define _E1000_DEFINES_H_ ++ ++/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ ++#define REQ_TX_DESCRIPTOR_MULTIPLE 8 ++#define REQ_RX_DESCRIPTOR_MULTIPLE 8 ++ ++/* Definitions for power management and wakeup registers */ ++/* Wake Up Control */ ++#define E1000_WUC_APME 0x00000001 /* APM Enable */ ++#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ ++#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ ++#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ ++#define E1000_WUC_LSCWE 0x00000010 /* Link Status wake up enable */ ++#define E1000_WUC_LSCWO 0x00000020 /* Link Status wake up override */ ++#define E1000_WUC_SPM 0x80000000 /* Enable SPM */ ++#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ ++ ++/* Wake Up Filter Control */ ++#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ ++#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ ++#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ ++#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ ++#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ ++#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ ++#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ ++#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ ++#define E1000_WUFC_IGNORE_TCO_BM 0x00000800 /* Ignore WakeOn TCO packets */ ++#define E1000_WUFC_FLX0_BM 0x00001000 /* Flexible Filter 0 Enable */ ++#define E1000_WUFC_FLX1_BM 0x00002000 /* Flexible Filter 1 Enable */ ++#define E1000_WUFC_FLX2_BM 0x00004000 /* Flexible Filter 2 Enable */ ++#define E1000_WUFC_FLX3_BM 0x00008000 /* Flexible Filter 3 Enable */ ++#define E1000_WUFC_IGNORE_TCO 0x00008000 /* Ignore WakeOn TCO packets */ ++#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ ++#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ ++#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ ++#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ ++#define E1000_WUFC_ALL_FILTERS_BM 0x0000F0FF /* Mask for all wakeup filters */ ++#define E1000_WUFC_FLX_OFFSET_BM 12 /* Offset to the Flexible Filters bits */ ++#define E1000_WUFC_FLX_FILTERS_BM 0x0000F000 /* Mask for the 4 flexible filters */ ++#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ ++#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ ++#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ ++ ++/* Wake Up Status */ ++#define E1000_WUS_LNKC E1000_WUFC_LNKC ++#define E1000_WUS_MAG E1000_WUFC_MAG ++#define E1000_WUS_EX E1000_WUFC_EX ++#define E1000_WUS_MC E1000_WUFC_MC ++#define E1000_WUS_BC E1000_WUFC_BC ++#define E1000_WUS_ARP E1000_WUFC_ARP ++#define E1000_WUS_IPV4 E1000_WUFC_IPV4 ++#define E1000_WUS_IPV6 E1000_WUFC_IPV6 ++#define E1000_WUS_FLX0_BM E1000_WUFC_FLX0_BM ++#define E1000_WUS_FLX1_BM E1000_WUFC_FLX1_BM ++#define E1000_WUS_FLX2_BM E1000_WUFC_FLX2_BM ++#define E1000_WUS_FLX3_BM E1000_WUFC_FLX3_BM ++#define E1000_WUS_FLX_FILTERS_BM E1000_WUFC_FLX_FILTERS_BM ++#define E1000_WUS_FLX0 E1000_WUFC_FLX0 ++#define E1000_WUS_FLX1 E1000_WUFC_FLX1 ++#define E1000_WUS_FLX2 E1000_WUFC_FLX2 ++#define E1000_WUS_FLX3 E1000_WUFC_FLX3 ++#define E1000_WUS_FLX_FILTERS E1000_WUFC_FLX_FILTERS ++ ++/* Wake Up Packet Length */ ++#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ ++ ++/* Four Flexible Filters are supported */ ++#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 ++ ++/* Each Flexible Filter is at most 128 (0x80) bytes in length */ ++#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 ++ ++#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX ++#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX ++#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX ++ ++/* Extended Device Control */ ++#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ ++#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ ++#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN ++#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ ++#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */ ++/* Reserved (bits 4,5) in >= 82575 */ ++#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */ ++#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */ ++#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA ++#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */ ++#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */ ++/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */ ++#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ ++#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ ++#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ ++#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ ++#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ ++#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ ++#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ ++#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ ++#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ ++#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 ++#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 ++#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 ++#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000 ++#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 ++#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES 0x00800000 ++#define E1000_CTRL_EXT_LINK_MODE_SGMII 0x00800000 ++#define E1000_CTRL_EXT_EIAME 0x01000000 ++#define E1000_CTRL_EXT_IRCA 0x00000001 ++#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 ++#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 ++#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 ++#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 ++#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 ++#define E1000_CTRL_EXT_CANC 0x04000000 /* Interrupt delay cancellation */ ++#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ ++/* IAME enable bit (27) was removed in >= 82575 */ ++#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ ++#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ ++#define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error detection enabled */ ++#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity error detection enable */ ++#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000 ++#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ ++#define E1000_CTRL_EXT_LSECCK 0x00001000 ++#define E1000_I2CCMD_REG_ADDR_SHIFT 16 ++#define E1000_I2CCMD_REG_ADDR 0x00FF0000 ++#define E1000_I2CCMD_PHY_ADDR_SHIFT 24 ++#define E1000_I2CCMD_PHY_ADDR 0x07000000 ++#define E1000_I2CCMD_OPCODE_READ 0x08000000 ++#define E1000_I2CCMD_OPCODE_WRITE 0x00000000 ++#define E1000_I2CCMD_RESET 0x10000000 ++#define E1000_I2CCMD_READY 0x20000000 ++#define E1000_I2CCMD_INTERRUPT_ENA 0x40000000 ++#define E1000_I2CCMD_ERROR 0x80000000 ++#define E1000_MAX_SGMII_PHY_REG_ADDR 255 ++#define E1000_I2CCMD_PHY_TIMEOUT 200 ++ ++/* Receive Descriptor bit definitions */ ++#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ ++#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ ++#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ ++#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ ++#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ ++#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ ++#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ ++#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ ++#define E1000_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ ++#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */ ++#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ ++#define E1000_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ ++#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ ++#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ ++#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ ++#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ ++#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ ++#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ ++#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ ++#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ ++#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ ++#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ ++#define E1000_RXD_SPC_PRI_SHIFT 13 ++#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ ++#define E1000_RXD_SPC_CFI_SHIFT 12 ++ ++#define E1000_RXDEXT_STATERR_CE 0x01000000 ++#define E1000_RXDEXT_STATERR_SE 0x02000000 ++#define E1000_RXDEXT_STATERR_SEQ 0x04000000 ++#define E1000_RXDEXT_STATERR_CXE 0x10000000 ++#define E1000_RXDEXT_STATERR_TCPE 0x20000000 ++#define E1000_RXDEXT_STATERR_IPE 0x40000000 ++#define E1000_RXDEXT_STATERR_RXE 0x80000000 ++ ++#define E1000_RXDEXT_LSECH 0x01000000 ++#define E1000_RXDEXT_LSECE_MASK 0x60000000 ++#define E1000_RXDEXT_LSECE_NO_ERROR 0x00000000 ++#define E1000_RXDEXT_LSECE_NO_SA_MATCH 0x20000000 ++#define E1000_RXDEXT_LSECE_REPLAY_DETECT 0x40000000 ++#define E1000_RXDEXT_LSECE_BAD_SIG 0x60000000 ++ ++/* mask to determine if packets should be dropped due to frame errors */ ++#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ ++ E1000_RXD_ERR_CE | \ ++ E1000_RXD_ERR_SE | \ ++ E1000_RXD_ERR_SEQ | \ ++ E1000_RXD_ERR_CXE | \ ++ E1000_RXD_ERR_RXE) ++ ++/* Same mask, but for extended and packet split descriptors */ ++#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \ ++ E1000_RXDEXT_STATERR_CE | \ ++ E1000_RXDEXT_STATERR_SE | \ ++ E1000_RXDEXT_STATERR_SEQ | \ ++ E1000_RXDEXT_STATERR_CXE | \ ++ E1000_RXDEXT_STATERR_RXE) ++ ++#define E1000_MRQC_ENABLE_MASK 0x00000007 ++#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001 ++#define E1000_MRQC_ENABLE_RSS_INT 0x00000004 ++#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 ++#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 ++#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 ++#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000 ++#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 ++#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 ++#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 ++ ++#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 ++#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF ++ ++/* Management Control */ ++#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ ++#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ ++#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ ++#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ ++#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ ++#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ ++#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ ++#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ ++#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ ++/* Enable Neighbor Discovery Filtering */ ++#define E1000_MANC_NEIGHBOR_EN 0x00004000 ++#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */ ++#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ ++#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ ++#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ ++#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */ ++#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ ++/* Enable MAC address filtering */ ++#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 ++/* Enable MNG packets to host memory */ ++#define E1000_MANC_EN_MNG2HOST 0x00200000 ++/* Enable IP address filtering */ ++#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 ++#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */ ++#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */ ++#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ ++#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ ++#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ ++#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ ++#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ ++#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ ++ ++#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ ++#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ ++ ++/* Receive Control */ ++#define E1000_RCTL_RST 0x00000001 /* Software reset */ ++#define E1000_RCTL_EN 0x00000002 /* enable */ ++#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ ++#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ ++#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ ++#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ ++#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ ++#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ ++#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ ++#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ ++#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */ ++#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ ++#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ ++#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ ++#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ ++#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ ++#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ ++#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ ++#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ ++#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ ++#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ ++#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ ++/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ ++#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ ++#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ ++#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ ++#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ ++/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ ++#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ ++#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ ++#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ ++#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ ++#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ ++#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ ++#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ ++#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ ++#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ ++#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ ++#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */ ++#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */ ++ ++/* ++ * Use byte values for the following shift parameters ++ * Usage: ++ * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) & ++ * E1000_PSRCTL_BSIZE0_MASK) | ++ * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) & ++ * E1000_PSRCTL_BSIZE1_MASK) | ++ * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) & ++ * E1000_PSRCTL_BSIZE2_MASK) | ++ * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |; ++ * E1000_PSRCTL_BSIZE3_MASK)) ++ * where value0 = [128..16256], default=256 ++ * value1 = [1024..64512], default=4096 ++ * value2 = [0..64512], default=4096 ++ * value3 = [0..64512], default=0 ++ */ ++ ++#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F ++#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 ++#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 ++#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000 ++ ++#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */ ++#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */ ++#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ ++#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ ++ ++/* SWFW_SYNC Definitions */ ++#define E1000_SWFW_EEP_SM 0x1 ++#define E1000_SWFW_PHY0_SM 0x2 ++#define E1000_SWFW_PHY1_SM 0x4 ++#define E1000_SWFW_CSR_SM 0x8 ++ ++/* FACTPS Definitions */ ++#define E1000_FACTPS_LFS 0x40000000 /* LAN Function Select */ ++/* Device Control */ ++#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ ++#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ ++#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ ++#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */ ++#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ ++#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ ++#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ ++#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ ++#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ ++#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ ++#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ ++#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ ++#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ ++#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ ++#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ ++#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ ++#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ ++#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ ++#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ ++#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */ ++#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */ ++#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ ++#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ ++#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ ++#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ ++#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ ++#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ ++#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ ++#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ ++#define E1000_CTRL_RST 0x04000000 /* Global reset */ ++#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ ++#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ ++#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ ++#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ ++#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ ++#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */ ++#define E1000_CTRL_I2C_ENA 0x02000000 /* I2C enable */ ++ ++/* Bit definitions for the Management Data IO (MDIO) and Management Data ++ * Clock (MDC) pins in the Device Control Register. ++ */ ++#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0 ++#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0 ++#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2 ++#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2 ++#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3 ++#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3 ++#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR ++#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA ++ ++#define E1000_CONNSW_ENRGSRC 0x4 ++#define E1000_PCS_CFG_PCS_EN 8 ++#define E1000_PCS_LCTL_FLV_LINK_UP 1 ++#define E1000_PCS_LCTL_FSV_10 0 ++#define E1000_PCS_LCTL_FSV_100 2 ++#define E1000_PCS_LCTL_FSV_1000 4 ++#define E1000_PCS_LCTL_FDV_FULL 8 ++#define E1000_PCS_LCTL_FSD 0x10 ++#define E1000_PCS_LCTL_FORCE_LINK 0x20 ++#define E1000_PCS_LCTL_LOW_LINK_LATCH 0x40 ++#define E1000_PCS_LCTL_FORCE_FCTRL 0x80 ++#define E1000_PCS_LCTL_AN_ENABLE 0x10000 ++#define E1000_PCS_LCTL_AN_RESTART 0x20000 ++#define E1000_PCS_LCTL_AN_TIMEOUT 0x40000 ++#define E1000_PCS_LCTL_AN_SGMII_BYPASS 0x80000 ++#define E1000_PCS_LCTL_AN_SGMII_TRIGGER 0x100000 ++#define E1000_PCS_LCTL_FAST_LINK_TIMER 0x1000000 ++#define E1000_PCS_LCTL_LINK_OK_FIX 0x2000000 ++#define E1000_PCS_LCTL_CRS_ON_NI 0x4000000 ++#define E1000_ENABLE_SERDES_LOOPBACK 0x0410 ++ ++#define E1000_PCS_LSTS_LINK_OK 1 ++#define E1000_PCS_LSTS_SPEED_10 0 ++#define E1000_PCS_LSTS_SPEED_100 2 ++#define E1000_PCS_LSTS_SPEED_1000 4 ++#define E1000_PCS_LSTS_DUPLEX_FULL 8 ++#define E1000_PCS_LSTS_SYNK_OK 0x10 ++#define E1000_PCS_LSTS_AN_COMPLETE 0x10000 ++#define E1000_PCS_LSTS_AN_PAGE_RX 0x20000 ++#define E1000_PCS_LSTS_AN_TIMED_OUT 0x40000 ++#define E1000_PCS_LSTS_AN_REMOTE_FAULT 0x80000 ++#define E1000_PCS_LSTS_AN_ERROR_RWS 0x100000 ++ ++/* Device Status */ ++#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ ++#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ ++#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ ++#define E1000_STATUS_FUNC_SHIFT 2 ++#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ ++#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ ++#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ ++#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ ++#define E1000_STATUS_SPEED_MASK 0x000000C0 ++#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ ++#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ ++#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ ++#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */ ++#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ ++#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */ ++#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ ++#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ ++#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ ++#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ ++#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ ++#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ ++#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */ ++#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */ ++#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */ ++#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */ ++#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution disabled */ ++#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */ ++#define E1000_STATUS_FUSE_8 0x04000000 ++#define E1000_STATUS_FUSE_9 0x08000000 ++#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */ ++#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */ ++ ++/* Constants used to interpret the masked PCI-X bus speed. */ ++#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ ++#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */ ++#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */ ++ ++#define SPEED_10 10 ++#define SPEED_100 100 ++#define SPEED_1000 1000 ++#define HALF_DUPLEX 1 ++#define FULL_DUPLEX 2 ++ ++#define PHY_FORCE_TIME 20 ++ ++#define ADVERTISE_10_HALF 0x0001 ++#define ADVERTISE_10_FULL 0x0002 ++#define ADVERTISE_100_HALF 0x0004 ++#define ADVERTISE_100_FULL 0x0008 ++#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ ++#define ADVERTISE_1000_FULL 0x0020 ++ ++/* 1000/H is not supported, nor spec-compliant. */ ++#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ ++ ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ ++ ADVERTISE_1000_FULL) ++#define E1000_ALL_NOT_GIG ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ ++ ADVERTISE_100_HALF | ADVERTISE_100_FULL) ++#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL) ++#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL) ++#define E1000_ALL_FULL_DUPLEX (ADVERTISE_10_FULL | ADVERTISE_100_FULL | \ ++ ADVERTISE_1000_FULL) ++#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF) ++ ++#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX ++ ++/* LED Control */ ++#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F ++#define E1000_LEDCTL_LED0_MODE_SHIFT 0 ++#define E1000_LEDCTL_LED0_BLINK_RATE 0x00000020 ++#define E1000_LEDCTL_LED0_IVRT 0x00000040 ++#define E1000_LEDCTL_LED0_BLINK 0x00000080 ++#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 ++#define E1000_LEDCTL_LED1_MODE_SHIFT 8 ++#define E1000_LEDCTL_LED1_BLINK_RATE 0x00002000 ++#define E1000_LEDCTL_LED1_IVRT 0x00004000 ++#define E1000_LEDCTL_LED1_BLINK 0x00008000 ++#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 ++#define E1000_LEDCTL_LED2_MODE_SHIFT 16 ++#define E1000_LEDCTL_LED2_BLINK_RATE 0x00200000 ++#define E1000_LEDCTL_LED2_IVRT 0x00400000 ++#define E1000_LEDCTL_LED2_BLINK 0x00800000 ++#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 ++#define E1000_LEDCTL_LED3_MODE_SHIFT 24 ++#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000 ++#define E1000_LEDCTL_LED3_IVRT 0x40000000 ++#define E1000_LEDCTL_LED3_BLINK 0x80000000 ++ ++#define E1000_LEDCTL_MODE_LINK_10_1000 0x0 ++#define E1000_LEDCTL_MODE_LINK_100_1000 0x1 ++#define E1000_LEDCTL_MODE_LINK_UP 0x2 ++#define E1000_LEDCTL_MODE_ACTIVITY 0x3 ++#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4 ++#define E1000_LEDCTL_MODE_LINK_10 0x5 ++#define E1000_LEDCTL_MODE_LINK_100 0x6 ++#define E1000_LEDCTL_MODE_LINK_1000 0x7 ++#define E1000_LEDCTL_MODE_PCIX_MODE 0x8 ++#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9 ++#define E1000_LEDCTL_MODE_COLLISION 0xA ++#define E1000_LEDCTL_MODE_BUS_SPEED 0xB ++#define E1000_LEDCTL_MODE_BUS_SIZE 0xC ++#define E1000_LEDCTL_MODE_PAUSED 0xD ++#define E1000_LEDCTL_MODE_LED_ON 0xE ++#define E1000_LEDCTL_MODE_LED_OFF 0xF ++ ++/* Transmit Descriptor bit definitions */ ++#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ ++#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ ++#define E1000_TXD_POPTS_SHIFT 8 /* POPTS shift */ ++#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ ++#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ ++#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ ++#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ ++#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ ++#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ ++#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ ++#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ ++#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ ++#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ ++#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ ++#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ ++#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ ++#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ ++#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ ++#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ ++#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ ++#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ ++/* Extended desc bits for Linksec and timesync */ ++#define E1000_TXD_CMD_LINKSEC 0x10000000 /* Apply LinkSec on packet */ ++#define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */ ++ ++/* Transmit Control */ ++#define E1000_TCTL_RST 0x00000001 /* software reset */ ++#define E1000_TCTL_EN 0x00000002 /* enable tx */ ++#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ ++#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ ++#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ ++#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ ++#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ ++#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ ++#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ ++#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ ++#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ ++ ++/* Transmit Arbitration Count */ ++#define E1000_TARC0_ENABLE 0x00000400 /* Enable Tx Queue 0 */ ++ ++/* SerDes Control */ ++#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400 ++ ++/* Receive Checksum Control */ ++#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ ++#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ ++#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ ++#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */ ++#define E1000_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */ ++#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ ++#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ ++ ++/* Header split receive */ ++#define E1000_RFCTL_ISCSI_DIS 0x00000001 ++#define E1000_RFCTL_ISCSI_DWC_MASK 0x0000003E ++#define E1000_RFCTL_ISCSI_DWC_SHIFT 1 ++#define E1000_RFCTL_NFSW_DIS 0x00000040 ++#define E1000_RFCTL_NFSR_DIS 0x00000080 ++#define E1000_RFCTL_NFS_VER_MASK 0x00000300 ++#define E1000_RFCTL_NFS_VER_SHIFT 8 ++#define E1000_RFCTL_IPV6_DIS 0x00000400 ++#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800 ++#define E1000_RFCTL_ACK_DIS 0x00001000 ++#define E1000_RFCTL_ACKD_DIS 0x00002000 ++#define E1000_RFCTL_IPFRSP_DIS 0x00004000 ++#define E1000_RFCTL_EXTEN 0x00008000 ++#define E1000_RFCTL_IPV6_EX_DIS 0x00010000 ++#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 ++#define E1000_RFCTL_LEF 0x00040000 ++ ++/* Collision related configuration parameters */ ++#define E1000_COLLISION_THRESHOLD 15 ++#define E1000_CT_SHIFT 4 ++#define E1000_COLLISION_DISTANCE 63 ++#define E1000_COLD_SHIFT 12 ++ ++/* Default values for the transmit IPG register */ ++#define DEFAULT_82543_TIPG_IPGT_FIBER 9 ++#define DEFAULT_82543_TIPG_IPGT_COPPER 8 ++ ++#define E1000_TIPG_IPGT_MASK 0x000003FF ++#define E1000_TIPG_IPGR1_MASK 0x000FFC00 ++#define E1000_TIPG_IPGR2_MASK 0x3FF00000 ++ ++#define DEFAULT_82543_TIPG_IPGR1 8 ++#define E1000_TIPG_IPGR1_SHIFT 10 ++ ++#define DEFAULT_82543_TIPG_IPGR2 6 ++#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7 ++#define E1000_TIPG_IPGR2_SHIFT 20 ++ ++/* Ethertype field values */ ++#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ ++ ++#define ETHERNET_FCS_SIZE 4 ++#define MAX_JUMBO_FRAME_SIZE 0x3F00 ++ ++/* Extended Configuration Control and Size */ ++#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 ++#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 ++#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 ++#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 ++#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 ++#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000 ++#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16 ++ ++#define E1000_PHY_CTRL_SPD_EN 0x00000001 ++#define E1000_PHY_CTRL_D0A_LPLU 0x00000002 ++#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004 ++#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008 ++#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040 ++ ++#define E1000_KABGTXD_BGSQLBIAS 0x00050000 ++ ++/* PBA constants */ ++#define E1000_PBA_6K 0x0006 /* 6KB */ ++#define E1000_PBA_8K 0x0008 /* 8KB */ ++#define E1000_PBA_12K 0x000C /* 12KB */ ++#define E1000_PBA_16K 0x0010 /* 16KB */ ++#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 */ ++#define E1000_PBA_64K 0x0040 /* 64KB */ ++ ++#define E1000_PBS_16K E1000_PBA_16K ++#define E1000_PBS_24K E1000_PBA_24K ++ ++#define IFS_MAX 80 ++#define IFS_MIN 40 ++#define IFS_RATIO 4 ++#define IFS_STEP 10 ++#define MIN_NUM_XMITS 1000 ++ ++/* SW Semaphore Register */ ++#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ ++#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ ++#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */ ++#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ ++ ++/* Interrupt Cause Read */ ++#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ ++#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ ++#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ ++#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ ++#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ ++#define E1000_ICR_RXO 0x00000040 /* rx overrun */ ++#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ ++#define E1000_ICR_VMMB 0x00000100 /* VM MB event */ ++#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ ++#define E1000_ICR_RXCFG 0x00000400 /* Rx /c/ ordered set */ ++#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ ++#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ ++#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ ++#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ ++#define E1000_ICR_TXD_LOW 0x00008000 ++#define E1000_ICR_SRPD 0x00010000 ++#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ ++#define E1000_ICR_MNG 0x00040000 /* Manageability event */ ++#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ ++#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ ++#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */ ++#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */ ++#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity error */ ++#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ ++#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */ ++#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */ ++#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ ++#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */ ++#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */ ++#define E1000_ICR_EPRST 0x00100000 /* ME hardware reset occurs */ ++#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */ ++#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */ ++#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */ ++#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ ++#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ ++ ++/* Extended Interrupt Cause Read */ ++#define E1000_EICR_RX_QUEUE0 0x00000001 /* Rx Queue 0 Interrupt */ ++#define E1000_EICR_RX_QUEUE1 0x00000002 /* Rx Queue 1 Interrupt */ ++#define E1000_EICR_RX_QUEUE2 0x00000004 /* Rx Queue 2 Interrupt */ ++#define E1000_EICR_RX_QUEUE3 0x00000008 /* Rx Queue 3 Interrupt */ ++#define E1000_EICR_TX_QUEUE0 0x00000100 /* Tx Queue 0 Interrupt */ ++#define E1000_EICR_TX_QUEUE1 0x00000200 /* Tx Queue 1 Interrupt */ ++#define E1000_EICR_TX_QUEUE2 0x00000400 /* Tx Queue 2 Interrupt */ ++#define E1000_EICR_TX_QUEUE3 0x00000800 /* Tx Queue 3 Interrupt */ ++#define E1000_EICR_TCP_TIMER 0x40000000 /* TCP Timer */ ++#define E1000_EICR_OTHER 0x80000000 /* Interrupt Cause Active */ ++/* TCP Timer */ ++#define E1000_TCPTIMER_KS 0x00000100 /* KickStart */ ++#define E1000_TCPTIMER_COUNT_ENABLE 0x00000200 /* Count Enable */ ++#define E1000_TCPTIMER_COUNT_FINISH 0x00000400 /* Count finish */ ++#define E1000_TCPTIMER_LOOP 0x00000800 /* Loop */ ++ ++/* ++ * This defines the bits that are set in the Interrupt Mask ++ * Set/Read Register. Each bit is documented below: ++ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) ++ * o RXSEQ = Receive Sequence Error ++ */ ++#define POLL_IMS_ENABLE_MASK ( \ ++ E1000_IMS_RXDMT0 | \ ++ E1000_IMS_RXSEQ) ++ ++/* ++ * This defines the bits that are set in the Interrupt Mask ++ * Set/Read Register. Each bit is documented below: ++ * o RXT0 = Receiver Timer Interrupt (ring 0) ++ * o TXDW = Transmit Descriptor Written Back ++ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) ++ * o RXSEQ = Receive Sequence Error ++ * o LSC = Link Status Change ++ */ ++#define IMS_ENABLE_MASK ( \ ++ E1000_IMS_RXT0 | \ ++ E1000_IMS_TXDW | \ ++ E1000_IMS_RXDMT0 | \ ++ E1000_IMS_RXSEQ | \ ++ E1000_IMS_LSC) ++ ++/* Interrupt Mask Set */ ++#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ ++#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ ++#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ ++#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ ++#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ ++#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ ++#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ ++#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ ++#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */ ++#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ ++#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ ++#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ ++#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ ++#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW ++#define E1000_IMS_SRPD E1000_ICR_SRPD ++#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ ++#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ ++#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ ++#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ ++#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ ++#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ ++#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ ++#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ ++#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ ++#define E1000_IMS_DSW E1000_ICR_DSW ++#define E1000_IMS_PHYINT E1000_ICR_PHYINT ++#define E1000_IMS_EPRST E1000_ICR_EPRST ++#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */ ++#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */ ++#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */ ++#define E1000_IMS_TXQ1 E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */ ++#define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */ ++ ++/* Extended Interrupt Mask Set */ ++#define E1000_EIMS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */ ++#define E1000_EIMS_RX_QUEUE1 E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */ ++#define E1000_EIMS_RX_QUEUE2 E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */ ++#define E1000_EIMS_RX_QUEUE3 E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */ ++#define E1000_EIMS_TX_QUEUE0 E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */ ++#define E1000_EIMS_TX_QUEUE1 E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */ ++#define E1000_EIMS_TX_QUEUE2 E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */ ++#define E1000_EIMS_TX_QUEUE3 E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */ ++#define E1000_EIMS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */ ++#define E1000_EIMS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */ ++ ++/* Interrupt Cause Set */ ++#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ ++#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ ++#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ ++#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ ++#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ ++#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ ++#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ ++#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ ++#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */ ++#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ ++#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ ++#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ ++#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ ++#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW ++#define E1000_ICS_SRPD E1000_ICR_SRPD ++#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ ++#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ ++#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ ++#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ ++#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ ++#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ ++#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ ++#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ ++#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ ++#define E1000_ICS_DSW E1000_ICR_DSW ++#define E1000_ICS_PHYINT E1000_ICR_PHYINT ++#define E1000_ICS_EPRST E1000_ICR_EPRST ++ ++/* Extended Interrupt Cause Set */ ++#define E1000_EICS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */ ++#define E1000_EICS_RX_QUEUE1 E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */ ++#define E1000_EICS_RX_QUEUE2 E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */ ++#define E1000_EICS_RX_QUEUE3 E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */ ++#define E1000_EICS_TX_QUEUE0 E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */ ++#define E1000_EICS_TX_QUEUE1 E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */ ++#define E1000_EICS_TX_QUEUE2 E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */ ++#define E1000_EICS_TX_QUEUE3 E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */ ++#define E1000_EICS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */ ++#define E1000_EICS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */ ++ ++/* Transmit Descriptor Control */ ++#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */ ++#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */ ++#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */ ++#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ ++#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ ++#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ ++#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */ ++/* Enable the counting of descriptors still to be processed. */ ++#define E1000_TXDCTL_COUNT_DESC 0x00400000 ++ ++/* Flow Control Constants */ ++#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 ++#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 ++#define FLOW_CONTROL_TYPE 0x8808 ++ ++/* 802.1q VLAN Packet Size */ ++#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMA'd) */ ++#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ ++ ++/* Receive Address */ ++/* ++ * Number of high/low register pairs in the RAR. The RAR (Receive Address ++ * Registers) holds the directed and multicast addresses that we monitor. ++ * Technically, we have 16 spots. However, we reserve one of these spots ++ * (RAR[15]) for our directed address used by controllers with ++ * manageability enabled, allowing us room for 15 multicast addresses. ++ */ ++#define E1000_RAR_ENTRIES 15 ++#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ ++ ++/* Error Codes */ ++#define E1000_SUCCESS 0 ++#define E1000_ERR_NVM 1 ++#define E1000_ERR_PHY 2 ++#define E1000_ERR_CONFIG 3 ++#define E1000_ERR_PARAM 4 ++#define E1000_ERR_MAC_INIT 5 ++#define E1000_ERR_PHY_TYPE 6 ++#define E1000_ERR_RESET 9 ++#define E1000_ERR_MASTER_REQUESTS_PENDING 10 ++#define E1000_ERR_HOST_INTERFACE_COMMAND 11 ++#define E1000_BLK_PHY_RESET 12 ++#define E1000_ERR_SWFW_SYNC 13 ++#define E1000_NOT_IMPLEMENTED 14 ++ ++/* Loop limit on how long we wait for auto-negotiation to complete */ ++#define FIBER_LINK_UP_LIMIT 50 ++#define COPPER_LINK_UP_LIMIT 10 ++#define PHY_AUTO_NEG_LIMIT 45 ++#define PHY_FORCE_LIMIT 20 ++/* Number of 100 microseconds we wait for PCI Express master disable */ ++#define MASTER_DISABLE_TIMEOUT 800 ++/* Number of milliseconds we wait for PHY configuration done after MAC reset */ ++#define PHY_CFG_TIMEOUT 100 ++/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */ ++#define MDIO_OWNERSHIP_TIMEOUT 10 ++/* Number of milliseconds for NVM auto read done after MAC reset. */ ++#define AUTO_READ_DONE_TIMEOUT 10 ++ ++/* Flow Control */ ++#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ ++#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */ ++#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ ++#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ ++ ++/* Transmit Configuration Word */ ++#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ ++#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ ++#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ ++#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ ++#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ ++#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */ ++#define E1000_TXCW_NP 0x00008000 /* TXCW next page */ ++#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */ ++#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */ ++#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ ++ ++/* Receive Configuration Word */ ++#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */ ++#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */ ++#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ ++#define E1000_RXCW_CC 0x10000000 /* Receive config change */ ++#define E1000_RXCW_C 0x20000000 /* Receive config */ ++#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ ++#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ ++ ++/* PCI Express Control */ ++#define E1000_GCR_RXD_NO_SNOOP 0x00000001 ++#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 ++#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 ++#define E1000_GCR_TXD_NO_SNOOP 0x00000008 ++#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 ++#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 ++ ++#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ ++ E1000_GCR_RXDSCW_NO_SNOOP | \ ++ E1000_GCR_RXDSCR_NO_SNOOP | \ ++ E1000_GCR_TXD_NO_SNOOP | \ ++ E1000_GCR_TXDSCW_NO_SNOOP | \ ++ E1000_GCR_TXDSCR_NO_SNOOP) ++ ++/* PHY Control Register */ ++#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ ++#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ ++#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ ++#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ ++#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ ++#define MII_CR_POWER_DOWN 0x0800 /* Power down */ ++#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ ++#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ ++#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ ++#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ ++#define MII_CR_SPEED_1000 0x0040 ++#define MII_CR_SPEED_100 0x2000 ++#define MII_CR_SPEED_10 0x0000 ++ ++/* PHY Status Register */ ++#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ ++#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ ++#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ ++#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ ++#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ ++#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ ++#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ ++#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ ++#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ ++#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ ++#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ ++#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ ++#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ ++#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ ++#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ ++ ++/* Autoneg Advertisement Register */ ++#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ ++#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ ++#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ ++#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ ++#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ ++#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ ++#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ ++#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ ++#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ ++#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ ++ ++/* Link Partner Ability Register (Base Page) */ ++#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ ++#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ ++#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ ++#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ ++#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ ++#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ ++#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ ++#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ ++#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ ++#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ ++#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ ++ ++/* Autoneg Expansion Register */ ++#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ ++#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ ++#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ ++#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ ++#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */ ++ ++/* 1000BASE-T Control Register */ ++#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ ++#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ ++#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ ++#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ ++ /* 0=DTE device */ ++#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ ++ /* 0=Configure PHY as Slave */ ++#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ ++ /* 0=Automatic Master/Slave config */ ++#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ ++#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ ++#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ ++#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ ++#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ ++ ++/* 1000BASE-T Status Register */ ++#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ ++#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ ++#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ ++#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ ++#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ ++#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ ++#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local Tx is Master, 0=Slave */ ++#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ ++ ++#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5 ++ ++/* PHY 1000 MII Register/Bit Definitions */ ++/* PHY Registers defined by IEEE */ ++#define PHY_CONTROL 0x00 /* Control Register */ ++#define PHY_STATUS 0x01 /* Status Register */ ++#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ ++#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ ++#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ ++#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ ++#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ ++#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */ ++#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ ++#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ ++#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ ++#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ ++ ++/* NVM Control */ ++#define E1000_EECD_SK 0x00000001 /* NVM Clock */ ++#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ ++#define E1000_EECD_DI 0x00000004 /* NVM Data In */ ++#define E1000_EECD_DO 0x00000008 /* NVM Data Out */ ++#define E1000_EECD_FWE_MASK 0x00000030 ++#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ ++#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ ++#define E1000_EECD_FWE_SHIFT 4 ++#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */ ++#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ ++#define E1000_EECD_PRES 0x00000100 /* NVM Present */ ++#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */ ++/* NVM Addressing bits based on type 0=small, 1=large */ ++#define E1000_EECD_ADDR_BITS 0x00000400 ++#define E1000_EECD_TYPE 0x00002000 /* NVM Type (1-SPI, 0-Microwire) */ ++#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */ ++#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ ++#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ ++#define E1000_EECD_SIZE_EX_SHIFT 11 ++#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */ ++#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */ ++#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */ ++#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ ++#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ ++#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ ++#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ ++#define E1000_EECD_SECVAL_SHIFT 22 ++ ++#define E1000_NVM_SWDPIN0 0x0001 /* SWDPIN 0 NVM Value */ ++#define E1000_NVM_LED_LOGIC 0x0020 /* Led Logic Word */ ++#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write registers */ ++#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ ++#define E1000_NVM_RW_REG_START 1 /* Start operation */ ++#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ ++#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */ ++#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */ ++#define E1000_FLASH_UPDATES 2000 ++ ++/* NVM Word Offsets */ ++#define NVM_COMPAT 0x0003 ++#define NVM_ID_LED_SETTINGS 0x0004 ++#define NVM_VERSION 0x0005 ++#define NVM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */ ++#define NVM_PHY_CLASS_WORD 0x0007 ++#define NVM_INIT_CONTROL1_REG 0x000A ++#define NVM_INIT_CONTROL2_REG 0x000F ++#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010 ++#define NVM_INIT_CONTROL3_PORT_B 0x0014 ++#define NVM_INIT_3GIO_3 0x001A ++#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020 ++#define NVM_INIT_CONTROL3_PORT_A 0x0024 ++#define NVM_CFG 0x0012 ++#define NVM_FLASH_VERSION 0x0032 ++#define NVM_ALT_MAC_ADDR_PTR 0x0037 ++#define NVM_CHECKSUM_REG 0x003F ++ ++#define E1000_NVM_CFG_DONE_PORT_0 0x40000 /* MNG config cycle done */ ++#define E1000_NVM_CFG_DONE_PORT_1 0x80000 /* ...for second port */ ++ ++/* Mask bits for fields in Word 0x0f of the NVM */ ++#define NVM_WORD0F_PAUSE_MASK 0x3000 ++#define NVM_WORD0F_PAUSE 0x1000 ++#define NVM_WORD0F_ASM_DIR 0x2000 ++#define NVM_WORD0F_ANE 0x0800 ++#define NVM_WORD0F_SWPDIO_EXT_MASK 0x00F0 ++#define NVM_WORD0F_LPLU 0x0001 ++ ++/* Mask bits for fields in Word 0x1a of the NVM */ ++#define NVM_WORD1A_ASPM_MASK 0x000C ++ ++/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ ++#define NVM_SUM 0xBABA ++ ++#define NVM_MAC_ADDR_OFFSET 0 ++#define NVM_PBA_OFFSET_0 8 ++#define NVM_PBA_OFFSET_1 9 ++#define NVM_RESERVED_WORD 0xFFFF ++#define NVM_PHY_CLASS_A 0x8000 ++#define NVM_SERDES_AMPLITUDE_MASK 0x000F ++#define NVM_SIZE_MASK 0x1C00 ++#define NVM_SIZE_SHIFT 10 ++#define NVM_WORD_SIZE_BASE_SHIFT 6 ++#define NVM_SWDPIO_EXT_SHIFT 4 ++ ++/* NVM Commands - Microwire */ ++#define NVM_READ_OPCODE_MICROWIRE 0x6 /* NVM read opcode */ ++#define NVM_WRITE_OPCODE_MICROWIRE 0x5 /* NVM write opcode */ ++#define NVM_ERASE_OPCODE_MICROWIRE 0x7 /* NVM erase opcode */ ++#define NVM_EWEN_OPCODE_MICROWIRE 0x13 /* NVM erase/write enable */ ++#define NVM_EWDS_OPCODE_MICROWIRE 0x10 /* NVM erase/write disable */ ++ ++/* NVM Commands - SPI */ ++#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ ++#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */ ++#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */ ++#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */ ++#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */ ++#define NVM_WRDI_OPCODE_SPI 0x04 /* NVM reset Write Enable latch */ ++#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */ ++#define NVM_WRSR_OPCODE_SPI 0x01 /* NVM write Status register */ ++ ++/* SPI NVM Status Register */ ++#define NVM_STATUS_RDY_SPI 0x01 ++#define NVM_STATUS_WEN_SPI 0x02 ++#define NVM_STATUS_BP0_SPI 0x04 ++#define NVM_STATUS_BP1_SPI 0x08 ++#define NVM_STATUS_WPEN_SPI 0x80 ++ ++/* Word definitions for ID LED Settings */ ++#define ID_LED_RESERVED_0000 0x0000 ++#define ID_LED_RESERVED_FFFF 0xFFFF ++#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \ ++ (ID_LED_OFF1_OFF2 << 8) | \ ++ (ID_LED_DEF1_DEF2 << 4) | \ ++ (ID_LED_DEF1_DEF2)) ++#define ID_LED_DEF1_DEF2 0x1 ++#define ID_LED_DEF1_ON2 0x2 ++#define ID_LED_DEF1_OFF2 0x3 ++#define ID_LED_ON1_DEF2 0x4 ++#define ID_LED_ON1_ON2 0x5 ++#define ID_LED_ON1_OFF2 0x6 ++#define ID_LED_OFF1_DEF2 0x7 ++#define ID_LED_OFF1_ON2 0x8 ++#define ID_LED_OFF1_OFF2 0x9 ++ ++#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF ++#define IGP_ACTIVITY_LED_ENABLE 0x0300 ++#define IGP_LED3_MODE 0x07000000 ++ ++/* PCI/PCI-X/PCI-EX Config space */ ++#define PCIX_COMMAND_REGISTER 0xE6 ++#define PCIX_STATUS_REGISTER_LO 0xE8 ++#define PCIX_STATUS_REGISTER_HI 0xEA ++#define PCI_HEADER_TYPE_REGISTER 0x0E ++#define PCIE_LINK_STATUS 0x12 ++ ++#define PCIX_COMMAND_MMRBC_MASK 0x000C ++#define PCIX_COMMAND_MMRBC_SHIFT 0x2 ++#define PCIX_STATUS_HI_MMRBC_MASK 0x0060 ++#define PCIX_STATUS_HI_MMRBC_SHIFT 0x5 ++#define PCIX_STATUS_HI_MMRBC_4K 0x3 ++#define PCIX_STATUS_HI_MMRBC_2K 0x2 ++#define PCIX_STATUS_LO_FUNC_MASK 0x7 ++#define PCI_HEADER_TYPE_MULTIFUNC 0x80 ++#define PCIE_LINK_WIDTH_MASK 0x3F0 ++#define PCIE_LINK_WIDTH_SHIFT 4 ++ ++#ifndef ETH_ADDR_LEN ++#define ETH_ADDR_LEN 6 ++#endif ++ ++#define PHY_REVISION_MASK 0xFFFFFFF0 ++#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ ++#define MAX_PHY_MULTI_PAGE_REG 0xF ++ ++/* Bit definitions for valid PHY IDs. */ ++/* ++ * I = Integrated ++ * E = External ++ */ ++#define M88E1000_E_PHY_ID 0x01410C50 ++#define M88E1000_I_PHY_ID 0x01410C30 ++#define M88E1011_I_PHY_ID 0x01410C20 ++#define IGP01E1000_I_PHY_ID 0x02A80380 ++#define M88E1011_I_REV_4 0x04 ++#define M88E1111_I_PHY_ID 0x01410CC0 ++#define GG82563_E_PHY_ID 0x01410CA0 ++#define IGP03E1000_E_PHY_ID 0x02A80390 ++#define IFE_E_PHY_ID 0x02A80330 ++#define IFE_PLUS_E_PHY_ID 0x02A80320 ++#define IFE_C_E_PHY_ID 0x02A80310 ++#define BME1000_E_PHY_ID 0x01410CB0 ++#define BME1000_E_PHY_ID_R2 0x01410CB1 ++#define M88_VENDOR 0x0141 ++ ++/* M88E1000 Specific Registers */ ++#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ ++#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ ++#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ ++#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ ++#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ ++#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ ++ ++#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */ ++#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ ++#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ ++#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */ ++#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */ ++ ++/* M88E1000 PHY Specific Control Register */ ++#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ ++#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ ++#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ ++/* 1=CLK125 low, 0=CLK125 toggling */ ++#define M88E1000_PSCR_CLK125_DISABLE 0x0010 ++#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ ++ /* Manual MDI configuration */ ++#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ ++/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ ++#define M88E1000_PSCR_AUTO_X_1000T 0x0040 ++/* Auto crossover enabled all speeds */ ++#define M88E1000_PSCR_AUTO_X_MODE 0x0060 ++/* ++ * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold ++ * 0=Normal 10BASE-T Rx Threshold ++ */ ++#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080 ++/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ ++#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 ++#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ ++#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ ++#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ ++ ++/* M88E1000 PHY Specific Status Register */ ++#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ ++#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ ++#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */ ++#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ ++/* ++ * 0 = <50M ++ * 1 = 50-80M ++ * 2 = 80-110M ++ * 3 = 110-140M ++ * 4 = >140M ++ */ ++#define M88E1000_PSSR_CABLE_LENGTH 0x0380 ++#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */ ++#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ ++#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */ ++#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ ++#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ ++#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */ ++#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */ ++#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ ++ ++#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 ++ ++/* M88E1000 Extended PHY Specific Control Register */ ++#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */ ++/* ++ * 1 = Lost lock detect enabled. ++ * Will assert lost lock and bring ++ * link down if idle not seen ++ * within 1ms in 1000BASE-T ++ */ ++#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 ++/* ++ * Number of times we will attempt to autonegotiate before downshifting if we ++ * are the master ++ */ ++#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00 ++#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 ++#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400 ++#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800 ++#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00 ++/* ++ * Number of times we will attempt to autonegotiate before downshifting if we ++ * are the slave ++ */ ++#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300 ++#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000 ++#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100 ++#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200 ++#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300 ++#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */ ++#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ ++#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ ++ ++/* M88EC018 Rev 2 specific DownShift settings */ ++#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 ++#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000 ++#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200 ++#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400 ++#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600 ++#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 ++#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00 ++#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00 ++#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00 ++ ++/* BME1000 PHY Specific Control Register */ ++#define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */ ++ ++/* ++ * Bits... ++ * 15-5: page ++ * 4-0: register offset ++ */ ++#define GG82563_PAGE_SHIFT 5 ++#define GG82563_REG(page, reg) \ ++ (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) ++#define GG82563_MIN_ALT_REG 30 ++ ++/* GG82563 Specific Registers */ ++#define GG82563_PHY_SPEC_CTRL \ ++ GG82563_REG(0, 16) /* PHY Specific Control */ ++#define GG82563_PHY_SPEC_STATUS \ ++ GG82563_REG(0, 17) /* PHY Specific Status */ ++#define GG82563_PHY_INT_ENABLE \ ++ GG82563_REG(0, 18) /* Interrupt Enable */ ++#define GG82563_PHY_SPEC_STATUS_2 \ ++ GG82563_REG(0, 19) /* PHY Specific Status 2 */ ++#define GG82563_PHY_RX_ERR_CNTR \ ++ GG82563_REG(0, 21) /* Receive Error Counter */ ++#define GG82563_PHY_PAGE_SELECT \ ++ GG82563_REG(0, 22) /* Page Select */ ++#define GG82563_PHY_SPEC_CTRL_2 \ ++ GG82563_REG(0, 26) /* PHY Specific Control 2 */ ++#define GG82563_PHY_PAGE_SELECT_ALT \ ++ GG82563_REG(0, 29) /* Alternate Page Select */ ++#define GG82563_PHY_TEST_CLK_CTRL \ ++ GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */ ++ ++#define GG82563_PHY_MAC_SPEC_CTRL \ ++ GG82563_REG(2, 21) /* MAC Specific Control Register */ ++#define GG82563_PHY_MAC_SPEC_CTRL_2 \ ++ GG82563_REG(2, 26) /* MAC Specific Control 2 */ ++ ++#define GG82563_PHY_DSP_DISTANCE \ ++ GG82563_REG(5, 26) /* DSP Distance */ ++ ++/* Page 193 - Port Control Registers */ ++#define GG82563_PHY_KMRN_MODE_CTRL \ ++ GG82563_REG(193, 16) /* Kumeran Mode Control */ ++#define GG82563_PHY_PORT_RESET \ ++ GG82563_REG(193, 17) /* Port Reset */ ++#define GG82563_PHY_REVISION_ID \ ++ GG82563_REG(193, 18) /* Revision ID */ ++#define GG82563_PHY_DEVICE_ID \ ++ GG82563_REG(193, 19) /* Device ID */ ++#define GG82563_PHY_PWR_MGMT_CTRL \ ++ GG82563_REG(193, 20) /* Power Management Control */ ++#define GG82563_PHY_RATE_ADAPT_CTRL \ ++ GG82563_REG(193, 25) /* Rate Adaptation Control */ ++ ++/* Page 194 - KMRN Registers */ ++#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \ ++ GG82563_REG(194, 16) /* FIFO's Control/Status */ ++#define GG82563_PHY_KMRN_CTRL \ ++ GG82563_REG(194, 17) /* Control */ ++#define GG82563_PHY_INBAND_CTRL \ ++ GG82563_REG(194, 18) /* Inband Control */ ++#define GG82563_PHY_KMRN_DIAGNOSTIC \ ++ GG82563_REG(194, 19) /* Diagnostic */ ++#define GG82563_PHY_ACK_TIMEOUTS \ ++ GG82563_REG(194, 20) /* Acknowledge Timeouts */ ++#define GG82563_PHY_ADV_ABILITY \ ++ GG82563_REG(194, 21) /* Advertised Ability */ ++#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \ ++ GG82563_REG(194, 23) /* Link Partner Advertised Ability */ ++#define GG82563_PHY_ADV_NEXT_PAGE \ ++ GG82563_REG(194, 24) /* Advertised Next Page */ ++#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \ ++ GG82563_REG(194, 25) /* Link Partner Advertised Next page */ ++#define GG82563_PHY_KMRN_MISC \ ++ GG82563_REG(194, 26) /* Misc. */ ++ ++/* MDI Control */ ++#define E1000_MDIC_DATA_MASK 0x0000FFFF ++#define E1000_MDIC_REG_MASK 0x001F0000 ++#define E1000_MDIC_REG_SHIFT 16 ++#define E1000_MDIC_PHY_MASK 0x03E00000 ++#define E1000_MDIC_PHY_SHIFT 21 ++#define E1000_MDIC_OP_WRITE 0x04000000 ++#define E1000_MDIC_OP_READ 0x08000000 ++#define E1000_MDIC_READY 0x10000000 ++#define E1000_MDIC_INT_EN 0x20000000 ++#define E1000_MDIC_ERROR 0x40000000 ++ ++/* SerDes Control */ ++#define E1000_GEN_CTL_READY 0x80000000 ++#define E1000_GEN_CTL_ADDRESS_SHIFT 8 ++#define E1000_GEN_POLL_TIMEOUT 640 ++ ++#endif +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000.h linux-2.6.22-10/drivers/net/e1000e/e1000.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,447 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++/* Linux PRO/1000 Ethernet Driver main header file */ ++ ++#ifndef _E1000_H_ ++#define _E1000_H_ ++ ++#include ++#include ++#include ++#include ++ ++#include "kcompat.h" ++ ++#include "e1000_hw.h" ++ ++struct e1000_info; ++ ++#define e_printk(level, adapter, format, arg...) \ ++ printk(level "%s: %s: " format, pci_name(adapter->pdev), \ ++ (strchr(adapter->netdev->name, '%') ? "" : \ ++ adapter->netdev->name), ## arg) ++ ++#define e_dbg(format, arg...) do { (void)(adapter); } while (0) ++ ++#define e_err(format, arg...) \ ++ e_printk(KERN_ERR, adapter, format, ## arg) ++#define e_info(format, arg...) \ ++ e_printk(KERN_INFO, adapter, format, ## arg) ++#define e_warn(format, arg...) \ ++ e_printk(KERN_WARNING, adapter, format, ## arg) ++#define e_notice(format, arg...) \ ++ e_printk(KERN_NOTICE, adapter, format, ## arg) ++ ++ ++#ifdef CONFIG_E1000E_MSIX ++/* Interrupt modes, as used by the IntMode paramter */ ++#define E1000E_INT_MODE_LEGACY 0 ++#define E1000E_INT_MODE_MSI 1 ++#define E1000E_INT_MODE_MSIX 2 ++ ++#endif /* CONFIG_E1000E_MSIX */ ++ ++#define E1000_MAX_INTR 10 ++ ++/* Tx/Rx descriptor defines */ ++#define E1000_DEFAULT_TXD 256 ++#define E1000_MAX_TXD 4096 ++#define E1000_MIN_TXD 80 ++ ++#define E1000_DEFAULT_RXD 256 ++#define E1000_MAX_RXD 4096 ++#define E1000_MIN_RXD 80 ++ ++#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */ ++#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */ ++ ++/* Early Receive defines */ ++#define E1000_ERT_2048 0x100 ++ ++#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ ++ ++/* How many Tx Descriptors do we need to call netif_wake_queue ? */ ++/* How many Rx Buffers do we bundle into one write to the hardware ? */ ++#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */ ++ ++#define AUTO_ALL_MODES 0 ++#define E1000_EEPROM_APME 0x0400 ++ ++#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) ++ ++enum e1000_boards { ++ board_82571, ++ board_82572, ++ board_82573, ++ board_82574, ++ board_80003es2lan, ++ board_ich8lan, ++ board_ich9lan, ++ board_ich10lan, ++}; ++ ++struct e1000_queue_stats { ++ u64 packets; ++ u64 bytes; ++}; ++ ++struct e1000_ps_page { ++ struct page *page; ++ u64 dma; /* must be u64 - written to hw */ ++}; ++ ++/* ++ * wrappers around a pointer to a socket buffer, ++ * so a DMA handle can be stored along with the buffer ++ */ ++struct e1000_buffer { ++ dma_addr_t dma; ++ struct sk_buff *skb; ++ union { ++ /* Tx */ ++ struct { ++ unsigned long time_stamp; ++ u16 length; ++ u16 next_to_watch; ++ }; ++ /* Rx */ ++ /* arrays of page information for packet split */ ++ struct e1000_ps_page *ps_pages; ++ }; ++ struct page *page; ++}; ++ ++struct e1000_ring { ++ void *desc; /* pointer to ring memory */ ++ dma_addr_t dma; /* phys address of ring */ ++ unsigned int size; /* length of ring in bytes */ ++ unsigned int count; /* number of desc. in ring */ ++ ++ u16 next_to_use; ++ u16 next_to_clean; ++ ++ u16 head; ++ u16 tail; ++ ++ /* array of buffer information structs */ ++ struct e1000_buffer *buffer_info; ++ ++#ifdef CONFIG_E1000E_MSIX ++ char name[IFNAMSIZ + 5]; ++ u32 ims_val; ++ u32 itr_val; ++ u16 itr_register; ++ int set_itr; ++ ++#endif /* CONFIG_E1000E_MSIX */ ++ struct sk_buff *rx_skb_top; ++ ++ struct e1000_queue_stats stats; ++}; ++ ++#ifdef SIOCGMIIPHY ++/* PHY register snapshot values */ ++struct e1000_phy_regs { ++ u16 bmcr; /* basic mode control register */ ++ u16 bmsr; /* basic mode status register */ ++ u16 advertise; /* auto-negotiation advertisement */ ++ u16 lpa; /* link partner ability register */ ++ u16 expansion; /* auto-negotiation expansion reg */ ++ u16 ctrl1000; /* 1000BASE-T control register */ ++ u16 stat1000; /* 1000BASE-T status register */ ++ u16 estatus; /* extended status register */ ++}; ++#endif ++ ++/* board specific private data structure */ ++struct e1000_adapter { ++ struct timer_list watchdog_timer; ++ struct timer_list phy_info_timer; ++ struct timer_list blink_timer; ++ ++ struct work_struct reset_task; ++ struct work_struct watchdog_task; ++ ++ const struct e1000_info *ei; ++ ++ struct vlan_group *vlgrp; ++ u32 bd_number; ++ u32 rx_buffer_len; ++ u16 mng_vlan_id; ++ u16 link_speed; ++ u16 link_duplex; ++ ++ spinlock_t tx_queue_lock; /* prevent concurrent tail updates */ ++ ++ /* track device up/down/testing state */ ++ unsigned long state; ++ ++ /* Interrupt Throttle Rate */ ++ u32 itr; ++ u32 itr_setting; ++ u16 tx_itr; ++ u16 rx_itr; ++ ++ /* ++ * Tx ++ */ ++ struct e1000_ring *tx_ring /* One per active queue */ ++ ____cacheline_aligned_in_smp; ++ ++#ifdef CONFIG_E1000E_NAPI ++ struct napi_struct napi; ++#endif ++ ++ unsigned long tx_queue_len; ++ unsigned int restart_queue; ++ u32 txd_cmd; ++ ++ bool detect_tx_hung; ++ u8 tx_timeout_factor; ++ ++ u32 tx_int_delay; ++ u32 tx_abs_int_delay; ++ ++ unsigned int total_tx_bytes; ++ unsigned int total_tx_packets; ++ unsigned int total_rx_bytes; ++ unsigned int total_rx_packets; ++ ++ /* Tx stats */ ++ u64 tpt_old; ++ u64 colc_old; ++ u32 gotc; ++ u64 gotc_old; ++ u32 tx_timeout_count; ++ u32 tx_fifo_head; ++ u32 tx_head_addr; ++ u32 tx_fifo_size; ++ u32 tx_dma_failed; ++ ++ /* ++ * Rx ++ */ ++#ifdef CONFIG_E1000E_NAPI ++ bool (*clean_rx) (struct e1000_adapter *adapter, ++ int *work_done, int work_to_do) ++ ____cacheline_aligned_in_smp; ++#else ++ bool (*clean_rx) (struct e1000_adapter *adapter) ++ ____cacheline_aligned_in_smp; ++#endif ++ void (*alloc_rx_buf) (struct e1000_adapter *adapter, ++ int cleaned_count); ++ struct e1000_ring *rx_ring; ++ ++ u32 rx_int_delay; ++ u32 rx_abs_int_delay; ++ ++ /* Rx stats */ ++ u64 hw_csum_err; ++ u64 hw_csum_good; ++ u64 rx_hdr_split; ++ u32 gorc; ++ u64 gorc_old; ++ u32 alloc_rx_buff_failed; ++ u32 rx_dma_failed; ++ ++ unsigned int rx_ps_pages; ++ u16 rx_ps_bsize0; ++ u32 max_frame_size; ++ u32 min_frame_size; ++ ++ /* OS defined structs */ ++ struct net_device *netdev; ++ struct pci_dev *pdev; ++ struct net_device_stats net_stats; ++ spinlock_t stats_lock; /* prevent concurrent stats updates */ ++ ++ /* structs defined in e1000_hw.h */ ++ struct e1000_hw hw; ++ ++ struct e1000_hw_stats stats; ++ struct e1000_phy_info phy_info; ++ struct e1000_phy_stats phy_stats; ++ ++#ifdef SIOCGMIIPHY ++ /* Snapshot of PHY registers */ ++ struct e1000_phy_regs phy_regs; ++#endif ++ ++ struct e1000_ring test_tx_ring; ++ struct e1000_ring test_rx_ring; ++ u32 test_icr; ++ ++ u32 msg_enable; ++#ifdef CONFIG_E1000E_MSIX ++ struct msix_entry *msix_entries; ++ int int_mode; ++ u32 eiac_mask; ++#endif /* CONFIG_E1000E_MSIX */ ++ ++ u32 eeprom_wol; ++ u32 wol; ++ u32 pba; ++ ++ bool fc_autoneg; ++ ++ unsigned long led_status; ++ ++ unsigned int flags; ++ unsigned int flags2; ++ u32 *config_space; ++ u32 stats_freq_us; /* stats update freq (microseconds) */ ++}; ++ ++struct e1000_info { ++ e1000_mac_type mac; ++ unsigned int flags; ++ unsigned int flags2; ++ u32 pba; ++ void (*init_ops)(struct e1000_hw *); ++ s32 (*get_variants)(struct e1000_adapter *); ++}; ++ ++/* hardware capability, feature, and workaround flags */ ++#define FLAG_HAS_AMT (1 << 0) ++#define FLAG_HAS_FLASH (1 << 1) ++#define FLAG_HAS_HW_VLAN_FILTER (1 << 2) ++#define FLAG_HAS_WOL (1 << 3) ++#define FLAG_HAS_ERT (1 << 4) ++#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) ++#define FLAG_HAS_SWSM_ON_LOAD (1 << 6) ++#define FLAG_HAS_JUMBO_FRAMES (1 << 7) ++#define FLAG_HAS_ASPM (1 << 8) ++#define FLAG_IS_ICH (1 << 9) ++#define FLAG_HAS_MSIX (1 << 10) ++#define FLAG_HAS_SMART_POWER_DOWN (1 << 11) ++#define FLAG_IS_QUAD_PORT_A (1 << 12) ++#define FLAG_IS_QUAD_PORT (1 << 13) ++#define FLAG_TIPG_MEDIUM_FOR_80003ESLAN (1 << 14) ++#define FLAG_APME_IN_WUC (1 << 15) ++#define FLAG_APME_IN_CTRL3 (1 << 16) ++#define FLAG_APME_CHECK_PORT_B (1 << 17) ++#define FLAG_DISABLE_FC_PAUSE_TIME (1 << 18) ++#define FLAG_NO_WAKE_UCAST (1 << 19) ++#define FLAG_MNG_PT_ENABLED (1 << 20) ++#define FLAG_RESET_OVERWRITES_LAA (1 << 21) ++#define FLAG_TARC_SPEED_MODE_BIT (1 << 22) ++#define FLAG_TARC_SET_BIT_ZERO (1 << 23) ++#define FLAG_RX_NEEDS_RESTART (1 << 24) ++#define FLAG_LSC_GIG_SPEED_DROP (1 << 25) ++#define FLAG_SMART_POWER_DOWN (1 << 26) ++#define FLAG_MSI_ENABLED (1 << 27) ++#define FLAG_RX_CSUM_ENABLED (1 << 28) ++#define FLAG_TSO_FORCE (1 << 29) ++#define FLAG_MSI_TEST_FAILED (1 << 30) ++#define FLAG_RX_RESTART_NOW (1 << 31) ++ ++#define FLAG2_READ_ONLY_NVM (1 << 1) ++ ++#define E1000_RX_DESC_PS(R, i) \ ++ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) ++#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) ++#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc) ++#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc) ++#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc) ++ ++enum e1000_state_t { ++ __E1000_TESTING, ++ __E1000_RESETTING, ++ __E1000_DOWN ++}; ++ ++enum latency_range { ++ lowest_latency = 0, ++ low_latency = 1, ++ bulk_latency = 2, ++ latency_invalid = 255 ++}; ++ ++extern char e1000e_driver_name[]; ++extern const char e1000e_driver_version[]; ++ ++extern void e1000_check_options(struct e1000_adapter *adapter); ++extern void e1000_set_ethtool_ops(struct net_device *netdev); ++#ifdef ETHTOOL_OPS_COMPAT ++extern int ethtool_ioctl(struct ifreq *ifr); ++#endif ++ ++extern int e1000_up(struct e1000_adapter *adapter); ++extern void e1000_down(struct e1000_adapter *adapter); ++extern void e1000_reinit_locked(struct e1000_adapter *adapter); ++extern void e1000_reset(struct e1000_adapter *adapter); ++extern int e1000_setup_rx_resources(struct e1000_adapter *adapter); ++extern int e1000_setup_tx_resources(struct e1000_adapter *adapter); ++extern void e1000_free_rx_resources(struct e1000_adapter *adapter); ++extern void e1000_free_tx_resources(struct e1000_adapter *adapter); ++extern void e1000_update_stats(struct e1000_adapter *adapter); ++#ifdef CONFIG_E1000E_MSIX ++extern void e1000_set_interrupt_capability(struct e1000_adapter *adapter); ++extern void e1000_reset_interrupt_capability(struct e1000_adapter *adapter); ++#endif ++ ++extern unsigned int copybreak; ++ ++static inline u32 __er32(struct e1000_hw *hw, unsigned long reg) ++{ ++ return readl(hw->hw_addr + reg); ++} ++ ++static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val) ++{ ++ writel(val, hw->hw_addr + reg); ++} ++#define er32(reg) E1000_READ_REG(hw, E1000_##reg) ++#define ew32(reg,val) E1000_WRITE_REG(hw, E1000_##reg, (val)) ++#define e1e_flush() er32(STATUS) ++ ++extern void e1000_init_function_pointers_82571(struct e1000_hw *hw); ++extern void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw); ++extern void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw); ++ ++static inline s32 e1000_read_mac_addr(struct e1000_hw *hw) ++{ ++ if (hw->mac.ops.read_mac_addr) ++ return hw->mac.ops.read_mac_addr(hw); ++ ++ return e1000_read_mac_addr_generic(hw); ++} ++ ++static inline void e1000_power_up_phy(struct e1000_hw *hw) ++{ ++ if(hw->phy.ops.power_up) ++ hw->phy.ops.power_up(hw); ++ hw->mac.ops.setup_link(hw); ++} ++ ++#endif /* _E1000_H_ */ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_hw.h linux-2.6.22-10/drivers/net/e1000e/e1000_hw.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_hw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_hw.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,671 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _E1000_HW_H_ ++#define _E1000_HW_H_ ++ ++#include "e1000_osdep.h" ++#include "e1000_regs.h" ++#include "e1000_defines.h" ++ ++struct e1000_hw; ++ ++#define E1000_DEV_ID_82571EB_COPPER 0x105E ++#define E1000_DEV_ID_82571EB_FIBER 0x105F ++#define E1000_DEV_ID_82571EB_SERDES 0x1060 ++#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9 ++#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA ++#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 ++#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5 ++#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 ++#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC ++#define E1000_DEV_ID_82572EI_COPPER 0x107D ++#define E1000_DEV_ID_82572EI_FIBER 0x107E ++#define E1000_DEV_ID_82572EI_SERDES 0x107F ++#define E1000_DEV_ID_82572EI 0x10B9 ++#define E1000_DEV_ID_82573E 0x108B ++#define E1000_DEV_ID_82573E_IAMT 0x108C ++#define E1000_DEV_ID_82573L 0x109A ++#define E1000_DEV_ID_82574L 0x10D3 ++#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 ++#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 ++#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA ++#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB ++#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 ++#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A ++#define E1000_DEV_ID_ICH8_IGP_C 0x104B ++#define E1000_DEV_ID_ICH8_IFE 0x104C ++#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4 ++#define E1000_DEV_ID_ICH8_IFE_G 0x10C5 ++#define E1000_DEV_ID_ICH8_IGP_M 0x104D ++#define E1000_DEV_ID_ICH9_IGP_M 0x10BF ++#define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5 ++#define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB ++#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD ++#define E1000_DEV_ID_ICH9_BM 0x10E5 ++#define E1000_DEV_ID_ICH9_IGP_C 0x294C ++#define E1000_DEV_ID_ICH9_IFE 0x10C0 ++#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3 ++#define E1000_DEV_ID_ICH9_IFE_G 0x10C2 ++#define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC ++#define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD ++#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE ++#define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE ++#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF ++ ++#define E1000_REVISION_0 0 ++#define E1000_REVISION_1 1 ++#define E1000_REVISION_2 2 ++#define E1000_REVISION_3 3 ++#define E1000_REVISION_4 4 ++ ++#define E1000_FUNC_0 0 ++#define E1000_FUNC_1 1 ++ ++typedef enum { ++ e1000_undefined = 0, ++ e1000_82571, ++ e1000_82572, ++ e1000_82573, ++ e1000_82574, ++ e1000_80003es2lan, ++ e1000_ich8lan, ++ e1000_ich9lan, ++ e1000_ich10lan, ++ e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ ++} e1000_mac_type; ++ ++typedef enum { ++ e1000_media_type_unknown = 0, ++ e1000_media_type_copper = 1, ++ e1000_media_type_fiber = 2, ++ e1000_media_type_internal_serdes = 3, ++ e1000_num_media_types ++} e1000_media_type; ++ ++typedef enum { ++ e1000_nvm_unknown = 0, ++ e1000_nvm_none, ++ e1000_nvm_eeprom_spi, ++ e1000_nvm_eeprom_microwire, ++ e1000_nvm_flash_hw, ++ e1000_nvm_flash_sw ++} e1000_nvm_type; ++ ++typedef enum { ++ e1000_nvm_override_none = 0, ++ e1000_nvm_override_spi_small, ++ e1000_nvm_override_spi_large, ++ e1000_nvm_override_microwire_small, ++ e1000_nvm_override_microwire_large ++} e1000_nvm_override; ++ ++typedef enum { ++ e1000_phy_unknown = 0, ++ e1000_phy_none, ++ e1000_phy_m88, ++ e1000_phy_igp, ++ e1000_phy_igp_2, ++ e1000_phy_gg82563, ++ e1000_phy_igp_3, ++ e1000_phy_ife, ++ e1000_phy_bm, ++} e1000_phy_type; ++ ++typedef enum { ++ e1000_bus_type_unknown = 0, ++ e1000_bus_type_pci, ++ e1000_bus_type_pcix, ++ e1000_bus_type_pci_express, ++ e1000_bus_type_reserved ++} e1000_bus_type; ++ ++typedef enum { ++ e1000_bus_speed_unknown = 0, ++ e1000_bus_speed_33, ++ e1000_bus_speed_66, ++ e1000_bus_speed_100, ++ e1000_bus_speed_120, ++ e1000_bus_speed_133, ++ e1000_bus_speed_2500, ++ e1000_bus_speed_5000, ++ e1000_bus_speed_reserved ++} e1000_bus_speed; ++ ++typedef enum { ++ e1000_bus_width_unknown = 0, ++ e1000_bus_width_pcie_x1, ++ e1000_bus_width_pcie_x2, ++ e1000_bus_width_pcie_x4 = 4, ++ e1000_bus_width_pcie_x8 = 8, ++ e1000_bus_width_32, ++ e1000_bus_width_64, ++ e1000_bus_width_reserved ++} e1000_bus_width; ++ ++typedef enum { ++ e1000_1000t_rx_status_not_ok = 0, ++ e1000_1000t_rx_status_ok, ++ e1000_1000t_rx_status_undefined = 0xFF ++} e1000_1000t_rx_status; ++ ++typedef enum { ++ e1000_rev_polarity_normal = 0, ++ e1000_rev_polarity_reversed, ++ e1000_rev_polarity_undefined = 0xFF ++} e1000_rev_polarity; ++ ++typedef enum { ++ e1000_fc_none = 0, ++ e1000_fc_rx_pause, ++ e1000_fc_tx_pause, ++ e1000_fc_full, ++ e1000_fc_default = 0xFF ++} e1000_fc_type; ++ ++ ++/* Receive Descriptor */ ++struct e1000_rx_desc { ++ u64 buffer_addr; /* Address of the descriptor's data buffer */ ++ u16 length; /* Length of data DMAed into data buffer */ ++ u16 csum; /* Packet checksum */ ++ u8 status; /* Descriptor status */ ++ u8 errors; /* Descriptor Errors */ ++ u16 special; ++}; ++ ++/* Receive Descriptor - Extended */ ++union e1000_rx_desc_extended { ++ struct { ++ u64 buffer_addr; ++ u64 reserved; ++ } read; ++ struct { ++ struct { ++ u32 mrq; /* Multiple Rx Queues */ ++ union { ++ u32 rss; /* RSS Hash */ ++ struct { ++ u16 ip_id; /* IP id */ ++ u16 csum; /* Packet Checksum */ ++ } csum_ip; ++ } hi_dword; ++ } lower; ++ struct { ++ u32 status_error; /* ext status/error */ ++ u16 length; ++ u16 vlan; /* VLAN tag */ ++ } upper; ++ } wb; /* writeback */ ++}; ++ ++#define MAX_PS_BUFFERS 4 ++/* Receive Descriptor - Packet Split */ ++union e1000_rx_desc_packet_split { ++ struct { ++ /* one buffer for protocol header(s), three data buffers */ ++ u64 buffer_addr[MAX_PS_BUFFERS]; ++ } read; ++ struct { ++ struct { ++ u32 mrq; /* Multiple Rx Queues */ ++ union { ++ u32 rss; /* RSS Hash */ ++ struct { ++ u16 ip_id; /* IP id */ ++ u16 csum; /* Packet Checksum */ ++ } csum_ip; ++ } hi_dword; ++ } lower; ++ struct { ++ u32 status_error; /* ext status/error */ ++ u16 length0; /* length of buffer 0 */ ++ u16 vlan; /* VLAN tag */ ++ } middle; ++ struct { ++ u16 header_status; ++ u16 length[3]; /* length of buffers 1-3 */ ++ } upper; ++ u64 reserved; ++ } wb; /* writeback */ ++}; ++ ++/* Transmit Descriptor */ ++struct e1000_tx_desc { ++ u64 buffer_addr; /* Address of the descriptor's data buffer */ ++ union { ++ u32 data; ++ struct { ++ u16 length; /* Data buffer length */ ++ u8 cso; /* Checksum offset */ ++ u8 cmd; /* Descriptor control */ ++ } flags; ++ } lower; ++ union { ++ u32 data; ++ struct { ++ u8 status; /* Descriptor status */ ++ u8 css; /* Checksum start */ ++ u16 special; ++ } fields; ++ } upper; ++}; ++ ++/* Offload Context Descriptor */ ++struct e1000_context_desc { ++ union { ++ u32 ip_config; ++ struct { ++ u8 ipcss; /* IP checksum start */ ++ u8 ipcso; /* IP checksum offset */ ++ u16 ipcse; /* IP checksum end */ ++ } ip_fields; ++ } lower_setup; ++ union { ++ u32 tcp_config; ++ struct { ++ u8 tucss; /* TCP checksum start */ ++ u8 tucso; /* TCP checksum offset */ ++ u16 tucse; /* TCP checksum end */ ++ } tcp_fields; ++ } upper_setup; ++ u32 cmd_and_length; ++ union { ++ u32 data; ++ struct { ++ u8 status; /* Descriptor status */ ++ u8 hdr_len; /* Header length */ ++ u16 mss; /* Maximum segment size */ ++ } fields; ++ } tcp_seg_setup; ++}; ++ ++/* Offload data descriptor */ ++struct e1000_data_desc { ++ u64 buffer_addr; /* Address of the descriptor's buffer address */ ++ union { ++ u32 data; ++ struct { ++ u16 length; /* Data buffer length */ ++ u8 typ_len_ext; ++ u8 cmd; ++ } flags; ++ } lower; ++ union { ++ u32 data; ++ struct { ++ u8 status; /* Descriptor status */ ++ u8 popts; /* Packet Options */ ++ u16 special; ++ } fields; ++ } upper; ++}; ++ ++/* Statistics counters collected by the MAC */ ++struct e1000_hw_stats { ++ u64 crcerrs; ++ u64 algnerrc; ++ u64 symerrs; ++ u64 rxerrc; ++ u64 mpc; ++ u64 scc; ++ u64 ecol; ++ u64 mcc; ++ u64 latecol; ++ u64 colc; ++ u64 dc; ++ u64 tncrs; ++ u64 sec; ++ u64 cexterr; ++ u64 rlec; ++ u64 xonrxc; ++ u64 xontxc; ++ u64 xoffrxc; ++ u64 xofftxc; ++ u64 fcruc; ++ u64 prc64; ++ u64 prc127; ++ u64 prc255; ++ u64 prc511; ++ u64 prc1023; ++ u64 prc1522; ++ u64 gprc; ++ u64 bprc; ++ u64 mprc; ++ u64 gptc; ++ u64 gorc; ++ u64 gotc; ++ u64 rnbc; ++ u64 ruc; ++ u64 rfc; ++ u64 roc; ++ u64 rjc; ++ u64 mgprc; ++ u64 mgpdc; ++ u64 mgptc; ++ u64 tor; ++ u64 tot; ++ u64 tpr; ++ u64 tpt; ++ u64 ptc64; ++ u64 ptc127; ++ u64 ptc255; ++ u64 ptc511; ++ u64 ptc1023; ++ u64 ptc1522; ++ u64 mptc; ++ u64 bptc; ++ u64 tsctc; ++ u64 tsctfc; ++ u64 iac; ++ u64 icrxptc; ++ u64 icrxatc; ++ u64 ictxptc; ++ u64 ictxatc; ++ u64 ictxqec; ++ u64 ictxqmtc; ++ u64 icrxdmtc; ++ u64 icrxoc; ++ u64 cbtmpc; ++ u64 htdpmc; ++ u64 cbrdpc; ++ u64 cbrmpc; ++ u64 rpthc; ++ u64 hgptc; ++ u64 htcbdpc; ++ u64 hgorc; ++ u64 hgotc; ++ u64 lenerrs; ++ u64 scvpc; ++ u64 hrmpc; ++}; ++ ++struct e1000_phy_stats { ++ u32 idle_errors; ++ u32 receive_errors; ++}; ++ ++struct e1000_host_mng_dhcp_cookie { ++ u32 signature; ++ u8 status; ++ u8 reserved0; ++ u16 vlan_id; ++ u32 reserved1; ++ u16 reserved2; ++ u8 reserved3; ++ u8 checksum; ++}; ++ ++/* Host Interface "Rev 1" */ ++struct e1000_host_command_header { ++ u8 command_id; ++ u8 command_length; ++ u8 command_options; ++ u8 checksum; ++}; ++ ++#define E1000_HI_MAX_DATA_LENGTH 252 ++struct e1000_host_command_info { ++ struct e1000_host_command_header command_header; ++ u8 command_data[E1000_HI_MAX_DATA_LENGTH]; ++}; ++ ++/* Host Interface "Rev 2" */ ++struct e1000_host_mng_command_header { ++ u8 command_id; ++ u8 checksum; ++ u16 reserved1; ++ u16 reserved2; ++ u16 command_length; ++}; ++ ++#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 ++struct e1000_host_mng_command_info { ++ struct e1000_host_mng_command_header command_header; ++ u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; ++}; ++ ++#include "e1000_mac.h" ++#include "e1000_phy.h" ++#include "e1000_nvm.h" ++#include "e1000_manage.h" ++ ++struct e1000_mac_operations { ++ /* Function pointers for the MAC. */ ++ s32 (*init_params)(struct e1000_hw *); ++ s32 (*blink_led)(struct e1000_hw *); ++ s32 (*check_for_link)(struct e1000_hw *); ++ bool (*check_mng_mode)(struct e1000_hw *hw); ++ s32 (*cleanup_led)(struct e1000_hw *); ++ void (*clear_hw_cntrs)(struct e1000_hw *); ++ void (*clear_vfta)(struct e1000_hw *); ++ s32 (*get_bus_info)(struct e1000_hw *); ++ s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); ++ s32 (*led_on)(struct e1000_hw *); ++ s32 (*led_off)(struct e1000_hw *); ++ void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32, u32, ++ u32); ++ void (*remove_device)(struct e1000_hw *); ++ s32 (*reset_hw)(struct e1000_hw *); ++ s32 (*init_hw)(struct e1000_hw *); ++ s32 (*setup_link)(struct e1000_hw *); ++ s32 (*setup_physical_interface)(struct e1000_hw *); ++ s32 (*setup_led)(struct e1000_hw *); ++ void (*write_vfta)(struct e1000_hw *, u32, u32); ++ void (*mta_set)(struct e1000_hw *, u32); ++ void (*config_collision_dist)(struct e1000_hw*); ++ void (*rar_set)(struct e1000_hw*, u8*, u32); ++ s32 (*read_mac_addr)(struct e1000_hw*); ++ s32 (*validate_mdi_setting)(struct e1000_hw*); ++ s32 (*mng_host_if_write)(struct e1000_hw*, u8*, u16, u16, u8*); ++ s32 (*mng_write_cmd_header)(struct e1000_hw *hw, ++ struct e1000_host_mng_command_header*); ++ s32 (*mng_enable_host_if)(struct e1000_hw*); ++ s32 (*wait_autoneg)(struct e1000_hw*); ++}; ++ ++struct e1000_phy_operations { ++ s32 (*init_params)(struct e1000_hw *); ++ s32 (*acquire)(struct e1000_hw *); ++ s32 (*cfg_on_link_up)(struct e1000_hw *); ++ s32 (*check_polarity)(struct e1000_hw *); ++ s32 (*check_reset_block)(struct e1000_hw *); ++ s32 (*commit)(struct e1000_hw *); ++ s32 (*force_speed_duplex)(struct e1000_hw *); ++ s32 (*get_cfg_done)(struct e1000_hw *hw); ++ s32 (*get_cable_length)(struct e1000_hw *); ++ s32 (*get_info)(struct e1000_hw *); ++ s32 (*read_reg)(struct e1000_hw *, u32, u16 *); ++ void (*release)(struct e1000_hw *); ++ s32 (*reset)(struct e1000_hw *); ++ s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); ++ s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); ++ s32 (*write_reg)(struct e1000_hw *, u32, u16); ++ void (*power_up)(struct e1000_hw *); ++ void (*power_down)(struct e1000_hw *); ++}; ++ ++struct e1000_nvm_operations { ++ s32 (*init_params)(struct e1000_hw *); ++ s32 (*acquire)(struct e1000_hw *); ++ s32 (*read)(struct e1000_hw *, u16, u16, u16 *); ++ void (*release)(struct e1000_hw *); ++ void (*reload)(struct e1000_hw *); ++ s32 (*update)(struct e1000_hw *); ++ s32 (*valid_led_default)(struct e1000_hw *, u16 *); ++ s32 (*validate)(struct e1000_hw *); ++ s32 (*write)(struct e1000_hw *, u16, u16, u16 *); ++}; ++ ++struct e1000_mac_info { ++ struct e1000_mac_operations ops; ++ u8 addr[6]; ++ u8 perm_addr[6]; ++ ++ e1000_mac_type type; ++ ++ u32 collision_delta; ++ u32 ledctl_default; ++ u32 ledctl_mode1; ++ u32 ledctl_mode2; ++ u32 mc_filter_type; ++ u32 tx_packet_delta; ++ u32 txcw; ++ ++ u16 current_ifs_val; ++ u16 ifs_max_val; ++ u16 ifs_min_val; ++ u16 ifs_ratio; ++ u16 ifs_step_size; ++ u16 mta_reg_count; ++ u16 rar_entry_count; ++ ++ u8 forced_speed_duplex; ++ ++ bool adaptive_ifs; ++ bool arc_subsystem_valid; ++ bool asf_firmware_present; ++ bool autoneg; ++ bool autoneg_failed; ++ bool disable_av; ++ bool disable_hw_init_bits; ++ bool get_link_status; ++ bool ifs_params_forced; ++ bool in_ifs_mode; ++ bool report_tx_early; ++ bool serdes_has_link; ++ bool tx_pkt_filtering; ++}; ++ ++struct e1000_phy_info { ++ struct e1000_phy_operations ops; ++ e1000_phy_type type; ++ ++ e1000_1000t_rx_status local_rx; ++ e1000_1000t_rx_status remote_rx; ++ e1000_ms_type ms_type; ++ e1000_ms_type original_ms_type; ++ e1000_rev_polarity cable_polarity; ++ e1000_smart_speed smart_speed; ++ ++ u32 addr; ++ u32 id; ++ u32 reset_delay_us; /* in usec */ ++ u32 revision; ++ ++ e1000_media_type media_type; ++ ++ u16 autoneg_advertised; ++ u16 autoneg_mask; ++ u16 cable_length; ++ u16 max_cable_length; ++ u16 min_cable_length; ++ ++ u8 mdix; ++ ++ bool disable_polarity_correction; ++ bool is_mdix; ++ bool polarity_correction; ++ bool reset_disable; ++ bool speed_downgraded; ++ bool autoneg_wait_to_complete; ++}; ++ ++struct e1000_nvm_info { ++ struct e1000_nvm_operations ops; ++ e1000_nvm_type type; ++ e1000_nvm_override override; ++ ++ u32 flash_bank_size; ++ u32 flash_base_addr; ++ u32 semaphore_delay; ++ ++ u16 word_size; ++ u16 delay_usec; ++ u16 address_bits; ++ u16 opcode_bits; ++ u16 page_size; ++}; ++ ++struct e1000_bus_info { ++ e1000_bus_type type; ++ e1000_bus_speed speed; ++ e1000_bus_width width; ++ ++ u32 snoop; ++ ++ u16 func; ++ u16 pci_cmd_word; ++}; ++ ++struct e1000_fc_info { ++ u32 high_water; /* Flow control high-water mark */ ++ u32 low_water; /* Flow control low-water mark */ ++ u16 pause_time; /* Flow control pause timer */ ++ bool send_xon; /* Flow control send XON */ ++ bool strict_ieee; /* Strict IEEE mode */ ++ e1000_fc_type type; /* Type of flow control */ ++ e1000_fc_type original_type; ++}; ++ ++struct e1000_hw { ++ void *back; ++ void *dev_spec; ++ ++ u8 __iomem *hw_addr; ++ u8 __iomem *flash_address; ++ unsigned long io_base; ++ ++ struct e1000_mac_info mac; ++ struct e1000_fc_info fc; ++ struct e1000_phy_info phy; ++ struct e1000_nvm_info nvm; ++ struct e1000_bus_info bus; ++ struct e1000_host_mng_dhcp_cookie mng_cookie; ++ ++ u32 dev_spec_size; ++ ++ u16 device_id; ++ u16 subsystem_vendor_id; ++ u16 subsystem_device_id; ++ u16 vendor_id; ++ ++ u8 revision_id; ++}; ++ ++#include "e1000_82571.h" ++#include "e1000_80003es2lan.h" ++#include "e1000_ich8lan.h" ++ ++/* These functions must be implemented by drivers */ ++s32 e1000_alloc_zeroed_dev_spec_struct(struct e1000_hw *hw, u32 size); ++s32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); ++void e1000_free_dev_spec_struct(struct e1000_hw *hw); ++void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value); ++ ++#endif +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_ich8lan.c linux-2.6.22-10/drivers/net/e1000e/e1000_ich8lan.c +--- linux-2.6.22-0/drivers/net/e1000e/e1000_ich8lan.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_ich8lan.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,2757 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++/* e1000_ich8lan ++ * e1000_ich9lan ++ */ ++ ++#include "e1000_hw.h" ++ ++static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw); ++static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw); ++static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw); ++static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw); ++static void e1000_release_swflag_ich8lan(struct e1000_hw *hw); ++static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); ++static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw); ++static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw); ++static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw); ++static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw); ++static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw); ++static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, ++ bool active); ++static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, ++ bool active); ++static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, ++ u16 words, u16 *data); ++static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, ++ u16 words, u16 *data); ++static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw); ++static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw); ++static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, ++ u16 *data); ++static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw); ++static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw); ++static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw); ++static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); ++static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); ++static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, ++ u16 *speed, u16 *duplex); ++static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); ++static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); ++static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); ++static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); ++static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); ++static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout); ++static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw); ++static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw); ++static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); ++static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); ++static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, ++ u32 offset, u8* data); ++static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, ++ u8 size, u16* data); ++static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, ++ u32 offset, u16 *data); ++static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, ++ u32 offset, u8 byte); ++static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, ++ u32 offset, u8 data); ++static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, ++ u8 size, u16 data); ++static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); ++static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); ++ ++/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ ++/* Offset 04h HSFSTS */ ++union ich8_hws_flash_status { ++ struct ich8_hsfsts { ++ u16 flcdone :1; /* bit 0 Flash Cycle Done */ ++ u16 flcerr :1; /* bit 1 Flash Cycle Error */ ++ u16 dael :1; /* bit 2 Direct Access error Log */ ++ u16 berasesz :2; /* bit 4:3 Sector Erase Size */ ++ u16 flcinprog :1; /* bit 5 flash cycle in Progress */ ++ u16 reserved1 :2; /* bit 13:6 Reserved */ ++ u16 reserved2 :6; /* bit 13:6 Reserved */ ++ u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */ ++ u16 flockdn :1; /* bit 15 Flash Config Lock-Down */ ++ } hsf_status; ++ u16 regval; ++}; ++ ++/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */ ++/* Offset 06h FLCTL */ ++union ich8_hws_flash_ctrl { ++ struct ich8_hsflctl { ++ u16 flcgo :1; /* 0 Flash Cycle Go */ ++ u16 flcycle :2; /* 2:1 Flash Cycle */ ++ u16 reserved :5; /* 7:3 Reserved */ ++ u16 fldbcount :2; /* 9:8 Flash Data Byte Count */ ++ u16 flockdn :6; /* 15:10 Reserved */ ++ } hsf_ctrl; ++ u16 regval; ++}; ++ ++/* ICH Flash Region Access Permissions */ ++union ich8_hws_flash_regacc { ++ struct ich8_flracc { ++ u32 grra :8; /* 0:7 GbE region Read Access */ ++ u32 grwa :8; /* 8:15 GbE region Write Access */ ++ u32 gmrag :8; /* 23:16 GbE Master Read Access Grant */ ++ u32 gmwag :8; /* 31:24 GbE Master Write Access Grant */ ++ } hsf_flregacc; ++ u16 regval; ++}; ++ ++struct e1000_shadow_ram { ++ u16 value; ++ bool modified; ++}; ++ ++struct e1000_dev_spec_ich8lan { ++ bool kmrn_lock_loss_workaround_enabled; ++ struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS]; ++}; ++ ++/** ++ * e1000_init_phy_params_ich8lan - Initialize PHY function pointers ++ * @hw: pointer to the HW structure ++ * ++ * Initialize family-specific PHY parameters and function pointers. ++ **/ ++static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ u16 i = 0; ++ ++ DEBUGFUNC("e1000_init_phy_params_ich8lan"); ++ ++ phy->addr = 1; ++ phy->reset_delay_us = 100; ++ ++ phy->ops.acquire = e1000_acquire_swflag_ich8lan; ++ phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; ++ phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; ++ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan; ++ phy->ops.get_cable_length = e1000_get_cable_length_igp_2; ++ phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; ++ phy->ops.get_info = e1000_get_phy_info_ich8lan; ++ phy->ops.read_reg = e1000_read_phy_reg_igp; ++ phy->ops.release = e1000_release_swflag_ich8lan; ++ phy->ops.reset = e1000_phy_hw_reset_ich8lan; ++ phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan; ++ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan; ++ phy->ops.write_reg = e1000_write_phy_reg_igp; ++ phy->ops.power_up = e1000_power_up_phy_copper; ++ phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; ++ ++ /* ++ * We may need to do this twice - once for IGP and if that fails, ++ * we'll set BM func pointers and try again ++ */ ++ ret_val = e1000_determine_phy_address(hw); ++ if (ret_val) { ++ phy->ops.write_reg = e1000_write_phy_reg_bm; ++ phy->ops.read_reg = e1000_read_phy_reg_bm; ++ ret_val = e1000_determine_phy_address(hw); ++ if (ret_val) { ++ DEBUGOUT("Cannot determine PHY address. Erroring out\n"); ++ goto out; ++ } ++ } ++ ++ phy->id = 0; ++ while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) && ++ (i++ < 100)) { ++ msec_delay(1); ++ ret_val = e1000_get_phy_id(hw); ++ if (ret_val) ++ goto out; ++ } ++ ++ /* Verify phy id */ ++ switch (phy->id) { ++ case IGP03E1000_E_PHY_ID: ++ phy->type = e1000_phy_igp_3; ++ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; ++ break; ++ case IFE_E_PHY_ID: ++ case IFE_PLUS_E_PHY_ID: ++ case IFE_C_E_PHY_ID: ++ phy->type = e1000_phy_ife; ++ phy->autoneg_mask = E1000_ALL_NOT_GIG; ++ break; ++ case BME1000_E_PHY_ID: ++ phy->type = e1000_phy_bm; ++ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; ++ phy->ops.read_reg = e1000_read_phy_reg_bm; ++ phy->ops.write_reg = e1000_write_phy_reg_bm; ++ phy->ops.commit = e1000_phy_sw_reset_generic; ++ break; ++ default: ++ ret_val = -E1000_ERR_PHY; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers ++ * @hw: pointer to the HW structure ++ * ++ * Initialize family-specific NVM parameters and function ++ * pointers. ++ **/ ++static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ struct e1000_dev_spec_ich8lan *dev_spec; ++ u32 gfpreg, sector_base_addr, sector_end_addr; ++ s32 ret_val = E1000_SUCCESS; ++ u16 i; ++ ++ DEBUGFUNC("e1000_init_nvm_params_ich8lan"); ++ ++ /* Can't read flash registers if the register set isn't mapped. */ ++ if (!hw->flash_address) { ++ DEBUGOUT("ERROR: Flash registers not mapped\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ nvm->type = e1000_nvm_flash_sw; ++ ++ gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG); ++ ++ /* ++ * sector_X_addr is a "sector"-aligned address (4096 bytes) ++ * Add 1 to sector_end_addr since this sector is included in ++ * the overall size. ++ */ ++ sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; ++ sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; ++ ++ /* flash_base_addr is byte-aligned */ ++ nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; ++ ++ /* ++ * find total size of the NVM, then cut in half since the total ++ * size represents two separate NVM banks. ++ */ ++ nvm->flash_bank_size = (sector_end_addr - sector_base_addr) ++ << FLASH_SECTOR_ADDR_SHIFT; ++ nvm->flash_bank_size /= 2; ++ /* Adjust to word count */ ++ nvm->flash_bank_size /= sizeof(u16); ++ ++ nvm->word_size = E1000_SHADOW_RAM_WORDS; ++ ++ dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; ++ ++ if (!dev_spec) { ++ DEBUGOUT("dev_spec pointer is set to NULL.\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ /* Clear shadow ram */ ++ for (i = 0; i < nvm->word_size; i++) { ++ dev_spec->shadow_ram[i].modified = false; ++ dev_spec->shadow_ram[i].value = 0xFFFF; ++ } ++ ++ /* Function Pointers */ ++ nvm->ops.acquire = e1000_acquire_swflag_ich8lan; ++ nvm->ops.read = e1000_read_nvm_ich8lan; ++ nvm->ops.release = e1000_release_swflag_ich8lan; ++ nvm->ops.update = e1000_update_nvm_checksum_ich8lan; ++ nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan; ++ nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan; ++ nvm->ops.write = e1000_write_nvm_ich8lan; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_init_mac_params_ich8lan - Initialize MAC function pointers ++ * @hw: pointer to the HW structure ++ * ++ * Initialize family-specific MAC parameters and function ++ * pointers. ++ **/ ++static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_init_mac_params_ich8lan"); ++ ++ /* Set media type function pointer */ ++ hw->phy.media_type = e1000_media_type_copper; ++ ++ /* Set mta register count */ ++ mac->mta_reg_count = 32; ++ /* Set rar entry count */ ++ mac->rar_entry_count = E1000_ICH_RAR_ENTRIES; ++ if (mac->type == e1000_ich8lan) ++ mac->rar_entry_count--; ++ /* Set if part includes ASF firmware */ ++ mac->asf_firmware_present = true; ++ /* Set if manageability features are enabled. */ ++ mac->arc_subsystem_valid = true; ++ ++ /* Function pointers */ ++ ++ /* bus type/speed/width */ ++ mac->ops.get_bus_info = e1000_get_bus_info_ich8lan; ++ /* reset */ ++ mac->ops.reset_hw = e1000_reset_hw_ich8lan; ++ /* hw initialization */ ++ mac->ops.init_hw = e1000_init_hw_ich8lan; ++ /* link setup */ ++ mac->ops.setup_link = e1000_setup_link_ich8lan; ++ /* physical interface setup */ ++ mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan; ++ /* check for link */ ++ mac->ops.check_for_link = e1000_check_for_copper_link_generic; ++ /* check management mode */ ++ mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; ++ /* link info */ ++ mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan; ++ /* multicast address update */ ++ mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; ++ /* setting MTA */ ++ mac->ops.mta_set = e1000_mta_set_generic; ++ /* blink LED */ ++ mac->ops.blink_led = e1000_blink_led_generic; ++ /* setup LED */ ++ mac->ops.setup_led = e1000_setup_led_generic; ++ /* cleanup LED */ ++ mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; ++ /* turn on/off LED */ ++ mac->ops.led_on = e1000_led_on_ich8lan; ++ mac->ops.led_off = e1000_led_off_ich8lan; ++ /* remove device */ ++ mac->ops.remove_device = e1000_remove_device_generic; ++ /* clear hardware counters */ ++ mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan; ++ ++ hw->dev_spec_size = sizeof(struct e1000_dev_spec_ich8lan); ++ ++ /* Device-specific structure allocation */ ++ ret_val = e1000_alloc_zeroed_dev_spec_struct(hw, hw->dev_spec_size); ++ if (ret_val) ++ goto out; ++ ++ /* Enable PCS Lock-loss workaround for ICH8 */ ++ if (mac->type == e1000_ich8lan) ++ e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, true); ++ ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers ++ * @hw: pointer to the HW structure ++ * ++ * Initialize family-specific function pointers for PHY, MAC, and NVM. ++ **/ ++void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw) ++{ ++ DEBUGFUNC("e1000_init_function_pointers_ich8lan"); ++ ++ e1000_init_mac_ops_generic(hw); ++ e1000_init_nvm_ops_generic(hw); ++ hw->mac.ops.init_params = e1000_init_mac_params_ich8lan; ++ hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan; ++ hw->phy.ops.init_params = e1000_init_phy_params_ich8lan; ++} ++ ++/** ++ * e1000_acquire_swflag_ich8lan - Acquire software control flag ++ * @hw: pointer to the HW structure ++ * ++ * Acquires the software control flag for performing NVM and PHY ++ * operations. This is a function pointer entry point only called by ++ * read/write routines for the PHY and NVM parts. ++ **/ ++static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) ++{ ++ u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_acquire_swflag_ich8lan"); ++ ++ while (timeout) { ++ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); ++ extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; ++ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); ++ ++ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); ++ if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) ++ break; ++ msec_delay_irq(1); ++ timeout--; ++ } ++ ++ if (!timeout) { ++ DEBUGOUT("FW or HW has locked the resource for too long.\n"); ++ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; ++ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_release_swflag_ich8lan - Release software control flag ++ * @hw: pointer to the HW structure ++ * ++ * Releases the software control flag for performing NVM and PHY operations. ++ * This is a function pointer entry point only called by read/write ++ * routines for the PHY and NVM parts. ++ **/ ++static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) ++{ ++ u32 extcnf_ctrl; ++ ++ DEBUGFUNC("e1000_release_swflag_ich8lan"); ++ ++ extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); ++ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; ++ E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); ++ ++ return; ++} ++ ++/** ++ * e1000_check_mng_mode_ich8lan - Checks management mode ++ * @hw: pointer to the HW structure ++ * ++ * This checks if the adapter has manageability enabled. ++ * This is a function pointer entry point only called by read/write ++ * routines for the PHY and NVM parts. ++ **/ ++static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw) ++{ ++ u32 fwsm; ++ ++ DEBUGFUNC("e1000_check_mng_mode_ich8lan"); ++ ++ fwsm = E1000_READ_REG(hw, E1000_FWSM); ++ ++ return ((fwsm & E1000_FWSM_MODE_MASK) == ++ (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); ++} ++ ++/** ++ * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked ++ * @hw: pointer to the HW structure ++ * ++ * Checks if firmware is blocking the reset of the PHY. ++ * This is a function pointer entry point only called by ++ * reset routines. ++ **/ ++static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) ++{ ++ u32 fwsm; ++ ++ DEBUGFUNC("e1000_check_reset_block_ich8lan"); ++ ++ fwsm = E1000_READ_REG(hw, E1000_FWSM); ++ ++ return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS ++ : E1000_BLK_PHY_RESET; ++} ++ ++/** ++ * e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex ++ * @hw: pointer to the HW structure ++ * ++ * Forces the speed and duplex settings of the PHY. ++ * This is a function pointer entry point only called by ++ * PHY setup routines. ++ **/ ++static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 data; ++ bool link; ++ ++ DEBUGFUNC("e1000_phy_force_speed_duplex_ich8lan"); ++ ++ if (phy->type != e1000_phy_ife) { ++ ret_val = e1000_phy_force_speed_duplex_igp(hw); ++ goto out; ++ } ++ ++ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data); ++ if (ret_val) ++ goto out; ++ ++ e1000_phy_force_speed_duplex_setup(hw, &data); ++ ++ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data); ++ if (ret_val) ++ goto out; ++ ++ /* Disable MDI-X support for 10/100 */ ++ ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~IFE_PMC_AUTO_MDIX; ++ data &= ~IFE_PMC_FORCE_MDIX; ++ ++ ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data); ++ if (ret_val) ++ goto out; ++ ++ DEBUGOUT1("IFE PMC: %X\n", data); ++ ++ usec_delay(1); ++ ++ if (phy->autoneg_wait_to_complete) { ++ DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n"); ++ ++ ret_val = e1000_phy_has_link_generic(hw, ++ PHY_FORCE_LIMIT, ++ 100000, ++ &link); ++ if (ret_val) ++ goto out; ++ ++ if (!link) { ++ DEBUGOUT("Link taking longer than expected.\n"); ++ } ++ ++ /* Try once more */ ++ ret_val = e1000_phy_has_link_generic(hw, ++ PHY_FORCE_LIMIT, ++ 100000, ++ &link); ++ if (ret_val) ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_phy_hw_reset_ich8lan - Performs a PHY reset ++ * @hw: pointer to the HW structure ++ * ++ * Resets the PHY ++ * This is a function pointer entry point called by drivers ++ * or other shared routines. ++ **/ ++static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; ++ s32 ret_val; ++ u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT; ++ u16 word_addr, reg_data, reg_addr, phy_page = 0; ++ ++ DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); ++ ++ ret_val = e1000_phy_hw_reset_generic(hw); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Initialize the PHY from the NVM on ICH platforms. This ++ * is needed due to an issue where the NVM configuration is ++ * not properly autoloaded after power transitions. ++ * Therefore, after each PHY reset, we will load the ++ * configuration data out of the NVM manually. ++ */ ++ if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) { ++ /* Check if SW needs configure the PHY */ ++ if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || ++ (hw->device_id == E1000_DEV_ID_ICH8_IGP_M)) ++ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; ++ else ++ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; ++ ++ data = E1000_READ_REG(hw, E1000_FEXTNVM); ++ if (!(data & sw_cfg_mask)) ++ goto out; ++ ++ /* Wait for basic configuration completes before proceeding*/ ++ do { ++ data = E1000_READ_REG(hw, E1000_STATUS); ++ data &= E1000_STATUS_LAN_INIT_DONE; ++ usec_delay(100); ++ } while ((!data) && --loop); ++ ++ /* ++ * If basic configuration is incomplete before the above loop ++ * count reaches 0, loading the configuration from NVM will ++ * leave the PHY in a bad state possibly resulting in no link. ++ */ ++ if (loop == 0) { ++ DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n"); ++ } ++ ++ /* Clear the Init Done bit for the next init event */ ++ data = E1000_READ_REG(hw, E1000_STATUS); ++ data &= ~E1000_STATUS_LAN_INIT_DONE; ++ E1000_WRITE_REG(hw, E1000_STATUS, data); ++ ++ /* ++ * Make sure HW does not configure LCD from PHY ++ * extended configuration before SW configuration ++ */ ++ data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); ++ if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) ++ goto out; ++ ++ cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); ++ cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; ++ cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; ++ if (!cnf_size) ++ goto out; ++ ++ cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; ++ cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; ++ ++ /* ++ * Configure LCD from extended configuration ++ * region. ++ */ ++ ++ /* cnf_base_addr is in DWORD */ ++ word_addr = (u16)(cnf_base_addr << 1); ++ ++ for (i = 0; i < cnf_size; i++) { ++ ret_val = nvm->ops.read(hw, ++ (word_addr + i * 2), ++ 1, ++ ®_data); ++ if (ret_val) ++ goto out; ++ ++ ret_val = nvm->ops.read(hw, ++ (word_addr + i * 2 + 1), ++ 1, ++ ®_addr); ++ if (ret_val) ++ goto out; ++ ++ /* Save off the PHY page for future writes. */ ++ if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { ++ phy_page = reg_data; ++ continue; ++ } ++ ++ reg_addr |= phy_page; ++ ++ ret_val = phy->ops.write_reg(hw, ++ (u32)reg_addr, ++ reg_data); ++ if (ret_val) ++ goto out; ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info ++ * @hw: pointer to the HW structure ++ * ++ * Wrapper for calling the get_phy_info routines for the appropriate phy type. ++ * This is a function pointer entry point called by drivers ++ * or other shared routines. ++ **/ ++static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = -E1000_ERR_PHY_TYPE; ++ ++ DEBUGFUNC("e1000_get_phy_info_ich8lan"); ++ ++ switch (hw->phy.type) { ++ case e1000_phy_ife: ++ ret_val = e1000_get_phy_info_ife_ich8lan(hw); ++ break; ++ case e1000_phy_igp_3: ++ case e1000_phy_bm: ++ ret_val = e1000_get_phy_info_igp(hw); ++ break; ++ default: ++ break; ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states ++ * @hw: pointer to the HW structure ++ * ++ * Populates "phy" structure with various feature states. ++ * This function is only called by other family-specific ++ * routines. ++ **/ ++static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 data; ++ bool link; ++ ++ DEBUGFUNC("e1000_get_phy_info_ife_ich8lan"); ++ ++ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); ++ if (ret_val) ++ goto out; ++ ++ if (!link) { ++ DEBUGOUT("Phy info is only valid if link is up\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data); ++ if (ret_val) ++ goto out; ++ phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE) ++ ? false : true; ++ ++ if (phy->polarity_correction) { ++ ret_val = e1000_check_polarity_ife_ich8lan(hw); ++ if (ret_val) ++ goto out; ++ } else { ++ /* Polarity is forced */ ++ phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) ++ ? e1000_rev_polarity_reversed ++ : e1000_rev_polarity_normal; ++ } ++ ++ ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); ++ if (ret_val) ++ goto out; ++ ++ phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false; ++ ++ /* The following parameters are undefined for 10/100 operation. */ ++ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; ++ phy->local_rx = e1000_1000t_rx_status_undefined; ++ phy->remote_rx = e1000_1000t_rx_status_undefined; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY ++ * @hw: pointer to the HW structure ++ * ++ * Polarity is determined on the polarity reversal feature being enabled. ++ * This function is only called by other family-specific ++ * routines. ++ **/ ++static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 phy_data, offset, mask; ++ ++ DEBUGFUNC("e1000_check_polarity_ife_ich8lan"); ++ ++ /* ++ * Polarity is determined based on the reversal feature ++ * being enabled. ++ */ ++ if (phy->polarity_correction) { ++ offset = IFE_PHY_EXTENDED_STATUS_CONTROL; ++ mask = IFE_PESC_POLARITY_REVERSED; ++ } else { ++ offset = IFE_PHY_SPECIAL_CONTROL; ++ mask = IFE_PSC_FORCE_POLARITY; ++ } ++ ++ ret_val = phy->ops.read_reg(hw, offset, &phy_data); ++ ++ if (!ret_val) ++ phy->cable_polarity = (phy_data & mask) ++ ? e1000_rev_polarity_reversed ++ : e1000_rev_polarity_normal; ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state ++ * @hw: pointer to the HW structure ++ * @active: true to enable LPLU, false to disable ++ * ++ * Sets the LPLU D0 state according to the active flag. When ++ * activating LPLU this function also disables smart speed ++ * and vice versa. LPLU will not be activated unless the ++ * device autonegotiation advertisement meets standards of ++ * either 10 or 10/100 or 10/100/1000 at all duplexes. ++ * This is a function pointer entry point only called by ++ * PHY setup routines. ++ **/ ++static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, ++ bool active) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ u32 phy_ctrl; ++ s32 ret_val = E1000_SUCCESS; ++ u16 data; ++ ++ DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan"); ++ ++ if (phy->type == e1000_phy_ife) ++ goto out; ++ ++ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); ++ ++ if (active) { ++ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; ++ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); ++ ++ /* ++ * Call gig speed drop workaround on LPLU before accessing ++ * any PHY registers ++ */ ++ if ((hw->mac.type == e1000_ich8lan) && ++ (hw->phy.type == e1000_phy_igp_3)) ++ e1000_gig_downshift_workaround_ich8lan(hw); ++ ++ /* When LPLU is enabled, we should disable SmartSpeed */ ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ data &= ~IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ } else { ++ phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; ++ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); ++ ++ /* ++ * LPLU and SmartSpeed are mutually exclusive. LPLU is used ++ * during Dx states where the power conservation is most ++ * important. During driver activity we should enable ++ * SmartSpeed, so performance is maintained. ++ */ ++ if (phy->smart_speed == e1000_smart_speed_on) { ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data |= IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ } else if (phy->smart_speed == e1000_smart_speed_off) { ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state ++ * @hw: pointer to the HW structure ++ * @active: true to enable LPLU, false to disable ++ * ++ * Sets the LPLU D3 state according to the active flag. When ++ * activating LPLU this function also disables smart speed ++ * and vice versa. LPLU will not be activated unless the ++ * device autonegotiation advertisement meets standards of ++ * either 10 or 10/100 or 10/100/1000 at all duplexes. ++ * This is a function pointer entry point only called by ++ * PHY setup routines. ++ **/ ++static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, ++ bool active) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ u32 phy_ctrl; ++ s32 ret_val = E1000_SUCCESS; ++ u16 data; ++ ++ DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan"); ++ ++ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); ++ ++ if (!active) { ++ phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; ++ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); ++ /* ++ * LPLU and SmartSpeed are mutually exclusive. LPLU is used ++ * during Dx states where the power conservation is most ++ * important. During driver activity we should enable ++ * SmartSpeed, so performance is maintained. ++ */ ++ if (phy->smart_speed == e1000_smart_speed_on) { ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data |= IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ } else if (phy->smart_speed == e1000_smart_speed_off) { ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ } ++ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || ++ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || ++ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { ++ phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; ++ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); ++ ++ /* ++ * Call gig speed drop workaround on LPLU before accessing ++ * any PHY registers ++ */ ++ if ((hw->mac.type == e1000_ich8lan) && ++ (hw->phy.type == e1000_phy_igp_3)) ++ e1000_gig_downshift_workaround_ich8lan(hw); ++ ++ /* When LPLU is enabled, we should disable SmartSpeed */ ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1 ++ * @hw: pointer to the HW structure ++ * @bank: pointer to the variable that returns the active bank ++ * ++ * Reads signature byte from the NVM using the flash access registers. ++ **/ ++static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ /* flash bank size is in words */ ++ u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); ++ u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; ++ u8 bank_high_byte = 0; ++ ++ if (hw->mac.type != e1000_ich10lan) { ++ if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_SEC1VAL) ++ *bank = 1; ++ else ++ *bank = 0; ++ } else if (hw->dev_spec != NULL) { ++ /* ++ * Make sure the signature for bank 0 is valid, ++ * if not check for bank1 ++ */ ++ e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte); ++ if ((bank_high_byte & 0xC0) == 0x80) { ++ *bank = 0; ++ } else { ++ /* ++ * find if segment 1 is valid by verifying ++ * bit 15:14 = 10b in word 0x13 ++ */ ++ e1000_read_flash_byte_ich8lan(hw, ++ act_offset + bank1_offset, ++ &bank_high_byte); ++ ++ /* bank1 has a valid signature equivalent to SEC1V */ ++ if ((bank_high_byte & 0xC0) == 0x80) { ++ *bank = 1; ++ } else { ++ DEBUGOUT("ERROR: EEPROM not present\n"); ++ ret_val = -E1000_ERR_NVM; ++ } ++ } ++ } else { ++ DEBUGOUT("DEV SPEC is NULL\n"); ++ ret_val = -E1000_ERR_NVM; ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_read_nvm_ich8lan - Read word(s) from the NVM ++ * @hw: pointer to the HW structure ++ * @offset: The offset (in bytes) of the word(s) to read. ++ * @words: Size of data to read in words ++ * @data: Pointer to the word(s) to read at offset. ++ * ++ * Reads a word(s) from the NVM using the flash access registers. ++ **/ ++static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, ++ u16 *data) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ struct e1000_dev_spec_ich8lan *dev_spec; ++ u32 act_offset; ++ s32 ret_val = E1000_SUCCESS; ++ u32 bank = 0; ++ u16 i, word; ++ ++ DEBUGFUNC("e1000_read_nvm_ich8lan"); ++ ++ dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; ++ ++ if (!dev_spec) { ++ DEBUGOUT("dev_spec pointer is set to NULL.\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || ++ (words == 0)) { ++ DEBUGOUT("nvm parameter(s) out of bounds\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ ret_val = nvm->ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); ++ if (ret_val != E1000_SUCCESS) ++ goto out; ++ ++ act_offset = (bank) ? nvm->flash_bank_size : 0; ++ act_offset += offset; ++ ++ for (i = 0; i < words; i++) { ++ if ((dev_spec->shadow_ram) && ++ (dev_spec->shadow_ram[offset+i].modified)) { ++ data[i] = dev_spec->shadow_ram[offset+i].value; ++ } else { ++ ret_val = e1000_read_flash_word_ich8lan(hw, ++ act_offset + i, ++ &word); ++ if (ret_val) ++ break; ++ data[i] = word; ++ } ++ } ++ ++ nvm->ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_flash_cycle_init_ich8lan - Initialize flash ++ * @hw: pointer to the HW structure ++ * ++ * This function does initial flash setup so that a new read/write/erase cycle ++ * can be started. ++ **/ ++static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) ++{ ++ union ich8_hws_flash_status hsfsts; ++ s32 ret_val = -E1000_ERR_NVM; ++ s32 i = 0; ++ ++ DEBUGFUNC("e1000_flash_cycle_init_ich8lan"); ++ ++ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); ++ ++ /* Check if the flash descriptor is valid */ ++ if (hsfsts.hsf_status.fldesvalid == 0) { ++ DEBUGOUT("Flash descriptor invalid. " ++ "SW Sequencing must be used."); ++ goto out; ++ } ++ ++ /* Clear FCERR and DAEL in hw status by writing 1 */ ++ hsfsts.hsf_status.flcerr = 1; ++ hsfsts.hsf_status.dael = 1; ++ ++ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); ++ ++ /* ++ * Either we should have a hardware SPI cycle in progress ++ * bit to check against, in order to start a new cycle or ++ * FDONE bit should be changed in the hardware so that it ++ * is 1 after hardware reset, which can then be used as an ++ * indication whether a cycle is in progress or has been ++ * completed. ++ */ ++ ++ if (hsfsts.hsf_status.flcinprog == 0) { ++ /* ++ * There is no cycle running at present, ++ * so we can start a cycle. ++ * Begin by setting Flash Cycle Done. ++ */ ++ hsfsts.hsf_status.flcdone = 1; ++ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); ++ ret_val = E1000_SUCCESS; ++ } else { ++ /* ++ * Otherwise poll for sometime so the current ++ * cycle has a chance to end before giving up. ++ */ ++ for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { ++ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ++ ICH_FLASH_HSFSTS); ++ if (hsfsts.hsf_status.flcinprog == 0) { ++ ret_val = E1000_SUCCESS; ++ break; ++ } ++ usec_delay(1); ++ } ++ if (ret_val == E1000_SUCCESS) { ++ /* ++ * Successful in waiting for previous cycle to timeout, ++ * now set the Flash Cycle Done. ++ */ ++ hsfsts.hsf_status.flcdone = 1; ++ E1000_WRITE_FLASH_REG16(hw, ++ ICH_FLASH_HSFSTS, ++ hsfsts.regval); ++ } else { ++ DEBUGOUT("Flash controller busy, cannot get access"); ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase) ++ * @hw: pointer to the HW structure ++ * @timeout: maximum time to wait for completion ++ * ++ * This function starts a flash cycle and waits for its completion. ++ **/ ++static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) ++{ ++ union ich8_hws_flash_ctrl hsflctl; ++ union ich8_hws_flash_status hsfsts; ++ s32 ret_val = -E1000_ERR_NVM; ++ u32 i = 0; ++ ++ DEBUGFUNC("e1000_flash_cycle_ich8lan"); ++ ++ /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ ++ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); ++ hsflctl.hsf_ctrl.flcgo = 1; ++ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); ++ ++ /* wait till FDONE bit is set to 1 */ ++ do { ++ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); ++ if (hsfsts.hsf_status.flcdone == 1) ++ break; ++ usec_delay(1); ++ } while (i++ < timeout); ++ ++ if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) ++ ret_val = E1000_SUCCESS; ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_read_flash_word_ich8lan - Read word from flash ++ * @hw: pointer to the HW structure ++ * @offset: offset to data location ++ * @data: pointer to the location for storing the data ++ * ++ * Reads the flash word at offset into data. Offset is converted ++ * to bytes before read. ++ **/ ++static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, ++ u16 *data) ++{ ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_read_flash_word_ich8lan"); ++ ++ if (!data) { ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ /* Must convert offset into bytes. */ ++ offset <<= 1; ++ ++ ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_flash_byte_ich8lan - Read byte from flash ++ * @hw: pointer to the HW structure ++ * @offset: The offset of the byte to read. ++ * @data: Pointer to a byte to store the value read. ++ * ++ * Reads a single byte from the NVM using the flash access registers. ++ **/ ++static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, ++ u8* data) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 word = 0; ++ ++ ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word); ++ if (ret_val) ++ goto out; ++ ++ *data = (u8)word; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_flash_data_ich8lan - Read byte or word from NVM ++ * @hw: pointer to the HW structure ++ * @offset: The offset (in bytes) of the byte or word to read. ++ * @size: Size of data to read, 1=byte 2=word ++ * @data: Pointer to the word to store the value read. ++ * ++ * Reads a byte or word from the NVM using the flash access registers. ++ **/ ++static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, ++ u8 size, u16* data) ++{ ++ union ich8_hws_flash_status hsfsts; ++ union ich8_hws_flash_ctrl hsflctl; ++ u32 flash_linear_addr; ++ u32 flash_data = 0; ++ s32 ret_val = -E1000_ERR_NVM; ++ u8 count = 0; ++ ++ DEBUGFUNC("e1000_read_flash_data_ich8lan"); ++ ++ if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) ++ goto out; ++ ++ flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + ++ hw->nvm.flash_base_addr; ++ ++ do { ++ usec_delay(1); ++ /* Steps */ ++ ret_val = e1000_flash_cycle_init_ich8lan(hw); ++ if (ret_val != E1000_SUCCESS) ++ break; ++ ++ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); ++ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ ++ hsflctl.hsf_ctrl.fldbcount = size - 1; ++ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; ++ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); ++ ++ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); ++ ++ ret_val = e1000_flash_cycle_ich8lan(hw, ++ ICH_FLASH_READ_COMMAND_TIMEOUT); ++ ++ /* ++ * Check if FCERR is set to 1, if set to 1, clear it ++ * and try the whole sequence a few more times, else ++ * read in (shift in) the Flash Data0, the order is ++ * least significant byte first msb to lsb ++ */ ++ if (ret_val == E1000_SUCCESS) { ++ flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0); ++ if (size == 1) { ++ *data = (u8)(flash_data & 0x000000FF); ++ } else if (size == 2) { ++ *data = (u16)(flash_data & 0x0000FFFF); ++ } ++ break; ++ } else { ++ /* ++ * If we've gotten here, then things are probably ++ * completely hosed, but if the error condition is ++ * detected, it won't hurt to give it another try... ++ * ICH_FLASH_CYCLE_REPEAT_COUNT times. ++ */ ++ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ++ ICH_FLASH_HSFSTS); ++ if (hsfsts.hsf_status.flcerr == 1) { ++ /* Repeat for some time before giving up. */ ++ continue; ++ } else if (hsfsts.hsf_status.flcdone == 0) { ++ DEBUGOUT("Timeout error - flash cycle " ++ "did not complete."); ++ break; ++ } ++ } ++ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_nvm_ich8lan - Write word(s) to the NVM ++ * @hw: pointer to the HW structure ++ * @offset: The offset (in bytes) of the word(s) to write. ++ * @words: Size of data to write in words ++ * @data: Pointer to the word(s) to write at offset. ++ * ++ * Writes a byte or word to the NVM using the flash access registers. ++ **/ ++static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, ++ u16 *data) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ struct e1000_dev_spec_ich8lan *dev_spec; ++ s32 ret_val = E1000_SUCCESS; ++ u16 i; ++ ++ DEBUGFUNC("e1000_write_nvm_ich8lan"); ++ ++ dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; ++ ++ if (!dev_spec) { ++ DEBUGOUT("dev_spec pointer is set to NULL.\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || ++ (words == 0)) { ++ DEBUGOUT("nvm parameter(s) out of bounds\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ ret_val = nvm->ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ for (i = 0; i < words; i++) { ++ dev_spec->shadow_ram[offset+i].modified = true; ++ dev_spec->shadow_ram[offset+i].value = data[i]; ++ } ++ ++ nvm->ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM ++ * @hw: pointer to the HW structure ++ * ++ * The NVM checksum is updated by calling the generic update_nvm_checksum, ++ * which writes the checksum to the shadow ram. The changes in the shadow ++ * ram are then committed to the EEPROM by processing each bank at a time ++ * checking for the modified bit and writing only the pending changes. ++ * After a successful commit, the shadow ram is cleared and is ready for ++ * future writes. ++ **/ ++static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ struct e1000_dev_spec_ich8lan *dev_spec; ++ u32 i, act_offset, new_bank_offset, old_bank_offset, bank; ++ s32 ret_val; ++ u16 data; ++ ++ DEBUGFUNC("e1000_update_nvm_checksum_ich8lan"); ++ ++ dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; ++ ++ ret_val = e1000_update_nvm_checksum_generic(hw); ++ if (ret_val) ++ goto out; ++ ++ if (nvm->type != e1000_nvm_flash_sw) ++ goto out; ++ ++ ret_val = nvm->ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * We're writing to the opposite bank so if we're on bank 1, ++ * write to bank 0 etc. We also need to erase the segment that ++ * is going to be written ++ */ ++ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); ++ if (ret_val != E1000_SUCCESS) ++ goto out; ++ ++ if (bank == 0) { ++ new_bank_offset = nvm->flash_bank_size; ++ old_bank_offset = 0; ++ e1000_erase_flash_bank_ich8lan(hw, 1); ++ } else { ++ old_bank_offset = nvm->flash_bank_size; ++ new_bank_offset = 0; ++ e1000_erase_flash_bank_ich8lan(hw, 0); ++ } ++ ++ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { ++ /* ++ * Determine whether to write the value stored ++ * in the other NVM bank or a modified value stored ++ * in the shadow RAM ++ */ ++ if (dev_spec->shadow_ram[i].modified) { ++ data = dev_spec->shadow_ram[i].value; ++ } else { ++ e1000_read_flash_word_ich8lan(hw, ++ i + old_bank_offset, ++ &data); ++ } ++ ++ /* ++ * If the word is 0x13, then make sure the signature bits ++ * (15:14) are 11b until the commit has completed. ++ * This will allow us to write 10b which indicates the ++ * signature is valid. We want to do this after the write ++ * has completed so that we don't mark the segment valid ++ * while the write is still in progress ++ */ ++ if (i == E1000_ICH_NVM_SIG_WORD) ++ data |= E1000_ICH_NVM_SIG_MASK; ++ ++ /* Convert offset to bytes. */ ++ act_offset = (i + new_bank_offset) << 1; ++ ++ usec_delay(100); ++ /* Write the bytes to the new bank. */ ++ ret_val = e1000_retry_write_flash_byte_ich8lan(hw, ++ act_offset, ++ (u8)data); ++ if (ret_val) ++ break; ++ ++ usec_delay(100); ++ ret_val = e1000_retry_write_flash_byte_ich8lan(hw, ++ act_offset + 1, ++ (u8)(data >> 8)); ++ if (ret_val) ++ break; ++ } ++ ++ /* ++ * Don't bother writing the segment valid bits if sector ++ * programming failed. ++ */ ++ if (ret_val) { ++ /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */ ++ DEBUGOUT("Flash commit failed.\n"); ++ nvm->ops.release(hw); ++ goto out; ++ } ++ ++ /* ++ * Finally validate the new segment by setting bit 15:14 ++ * to 10b in word 0x13 , this can be done without an ++ * erase as well since these bits are 11 to start with ++ * and we need to change bit 14 to 0b ++ */ ++ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; ++ e1000_read_flash_word_ich8lan(hw, act_offset, &data); ++ data &= 0xBFFF; ++ ret_val = e1000_retry_write_flash_byte_ich8lan(hw, ++ act_offset * 2 + 1, ++ (u8)(data >> 8)); ++ if (ret_val) { ++ nvm->ops.release(hw); ++ goto out; ++ } ++ ++ /* ++ * And invalidate the previously valid segment by setting ++ * its signature word (0x13) high_byte to 0b. This can be ++ * done without an erase because flash erase sets all bits ++ * to 1's. We can write 1's to 0's without an erase ++ */ ++ act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; ++ ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); ++ if (ret_val) { ++ nvm->ops.release(hw); ++ goto out; ++ } ++ ++ /* Great! Everything worked, we can now clear the cached entries. */ ++ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { ++ dev_spec->shadow_ram[i].modified = false; ++ dev_spec->shadow_ram[i].value = 0xFFFF; ++ } ++ ++ nvm->ops.release(hw); ++ ++ /* ++ * Reload the EEPROM, or else modifications will not appear ++ * until after the next adapter reset. ++ */ ++ nvm->ops.reload(hw); ++ msec_delay(10); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum ++ * @hw: pointer to the HW structure ++ * ++ * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19. ++ * If the bit is 0, that the EEPROM had been modified, but the checksum was ++ * not calculated, in which case we need to calculate the checksum and set ++ * bit 6. ++ **/ ++static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 data; ++ ++ DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan"); ++ ++ /* ++ * Read 0x19 and check bit 6. If this bit is 0, the checksum ++ * needs to be fixed. This bit is an indication that the NVM ++ * was prepared by OEM software and did not calculate the ++ * checksum...a likely scenario. ++ */ ++ ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data); ++ if (ret_val) ++ goto out; ++ ++ if ((data & 0x40) == 0) { ++ data |= 0x40; ++ ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data); ++ if (ret_val) ++ goto out; ++ ret_val = hw->nvm.ops.update(hw); ++ if (ret_val) ++ goto out; ++ } ++ ++ ret_val = e1000_validate_nvm_checksum_generic(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000e_write_protect_nvm_ich8lan - Make the NVM read-only ++ * @hw: pointer to the HW structure ++ * ++ * To prevent malicious write/erase of the NVM, set it to be read-only ++ * so that the hardware ignores all write/erase cycles of the NVM via ++ * the flash control registers. The shadow-ram copy of the NVM will ++ * still be updated, however any updates to this copy will not stick ++ * across driver reloads. ++ **/ ++void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw) ++{ ++ union ich8_flash_protected_range pr0; ++ union ich8_hws_flash_status hsfsts; ++ u32 gfpreg; ++ s32 ret_val; ++ ++ ret_val = e1000_acquire_swflag_ich8lan(hw); ++ if (ret_val) ++ return; ++ ++ gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG); ++ ++ /* Write-protect GbE Sector of NVM */ ++ pr0.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_PR0); ++ pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK; ++ pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK); ++ pr0.range.wpe = true; ++ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_PR0, pr0.regval); ++ ++ /* ++ * Lock down a subset of GbE Flash Control Registers, e.g. ++ * PR0 to prevent the write-protection from being lifted. ++ * Once FLOCKDN is set, the registers protected by it cannot ++ * be written until FLOCKDN is cleared by a hardware reset. ++ */ ++ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); ++ hsfsts.hsf_status.flockdn = true; ++ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); ++ ++ e1000_release_swflag_ich8lan(hw); ++} ++ ++/** ++ * e1000_write_flash_data_ich8lan - Writes bytes to the NVM ++ * @hw: pointer to the HW structure ++ * @offset: The offset (in bytes) of the byte/word to read. ++ * @size: Size of data to read, 1=byte 2=word ++ * @data: The byte(s) to write to the NVM. ++ * ++ * Writes one/two bytes to the NVM using the flash access registers. ++ **/ ++static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, ++ u8 size, u16 data) ++{ ++ union ich8_hws_flash_status hsfsts; ++ union ich8_hws_flash_ctrl hsflctl; ++ u32 flash_linear_addr; ++ u32 flash_data = 0; ++ s32 ret_val = -E1000_ERR_NVM; ++ u8 count = 0; ++ ++ DEBUGFUNC("e1000_write_ich8_data"); ++ ++ if (size < 1 || size > 2 || data > size * 0xff || ++ offset > ICH_FLASH_LINEAR_ADDR_MASK) ++ goto out; ++ ++ flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + ++ hw->nvm.flash_base_addr; ++ ++ do { ++ usec_delay(1); ++ /* Steps */ ++ ret_val = e1000_flash_cycle_init_ich8lan(hw); ++ if (ret_val != E1000_SUCCESS) ++ break; ++ ++ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); ++ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ ++ hsflctl.hsf_ctrl.fldbcount = size -1; ++ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; ++ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); ++ ++ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); ++ ++ if (size == 1) ++ flash_data = (u32)data & 0x00FF; ++ else ++ flash_data = (u32)data; ++ ++ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data); ++ ++ /* ++ * check if FCERR is set to 1 , if set to 1, clear it ++ * and try the whole sequence a few more times else done ++ */ ++ ret_val = e1000_flash_cycle_ich8lan(hw, ++ ICH_FLASH_WRITE_COMMAND_TIMEOUT); ++ if (ret_val == E1000_SUCCESS) { ++ break; ++ } else { ++ /* ++ * If we're here, then things are most likely ++ * completely hosed, but if the error condition ++ * is detected, it won't hurt to give it another ++ * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. ++ */ ++ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ++ ICH_FLASH_HSFSTS); ++ if (hsfsts.hsf_status.flcerr == 1) { ++ /* Repeat for some time before giving up. */ ++ continue; ++ } else if (hsfsts.hsf_status.flcdone == 0) { ++ DEBUGOUT("Timeout error - flash cycle " ++ "did not complete."); ++ break; ++ } ++ } ++ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_flash_byte_ich8lan - Write a single byte to NVM ++ * @hw: pointer to the HW structure ++ * @offset: The index of the byte to read. ++ * @data: The byte to write to the NVM. ++ * ++ * Writes a single byte to the NVM using the flash access registers. ++ **/ ++static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, ++ u8 data) ++{ ++ u16 word = (u16)data; ++ ++ DEBUGFUNC("e1000_write_flash_byte_ich8lan"); ++ ++ return e1000_write_flash_data_ich8lan(hw, offset, 1, word); ++} ++ ++/** ++ * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM ++ * @hw: pointer to the HW structure ++ * @offset: The offset of the byte to write. ++ * @byte: The byte to write to the NVM. ++ * ++ * Writes a single byte to the NVM using the flash access registers. ++ * Goes through a retry algorithm before giving up. ++ **/ ++static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, ++ u32 offset, u8 byte) ++{ ++ s32 ret_val; ++ u16 program_retries; ++ ++ DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan"); ++ ++ ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); ++ if (ret_val == E1000_SUCCESS) ++ goto out; ++ ++ for (program_retries = 0; program_retries < 100; program_retries++) { ++ DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset); ++ usec_delay(100); ++ ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); ++ if (ret_val == E1000_SUCCESS) ++ break; ++ } ++ if (program_retries == 100) { ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM ++ * @hw: pointer to the HW structure ++ * @bank: 0 for first bank, 1 for second bank, etc. ++ * ++ * Erases the bank specified. Each bank is a 4k block. Banks are 0 based. ++ * bank N is 4096 * N + flash_reg_addr. ++ **/ ++static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ union ich8_hws_flash_status hsfsts; ++ union ich8_hws_flash_ctrl hsflctl; ++ u32 flash_linear_addr; ++ /* bank size is in 16bit words - adjust to bytes */ ++ u32 flash_bank_size = nvm->flash_bank_size * 2; ++ s32 ret_val = E1000_SUCCESS; ++ s32 count = 0; ++ s32 j, iteration, sector_size; ++ ++ DEBUGFUNC("e1000_erase_flash_bank_ich8lan"); ++ ++ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); ++ ++ /* ++ * Determine HW Sector size: Read BERASE bits of hw flash status ++ * register ++ * 00: The Hw sector is 256 bytes, hence we need to erase 16 ++ * consecutive sectors. The start index for the nth Hw sector ++ * can be calculated as = bank * 4096 + n * 256 ++ * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. ++ * The start index for the nth Hw sector can be calculated ++ * as = bank * 4096 ++ * 10: The Hw sector is 8K bytes, nth sector = bank * 8192 ++ * (ich9 only, otherwise error condition) ++ * 11: The Hw sector is 64K bytes, nth sector = bank * 65536 ++ */ ++ switch (hsfsts.hsf_status.berasesz) { ++ case 0: ++ /* Hw sector size 256 */ ++ sector_size = ICH_FLASH_SEG_SIZE_256; ++ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256; ++ break; ++ case 1: ++ sector_size = ICH_FLASH_SEG_SIZE_4K; ++ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K; ++ break; ++ case 2: ++ if (hw->mac.type == e1000_ich9lan) { ++ sector_size = ICH_FLASH_SEG_SIZE_8K; ++ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K; ++ } else { ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ break; ++ case 3: ++ sector_size = ICH_FLASH_SEG_SIZE_64K; ++ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K; ++ break; ++ default: ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ /* Start with the base address, then add the sector offset. */ ++ flash_linear_addr = hw->nvm.flash_base_addr; ++ flash_linear_addr += (bank) ? (sector_size * iteration) : 0; ++ ++ for (j = 0; j < iteration ; j++) { ++ do { ++ /* Steps */ ++ ret_val = e1000_flash_cycle_init_ich8lan(hw); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Write a value 11 (block Erase) in Flash ++ * Cycle field in hw flash control ++ */ ++ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ++ ICH_FLASH_HSFCTL); ++ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; ++ E1000_WRITE_FLASH_REG16(hw, ++ ICH_FLASH_HSFCTL, ++ hsflctl.regval); ++ ++ /* ++ * Write the last 24 bits of an index within the ++ * block into Flash Linear address field in Flash ++ * Address. ++ */ ++ flash_linear_addr += (j * sector_size); ++ E1000_WRITE_FLASH_REG(hw, ++ ICH_FLASH_FADDR, ++ flash_linear_addr); ++ ++ ret_val = e1000_flash_cycle_ich8lan(hw, ++ ICH_FLASH_ERASE_COMMAND_TIMEOUT); ++ if (ret_val == E1000_SUCCESS) { ++ break; ++ } else { ++ /* ++ * Check if FCERR is set to 1. If 1, ++ * clear it and try the whole sequence ++ * a few more times else Done ++ */ ++ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ++ ICH_FLASH_HSFSTS); ++ if (hsfsts.hsf_status.flcerr == 1) { ++ /* ++ * repeat for some time before ++ * giving up ++ */ ++ continue; ++ } else if (hsfsts.hsf_status.flcdone == 0) ++ goto out; ++ } ++ } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_valid_led_default_ich8lan - Set the default LED settings ++ * @hw: pointer to the HW structure ++ * @data: Pointer to the LED settings ++ * ++ * Reads the LED default settings from the NVM to data. If the NVM LED ++ * settings is all 0's or F's, set the LED default to a valid LED default ++ * setting. ++ **/ ++static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) ++{ ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_valid_led_default_ich8lan"); ++ ++ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error\n"); ++ goto out; ++ } ++ ++ if (*data == ID_LED_RESERVED_0000 || ++ *data == ID_LED_RESERVED_FFFF) ++ *data = ID_LED_DEFAULT_ICH8LAN; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_bus_info_ich8lan - Get/Set the bus type and width ++ * @hw: pointer to the HW structure ++ * ++ * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability ++ * register, so the the bus width is hard coded. ++ **/ ++static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_bus_info *bus = &hw->bus; ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_get_bus_info_ich8lan"); ++ ++ ret_val = e1000_get_bus_info_pcie_generic(hw); ++ ++ /* ++ * ICH devices are "PCI Express"-ish. They have ++ * a configuration space, but do not contain ++ * PCI Express Capability registers, so bus width ++ * must be hardcoded. ++ */ ++ if (bus->width == e1000_bus_width_unknown) ++ bus->width = e1000_bus_width_pcie_x1; ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_reset_hw_ich8lan - Reset the hardware ++ * @hw: pointer to the HW structure ++ * ++ * Does a full reset of the hardware which includes a reset of the PHY and ++ * MAC. ++ **/ ++static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ++{ ++ u32 ctrl, icr, kab; ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_reset_hw_ich8lan"); ++ ++ /* ++ * Prevent the PCI-E bus from sticking if there is no TLP connection ++ * on the last TLP read/write transaction when MAC is reset. ++ */ ++ ret_val = e1000_disable_pcie_master_generic(hw); ++ if (ret_val) { ++ DEBUGOUT("PCI-E Master disable polling has failed.\n"); ++ } ++ ++ DEBUGOUT("Masking off all interrupts\n"); ++ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); ++ ++ /* ++ * Disable the Transmit and Receive units. Then delay to allow ++ * any pending transactions to complete before we hit the MAC ++ * with the global reset. ++ */ ++ E1000_WRITE_REG(hw, E1000_RCTL, 0); ++ E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); ++ E1000_WRITE_FLUSH(hw); ++ ++ msec_delay(10); ++ ++ /* Workaround for ICH8 bit corruption issue in FIFO memory */ ++ if (hw->mac.type == e1000_ich8lan) { ++ /* Set Tx and Rx buffer allocation to 8k apiece. */ ++ E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K); ++ /* Set Packet Buffer Size to 16k. */ ++ E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K); ++ } ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ++ if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) { ++ /* ++ * PHY HW reset requires MAC CORE reset at the same ++ * time to make sure the interface between MAC and the ++ * external PHY is reset. ++ */ ++ ctrl |= E1000_CTRL_PHY_RST; ++ } ++ ret_val = e1000_acquire_swflag_ich8lan(hw); ++ DEBUGOUT("Issuing a global reset to ich8lan"); ++ E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST)); ++ msec_delay(20); ++ ++ ret_val = e1000_get_auto_rd_done_generic(hw); ++ if (ret_val) { ++ /* ++ * When auto config read does not complete, do not ++ * return with an error. This can happen in situations ++ * where there is no eeprom and prevents getting link. ++ */ ++ DEBUGOUT("Auto Read Done did not complete\n"); ++ } ++ ++ E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); ++ icr = E1000_READ_REG(hw, E1000_ICR); ++ ++ kab = E1000_READ_REG(hw, E1000_KABGTXD); ++ kab |= E1000_KABGTXD_BGSQLBIAS; ++ E1000_WRITE_REG(hw, E1000_KABGTXD, kab); ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_init_hw_ich8lan - Initialize the hardware ++ * @hw: pointer to the HW structure ++ * ++ * Prepares the hardware for transmit and receive by doing the following: ++ * - initialize hardware bits ++ * - initialize LED identification ++ * - setup receive address registers ++ * - setup flow control ++ * - setup transmit descriptors ++ * - clear statistics ++ **/ ++static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ u32 ctrl_ext, txdctl, snoop; ++ s32 ret_val; ++ u16 i; ++ ++ DEBUGFUNC("e1000_init_hw_ich8lan"); ++ ++ e1000_initialize_hw_bits_ich8lan(hw); ++ ++ /* Initialize identification LED */ ++ ret_val = e1000_id_led_init_generic(hw); ++ if (ret_val) { ++ DEBUGOUT("Error initializing identification LED\n"); ++ /* This is not fatal and we should not stop init due to this */ ++ } ++ ++ /* Setup the receive address. */ ++ e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); ++ ++ /* Zero out the Multicast HASH table */ ++ DEBUGOUT("Zeroing the MTA\n"); ++ for (i = 0; i < mac->mta_reg_count; i++) ++ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); ++ ++ /* Setup link and flow control */ ++ ret_val = mac->ops.setup_link(hw); ++ ++ /* Set the transmit descriptor write-back policy for both queues */ ++ txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0)); ++ txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | ++ E1000_TXDCTL_FULL_TX_DESC_WB; ++ txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | ++ E1000_TXDCTL_MAX_TX_DESC_PREFETCH; ++ E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl); ++ txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1)); ++ txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | ++ E1000_TXDCTL_FULL_TX_DESC_WB; ++ txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | ++ E1000_TXDCTL_MAX_TX_DESC_PREFETCH; ++ E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl); ++ ++ /* ++ * ICH8 has opposite polarity of no_snoop bits. ++ * By default, we should use snoop behavior. ++ */ ++ if (mac->type == e1000_ich8lan) ++ snoop = PCIE_ICH8_SNOOP_ALL; ++ else ++ snoop = (u32)~(PCIE_NO_SNOOP_ALL); ++ e1000_set_pcie_no_snoop_generic(hw, snoop); ++ ++ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); ++ ctrl_ext |= E1000_CTRL_EXT_RO_DIS; ++ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); ++ ++ /* ++ * Clear all of the statistics registers (clear on read). It is ++ * important that we do this after we have tried to establish link ++ * because the symbol error count will increment wildly if there ++ * is no link. ++ */ ++ e1000_clear_hw_cntrs_ich8lan(hw); ++ ++ return ret_val; ++} ++/** ++ * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits ++ * @hw: pointer to the HW structure ++ * ++ * Sets/Clears required hardware bits necessary for correctly setting up the ++ * hardware for transmit and receive. ++ **/ ++static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) ++{ ++ u32 reg; ++ ++ DEBUGFUNC("e1000_initialize_hw_bits_ich8lan"); ++ ++ if (hw->mac.disable_hw_init_bits) ++ goto out; ++ ++ /* Extended Device Control */ ++ reg = E1000_READ_REG(hw, E1000_CTRL_EXT); ++ reg |= (1 << 22); ++ E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); ++ ++ /* Transmit Descriptor Control 0 */ ++ reg = E1000_READ_REG(hw, E1000_TXDCTL(0)); ++ reg |= (1 << 22); ++ E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg); ++ ++ /* Transmit Descriptor Control 1 */ ++ reg = E1000_READ_REG(hw, E1000_TXDCTL(1)); ++ reg |= (1 << 22); ++ E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg); ++ ++ /* Transmit Arbitration Control 0 */ ++ reg = E1000_READ_REG(hw, E1000_TARC(0)); ++ if (hw->mac.type == e1000_ich8lan) ++ reg |= (1 << 28) | (1 << 29); ++ reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27); ++ E1000_WRITE_REG(hw, E1000_TARC(0), reg); ++ ++ /* Transmit Arbitration Control 1 */ ++ reg = E1000_READ_REG(hw, E1000_TARC(1)); ++ if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR) ++ reg &= ~(1 << 28); ++ else ++ reg |= (1 << 28); ++ reg |= (1 << 24) | (1 << 26) | (1 << 30); ++ E1000_WRITE_REG(hw, E1000_TARC(1), reg); ++ ++ /* Device Status */ ++ if (hw->mac.type == e1000_ich8lan) { ++ reg = E1000_READ_REG(hw, E1000_STATUS); ++ reg &= ~(1 << 31); ++ E1000_WRITE_REG(hw, E1000_STATUS, reg); ++ } ++ ++out: ++ return; ++} ++ ++/** ++ * e1000_setup_link_ich8lan - Setup flow control and link settings ++ * @hw: pointer to the HW structure ++ * ++ * Determines which flow control settings to use, then configures flow ++ * control. Calls the appropriate media-specific link configuration ++ * function. Assuming the adapter has a valid link partner, a valid link ++ * should be established. Assumes the hardware has previously been reset ++ * and the transmitter and receiver are not enabled. ++ **/ ++static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_setup_link_ich8lan"); ++ ++ if (hw->phy.ops.check_reset_block(hw)) ++ goto out; ++ ++ /* ++ * ICH parts do not have a word in the NVM to determine ++ * the default flow control setting, so we explicitly ++ * set it to full. ++ */ ++ if (hw->fc.type == e1000_fc_default) ++ hw->fc.type = e1000_fc_full; ++ ++ hw->fc.original_type = hw->fc.type; ++ ++ DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc.type); ++ ++ /* Continue to configure the copper link. */ ++ ret_val = hw->mac.ops.setup_physical_interface(hw); ++ if (ret_val) ++ goto out; ++ ++ E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); ++ ++ ret_val = e1000_set_fc_watermarks_generic(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface ++ * @hw: pointer to the HW structure ++ * ++ * Configures the kumeran interface to the PHY to wait the appropriate time ++ * when polling the PHY, then call the generic setup_copper_link to finish ++ * configuring the copper link. ++ **/ ++static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) ++{ ++ u32 ctrl; ++ s32 ret_val; ++ u16 reg_data; ++ ++ DEBUGFUNC("e1000_setup_copper_link_ich8lan"); ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ctrl |= E1000_CTRL_SLU; ++ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ ++ /* ++ * Set the mac to wait the maximum time between each iteration ++ * and increase the max iterations when polling the phy; ++ * this fixes erroneous timeouts at 10Mbps. ++ */ ++ ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 4), ++ 0xFFFF); ++ if (ret_val) ++ goto out; ++ ret_val = e1000_read_kmrn_reg_generic(hw, GG82563_REG(0x34, 9), ++ ®_data); ++ if (ret_val) ++ goto out; ++ reg_data |= 0x3F; ++ ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 9), ++ reg_data); ++ if (ret_val) ++ goto out; ++ ++ if (hw->phy.type == e1000_phy_igp_3) { ++ ret_val = e1000_copper_link_setup_igp(hw); ++ if (ret_val) ++ goto out; ++ } else if (hw->phy.type == e1000_phy_bm) { ++ ret_val = e1000_copper_link_setup_m88(hw); ++ if (ret_val) ++ goto out; ++ } ++ ++ if (hw->phy.type == e1000_phy_ife) { ++ ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, ++ ®_data); ++ if (ret_val) ++ goto out; ++ ++ reg_data &= ~IFE_PMC_AUTO_MDIX; ++ ++ switch (hw->phy.mdix) { ++ case 1: ++ reg_data &= ~IFE_PMC_FORCE_MDIX; ++ break; ++ case 2: ++ reg_data |= IFE_PMC_FORCE_MDIX; ++ break; ++ case 0: ++ default: ++ reg_data |= IFE_PMC_AUTO_MDIX; ++ break; ++ } ++ ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, ++ reg_data); ++ if (ret_val) ++ goto out; ++ } ++ ret_val = e1000_setup_copper_link_generic(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_link_up_info_ich8lan - Get current link speed and duplex ++ * @hw: pointer to the HW structure ++ * @speed: pointer to store current link speed ++ * @duplex: pointer to store the current link duplex ++ * ++ * Calls the generic get_speed_and_duplex to retrieve the current link ++ * information and then calls the Kumeran lock loss workaround for links at ++ * gigabit speeds. ++ **/ ++static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, ++ u16 *duplex) ++{ ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_get_link_up_info_ich8lan"); ++ ++ ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex); ++ if (ret_val) ++ goto out; ++ ++ if ((hw->mac.type == e1000_ich8lan) && ++ (hw->phy.type == e1000_phy_igp_3) && ++ (*speed == SPEED_1000)) { ++ ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround ++ * @hw: pointer to the HW structure ++ * ++ * Work-around for 82566 Kumeran PCS lock loss: ++ * On link status change (i.e. PCI reset, speed change) and link is up and ++ * speed is gigabit- ++ * 0) if workaround is optionally disabled do nothing ++ * 1) wait 1ms for Kumeran link to come up ++ * 2) check Kumeran Diagnostic register PCS lock loss bit ++ * 3) if not set the link is locked (all is good), otherwise... ++ * 4) reset the PHY ++ * 5) repeat up to 10 times ++ * Note: this is only called for IGP3 copper when speed is 1gb. ++ **/ ++static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_dev_spec_ich8lan *dev_spec; ++ u32 phy_ctrl; ++ s32 ret_val = E1000_SUCCESS; ++ u16 i, data; ++ bool link; ++ ++ DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan"); ++ ++ dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; ++ ++ if (!dev_spec) { ++ DEBUGOUT("dev_spec pointer is set to NULL.\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ if (!(dev_spec->kmrn_lock_loss_workaround_enabled)) ++ goto out; ++ ++ /* ++ * Make sure link is up before proceeding. If not just return. ++ * Attempting this while link is negotiating fouled up link ++ * stability ++ */ ++ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); ++ if (!link) { ++ ret_val = E1000_SUCCESS; ++ goto out; ++ } ++ ++ for (i = 0; i < 10; i++) { ++ /* read once to clear */ ++ ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); ++ if (ret_val) ++ goto out; ++ /* and again to get new status */ ++ ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); ++ if (ret_val) ++ goto out; ++ ++ /* check for PCS lock */ ++ if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) { ++ ret_val = E1000_SUCCESS; ++ goto out; ++ } ++ ++ /* Issue PHY reset */ ++ hw->phy.ops.reset(hw); ++ msec_delay_irq(5); ++ } ++ /* Disable GigE link negotiation */ ++ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); ++ phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | ++ E1000_PHY_CTRL_NOND0A_GBE_DISABLE); ++ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); ++ ++ /* ++ * Call gig speed drop workaround on Gig disable before accessing ++ * any PHY registers ++ */ ++ e1000_gig_downshift_workaround_ich8lan(hw); ++ ++ /* unable to acquire PCS lock */ ++ ret_val = -E1000_ERR_PHY; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state ++ * @hw: pointer to the HW structure ++ * @state: boolean value used to set the current Kumeran workaround state ++ * ++ * If ICH8, set the current Kumeran workaround state (enabled - true ++ * /disabled - false). ++ **/ ++void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, ++ bool state) ++{ ++ struct e1000_dev_spec_ich8lan *dev_spec; ++ ++ DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan"); ++ ++ if (hw->mac.type != e1000_ich8lan) { ++ DEBUGOUT("Workaround applies to ICH8 only.\n"); ++ goto out; ++ } ++ ++ dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; ++ ++ if (!dev_spec) { ++ DEBUGOUT("dev_spec pointer is set to NULL.\n"); ++ goto out; ++ } ++ ++ dev_spec->kmrn_lock_loss_workaround_enabled = state; ++ ++out: ++ return; ++} ++ ++/** ++ * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 ++ * @hw: pointer to the HW structure ++ * ++ * Workaround for 82566 power-down on D3 entry: ++ * 1) disable gigabit link ++ * 2) write VR power-down enable ++ * 3) read it back ++ * Continue if successful, else issue LCD reset and repeat ++ **/ ++void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) ++{ ++ u32 reg; ++ u16 data; ++ u8 retry = 0; ++ ++ DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan"); ++ ++ if (hw->phy.type != e1000_phy_igp_3) ++ goto out; ++ ++ /* Try the workaround twice (if needed) */ ++ do { ++ /* Disable link */ ++ reg = E1000_READ_REG(hw, E1000_PHY_CTRL); ++ reg |= (E1000_PHY_CTRL_GBE_DISABLE | ++ E1000_PHY_CTRL_NOND0A_GBE_DISABLE); ++ E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg); ++ ++ /* ++ * Call gig speed drop workaround on Gig disable before ++ * accessing any PHY registers ++ */ ++ if (hw->mac.type == e1000_ich8lan) ++ e1000_gig_downshift_workaround_ich8lan(hw); ++ ++ /* Write VR power-down enable */ ++ hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); ++ data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; ++ hw->phy.ops.write_reg(hw, ++ IGP3_VR_CTRL, ++ data | IGP3_VR_CTRL_MODE_SHUTDOWN); ++ ++ /* Read it back and test */ ++ hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); ++ data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; ++ if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) ++ break; ++ ++ /* Issue PHY reset and repeat at most one more time */ ++ reg = E1000_READ_REG(hw, E1000_CTRL); ++ E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST); ++ retry++; ++ } while (retry); ++ ++out: ++ return; ++} ++ ++/** ++ * e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working ++ * @hw: pointer to the HW structure ++ * ++ * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), ++ * LPLU, Gig disable, MDIC PHY reset): ++ * 1) Set Kumeran Near-end loopback ++ * 2) Clear Kumeran Near-end loopback ++ * Should only be called for ICH8[m] devices with IGP_3 Phy. ++ **/ ++void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 reg_data; ++ ++ DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan"); ++ ++ if ((hw->mac.type != e1000_ich8lan) || ++ (hw->phy.type != e1000_phy_igp_3)) ++ goto out; ++ ++ ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, ++ ®_data); ++ if (ret_val) ++ goto out; ++ reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; ++ ret_val = e1000_write_kmrn_reg_generic(hw, ++ E1000_KMRNCTRLSTA_DIAG_OFFSET, ++ reg_data); ++ if (ret_val) ++ goto out; ++ reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; ++ ret_val = e1000_write_kmrn_reg_generic(hw, ++ E1000_KMRNCTRLSTA_DIAG_OFFSET, ++ reg_data); ++out: ++ return; ++} ++ ++/** ++ * e1000_disable_gig_wol_ich8lan - disable gig during WoL ++ * @hw: pointer to the HW structure ++ * ++ * During S0 to Sx transition, it is possible the link remains at gig ++ * instead of negotiating to a lower speed. Before going to Sx, set ++ * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation ++ * to a lower speed. ++ * ++ * Should only be called for ICH9 and ICH10 devices. ++ **/ ++void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw) ++{ ++ u32 phy_ctrl; ++ ++ if ((hw->mac.type == e1000_ich10lan) || ++ (hw->mac.type == e1000_ich9lan)) { ++ phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); ++ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | ++ E1000_PHY_CTRL_GBE_DISABLE; ++ E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); ++ } ++ ++ return; ++} ++ ++/** ++ * e1000_cleanup_led_ich8lan - Restore the default LED operation ++ * @hw: pointer to the HW structure ++ * ++ * Return the LED back to the default configuration. ++ **/ ++static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_cleanup_led_ich8lan"); ++ ++ if (hw->phy.type == e1000_phy_ife) ++ ret_val = hw->phy.ops.write_reg(hw, ++ IFE_PHY_SPECIAL_CONTROL_LED, ++ 0); ++ else ++ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_led_on_ich8lan - Turn LEDs on ++ * @hw: pointer to the HW structure ++ * ++ * Turn on the LEDs. ++ **/ ++static s32 e1000_led_on_ich8lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_led_on_ich8lan"); ++ ++ if (hw->phy.type == e1000_phy_ife) ++ ret_val = hw->phy.ops.write_reg(hw, ++ IFE_PHY_SPECIAL_CONTROL_LED, ++ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); ++ else ++ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_led_off_ich8lan - Turn LEDs off ++ * @hw: pointer to the HW structure ++ * ++ * Turn off the LEDs. ++ **/ ++static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_led_off_ich8lan"); ++ ++ if (hw->phy.type == e1000_phy_ife) ++ ret_val = hw->phy.ops.write_reg(hw, ++ IFE_PHY_SPECIAL_CONTROL_LED, ++ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); ++ else ++ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_get_cfg_done_ich8lan - Read config done bit ++ * @hw: pointer to the HW structure ++ * ++ * Read the management control register for the config done bit for ++ * completion status. NOTE: silicon which is EEPROM-less will fail trying ++ * to read the config done bit, so an error is *ONLY* logged and returns ++ * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon ++ * would not be able to be reset or change link. ++ **/ ++static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u32 bank = 0; ++ ++ e1000_get_cfg_done_generic(hw); ++ ++ /* If EEPROM is not marked present, init the IGP 3 PHY manually */ ++ if (hw->mac.type != e1000_ich10lan) { ++ if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) && ++ (hw->phy.type == e1000_phy_igp_3)) { ++ e1000_phy_init_script_igp3(hw); ++ } ++ } else { ++ if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) { ++ /* Maybe we should do a basic Boazman config */ ++ DEBUGOUT("EEPROM not present\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ } ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down ++ * @hw: pointer to the HW structure ++ * ++ * In the case of a PHY power down to save power, or to turn off link during a ++ * driver unload, or wake on lan is not enabled, remove the link. ++ **/ ++static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ struct e1000_mac_info *mac = &hw->mac; ++ ++ /* If the management interface is not enabled, then power down */ ++ if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw))) ++ e1000_power_down_phy_copper(hw); ++ ++ return; ++} ++ ++/** ++ * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters ++ * @hw: pointer to the HW structure ++ * ++ * Clears hardware counters specific to the silicon family and calls ++ * clear_hw_cntrs_generic to clear all general purpose counters. ++ **/ ++static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) ++{ ++ volatile u32 temp; ++ ++ DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan"); ++ ++ e1000_clear_hw_cntrs_base_generic(hw); ++ ++ temp = E1000_READ_REG(hw, E1000_ALGNERRC); ++ temp = E1000_READ_REG(hw, E1000_RXERRC); ++ temp = E1000_READ_REG(hw, E1000_TNCRS); ++ temp = E1000_READ_REG(hw, E1000_CEXTERR); ++ temp = E1000_READ_REG(hw, E1000_TSCTC); ++ temp = E1000_READ_REG(hw, E1000_TSCTFC); ++ ++ temp = E1000_READ_REG(hw, E1000_MGTPRC); ++ temp = E1000_READ_REG(hw, E1000_MGTPDC); ++ temp = E1000_READ_REG(hw, E1000_MGTPTC); ++ ++ temp = E1000_READ_REG(hw, E1000_IAC); ++ temp = E1000_READ_REG(hw, E1000_ICRXOC); ++} ++ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_ich8lan.h linux-2.6.22-10/drivers/net/e1000e/e1000_ich8lan.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_ich8lan.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_ich8lan.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,144 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _E1000_ICH8LAN_H_ ++#define _E1000_ICH8LAN_H_ ++ ++#define ICH_FLASH_GFPREG 0x0000 ++#define ICH_FLASH_HSFSTS 0x0004 ++#define ICH_FLASH_HSFCTL 0x0006 ++#define ICH_FLASH_FADDR 0x0008 ++#define ICH_FLASH_FDATA0 0x0010 ++#define ICH_FLASH_PR0 0x0074 ++ ++#define ICH_FLASH_READ_COMMAND_TIMEOUT 500 ++#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500 ++#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 3000000 ++#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF ++#define ICH_FLASH_CYCLE_REPEAT_COUNT 10 ++ ++#define ICH_CYCLE_READ 0 ++#define ICH_CYCLE_WRITE 2 ++#define ICH_CYCLE_ERASE 3 ++ ++#define FLASH_GFPREG_BASE_MASK 0x1FFF ++#define FLASH_SECTOR_ADDR_SHIFT 12 ++ ++#define E1000_SHADOW_RAM_WORDS 2048 ++ ++#define ICH_FLASH_SEG_SIZE_256 256 ++#define ICH_FLASH_SEG_SIZE_4K 4096 ++#define ICH_FLASH_SEG_SIZE_8K 8192 ++#define ICH_FLASH_SEG_SIZE_64K 65536 ++#define ICH_FLASH_SECTOR_SIZE 4096 ++ ++#define ICH_FLASH_REG_MAPSIZE 0x00A0 ++ ++#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */ ++#define E1000_ICH_FWSM_DISSW 0x10000000 /* FW Disables SW Writes */ ++/* FW established a valid mode */ ++#define E1000_ICH_FWSM_FW_VALID 0x00008000 ++ ++#define E1000_ICH_MNG_IAMT_MODE 0x2 ++ ++#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ ++ (ID_LED_DEF1_OFF2 << 8) | \ ++ (ID_LED_DEF1_ON2 << 4) | \ ++ (ID_LED_DEF1_DEF2)) ++ ++#define E1000_ICH_NVM_SIG_WORD 0x13 ++#define E1000_ICH_NVM_SIG_MASK 0xC000 ++ ++#define E1000_ICH8_LAN_INIT_TIMEOUT 1500 ++ ++#define E1000_FEXTNVM_SW_CONFIG 1 ++#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */ ++ ++#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL ++ ++#define E1000_ICH_RAR_ENTRIES 7 ++ ++#define PHY_PAGE_SHIFT 5 ++#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \ ++ ((reg) & MAX_PHY_REG_ADDRESS)) ++#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */ ++#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */ ++#define IGP3_CAPABILITY PHY_REG(776, 19) /* Capability */ ++#define IGP3_PM_CTRL PHY_REG(769, 20) /* Power Management Control */ ++ ++#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002 ++#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300 ++#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200 ++#define IGP3_PM_CTRL_FORCE_PWR_DOWN 0x0020 ++ ++/* ++ * Additional interrupts need to be handled for ICH family: ++ * DSW = The FW changed the status of the DISSW bit in FWSM ++ * PHYINT = The LAN connected device generates an interrupt ++ * EPRST = Manageability reset event ++ */ ++#define IMS_ICH_ENABLE_MASK (\ ++ E1000_IMS_DSW | \ ++ E1000_IMS_PHYINT | \ ++ E1000_IMS_EPRST) ++ ++/* Additional interrupt register bit definitions */ ++#define E1000_ICR_LSECPNC 0x00004000 /* PN threshold - client */ ++#define E1000_IMS_LSECPNC E1000_ICR_LSECPNC /* PN threshold - client */ ++#define E1000_ICS_LSECPNC E1000_ICR_LSECPNC /* PN threshold - client */ ++ ++/* Security Processing bit Indication */ ++#define E1000_RXDEXT_LINKSEC_STATUS_LSECH 0x01000000 ++#define E1000_RXDEXT_LINKSEC_ERROR_BIT_MASK 0x60000000 ++#define E1000_RXDEXT_LINKSEC_ERROR_NO_SA_MATCH 0x20000000 ++#define E1000_RXDEXT_LINKSEC_ERROR_REPLAY_ERROR 0x40000000 ++#define E1000_RXDEXT_LINKSEC_ERROR_BAD_SIG 0x60000000 ++ ++ ++/* ICH Flash Protected Region */ ++union ich8_flash_protected_range { ++ struct ich8_pr { ++ u32 base:13; /* 0:12 Protected Range Base */ ++ u32 reserved1:2; /* 13:14 Reserved */ ++ u32 rpe:1; /* 15 Read Protection Enable */ ++ u32 limit:13; /* 16:28 Protected Range Limit */ ++ u32 reserved2:2; /* 29:30 Reserved */ ++ u32 wpe:1; /* 31 Write Protection Enable */ ++ } range; ++ u32 regval; ++}; ++ ++void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, ++ bool state); ++void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw); ++ ++void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); ++void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); ++void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw); ++ ++#endif +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_mac.c linux-2.6.22-10/drivers/net/e1000e/e1000_mac.c +--- linux-2.6.22-0/drivers/net/e1000e/e1000_mac.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_mac.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,1988 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include "e1000_hw.h" ++ ++/** ++ * e1000_init_mac_ops_generic - Initialize MAC function pointers ++ * @hw: pointer to the HW structure ++ * ++ * Setups up the function pointers to no-op functions ++ **/ ++void e1000_init_mac_ops_generic(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ DEBUGFUNC("e1000_init_mac_ops_generic"); ++ ++ /* General Setup */ ++ mac->ops.read_mac_addr = e1000_read_mac_addr_generic; ++ mac->ops.remove_device = e1000_remove_device_generic; ++ mac->ops.config_collision_dist = e1000_config_collision_dist_generic; ++ /* LINK */ ++ mac->ops.wait_autoneg = e1000_wait_autoneg_generic; ++ /* Management */ ++ mac->ops.mng_host_if_write = e1000_mng_host_if_write_generic; ++ mac->ops.mng_write_cmd_header = e1000_mng_write_cmd_header_generic; ++ mac->ops.mng_enable_host_if = e1000_mng_enable_host_if_generic; ++ /* VLAN, MC, etc. */ ++ mac->ops.rar_set = e1000_rar_set_generic; ++ mac->ops.validate_mdi_setting = e1000_validate_mdi_setting_generic; ++} ++ ++/** ++ * e1000_remove_device_generic - Free device specific structure ++ * @hw: pointer to the HW structure ++ * ++ * If a device specific structure was allocated, this function will ++ * free it. ++ **/ ++void e1000_remove_device_generic(struct e1000_hw *hw) ++{ ++ DEBUGFUNC("e1000_remove_device_generic"); ++ ++ /* Freeing the dev_spec member of e1000_hw structure */ ++ e1000_free_dev_spec_struct(hw); ++} ++ ++/** ++ * e1000_get_bus_info_pcie_generic - Get PCIe bus information ++ * @hw: pointer to the HW structure ++ * ++ * Determines and stores the system bus information for a particular ++ * network interface. The following bus information is determined and stored: ++ * bus speed, bus width, type (PCIe), and PCIe function. ++ **/ ++s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw) ++{ ++ struct e1000_bus_info *bus = &hw->bus; ++ s32 ret_val; ++ u32 status; ++ u16 pcie_link_status, pci_header_type; ++ ++ DEBUGFUNC("e1000_get_bus_info_pcie_generic"); ++ ++ bus->type = e1000_bus_type_pci_express; ++ bus->speed = e1000_bus_speed_2500; ++ ++ ret_val = e1000_read_pcie_cap_reg(hw, ++ PCIE_LINK_STATUS, ++ &pcie_link_status); ++ if (ret_val) ++ bus->width = e1000_bus_width_unknown; ++ else ++ bus->width = (e1000_bus_width)((pcie_link_status & ++ PCIE_LINK_WIDTH_MASK) >> ++ PCIE_LINK_WIDTH_SHIFT); ++ ++ e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type); ++ if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) { ++ status = E1000_READ_REG(hw, E1000_STATUS); ++ bus->func = (status & E1000_STATUS_FUNC_MASK) ++ >> E1000_STATUS_FUNC_SHIFT; ++ } else { ++ bus->func = 0; ++ } ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_clear_vfta_generic - Clear VLAN filter table ++ * @hw: pointer to the HW structure ++ * ++ * Clears the register array which contains the VLAN filter table by ++ * setting all the values to 0. ++ **/ ++void e1000_clear_vfta_generic(struct e1000_hw *hw) ++{ ++ u32 offset; ++ ++ DEBUGFUNC("e1000_clear_vfta_generic"); ++ ++ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { ++ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0); ++ E1000_WRITE_FLUSH(hw); ++ } ++} ++ ++/** ++ * e1000_write_vfta_generic - Write value to VLAN filter table ++ * @hw: pointer to the HW structure ++ * @offset: register offset in VLAN filter table ++ * @value: register value written to VLAN filter table ++ * ++ * Writes value at the given offset in the register array which stores ++ * the VLAN filter table. ++ **/ ++void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value) ++{ ++ DEBUGFUNC("e1000_write_vfta_generic"); ++ ++ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value); ++ E1000_WRITE_FLUSH(hw); ++} ++ ++/** ++ * e1000_init_rx_addrs_generic - Initialize receive address's ++ * @hw: pointer to the HW structure ++ * @rar_count: receive address registers ++ * ++ * Setups the receive address registers by setting the base receive address ++ * register to the devices MAC address and clearing all the other receive ++ * address registers to 0. ++ **/ ++void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count) ++{ ++ u32 i; ++ ++ DEBUGFUNC("e1000_init_rx_addrs_generic"); ++ ++ /* Setup the receive address */ ++ DEBUGOUT("Programming MAC Address into RAR[0]\n"); ++ ++ hw->mac.ops.rar_set(hw, hw->mac.addr, 0); ++ ++ /* Zero out the other (rar_entry_count - 1) receive addresses */ ++ DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1); ++ for (i = 1; i < rar_count; i++) { ++ E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0); ++ E1000_WRITE_FLUSH(hw); ++ E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0); ++ E1000_WRITE_FLUSH(hw); ++ } ++} ++ ++/** ++ * e1000_check_alt_mac_addr_generic - Check for alternate MAC addr ++ * @hw: pointer to the HW structure ++ * ++ * Checks the nvm for an alternate MAC address. An alternate MAC address ++ * can be setup by pre-boot software and must be treated like a permanent ++ * address and must override the actual permanent MAC address. If an ++ * alternate MAC address is found it is saved in the hw struct and ++ * programmed into RAR0 and the function returns success, otherwise the ++ * function returns an error. ++ **/ ++s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) ++{ ++ u32 i; ++ s32 ret_val = E1000_SUCCESS; ++ u16 offset, nvm_alt_mac_addr_offset, nvm_data; ++ u8 alt_mac_addr[ETH_ADDR_LEN]; ++ ++ DEBUGFUNC("e1000_check_alt_mac_addr_generic"); ++ ++ ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1, ++ &nvm_alt_mac_addr_offset); ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error\n"); ++ goto out; ++ } ++ ++ if (nvm_alt_mac_addr_offset == 0xFFFF) { ++ ret_val = -(E1000_NOT_IMPLEMENTED); ++ goto out; ++ } ++ ++ if (hw->bus.func == E1000_FUNC_1) ++ nvm_alt_mac_addr_offset += ETH_ADDR_LEN/sizeof(u16); ++ ++ for (i = 0; i < ETH_ADDR_LEN; i += 2) { ++ offset = nvm_alt_mac_addr_offset + (i >> 1); ++ ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error\n"); ++ goto out; ++ } ++ ++ alt_mac_addr[i] = (u8)(nvm_data & 0xFF); ++ alt_mac_addr[i + 1] = (u8)(nvm_data >> 8); ++ } ++ ++ /* if multicast bit is set, the alternate address will not be used */ ++ if (alt_mac_addr[0] & 0x01) { ++ ret_val = -(E1000_NOT_IMPLEMENTED); ++ goto out; ++ } ++ ++ for (i = 0; i < ETH_ADDR_LEN; i++) ++ hw->mac.addr[i] = hw->mac.perm_addr[i] = alt_mac_addr[i]; ++ ++ hw->mac.ops.rar_set(hw, hw->mac.perm_addr, 0); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_rar_set_generic - Set receive address register ++ * @hw: pointer to the HW structure ++ * @addr: pointer to the receive address ++ * @index: receive address array register ++ * ++ * Sets the receive address array register at index to the address passed ++ * in by addr. ++ **/ ++void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index) ++{ ++ u32 rar_low, rar_high; ++ ++ DEBUGFUNC("e1000_rar_set_generic"); ++ ++ /* ++ * HW expects these in little endian so we reverse the byte order ++ * from network order (big endian) to little endian ++ */ ++ rar_low = ((u32) addr[0] | ++ ((u32) addr[1] << 8) | ++ ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); ++ ++ rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); ++ ++ /* If MAC address zero, no need to set the AV bit */ ++ if (rar_low || rar_high) { ++ if (!hw->mac.disable_av) ++ rar_high |= E1000_RAH_AV; ++ } ++ ++ E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); ++ E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); ++} ++ ++/** ++ * e1000_mta_set_generic - Set multicast filter table address ++ * @hw: pointer to the HW structure ++ * @hash_value: determines the MTA register and bit to set ++ * ++ * The multicast table address is a register array of 32-bit registers. ++ * The hash_value is used to determine what register the bit is in, the ++ * current value is read, the new bit is OR'd in and the new value is ++ * written back into the register. ++ **/ ++void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value) ++{ ++ u32 hash_bit, hash_reg, mta; ++ ++ DEBUGFUNC("e1000_mta_set_generic"); ++ /* ++ * The MTA is a register array of 32-bit registers. It is ++ * treated like an array of (32*mta_reg_count) bits. We want to ++ * set bit BitArray[hash_value]. So we figure out what register ++ * the bit is in, read it, OR in the new bit, then write ++ * back the new value. The (hw->mac.mta_reg_count - 1) serves as a ++ * mask to bits 31:5 of the hash value which gives us the ++ * register we're modifying. The hash bit within that register ++ * is determined by the lower 5 bits of the hash value. ++ */ ++ hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); ++ hash_bit = hash_value & 0x1F; ++ ++ mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg); ++ ++ mta |= (1 << hash_bit); ++ ++ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta); ++ E1000_WRITE_FLUSH(hw); ++} ++ ++/** ++ * e1000_update_mc_addr_list_generic - Update Multicast addresses ++ * @hw: pointer to the HW structure ++ * @mc_addr_list: array of multicast addresses to program ++ * @mc_addr_count: number of multicast addresses to program ++ * @rar_used_count: the first RAR register free to program ++ * @rar_count: total number of supported Receive Address Registers ++ * ++ * Updates the Receive Address Registers and Multicast Table Array. ++ * The caller must have a packed mc_addr_list of multicast addresses. ++ * The parameter rar_count will usually be hw->mac.rar_entry_count ++ * unless there are workarounds that change this. ++ **/ ++void e1000_update_mc_addr_list_generic(struct e1000_hw *hw, ++ u8 *mc_addr_list, u32 mc_addr_count, ++ u32 rar_used_count, u32 rar_count) ++{ ++ u32 hash_value; ++ u32 i; ++ ++ DEBUGFUNC("e1000_update_mc_addr_list_generic"); ++ ++ /* ++ * Load the first set of multicast addresses into the exact ++ * filters (RAR). If there are not enough to fill the RAR ++ * array, clear the filters. ++ */ ++ for (i = rar_used_count; i < rar_count; i++) { ++ if (mc_addr_count) { ++ hw->mac.ops.rar_set(hw, mc_addr_list, i); ++ mc_addr_count--; ++ mc_addr_list += ETH_ADDR_LEN; ++ } else { ++ E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0); ++ E1000_WRITE_FLUSH(hw); ++ E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0); ++ E1000_WRITE_FLUSH(hw); ++ } ++ } ++ ++ /* Clear the old settings from the MTA */ ++ DEBUGOUT("Clearing MTA\n"); ++ for (i = 0; i < hw->mac.mta_reg_count; i++) { ++ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); ++ E1000_WRITE_FLUSH(hw); ++ } ++ ++ /* Load any remaining multicast addresses into the hash table. */ ++ for (; mc_addr_count > 0; mc_addr_count--) { ++ hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list); ++ DEBUGOUT1("Hash value = 0x%03X\n", hash_value); ++ hw->mac.ops.mta_set(hw, hash_value); ++ mc_addr_list += ETH_ADDR_LEN; ++ } ++} ++ ++/** ++ * e1000_hash_mc_addr_generic - Generate a multicast hash value ++ * @hw: pointer to the HW structure ++ * @mc_addr: pointer to a multicast address ++ * ++ * Generates a multicast address hash value which is used to determine ++ * the multicast filter table array address and new table value. See ++ * e1000_mta_set_generic() ++ **/ ++u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr) ++{ ++ u32 hash_value, hash_mask; ++ u8 bit_shift = 0; ++ ++ DEBUGFUNC("e1000_hash_mc_addr_generic"); ++ ++ /* Register count multiplied by bits per register */ ++ hash_mask = (hw->mac.mta_reg_count * 32) - 1; ++ ++ /* ++ * For a mc_filter_type of 0, bit_shift is the number of left-shifts ++ * where 0xFF would still fall within the hash mask. ++ */ ++ while (hash_mask >> bit_shift != 0xFF) ++ bit_shift++; ++ ++ /* ++ * The portion of the address that is used for the hash table ++ * is determined by the mc_filter_type setting. ++ * The algorithm is such that there is a total of 8 bits of shifting. ++ * The bit_shift for a mc_filter_type of 0 represents the number of ++ * left-shifts where the MSB of mc_addr[5] would still fall within ++ * the hash_mask. Case 0 does this exactly. Since there are a total ++ * of 8 bits of shifting, then mc_addr[4] will shift right the ++ * remaining number of bits. Thus 8 - bit_shift. The rest of the ++ * cases are a variation of this algorithm...essentially raising the ++ * number of bits to shift mc_addr[5] left, while still keeping the ++ * 8-bit shifting total. ++ * ++ * For example, given the following Destination MAC Address and an ++ * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask), ++ * we can see that the bit_shift for case 0 is 4. These are the hash ++ * values resulting from each mc_filter_type... ++ * [0] [1] [2] [3] [4] [5] ++ * 01 AA 00 12 34 56 ++ * LSB MSB ++ * ++ * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 ++ * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 ++ * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 ++ * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 ++ */ ++ switch (hw->mac.mc_filter_type) { ++ default: ++ case 0: ++ break; ++ case 1: ++ bit_shift += 1; ++ break; ++ case 2: ++ bit_shift += 2; ++ break; ++ case 3: ++ bit_shift += 4; ++ break; ++ } ++ ++ hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | ++ (((u16) mc_addr[5]) << bit_shift))); ++ ++ return hash_value; ++} ++ ++/** ++ * e1000_clear_hw_cntrs_base_generic - Clear base hardware counters ++ * @hw: pointer to the HW structure ++ * ++ * Clears the base hardware counters by reading the counter registers. ++ **/ ++void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw) ++{ ++ volatile u32 temp; ++ ++ DEBUGFUNC("e1000_clear_hw_cntrs_base_generic"); ++ ++ temp = E1000_READ_REG(hw, E1000_CRCERRS); ++ temp = E1000_READ_REG(hw, E1000_SYMERRS); ++ temp = E1000_READ_REG(hw, E1000_MPC); ++ temp = E1000_READ_REG(hw, E1000_SCC); ++ temp = E1000_READ_REG(hw, E1000_ECOL); ++ temp = E1000_READ_REG(hw, E1000_MCC); ++ temp = E1000_READ_REG(hw, E1000_LATECOL); ++ temp = E1000_READ_REG(hw, E1000_COLC); ++ temp = E1000_READ_REG(hw, E1000_DC); ++ temp = E1000_READ_REG(hw, E1000_SEC); ++ temp = E1000_READ_REG(hw, E1000_RLEC); ++ temp = E1000_READ_REG(hw, E1000_XONRXC); ++ temp = E1000_READ_REG(hw, E1000_XONTXC); ++ temp = E1000_READ_REG(hw, E1000_XOFFRXC); ++ temp = E1000_READ_REG(hw, E1000_XOFFTXC); ++ temp = E1000_READ_REG(hw, E1000_FCRUC); ++ temp = E1000_READ_REG(hw, E1000_GPRC); ++ temp = E1000_READ_REG(hw, E1000_BPRC); ++ temp = E1000_READ_REG(hw, E1000_MPRC); ++ temp = E1000_READ_REG(hw, E1000_GPTC); ++ temp = E1000_READ_REG(hw, E1000_GORCL); ++ temp = E1000_READ_REG(hw, E1000_GORCH); ++ temp = E1000_READ_REG(hw, E1000_GOTCL); ++ temp = E1000_READ_REG(hw, E1000_GOTCH); ++ temp = E1000_READ_REG(hw, E1000_RNBC); ++ temp = E1000_READ_REG(hw, E1000_RUC); ++ temp = E1000_READ_REG(hw, E1000_RFC); ++ temp = E1000_READ_REG(hw, E1000_ROC); ++ temp = E1000_READ_REG(hw, E1000_RJC); ++ temp = E1000_READ_REG(hw, E1000_TORL); ++ temp = E1000_READ_REG(hw, E1000_TORH); ++ temp = E1000_READ_REG(hw, E1000_TOTL); ++ temp = E1000_READ_REG(hw, E1000_TOTH); ++ temp = E1000_READ_REG(hw, E1000_TPR); ++ temp = E1000_READ_REG(hw, E1000_TPT); ++ temp = E1000_READ_REG(hw, E1000_MPTC); ++ temp = E1000_READ_REG(hw, E1000_BPTC); ++} ++ ++/** ++ * e1000_check_for_copper_link_generic - Check for link (Copper) ++ * @hw: pointer to the HW structure ++ * ++ * Checks to see of the link status of the hardware has changed. If a ++ * change in link status has been detected, then we read the PHY registers ++ * to get the current speed/duplex if link exists. ++ **/ ++s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ s32 ret_val; ++ bool link; ++ ++ DEBUGFUNC("e1000_check_for_copper_link"); ++ ++ /* ++ * We only want to go out to the PHY registers to see if Auto-Neg ++ * has completed and/or if our link status has changed. The ++ * get_link_status flag is set upon receiving a Link Status ++ * Change or Rx Sequence Error interrupt. ++ */ ++ if (!mac->get_link_status) { ++ ret_val = E1000_SUCCESS; ++ goto out; ++ } ++ ++ /* ++ * First we want to see if the MII Status Register reports ++ * link. If so, then we want to get the current speed/duplex ++ * of the PHY. ++ */ ++ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); ++ if (ret_val) ++ goto out; ++ ++ if (!link) ++ goto out; /* No link detected */ ++ ++ mac->get_link_status = false; ++ ++ /* ++ * Check if there was DownShift, must be checked ++ * immediately after link-up ++ */ ++ e1000_check_downshift_generic(hw); ++ ++ /* ++ * If we are forcing speed/duplex, then we simply return since ++ * we have already determined whether we have link or not. ++ */ ++ if (!mac->autoneg) { ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ /* ++ * Auto-Neg is enabled. Auto Speed Detection takes care ++ * of MAC speed/duplex configuration. So we only need to ++ * configure Collision Distance in the MAC. ++ */ ++ e1000_config_collision_dist_generic(hw); ++ ++ /* ++ * Configure Flow Control now that Auto-Neg has completed. ++ * First, we need to restore the desired flow control ++ * settings because we may have had to re-autoneg with a ++ * different link partner. ++ */ ++ ret_val = e1000_config_fc_after_link_up_generic(hw); ++ if (ret_val) { ++ DEBUGOUT("Error configuring flow control\n"); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_check_for_fiber_link_generic - Check for link (Fiber) ++ * @hw: pointer to the HW structure ++ * ++ * Checks for link up on the hardware. If link is not up and we have ++ * a signal, then we need to force link up. ++ **/ ++s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ u32 rxcw; ++ u32 ctrl; ++ u32 status; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_check_for_fiber_link_generic"); ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ status = E1000_READ_REG(hw, E1000_STATUS); ++ rxcw = E1000_READ_REG(hw, E1000_RXCW); ++ ++ /* ++ * If we don't have link (auto-negotiation failed or link partner ++ * cannot auto-negotiate), the cable is plugged in (we have signal), ++ * and our link partner is not trying to auto-negotiate with us (we ++ * are receiving idles or data), we need to force link up. We also ++ * need to give auto-negotiation time to complete, in case the cable ++ * was just plugged in. The autoneg_failed flag does this. ++ */ ++ /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ ++ if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) && ++ (!(rxcw & E1000_RXCW_C))) { ++ if (mac->autoneg_failed == 0) { ++ mac->autoneg_failed = 1; ++ goto out; ++ } ++ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n"); ++ ++ /* Disable auto-negotiation in the TXCW register */ ++ E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE)); ++ ++ /* Force link-up and also force full-duplex. */ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ ++ /* Configure Flow Control after forcing link up. */ ++ ret_val = e1000_config_fc_after_link_up_generic(hw); ++ if (ret_val) { ++ DEBUGOUT("Error configuring flow control\n"); ++ goto out; ++ } ++ } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { ++ /* ++ * If we are forcing link and we are receiving /C/ ordered ++ * sets, re-enable auto-negotiation in the TXCW register ++ * and disable forced link in the Device Control register ++ * in an attempt to auto-negotiate with our link partner. ++ */ ++ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n"); ++ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); ++ E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU)); ++ ++ mac->serdes_has_link = true; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_check_for_serdes_link_generic - Check for link (Serdes) ++ * @hw: pointer to the HW structure ++ * ++ * Checks for link up on the hardware. If link is not up and we have ++ * a signal, then we need to force link up. ++ **/ ++s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ u32 rxcw; ++ u32 ctrl; ++ u32 status; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_check_for_serdes_link_generic"); ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ status = E1000_READ_REG(hw, E1000_STATUS); ++ rxcw = E1000_READ_REG(hw, E1000_RXCW); ++ ++ /* ++ * If we don't have link (auto-negotiation failed or link partner ++ * cannot auto-negotiate), and our link partner is not trying to ++ * auto-negotiate with us (we are receiving idles or data), ++ * we need to force link up. We also need to give auto-negotiation ++ * time to complete. ++ */ ++ /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ ++ if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) { ++ if (mac->autoneg_failed == 0) { ++ mac->autoneg_failed = 1; ++ goto out; ++ } ++ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n"); ++ ++ /* Disable auto-negotiation in the TXCW register */ ++ E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE)); ++ ++ /* Force link-up and also force full-duplex. */ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ ++ /* Configure Flow Control after forcing link up. */ ++ ret_val = e1000_config_fc_after_link_up_generic(hw); ++ if (ret_val) { ++ DEBUGOUT("Error configuring flow control\n"); ++ goto out; ++ } ++ } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { ++ /* ++ * If we are forcing link and we are receiving /C/ ordered ++ * sets, re-enable auto-negotiation in the TXCW register ++ * and disable forced link in the Device Control register ++ * in an attempt to auto-negotiate with our link partner. ++ */ ++ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n"); ++ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); ++ E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU)); ++ ++ mac->serdes_has_link = true; ++ } else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) { ++ /* ++ * If we force link for non-auto-negotiation switch, check ++ * link status based on MAC synchronization for internal ++ * serdes media type. ++ */ ++ /* SYNCH bit and IV bit are sticky. */ ++ usec_delay(10); ++ rxcw = E1000_READ_REG(hw, E1000_RXCW); ++ if (rxcw & E1000_RXCW_SYNCH) { ++ if (!(rxcw & E1000_RXCW_IV)) { ++ mac->serdes_has_link = true; ++ DEBUGOUT("SERDES: Link up - forced.\n"); ++ } ++ } else { ++ mac->serdes_has_link = false; ++ DEBUGOUT("SERDES: Link down - force failed.\n"); ++ } ++ } ++ ++ if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) { ++ status = E1000_READ_REG(hw, E1000_STATUS); ++ if (status & E1000_STATUS_LU) { ++ /* SYNCH bit and IV bit are sticky, so reread rxcw. */ ++ usec_delay(10); ++ rxcw = E1000_READ_REG(hw, E1000_RXCW); ++ if (rxcw & E1000_RXCW_SYNCH) { ++ if (!(rxcw & E1000_RXCW_IV)) { ++ mac->serdes_has_link = TRUE; ++ DEBUGOUT("SERDES: Link up - autoneg " ++ "completed sucessfully.\n"); ++ } else { ++ mac->serdes_has_link = FALSE; ++ DEBUGOUT("SERDES: Link down - invalid" ++ "codewords detected in autoneg.\n"); ++ } ++ } else { ++ mac->serdes_has_link = FALSE; ++ DEBUGOUT("SERDES: Link down - no sync.\n"); ++ } ++ } else { ++ mac->serdes_has_link = FALSE; ++ DEBUGOUT("SERDES: Link down - autoneg failed\n"); ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_setup_link_generic - Setup flow control and link settings ++ * @hw: pointer to the HW structure ++ * ++ * Determines which flow control settings to use, then configures flow ++ * control. Calls the appropriate media-specific link configuration ++ * function. Assuming the adapter has a valid link partner, a valid link ++ * should be established. Assumes the hardware has previously been reset ++ * and the transmitter and receiver are not enabled. ++ **/ ++s32 e1000_setup_link_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_setup_link_generic"); ++ ++ /* ++ * In the case of the phy reset being blocked, we already have a link. ++ * We do not need to set it up again. ++ */ ++ if (hw->phy.ops.check_reset_block) ++ if (hw->phy.ops.check_reset_block(hw)) ++ goto out; ++ ++ /* ++ * If flow control is set to default, set flow control based on ++ * the EEPROM flow control settings. ++ */ ++ if (hw->fc.type == e1000_fc_default) { ++ ret_val = e1000_set_default_fc_generic(hw); ++ if (ret_val) ++ goto out; ++ } ++ ++ /* ++ * We want to save off the original Flow Control configuration just ++ * in case we get disconnected and then reconnected into a different ++ * hub or switch with different Flow Control capabilities. ++ */ ++ hw->fc.original_type = hw->fc.type; ++ ++ DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc.type); ++ ++ /* Call the necessary media_type subroutine to configure the link. */ ++ ret_val = hw->mac.ops.setup_physical_interface(hw); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Initialize the flow control address, type, and PAUSE timer ++ * registers to their default values. This is done even if flow ++ * control is disabled, because it does not hurt anything to ++ * initialize these registers. ++ */ ++ DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); ++ E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE); ++ E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH); ++ E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW); ++ ++ E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); ++ ++ ret_val = e1000_set_fc_watermarks_generic(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_setup_fiber_serdes_link_generic - Setup link for fiber/serdes ++ * @hw: pointer to the HW structure ++ * ++ * Configures collision distance and flow control for fiber and serdes ++ * links. Upon successful setup, poll for link. ++ **/ ++s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw) ++{ ++ u32 ctrl; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_setup_fiber_serdes_link_generic"); ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ++ /* Take the link out of reset */ ++ ctrl &= ~E1000_CTRL_LRST; ++ ++ e1000_config_collision_dist_generic(hw); ++ ++ ret_val = e1000_commit_fc_settings_generic(hw); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Since auto-negotiation is enabled, take the link out of reset (the ++ * link will be in reset, because we previously reset the chip). This ++ * will restart auto-negotiation. If auto-negotiation is successful ++ * then the link-up status bit will be set and the flow control enable ++ * bits (RFCE and TFCE) will be set according to their negotiated value. ++ */ ++ DEBUGOUT("Auto-negotiation enabled\n"); ++ ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ E1000_WRITE_FLUSH(hw); ++ msec_delay(1); ++ ++ /* ++ * For these adapters, the SW definable pin 1 is set when the optics ++ * detect a signal. If we have a signal, then poll for a "Link-Up" ++ * indication. ++ */ ++ if (hw->phy.media_type == e1000_media_type_internal_serdes || ++ (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) { ++ ret_val = e1000_poll_fiber_serdes_link_generic(hw); ++ } else { ++ DEBUGOUT("No signal detected\n"); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_config_collision_dist_generic - Configure collision distance ++ * @hw: pointer to the HW structure ++ * ++ * Configures the collision distance to the default value and is used ++ * during link setup. Currently no func pointer exists and all ++ * implementations are handled in the generic version of this function. ++ **/ ++void e1000_config_collision_dist_generic(struct e1000_hw *hw) ++{ ++ u32 tctl; ++ ++ DEBUGFUNC("e1000_config_collision_dist_generic"); ++ ++ tctl = E1000_READ_REG(hw, E1000_TCTL); ++ ++ tctl &= ~E1000_TCTL_COLD; ++ tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; ++ ++ E1000_WRITE_REG(hw, E1000_TCTL, tctl); ++ E1000_WRITE_FLUSH(hw); ++} ++ ++/** ++ * e1000_poll_fiber_serdes_link_generic - Poll for link up ++ * @hw: pointer to the HW structure ++ * ++ * Polls for link up by reading the status register, if link fails to come ++ * up with auto-negotiation, then the link is forced if a signal is detected. ++ **/ ++s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ u32 i, status; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_poll_fiber_serdes_link_generic"); ++ ++ /* ++ * If we have a signal (the cable is plugged in, or assumed true for ++ * serdes media) then poll for a "Link-Up" indication in the Device ++ * Status Register. Time-out if a link isn't seen in 500 milliseconds ++ * seconds (Auto-negotiation should complete in less than 500 ++ * milliseconds even if the other end is doing it in SW). ++ */ ++ for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { ++ msec_delay(10); ++ status = E1000_READ_REG(hw, E1000_STATUS); ++ if (status & E1000_STATUS_LU) ++ break; ++ } ++ if (i == FIBER_LINK_UP_LIMIT) { ++ DEBUGOUT("Never got a valid link from auto-neg!!!\n"); ++ mac->autoneg_failed = 1; ++ /* ++ * AutoNeg failed to achieve a link, so we'll call ++ * mac->check_for_link. This routine will force the ++ * link up if we detect a signal. This will allow us to ++ * communicate with non-autonegotiating link partners. ++ */ ++ ret_val = hw->mac.ops.check_for_link(hw); ++ if (ret_val) { ++ DEBUGOUT("Error while checking for link\n"); ++ goto out; ++ } ++ mac->autoneg_failed = 0; ++ } else { ++ mac->autoneg_failed = 0; ++ DEBUGOUT("Valid Link Found\n"); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_commit_fc_settings_generic - Configure flow control ++ * @hw: pointer to the HW structure ++ * ++ * Write the flow control settings to the Transmit Config Word Register (TXCW) ++ * base on the flow control settings in e1000_mac_info. ++ **/ ++s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ u32 txcw; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_commit_fc_settings_generic"); ++ ++ /* ++ * Check for a software override of the flow control settings, and ++ * setup the device accordingly. If auto-negotiation is enabled, then ++ * software will have to set the "PAUSE" bits to the correct value in ++ * the Transmit Config Word Register (TXCW) and re-start auto- ++ * negotiation. However, if auto-negotiation is disabled, then ++ * software will have to manually configure the two flow control enable ++ * bits in the CTRL register. ++ * ++ * The possible values of the "fc" parameter are: ++ * 0: Flow control is completely disabled ++ * 1: Rx flow control is enabled (we can receive pause frames, ++ * but not send pause frames). ++ * 2: Tx flow control is enabled (we can send pause frames but we ++ * do not support receiving pause frames). ++ * 3: Both Rx and Tx flow control (symmetric) are enabled. ++ */ ++ switch (hw->fc.type) { ++ case e1000_fc_none: ++ /* Flow control completely disabled by a software over-ride. */ ++ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); ++ break; ++ case e1000_fc_rx_pause: ++ /* ++ * Rx Flow control is enabled and Tx Flow control is disabled ++ * by a software over-ride. Since there really isn't a way to ++ * advertise that we are capable of Rx Pause ONLY, we will ++ * advertise that we support both symmetric and asymmetric RX ++ * PAUSE. Later, we will disable the adapter's ability to send ++ * PAUSE frames. ++ */ ++ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); ++ break; ++ case e1000_fc_tx_pause: ++ /* ++ * Tx Flow control is enabled, and Rx Flow control is disabled, ++ * by a software over-ride. ++ */ ++ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); ++ break; ++ case e1000_fc_full: ++ /* ++ * Flow control (both Rx and Tx) is enabled by a software ++ * over-ride. ++ */ ++ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); ++ break; ++ default: ++ DEBUGOUT("Flow control param set incorrectly\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ break; ++ } ++ ++ E1000_WRITE_REG(hw, E1000_TXCW, txcw); ++ mac->txcw = txcw; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_set_fc_watermarks_generic - Set flow control high/low watermarks ++ * @hw: pointer to the HW structure ++ * ++ * Sets the flow control high/low threshold (watermark) registers. If ++ * flow control XON frame transmission is enabled, then set XON frame ++ * transmission as well. ++ **/ ++s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u32 fcrtl = 0, fcrth = 0; ++ ++ DEBUGFUNC("e1000_set_fc_watermarks_generic"); ++ ++ /* ++ * Set the flow control receive threshold registers. Normally, ++ * these registers will be set to a default threshold that may be ++ * adjusted later by the driver's runtime code. However, if the ++ * ability to transmit pause frames is not enabled, then these ++ * registers will be set to 0. ++ */ ++ if (hw->fc.type & e1000_fc_tx_pause) { ++ /* ++ * We need to set up the Receive Threshold high and low water ++ * marks as well as (optionally) enabling the transmission of ++ * XON frames. ++ */ ++ fcrtl = hw->fc.low_water; ++ if (hw->fc.send_xon) ++ fcrtl |= E1000_FCRTL_XONE; ++ ++ fcrth = hw->fc.high_water; ++ } ++ E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl); ++ E1000_WRITE_REG(hw, E1000_FCRTH, fcrth); ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_set_default_fc_generic - Set flow control default values ++ * @hw: pointer to the HW structure ++ * ++ * Read the EEPROM for the default values for flow control and store the ++ * values. ++ **/ ++s32 e1000_set_default_fc_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 nvm_data; ++ ++ DEBUGFUNC("e1000_set_default_fc_generic"); ++ ++ /* ++ * Read and store word 0x0F of the EEPROM. This word contains bits ++ * that determine the hardware's default PAUSE (flow control) mode, ++ * a bit that determines whether the HW defaults to enabling or ++ * disabling auto-negotiation, and the direction of the ++ * SW defined pins. If there is no SW over-ride of the flow ++ * control setting, then the variable hw->fc will ++ * be initialized based on a value in the EEPROM. ++ */ ++ ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data); ++ ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error\n"); ++ goto out; ++ } ++ ++ if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) ++ hw->fc.type = e1000_fc_none; ++ else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == ++ NVM_WORD0F_ASM_DIR) ++ hw->fc.type = e1000_fc_tx_pause; ++ else ++ hw->fc.type = e1000_fc_full; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_force_mac_fc_generic - Force the MAC's flow control settings ++ * @hw: pointer to the HW structure ++ * ++ * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the ++ * device control register to reflect the adapter settings. TFCE and RFCE ++ * need to be explicitly set by software when a copper PHY is used because ++ * autonegotiation is managed by the PHY rather than the MAC. Software must ++ * also configure these bits when link is forced on a fiber connection. ++ **/ ++s32 e1000_force_mac_fc_generic(struct e1000_hw *hw) ++{ ++ u32 ctrl; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_force_mac_fc_generic"); ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ++ /* ++ * Because we didn't get link via the internal auto-negotiation ++ * mechanism (we either forced link or we got link via PHY ++ * auto-neg), we have to manually enable/disable transmit an ++ * receive flow control. ++ * ++ * The "Case" statement below enables/disable flow control ++ * according to the "hw->fc.type" parameter. ++ * ++ * The possible values of the "fc" parameter are: ++ * 0: Flow control is completely disabled ++ * 1: Rx flow control is enabled (we can receive pause ++ * frames but not send pause frames). ++ * 2: Tx flow control is enabled (we can send pause frames ++ * frames but we do not receive pause frames). ++ * 3: Both Rx and Tx flow control (symmetric) is enabled. ++ * other: No other values should be possible at this point. ++ */ ++ DEBUGOUT1("hw->fc.type = %u\n", hw->fc.type); ++ ++ switch (hw->fc.type) { ++ case e1000_fc_none: ++ ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); ++ break; ++ case e1000_fc_rx_pause: ++ ctrl &= (~E1000_CTRL_TFCE); ++ ctrl |= E1000_CTRL_RFCE; ++ break; ++ case e1000_fc_tx_pause: ++ ctrl &= (~E1000_CTRL_RFCE); ++ ctrl |= E1000_CTRL_TFCE; ++ break; ++ case e1000_fc_full: ++ ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); ++ break; ++ default: ++ DEBUGOUT("Flow control param set incorrectly\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_config_fc_after_link_up_generic - Configures flow control after link ++ * @hw: pointer to the HW structure ++ * ++ * Checks the status of auto-negotiation after link up to ensure that the ++ * speed and duplex were not forced. If the link needed to be forced, then ++ * flow control needs to be forced also. If auto-negotiation is enabled ++ * and did not fail, then we configure flow control based on our link ++ * partner. ++ **/ ++s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; ++ u16 speed, duplex; ++ ++ DEBUGFUNC("e1000_config_fc_after_link_up_generic"); ++ ++ /* ++ * Check for the case where we have fiber media and auto-neg failed ++ * so we had to force link. In this case, we need to force the ++ * configuration of the MAC to match the "fc" parameter. ++ */ ++ if (mac->autoneg_failed) { ++ if (hw->phy.media_type == e1000_media_type_fiber || ++ hw->phy.media_type == e1000_media_type_internal_serdes) ++ ret_val = e1000_force_mac_fc_generic(hw); ++ } else { ++ if (hw->phy.media_type == e1000_media_type_copper) ++ ret_val = e1000_force_mac_fc_generic(hw); ++ } ++ ++ if (ret_val) { ++ DEBUGOUT("Error forcing flow control settings\n"); ++ goto out; ++ } ++ ++ /* ++ * Check for the case where we have copper media and auto-neg is ++ * enabled. In this case, we need to check and see if Auto-Neg ++ * has completed, and if so, how the PHY and link partner has ++ * flow control configured. ++ */ ++ if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) { ++ /* ++ * Read the MII Status Register and check to see if AutoNeg ++ * has completed. We read this twice because this reg has ++ * some "sticky" (latched) bits. ++ */ ++ ret_val = phy->ops.read_reg(hw, PHY_STATUS, &mii_status_reg); ++ if (ret_val) ++ goto out; ++ ret_val = phy->ops.read_reg(hw, PHY_STATUS, &mii_status_reg); ++ if (ret_val) ++ goto out; ++ ++ if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { ++ DEBUGOUT("Copper PHY and Auto Neg " ++ "has not completed.\n"); ++ goto out; ++ } ++ ++ /* ++ * The AutoNeg process has completed, so we now need to ++ * read both the Auto Negotiation Advertisement ++ * Register (Address 4) and the Auto_Negotiation Base ++ * Page Ability Register (Address 5) to determine how ++ * flow control was negotiated. ++ */ ++ ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, ++ &mii_nway_adv_reg); ++ if (ret_val) ++ goto out; ++ ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, ++ &mii_nway_lp_ability_reg); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Two bits in the Auto Negotiation Advertisement Register ++ * (Address 4) and two bits in the Auto Negotiation Base ++ * Page Ability Register (Address 5) determine flow control ++ * for both the PHY and the link partner. The following ++ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, ++ * 1999, describes these PAUSE resolution bits and how flow ++ * control is determined based upon these settings. ++ * NOTE: DC = Don't Care ++ * ++ * LOCAL DEVICE | LINK PARTNER ++ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution ++ *-------|---------|-------|---------|-------------------- ++ * 0 | 0 | DC | DC | e1000_fc_none ++ * 0 | 1 | 0 | DC | e1000_fc_none ++ * 0 | 1 | 1 | 0 | e1000_fc_none ++ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause ++ * 1 | 0 | 0 | DC | e1000_fc_none ++ * 1 | DC | 1 | DC | e1000_fc_full ++ * 1 | 1 | 0 | 0 | e1000_fc_none ++ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause ++ * ++ * Are both PAUSE bits set to 1? If so, this implies ++ * Symmetric Flow Control is enabled at both ends. The ++ * ASM_DIR bits are irrelevant per the spec. ++ * ++ * For Symmetric Flow Control: ++ * ++ * LOCAL DEVICE | LINK PARTNER ++ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result ++ *-------|---------|-------|---------|-------------------- ++ * 1 | DC | 1 | DC | E1000_fc_full ++ * ++ */ ++ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && ++ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { ++ /* ++ * Now we need to check if the user selected Rx ONLY ++ * of pause frames. In this case, we had to advertise ++ * FULL flow control because we could not advertise RX ++ * ONLY. Hence, we must now check to see if we need to ++ * turn OFF the TRANSMISSION of PAUSE frames. ++ */ ++ if (hw->fc.original_type == e1000_fc_full) { ++ hw->fc.type = e1000_fc_full; ++ DEBUGOUT("Flow Control = FULL.\r\n"); ++ } else { ++ hw->fc.type = e1000_fc_rx_pause; ++ DEBUGOUT("Flow Control = " ++ "RX PAUSE frames only.\r\n"); ++ } ++ } ++ /* ++ * For receiving PAUSE frames ONLY. ++ * ++ * LOCAL DEVICE | LINK PARTNER ++ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result ++ *-------|---------|-------|---------|-------------------- ++ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause ++ */ ++ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && ++ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && ++ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && ++ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { ++ hw->fc.type = e1000_fc_tx_pause; ++ DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); ++ } ++ /* ++ * For transmitting PAUSE frames ONLY. ++ * ++ * LOCAL DEVICE | LINK PARTNER ++ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result ++ *-------|---------|-------|---------|-------------------- ++ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause ++ */ ++ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && ++ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && ++ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && ++ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { ++ hw->fc.type = e1000_fc_rx_pause; ++ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); ++ } else { ++ /* ++ * Per the IEEE spec, at this point flow control ++ * should be disabled. ++ */ ++ hw->fc.type = e1000_fc_none; ++ DEBUGOUT("Flow Control = NONE.\r\n"); ++ } ++ ++ /* ++ * Now we need to do one last check... If we auto- ++ * negotiated to HALF DUPLEX, flow control should not be ++ * enabled per IEEE 802.3 spec. ++ */ ++ ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex); ++ if (ret_val) { ++ DEBUGOUT("Error getting link speed and duplex\n"); ++ goto out; ++ } ++ ++ if (duplex == HALF_DUPLEX) ++ hw->fc.type = e1000_fc_none; ++ ++ /* ++ * Now we call a subroutine to actually force the MAC ++ * controller to use the correct flow control settings. ++ */ ++ ret_val = e1000_force_mac_fc_generic(hw); ++ if (ret_val) { ++ DEBUGOUT("Error forcing flow control settings\n"); ++ goto out; ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex ++ * @hw: pointer to the HW structure ++ * @speed: stores the current speed ++ * @duplex: stores the current duplex ++ * ++ * Read the status register for the current speed/duplex and store the current ++ * speed and duplex for copper connections. ++ **/ ++s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed, ++ u16 *duplex) ++{ ++ u32 status; ++ ++ DEBUGFUNC("e1000_get_speed_and_duplex_copper_generic"); ++ ++ status = E1000_READ_REG(hw, E1000_STATUS); ++ if (status & E1000_STATUS_SPEED_1000) { ++ *speed = SPEED_1000; ++ DEBUGOUT("1000 Mbs, "); ++ } else if (status & E1000_STATUS_SPEED_100) { ++ *speed = SPEED_100; ++ DEBUGOUT("100 Mbs, "); ++ } else { ++ *speed = SPEED_10; ++ DEBUGOUT("10 Mbs, "); ++ } ++ ++ if (status & E1000_STATUS_FD) { ++ *duplex = FULL_DUPLEX; ++ DEBUGOUT("Full Duplex\n"); ++ } else { ++ *duplex = HALF_DUPLEX; ++ DEBUGOUT("Half Duplex\n"); ++ } ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex ++ * @hw: pointer to the HW structure ++ * @speed: stores the current speed ++ * @duplex: stores the current duplex ++ * ++ * Sets the speed and duplex to gigabit full duplex (the only possible option) ++ * for fiber/serdes links. ++ **/ ++s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw, ++ u16 *speed, u16 *duplex) ++{ ++ DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic"); ++ ++ *speed = SPEED_1000; ++ *duplex = FULL_DUPLEX; ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_get_hw_semaphore_generic - Acquire hardware semaphore ++ * @hw: pointer to the HW structure ++ * ++ * Acquire the HW semaphore to access the PHY or NVM ++ **/ ++s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw) ++{ ++ u32 swsm; ++ s32 ret_val = E1000_SUCCESS; ++ s32 timeout = hw->nvm.word_size + 1; ++ s32 i = 0; ++ ++ DEBUGFUNC("e1000_get_hw_semaphore_generic"); ++ ++ /* Get the SW semaphore */ ++ while (i < timeout) { ++ swsm = E1000_READ_REG(hw, E1000_SWSM); ++ if (!(swsm & E1000_SWSM_SMBI)) ++ break; ++ ++ usec_delay(50); ++ i++; ++ } ++ ++ if (i == timeout) { ++ DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ /* Get the FW semaphore. */ ++ for (i = 0; i < timeout; i++) { ++ swsm = E1000_READ_REG(hw, E1000_SWSM); ++ E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); ++ ++ /* Semaphore acquired if bit latched */ ++ if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI) ++ break; ++ ++ usec_delay(50); ++ } ++ ++ if (i == timeout) { ++ /* Release semaphores */ ++ e1000_put_hw_semaphore_generic(hw); ++ DEBUGOUT("Driver can't access the NVM\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_put_hw_semaphore_generic - Release hardware semaphore ++ * @hw: pointer to the HW structure ++ * ++ * Release hardware semaphore used to access the PHY or NVM ++ **/ ++void e1000_put_hw_semaphore_generic(struct e1000_hw *hw) ++{ ++ u32 swsm; ++ ++ DEBUGFUNC("e1000_put_hw_semaphore_generic"); ++ ++ swsm = E1000_READ_REG(hw, E1000_SWSM); ++ ++ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); ++ ++ E1000_WRITE_REG(hw, E1000_SWSM, swsm); ++} ++ ++/** ++ * e1000_get_auto_rd_done_generic - Check for auto read completion ++ * @hw: pointer to the HW structure ++ * ++ * Check EEPROM for Auto Read done bit. ++ **/ ++s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw) ++{ ++ s32 i = 0; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_get_auto_rd_done_generic"); ++ ++ while (i < AUTO_READ_DONE_TIMEOUT) { ++ if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD) ++ break; ++ msec_delay(1); ++ i++; ++ } ++ ++ if (i == AUTO_READ_DONE_TIMEOUT) { ++ DEBUGOUT("Auto read by HW from NVM has not completed.\n"); ++ ret_val = -E1000_ERR_RESET; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_valid_led_default_generic - Verify a valid default LED config ++ * @hw: pointer to the HW structure ++ * @data: pointer to the NVM (EEPROM) ++ * ++ * Read the EEPROM for the current default LED configuration. If the ++ * LED configuration is not valid, set to a valid LED configuration. ++ **/ ++s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data) ++{ ++ s32 ret_val; ++ ++ DEBUGFUNC("e1000_valid_led_default_generic"); ++ ++ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error\n"); ++ goto out; ++ } ++ ++ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) ++ *data = ID_LED_DEFAULT; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_id_led_init_generic - ++ * @hw: pointer to the HW structure ++ * ++ **/ ++s32 e1000_id_led_init_generic(struct e1000_hw * hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ s32 ret_val; ++ const u32 ledctl_mask = 0x000000FF; ++ const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON; ++ const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF; ++ u16 data, i, temp; ++ const u16 led_mask = 0x0F; ++ ++ DEBUGFUNC("e1000_id_led_init_generic"); ++ ++ ret_val = hw->nvm.ops.valid_led_default(hw, &data); ++ if (ret_val) ++ goto out; ++ ++ mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL); ++ mac->ledctl_mode1 = mac->ledctl_default; ++ mac->ledctl_mode2 = mac->ledctl_default; ++ ++ for (i = 0; i < 4; i++) { ++ temp = (data >> (i << 2)) & led_mask; ++ switch (temp) { ++ case ID_LED_ON1_DEF2: ++ case ID_LED_ON1_ON2: ++ case ID_LED_ON1_OFF2: ++ mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); ++ mac->ledctl_mode1 |= ledctl_on << (i << 3); ++ break; ++ case ID_LED_OFF1_DEF2: ++ case ID_LED_OFF1_ON2: ++ case ID_LED_OFF1_OFF2: ++ mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); ++ mac->ledctl_mode1 |= ledctl_off << (i << 3); ++ break; ++ default: ++ /* Do nothing */ ++ break; ++ } ++ switch (temp) { ++ case ID_LED_DEF1_ON2: ++ case ID_LED_ON1_ON2: ++ case ID_LED_OFF1_ON2: ++ mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); ++ mac->ledctl_mode2 |= ledctl_on << (i << 3); ++ break; ++ case ID_LED_DEF1_OFF2: ++ case ID_LED_ON1_OFF2: ++ case ID_LED_OFF1_OFF2: ++ mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); ++ mac->ledctl_mode2 |= ledctl_off << (i << 3); ++ break; ++ default: ++ /* Do nothing */ ++ break; ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_setup_led_generic - Configures SW controllable LED ++ * @hw: pointer to the HW structure ++ * ++ * This prepares the SW controllable LED for use and saves the current state ++ * of the LED so it can be later restored. ++ **/ ++s32 e1000_setup_led_generic(struct e1000_hw *hw) ++{ ++ u32 ledctl; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_setup_led_generic"); ++ ++ if (hw->mac.ops.setup_led != e1000_setup_led_generic) { ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ if (hw->phy.media_type == e1000_media_type_fiber) { ++ ledctl = E1000_READ_REG(hw, E1000_LEDCTL); ++ hw->mac.ledctl_default = ledctl; ++ /* Turn off LED0 */ ++ ledctl &= ~(E1000_LEDCTL_LED0_IVRT | ++ E1000_LEDCTL_LED0_BLINK | ++ E1000_LEDCTL_LED0_MODE_MASK); ++ ledctl |= (E1000_LEDCTL_MODE_LED_OFF << ++ E1000_LEDCTL_LED0_MODE_SHIFT); ++ E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl); ++ } else if (hw->phy.media_type == e1000_media_type_copper) { ++ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_cleanup_led_generic - Set LED config to default operation ++ * @hw: pointer to the HW structure ++ * ++ * Remove the current LED configuration and set the LED configuration ++ * to the default value, saved from the EEPROM. ++ **/ ++s32 e1000_cleanup_led_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_cleanup_led_generic"); ++ ++ if (hw->mac.ops.cleanup_led != e1000_cleanup_led_generic) { ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_blink_led_generic - Blink LED ++ * @hw: pointer to the HW structure ++ * ++ * Blink the LEDs which are set to be on. ++ **/ ++s32 e1000_blink_led_generic(struct e1000_hw *hw) ++{ ++ u32 ledctl_blink = 0; ++ u32 i; ++ ++ DEBUGFUNC("e1000_blink_led_generic"); ++ ++ if (hw->phy.media_type == e1000_media_type_fiber) { ++ /* always blink LED0 for PCI-E fiber */ ++ ledctl_blink = E1000_LEDCTL_LED0_BLINK | ++ (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); ++ } else { ++ /* ++ * set the blink bit for each LED that's "on" (0x0E) ++ * in ledctl_mode2 ++ */ ++ ledctl_blink = hw->mac.ledctl_mode2; ++ for (i = 0; i < 4; i++) ++ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == ++ E1000_LEDCTL_MODE_LED_ON) ++ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << ++ (i * 8)); ++ } ++ ++ E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink); ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_led_on_generic - Turn LED on ++ * @hw: pointer to the HW structure ++ * ++ * Turn LED on. ++ **/ ++s32 e1000_led_on_generic(struct e1000_hw *hw) ++{ ++ u32 ctrl; ++ ++ DEBUGFUNC("e1000_led_on_generic"); ++ ++ switch (hw->phy.media_type) { ++ case e1000_media_type_fiber: ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ctrl &= ~E1000_CTRL_SWDPIN0; ++ ctrl |= E1000_CTRL_SWDPIO0; ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ break; ++ case e1000_media_type_copper: ++ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); ++ break; ++ default: ++ break; ++ } ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_led_off_generic - Turn LED off ++ * @hw: pointer to the HW structure ++ * ++ * Turn LED off. ++ **/ ++s32 e1000_led_off_generic(struct e1000_hw *hw) ++{ ++ u32 ctrl; ++ ++ DEBUGFUNC("e1000_led_off_generic"); ++ ++ switch (hw->phy.media_type) { ++ case e1000_media_type_fiber: ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ctrl |= E1000_CTRL_SWDPIN0; ++ ctrl |= E1000_CTRL_SWDPIO0; ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ break; ++ case e1000_media_type_copper: ++ E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); ++ break; ++ default: ++ break; ++ } ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_set_pcie_no_snoop_generic - Set PCI-express capabilities ++ * @hw: pointer to the HW structure ++ * @no_snoop: bitmap of snoop events ++ * ++ * Set the PCI-express register to snoop for events enabled in 'no_snoop'. ++ **/ ++void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop) ++{ ++ u32 gcr; ++ ++ DEBUGFUNC("e1000_set_pcie_no_snoop_generic"); ++ ++ if (hw->bus.type != e1000_bus_type_pci_express) ++ goto out; ++ ++ if (no_snoop) { ++ gcr = E1000_READ_REG(hw, E1000_GCR); ++ gcr &= ~(PCIE_NO_SNOOP_ALL); ++ gcr |= no_snoop; ++ E1000_WRITE_REG(hw, E1000_GCR, gcr); ++ } ++out: ++ return; ++} ++ ++/** ++ * e1000_disable_pcie_master_generic - Disables PCI-express master access ++ * @hw: pointer to the HW structure ++ * ++ * Returns 0 (E1000_SUCCESS) if successful, else returns -10 ++ * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused ++ * the master requests to be disabled. ++ * ++ * Disables PCI-Express master access and verifies there are no pending ++ * requests. ++ **/ ++s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw) ++{ ++ u32 ctrl; ++ s32 timeout = MASTER_DISABLE_TIMEOUT; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_disable_pcie_master_generic"); ++ ++ if (hw->bus.type != e1000_bus_type_pci_express) ++ goto out; ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ ++ while (timeout) { ++ if (!(E1000_READ_REG(hw, E1000_STATUS) & ++ E1000_STATUS_GIO_MASTER_ENABLE)) ++ break; ++ usec_delay(100); ++ timeout--; ++ } ++ ++ if (!timeout) { ++ DEBUGOUT("Master requests are pending.\n"); ++ ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_reset_adaptive_generic - Reset Adaptive Interframe Spacing ++ * @hw: pointer to the HW structure ++ * ++ * Reset the Adaptive Interframe Spacing throttle to default values. ++ **/ ++void e1000_reset_adaptive_generic(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ ++ DEBUGFUNC("e1000_reset_adaptive_generic"); ++ ++ if (!mac->adaptive_ifs) { ++ DEBUGOUT("Not in Adaptive IFS mode!\n"); ++ goto out; ++ } ++ ++ if (!mac->ifs_params_forced) { ++ mac->current_ifs_val = 0; ++ mac->ifs_min_val = IFS_MIN; ++ mac->ifs_max_val = IFS_MAX; ++ mac->ifs_step_size = IFS_STEP; ++ mac->ifs_ratio = IFS_RATIO; ++ } ++ ++ mac->in_ifs_mode = false; ++ E1000_WRITE_REG(hw, E1000_AIT, 0); ++out: ++ return; ++} ++ ++/** ++ * e1000_update_adaptive_generic - Update Adaptive Interframe Spacing ++ * @hw: pointer to the HW structure ++ * ++ * Update the Adaptive Interframe Spacing Throttle value based on the ++ * time between transmitted packets and time between collisions. ++ **/ ++void e1000_update_adaptive_generic(struct e1000_hw *hw) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ ++ DEBUGFUNC("e1000_update_adaptive_generic"); ++ ++ if (!mac->adaptive_ifs) { ++ DEBUGOUT("Not in Adaptive IFS mode!\n"); ++ goto out; ++ } ++ ++ if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) { ++ if (mac->tx_packet_delta > MIN_NUM_XMITS) { ++ mac->in_ifs_mode = true; ++ if (mac->current_ifs_val < mac->ifs_max_val) { ++ if (!mac->current_ifs_val) ++ mac->current_ifs_val = mac->ifs_min_val; ++ else ++ mac->current_ifs_val += ++ mac->ifs_step_size; ++ E1000_WRITE_REG(hw, E1000_AIT, mac->current_ifs_val); ++ } ++ } ++ } else { ++ if (mac->in_ifs_mode && ++ (mac->tx_packet_delta <= MIN_NUM_XMITS)) { ++ mac->current_ifs_val = 0; ++ mac->in_ifs_mode = false; ++ E1000_WRITE_REG(hw, E1000_AIT, 0); ++ } ++ } ++out: ++ return; ++} ++ ++/** ++ * e1000_validate_mdi_setting_generic - Verify MDI/MDIx settings ++ * @hw: pointer to the HW structure ++ * ++ * Verify that when not using auto-negotiation that MDI/MDIx is correctly ++ * set, which is forced to MDI mode only. ++ **/ ++s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_validate_mdi_setting_generic"); ++ ++ if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) { ++ DEBUGOUT("Invalid MDI setting detected\n"); ++ hw->phy.mdix = 1; ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_8bit_ctrl_reg_generic - Write a 8bit CTRL register ++ * @hw: pointer to the HW structure ++ * @reg: 32bit register offset such as E1000_SCTL ++ * @offset: register offset to write to ++ * @data: data to write at register offset ++ * ++ * Writes an address/data control type register. There are several of these ++ * and they all have the format address << 8 | data and bit 31 is polled for ++ * completion. ++ **/ ++s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg, ++ u32 offset, u8 data) ++{ ++ u32 i, regvalue = 0; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_write_8bit_ctrl_reg_generic"); ++ ++ /* Set up the address and data */ ++ regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT); ++ E1000_WRITE_REG(hw, reg, regvalue); ++ ++ /* Poll the ready bit to see if the MDI read completed */ ++ for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) { ++ usec_delay(5); ++ regvalue = E1000_READ_REG(hw, reg); ++ if (regvalue & E1000_GEN_CTL_READY) ++ break; ++ } ++ if (!(regvalue & E1000_GEN_CTL_READY)) { ++ DEBUGOUT1("Reg %08x did not indicate ready\n", reg); ++ ret_val = -E1000_ERR_PHY; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_mac.h linux-2.6.22-10/drivers/net/e1000e/e1000_mac.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_mac.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_mac.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,86 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _E1000_MAC_H_ ++#define _E1000_MAC_H_ ++ ++/* ++ * Functions that should not be called directly from drivers but can be used ++ * by other files in this 'shared code' ++ */ ++void e1000_init_mac_ops_generic(struct e1000_hw *hw); ++s32 e1000_blink_led_generic(struct e1000_hw *hw); ++s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw); ++s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw); ++s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw); ++s32 e1000_cleanup_led_generic(struct e1000_hw *hw); ++s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw); ++s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw); ++s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw); ++s32 e1000_force_mac_fc_generic(struct e1000_hw *hw); ++s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw); ++s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw); ++s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw); ++s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed, ++ u16 *duplex); ++s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw, ++ u16 *speed, u16 *duplex); ++s32 e1000_id_led_init_generic(struct e1000_hw *hw); ++s32 e1000_led_on_generic(struct e1000_hw *hw); ++s32 e1000_led_off_generic(struct e1000_hw *hw); ++void e1000_update_mc_addr_list_generic(struct e1000_hw *hw, ++ u8 *mc_addr_list, u32 mc_addr_count, ++ u32 rar_used_count, u32 rar_count); ++s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw); ++s32 e1000_set_default_fc_generic(struct e1000_hw *hw); ++s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw); ++s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw); ++s32 e1000_setup_led_generic(struct e1000_hw *hw); ++s32 e1000_setup_link_generic(struct e1000_hw *hw); ++s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw); ++s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg, ++ u32 offset, u8 data); ++ ++u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr); ++ ++void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw); ++void e1000_clear_vfta_generic(struct e1000_hw *hw); ++void e1000_config_collision_dist_generic(struct e1000_hw *hw); ++void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count); ++void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value); ++void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw); ++void e1000_put_hw_semaphore_generic(struct e1000_hw *hw); ++void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index); ++s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw); ++void e1000_remove_device_generic(struct e1000_hw *hw); ++void e1000_reset_adaptive_generic(struct e1000_hw *hw); ++void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop); ++void e1000_update_adaptive_generic(struct e1000_hw *hw); ++void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); ++ ++#endif +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_manage.c linux-2.6.22-10/drivers/net/e1000e/e1000_manage.c +--- linux-2.6.22-0/drivers/net/e1000e/e1000_manage.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_manage.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,383 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include "e1000_hw.h" ++ ++static u8 e1000_calculate_checksum(u8 *buffer, u32 length); ++ ++/** ++ * e1000_calculate_checksum - Calculate checksum for buffer ++ * @buffer: pointer to EEPROM ++ * @length: size of EEPROM to calculate a checksum for ++ * ++ * Calculates the checksum for some buffer on a specified length. The ++ * checksum calculated is returned. ++ **/ ++static u8 e1000_calculate_checksum(u8 *buffer, u32 length) ++{ ++ u32 i; ++ u8 sum = 0; ++ ++ DEBUGFUNC("e1000_calculate_checksum"); ++ ++ if (!buffer) ++ return 0; ++ ++ for (i = 0; i < length; i++) ++ sum += buffer[i]; ++ ++ return (u8) (0 - sum); ++} ++ ++/** ++ * e1000_mng_enable_host_if_generic - Checks host interface is enabled ++ * @hw: pointer to the HW structure ++ * ++ * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND ++ * ++ * This function checks whether the HOST IF is enabled for command operation ++ * and also checks whether the previous command is completed. It busy waits ++ * in case of previous command is not completed. ++ **/ ++s32 e1000_mng_enable_host_if_generic(struct e1000_hw * hw) ++{ ++ u32 hicr; ++ s32 ret_val = E1000_SUCCESS; ++ u8 i; ++ ++ DEBUGFUNC("e1000_mng_enable_host_if_generic"); ++ ++ /* Check that the host interface is enabled. */ ++ hicr = E1000_READ_REG(hw, E1000_HICR); ++ if ((hicr & E1000_HICR_EN) == 0) { ++ DEBUGOUT("E1000_HOST_EN bit disabled.\n"); ++ ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; ++ goto out; ++ } ++ /* check the previous command is completed */ ++ for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { ++ hicr = E1000_READ_REG(hw, E1000_HICR); ++ if (!(hicr & E1000_HICR_C)) ++ break; ++ msec_delay_irq(1); ++ } ++ ++ if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { ++ DEBUGOUT("Previous command timeout failed .\n"); ++ ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_check_mng_mode_generic - Generic check management mode ++ * @hw: pointer to the HW structure ++ * ++ * Reads the firmware semaphore register and returns true (>0) if ++ * manageability is enabled, else false (0). ++ **/ ++bool e1000_check_mng_mode_generic(struct e1000_hw *hw) ++{ ++ u32 fwsm; ++ ++ DEBUGFUNC("e1000_check_mng_mode_generic"); ++ ++ fwsm = E1000_READ_REG(hw, E1000_FWSM); ++ ++ return ((fwsm & E1000_FWSM_MODE_MASK) == ++ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); ++} ++ ++/** ++ * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX ++ * @hw: pointer to the HW structure ++ * ++ * Enables packet filtering on transmit packets if manageability is enabled ++ * and host interface is enabled. ++ **/ ++bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) ++{ ++ struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; ++ u32 *buffer = (u32 *)&hw->mng_cookie; ++ u32 offset; ++ s32 ret_val, hdr_csum, csum; ++ u8 i, len; ++ bool tx_filter = true; ++ ++ DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic"); ++ ++ /* No manageability, no filtering */ ++ if (!hw->mac.ops.check_mng_mode(hw)) { ++ tx_filter = false; ++ goto out; ++ } ++ ++ /* ++ * If we can't read from the host interface for whatever ++ * reason, disable filtering. ++ */ ++ ret_val = hw->mac.ops.mng_enable_host_if(hw); ++ if (ret_val != E1000_SUCCESS) { ++ tx_filter = false; ++ goto out; ++ } ++ ++ /* Read in the header. Length and offset are in dwords. */ ++ len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; ++ offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; ++ for (i = 0; i < len; i++) { ++ *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, ++ E1000_HOST_IF, ++ offset + i); ++ } ++ hdr_csum = hdr->checksum; ++ hdr->checksum = 0; ++ csum = e1000_calculate_checksum((u8 *)hdr, ++ E1000_MNG_DHCP_COOKIE_LENGTH); ++ /* ++ * If either the checksums or signature don't match, then ++ * the cookie area isn't considered valid, in which case we ++ * take the safe route of assuming Tx filtering is enabled. ++ */ ++ if (hdr_csum != csum) ++ goto out; ++ if (hdr->signature != E1000_IAMT_SIGNATURE) ++ goto out; ++ ++ /* Cookie area is valid, make the final check for filtering. */ ++ if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) ++ tx_filter = false; ++ ++out: ++ hw->mac.tx_pkt_filtering = tx_filter; ++ return tx_filter; ++} ++ ++/** ++ * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface ++ * @hw: pointer to the HW structure ++ * @buffer: pointer to the host interface ++ * @length: size of the buffer ++ * ++ * Writes the DHCP information to the host interface. ++ **/ ++s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw * hw, u8 *buffer, ++ u16 length) ++{ ++ struct e1000_host_mng_command_header hdr; ++ s32 ret_val; ++ u32 hicr; ++ ++ DEBUGFUNC("e1000_mng_write_dhcp_info_generic"); ++ ++ hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; ++ hdr.command_length = length; ++ hdr.reserved1 = 0; ++ hdr.reserved2 = 0; ++ hdr.checksum = 0; ++ ++ /* Enable the host interface */ ++ ret_val = hw->mac.ops.mng_enable_host_if(hw); ++ if (ret_val) ++ goto out; ++ ++ /* Populate the host interface with the contents of "buffer". */ ++ ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length, ++ sizeof(hdr), &(hdr.checksum)); ++ if (ret_val) ++ goto out; ++ ++ /* Write the manageability command header */ ++ ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr); ++ if (ret_val) ++ goto out; ++ ++ /* Tell the ARC a new command is pending. */ ++ hicr = E1000_READ_REG(hw, E1000_HICR); ++ E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_mng_write_cmd_header_generic - Writes manageability command header ++ * @hw: pointer to the HW structure ++ * @hdr: pointer to the host interface command header ++ * ++ * Writes the command header after does the checksum calculation. ++ **/ ++s32 e1000_mng_write_cmd_header_generic(struct e1000_hw * hw, ++ struct e1000_host_mng_command_header * hdr) ++{ ++ u16 i, length = sizeof(struct e1000_host_mng_command_header); ++ ++ DEBUGFUNC("e1000_mng_write_cmd_header_generic"); ++ ++ /* Write the whole command header structure with new checksum. */ ++ ++ hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length); ++ ++ length >>= 2; ++ /* Write the relevant command block into the ram area. */ ++ for (i = 0; i < length; i++) { ++ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i, ++ *((u32 *) hdr + i)); ++ E1000_WRITE_FLUSH(hw); ++ } ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_mng_host_if_write_generic - Write to the manageability host interface ++ * @hw: pointer to the HW structure ++ * @buffer: pointer to the host interface buffer ++ * @length: size of the buffer ++ * @offset: location in the buffer to write to ++ * @sum: sum of the data (not checksum) ++ * ++ * This function writes the buffer content at the offset given on the host if. ++ * It also does alignment considerations to do the writes in most efficient ++ * way. Also fills up the sum of the buffer in *buffer parameter. ++ **/ ++s32 e1000_mng_host_if_write_generic(struct e1000_hw * hw, u8 *buffer, ++ u16 length, u16 offset, u8 *sum) ++{ ++ u8 *tmp; ++ u8 *bufptr = buffer; ++ u32 data = 0; ++ s32 ret_val = E1000_SUCCESS; ++ u16 remaining, i, j, prev_bytes; ++ ++ DEBUGFUNC("e1000_mng_host_if_write_generic"); ++ ++ /* sum = only sum of the data and it is not checksum */ ++ ++ if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) { ++ ret_val = -E1000_ERR_PARAM; ++ goto out; ++ } ++ ++ tmp = (u8 *)&data; ++ prev_bytes = offset & 0x3; ++ offset >>= 2; ++ ++ if (prev_bytes) { ++ data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset); ++ for (j = prev_bytes; j < sizeof(u32); j++) { ++ *(tmp + j) = *bufptr++; ++ *sum += *(tmp + j); ++ } ++ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data); ++ length -= j - prev_bytes; ++ offset++; ++ } ++ ++ remaining = length & 0x3; ++ length -= remaining; ++ ++ /* Calculate length in DWORDs */ ++ length >>= 2; ++ ++ /* ++ * The device driver writes the relevant command block into the ++ * ram area. ++ */ ++ for (i = 0; i < length; i++) { ++ for (j = 0; j < sizeof(u32); j++) { ++ *(tmp + j) = *bufptr++; ++ *sum += *(tmp + j); ++ } ++ ++ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data); ++ } ++ if (remaining) { ++ for (j = 0; j < sizeof(u32); j++) { ++ if (j < remaining) ++ *(tmp + j) = *bufptr++; ++ else ++ *(tmp + j) = 0; ++ ++ *sum += *(tmp + j); ++ } ++ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_enable_mng_pass_thru - Enable processing of ARP's ++ * @hw: pointer to the HW structure ++ * ++ * Verifies the hardware needs to allow ARPs to be processed by the host. ++ **/ ++bool e1000_enable_mng_pass_thru(struct e1000_hw *hw) ++{ ++ u32 manc; ++ u32 fwsm, factps; ++ bool ret_val = false; ++ ++ DEBUGFUNC("e1000_enable_mng_pass_thru"); ++ ++ if (!hw->mac.asf_firmware_present) ++ goto out; ++ ++ manc = E1000_READ_REG(hw, E1000_MANC); ++ ++ if (!(manc & E1000_MANC_RCV_TCO_EN) || ++ !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) ++ goto out; ++ ++ if (hw->mac.arc_subsystem_valid) { ++ fwsm = E1000_READ_REG(hw, E1000_FWSM); ++ factps = E1000_READ_REG(hw, E1000_FACTPS); ++ ++ if (!(factps & E1000_FACTPS_MNGCG) && ++ ((fwsm & E1000_FWSM_MODE_MASK) == ++ (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { ++ ret_val = true; ++ goto out; ++ } ++ } else { ++ if ((manc & E1000_MANC_SMBUS_EN) && ++ !(manc & E1000_MANC_ASF_EN)) { ++ ret_val = true; ++ goto out; ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_manage.h linux-2.6.22-10/drivers/net/e1000e/e1000_manage.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_manage.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_manage.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,82 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _E1000_MANAGE_H_ ++#define _E1000_MANAGE_H_ ++ ++bool e1000_check_mng_mode_generic(struct e1000_hw *hw); ++bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw); ++s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw); ++s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, ++ u16 length, u16 offset, u8 *sum); ++s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw, ++ struct e1000_host_mng_command_header *hdr); ++s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, ++ u8 *buffer, u16 length); ++bool e1000_enable_mng_pass_thru(struct e1000_hw *hw); ++ ++typedef enum { ++ e1000_mng_mode_none = 0, ++ e1000_mng_mode_asf, ++ e1000_mng_mode_pt, ++ e1000_mng_mode_ipmi, ++ e1000_mng_mode_host_if_only ++} e1000_mng_mode; ++ ++#define E1000_FACTPS_MNGCG 0x20000000 ++ ++#define E1000_FWSM_MODE_MASK 0xE ++#define E1000_FWSM_MODE_SHIFT 1 ++ ++#define E1000_MNG_IAMT_MODE 0x3 ++#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 ++#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 ++#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 ++#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64 ++#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1 ++#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2 ++ ++#define E1000_VFTA_ENTRY_SHIFT 5 ++#define E1000_VFTA_ENTRY_MASK 0x7F ++#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F ++ ++#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Num of bytes in range */ ++#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Num of dwords in range */ ++#define E1000_HI_COMMAND_TIMEOUT 500 /* Process HI command limit */ ++ ++#define E1000_HICR_EN 0x01 /* Enable bit - RO */ ++/* Driver sets this bit when done to put command in RAM */ ++#define E1000_HICR_C 0x02 ++#define E1000_HICR_SV 0x04 /* Status Validity */ ++#define E1000_HICR_FW_RESET_ENABLE 0x40 ++#define E1000_HICR_FW_RESET 0x80 ++ ++/* Intel(R) Active Management Technology signature */ ++#define E1000_IAMT_SIGNATURE 0x544D4149 ++ ++#endif +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_nvm.c linux-2.6.22-10/drivers/net/e1000e/e1000_nvm.c +--- linux-2.6.22-0/drivers/net/e1000e/e1000_nvm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_nvm.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,875 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include "e1000_hw.h" ++ ++/** ++ * e1000_init_nvm_ops_generic - Initialize NVM function pointers ++ * @hw: pointer to the HW structure ++ * ++ * Setups up the function pointers to no-op functions ++ **/ ++void e1000_init_nvm_ops_generic(struct e1000_hw *hw) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ DEBUGFUNC("e1000_init_nvm_ops_generic"); ++ ++ /* Initialize function pointers */ ++ nvm->ops.reload = e1000_reload_nvm_generic; ++} ++ ++/** ++ * e1000_raise_eec_clk - Raise EEPROM clock ++ * @hw: pointer to the HW structure ++ * @eecd: pointer to the EEPROM ++ * ++ * Enable/Raise the EEPROM clock bit. ++ **/ ++static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd) ++{ ++ *eecd = *eecd | E1000_EECD_SK; ++ E1000_WRITE_REG(hw, E1000_EECD, *eecd); ++ E1000_WRITE_FLUSH(hw); ++ usec_delay(hw->nvm.delay_usec); ++} ++ ++/** ++ * e1000_lower_eec_clk - Lower EEPROM clock ++ * @hw: pointer to the HW structure ++ * @eecd: pointer to the EEPROM ++ * ++ * Clear/Lower the EEPROM clock bit. ++ **/ ++static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd) ++{ ++ *eecd = *eecd & ~E1000_EECD_SK; ++ E1000_WRITE_REG(hw, E1000_EECD, *eecd); ++ E1000_WRITE_FLUSH(hw); ++ usec_delay(hw->nvm.delay_usec); ++} ++ ++/** ++ * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM ++ * @hw: pointer to the HW structure ++ * @data: data to send to the EEPROM ++ * @count: number of bits to shift out ++ * ++ * We need to shift 'count' bits out to the EEPROM. So, the value in the ++ * "data" parameter will be shifted out to the EEPROM one bit at a time. ++ * In order to do this, "data" must be broken down into bits. ++ **/ ++static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ u32 eecd = E1000_READ_REG(hw, E1000_EECD); ++ u32 mask; ++ ++ DEBUGFUNC("e1000_shift_out_eec_bits"); ++ ++ mask = 0x01 << (count - 1); ++ if (nvm->type == e1000_nvm_eeprom_microwire) ++ eecd &= ~E1000_EECD_DO; ++ else if (nvm->type == e1000_nvm_eeprom_spi) ++ eecd |= E1000_EECD_DO; ++ ++ do { ++ eecd &= ~E1000_EECD_DI; ++ ++ if (data & mask) ++ eecd |= E1000_EECD_DI; ++ ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ E1000_WRITE_FLUSH(hw); ++ ++ usec_delay(nvm->delay_usec); ++ ++ e1000_raise_eec_clk(hw, &eecd); ++ e1000_lower_eec_clk(hw, &eecd); ++ ++ mask >>= 1; ++ } while (mask); ++ ++ eecd &= ~E1000_EECD_DI; ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++} ++ ++/** ++ * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM ++ * @hw: pointer to the HW structure ++ * @count: number of bits to shift in ++ * ++ * In order to read a register from the EEPROM, we need to shift 'count' bits ++ * in from the EEPROM. Bits are "shifted in" by raising the clock input to ++ * the EEPROM (setting the SK bit), and then reading the value of the data out ++ * "DO" bit. During this "shifting in" process the data in "DI" bit should ++ * always be clear. ++ **/ ++static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count) ++{ ++ u32 eecd; ++ u32 i; ++ u16 data; ++ ++ DEBUGFUNC("e1000_shift_in_eec_bits"); ++ ++ eecd = E1000_READ_REG(hw, E1000_EECD); ++ ++ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); ++ data = 0; ++ ++ for (i = 0; i < count; i++) { ++ data <<= 1; ++ e1000_raise_eec_clk(hw, &eecd); ++ ++ eecd = E1000_READ_REG(hw, E1000_EECD); ++ ++ eecd &= ~E1000_EECD_DI; ++ if (eecd & E1000_EECD_DO) ++ data |= 1; ++ ++ e1000_lower_eec_clk(hw, &eecd); ++ } ++ ++ return data; ++} ++ ++/** ++ * e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion ++ * @hw: pointer to the HW structure ++ * @ee_reg: EEPROM flag for polling ++ * ++ * Polls the EEPROM status bit for either read or write completion based ++ * upon the value of 'ee_reg'. ++ **/ ++s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg) ++{ ++ u32 attempts = 100000; ++ u32 i, reg = 0; ++ s32 ret_val = -E1000_ERR_NVM; ++ ++ DEBUGFUNC("e1000_poll_eerd_eewr_done"); ++ ++ for (i = 0; i < attempts; i++) { ++ if (ee_reg == E1000_NVM_POLL_READ) ++ reg = E1000_READ_REG(hw, E1000_EERD); ++ else ++ reg = E1000_READ_REG(hw, E1000_EEWR); ++ ++ if (reg & E1000_NVM_RW_REG_DONE) { ++ ret_val = E1000_SUCCESS; ++ break; ++ } ++ ++ usec_delay(5); ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_acquire_nvm_generic - Generic request for access to EEPROM ++ * @hw: pointer to the HW structure ++ * ++ * Set the EEPROM access request bit and wait for EEPROM access grant bit. ++ * Return successful if access grant bit set, else clear the request for ++ * EEPROM access and return -E1000_ERR_NVM (-1). ++ **/ ++s32 e1000_acquire_nvm_generic(struct e1000_hw *hw) ++{ ++ u32 eecd = E1000_READ_REG(hw, E1000_EECD); ++ s32 timeout = E1000_NVM_GRANT_ATTEMPTS; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_acquire_nvm_generic"); ++ ++ E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ); ++ eecd = E1000_READ_REG(hw, E1000_EECD); ++ ++ while (timeout) { ++ if (eecd & E1000_EECD_GNT) ++ break; ++ usec_delay(5); ++ eecd = E1000_READ_REG(hw, E1000_EECD); ++ timeout--; ++ } ++ ++ if (!timeout) { ++ eecd &= ~E1000_EECD_REQ; ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ DEBUGOUT("Could not acquire NVM grant\n"); ++ ret_val = -E1000_ERR_NVM; ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_standby_nvm - Return EEPROM to standby state ++ * @hw: pointer to the HW structure ++ * ++ * Return the EEPROM to a standby state. ++ **/ ++static void e1000_standby_nvm(struct e1000_hw *hw) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ u32 eecd = E1000_READ_REG(hw, E1000_EECD); ++ ++ DEBUGFUNC("e1000_standby_nvm"); ++ ++ if (nvm->type == e1000_nvm_eeprom_microwire) { ++ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ E1000_WRITE_FLUSH(hw); ++ usec_delay(nvm->delay_usec); ++ ++ e1000_raise_eec_clk(hw, &eecd); ++ ++ /* Select EEPROM */ ++ eecd |= E1000_EECD_CS; ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ E1000_WRITE_FLUSH(hw); ++ usec_delay(nvm->delay_usec); ++ ++ e1000_lower_eec_clk(hw, &eecd); ++ } else if (nvm->type == e1000_nvm_eeprom_spi) { ++ /* Toggle CS to flush commands */ ++ eecd |= E1000_EECD_CS; ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ E1000_WRITE_FLUSH(hw); ++ usec_delay(nvm->delay_usec); ++ eecd &= ~E1000_EECD_CS; ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ E1000_WRITE_FLUSH(hw); ++ usec_delay(nvm->delay_usec); ++ } ++} ++ ++/** ++ * e1000_stop_nvm - Terminate EEPROM command ++ * @hw: pointer to the HW structure ++ * ++ * Terminates the current command by inverting the EEPROM's chip select pin. ++ **/ ++void e1000_stop_nvm(struct e1000_hw *hw) ++{ ++ u32 eecd; ++ ++ DEBUGFUNC("e1000_stop_nvm"); ++ ++ eecd = E1000_READ_REG(hw, E1000_EECD); ++ if (hw->nvm.type == e1000_nvm_eeprom_spi) { ++ /* Pull CS high */ ++ eecd |= E1000_EECD_CS; ++ e1000_lower_eec_clk(hw, &eecd); ++ } else if (hw->nvm.type == e1000_nvm_eeprom_microwire) { ++ /* CS on Microwire is active-high */ ++ eecd &= ~(E1000_EECD_CS | E1000_EECD_DI); ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ e1000_raise_eec_clk(hw, &eecd); ++ e1000_lower_eec_clk(hw, &eecd); ++ } ++} ++ ++/** ++ * e1000_release_nvm_generic - Release exclusive access to EEPROM ++ * @hw: pointer to the HW structure ++ * ++ * Stop any current commands to the EEPROM and clear the EEPROM request bit. ++ **/ ++void e1000_release_nvm_generic(struct e1000_hw *hw) ++{ ++ u32 eecd; ++ ++ DEBUGFUNC("e1000_release_nvm_generic"); ++ ++ e1000_stop_nvm(hw); ++ ++ eecd = E1000_READ_REG(hw, E1000_EECD); ++ eecd &= ~E1000_EECD_REQ; ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++} ++ ++/** ++ * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write ++ * @hw: pointer to the HW structure ++ * ++ * Setups the EEPROM for reading and writing. ++ **/ ++static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ u32 eecd = E1000_READ_REG(hw, E1000_EECD); ++ s32 ret_val = E1000_SUCCESS; ++ u16 timeout = 0; ++ u8 spi_stat_reg; ++ ++ DEBUGFUNC("e1000_ready_nvm_eeprom"); ++ ++ if (nvm->type == e1000_nvm_eeprom_microwire) { ++ /* Clear SK and DI */ ++ eecd &= ~(E1000_EECD_DI | E1000_EECD_SK); ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ /* Set CS */ ++ eecd |= E1000_EECD_CS; ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ } else if (nvm->type == e1000_nvm_eeprom_spi) { ++ /* Clear SK and CS */ ++ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); ++ E1000_WRITE_REG(hw, E1000_EECD, eecd); ++ usec_delay(1); ++ timeout = NVM_MAX_RETRY_SPI; ++ ++ /* ++ * Read "Status Register" repeatedly until the LSB is cleared. ++ * The EEPROM will signal that the command has been completed ++ * by clearing bit 0 of the internal status register. If it's ++ * not cleared within 'timeout', then error out. ++ */ ++ while (timeout) { ++ e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI, ++ hw->nvm.opcode_bits); ++ spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8); ++ if (!(spi_stat_reg & NVM_STATUS_RDY_SPI)) ++ break; ++ ++ usec_delay(5); ++ e1000_standby_nvm(hw); ++ timeout--; ++ } ++ ++ if (!timeout) { ++ DEBUGOUT("SPI NVM Status error\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_nvm_spi - Read EEPROM's using SPI ++ * @hw: pointer to the HW structure ++ * @offset: offset of word in the EEPROM to read ++ * @words: number of words to read ++ * @data: word read from the EEPROM ++ * ++ * Reads a 16 bit word from the EEPROM. ++ **/ ++s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ u32 i = 0; ++ s32 ret_val; ++ u16 word_in; ++ u8 read_opcode = NVM_READ_OPCODE_SPI; ++ ++ DEBUGFUNC("e1000_read_nvm_spi"); ++ ++ /* ++ * A check for invalid values: offset too large, too many words, ++ * and not enough words. ++ */ ++ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || ++ (words == 0)) { ++ DEBUGOUT("nvm parameter(s) out of bounds\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ ret_val = nvm->ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_ready_nvm_eeprom(hw); ++ if (ret_val) ++ goto release; ++ ++ e1000_standby_nvm(hw); ++ ++ if ((nvm->address_bits == 8) && (offset >= 128)) ++ read_opcode |= NVM_A8_OPCODE_SPI; ++ ++ /* Send the READ command (opcode + addr) */ ++ e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits); ++ e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits); ++ ++ /* ++ * Read the data. SPI NVMs increment the address with each byte ++ * read and will roll over if reading beyond the end. This allows ++ * us to read the whole NVM from any offset ++ */ ++ for (i = 0; i < words; i++) { ++ word_in = e1000_shift_in_eec_bits(hw, 16); ++ data[i] = (word_in >> 8) | (word_in << 8); ++ } ++ ++release: ++ nvm->ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_nvm_microwire - Reads EEPROM's using microwire ++ * @hw: pointer to the HW structure ++ * @offset: offset of word in the EEPROM to read ++ * @words: number of words to read ++ * @data: word read from the EEPROM ++ * ++ * Reads a 16 bit word from the EEPROM. ++ **/ ++s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words, ++ u16 *data) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ u32 i = 0; ++ s32 ret_val; ++ u8 read_opcode = NVM_READ_OPCODE_MICROWIRE; ++ ++ DEBUGFUNC("e1000_read_nvm_microwire"); ++ ++ /* ++ * A check for invalid values: offset too large, too many words, ++ * and not enough words. ++ */ ++ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || ++ (words == 0)) { ++ DEBUGOUT("nvm parameter(s) out of bounds\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ ret_val = nvm->ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_ready_nvm_eeprom(hw); ++ if (ret_val) ++ goto release; ++ ++ for (i = 0; i < words; i++) { ++ /* Send the READ command (opcode + addr) */ ++ e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits); ++ e1000_shift_out_eec_bits(hw, (u16)(offset + i), ++ nvm->address_bits); ++ ++ /* ++ * Read the data. For microwire, each word requires the ++ * overhead of setup and tear-down. ++ */ ++ data[i] = e1000_shift_in_eec_bits(hw, 16); ++ e1000_standby_nvm(hw); ++ } ++ ++release: ++ nvm->ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_nvm_eerd - Reads EEPROM using EERD register ++ * @hw: pointer to the HW structure ++ * @offset: offset of word in the EEPROM to read ++ * @words: number of words to read ++ * @data: word read from the EEPROM ++ * ++ * Reads a 16 bit word from the EEPROM using the EERD register. ++ **/ ++s32 e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ u32 i, eerd = 0; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_read_nvm_eerd"); ++ ++ /* ++ * A check for invalid values: offset too large, too many words, ++ * too many words for the offset, and not enough words. ++ */ ++ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || ++ (words == 0)) { ++ DEBUGOUT("nvm parameter(s) out of bounds\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ for (i = 0; i < words; i++) { ++ eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) + ++ E1000_NVM_RW_REG_START; ++ ++ E1000_WRITE_REG(hw, E1000_EERD, eerd); ++ ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ); ++ if (ret_val) ++ break; ++ ++ data[i] = (E1000_READ_REG(hw, E1000_EERD) >> ++ E1000_NVM_RW_REG_DATA); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_nvm_spi - Write to EEPROM using SPI ++ * @hw: pointer to the HW structure ++ * @offset: offset within the EEPROM to be written to ++ * @words: number of words to write ++ * @data: 16 bit word(s) to be written to the EEPROM ++ * ++ * Writes data to EEPROM at offset using SPI interface. ++ * ++ * If e1000_update_nvm_checksum is not called after this function , the ++ * EEPROM will most likely contain an invalid checksum. ++ **/ ++s32 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ s32 ret_val; ++ u16 widx = 0; ++ ++ DEBUGFUNC("e1000_write_nvm_spi"); ++ ++ /* ++ * A check for invalid values: offset too large, too many words, ++ * and not enough words. ++ */ ++ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || ++ (words == 0)) { ++ DEBUGOUT("nvm parameter(s) out of bounds\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ ret_val = nvm->ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ while (widx < words) { ++ u8 write_opcode = NVM_WRITE_OPCODE_SPI; ++ ++ ret_val = e1000_ready_nvm_eeprom(hw); ++ if (ret_val) ++ goto release; ++ ++ e1000_standby_nvm(hw); ++ ++ /* Send the WRITE ENABLE command (8 bit opcode) */ ++ e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI, ++ nvm->opcode_bits); ++ ++ e1000_standby_nvm(hw); ++ ++ /* ++ * Some SPI eeproms use the 8th address bit embedded in the ++ * opcode ++ */ ++ if ((nvm->address_bits == 8) && (offset >= 128)) ++ write_opcode |= NVM_A8_OPCODE_SPI; ++ ++ /* Send the Write command (8-bit opcode + addr) */ ++ e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits); ++ e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2), ++ nvm->address_bits); ++ ++ /* Loop to allow for up to whole page write of eeprom */ ++ while (widx < words) { ++ u16 word_out = data[widx]; ++ word_out = (word_out >> 8) | (word_out << 8); ++ e1000_shift_out_eec_bits(hw, word_out, 16); ++ widx++; ++ ++ if ((((offset + widx) * 2) % nvm->page_size) == 0) { ++ e1000_standby_nvm(hw); ++ break; ++ } ++ } ++ } ++ ++ msec_delay(nvm->semaphore_delay); ++release: ++ nvm->ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_nvm_microwire - Writes EEPROM using microwire ++ * @hw: pointer to the HW structure ++ * @offset: offset within the EEPROM to be written to ++ * @words: number of words to write ++ * @data: 16 bit word(s) to be written to the EEPROM ++ * ++ * Writes data to EEPROM at offset using microwire interface. ++ * ++ * If e1000_update_nvm_checksum is not called after this function , the ++ * EEPROM will most likely contain an invalid checksum. ++ **/ ++s32 e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words, ++ u16 *data) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ s32 ret_val; ++ u32 eecd; ++ u16 words_written = 0; ++ u16 widx = 0; ++ ++ DEBUGFUNC("e1000_write_nvm_microwire"); ++ ++ /* ++ * A check for invalid values: offset too large, too many words, ++ * and not enough words. ++ */ ++ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || ++ (words == 0)) { ++ DEBUGOUT("nvm parameter(s) out of bounds\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++ ret_val = nvm->ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_ready_nvm_eeprom(hw); ++ if (ret_val) ++ goto release; ++ ++ e1000_shift_out_eec_bits(hw, NVM_EWEN_OPCODE_MICROWIRE, ++ (u16)(nvm->opcode_bits + 2)); ++ ++ e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2)); ++ ++ e1000_standby_nvm(hw); ++ ++ while (words_written < words) { ++ e1000_shift_out_eec_bits(hw, NVM_WRITE_OPCODE_MICROWIRE, ++ nvm->opcode_bits); ++ ++ e1000_shift_out_eec_bits(hw, (u16)(offset + words_written), ++ nvm->address_bits); ++ ++ e1000_shift_out_eec_bits(hw, data[words_written], 16); ++ ++ e1000_standby_nvm(hw); ++ ++ for (widx = 0; widx < 200; widx++) { ++ eecd = E1000_READ_REG(hw, E1000_EECD); ++ if (eecd & E1000_EECD_DO) ++ break; ++ usec_delay(50); ++ } ++ ++ if (widx == 200) { ++ DEBUGOUT("NVM Write did not complete\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto release; ++ } ++ ++ e1000_standby_nvm(hw); ++ ++ words_written++; ++ } ++ ++ e1000_shift_out_eec_bits(hw, NVM_EWDS_OPCODE_MICROWIRE, ++ (u16)(nvm->opcode_bits + 2)); ++ ++ e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2)); ++ ++release: ++ nvm->ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_pba_num_generic - Read device part number ++ * @hw: pointer to the HW structure ++ * @pba_num: pointer to device part number ++ * ++ * Reads the product board assembly (PBA) number from the EEPROM and stores ++ * the value in pba_num. ++ **/ ++s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num) ++{ ++ s32 ret_val; ++ u16 nvm_data; ++ ++ DEBUGFUNC("e1000_read_pba_num_generic"); ++ ++ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error\n"); ++ goto out; ++ } ++ *pba_num = (u32)(nvm_data << 16); ++ ++ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error\n"); ++ goto out; ++ } ++ *pba_num |= nvm_data; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_mac_addr_generic - Read device MAC address ++ * @hw: pointer to the HW structure ++ * ++ * Reads the device MAC address from the EEPROM and stores the value. ++ * Since devices with two ports use the same EEPROM, we increment the ++ * last bit in the MAC address for the second port. ++ **/ ++s32 e1000_read_mac_addr_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 offset, nvm_data, i; ++ ++ DEBUGFUNC("e1000_read_mac_addr"); ++ ++ for (i = 0; i < ETH_ADDR_LEN; i += 2) { ++ offset = i >> 1; ++ ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error\n"); ++ goto out; ++ } ++ hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); ++ hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); ++ } ++ ++ /* Flip last bit of mac address if we're on second port */ ++ if (hw->bus.func == E1000_FUNC_1) ++ hw->mac.perm_addr[5] ^= 1; ++ ++ for (i = 0; i < ETH_ADDR_LEN; i++) ++ hw->mac.addr[i] = hw->mac.perm_addr[i]; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_validate_nvm_checksum_generic - Validate EEPROM checksum ++ * @hw: pointer to the HW structure ++ * ++ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM ++ * and then verifies that the sum of the EEPROM is equal to 0xBABA. ++ **/ ++s32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 checksum = 0; ++ u16 i, nvm_data; ++ ++ DEBUGFUNC("e1000_validate_nvm_checksum_generic"); ++ ++ for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { ++ ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error\n"); ++ goto out; ++ } ++ checksum += nvm_data; ++ } ++ ++ if (checksum != (u16) NVM_SUM) { ++ DEBUGOUT("NVM Checksum Invalid\n"); ++ ret_val = -E1000_ERR_NVM; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_update_nvm_checksum_generic - Update EEPROM checksum ++ * @hw: pointer to the HW structure ++ * ++ * Updates the EEPROM checksum by reading/adding each word of the EEPROM ++ * up to the checksum. Then calculates the EEPROM checksum and writes the ++ * value to the EEPROM. ++ **/ ++s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val; ++ u16 checksum = 0; ++ u16 i, nvm_data; ++ ++ DEBUGFUNC("e1000_update_nvm_checksum"); ++ ++ for (i = 0; i < NVM_CHECKSUM_REG; i++) { ++ ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); ++ if (ret_val) { ++ DEBUGOUT("NVM Read Error while updating checksum.\n"); ++ goto out; ++ } ++ checksum += nvm_data; ++ } ++ checksum = (u16) NVM_SUM - checksum; ++ ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum); ++ if (ret_val) { ++ DEBUGOUT("NVM Write Error while updating checksum.\n"); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_reload_nvm_generic - Reloads EEPROM ++ * @hw: pointer to the HW structure ++ * ++ * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the ++ * extended control register. ++ **/ ++void e1000_reload_nvm_generic(struct e1000_hw *hw) ++{ ++ u32 ctrl_ext; ++ ++ DEBUGFUNC("e1000_reload_nvm_generic"); ++ ++ usec_delay(10); ++ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); ++ ctrl_ext |= E1000_CTRL_EXT_EE_RST; ++ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); ++ E1000_WRITE_FLUSH(hw); ++} ++ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_nvm.h linux-2.6.22-10/drivers/net/e1000e/e1000_nvm.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_nvm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_nvm.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,58 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _E1000_NVM_H_ ++#define _E1000_NVM_H_ ++ ++void e1000_init_nvm_ops_generic(struct e1000_hw *hw); ++s32 e1000_acquire_nvm_generic(struct e1000_hw *hw); ++ ++s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg); ++s32 e1000_read_mac_addr_generic(struct e1000_hw *hw); ++s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num); ++s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); ++s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, ++ u16 words, u16 *data); ++s32 e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, ++ u16 *data); ++s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data); ++s32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw); ++s32 e1000_write_nvm_eewr(struct e1000_hw *hw, u16 offset, ++ u16 words, u16 *data); ++s32 e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset, ++ u16 words, u16 *data); ++s32 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, ++ u16 *data); ++s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw); ++void e1000_stop_nvm(struct e1000_hw *hw); ++void e1000_release_nvm_generic(struct e1000_hw *hw); ++void e1000_reload_nvm_generic(struct e1000_hw *hw); ++ ++#define E1000_STM_OPCODE 0xDB00 ++ ++#endif +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_osdep.h linux-2.6.22-10/drivers/net/e1000e/e1000_osdep.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_osdep.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_osdep.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,116 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++ ++/* glue for the OS-dependent part of e1000 ++ * includes register access macros ++ */ ++ ++#ifndef _E1000_OSDEP_H_ ++#define _E1000_OSDEP_H_ ++ ++#include ++#include ++#include ++#include ++ ++#include "kcompat.h" ++ ++#define usec_delay(x) udelay(x) ++#ifndef msec_delay ++#define msec_delay(x) do { if(in_interrupt()) { \ ++ /* Don't sleep in interrupt context! */ \ ++ BUG(); \ ++ } else { \ ++ msleep(x); \ ++ } } while (0) ++ ++/* Some workarounds require millisecond delays and are run during interrupt ++ * context. Most notably, when establishing link, the phy may need tweaking ++ * but cannot process phy register reads/writes faster than millisecond ++ * intervals...and we establish link due to a "link status change" interrupt. ++ */ ++#define msec_delay_irq(x) mdelay(x) ++#endif ++ ++#define PCI_COMMAND_REGISTER PCI_COMMAND ++#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE ++#define ETH_ADDR_LEN ETH_ALEN ++ ++ ++#define DEBUGOUT(S) ++#define DEBUGOUT1(S, A...) ++ ++#define DEBUGFUNC(F) DEBUGOUT(F "\n") ++#define DEBUGOUT2 DEBUGOUT1 ++#define DEBUGOUT3 DEBUGOUT2 ++#define DEBUGOUT7 DEBUGOUT3 ++ ++#define E1000_WRITE_REG(a, reg, value) ( \ ++ writel((value), ((a)->hw_addr + reg))) ++ ++#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + reg)) ++ ++#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \ ++ writel((value), ((a)->hw_addr + reg + ((offset) << 2)))) ++ ++#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ ++ readl((a)->hw_addr + reg + ((offset) << 2))) ++ ++#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY ++#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY ++ ++#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \ ++ writew((value), ((a)->hw_addr + reg + ((offset) << 1)))) ++ ++#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \ ++ readw((a)->hw_addr + reg + ((offset) << 1))) ++ ++#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \ ++ writeb((value), ((a)->hw_addr + reg + (offset)))) ++ ++#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \ ++ readb((a)->hw_addr + reg + (offset))) ++ ++#define E1000_WRITE_REG_IO(a, reg, offset) do { \ ++ outl(reg, ((a)->io_base)); \ ++ outl(offset, ((a)->io_base + 4)); } while(0) ++ ++#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS) ++ ++#define E1000_WRITE_FLASH_REG(a, reg, value) ( \ ++ writel((value), ((a)->flash_address + reg))) ++ ++#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \ ++ writew((value), ((a)->flash_address + reg))) ++ ++#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg)) ++ ++#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg)) ++ ++#endif /* _E1000_OSDEP_H_ */ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_phy.c linux-2.6.22-10/drivers/net/e1000e/e1000_phy.c +--- linux-2.6.22-0/drivers/net/e1000e/e1000_phy.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_phy.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,2489 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include "e1000_hw.h" ++ ++static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg); ++/* Cable length tables */ ++static const u16 e1000_m88_cable_length_table[] = ++ { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; ++#define M88E1000_CABLE_LENGTH_TABLE_SIZE \ ++ (sizeof(e1000_m88_cable_length_table) / \ ++ sizeof(e1000_m88_cable_length_table[0])) ++ ++static const u16 e1000_igp_2_cable_length_table[] = ++ { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, ++ 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, ++ 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, ++ 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, ++ 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, ++ 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, ++ 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, ++ 104, 109, 114, 118, 121, 124}; ++#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ ++ (sizeof(e1000_igp_2_cable_length_table) / \ ++ sizeof(e1000_igp_2_cable_length_table[0])) ++ ++/** ++ * e1000_check_reset_block_generic - Check if PHY reset is blocked ++ * @hw: pointer to the HW structure ++ * ++ * Read the PHY management control register and check whether a PHY reset ++ * is blocked. If a reset is not blocked return E1000_SUCCESS, otherwise ++ * return E1000_BLK_PHY_RESET (12). ++ **/ ++s32 e1000_check_reset_block_generic(struct e1000_hw *hw) ++{ ++ u32 manc; ++ ++ DEBUGFUNC("e1000_check_reset_block"); ++ ++ manc = E1000_READ_REG(hw, E1000_MANC); ++ ++ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? ++ E1000_BLK_PHY_RESET : E1000_SUCCESS; ++} ++ ++/** ++ * e1000_get_phy_id - Retrieve the PHY ID and revision ++ * @hw: pointer to the HW structure ++ * ++ * Reads the PHY registers and stores the PHY ID and possibly the PHY ++ * revision in the hardware structure. ++ **/ ++s32 e1000_get_phy_id(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ u16 phy_id; ++ ++ DEBUGFUNC("e1000_get_phy_id"); ++ ++ if (!(phy->ops.read_reg)) ++ goto out; ++ ++ ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); ++ if (ret_val) ++ goto out; ++ ++ phy->id = (u32)(phy_id << 16); ++ usec_delay(20); ++ ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id); ++ if (ret_val) ++ goto out; ++ ++ phy->id |= (u32)(phy_id & PHY_REVISION_MASK); ++ phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_phy_reset_dsp_generic - Reset PHY DSP ++ * @hw: pointer to the HW structure ++ * ++ * Reset the digital signal processor. ++ **/ ++s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_phy_reset_dsp_generic"); ++ ++ if (!(hw->phy.ops.write_reg)) ++ goto out; ++ ++ ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); ++ if (ret_val) ++ goto out; ++ ++ ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_phy_reg_mdic - Read MDI control register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to be read ++ * @data: pointer to the read data ++ * ++ * Reads the MDI control register in the PHY at offset and stores the ++ * information read to data. ++ **/ ++s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ u32 i, mdic = 0; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_read_phy_reg_mdic"); ++ ++ /* ++ * Set up Op-code, Phy Address, and register offset in the MDI ++ * Control register. The MAC will take care of interfacing with the ++ * PHY to retrieve the desired data. ++ */ ++ mdic = ((offset << E1000_MDIC_REG_SHIFT) | ++ (phy->addr << E1000_MDIC_PHY_SHIFT) | ++ (E1000_MDIC_OP_READ)); ++ ++ E1000_WRITE_REG(hw, E1000_MDIC, mdic); ++ ++ /* ++ * Poll the ready bit to see if the MDI read completed ++ * Increasing the time out as testing showed failures with ++ * the lower time out ++ */ ++ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { ++ usec_delay(50); ++ mdic = E1000_READ_REG(hw, E1000_MDIC); ++ if (mdic & E1000_MDIC_READY) ++ break; ++ } ++ if (!(mdic & E1000_MDIC_READY)) { ++ DEBUGOUT("MDI Read did not complete\n"); ++ ret_val = -E1000_ERR_PHY; ++ goto out; ++ } ++ if (mdic & E1000_MDIC_ERROR) { ++ DEBUGOUT("MDI Error\n"); ++ ret_val = -E1000_ERR_PHY; ++ goto out; ++ } ++ *data = (u16) mdic; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_phy_reg_mdic - Write MDI control register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to write to ++ * @data: data to write to register at offset ++ * ++ * Writes data to MDI control register in the PHY at offset. ++ **/ ++s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ u32 i, mdic = 0; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_write_phy_reg_mdic"); ++ ++ /* ++ * Set up Op-code, Phy Address, and register offset in the MDI ++ * Control register. The MAC will take care of interfacing with the ++ * PHY to retrieve the desired data. ++ */ ++ mdic = (((u32)data) | ++ (offset << E1000_MDIC_REG_SHIFT) | ++ (phy->addr << E1000_MDIC_PHY_SHIFT) | ++ (E1000_MDIC_OP_WRITE)); ++ ++ E1000_WRITE_REG(hw, E1000_MDIC, mdic); ++ ++ /* ++ * Poll the ready bit to see if the MDI read completed ++ * Increasing the time out as testing showed failures with ++ * the lower time out ++ */ ++ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { ++ usec_delay(50); ++ mdic = E1000_READ_REG(hw, E1000_MDIC); ++ if (mdic & E1000_MDIC_READY) ++ break; ++ } ++ if (!(mdic & E1000_MDIC_READY)) { ++ DEBUGOUT("MDI Write did not complete\n"); ++ ret_val = -E1000_ERR_PHY; ++ goto out; ++ } ++ if (mdic & E1000_MDIC_ERROR) { ++ DEBUGOUT("MDI Error\n"); ++ ret_val = -E1000_ERR_PHY; ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_phy_reg_m88 - Read m88 PHY register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to be read ++ * @data: pointer to the read data ++ * ++ * Acquires semaphore, if necessary, then reads the PHY register at offset ++ * and storing the retrieved information in data. Release any acquired ++ * semaphores before exiting. ++ **/ ++s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_read_phy_reg_m88"); ++ ++ if (!(hw->phy.ops.acquire)) ++ goto out; ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_read_phy_reg_mdic(hw, ++ MAX_PHY_REG_ADDRESS & offset, ++ data); ++ ++ hw->phy.ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_phy_reg_m88 - Write m88 PHY register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to write to ++ * @data: data to write at register offset ++ * ++ * Acquires semaphore, if necessary, then writes the data to PHY register ++ * at the offset. Release any acquired semaphores before exiting. ++ **/ ++s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_write_phy_reg_m88"); ++ ++ if (!(hw->phy.ops.acquire)) ++ goto out; ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = e1000_write_phy_reg_mdic(hw, ++ MAX_PHY_REG_ADDRESS & offset, ++ data); ++ ++ hw->phy.ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_phy_reg_igp - Read igp PHY register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to be read ++ * @data: pointer to the read data ++ * ++ * Acquires semaphore, if necessary, then reads the PHY register at offset ++ * and storing the retrieved information in data. Release any acquired ++ * semaphores before exiting. ++ **/ ++s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_read_phy_reg_igp"); ++ ++ if (!(hw->phy.ops.acquire)) ++ goto out; ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ if (offset > MAX_PHY_MULTI_PAGE_REG) { ++ ret_val = e1000_write_phy_reg_mdic(hw, ++ IGP01E1000_PHY_PAGE_SELECT, ++ (u16)offset); ++ if (ret_val) { ++ hw->phy.ops.release(hw); ++ goto out; ++ } ++ } ++ ++ ret_val = e1000_read_phy_reg_mdic(hw, ++ MAX_PHY_REG_ADDRESS & offset, ++ data); ++ ++ hw->phy.ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_phy_reg_igp - Write igp PHY register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to write to ++ * @data: data to write at register offset ++ * ++ * Acquires semaphore, if necessary, then writes the data to PHY register ++ * at the offset. Release any acquired semaphores before exiting. ++ **/ ++s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_write_phy_reg_igp"); ++ ++ if (!(hw->phy.ops.acquire)) ++ goto out; ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ if (offset > MAX_PHY_MULTI_PAGE_REG) { ++ ret_val = e1000_write_phy_reg_mdic(hw, ++ IGP01E1000_PHY_PAGE_SELECT, ++ (u16)offset); ++ if (ret_val) { ++ hw->phy.ops.release(hw); ++ goto out; ++ } ++ } ++ ++ ret_val = e1000_write_phy_reg_mdic(hw, ++ MAX_PHY_REG_ADDRESS & offset, ++ data); ++ ++ hw->phy.ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_kmrn_reg_generic - Read kumeran register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to be read ++ * @data: pointer to the read data ++ * ++ * Acquires semaphore, if necessary. Then reads the PHY register at offset ++ * using the kumeran interface. The information retrieved is stored in data. ++ * Release any acquired semaphores before exiting. ++ **/ ++s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data) ++{ ++ u32 kmrnctrlsta; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_read_kmrn_reg_generic"); ++ ++ if (!(hw->phy.ops.acquire)) ++ goto out; ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & ++ E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; ++ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); ++ ++ usec_delay(2); ++ ++ kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA); ++ *data = (u16)kmrnctrlsta; ++ ++ hw->phy.ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_kmrn_reg_generic - Write kumeran register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to write to ++ * @data: data to write at register offset ++ * ++ * Acquires semaphore, if necessary. Then write the data to PHY register ++ * at the offset using the kumeran interface. Release any acquired semaphores ++ * before exiting. ++ **/ ++s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data) ++{ ++ u32 kmrnctrlsta; ++ s32 ret_val = E1000_SUCCESS; ++ ++ DEBUGFUNC("e1000_write_kmrn_reg_generic"); ++ ++ if (!(hw->phy.ops.acquire)) ++ goto out; ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & ++ E1000_KMRNCTRLSTA_OFFSET) | data; ++ E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); ++ ++ usec_delay(2); ++ hw->phy.ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link ++ * @hw: pointer to the HW structure ++ * ++ * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock ++ * and downshift values are set also. ++ **/ ++s32 e1000_copper_link_setup_m88(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 phy_data; ++ ++ DEBUGFUNC("e1000_copper_link_setup_m88"); ++ ++ if (phy->reset_disable) { ++ ret_val = E1000_SUCCESS; ++ goto out; ++ } ++ ++ /* Enable CRS on TX. This must be set for half-duplex operation. */ ++ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ /* For newer PHYs this bit is downshift enable */ ++ if (phy->type == e1000_phy_m88) ++ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; ++ ++ /* ++ * Options: ++ * MDI/MDI-X = 0 (default) ++ * 0 - Auto for all speeds ++ * 1 - MDI mode ++ * 2 - MDI-X mode ++ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) ++ */ ++ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; ++ ++ switch (phy->mdix) { ++ case 1: ++ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; ++ break; ++ case 2: ++ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; ++ break; ++ case 3: ++ phy_data |= M88E1000_PSCR_AUTO_X_1000T; ++ break; ++ case 0: ++ default: ++ phy_data |= M88E1000_PSCR_AUTO_X_MODE; ++ break; ++ } ++ ++ /* ++ * Options: ++ * disable_polarity_correction = 0 (default) ++ * Automatic Correction for Reversed Cable Polarity ++ * 0 - Disabled ++ * 1 - Enabled ++ */ ++ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; ++ if (phy->disable_polarity_correction == 1) ++ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; ++ ++ /* Enable downshift on BM (disabled by default) */ ++ if (phy->type == e1000_phy_bm) ++ phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT; ++ ++ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); ++ if (ret_val) ++ goto out; ++ ++ if ((phy->type == e1000_phy_m88) && ++ (phy->revision < E1000_REVISION_4) && ++ (phy->id != BME1000_E_PHY_ID_R2)) { ++ /* ++ * Force TX_CLK in the Extended PHY Specific Control Register ++ * to 25MHz clock. ++ */ ++ ret_val = phy->ops.read_reg(hw, ++ M88E1000_EXT_PHY_SPEC_CTRL, ++ &phy_data); ++ if (ret_val) ++ goto out; ++ ++ phy_data |= M88E1000_EPSCR_TX_CLK_25; ++ ++ if ((phy->revision == E1000_REVISION_2) && ++ (phy->id == M88E1111_I_PHY_ID)) { ++ /* 82573L PHY - set the downshift counter to 5x. */ ++ phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK; ++ phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X; ++ } else { ++ /* Configure Master and Slave downshift values */ ++ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | ++ M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); ++ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | ++ M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); ++ } ++ ret_val = phy->ops.write_reg(hw, ++ M88E1000_EXT_PHY_SPEC_CTRL, ++ phy_data); ++ if (ret_val) ++ goto out; ++ } ++ ++ if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) { ++ /* Set PHY page 0, register 29 to 0x0003 */ ++ ret_val = phy->ops.write_reg(hw, 29, 0x0003); ++ if (ret_val) ++ goto out; ++ ++ /* Set PHY page 0, register 30 to 0x0000 */ ++ ret_val = phy->ops.write_reg(hw, 30, 0x0000); ++ if (ret_val) ++ goto out; ++ } ++ ++ /* Commit the changes. */ ++ ret_val = phy->ops.commit(hw); ++ if (ret_val) { ++ DEBUGOUT("Error committing the PHY changes\n"); ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_copper_link_setup_igp - Setup igp PHY's for copper link ++ * @hw: pointer to the HW structure ++ * ++ * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for ++ * igp PHY's. ++ **/ ++s32 e1000_copper_link_setup_igp(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 data; ++ ++ DEBUGFUNC("e1000_copper_link_setup_igp"); ++ ++ if (phy->reset_disable) { ++ ret_val = E1000_SUCCESS; ++ goto out; ++ } ++ ++ ret_val = hw->phy.ops.reset(hw); ++ if (ret_val) { ++ DEBUGOUT("Error resetting the PHY.\n"); ++ goto out; ++ } ++ ++ /* ++ * Wait 100ms for MAC to configure PHY from NVM settings, to avoid ++ * timeout issues when LFS is enabled. ++ */ ++ msec_delay(100); ++ ++ /* ++ * The NVM settings will configure LPLU in D3 for ++ * non-IGP1 PHYs. ++ */ ++ if (phy->type == e1000_phy_igp) { ++ /* disable lplu d3 during driver init */ ++ ret_val = hw->phy.ops.set_d3_lplu_state(hw, false); ++ if (ret_val) { ++ DEBUGOUT("Error Disabling LPLU D3\n"); ++ goto out; ++ } ++ } ++ ++ /* disable lplu d0 during driver init */ ++ if (hw->phy.ops.set_d0_lplu_state) { ++ ret_val = hw->phy.ops.set_d0_lplu_state(hw, false); ++ if (ret_val) { ++ DEBUGOUT("Error Disabling LPLU D0\n"); ++ goto out; ++ } ++ } ++ /* Configure mdi-mdix settings */ ++ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~IGP01E1000_PSCR_AUTO_MDIX; ++ ++ switch (phy->mdix) { ++ case 1: ++ data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; ++ break; ++ case 2: ++ data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; ++ break; ++ case 0: ++ default: ++ data |= IGP01E1000_PSCR_AUTO_MDIX; ++ break; ++ } ++ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data); ++ if (ret_val) ++ goto out; ++ ++ /* set auto-master slave resolution settings */ ++ if (hw->mac.autoneg) { ++ /* ++ * when autonegotiation advertisement is only 1000Mbps then we ++ * should disable SmartSpeed and enable Auto MasterSlave ++ * resolution as hardware default. ++ */ ++ if (phy->autoneg_advertised == ADVERTISE_1000_FULL) { ++ /* Disable SmartSpeed */ ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ ++ /* Set auto Master/Slave resolution process */ ++ ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~CR_1000T_MS_ENABLE; ++ ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data); ++ if (ret_val) ++ goto out; ++ } ++ ++ ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data); ++ if (ret_val) ++ goto out; ++ ++ /* load defaults for future use */ ++ phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ? ++ ((data & CR_1000T_MS_VALUE) ? ++ e1000_ms_force_master : ++ e1000_ms_force_slave) : ++ e1000_ms_auto; ++ ++ switch (phy->ms_type) { ++ case e1000_ms_force_master: ++ data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); ++ break; ++ case e1000_ms_force_slave: ++ data |= CR_1000T_MS_ENABLE; ++ data &= ~(CR_1000T_MS_VALUE); ++ break; ++ case e1000_ms_auto: ++ data &= ~CR_1000T_MS_ENABLE; ++ default: ++ break; ++ } ++ ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data); ++ if (ret_val) ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link ++ * @hw: pointer to the HW structure ++ * ++ * Performs initial bounds checking on autoneg advertisement parameter, then ++ * configure to advertise the full capability. Setup the PHY to autoneg ++ * and restart the negotiation process between the link partner. If ++ * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. ++ **/ ++s32 e1000_copper_link_autoneg(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 phy_ctrl; ++ ++ DEBUGFUNC("e1000_copper_link_autoneg"); ++ ++ /* ++ * Perform some bounds checking on the autoneg advertisement ++ * parameter. ++ */ ++ phy->autoneg_advertised &= phy->autoneg_mask; ++ ++ /* ++ * If autoneg_advertised is zero, we assume it was not defaulted ++ * by the calling code so we set to advertise full capability. ++ */ ++ if (phy->autoneg_advertised == 0) ++ phy->autoneg_advertised = phy->autoneg_mask; ++ ++ DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); ++ ret_val = e1000_phy_setup_autoneg(hw); ++ if (ret_val) { ++ DEBUGOUT("Error Setting up Auto-Negotiation\n"); ++ goto out; ++ } ++ DEBUGOUT("Restarting Auto-Neg\n"); ++ ++ /* ++ * Restart auto-negotiation by setting the Auto Neg Enable bit and ++ * the Auto Neg Restart bit in the PHY control register. ++ */ ++ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); ++ if (ret_val) ++ goto out; ++ ++ phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); ++ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Does the user want to wait for Auto-Neg to complete here, or ++ * check at a later time (for example, callback routine). ++ */ ++ if (phy->autoneg_wait_to_complete) { ++ ret_val = hw->mac.ops.wait_autoneg(hw); ++ if (ret_val) { ++ DEBUGOUT("Error while waiting for " ++ "autoneg to complete\n"); ++ goto out; ++ } ++ } ++ ++ hw->mac.get_link_status = true; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation ++ * @hw: pointer to the HW structure ++ * ++ * Reads the MII auto-neg advertisement register and/or the 1000T control ++ * register and if the PHY is already setup for auto-negotiation, then ++ * return successful. Otherwise, setup advertisement and flow control to ++ * the appropriate values for the wanted auto-negotiation. ++ **/ ++s32 e1000_phy_setup_autoneg(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 mii_autoneg_adv_reg; ++ u16 mii_1000t_ctrl_reg = 0; ++ ++ DEBUGFUNC("e1000_phy_setup_autoneg"); ++ ++ phy->autoneg_advertised &= phy->autoneg_mask; ++ ++ /* Read the MII Auto-Neg Advertisement Register (Address 4). */ ++ ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); ++ if (ret_val) ++ goto out; ++ ++ if (phy->autoneg_mask & ADVERTISE_1000_FULL) { ++ /* Read the MII 1000Base-T Control Register (Address 9). */ ++ ret_val = phy->ops.read_reg(hw, ++ PHY_1000T_CTRL, ++ &mii_1000t_ctrl_reg); ++ if (ret_val) ++ goto out; ++ } ++ ++ /* ++ * Need to parse both autoneg_advertised and fc and set up ++ * the appropriate PHY registers. First we will parse for ++ * autoneg_advertised software override. Since we can advertise ++ * a plethora of combinations, we need to check each bit ++ * individually. ++ */ ++ ++ /* ++ * First we clear all the 10/100 mb speed bits in the Auto-Neg ++ * Advertisement Register (Address 4) and the 1000 mb speed bits in ++ * the 1000Base-T Control Register (Address 9). ++ */ ++ mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | ++ NWAY_AR_100TX_HD_CAPS | ++ NWAY_AR_10T_FD_CAPS | ++ NWAY_AR_10T_HD_CAPS); ++ mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); ++ ++ DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised); ++ ++ /* Do we want to advertise 10 Mb Half Duplex? */ ++ if (phy->autoneg_advertised & ADVERTISE_10_HALF) { ++ DEBUGOUT("Advertise 10mb Half duplex\n"); ++ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; ++ } ++ ++ /* Do we want to advertise 10 Mb Full Duplex? */ ++ if (phy->autoneg_advertised & ADVERTISE_10_FULL) { ++ DEBUGOUT("Advertise 10mb Full duplex\n"); ++ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; ++ } ++ ++ /* Do we want to advertise 100 Mb Half Duplex? */ ++ if (phy->autoneg_advertised & ADVERTISE_100_HALF) { ++ DEBUGOUT("Advertise 100mb Half duplex\n"); ++ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; ++ } ++ ++ /* Do we want to advertise 100 Mb Full Duplex? */ ++ if (phy->autoneg_advertised & ADVERTISE_100_FULL) { ++ DEBUGOUT("Advertise 100mb Full duplex\n"); ++ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; ++ } ++ ++ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ ++ if (phy->autoneg_advertised & ADVERTISE_1000_HALF) { ++ DEBUGOUT("Advertise 1000mb Half duplex request denied!\n"); ++ } ++ ++ /* Do we want to advertise 1000 Mb Full Duplex? */ ++ if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { ++ DEBUGOUT("Advertise 1000mb Full duplex\n"); ++ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; ++ } ++ ++ /* ++ * Check for a software override of the flow control settings, and ++ * setup the PHY advertisement registers accordingly. If ++ * auto-negotiation is enabled, then software will have to set the ++ * "PAUSE" bits to the correct value in the Auto-Negotiation ++ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- ++ * negotiation. ++ * ++ * The possible values of the "fc" parameter are: ++ * 0: Flow control is completely disabled ++ * 1: Rx flow control is enabled (we can receive pause frames ++ * but not send pause frames). ++ * 2: Tx flow control is enabled (we can send pause frames ++ * but we do not support receiving pause frames). ++ * 3: Both Rx and Tx flow control (symmetric) are enabled. ++ * other: No software override. The flow control configuration ++ * in the EEPROM is used. ++ */ ++ switch (hw->fc.type) { ++ case e1000_fc_none: ++ /* ++ * Flow control (Rx & Tx) is completely disabled by a ++ * software over-ride. ++ */ ++ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); ++ break; ++ case e1000_fc_rx_pause: ++ /* ++ * Rx Flow control is enabled, and Tx Flow control is ++ * disabled, by a software over-ride. ++ * ++ * Since there really isn't a way to advertise that we are ++ * capable of Rx Pause ONLY, we will advertise that we ++ * support both symmetric and asymmetric Rx PAUSE. Later ++ * (in e1000_config_fc_after_link_up) we will disable the ++ * hw's ability to send PAUSE frames. ++ */ ++ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); ++ break; ++ case e1000_fc_tx_pause: ++ /* ++ * Tx Flow control is enabled, and Rx Flow control is ++ * disabled, by a software over-ride. ++ */ ++ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; ++ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; ++ break; ++ case e1000_fc_full: ++ /* ++ * Flow control (both Rx and Tx) is enabled by a software ++ * over-ride. ++ */ ++ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); ++ break; ++ default: ++ DEBUGOUT("Flow control param set incorrectly\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); ++ if (ret_val) ++ goto out; ++ ++ DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); ++ ++ if (phy->autoneg_mask & ADVERTISE_1000_FULL) { ++ ret_val = phy->ops.write_reg(hw, ++ PHY_1000T_CTRL, ++ mii_1000t_ctrl_reg); ++ if (ret_val) ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_setup_copper_link_generic - Configure copper link settings ++ * @hw: pointer to the HW structure ++ * ++ * Calls the appropriate function to configure the link for auto-neg or forced ++ * speed and duplex. Then we check for link, once link is established calls ++ * to configure collision distance and flow control are called. If link is ++ * not established, we return -E1000_ERR_PHY (-2). ++ **/ ++s32 e1000_setup_copper_link_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val; ++ bool link; ++ ++ DEBUGFUNC("e1000_setup_copper_link_generic"); ++ ++ if (hw->mac.autoneg) { ++ /* ++ * Setup autoneg and flow control advertisement and perform ++ * autonegotiation. ++ */ ++ ret_val = e1000_copper_link_autoneg(hw); ++ if (ret_val) ++ goto out; ++ } else { ++ /* ++ * PHY will be set to 10H, 10F, 100H or 100F ++ * depending on user settings. ++ */ ++ DEBUGOUT("Forcing Speed and Duplex\n"); ++ ret_val = hw->phy.ops.force_speed_duplex(hw); ++ if (ret_val) { ++ DEBUGOUT("Error Forcing Speed and Duplex\n"); ++ goto out; ++ } ++ } ++ ++ /* ++ * Check link status. Wait up to 100 microseconds for link to become ++ * valid. ++ */ ++ ret_val = e1000_phy_has_link_generic(hw, ++ COPPER_LINK_UP_LIMIT, ++ 10, ++ &link); ++ if (ret_val) ++ goto out; ++ ++ if (link) { ++ DEBUGOUT("Valid link established!!!\n"); ++ e1000_config_collision_dist_generic(hw); ++ ret_val = e1000_config_fc_after_link_up_generic(hw); ++ } else { ++ DEBUGOUT("Unable to establish link!!!\n"); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY ++ * @hw: pointer to the HW structure ++ * ++ * Calls the PHY setup function to force speed and duplex. Clears the ++ * auto-crossover to force MDI manually. Waits for link and returns ++ * successful if link up is successful, else -E1000_ERR_PHY (-2). ++ **/ ++s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 phy_data; ++ bool link; ++ ++ DEBUGFUNC("e1000_phy_force_speed_duplex_igp"); ++ ++ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ e1000_phy_force_speed_duplex_setup(hw, &phy_data); ++ ++ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Clear Auto-Crossover to force MDI manually. IGP requires MDI ++ * forced whenever speed and duplex are forced. ++ */ ++ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; ++ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; ++ ++ ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); ++ if (ret_val) ++ goto out; ++ ++ DEBUGOUT1("IGP PSCR: %X\n", phy_data); ++ ++ usec_delay(1); ++ ++ if (phy->autoneg_wait_to_complete) { ++ DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n"); ++ ++ ret_val = e1000_phy_has_link_generic(hw, ++ PHY_FORCE_LIMIT, ++ 100000, ++ &link); ++ if (ret_val) ++ goto out; ++ ++ if (!link) { ++ DEBUGOUT("Link taking longer than expected.\n"); ++ } ++ ++ /* Try once more */ ++ ret_val = e1000_phy_has_link_generic(hw, ++ PHY_FORCE_LIMIT, ++ 100000, ++ &link); ++ if (ret_val) ++ goto out; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY ++ * @hw: pointer to the HW structure ++ * ++ * Calls the PHY setup function to force speed and duplex. Clears the ++ * auto-crossover to force MDI manually. Resets the PHY to commit the ++ * changes. If time expires while waiting for link up, we reset the DSP. ++ * After reset, TX_CLK and CRS on Tx must be set. Return successful upon ++ * successful completion, else return corresponding error code. ++ **/ ++s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 phy_data; ++ bool link; ++ ++ DEBUGFUNC("e1000_phy_force_speed_duplex_m88"); ++ ++ /* ++ * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI ++ * forced whenever speed and duplex are forced. ++ */ ++ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; ++ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); ++ if (ret_val) ++ goto out; ++ ++ DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data); ++ ++ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ e1000_phy_force_speed_duplex_setup(hw, &phy_data); ++ ++ /* Reset the phy to commit changes. */ ++ phy_data |= MII_CR_RESET; ++ ++ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); ++ if (ret_val) ++ goto out; ++ ++ usec_delay(1); ++ ++ if (phy->autoneg_wait_to_complete) { ++ DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n"); ++ ++ ret_val = e1000_phy_has_link_generic(hw, ++ PHY_FORCE_LIMIT, ++ 100000, ++ &link); ++ if (ret_val) ++ goto out; ++ ++ if (!link) { ++ /* ++ * We didn't get link. ++ * Reset the DSP and cross our fingers. ++ */ ++ ret_val = phy->ops.write_reg(hw, ++ M88E1000_PHY_PAGE_SELECT, ++ 0x001d); ++ if (ret_val) ++ goto out; ++ ret_val = e1000_phy_reset_dsp_generic(hw); ++ if (ret_val) ++ goto out; ++ } ++ ++ /* Try once more */ ++ ret_val = e1000_phy_has_link_generic(hw, ++ PHY_FORCE_LIMIT, ++ 100000, ++ &link); ++ if (ret_val) ++ goto out; ++ } ++ ++ ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Resetting the phy means we need to re-force TX_CLK in the ++ * Extended PHY Specific Control Register to 25MHz clock from ++ * the reset value of 2.5MHz. ++ */ ++ phy_data |= M88E1000_EPSCR_TX_CLK_25; ++ ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * In addition, we must re-enable CRS on Tx for both half and full ++ * duplex. ++ */ ++ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; ++ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex ++ * @hw: pointer to the HW structure ++ * @phy_ctrl: pointer to current value of PHY_CONTROL ++ * ++ * Forces speed and duplex on the PHY by doing the following: disable flow ++ * control, force speed/duplex on the MAC, disable auto speed detection, ++ * disable auto-negotiation, configure duplex, configure speed, configure ++ * the collision distance, write configuration to CTRL register. The ++ * caller must write to the PHY_CONTROL register for these settings to ++ * take affect. ++ **/ ++void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl) ++{ ++ struct e1000_mac_info *mac = &hw->mac; ++ u32 ctrl; ++ ++ DEBUGFUNC("e1000_phy_force_speed_duplex_setup"); ++ ++ /* Turn off flow control when forcing speed/duplex */ ++ hw->fc.type = e1000_fc_none; ++ ++ /* Force speed/duplex on the mac */ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); ++ ctrl &= ~E1000_CTRL_SPD_SEL; ++ ++ /* Disable Auto Speed Detection */ ++ ctrl &= ~E1000_CTRL_ASDE; ++ ++ /* Disable autoneg on the phy */ ++ *phy_ctrl &= ~MII_CR_AUTO_NEG_EN; ++ ++ /* Forcing Full or Half Duplex? */ ++ if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) { ++ ctrl &= ~E1000_CTRL_FD; ++ *phy_ctrl &= ~MII_CR_FULL_DUPLEX; ++ DEBUGOUT("Half Duplex\n"); ++ } else { ++ ctrl |= E1000_CTRL_FD; ++ *phy_ctrl |= MII_CR_FULL_DUPLEX; ++ DEBUGOUT("Full Duplex\n"); ++ } ++ ++ /* Forcing 10mb or 100mb? */ ++ if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) { ++ ctrl |= E1000_CTRL_SPD_100; ++ *phy_ctrl |= MII_CR_SPEED_100; ++ *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); ++ DEBUGOUT("Forcing 100mb\n"); ++ } else { ++ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); ++ *phy_ctrl |= MII_CR_SPEED_10; ++ *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); ++ DEBUGOUT("Forcing 10mb\n"); ++ } ++ ++ e1000_config_collision_dist_generic(hw); ++ ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++} ++ ++/** ++ * e1000_set_d3_lplu_state_generic - Sets low power link up state for D3 ++ * @hw: pointer to the HW structure ++ * @active: boolean used to enable/disable lplu ++ * ++ * Success returns 0, Failure returns 1 ++ * ++ * The low power link up (lplu) state is set to the power management level D3 ++ * and SmartSpeed is disabled when active is true, else clear lplu for D3 ++ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU ++ * is used during Dx states where the power conservation is most important. ++ * During driver activity, SmartSpeed should be enabled so performance is ++ * maintained. ++ **/ ++s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ u16 data; ++ ++ DEBUGFUNC("e1000_set_d3_lplu_state_generic"); ++ ++ if (!(hw->phy.ops.read_reg)) ++ goto out; ++ ++ ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data); ++ if (ret_val) ++ goto out; ++ ++ if (!active) { ++ data &= ~IGP02E1000_PM_D3_LPLU; ++ ret_val = phy->ops.write_reg(hw, ++ IGP02E1000_PHY_POWER_MGMT, ++ data); ++ if (ret_val) ++ goto out; ++ /* ++ * LPLU and SmartSpeed are mutually exclusive. LPLU is used ++ * during Dx states where the power conservation is most ++ * important. During driver activity we should enable ++ * SmartSpeed, so performance is maintained. ++ */ ++ if (phy->smart_speed == e1000_smart_speed_on) { ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data |= IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ } else if (phy->smart_speed == e1000_smart_speed_off) { ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ if (ret_val) ++ goto out; ++ } ++ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || ++ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || ++ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { ++ data |= IGP02E1000_PM_D3_LPLU; ++ ret_val = phy->ops.write_reg(hw, ++ IGP02E1000_PHY_POWER_MGMT, ++ data); ++ if (ret_val) ++ goto out; ++ ++ /* When LPLU is enabled, we should disable SmartSpeed */ ++ ret_val = phy->ops.read_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ &data); ++ if (ret_val) ++ goto out; ++ ++ data &= ~IGP01E1000_PSCFR_SMART_SPEED; ++ ret_val = phy->ops.write_reg(hw, ++ IGP01E1000_PHY_PORT_CONFIG, ++ data); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_check_downshift_generic - Checks whether a downshift in speed occurred ++ * @hw: pointer to the HW structure ++ * ++ * Success returns 0, Failure returns 1 ++ * ++ * A downshift is detected by querying the PHY link health. ++ **/ ++s32 e1000_check_downshift_generic(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 phy_data, offset, mask; ++ ++ DEBUGFUNC("e1000_check_downshift_generic"); ++ ++ switch (phy->type) { ++ case e1000_phy_m88: ++ case e1000_phy_gg82563: ++ case e1000_phy_bm: ++ offset = M88E1000_PHY_SPEC_STATUS; ++ mask = M88E1000_PSSR_DOWNSHIFT; ++ break; ++ case e1000_phy_igp_2: ++ case e1000_phy_igp: ++ case e1000_phy_igp_3: ++ offset = IGP01E1000_PHY_LINK_HEALTH; ++ mask = IGP01E1000_PLHR_SS_DOWNGRADE; ++ break; ++ default: ++ /* speed downshift not supported */ ++ phy->speed_downgraded = false; ++ ret_val = E1000_SUCCESS; ++ goto out; ++ } ++ ++ ret_val = phy->ops.read_reg(hw, offset, &phy_data); ++ ++ if (!ret_val) ++ phy->speed_downgraded = (phy_data & mask) ? true : false; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_check_polarity_m88 - Checks the polarity. ++ * @hw: pointer to the HW structure ++ * ++ * Success returns 0, Failure returns -E1000_ERR_PHY (-2) ++ * ++ * Polarity is determined based on the PHY specific status register. ++ **/ ++s32 e1000_check_polarity_m88(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 data; ++ ++ DEBUGFUNC("e1000_check_polarity_m88"); ++ ++ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data); ++ ++ if (!ret_val) ++ phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY) ++ ? e1000_rev_polarity_reversed ++ : e1000_rev_polarity_normal; ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_check_polarity_igp - Checks the polarity. ++ * @hw: pointer to the HW structure ++ * ++ * Success returns 0, Failure returns -E1000_ERR_PHY (-2) ++ * ++ * Polarity is determined based on the PHY port status register, and the ++ * current speed (since there is no polarity at 100Mbps). ++ **/ ++s32 e1000_check_polarity_igp(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 data, offset, mask; ++ ++ DEBUGFUNC("e1000_check_polarity_igp"); ++ ++ /* ++ * Polarity is determined based on the speed of ++ * our connection. ++ */ ++ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); ++ if (ret_val) ++ goto out; ++ ++ if ((data & IGP01E1000_PSSR_SPEED_MASK) == ++ IGP01E1000_PSSR_SPEED_1000MBPS) { ++ offset = IGP01E1000_PHY_PCS_INIT_REG; ++ mask = IGP01E1000_PHY_POLARITY_MASK; ++ } else { ++ /* ++ * This really only applies to 10Mbps since ++ * there is no polarity for 100Mbps (always 0). ++ */ ++ offset = IGP01E1000_PHY_PORT_STATUS; ++ mask = IGP01E1000_PSSR_POLARITY_REVERSED; ++ } ++ ++ ret_val = phy->ops.read_reg(hw, offset, &data); ++ ++ if (!ret_val) ++ phy->cable_polarity = (data & mask) ++ ? e1000_rev_polarity_reversed ++ : e1000_rev_polarity_normal; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_wait_autoneg_generic - Wait for auto-neg completion ++ * @hw: pointer to the HW structure ++ * ++ * Waits for auto-negotiation to complete or for the auto-negotiation time ++ * limit to expire, which ever happens first. ++ **/ ++s32 e1000_wait_autoneg_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 i, phy_status; ++ ++ DEBUGFUNC("e1000_wait_autoneg_generic"); ++ ++ if (!(hw->phy.ops.read_reg)) ++ return E1000_SUCCESS; ++ ++ /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ ++ for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { ++ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); ++ if (ret_val) ++ break; ++ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); ++ if (ret_val) ++ break; ++ if (phy_status & MII_SR_AUTONEG_COMPLETE) ++ break; ++ msec_delay(100); ++ } ++ ++ /* ++ * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation ++ * has completed. ++ */ ++ return ret_val; ++} ++ ++/** ++ * e1000_phy_has_link_generic - Polls PHY for link ++ * @hw: pointer to the HW structure ++ * @iterations: number of times to poll for link ++ * @usec_interval: delay between polling attempts ++ * @success: pointer to whether polling was successful or not ++ * ++ * Polls the PHY status register for link, 'iterations' number of times. ++ **/ ++s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, ++ u32 usec_interval, bool *success) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 i, phy_status; ++ ++ DEBUGFUNC("e1000_phy_has_link_generic"); ++ ++ if (!(hw->phy.ops.read_reg)) ++ return E1000_SUCCESS; ++ ++ for (i = 0; i < iterations; i++) { ++ /* ++ * Some PHYs require the PHY_STATUS register to be read ++ * twice due to the link bit being sticky. No harm doing ++ * it across the board. ++ */ ++ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); ++ if (ret_val) ++ break; ++ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); ++ if (ret_val) ++ break; ++ if (phy_status & MII_SR_LINK_STATUS) ++ break; ++ if (usec_interval >= 1000) ++ msec_delay_irq(usec_interval/1000); ++ else ++ usec_delay(usec_interval); ++ } ++ ++ *success = (i < iterations) ? true : false; ++ ++ return ret_val; ++} ++ ++/** ++ * e1000_get_cable_length_m88 - Determine cable length for m88 PHY ++ * @hw: pointer to the HW structure ++ * ++ * Reads the PHY specific status register to retrieve the cable length ++ * information. The cable length is determined by averaging the minimum and ++ * maximum values to get the "average" cable length. The m88 PHY has four ++ * possible cable length values, which are: ++ * Register Value Cable Length ++ * 0 < 50 meters ++ * 1 50 - 80 meters ++ * 2 80 - 110 meters ++ * 3 110 - 140 meters ++ * 4 > 140 meters ++ **/ ++s32 e1000_get_cable_length_m88(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 phy_data, index; ++ ++ DEBUGFUNC("e1000_get_cable_length_m88"); ++ ++ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> ++ M88E1000_PSSR_CABLE_LENGTH_SHIFT; ++ phy->min_cable_length = e1000_m88_cable_length_table[index]; ++ phy->max_cable_length = e1000_m88_cable_length_table[index+1]; ++ ++ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY ++ * @hw: pointer to the HW structure ++ * ++ * The automatic gain control (agc) normalizes the amplitude of the ++ * received signal, adjusting for the attenuation produced by the ++ * cable. By reading the AGC registers, which represent the ++ * combination of coarse and fine gain value, the value can be put ++ * into a lookup table to obtain the approximate cable length ++ * for each channel. ++ **/ ++s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ u16 phy_data, i, agc_value = 0; ++ u16 cur_agc_index, max_agc_index = 0; ++ u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; ++ u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = ++ {IGP02E1000_PHY_AGC_A, ++ IGP02E1000_PHY_AGC_B, ++ IGP02E1000_PHY_AGC_C, ++ IGP02E1000_PHY_AGC_D}; ++ ++ DEBUGFUNC("e1000_get_cable_length_igp_2"); ++ ++ /* Read the AGC registers for all channels */ ++ for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { ++ ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data); ++ if (ret_val) ++ goto out; ++ ++ /* ++ * Getting bits 15:9, which represent the combination of ++ * coarse and fine gain values. The result is a number ++ * that can be put into the lookup table to obtain the ++ * approximate cable length. ++ */ ++ cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & ++ IGP02E1000_AGC_LENGTH_MASK; ++ ++ /* Array index bound check. */ ++ if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || ++ (cur_agc_index == 0)) { ++ ret_val = -E1000_ERR_PHY; ++ goto out; ++ } ++ ++ /* Remove min & max AGC values from calculation. */ ++ if (e1000_igp_2_cable_length_table[min_agc_index] > ++ e1000_igp_2_cable_length_table[cur_agc_index]) ++ min_agc_index = cur_agc_index; ++ if (e1000_igp_2_cable_length_table[max_agc_index] < ++ e1000_igp_2_cable_length_table[cur_agc_index]) ++ max_agc_index = cur_agc_index; ++ ++ agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; ++ } ++ ++ agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + ++ e1000_igp_2_cable_length_table[max_agc_index]); ++ agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); ++ ++ /* Calculate cable length with the error range of +/- 10 meters. */ ++ phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? ++ (agc_value - IGP02E1000_AGC_RANGE) : 0; ++ phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE; ++ ++ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_phy_info_m88 - Retrieve PHY information ++ * @hw: pointer to the HW structure ++ * ++ * Valid for only copper links. Read the PHY status register (sticky read) ++ * to verify that link is up. Read the PHY special control register to ++ * determine the polarity and 10base-T extended distance. Read the PHY ++ * special status register to determine MDI/MDIx and current speed. If ++ * speed is 1000, then determine cable length, local and remote receiver. ++ **/ ++s32 e1000_get_phy_info_m88(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 phy_data; ++ bool link; ++ ++ DEBUGFUNC("e1000_get_phy_info_m88"); ++ ++ if (hw->phy.media_type != e1000_media_type_copper) { ++ DEBUGOUT("Phy info is only valid for copper media\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); ++ if (ret_val) ++ goto out; ++ ++ if (!link) { ++ DEBUGOUT("Phy info is only valid if link is up\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) ++ ? true ++ : false; ++ ++ ret_val = e1000_check_polarity_m88(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false; ++ ++ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { ++ ret_val = hw->phy.ops.get_cable_length(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data); ++ if (ret_val) ++ goto out; ++ ++ phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) ++ ? e1000_1000t_rx_status_ok ++ : e1000_1000t_rx_status_not_ok; ++ ++ phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) ++ ? e1000_1000t_rx_status_ok ++ : e1000_1000t_rx_status_not_ok; ++ } else { ++ /* Set values to "undefined" */ ++ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; ++ phy->local_rx = e1000_1000t_rx_status_undefined; ++ phy->remote_rx = e1000_1000t_rx_status_undefined; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_phy_info_igp - Retrieve igp PHY information ++ * @hw: pointer to the HW structure ++ * ++ * Read PHY status to determine if link is up. If link is up, then ++ * set/determine 10base-T extended distance and polarity correction. Read ++ * PHY port status to determine MDI/MDIx and speed. Based on the speed, ++ * determine on the cable length, local and remote receiver. ++ **/ ++s32 e1000_get_phy_info_igp(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 data; ++ bool link; ++ ++ DEBUGFUNC("e1000_get_phy_info_igp"); ++ ++ ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); ++ if (ret_val) ++ goto out; ++ ++ if (!link) { ++ DEBUGOUT("Phy info is only valid if link is up\n"); ++ ret_val = -E1000_ERR_CONFIG; ++ goto out; ++ } ++ ++ phy->polarity_correction = true; ++ ++ ret_val = e1000_check_polarity_igp(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); ++ if (ret_val) ++ goto out; ++ ++ phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false; ++ ++ if ((data & IGP01E1000_PSSR_SPEED_MASK) == ++ IGP01E1000_PSSR_SPEED_1000MBPS) { ++ ret_val = hw->phy.ops.get_cable_length(hw); ++ if (ret_val) ++ goto out; ++ ++ ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data); ++ if (ret_val) ++ goto out; ++ ++ phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) ++ ? e1000_1000t_rx_status_ok ++ : e1000_1000t_rx_status_not_ok; ++ ++ phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) ++ ? e1000_1000t_rx_status_ok ++ : e1000_1000t_rx_status_not_ok; ++ } else { ++ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; ++ phy->local_rx = e1000_1000t_rx_status_undefined; ++ phy->remote_rx = e1000_1000t_rx_status_undefined; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_phy_sw_reset_generic - PHY software reset ++ * @hw: pointer to the HW structure ++ * ++ * Does a software reset of the PHY by reading the PHY control register and ++ * setting/write the control register reset bit to the PHY. ++ **/ ++s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw) ++{ ++ s32 ret_val = E1000_SUCCESS; ++ u16 phy_ctrl; ++ ++ DEBUGFUNC("e1000_phy_sw_reset_generic"); ++ ++ if (!(hw->phy.ops.read_reg)) ++ goto out; ++ ++ ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); ++ if (ret_val) ++ goto out; ++ ++ phy_ctrl |= MII_CR_RESET; ++ ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl); ++ if (ret_val) ++ goto out; ++ ++ usec_delay(1); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_phy_hw_reset_generic - PHY hardware reset ++ * @hw: pointer to the HW structure ++ * ++ * Verify the reset block is not blocking us from resetting. Acquire ++ * semaphore (if necessary) and read/set/write the device control reset ++ * bit in the PHY. Wait the appropriate delay time for the device to ++ * reset and release the semaphore (if necessary). ++ **/ ++s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw) ++{ ++ struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val = E1000_SUCCESS; ++ u32 ctrl; ++ ++ DEBUGFUNC("e1000_phy_hw_reset_generic"); ++ ++ ret_val = phy->ops.check_reset_block(hw); ++ if (ret_val) { ++ ret_val = E1000_SUCCESS; ++ goto out; ++ } ++ ++ ret_val = phy->ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ ctrl = E1000_READ_REG(hw, E1000_CTRL); ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST); ++ E1000_WRITE_FLUSH(hw); ++ ++ usec_delay(phy->reset_delay_us); ++ ++ E1000_WRITE_REG(hw, E1000_CTRL, ctrl); ++ E1000_WRITE_FLUSH(hw); ++ ++ usec_delay(150); ++ ++ phy->ops.release(hw); ++ ++ ret_val = phy->ops.get_cfg_done(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_cfg_done_generic - Generic configuration done ++ * @hw: pointer to the HW structure ++ * ++ * Generic function to wait 10 milli-seconds for configuration to complete ++ * and return success. ++ **/ ++s32 e1000_get_cfg_done_generic(struct e1000_hw *hw) ++{ ++ DEBUGFUNC("e1000_get_cfg_done_generic"); ++ ++ msec_delay_irq(10); ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_phy_init_script_igp3 - Inits the IGP3 PHY ++ * @hw: pointer to the HW structure ++ * ++ * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. ++ **/ ++s32 e1000_phy_init_script_igp3(struct e1000_hw *hw) ++{ ++ DEBUGOUT("Running IGP 3 PHY init script\n"); ++ ++ /* PHY init IGP 3 */ ++ /* Enable rise/fall, 10-mode work in class-A */ ++ hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018); ++ /* Remove all caps from Replica path filter */ ++ hw->phy.ops.write_reg(hw, 0x2F52, 0x0000); ++ /* Bias trimming for ADC, AFE and Driver (Default) */ ++ hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24); ++ /* Increase Hybrid poly bias */ ++ hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0); ++ /* Add 4% to Tx amplitude in Gig mode */ ++ hw->phy.ops.write_reg(hw, 0x2010, 0x10B0); ++ /* Disable trimming (TTT) */ ++ hw->phy.ops.write_reg(hw, 0x2011, 0x0000); ++ /* Poly DC correction to 94.6% + 2% for all channels */ ++ hw->phy.ops.write_reg(hw, 0x20DD, 0x249A); ++ /* ABS DC correction to 95.9% */ ++ hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3); ++ /* BG temp curve trim */ ++ hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE); ++ /* Increasing ADC OPAMP stage 1 currents to max */ ++ hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4); ++ /* Force 1000 ( required for enabling PHY regs configuration) */ ++ hw->phy.ops.write_reg(hw, 0x0000, 0x0140); ++ /* Set upd_freq to 6 */ ++ hw->phy.ops.write_reg(hw, 0x1F30, 0x1606); ++ /* Disable NPDFE */ ++ hw->phy.ops.write_reg(hw, 0x1F31, 0xB814); ++ /* Disable adaptive fixed FFE (Default) */ ++ hw->phy.ops.write_reg(hw, 0x1F35, 0x002A); ++ /* Enable FFE hysteresis */ ++ hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067); ++ /* Fixed FFE for short cable lengths */ ++ hw->phy.ops.write_reg(hw, 0x1F54, 0x0065); ++ /* Fixed FFE for medium cable lengths */ ++ hw->phy.ops.write_reg(hw, 0x1F55, 0x002A); ++ /* Fixed FFE for long cable lengths */ ++ hw->phy.ops.write_reg(hw, 0x1F56, 0x002A); ++ /* Enable Adaptive Clip Threshold */ ++ hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0); ++ /* AHT reset limit to 1 */ ++ hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF); ++ /* Set AHT master delay to 127 msec */ ++ hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC); ++ /* Set scan bits for AHT */ ++ hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF); ++ /* Set AHT Preset bits */ ++ hw->phy.ops.write_reg(hw, 0x1F79, 0x0210); ++ /* Change integ_factor of channel A to 3 */ ++ hw->phy.ops.write_reg(hw, 0x1895, 0x0003); ++ /* Change prop_factor of channels BCD to 8 */ ++ hw->phy.ops.write_reg(hw, 0x1796, 0x0008); ++ /* Change cg_icount + enable integbp for channels BCD */ ++ hw->phy.ops.write_reg(hw, 0x1798, 0xD008); ++ /* ++ * Change cg_icount + enable integbp + change prop_factor_master ++ * to 8 for channel A ++ */ ++ hw->phy.ops.write_reg(hw, 0x1898, 0xD918); ++ /* Disable AHT in Slave mode on channel A */ ++ hw->phy.ops.write_reg(hw, 0x187A, 0x0800); ++ /* ++ * Enable LPLU and disable AN to 1000 in non-D0a states, ++ * Enable SPD+B2B ++ */ ++ hw->phy.ops.write_reg(hw, 0x0019, 0x008D); ++ /* Enable restart AN on an1000_dis change */ ++ hw->phy.ops.write_reg(hw, 0x001B, 0x2080); ++ /* Enable wh_fifo read clock in 10/100 modes */ ++ hw->phy.ops.write_reg(hw, 0x0014, 0x0045); ++ /* Restart AN, Speed selection is 1000 */ ++ hw->phy.ops.write_reg(hw, 0x0000, 0x1340); ++ ++ return E1000_SUCCESS; ++} ++ ++/** ++ * e1000_get_phy_type_from_id - Get PHY type from id ++ * @phy_id: phy_id read from the phy ++ * ++ * Returns the phy type from the id. ++ **/ ++e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id) ++{ ++ e1000_phy_type phy_type = e1000_phy_unknown; ++ ++ switch (phy_id) { ++ case M88E1000_I_PHY_ID: ++ case M88E1000_E_PHY_ID: ++ case M88E1111_I_PHY_ID: ++ case M88E1011_I_PHY_ID: ++ phy_type = e1000_phy_m88; ++ break; ++ case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */ ++ phy_type = e1000_phy_igp_2; ++ break; ++ case GG82563_E_PHY_ID: ++ phy_type = e1000_phy_gg82563; ++ break; ++ case IGP03E1000_E_PHY_ID: ++ phy_type = e1000_phy_igp_3; ++ break; ++ case IFE_E_PHY_ID: ++ case IFE_PLUS_E_PHY_ID: ++ case IFE_C_E_PHY_ID: ++ phy_type = e1000_phy_ife; ++ break; ++ case BME1000_E_PHY_ID: ++ case BME1000_E_PHY_ID_R2: ++ phy_type = e1000_phy_bm; ++ break; ++ default: ++ phy_type = e1000_phy_unknown; ++ break; ++ } ++ return phy_type; ++} ++ ++/** ++ * e1000_determine_phy_address - Determines PHY address. ++ * @hw: pointer to the HW structure ++ * ++ * This uses a trial and error method to loop through possible PHY ++ * addresses. It tests each by reading the PHY ID registers and ++ * checking for a match. ++ **/ ++s32 e1000_determine_phy_address(struct e1000_hw* hw) ++{ ++ s32 ret_val = -E1000_ERR_PHY_TYPE; ++ u32 phy_addr= 0; ++ u32 i; ++ e1000_phy_type phy_type = e1000_phy_unknown; ++ ++ for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) { ++ hw->phy.addr = phy_addr; ++ i = 0; ++ ++ do { ++ e1000_get_phy_id(hw); ++ phy_type = e1000_get_phy_type_from_id(hw->phy.id); ++ ++ /* ++ * If phy_type is valid, break - we found our ++ * PHY address ++ */ ++ if (phy_type != e1000_phy_unknown) { ++ ret_val = E1000_SUCCESS; ++ goto out; ++ } ++ msec_delay(1); ++ i++; ++ } while (i < 10); ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_get_phy_addr_for_bm_page - Retrieve PHY page address ++ * @page: page to access ++ * ++ * Returns the phy address for the page requested. ++ **/ ++static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg) ++{ ++ u32 phy_addr = 2; ++ ++ if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31)) ++ phy_addr = 1; ++ ++ return phy_addr; ++} ++ ++/** ++ * e1000_write_phy_reg_bm - Write BM PHY register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to write to ++ * @data: data to write at register offset ++ * ++ * Acquires semaphore, if necessary, then writes the data to PHY register ++ * at the offset. Release any acquired semaphores before exiting. ++ **/ ++s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data) ++{ ++ s32 ret_val; ++ u32 page_select = 0; ++ u32 page = offset >> IGP_PAGE_SHIFT; ++ u32 page_shift = 0; ++ ++ DEBUGFUNC("e1000_write_phy_reg_bm"); ++ ++ /* Page 800 works differently than the rest so it has its own func */ ++ if (page == BM_WUC_PAGE) { ++ ret_val = e1000_access_phy_wakeup_reg_bm(hw, ++ offset, &data, false); ++ goto out; ++ } ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset); ++ ++ if (offset > MAX_PHY_MULTI_PAGE_REG) { ++ /* ++ * Page select is register 31 for phy address 1 and 22 for ++ * phy address 2 and 3. Page select is shifted only for ++ * phy address 1. ++ */ ++ if (hw->phy.addr == 1) { ++ page_shift = IGP_PAGE_SHIFT; ++ page_select = IGP01E1000_PHY_PAGE_SELECT; ++ } else { ++ page_shift = 0; ++ page_select = BM_PHY_PAGE_SELECT; ++ } ++ ++ /* Page is shifted left, PHY expects (page x 32) */ ++ ret_val = e1000_write_phy_reg_mdic(hw, page_select, ++ (page << page_shift)); ++ if (ret_val) { ++ hw->phy.ops.release(hw); ++ goto out; ++ } ++ } ++ ++ ret_val = e1000_write_phy_reg_mdic(hw, ++ MAX_PHY_REG_ADDRESS & offset, ++ data); ++ ++ hw->phy.ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_phy_reg_bm - Read BM PHY register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to be read ++ * @data: pointer to the read data ++ * ++ * Acquires semaphore, if necessary, then reads the PHY register at offset ++ * and storing the retrieved information in data. Release any acquired ++ * semaphores before exiting. ++ **/ ++s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data) ++{ ++ s32 ret_val; ++ u32 page_select = 0; ++ u32 page = offset >> IGP_PAGE_SHIFT; ++ u32 page_shift = 0; ++ ++ DEBUGFUNC("e1000_read_phy_reg_bm"); ++ ++ /* Page 800 works differently than the rest so it has its own func */ ++ if (page == BM_WUC_PAGE) { ++ ret_val = e1000_access_phy_wakeup_reg_bm(hw, ++ offset, data, true); ++ goto out; ++ } ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset); ++ ++ if (offset > MAX_PHY_MULTI_PAGE_REG) { ++ /* ++ * Page select is register 31 for phy address 1 and 22 for ++ * phy address 2 and 3. Page select is shifted only for ++ * phy address 1. ++ */ ++ if (hw->phy.addr == 1) { ++ page_shift = IGP_PAGE_SHIFT; ++ page_select = IGP01E1000_PHY_PAGE_SELECT; ++ } else { ++ page_shift = 0; ++ page_select = BM_PHY_PAGE_SELECT; ++ } ++ ++ /* Page is shifted left, PHY expects (page x 32) */ ++ ret_val = e1000_write_phy_reg_mdic(hw, page_select, ++ (page << page_shift)); ++ if (ret_val) { ++ hw->phy.ops.release(hw); ++ goto out; ++ } ++ } ++ ++ ret_val = e1000_read_phy_reg_mdic(hw, ++ MAX_PHY_REG_ADDRESS & offset, ++ data); ++ hw->phy.ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_read_phy_reg_bm2 - Read BM PHY register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to be read ++ * @data: pointer to the read data ++ * ++ * Acquires semaphore, if necessary, then reads the PHY register at offset ++ * and storing the retrieved information in data. Release any acquired ++ * semaphores before exiting. ++ **/ ++s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) ++{ ++ s32 ret_val; ++ u16 page = (u16)(offset >> IGP_PAGE_SHIFT); ++ ++ DEBUGFUNC("e1000_write_phy_reg_bm2"); ++ ++ /* Page 800 works differently than the rest so it has its own func */ ++ if (page == BM_WUC_PAGE) { ++ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, ++ true); ++ goto out; ++ } ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ hw->phy.addr = 1; ++ ++ if (offset > MAX_PHY_MULTI_PAGE_REG) { ++ ++ /* Page is shifted left, PHY expects (page x 32) */ ++ ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, ++ page); ++ ++ if (ret_val) { ++ hw->phy.ops.release(hw); ++ goto out; ++ } ++ } ++ ++ ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, ++ data); ++ hw->phy.ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_write_phy_reg_bm2 - Write BM PHY register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to write to ++ * @data: data to write at register offset ++ * ++ * Acquires semaphore, if necessary, then writes the data to PHY register ++ * at the offset. Release any acquired semaphores before exiting. ++ **/ ++s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) ++{ ++ s32 ret_val; ++ u16 page = (u16)(offset >> IGP_PAGE_SHIFT); ++ ++ DEBUGFUNC("e1000_write_phy_reg_bm2"); ++ ++ /* Page 800 works differently than the rest so it has its own func */ ++ if (page == BM_WUC_PAGE) { ++ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, ++ false); ++ goto out; ++ } ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) ++ goto out; ++ ++ hw->phy.addr = 1; ++ ++ if (offset > MAX_PHY_MULTI_PAGE_REG) { ++ /* Page is shifted left, PHY expects (page x 32) */ ++ ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, ++ page); ++ ++ if (ret_val) { ++ hw->phy.ops.release(hw); ++ goto out; ++ } ++ } ++ ++ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, ++ data); ++ ++ hw->phy.ops.release(hw); ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to be read or written ++ * @data: pointer to the data to read or write ++ * @read: determines if operation is read or write ++ * ++ * Acquires semaphore, if necessary, then reads the PHY register at offset ++ * and storing the retrieved information in data. Release any acquired ++ * semaphores before exiting. Note that procedure to read the wakeup ++ * registers are different. It works as such: ++ * 1) Set page 769, register 17, bit 2 = 1 ++ * 2) Set page to 800 for host (801 if we were manageability) ++ * 3) Write the address using the address opcode (0x11) ++ * 4) Read or write the data using the data opcode (0x12) ++ * 5) Restore 769_17.2 to its original value ++ **/ ++s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, ++ u32 offset, u16 *data, bool read) ++{ ++ s32 ret_val; ++ u16 reg = ((u16)offset); ++ u16 phy_reg = 0; ++ u8 phy_acquired = 1; ++ ++ DEBUGFUNC("e1000_read_phy_wakeup_reg_bm"); ++ ++ ret_val = hw->phy.ops.acquire(hw); ++ if (ret_val) { ++ DEBUGOUT("Could not acquire PHY\n"); ++ phy_acquired = 0; ++ goto out; ++ } ++ ++ /* All operations in this function are phy address 1 */ ++ hw->phy.addr = 1; ++ ++ /* Set page 769 */ ++ e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, ++ (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); ++ ++ ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg); ++ if (ret_val) { ++ DEBUGOUT("Could not read PHY page 769\n"); ++ goto out; ++ } ++ ++ /* First clear bit 4 to avoid a power state change */ ++ phy_reg &= ~(BM_WUC_HOST_WU_BIT); ++ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); ++ if (ret_val) { ++ DEBUGOUT("Could not clear PHY page 769 bit 4\n"); ++ goto out; ++ } ++ ++ /* Write bit 2 = 1, and clear bit 4 to 769_17 */ ++ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, ++ phy_reg | BM_WUC_ENABLE_BIT); ++ if (ret_val) { ++ DEBUGOUT("Could not write PHY page 769 bit 2\n"); ++ goto out; ++ } ++ ++ /* Select page 800 */ ++ ret_val = e1000_write_phy_reg_mdic(hw, ++ IGP01E1000_PHY_PAGE_SELECT, ++ (BM_WUC_PAGE << IGP_PAGE_SHIFT)); ++ ++ /* Write the page 800 offset value using opcode 0x11 */ ++ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg); ++ if (ret_val) { ++ DEBUGOUT("Could not write address opcode to page 800\n"); ++ goto out; ++ } ++ ++ if (read) { ++ /* Read the page 800 value using opcode 0x12 */ ++ ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE, ++ data); ++ } else { ++ /* Read the page 800 value using opcode 0x12 */ ++ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE, ++ *data); ++ } ++ ++ if (ret_val) { ++ DEBUGOUT("Could not read data value from page 800\n"); ++ goto out; ++ } ++ ++ /* ++ * Restore 769_17.2 to its original value ++ * Set page 769 ++ */ ++ e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, ++ (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); ++ ++ /* Clear 769_17.2 */ ++ ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); ++ if (ret_val) { ++ DEBUGOUT("Could not clear PHY page 769 bit 2\n"); ++ goto out; ++ } ++ ++out: ++ if (phy_acquired == 1) ++ hw->phy.ops.release(hw); ++ return ret_val; ++} ++ ++/** ++ * e1000_power_up_phy_copper - Restore copper link in case of PHY power down ++ * @hw: pointer to the HW structure ++ * ++ * In the case of a PHY power down to save power, or to turn off link during a ++ * driver unload, or wake on lan is not enabled, restore the link to previous ++ * settings. ++ **/ ++void e1000_power_up_phy_copper(struct e1000_hw *hw) ++{ ++ u16 mii_reg = 0; ++ ++ /* The PHY will retain its settings across a power down/up cycle */ ++ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); ++ mii_reg &= ~MII_CR_POWER_DOWN; ++ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); ++} ++ ++/** ++ * e1000_power_down_phy_copper - Restore copper link in case of PHY power down ++ * @hw: pointer to the HW structure ++ * ++ * In the case of a PHY power down to save power, or to turn off link during a ++ * driver unload, or wake on lan is not enabled, restore the link to previous ++ * settings. ++ **/ ++void e1000_power_down_phy_copper(struct e1000_hw *hw) ++{ ++ u16 mii_reg = 0; ++ ++ /* The PHY will retain its settings across a power down/up cycle */ ++ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); ++ mii_reg |= MII_CR_POWER_DOWN; ++ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); ++ msec_delay(1); ++} +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_phy.h linux-2.6.22-10/drivers/net/e1000e/e1000_phy.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_phy.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_phy.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,190 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _E1000_PHY_H_ ++#define _E1000_PHY_H_ ++ ++typedef enum { ++ e1000_ms_hw_default = 0, ++ e1000_ms_force_master, ++ e1000_ms_force_slave, ++ e1000_ms_auto ++} e1000_ms_type; ++ ++typedef enum { ++ e1000_smart_speed_default = 0, ++ e1000_smart_speed_on, ++ e1000_smart_speed_off ++} e1000_smart_speed; ++ ++void e1000_init_phy_ops_generic(struct e1000_hw *hw); ++s32 e1000_check_downshift_generic(struct e1000_hw *hw); ++s32 e1000_check_polarity_m88(struct e1000_hw *hw); ++s32 e1000_check_polarity_igp(struct e1000_hw *hw); ++s32 e1000_check_reset_block_generic(struct e1000_hw *hw); ++s32 e1000_copper_link_autoneg(struct e1000_hw *hw); ++s32 e1000_copper_link_setup_igp(struct e1000_hw *hw); ++s32 e1000_copper_link_setup_m88(struct e1000_hw *hw); ++s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw); ++s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw); ++s32 e1000_get_cable_length_m88(struct e1000_hw *hw); ++s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw); ++s32 e1000_get_cfg_done_generic(struct e1000_hw *hw); ++s32 e1000_get_phy_id(struct e1000_hw *hw); ++s32 e1000_get_phy_info_igp(struct e1000_hw *hw); ++s32 e1000_get_phy_info_m88(struct e1000_hw *hw); ++s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw); ++void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); ++s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw); ++s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw); ++s32 e1000_phy_setup_autoneg(struct e1000_hw *hw); ++s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data); ++s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); ++s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); ++s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active); ++s32 e1000_setup_copper_link_generic(struct e1000_hw *hw); ++s32 e1000_wait_autoneg_generic(struct e1000_hw *hw); ++s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data); ++s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); ++s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); ++s32 e1000_phy_reset_dsp(struct e1000_hw *hw); ++s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, ++ u32 usec_interval, bool *success); ++s32 e1000_phy_init_script_igp3(struct e1000_hw *hw); ++e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id); ++s32 e1000_determine_phy_address(struct e1000_hw* hw); ++s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data); ++s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data); ++s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data, ++ bool read); ++s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data); ++s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data); ++void e1000_power_up_phy_copper(struct e1000_hw *hw); ++void e1000_power_down_phy_copper(struct e1000_hw *hw); ++s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); ++s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); ++ ++#define E1000_MAX_PHY_ADDR 4 ++ ++/* IGP01E1000 Specific Registers */ ++#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ ++#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */ ++#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */ ++#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */ ++#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO */ ++#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality */ ++#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */ ++#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */ ++#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */ ++#define IGP_PAGE_SHIFT 5 ++#define PHY_REG_MASK 0x1F ++ ++#define BM_WUC_PAGE 800 ++#define BM_WUC_ADDRESS_OPCODE 0x11 ++#define BM_WUC_DATA_OPCODE 0x12 ++#define BM_WUC_ENABLE_PAGE 769 ++#define BM_WUC_ENABLE_REG 17 ++#define BM_WUC_ENABLE_BIT (1 << 2) ++#define BM_WUC_HOST_WU_BIT (1 << 4) ++ ++/* BM PHY Copper Specific Control 1 */ ++#define BM_CS_CTRL1 16 ++#define BM_CS_CTRL1_ENERGY_DETECT 0x0300 /* Enable Energy Detect */ ++ ++/* BM PHY Copper Specific States */ ++#define BM_CS_STATUS 17 ++#define BM_CS_STATUS_ENERGY_DETECT 0x0010 /* Energy Detect Status */ ++ ++#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 ++#define IGP01E1000_PHY_POLARITY_MASK 0x0078 ++ ++#define IGP01E1000_PSCR_AUTO_MDIX 0x1000 ++#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */ ++ ++#define IGP01E1000_PSCFR_SMART_SPEED 0x0080 ++ ++/* Enable flexible speed on link-up */ ++#define IGP01E1000_GMII_FLEX_SPD 0x0010 ++#define IGP01E1000_GMII_SPD 0x0020 /* Enable SPD */ ++ ++#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */ ++#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */ ++#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ ++ ++#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 ++ ++#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 ++#define IGP01E1000_PSSR_MDIX 0x0008 ++#define IGP01E1000_PSSR_SPEED_MASK 0xC000 ++#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 ++ ++#define IGP02E1000_PHY_CHANNEL_NUM 4 ++#define IGP02E1000_PHY_AGC_A 0x11B1 ++#define IGP02E1000_PHY_AGC_B 0x12B1 ++#define IGP02E1000_PHY_AGC_C 0x14B1 ++#define IGP02E1000_PHY_AGC_D 0x18B1 ++ ++#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */ ++#define IGP02E1000_AGC_LENGTH_MASK 0x7F ++#define IGP02E1000_AGC_RANGE 15 ++ ++#define IGP03E1000_PHY_MISC_CTRL 0x1B ++#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Manually Set Duplex */ ++ ++#define E1000_CABLE_LENGTH_UNDEFINED 0xFF ++ ++#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000 ++#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16 ++#define E1000_KMRNCTRLSTA_REN 0x00200000 ++#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */ ++#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ ++ ++#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 ++#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ ++#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */ ++#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */ ++ ++/* IFE PHY Extended Status Control */ ++#define IFE_PESC_POLARITY_REVERSED 0x0100 ++ ++/* IFE PHY Special Control */ ++#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 ++#define IFE_PSC_FORCE_POLARITY 0x0020 ++#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 ++ ++/* IFE PHY Special Control and LED Control */ ++#define IFE_PSCL_PROBE_MODE 0x0020 ++#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */ ++#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */ ++ ++/* IFE PHY MDIX Control */ ++#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */ ++#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */ ++#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */ ++ ++#endif +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/e1000_regs.h linux-2.6.22-10/drivers/net/e1000e/e1000_regs.h +--- linux-2.6.22-0/drivers/net/e1000e/e1000_regs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/e1000_regs.h 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,310 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _E1000_REGS_H_ ++#define _E1000_REGS_H_ ++ ++#define E1000_CTRL 0x00000 /* Device Control - RW */ ++#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */ ++#define E1000_STATUS 0x00008 /* Device Status - RO */ ++#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ ++#define E1000_EERD 0x00014 /* EEPROM Read - RW */ ++#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ ++#define E1000_FLA 0x0001C /* Flash Access - RW */ ++#define E1000_MDIC 0x00020 /* MDI Control - RW */ ++#define E1000_SCTL 0x00024 /* SerDes Control - RW */ ++#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ ++#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ ++#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ ++#define E1000_FCT 0x00030 /* Flow Control Type - RW */ ++#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ ++#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ ++#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ ++#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ ++#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ ++#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ ++#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ ++#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ ++#define E1000_IVAR 0x000E4 /* Interrupt Vector Allocation Register - RW */ ++#define E1000_RCTL 0x00100 /* Rx Control - 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 */ ++#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */ ++#define E1000_EITR(_n) (0x01680 + (0x4 * (_n))) ++#define E1000_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */ ++#define E1000_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */ ++#define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */ ++#define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */ ++#define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */ ++#define E1000_TCTL 0x00400 /* Tx Control - RW */ ++#define E1000_TCTL_EXT 0x00404 /* Extended Tx Control - RW */ ++#define E1000_TIPG 0x00410 /* Tx Inter-packet gap -RW */ ++#define E1000_TBT 0x00448 /* Tx Burst Timer - RW */ ++#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ ++#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ ++#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */ ++#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */ ++#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */ ++#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ ++#define E1000_PBS 0x01008 /* Packet Buffer Size */ ++#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ ++#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */ ++#define E1000_FLASHT 0x01028 /* FLASH Timer Register */ ++#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */ ++#define E1000_FLSWCTL 0x01030 /* FLASH control register */ ++#define E1000_FLSWDATA 0x01034 /* FLASH data register */ ++#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */ ++#define E1000_FLOP 0x0103C /* FLASH Opcode Register */ ++#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */ ++#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */ ++#define E1000_WDSTP 0x01040 /* Watchdog Setup - RW */ ++#define E1000_SWDSTS 0x01044 /* SW Device Status - RW */ ++#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */ ++#define E1000_TCPTIMER 0x0104C /* TCP Timer - RW */ ++#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ ++#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ ++#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ ++#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */ ++#define E1000_RDFPCQ(_n) (0x02430 + (0x4 * (_n))) ++#define E1000_PBRTH 0x02458 /* PB Rx Arbitration Threshold - RW */ ++#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */ ++/* Split and Replication Rx Control - RW */ ++#define E1000_RDPUMB 0x025CC /* DMA Rx Descriptor uC Mailbox - RW */ ++#define E1000_RDPUAD 0x025D0 /* DMA Rx Descriptor uC Addr Command - RW */ ++#define E1000_RDPUWD 0x025D4 /* DMA Rx Descriptor uC Data Write - RW */ ++#define E1000_RDPURD 0x025D8 /* DMA Rx Descriptor uC Data Read - RW */ ++#define E1000_RDPUCTL 0x025DC /* DMA Rx Descriptor uC Control - RW */ ++#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */ ++#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */ ++/* ++ * Convenience macros ++ * ++ * Note: "_n" is the queue number of the register to be written to. ++ * ++ * Example usage: ++ * E1000_RDBAL_REG(current_rx_queue) ++ */ ++#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : (0x0C000 + ((_n) * 0x40))) ++#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : (0x0C004 + ((_n) * 0x40))) ++#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : (0x0C008 + ((_n) * 0x40))) ++#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : (0x0C00C + ((_n) * 0x40))) ++#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : (0x0C010 + ((_n) * 0x40))) ++#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : (0x0C018 + ((_n) * 0x40))) ++#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : (0x0C028 + ((_n) * 0x40))) ++#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : (0x0E000 + ((_n) * 0x40))) ++#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : (0x0E004 + ((_n) * 0x40))) ++#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : (0x0E008 + ((_n) * 0x40))) ++#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : (0x0E010 + ((_n) * 0x40))) ++#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : (0x0E018 + ((_n) * 0x40))) ++#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : (0x0E028 + ((_n) * 0x40))) ++#define E1000_TARC(_n) (0x03840 + (_n << 8)) ++#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8)) ++#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8)) ++#define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : (0x0E038 + ((_n) * 0x40))) ++#define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : (0x0E03C + ((_n) * 0x40))) ++#define E1000_RSRPD 0x02C00 /* Rx Small Packet Detect - RW */ ++#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ ++#define E1000_TXDMAC 0x03000 /* Tx DMA Control - RW */ ++#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */ ++#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4)) ++#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : (0x054E0 + ((_i - 16) * 8))) ++#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : (0x054E4 + ((_i - 16) * 8))) ++#define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8)) ++#define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4)) ++#define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4)) ++#define E1000_FFMT_REG(_i) (0x09000 + ((_i) * 8)) ++#define E1000_FFVT_REG(_i) (0x09800 + ((_i) * 8)) ++#define E1000_FFLT_REG(_i) (0x05F00 + ((_i) * 8)) ++#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */ ++#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */ ++#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */ ++#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */ ++#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */ ++#define E1000_TDPUMB 0x0357C /* DMA Tx Descriptor uC Mail Box - RW */ ++#define E1000_TDPUAD 0x03580 /* DMA Tx Descriptor uC Addr Command - RW */ ++#define E1000_TDPUWD 0x03584 /* DMA Tx Descriptor uC Data Write - RW */ ++#define E1000_TDPURD 0x03588 /* DMA Tx Descriptor uC Data Read - RW */ ++#define E1000_TDPUCTL 0x0358C /* DMA Tx Descriptor uC Control - RW */ ++#define E1000_DTXCTL 0x03590 /* DMA Tx Control - RW */ ++#define E1000_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */ ++#define E1000_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */ ++#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ ++#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ ++#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ ++#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ ++#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ ++#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ ++#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ ++#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ ++#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ ++#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ ++#define E1000_COLC 0x04028 /* Collision Count - R/clr */ ++#define E1000_DC 0x04030 /* Defer Count - R/clr */ ++#define E1000_TNCRS 0x04034 /* Tx-No CRS - R/clr */ ++#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ ++#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ ++#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ ++#define E1000_XONRXC 0x04048 /* XON Rx Count - R/clr */ ++#define E1000_XONTXC 0x0404C /* XON Tx Count - R/clr */ ++#define E1000_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */ ++#define E1000_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */ ++#define E1000_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */ ++#define E1000_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */ ++#define E1000_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */ ++#define E1000_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */ ++#define E1000_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */ ++#define E1000_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */ ++#define E1000_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */ ++#define E1000_GPRC 0x04074 /* Good Packets Rx Count - R/clr */ ++#define E1000_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */ ++#define E1000_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */ ++#define E1000_GPTC 0x04080 /* Good Packets Tx Count - R/clr */ ++#define E1000_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */ ++#define E1000_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */ ++#define E1000_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */ ++#define E1000_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */ ++#define E1000_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */ ++#define E1000_RUC 0x040A4 /* Rx Undersize Count - R/clr */ ++#define E1000_RFC 0x040A8 /* Rx Fragment Count - R/clr */ ++#define E1000_ROC 0x040AC /* Rx Oversize Count - R/clr */ ++#define E1000_RJC 0x040B0 /* Rx Jabber Count - R/clr */ ++#define E1000_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */ ++#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ ++#define E1000_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */ ++#define E1000_TORL 0x040C0 /* Total Octets Rx Low - R/clr */ ++#define E1000_TORH 0x040C4 /* Total Octets Rx High - R/clr */ ++#define E1000_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */ ++#define E1000_TOTH 0x040CC /* Total Octets Tx High - R/clr */ ++#define E1000_TPR 0x040D0 /* Total Packets Rx - R/clr */ ++#define E1000_TPT 0x040D4 /* Total Packets Tx - R/clr */ ++#define E1000_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */ ++#define E1000_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */ ++#define E1000_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */ ++#define E1000_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */ ++#define E1000_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */ ++#define E1000_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */ ++#define E1000_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */ ++#define E1000_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */ ++#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */ ++#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */ ++#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ ++#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */ ++#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */ ++#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */ ++#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */ ++#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ ++#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ ++#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ ++#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ ++ ++#define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */ ++#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */ ++#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */ ++#define E1000_CBTMPC 0x0402C /* Circuit Breaker Tx Packet Count */ ++#define E1000_HTDPMC 0x0403C /* Host Transmit Discarded Packets */ ++#define E1000_CBRDPC 0x04044 /* Circuit Breaker Rx Dropped Count */ ++#define E1000_CBRMPC 0x040FC /* Circuit Breaker Rx Packet Count */ ++#define E1000_RPTHC 0x04104 /* Rx Packets To Host */ ++#define E1000_HGPTC 0x04118 /* Host Good Packets Tx Count */ ++#define E1000_HTCBDPC 0x04124 /* Host Tx Circuit Breaker Dropped Count */ ++#define E1000_HGORCL 0x04128 /* Host Good Octets Received Count Low */ ++#define E1000_HGORCH 0x0412C /* Host Good Octets Received Count High */ ++#define E1000_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */ ++#define E1000_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */ ++#define E1000_LENERRS 0x04138 /* Length Errors Count */ ++#define E1000_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */ ++#define E1000_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */ ++#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */ ++#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */ ++#define E1000_PCS_NPTX 0x04220 /* AN Next Page Transmit - RW */ ++#define E1000_PCS_LPABNP 0x04224 /* Link Partner Ability Next Page - RW */ ++#define E1000_1GSTAT_RCV 0x04228 /* 1GSTAT Code Violation Packet Count - RW */ ++#define E1000_RXCSUM 0x05000 /* Rx Checksum Control - RW */ ++#define E1000_RLPML 0x05004 /* Rx Long Packet Max Length */ ++#define E1000_RFCTL 0x05008 /* Receive Filter Control*/ ++#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ ++#define E1000_RA 0x05400 /* Receive Address - RW Array */ ++#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ ++#define E1000_VMD_CTL 0x0581C /* VMDq Control - RW */ ++#define E1000_VFQA0 0x0B000 /* VLAN Filter Queue Array 0 - RW Array */ ++#define E1000_VFQA1 0x0B200 /* VLAN Filter Queue Array 1 - RW Array */ ++#define E1000_WUC 0x05800 /* Wakeup Control - RW */ ++#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ ++#define E1000_WUS 0x05810 /* Wakeup Status - RO */ ++#define E1000_MANC 0x05820 /* Management Control - RW */ ++#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ ++#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ ++#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ ++#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ ++#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ ++#define E1000_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */ ++#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ ++#define E1000_HOST_IF 0x08800 /* Host Interface */ ++#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ ++#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ ++ ++#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */ ++#define E1000_MDPHYA 0x0003C /* PHY address - RW */ ++#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ ++#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ ++#define E1000_CCMCTL 0x05B48 /* CCM Control Register */ ++#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ ++#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */ ++#define E1000_GCR 0x05B00 /* PCI-Ex Control */ ++#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ ++#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ ++#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */ ++#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */ ++#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ ++#define E1000_SWSM 0x05B50 /* SW Semaphore */ ++#define E1000_FWSM 0x05B54 /* FW Semaphore */ ++#define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */ ++#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */ ++#define E1000_FFLT_DBG 0x05F04 /* Debug Register */ ++#define E1000_HICR 0x08F00 /* Host Interface Control */ ++ ++/* RSS registers */ ++#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ ++#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ ++#define E1000_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */ ++#define E1000_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate Interrupt Ext*/ ++#define E1000_IMIRVP 0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */ ++#define E1000_MSIXBM(_i) (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register (_i) - RW */ ++#define E1000_MSIXTADD(_i) (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr low reg 0 - RW */ ++#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr upper reg 0 - RW */ ++#define E1000_MSIXTMSG(_i) (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry message reg 0 - RW */ ++#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry vector ctrl reg 0 - RW */ ++#define E1000_MSIXPBA 0x0E000 /* MSI-X Pending bit array */ ++#define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) /* Redirection Table - RW Array */ ++#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW Array */ ++#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ ++#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ ++#define E1000_RXMTRL 0x0B634 /* Time sync Rx EtherType and Message Type - RW */ ++#define E1000_RXUDP 0x0B638 /* Time Sync Rx UDP Port - RW */ ++#endif +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/ethtool.c linux-2.6.22-10/drivers/net/e1000e/ethtool.c +--- linux-2.6.22-0/drivers/net/e1000e/ethtool.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/ethtool.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,2005 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++/* ethtool support for e1000 */ ++ ++#include ++#ifdef SIOCETHTOOL ++#include ++#include ++#include ++ ++#include "e1000.h" ++#ifdef NETIF_F_HW_VLAN_TX ++#include ++#endif ++ ++#ifdef ETHTOOL_OPS_COMPAT ++#include "kcompat_ethtool.c" ++#endif ++ ++struct e1000_stats { ++ char stat_string[ETH_GSTRING_LEN]; ++ int sizeof_stat; ++ int stat_offset; ++}; ++ ++#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \ ++ offsetof(struct e1000_adapter, m) ++static const struct e1000_stats e1000_gstrings_stats[] = { ++ { "rx_packets", E1000_STAT(stats.gprc) }, ++ { "tx_packets", E1000_STAT(stats.gptc) }, ++ { "rx_bytes", E1000_STAT(stats.gorc) }, ++ { "tx_bytes", E1000_STAT(stats.gotc) }, ++ { "rx_broadcast", E1000_STAT(stats.bprc) }, ++ { "tx_broadcast", E1000_STAT(stats.bptc) }, ++ { "rx_multicast", E1000_STAT(stats.mprc) }, ++ { "tx_multicast", E1000_STAT(stats.mptc) }, ++ { "rx_errors", E1000_STAT(net_stats.rx_errors) }, ++ { "tx_errors", E1000_STAT(net_stats.tx_errors) }, ++ { "tx_dropped", E1000_STAT(net_stats.tx_dropped) }, ++ { "multicast", E1000_STAT(stats.mprc) }, ++ { "collisions", E1000_STAT(stats.colc) }, ++ { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) }, ++ { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) }, ++ { "rx_crc_errors", E1000_STAT(stats.crcerrs) }, ++ { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) }, ++ { "rx_no_buffer_count", E1000_STAT(stats.rnbc) }, ++ { "rx_missed_errors", E1000_STAT(stats.mpc) }, ++ { "tx_aborted_errors", E1000_STAT(stats.ecol) }, ++ { "tx_carrier_errors", E1000_STAT(stats.tncrs) }, ++ { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) }, ++ { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) }, ++ { "tx_window_errors", E1000_STAT(stats.latecol) }, ++ { "tx_abort_late_coll", E1000_STAT(stats.latecol) }, ++ { "tx_deferred_ok", E1000_STAT(stats.dc) }, ++ { "tx_single_coll_ok", E1000_STAT(stats.scc) }, ++ { "tx_multi_coll_ok", E1000_STAT(stats.mcc) }, ++ { "tx_timeout_count", E1000_STAT(tx_timeout_count) }, ++ { "tx_restart_queue", E1000_STAT(restart_queue) }, ++ { "rx_long_length_errors", E1000_STAT(stats.roc) }, ++ { "rx_short_length_errors", E1000_STAT(stats.ruc) }, ++ { "rx_align_errors", E1000_STAT(stats.algnerrc) }, ++ { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) }, ++ { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) }, ++ { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) }, ++ { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, ++ { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, ++ { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, ++ { "rx_long_byte_count", E1000_STAT(stats.gorc) }, ++ { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, ++ { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, ++ { "rx_header_split", E1000_STAT(rx_hdr_split) }, ++ { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, ++ { "tx_smbus", E1000_STAT(stats.mgptc) }, ++ { "rx_smbus", E1000_STAT(stats.mgprc) }, ++ { "dropped_smbus", E1000_STAT(stats.mgpdc) }, ++ { "rx_dma_failed", E1000_STAT(rx_dma_failed) }, ++ { "tx_dma_failed", E1000_STAT(tx_dma_failed) }, ++}; ++ ++#define E1000_GLOBAL_STATS_LEN \ ++ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) ++#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN) ++static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { ++ "Register test (offline)", "Eeprom test (offline)", ++ "Interrupt test (offline)", "Loopback test (offline)", ++ "Link test (on/offline)" ++}; ++#define E1000_TEST_LEN ARRAY_SIZE(e1000_gstrings_test) ++ ++static int e1000_get_settings(struct net_device *netdev, ++ struct ethtool_cmd *ecmd) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 status; ++ ++ if (hw->phy.media_type == e1000_media_type_copper) { ++ ++ ecmd->supported = (SUPPORTED_10baseT_Half | ++ SUPPORTED_10baseT_Full | ++ SUPPORTED_100baseT_Half | ++ SUPPORTED_100baseT_Full | ++ SUPPORTED_1000baseT_Full | ++ SUPPORTED_Autoneg | ++ SUPPORTED_TP); ++ if (hw->phy.type == e1000_phy_ife) ++ ecmd->supported &= ~SUPPORTED_1000baseT_Full; ++ ecmd->advertising = ADVERTISED_TP; ++ ++ if (hw->mac.autoneg == 1) { ++ ecmd->advertising |= ADVERTISED_Autoneg; ++ /* the e1000 autoneg seems to match ethtool nicely */ ++ ecmd->advertising |= hw->phy.autoneg_advertised; ++ } ++ ++ ecmd->port = PORT_TP; ++ ecmd->phy_address = hw->phy.addr; ++ ecmd->transceiver = XCVR_INTERNAL; ++ ++ } else { ++ ecmd->supported = (SUPPORTED_1000baseT_Full | ++ SUPPORTED_FIBRE | ++ SUPPORTED_Autoneg); ++ ++ ecmd->advertising = (ADVERTISED_1000baseT_Full | ++ ADVERTISED_FIBRE | ++ ADVERTISED_Autoneg); ++ ++ ecmd->port = PORT_FIBRE; ++ ecmd->transceiver = XCVR_EXTERNAL; ++ } ++ ++ status = er32(STATUS); ++ if (status & E1000_STATUS_LU) { ++ if (status & E1000_STATUS_SPEED_1000) ++ ecmd->speed = 1000; ++ else if (status & E1000_STATUS_SPEED_100) ++ ecmd->speed = 100; ++ else ++ ecmd->speed = 10; ++ ++ if (status & E1000_STATUS_FD) ++ ecmd->duplex = DUPLEX_FULL; ++ else ++ ecmd->duplex = DUPLEX_HALF; ++ } else { ++ ecmd->speed = -1; ++ ecmd->duplex = -1; ++ } ++ ++ ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || ++ hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; ++ return 0; ++} ++ ++static u32 e1000_get_link(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 status; ++ ++ status = er32(STATUS); ++ return (status & E1000_STATUS_LU); ++} ++ ++static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) ++{ ++ struct e1000_mac_info *mac = &adapter->hw.mac; ++ ++ mac->autoneg = 0; ++ ++ /* Fiber NICs only allow 1000 gbps Full duplex */ ++ if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && ++ spddplx != (SPEED_1000 + DUPLEX_FULL)) { ++ e_err("Unsupported Speed/Duplex configuration\n"); ++ return -EINVAL; ++ } ++ ++ switch (spddplx) { ++ case SPEED_10 + DUPLEX_HALF: ++ mac->forced_speed_duplex = ADVERTISE_10_HALF; ++ break; ++ case SPEED_10 + DUPLEX_FULL: ++ mac->forced_speed_duplex = ADVERTISE_10_FULL; ++ break; ++ case SPEED_100 + DUPLEX_HALF: ++ mac->forced_speed_duplex = ADVERTISE_100_HALF; ++ break; ++ case SPEED_100 + DUPLEX_FULL: ++ mac->forced_speed_duplex = ADVERTISE_100_FULL; ++ break; ++ case SPEED_1000 + DUPLEX_FULL: ++ mac->autoneg = 1; ++ adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL; ++ break; ++ case SPEED_1000 + DUPLEX_HALF: /* not supported */ ++ default: ++ e_err("Unsupported Speed/Duplex configuration\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int e1000_set_settings(struct net_device *netdev, ++ struct ethtool_cmd *ecmd) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ ++ /* ++ * When SoL/IDER sessions are active, autoneg/speed/duplex ++ * cannot be changed ++ */ ++ if (hw->phy.ops.check_reset_block && ++ hw->phy.ops.check_reset_block(&adapter->hw)) { ++ e_err("Cannot change link characteristics when SoL/IDER" ++ " is active.\n"); ++ return -EINVAL; ++ } ++ ++ while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) ++ msleep(1); ++ ++ if (ecmd->autoneg == AUTONEG_ENABLE) { ++ hw->mac.autoneg = 1; ++ if (hw->phy.media_type == e1000_media_type_fiber) ++ hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | ++ ADVERTISED_FIBRE | ++ ADVERTISED_Autoneg; ++ else ++ hw->phy.autoneg_advertised = ecmd->advertising | ++ ADVERTISED_TP | ++ ADVERTISED_Autoneg; ++ ecmd->advertising = hw->phy.autoneg_advertised; ++ if (adapter->fc_autoneg) ++ hw->fc.original_type = e1000_fc_default; ++ } else { ++ if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { ++ clear_bit(__E1000_RESETTING, &adapter->state); ++ return -EINVAL; ++ } ++ } ++ ++ /* reset the link */ ++ ++ if (netif_running(adapter->netdev)) { ++ e1000_down(adapter); ++ e1000_up(adapter); ++ } else { ++ e1000_reset(adapter); ++ } ++ ++ clear_bit(__E1000_RESETTING, &adapter->state); ++ return 0; ++} ++ ++static void e1000_get_pauseparam(struct net_device *netdev, ++ struct ethtool_pauseparam *pause) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ ++ pause->autoneg = ++ (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); ++ ++ if (hw->fc.type == e1000_fc_rx_pause) { ++ pause->rx_pause = 1; ++ } else if (hw->fc.type == e1000_fc_tx_pause) { ++ pause->tx_pause = 1; ++ } else if (hw->fc.type == e1000_fc_full) { ++ pause->rx_pause = 1; ++ pause->tx_pause = 1; ++ } ++} ++ ++static int e1000_set_pauseparam(struct net_device *netdev, ++ struct ethtool_pauseparam *pause) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ int retval = 0; ++ ++ adapter->fc_autoneg = pause->autoneg; ++ ++ while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) ++ msleep(1); ++ ++ if (pause->rx_pause && pause->tx_pause) ++ hw->fc.type = e1000_fc_full; ++ else if (pause->rx_pause && !pause->tx_pause) ++ hw->fc.type = e1000_fc_rx_pause; ++ else if (!pause->rx_pause && pause->tx_pause) ++ hw->fc.type = e1000_fc_tx_pause; ++ else if (!pause->rx_pause && !pause->tx_pause) ++ hw->fc.type = e1000_fc_none; ++ ++ hw->fc.original_type = hw->fc.type; ++ ++ if (adapter->fc_autoneg == AUTONEG_ENABLE) { ++ hw->fc.type = e1000_fc_default; ++ if (netif_running(adapter->netdev)) { ++ e1000_down(adapter); ++ e1000_up(adapter); ++ } else { ++ e1000_reset(adapter); ++ } ++ } else { ++ retval = ((hw->phy.media_type == e1000_media_type_fiber) ? ++ hw->mac.ops.setup_link(hw) : ++ e1000_force_mac_fc_generic(hw)); ++ } ++ ++ clear_bit(__E1000_RESETTING, &adapter->state); ++ return retval; ++} ++ ++static u32 e1000_get_rx_csum(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ return (adapter->flags & FLAG_RX_CSUM_ENABLED); ++} ++ ++static int e1000_set_rx_csum(struct net_device *netdev, u32 data) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ if (data) ++ adapter->flags |= FLAG_RX_CSUM_ENABLED; ++ else ++ adapter->flags &= ~FLAG_RX_CSUM_ENABLED; ++ ++ if (netif_running(netdev)) ++ e1000_reinit_locked(adapter); ++ else ++ e1000_reset(adapter); ++ return 0; ++} ++ ++static u32 e1000_get_tx_csum(struct net_device *netdev) ++{ ++ return ((netdev->features & NETIF_F_HW_CSUM) != 0); ++} ++ ++static int e1000_set_tx_csum(struct net_device *netdev, u32 data) ++{ ++ if (data) ++ netdev->features |= NETIF_F_HW_CSUM; ++ else ++ netdev->features &= ~NETIF_F_HW_CSUM; ++ ++ return 0; ++} ++ ++#ifdef NETIF_F_TSO ++static int e1000_set_tso(struct net_device *netdev, u32 data) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ int i; ++ struct net_device *v_netdev; ++ ++ if (data) { ++ netdev->features |= NETIF_F_TSO; ++#ifdef NETIF_F_TSO6 ++ netdev->features |= NETIF_F_TSO6; ++#endif ++ } else { ++ netdev->features &= ~NETIF_F_TSO; ++#ifdef NETIF_F_TSO6 ++ netdev->features &= ~NETIF_F_TSO6; ++#endif ++#ifdef NETIF_F_HW_VLAN_TX ++ /* disable TSO on all VLANs if they're present */ ++ if (!adapter->vlgrp) ++ goto tso_out; ++ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { ++ v_netdev = vlan_group_get_device(adapter->vlgrp, i); ++ if (!v_netdev) ++ continue; ++ ++ v_netdev->features &= ~NETIF_F_TSO; ++#ifdef NETIF_F_TSO6 ++ v_netdev->features &= ~NETIF_F_TSO6; ++#endif ++ vlan_group_set_device(adapter->vlgrp, i, v_netdev); ++ } ++#endif ++ } ++ ++tso_out: ++ e_info("TSO is %s\n", data ? "Enabled" : "Disabled"); ++ adapter->flags |= FLAG_TSO_FORCE; ++ return 0; ++} ++#endif ++ ++static u32 e1000_get_msglevel(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ return adapter->msg_enable; ++} ++ ++static void e1000_set_msglevel(struct net_device *netdev, u32 data) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ adapter->msg_enable = data; ++} ++ ++static int e1000_get_regs_len(struct net_device *netdev) ++{ ++#define E1000_REGS_LEN 32 /* overestimate */ ++ return E1000_REGS_LEN * sizeof(u32); ++} ++ ++static void e1000_get_regs(struct net_device *netdev, ++ struct ethtool_regs *regs, void *p) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 *regs_buff = p; ++ u16 phy_data; ++ u8 revision_id; ++ ++ memset(p, 0, E1000_REGS_LEN * sizeof(u32)); ++ ++ pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id); ++ ++ regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device; ++ ++ regs_buff[0] = er32(CTRL); ++ regs_buff[1] = er32(STATUS); ++ ++ regs_buff[2] = er32(RCTL); ++ regs_buff[3] = er32(RDLEN(0)); ++ regs_buff[4] = er32(RDH(0)); ++ regs_buff[5] = er32(RDT(0)); ++ regs_buff[6] = er32(RDTR); ++ ++ regs_buff[7] = er32(TCTL); ++ regs_buff[8] = er32(TDLEN(0)); ++ regs_buff[9] = er32(TDH(0)); ++ regs_buff[10] = er32(TDT(0)); ++ regs_buff[11] = er32(TIDV); ++ ++ regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */ ++ if (hw->phy.type == e1000_phy_m88) { ++ hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); ++ regs_buff[13] = (u32)phy_data; /* cable length */ ++ regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */ ++ regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */ ++ regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */ ++ hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); ++ regs_buff[17] = (u32)phy_data; /* extended 10bt distance */ ++ regs_buff[18] = regs_buff[13]; /* cable polarity */ ++ regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */ ++ regs_buff[20] = regs_buff[17]; /* polarity correction */ ++ /* phy receive errors */ ++ regs_buff[22] = adapter->phy_stats.receive_errors; ++ regs_buff[23] = regs_buff[13]; /* mdix mode */ ++ } ++ regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */ ++ hw->phy.ops.read_reg(hw, PHY_1000T_STATUS, &phy_data); ++ regs_buff[24] = (u32)phy_data; /* phy local receiver status */ ++ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ ++} ++ ++static int e1000_get_eeprom_len(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ return adapter->hw.nvm.word_size * 2; ++} ++ ++static int e1000_get_eeprom(struct net_device *netdev, ++ struct ethtool_eeprom *eeprom, u8 *bytes) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u16 *eeprom_buff; ++ int first_word; ++ int last_word; ++ int ret_val = 0; ++ u16 i; ++ ++ if (eeprom->len == 0) ++ return -EINVAL; ++ ++ eeprom->magic = adapter->pdev->vendor | (adapter->pdev->device << 16); ++ ++ first_word = eeprom->offset >> 1; ++ last_word = (eeprom->offset + eeprom->len - 1) >> 1; ++ ++ eeprom_buff = kmalloc(sizeof(u16) * ++ (last_word - first_word + 1), GFP_KERNEL); ++ if (!eeprom_buff) ++ return -ENOMEM; ++ ++ if (hw->nvm.type == e1000_nvm_eeprom_spi) { ++ ret_val = hw->nvm.ops.read(hw, first_word, ++ last_word - first_word + 1, ++ eeprom_buff); ++ } else { ++ for (i = 0; i < last_word - first_word + 1; i++) { ++ ret_val = hw->nvm.ops.read(hw, first_word + i, 1, ++ &eeprom_buff[i]); ++ if (ret_val) ++ break; ++ } ++ } ++ ++ /* Device's eeprom is always little-endian, word addressable */ ++ for (i = 0; i < last_word - first_word + 1; i++) ++ le16_to_cpus(&eeprom_buff[i]); ++ ++ memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); ++ kfree(eeprom_buff); ++ ++ return ret_val; ++} ++ ++static int e1000_set_eeprom(struct net_device *netdev, ++ struct ethtool_eeprom *eeprom, u8 *bytes) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u16 *eeprom_buff; ++ void *ptr; ++ int max_len; ++ int first_word; ++ int last_word; ++ int ret_val = 0; ++ u16 i; ++ ++ if (eeprom->len == 0) ++ return -EOPNOTSUPP; ++ ++ if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16))) ++ return -EFAULT; ++ ++ if (adapter->flags2 & FLAG2_READ_ONLY_NVM) ++ return -EINVAL; ++ ++ max_len = hw->nvm.word_size * 2; ++ ++ first_word = eeprom->offset >> 1; ++ last_word = (eeprom->offset + eeprom->len - 1) >> 1; ++ eeprom_buff = kmalloc(max_len, GFP_KERNEL); ++ if (!eeprom_buff) ++ return -ENOMEM; ++ ++ ptr = (void *)eeprom_buff; ++ ++ if (eeprom->offset & 1) { ++ /* need read/modify/write of first changed EEPROM word */ ++ /* only the second byte of the word is being modified */ ++ ret_val = hw->nvm.ops.read(hw, first_word, 1, &eeprom_buff[0]); ++ ptr++; ++ } ++ if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) ++ /* need read/modify/write of last changed EEPROM word */ ++ /* only the first byte of the word is being modified */ ++ ret_val = hw->nvm.ops.read(hw, last_word, 1, ++ &eeprom_buff[last_word - first_word]); ++ ++ /* Device's eeprom is always little-endian, word addressable */ ++ for (i = 0; i < last_word - first_word + 1; i++) ++ le16_to_cpus(&eeprom_buff[i]); ++ ++ memcpy(ptr, bytes, eeprom->len); ++ ++ for (i = 0; i < last_word - first_word + 1; i++) ++ eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]); ++ ++ ret_val = hw->nvm.ops.write(hw, first_word, last_word - first_word + 1, ++ eeprom_buff); ++ ++ /* ++ * Update the checksum over the first part of the EEPROM if needed ++ * and flush shadow RAM for 82573 controllers ++ */ ++ if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) || ++ (hw->mac.type == e1000_82574) || ++ (hw->mac.type == e1000_82573))) ++ hw->nvm.ops.update(hw); ++ ++ kfree(eeprom_buff); ++ return ret_val; ++} ++ ++static void e1000_get_drvinfo(struct net_device *netdev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ char firmware_version[32]; ++ u16 eeprom_data; ++ ++ strncpy(drvinfo->driver, e1000e_driver_name, 32); ++ strncpy(drvinfo->version, e1000e_driver_version, 32); ++ ++ /* ++ * EEPROM image version # is reported as firmware version # for ++ * PCI-E controllers ++ */ ++ hw->nvm.ops.read(&adapter->hw, 5, 1, &eeprom_data); ++ sprintf(firmware_version, "%d.%d-%d", ++ (eeprom_data & 0xF000) >> 12, ++ (eeprom_data & 0x0FF0) >> 4, ++ eeprom_data & 0x000F); ++ ++ strncpy(drvinfo->fw_version, firmware_version, 32); ++ strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); ++ drvinfo->regdump_len = e1000_get_regs_len(netdev); ++ drvinfo->eedump_len = e1000_get_eeprom_len(netdev); ++} ++ ++static void e1000_get_ringparam(struct net_device *netdev, ++ struct ethtool_ringparam *ring) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ ++ ring->rx_max_pending = E1000_MAX_RXD; ++ ring->tx_max_pending = E1000_MAX_TXD; ++ ring->rx_mini_max_pending = 0; ++ ring->rx_jumbo_max_pending = 0; ++ ring->rx_pending = rx_ring->count; ++ ring->tx_pending = tx_ring->count; ++ ring->rx_mini_pending = 0; ++ ring->rx_jumbo_pending = 0; ++} ++ ++static int e1000_set_ringparam(struct net_device *netdev, ++ struct ethtool_ringparam *ring) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_ring *tx_ring, *tx_old; ++ struct e1000_ring *rx_ring, *rx_old; ++ int err; ++ ++ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) ++ return -EINVAL; ++ ++ while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) ++ msleep(1); ++ ++ if (netif_running(adapter->netdev)) ++ e1000_down(adapter); ++ ++ tx_old = adapter->tx_ring; ++ rx_old = adapter->rx_ring; ++ ++ err = -ENOMEM; ++ tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); ++ if (!tx_ring) ++ goto err_alloc_tx; ++ /* ++ * use a memcpy to save any previously configured ++ * items like napi structs from having to be ++ * reinitialized ++ */ ++ memcpy(tx_ring, tx_old, sizeof(struct e1000_ring)); ++ ++ rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); ++ if (!rx_ring) ++ goto err_alloc_rx; ++ memcpy(rx_ring, rx_old, sizeof(struct e1000_ring)); ++ ++ adapter->tx_ring = tx_ring; ++ adapter->rx_ring = rx_ring; ++ ++ rx_ring->count = max(ring->rx_pending, (u32)E1000_MIN_RXD); ++ rx_ring->count = min(rx_ring->count, (u32)(E1000_MAX_RXD)); ++ rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); ++ ++ tx_ring->count = max(ring->tx_pending, (u32)E1000_MIN_TXD); ++ tx_ring->count = min(tx_ring->count, (u32)(E1000_MAX_TXD)); ++ tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); ++ ++ if (netif_running(adapter->netdev)) { ++ /* Try to get new resources before deleting old */ ++ err = e1000_setup_rx_resources(adapter); ++ if (err) ++ goto err_setup_rx; ++ err = e1000_setup_tx_resources(adapter); ++ if (err) ++ goto err_setup_tx; ++ ++ /* ++ * restore the old in order to free it, ++ * then add in the new ++ */ ++ adapter->rx_ring = rx_old; ++ adapter->tx_ring = tx_old; ++ e1000_free_rx_resources(adapter); ++ e1000_free_tx_resources(adapter); ++ kfree(tx_old); ++ kfree(rx_old); ++ adapter->rx_ring = rx_ring; ++ adapter->tx_ring = tx_ring; ++ err = e1000_up(adapter); ++ if (err) ++ goto err_setup; ++ } ++ ++ clear_bit(__E1000_RESETTING, &adapter->state); ++ return 0; ++err_setup_tx: ++ e1000_free_rx_resources(adapter); ++err_setup_rx: ++ adapter->rx_ring = rx_old; ++ adapter->tx_ring = tx_old; ++ kfree(rx_ring); ++err_alloc_rx: ++ kfree(tx_ring); ++err_alloc_tx: ++ e1000_up(adapter); ++err_setup: ++ clear_bit(__E1000_RESETTING, &adapter->state); ++ return err; ++} ++ ++static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data, ++ int reg, int offset, u32 mask, u32 write) ++{ ++ u32 pat, val; ++ static const u32 test[] = ++ {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; ++ for (pat = 0; pat < ARRAY_SIZE(test); pat++) { ++ E1000_WRITE_REG_ARRAY(&adapter->hw, reg, offset, ++ (test[pat] & write)); ++ val = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset); ++ if (val != (test[pat] & write & mask)) { ++ e_err("pattern test reg %04X failed: got " ++ "0x%08X expected 0x%08X\n", ++ reg + offset, ++ val, (test[pat] & write & mask)); ++ *data = reg; ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data, ++ int reg, u32 mask, u32 write) ++{ ++ u32 val; ++ __ew32(&adapter->hw, reg, write & mask); ++ val = __er32(&adapter->hw, reg); ++ if ((write & mask) != (val & mask)) { ++ e_err("set/check reg %04X test failed: got 0x%08X" ++ "expected 0x%08X\n", reg, (val & mask), (write & mask)); ++ *data = reg; ++ return 1; ++ } ++ return 0; ++} ++#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, write) \ ++ do { \ ++ if (reg_pattern_test(adapter, data, reg, offset, mask, write)) \ ++ return 1; \ ++ } while (0) ++#define REG_PATTERN_TEST(reg, mask, write) \ ++ REG_PATTERN_TEST_ARRAY(reg, 0, mask, write) ++ ++#define REG_SET_AND_CHECK(reg, mask, write) \ ++ do { \ ++ if (reg_set_and_check(adapter, data, reg, mask, write)) \ ++ return 1; \ ++ } while (0) ++ ++static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ struct e1000_mac_info *mac = &adapter->hw.mac; ++ u32 value; ++ u32 before; ++ u32 after; ++ u32 i; ++ u32 toggle; ++ ++ /* ++ * The status register is Read Only, so a write should fail. ++ * Some bits that get toggled are ignored. ++ */ ++ switch (mac->type) { ++ /* there are several bits on newer hardware that are r/w */ ++ case e1000_82571: ++ case e1000_82572: ++ case e1000_80003es2lan: ++ toggle = 0x7FFFF3FF; ++ break; ++ case e1000_82573: ++ case e1000_82574: ++ case e1000_ich8lan: ++ case e1000_ich9lan: ++ case e1000_ich10lan: ++ toggle = 0x7FFFF033; ++ break; ++ default: ++ toggle = 0xFFFFF833; ++ break; ++ } ++ ++ before = er32(STATUS); ++ value = (er32(STATUS) & toggle); ++ ew32(STATUS, toggle); ++ after = er32(STATUS) & toggle; ++ if (value != after) { ++ e_err("failed STATUS register test got: " ++ "0x%08X expected: 0x%08X\n", after, value); ++ *data = 1; ++ return 1; ++ } ++ /* restore previous status */ ++ ew32(STATUS, before); ++ ++ if (!(adapter->flags & FLAG_IS_ICH)) { ++ REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF); ++ REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF); ++ REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF); ++ REG_PATTERN_TEST(E1000_VET, 0x0000FFFF, 0xFFFFFFFF); ++ } ++ ++ REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF); ++ REG_PATTERN_TEST(E1000_RDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF); ++ REG_PATTERN_TEST(E1000_RDLEN(0), 0x000FFF80, 0x000FFFFF); ++ REG_PATTERN_TEST(E1000_RDH(0), 0x0000FFFF, 0x0000FFFF); ++ REG_PATTERN_TEST(E1000_RDT(0), 0x0000FFFF, 0x0000FFFF); ++ REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8); ++ REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF); ++ REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF); ++ REG_PATTERN_TEST(E1000_TDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF); ++ REG_PATTERN_TEST(E1000_TDLEN(0), 0x000FFF80, 0x000FFFFF); ++ ++ REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000); ++ ++ before = ((adapter->flags & FLAG_IS_ICH) ? 0x06C3B33E : 0x06DFB3FE); ++ REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB); ++ REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000); ++ ++ REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF); ++ REG_PATTERN_TEST(E1000_RDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF); ++ if (!(adapter->flags & FLAG_IS_ICH)) ++ REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF); ++ REG_PATTERN_TEST(E1000_TDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF); ++ REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); ++ for (i = 0; i < mac->rar_entry_count; i++) ++ REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), ++ ((mac->type == e1000_ich10lan) ? ++ 0x8007FFFF : 0x8003FFFF), ++ 0xFFFFFFFF); ++ ++ for (i = 0; i < mac->mta_reg_count; i++) ++ REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); ++ ++ *data = 0; ++ return 0; ++} ++ ++static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u16 temp; ++ u16 checksum = 0; ++ u16 i; ++ ++ *data = 0; ++ /* Read and add up the contents of the EEPROM */ ++ for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { ++ if ((hw->nvm.ops.read(&adapter->hw, i, 1, &temp)) < 0) { ++ *data = 1; ++ break; ++ } ++ checksum += temp; ++ } ++ ++ /* If Checksum is not Correct return error else test passed */ ++ if ((checksum != (u16) NVM_SUM) && !(*data)) ++ *data = 2; ++ ++ return *data; ++} ++ ++static irqreturn_t e1000_test_intr(int irq, void *data) ++{ ++ struct net_device *netdev = (struct net_device *) data; ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ ++ adapter->test_icr |= er32(ICR); ++ ++ return IRQ_HANDLED; ++} ++ ++static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct e1000_hw *hw = &adapter->hw; ++ u32 mask; ++ u32 shared_int = 1; ++ u32 irq = adapter->pdev->irq; ++ int i; ++#ifdef CONFIG_E1000E_MSIX ++ int ret_val = 0; ++ int int_mode = E1000E_INT_MODE_LEGACY; ++#endif ++ ++ *data = 0; ++ ++ /* NOTE: we don't test MSI/MSI-X interrupts here, yet */ ++#ifdef CONFIG_E1000E_MSIX ++ if (adapter->int_mode == E1000E_INT_MODE_MSIX) { ++ int_mode = adapter->int_mode; ++ e1000_reset_interrupt_capability(adapter); ++ adapter->int_mode = E1000E_INT_MODE_LEGACY; ++ e1000_set_interrupt_capability(adapter); ++ } ++#endif ++ /* Hook up test interrupt handler just for this test */ ++ if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, ++ netdev)) { ++ shared_int = 0; ++ } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED, ++ netdev->name, netdev)) { ++ *data = 1; ++#ifdef CONFIG_E1000E_MSIX ++ ret_val = -1; ++ goto out; ++#else ++ return -1; ++#endif ++ } ++ e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared")); ++ ++ /* Disable all the interrupts */ ++ ew32(IMC, 0xFFFFFFFF); ++ msleep(10); ++ ++ /* Test each interrupt */ ++ for (i = 0; i < 10; i++) { ++ /* Interrupt to test */ ++ mask = 1 << i; ++ ++ if (adapter->flags & FLAG_IS_ICH) { ++ switch (mask) { ++ case E1000_ICR_RXSEQ: ++ continue; ++ case 0x00000100: ++ if (adapter->hw.mac.type == e1000_ich8lan || ++ adapter->hw.mac.type == e1000_ich9lan) ++ continue; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if (!shared_int) { ++ /* ++ * Disable the interrupt to be reported in ++ * the cause register and then force the same ++ * interrupt and see if one gets posted. If ++ * an interrupt was posted to the bus, the ++ * test failed. ++ */ ++ adapter->test_icr = 0; ++ ew32(IMC, mask); ++ ew32(ICS, mask); ++ msleep(10); ++ ++ if (adapter->test_icr & mask) { ++ *data = 3; ++ break; ++ } ++ } ++ ++ /* ++ * Enable the interrupt to be reported in ++ * the cause register and then force the same ++ * interrupt and see if one gets posted. If ++ * an interrupt was not posted to the bus, the ++ * test failed. ++ */ ++ adapter->test_icr = 0; ++ ew32(IMS, mask); ++ ew32(ICS, mask); ++ msleep(10); ++ ++ if (!(adapter->test_icr & mask)) { ++ *data = 4; ++ break; ++ } ++ ++ if (!shared_int) { ++ /* ++ * Disable the other interrupts to be reported in ++ * the cause register and then force the other ++ * interrupts and see if any get posted. If ++ * an interrupt was posted to the bus, the ++ * test failed. ++ */ ++ adapter->test_icr = 0; ++ ew32(IMC, ~mask & 0x00007FFF); ++ ew32(ICS, ~mask & 0x00007FFF); ++ msleep(10); ++ ++ if (adapter->test_icr) { ++ *data = 5; ++ break; ++ } ++ } ++ } ++ ++ /* Disable all the interrupts */ ++ ew32(IMC, 0xFFFFFFFF); ++ msleep(10); ++ ++ /* Unhook test interrupt handler */ ++ free_irq(irq, netdev); ++ ++#ifdef CONFIG_E1000E_MSIX ++out: ++ if (int_mode == E1000E_INT_MODE_MSIX) { ++ e1000_reset_interrupt_capability(adapter); ++ adapter->int_mode = int_mode; ++ e1000_set_interrupt_capability(adapter); ++ } ++ ++ return ret_val; ++#else ++ return *data; ++#endif ++} ++ ++static void e1000_free_desc_rings(struct e1000_adapter *adapter) ++{ ++ struct e1000_ring *tx_ring = &adapter->test_tx_ring; ++ struct e1000_ring *rx_ring = &adapter->test_rx_ring; ++ struct pci_dev *pdev = adapter->pdev; ++ int i; ++ ++ if (tx_ring->desc && tx_ring->buffer_info) { ++ for (i = 0; i < tx_ring->count; i++) { ++ if (tx_ring->buffer_info[i].dma) ++ pci_unmap_single(pdev, ++ tx_ring->buffer_info[i].dma, ++ tx_ring->buffer_info[i].length, ++ PCI_DMA_TODEVICE); ++ if (tx_ring->buffer_info[i].skb) ++ dev_kfree_skb(tx_ring->buffer_info[i].skb); ++ } ++ } ++ ++ if (rx_ring->desc && rx_ring->buffer_info) { ++ for (i = 0; i < rx_ring->count; i++) { ++ if (rx_ring->buffer_info[i].dma) ++ pci_unmap_single(pdev, ++ rx_ring->buffer_info[i].dma, ++ 2048, PCI_DMA_FROMDEVICE); ++ if (rx_ring->buffer_info[i].skb) ++ dev_kfree_skb(rx_ring->buffer_info[i].skb); ++ } ++ } ++ ++ if (tx_ring->desc) { ++ dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc, ++ tx_ring->dma); ++ tx_ring->desc = NULL; ++ } ++ if (rx_ring->desc) { ++ dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc, ++ rx_ring->dma); ++ rx_ring->desc = NULL; ++ } ++ ++ kfree(tx_ring->buffer_info); ++ tx_ring->buffer_info = NULL; ++ kfree(rx_ring->buffer_info); ++ rx_ring->buffer_info = NULL; ++} ++ ++static int e1000_setup_desc_rings(struct e1000_adapter *adapter) ++{ ++ struct e1000_ring *tx_ring = &adapter->test_tx_ring; ++ struct e1000_ring *rx_ring = &adapter->test_rx_ring; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_hw *hw = &adapter->hw; ++ u32 rctl; ++ int i; ++ int ret_val; ++ ++ /* Setup Tx descriptor ring and Tx buffers */ ++ ++ if (!tx_ring->count) ++ tx_ring->count = E1000_DEFAULT_TXD; ++ ++ if (!(tx_ring->buffer_info = kcalloc(tx_ring->count, ++ sizeof(struct e1000_buffer), ++ GFP_KERNEL))) { ++ ret_val = 1; ++ goto err_nomem; ++ } ++ ++ tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); ++ tx_ring->size = ALIGN(tx_ring->size, 4096); ++ tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size, ++ &tx_ring->dma, GFP_KERNEL); ++ if (!tx_ring->desc) { ++ ret_val = 2; ++ goto err_nomem; ++ } ++ tx_ring->next_to_use = 0; ++ tx_ring->next_to_clean = 0; ++ ++ ew32(TDBAL(0), ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); ++ ew32(TDBAH(0), ((u64) tx_ring->dma >> 32)); ++ ew32(TDLEN(0), tx_ring->count * sizeof(struct e1000_tx_desc)); ++ ew32(TDH(0), 0); ++ ew32(TDT(0), 0); ++ ew32(TCTL, E1000_TCTL_PSP | E1000_TCTL_EN | E1000_TCTL_MULR | ++ E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | ++ E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT); ++ ++ for (i = 0; i < tx_ring->count; i++) { ++ struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i); ++ struct sk_buff *skb; ++ unsigned int skb_size = 1024; ++ ++ skb = alloc_skb(skb_size, GFP_KERNEL); ++ if (!skb) { ++ ret_val = 3; ++ goto err_nomem; ++ } ++ skb_put(skb, skb_size); ++ tx_ring->buffer_info[i].skb = skb; ++ tx_ring->buffer_info[i].length = skb->len; ++ tx_ring->buffer_info[i].dma = ++ pci_map_single(pdev, skb->data, skb->len, ++ PCI_DMA_TODEVICE); ++ if (pci_dma_mapping_error(pdev, tx_ring->buffer_info[i].dma)) { ++ ret_val = 4; ++ goto err_nomem; ++ } ++ tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); ++ tx_desc->lower.data = cpu_to_le32(skb->len); ++ tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | ++ E1000_TXD_CMD_IFCS | ++ E1000_TXD_CMD_RS); ++ tx_desc->upper.data = 0; ++ } ++ ++ /* Setup Rx descriptor ring and Rx buffers */ ++ ++ if (!rx_ring->count) ++ rx_ring->count = E1000_DEFAULT_RXD; ++ ++ if (!(rx_ring->buffer_info = kcalloc(rx_ring->count, ++ sizeof(struct e1000_buffer), ++ GFP_KERNEL))) { ++ ret_val = 5; ++ goto err_nomem; ++ } ++ ++ rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc); ++ rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size, ++ &rx_ring->dma, GFP_KERNEL); ++ if (!rx_ring->desc) { ++ ret_val = 6; ++ goto err_nomem; ++ } ++ rx_ring->next_to_use = 0; ++ rx_ring->next_to_clean = 0; ++ ++ rctl = er32(RCTL); ++ ew32(RCTL, rctl & ~E1000_RCTL_EN); ++ ew32(RDBAL(0), ((u64) rx_ring->dma & 0xFFFFFFFF)); ++ ew32(RDBAH(0), ((u64) rx_ring->dma >> 32)); ++ ew32(RDLEN(0), rx_ring->size); ++ ew32(RDH(0), 0); ++ ew32(RDT(0), 0); ++ rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | ++ E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_LPE | ++ E1000_RCTL_SBP | E1000_RCTL_SECRC | ++ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | ++ (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); ++ ew32(RCTL, rctl); ++ ++ for (i = 0; i < rx_ring->count; i++) { ++ struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i); ++ struct sk_buff *skb; ++ ++ skb = alloc_skb(2048 + NET_IP_ALIGN, GFP_KERNEL); ++ if (!skb) { ++ ret_val = 7; ++ goto err_nomem; ++ } ++ skb_reserve(skb, NET_IP_ALIGN); ++ rx_ring->buffer_info[i].skb = skb; ++ rx_ring->buffer_info[i].dma = ++ pci_map_single(pdev, skb->data, 2048, ++ PCI_DMA_FROMDEVICE); ++ if (pci_dma_mapping_error(pdev, rx_ring->buffer_info[i].dma)) { ++ ret_val = 8; ++ goto err_nomem; ++ } ++ rx_desc->buffer_addr = ++ cpu_to_le64(rx_ring->buffer_info[i].dma); ++ memset(skb->data, 0x00, skb->len); ++ } ++ ++ return 0; ++ ++err_nomem: ++ e1000_free_desc_rings(adapter); ++ return ret_val; ++} ++ ++static void e1000_phy_disable_receiver(struct e1000_adapter *adapter) ++{ ++ /* Write out to PHY registers 29 and 30 to disable the Receiver. */ ++ adapter->hw.phy.ops.write_reg(&adapter->hw, 29, 0x001F); ++ adapter->hw.phy.ops.write_reg(&adapter->hw, 30, 0x8FFC); ++ adapter->hw.phy.ops.write_reg(&adapter->hw, 29, 0x001A); ++ adapter->hw.phy.ops.write_reg(&adapter->hw, 30, 0x8FF0); ++} ++ ++static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u32 ctrl_reg = 0; ++ u32 stat_reg = 0; ++ u16 phy_reg = 0; ++ ++ hw->mac.autoneg = 0; ++ ++ if (hw->phy.type == e1000_phy_m88) { ++ /* Auto-MDI/MDIX Off */ ++ hw->phy.ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); ++ /* reset to update Auto-MDI/MDIX */ ++ hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x9140); ++ /* autoneg off */ ++ hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x8140); ++ } else if (hw->phy.type == e1000_phy_gg82563) ++ hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC); ++ ++ ctrl_reg = er32(CTRL); ++ ++ switch (hw->phy.type) { ++ case e1000_phy_ife: ++ /* force 100, set loopback */ ++ hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x6100); ++ ++ /* Now set up the MAC to the same speed/duplex as the PHY. */ ++ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ ++ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ ++ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ ++ E1000_CTRL_SPD_100 |/* Force Speed to 100 */ ++ E1000_CTRL_FD); /* Force Duplex to FULL */ ++ break; ++ case e1000_phy_bm: ++ /* Set Default MAC Interface speed to 1GB */ ++ hw->phy.ops.read_reg(hw, PHY_REG(2, 21), &phy_reg); ++ phy_reg &= ~0x0007; ++ phy_reg |= 0x006; ++ hw->phy.ops.write_reg(hw, PHY_REG(2, 21), phy_reg); ++ /* Assert SW reset for above settings to take effect */ ++ hw->phy.ops.commit(hw); ++ mdelay(1); ++ /* Force Full Duplex */ ++ hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &phy_reg); ++ hw->phy.ops.write_reg(hw, PHY_REG(769, 16), phy_reg | 0x000C); ++ /* Set Link Up (in force link) */ ++ hw->phy.ops.read_reg(hw, PHY_REG(776, 16), &phy_reg); ++ hw->phy.ops.write_reg(hw, PHY_REG(776, 16), phy_reg | 0x0040); ++ /* Force Link */ ++ hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &phy_reg); ++ hw->phy.ops.write_reg(hw, PHY_REG(769, 16), phy_reg | 0x0040); ++ /* Set Early Link Enable */ ++ hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg); ++ hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg | 0x0400); ++ /* fall through */ ++ default: ++ /* force 1000, set loopback */ ++ hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x4140); ++ mdelay(250); ++ ++ /* Now set up the MAC to the same speed/duplex as the PHY. */ ++ ctrl_reg = er32(CTRL); ++ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ ++ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ ++ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ ++ E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ ++ E1000_CTRL_FD); /* Force Duplex to FULL */ ++ ++ if (adapter->flags & FLAG_IS_ICH) ++ ctrl_reg |= E1000_CTRL_SLU; /* Set Link Up */ ++ } ++ ++ if (hw->phy.media_type == e1000_media_type_copper && ++ hw->phy.type == e1000_phy_m88) { ++ ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ ++ } else { ++ /* ++ * Set the ILOS bit on the fiber Nic if half duplex link is ++ * detected. ++ */ ++ stat_reg = er32(STATUS); ++ if ((stat_reg & E1000_STATUS_FD) == 0) ++ ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); ++ } ++ ++ ew32(CTRL, ctrl_reg); ++ ++ /* ++ * Disable the receiver on the PHY so when a cable is plugged in, the ++ * PHY does not begin to autoneg when a cable is reconnected to the NIC. ++ */ ++ if (hw->phy.type == e1000_phy_m88) ++ e1000_phy_disable_receiver(adapter); ++ ++ udelay(500); ++ ++ return 0; ++} ++ ++static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u32 ctrl = er32(CTRL); ++ int link = 0; ++ ++ /* special requirements for 82571/82572 fiber adapters */ ++ ++ /* ++ * jump through hoops to make sure link is up because serdes ++ * link is hardwired up ++ */ ++ ctrl |= E1000_CTRL_SLU; ++ ew32(CTRL, ctrl); ++ ++ /* disable autoneg */ ++ ctrl = er32(TXCW); ++ ctrl &= ~(1 << 31); ++ ew32(TXCW, ctrl); ++ ++ link = (er32(STATUS) & E1000_STATUS_LU); ++ ++ if (!link) { ++ /* set invert loss of signal */ ++ ctrl = er32(CTRL); ++ ctrl |= E1000_CTRL_ILOS; ++ ew32(CTRL, ctrl); ++ } ++ ++ /* ++ * special write to serdes control register to enable SerDes analog ++ * loopback ++ */ ++#define E1000_SERDES_LB_ON 0x410 ++ ew32(SCTL, E1000_SERDES_LB_ON); ++ msleep(10); ++ ++ return 0; ++} ++ ++/* only call this for fiber/serdes connections to es2lan */ ++static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u32 ctrlext = er32(CTRL_EXT); ++ u32 ctrl = er32(CTRL); ++ ++ /* ++ * save CTRL_EXT to restore later, reuse an empty variable (unused ++ * on mac_type 80003es2lan) ++ */ ++ adapter->tx_fifo_head = ctrlext; ++ ++ /* clear the serdes mode bits, putting the device into mac loopback */ ++ ctrlext &= ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; ++ ew32(CTRL_EXT, ctrlext); ++ ++ /* force speed to 1000/FD, link up */ ++ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); ++ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | ++ E1000_CTRL_SPD_1000 | E1000_CTRL_FD); ++ ew32(CTRL, ctrl); ++ ++ /* set mac loopback */ ++ ctrl = er32(RCTL); ++ ctrl |= E1000_RCTL_LBM_MAC; ++ ew32(RCTL, ctrl); ++ ++ /* set testing mode parameters (no need to reset later) */ ++#define KMRNCTRLSTA_OPMODE (0x1F << 16) ++#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582 ++ ew32(KMRNCTRLSTA, ++ (KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII)); ++ ++ return 0; ++} ++ ++static int e1000_setup_loopback_test(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u32 rctl; ++ ++ if (hw->phy.media_type == e1000_media_type_fiber || ++ hw->phy.media_type == e1000_media_type_internal_serdes) { ++ switch (hw->mac.type) { ++ case e1000_80003es2lan: ++ return e1000_set_es2lan_mac_loopback(adapter); ++ break; ++ case e1000_82571: ++ case e1000_82572: ++ return e1000_set_82571_fiber_loopback(adapter); ++ break; ++ default: ++ rctl = er32(RCTL); ++ rctl |= E1000_RCTL_LBM_TCVR; ++ ew32(RCTL, rctl); ++ return 0; ++ } ++ } else if (hw->phy.media_type == e1000_media_type_copper) { ++ return e1000_integrated_phy_loopback(adapter); ++ } ++ ++ return 7; ++} ++ ++static void e1000_loopback_cleanup(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u32 rctl; ++ u16 phy_reg; ++ ++ rctl = er32(RCTL); ++ rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); ++ ew32(RCTL, rctl); ++ ++ switch (hw->mac.type) { ++ case e1000_80003es2lan: ++ if (hw->phy.media_type == e1000_media_type_fiber || ++ hw->phy.media_type == e1000_media_type_internal_serdes) { ++ /* restore CTRL_EXT, stealing space from tx_fifo_head */ ++ ew32(CTRL_EXT, adapter->tx_fifo_head); ++ adapter->tx_fifo_head = 0; ++ } ++ /* fall through */ ++ case e1000_82571: ++ case e1000_82572: ++ if (hw->phy.media_type == e1000_media_type_fiber || ++ hw->phy.media_type == e1000_media_type_internal_serdes) { ++#define E1000_SERDES_LB_OFF 0x400 ++ ew32(SCTL, E1000_SERDES_LB_OFF); ++ msleep(10); ++ break; ++ } ++ /* Fall Through */ ++ default: ++ hw->mac.autoneg = 1; ++ if (hw->phy.type == e1000_phy_gg82563) ++ hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ++ 0x180); ++ if(hw->phy.ops.read_reg) ++ hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_reg); ++ if (phy_reg & MII_CR_LOOPBACK) { ++ phy_reg &= ~MII_CR_LOOPBACK; ++ hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_reg); ++ if (hw->phy.ops.commit) ++ hw->phy.ops.commit(hw); ++ } ++ break; ++ } ++} ++ ++static void e1000_create_lbtest_frame(struct sk_buff *skb, ++ unsigned int frame_size) ++{ ++ memset(skb->data, 0xFF, frame_size); ++ frame_size &= ~1; ++ memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); ++ memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); ++ memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); ++} ++ ++static int e1000_check_lbtest_frame(struct sk_buff *skb, ++ unsigned int frame_size) ++{ ++ frame_size &= ~1; ++ if (*(skb->data + 3) == 0xFF) ++ if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && ++ (*(skb->data + frame_size / 2 + 12) == 0xAF)) ++ return 0; ++ return 13; ++} ++ ++static int e1000_run_loopback_test(struct e1000_adapter *adapter) ++{ ++ struct e1000_ring *tx_ring = &adapter->test_tx_ring; ++ struct e1000_ring *rx_ring = &adapter->test_rx_ring; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_hw *hw = &adapter->hw; ++ int i, j, k, l; ++ int lc; ++ int good_cnt; ++ int ret_val = 0; ++ unsigned long time; ++ ++ ew32(RDT(0), rx_ring->count - 1); ++ ++ /* ++ * Calculate the loop count based on the largest descriptor ring ++ * The idea is to wrap the largest ring a number of times using 64 ++ * send/receive pairs during each loop ++ */ ++ ++ if (rx_ring->count <= tx_ring->count) ++ lc = ((tx_ring->count / 64) * 2) + 1; ++ else ++ lc = ((rx_ring->count / 64) * 2) + 1; ++ ++ k = 0; ++ l = 0; ++ for (j = 0; j <= lc; j++) { /* loop count loop */ ++ for (i = 0; i < 64; i++) { /* send the packets */ ++ e1000_create_lbtest_frame(tx_ring->buffer_info[k].skb, ++ 1024); ++ pci_dma_sync_single_for_device(pdev, ++ tx_ring->buffer_info[k].dma, ++ tx_ring->buffer_info[k].length, ++ PCI_DMA_TODEVICE); ++ k++; ++ if (k == tx_ring->count) ++ k = 0; ++ } ++ ew32(TDT(0), k); ++ msleep(200); ++ time = jiffies; /* set the start time for the receive */ ++ good_cnt = 0; ++ do { /* receive the sent packets */ ++ pci_dma_sync_single_for_cpu(pdev, ++ rx_ring->buffer_info[l].dma, 2048, ++ PCI_DMA_FROMDEVICE); ++ ++ ret_val = e1000_check_lbtest_frame( ++ rx_ring->buffer_info[l].skb, 1024); ++ if (!ret_val) ++ good_cnt++; ++ l++; ++ if (l == rx_ring->count) ++ l = 0; ++ /* ++ * time + 20 msecs (200 msecs on 2.4) is more than ++ * enough time to complete the receives, if it's ++ * exceeded, break and error off ++ */ ++ } while ((good_cnt < 64) && !time_after(jiffies, time + 20)); ++ if (good_cnt != 64) { ++ ret_val = 13; /* ret_val is the same as mis-compare */ ++ break; ++ } ++ if (jiffies >= (time + 20)) { ++ ret_val = 14; /* error code for time out error */ ++ break; ++ } ++ } /* end loop count loop */ ++ return ret_val; ++} ++ ++static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ /* ++ * PHY loopback cannot be performed if SoL/IDER ++ * sessions are active ++ */ ++ if (hw->phy.ops.check_reset_block && ++ hw->phy.ops.check_reset_block(&adapter->hw)) { ++ e_err("Cannot do PHY loopback test when SoL/IDER is active.\n"); ++ *data = 0; ++ goto out; ++ } ++ ++ *data = e1000_setup_desc_rings(adapter); ++ if (*data) ++ goto out; ++ ++ *data = e1000_setup_loopback_test(adapter); ++ if (*data) ++ goto err_loopback; ++ ++ *data = e1000_run_loopback_test(adapter); ++ e1000_loopback_cleanup(adapter); ++ ++err_loopback: ++ e1000_free_desc_rings(adapter); ++out: ++ return *data; ++} ++ ++static int e1000_link_test(struct e1000_adapter *adapter, u64 *data) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ ++ *data = 0; ++ if (hw->phy.media_type == e1000_media_type_internal_serdes) { ++ int i = 0; ++ hw->mac.serdes_has_link = 0; ++ ++ /* ++ * On some blade server designs, link establishment ++ * could take as long as 2-3 minutes ++ */ ++ do { ++ hw->mac.ops.check_for_link(hw); ++ if (hw->mac.serdes_has_link) ++ return *data; ++ msleep(20); ++ } while (i++ < 3750); ++ ++ *data = 1; ++ } else { ++ hw->mac.ops.check_for_link(hw); ++ if (hw->mac.autoneg) ++ msleep(4000); ++ ++ if (!(er32(STATUS) & ++ E1000_STATUS_LU)) ++ *data = 1; ++ } ++ return *data; ++} ++ ++static int e1000_get_self_test_count(struct net_device *netdev) ++{ ++ return E1000_TEST_LEN; ++} ++ ++static int e1000_get_stats_count(struct net_device *netdev) ++{ ++ return E1000_STATS_LEN; ++} ++ ++static void e1000_diag_test(struct net_device *netdev, ++ struct ethtool_test *eth_test, u64 *data) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ u16 autoneg_advertised; ++ u8 forced_speed_duplex; ++ u8 autoneg; ++ bool if_running = netif_running(netdev); ++ ++ set_bit(__E1000_TESTING, &adapter->state); ++ if (eth_test->flags == ETH_TEST_FL_OFFLINE) { ++ /* Offline tests */ ++ ++ /* save speed, duplex, autoneg settings */ ++ autoneg_advertised = adapter->hw.phy.autoneg_advertised; ++ forced_speed_duplex = adapter->hw.mac.forced_speed_duplex; ++ autoneg = adapter->hw.mac.autoneg; ++ ++ e_info("offline testing starting\n"); ++ ++ /* ++ * Link test performed before hardware reset so autoneg doesn't ++ * interfere with test result ++ */ ++ if (e1000_link_test(adapter, &data[4])) ++ eth_test->flags |= ETH_TEST_FL_FAILED; ++ ++ if (if_running) ++ /* indicate we're in test mode */ ++ dev_close(netdev); ++ else ++ e1000_reset(adapter); ++ ++ if (e1000_reg_test(adapter, &data[0])) ++ eth_test->flags |= ETH_TEST_FL_FAILED; ++ ++ e1000_reset(adapter); ++ if (e1000_eeprom_test(adapter, &data[1])) ++ eth_test->flags |= ETH_TEST_FL_FAILED; ++ ++ e1000_reset(adapter); ++ if (e1000_intr_test(adapter, &data[2])) ++ eth_test->flags |= ETH_TEST_FL_FAILED; ++ ++ e1000_reset(adapter); ++ /* make sure the phy is powered up */ ++ e1000_power_up_phy(&adapter->hw); ++ if (e1000_loopback_test(adapter, &data[3])) ++ eth_test->flags |= ETH_TEST_FL_FAILED; ++ ++ /* restore speed, duplex, autoneg settings */ ++ adapter->hw.phy.autoneg_advertised = autoneg_advertised; ++ adapter->hw.mac.forced_speed_duplex = forced_speed_duplex; ++ adapter->hw.mac.autoneg = autoneg; ++ ++ /* force this routine to wait until autoneg complete/timeout */ ++ adapter->hw.phy.autoneg_wait_to_complete = 1; ++ e1000_reset(adapter); ++ adapter->hw.phy.autoneg_wait_to_complete = 0; ++ ++ clear_bit(__E1000_TESTING, &adapter->state); ++ if (if_running) ++ dev_open(netdev); ++ } else { ++ e_info("online testing starting\n"); ++ /* Online tests */ ++ if (e1000_link_test(adapter, &data[4])) ++ eth_test->flags |= ETH_TEST_FL_FAILED; ++ ++ /* Online tests aren't run; pass by default */ ++ data[0] = 0; ++ data[1] = 0; ++ data[2] = 0; ++ data[3] = 0; ++ ++ clear_bit(__E1000_TESTING, &adapter->state); ++ } ++ msleep_interruptible(4 * 1000); ++} ++ ++static void e1000_get_wol(struct net_device *netdev, ++ struct ethtool_wolinfo *wol) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ wol->supported = 0; ++ wol->wolopts = 0; ++ ++ if (!(adapter->flags & FLAG_HAS_WOL)) ++ return; ++ ++ wol->supported = WAKE_UCAST | WAKE_MCAST | ++ WAKE_BCAST | WAKE_MAGIC | ++ WAKE_PHY | WAKE_ARP; ++ ++ /* apply any specific unsupported masks here */ ++ if (adapter->flags & FLAG_NO_WAKE_UCAST) { ++ wol->supported &= ~WAKE_UCAST; ++ ++ if (adapter->wol & E1000_WUFC_EX) ++ e_err("Interface does not support directed (unicast)" ++ " frame wake-up packets\n"); ++ } ++ ++ if (adapter->wol & E1000_WUFC_EX) ++ wol->wolopts |= WAKE_UCAST; ++ if (adapter->wol & E1000_WUFC_MC) ++ wol->wolopts |= WAKE_MCAST; ++ if (adapter->wol & E1000_WUFC_BC) ++ wol->wolopts |= WAKE_BCAST; ++ if (adapter->wol & E1000_WUFC_MAG) ++ wol->wolopts |= WAKE_MAGIC; ++ if (adapter->wol & E1000_WUFC_LNKC) ++ wol->wolopts |= WAKE_PHY; ++ if (adapter->wol & E1000_WUFC_ARP) ++ wol->wolopts |= WAKE_ARP; ++} ++ ++static int e1000_set_wol(struct net_device *netdev, ++ struct ethtool_wolinfo *wol) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ if (wol->wolopts & WAKE_MAGICSECURE) ++ return -EOPNOTSUPP; ++ ++ if (!(adapter->flags & FLAG_HAS_WOL)) ++ return wol->wolopts ? -EOPNOTSUPP : 0; ++ ++ /* these settings will always override what we currently have */ ++ adapter->wol = 0; ++ ++ if (wol->wolopts & WAKE_UCAST) ++ adapter->wol |= E1000_WUFC_EX; ++ if (wol->wolopts & WAKE_MCAST) ++ adapter->wol |= E1000_WUFC_MC; ++ if (wol->wolopts & WAKE_BCAST) ++ adapter->wol |= E1000_WUFC_BC; ++ if (wol->wolopts & WAKE_MAGIC) ++ adapter->wol |= E1000_WUFC_MAG; ++ if (wol->wolopts & WAKE_PHY) ++ adapter->wol |= E1000_WUFC_LNKC; ++ if (wol->wolopts & WAKE_ARP) ++ adapter->wol |= E1000_WUFC_ARP; ++ ++ return 0; ++} ++ ++/* toggle LED 4 times per second = 2 "blinks" per second */ ++#define E1000_ID_INTERVAL (HZ/4) ++ ++/* bit defines for adapter->led_status */ ++#define E1000_LED_ON 0 ++ ++static void e1000_led_blink_callback(unsigned long data) ++{ ++ struct e1000_adapter *adapter = (struct e1000_adapter *) data; ++ ++ if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) ++ adapter->hw.mac.ops.led_off(&adapter->hw); ++ else ++ adapter->hw.mac.ops.led_on(&adapter->hw); ++ ++ mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); ++} ++ ++static int e1000_phys_id(struct net_device *netdev, u32 data) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ ++ if (!data) ++ data = INT_MAX; ++ ++ if ((hw->phy.type == e1000_phy_ife) || ++ (hw->mac.type == e1000_82574)) { ++ if (!adapter->blink_timer.function) { ++ init_timer(&adapter->blink_timer); ++ adapter->blink_timer.function = ++ e1000_led_blink_callback; ++ adapter->blink_timer.data = (unsigned long) adapter; ++ } ++ mod_timer(&adapter->blink_timer, jiffies); ++ msleep_interruptible(data * 1000); ++ del_timer_sync(&adapter->blink_timer); ++ if (hw->phy.type == e1000_phy_ife) ++ hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, ++ 0); ++ } else { ++ hw->mac.ops.blink_led(hw); ++ msleep_interruptible(data * 1000); ++ } ++ ++ hw->mac.ops.led_off(hw); ++ clear_bit(E1000_LED_ON, &adapter->led_status); ++ hw->mac.ops.cleanup_led(hw); ++ ++ return 0; ++} ++ ++static int e1000_get_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *ec) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ if (adapter->itr_setting <= 3) ++ ec->rx_coalesce_usecs = adapter->itr_setting; ++ else ++ ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; ++ ++ ec->stats_block_coalesce_usecs = adapter->stats_freq_us; ++ ++ return 0; ++} ++ ++static int e1000_set_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *ec) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ ++ if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) || ++ ((ec->rx_coalesce_usecs > 3) && ++ (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) || ++ (ec->rx_coalesce_usecs == 2) || ++ (ec->stats_block_coalesce_usecs > (10 * 1000000))) ++ return -EINVAL; ++ ++ adapter->stats_freq_us = ec->stats_block_coalesce_usecs; ++ ++ if (ec->rx_coalesce_usecs <= 3) { ++ adapter->itr = 20000; ++ adapter->itr_setting = ec->rx_coalesce_usecs; ++ } else { ++ adapter->itr = (1000000 / ec->rx_coalesce_usecs); ++ adapter->itr_setting = adapter->itr & ~3; ++ } ++ ++ if (adapter->itr_setting != 0) ++ ew32(ITR, 1000000000 / (adapter->itr * 256)); ++ else ++ ew32(ITR, 0); ++ ++ return 0; ++} ++ ++static int e1000_nway_reset(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ if (netif_running(netdev)) ++ e1000_reinit_locked(adapter); ++ return 0; ++} ++ ++static void e1000_get_ethtool_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, ++ u64 *data) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ int i; ++ ++ e1000_update_stats(adapter); ++ for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { ++ char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; ++ data[i] = (e1000_gstrings_stats[i].sizeof_stat == ++ sizeof(u64)) ? *(u64 *)p : *(u32 *)p; ++ } ++} ++ ++static void e1000_get_strings(struct net_device *netdev, u32 stringset, ++ u8 *data) ++{ ++ u8 *p = data; ++ int i; ++ ++ switch (stringset) { ++ case ETH_SS_TEST: ++ memcpy(data, *e1000_gstrings_test, sizeof(e1000_gstrings_test)); ++ break; ++ case ETH_SS_STATS: ++ for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { ++ memcpy(p, e1000_gstrings_stats[i].stat_string, ++ ETH_GSTRING_LEN); ++ p += ETH_GSTRING_LEN; ++ } ++ break; ++ } ++} ++ ++static const struct ethtool_ops e1000_ethtool_ops = { ++ .get_settings = e1000_get_settings, ++ .set_settings = e1000_set_settings, ++ .get_drvinfo = e1000_get_drvinfo, ++ .get_regs_len = e1000_get_regs_len, ++ .get_regs = e1000_get_regs, ++ .get_wol = e1000_get_wol, ++ .set_wol = e1000_set_wol, ++ .get_msglevel = e1000_get_msglevel, ++ .set_msglevel = e1000_set_msglevel, ++ .nway_reset = e1000_nway_reset, ++ .get_link = e1000_get_link, ++ .get_eeprom_len = e1000_get_eeprom_len, ++ .get_eeprom = e1000_get_eeprom, ++ .set_eeprom = e1000_set_eeprom, ++ .get_ringparam = e1000_get_ringparam, ++ .set_ringparam = e1000_set_ringparam, ++ .get_pauseparam = e1000_get_pauseparam, ++ .set_pauseparam = e1000_set_pauseparam, ++ .get_rx_csum = e1000_get_rx_csum, ++ .set_rx_csum = e1000_set_rx_csum, ++ .get_tx_csum = e1000_get_tx_csum, ++ .set_tx_csum = e1000_set_tx_csum, ++ .get_sg = ethtool_op_get_sg, ++ .set_sg = ethtool_op_set_sg, ++#ifdef NETIF_F_TSO ++ .get_tso = ethtool_op_get_tso, ++ .set_tso = e1000_set_tso, ++#endif ++ .self_test = e1000_diag_test, ++ .get_strings = e1000_get_strings, ++ .phys_id = e1000_phys_id, ++ .get_ethtool_stats = e1000_get_ethtool_stats, ++ .self_test_count = e1000_get_self_test_count, ++ .get_stats_count = e1000_get_stats_count, ++ .get_coalesce = e1000_get_coalesce, ++ .set_coalesce = e1000_set_coalesce, ++}; ++ ++void e1000_set_ethtool_ops(struct net_device *netdev) ++{ ++ /* have to "undeclare" const on this struct to remove warnings */ ++ SET_ETHTOOL_OPS(netdev, (struct ethtool_ops *)&e1000_ethtool_ops); ++} ++#endif /* SIOCETHTOOL */ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/kcompat.c linux-2.6.22-10/drivers/net/e1000e/kcompat.c +--- linux-2.6.22-0/drivers/net/e1000e/kcompat.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/kcompat.c 2008-11-10 17:29:35.000000000 +0100 +@@ -0,0 +1,319 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++ ++#define DRIVER_E1000E ++ ++#ifdef DRIVER_E1000E ++#include "e1000.h" ++#endif ++ ++ ++ ++ ++#include "kcompat.h" ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) ) ++ ++/**************************************/ ++/* 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) ++{ ++ return (((u64) (page - mem_map) << PAGE_SHIFT) + offset + ++ PCI_DRAM_OFFSET); ++} ++ ++#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 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) ) ++ ++/**************************************/ ++/* 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 < 6; 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 < 6; 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 + 31; ++ 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) + 31) & ~31); ++ dev->name[0] = '\0'; ++ ether_setup(dev); ++ ++ return dev; ++} ++ ++int ++_kc_is_valid_ether_addr(u8 *addr) ++{ ++ const char zaddr[6] = { 0, }; ++ ++ return !(addr[0] & 1) && memcmp(addr, zaddr, 6); ++} ++ ++#endif /* 2.4.3 => 2.4.0 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) ) ++ ++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,6,0) ) ++void _kc_skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, ++ int off, int size) ++{ ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; ++ frag->page = page; ++ frag->page_offset = off; ++ frag->size = size; ++ skb_shinfo(skb)->nr_frags = i + 1; ++} ++ ++/* ++ * Original Copyright: ++ * find_next_bit.c: fallback find next bit implementation ++ * ++ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ */ ++ ++/** ++ * find_next_bit - find the next set bit in a memory region ++ * @addr: The address to base the search on ++ * @offset: The bitnumber to start searching at ++ * @size: The maximum size to search ++ */ ++unsigned long find_next_bit(const unsigned long *addr, unsigned long size, ++ unsigned long offset) ++{ ++ const unsigned long *p = addr + BITOP_WORD(offset); ++ unsigned long result = offset & ~(BITS_PER_LONG-1); ++ unsigned long tmp; ++ ++ if (offset >= size) ++ return size; ++ size -= result; ++ offset %= BITS_PER_LONG; ++ if (offset) { ++ tmp = *(p++); ++ tmp &= (~0UL << offset); ++ if (size < BITS_PER_LONG) ++ goto found_first; ++ if (tmp) ++ goto found_middle; ++ size -= BITS_PER_LONG; ++ result += BITS_PER_LONG; ++ } ++ while (size & ~(BITS_PER_LONG-1)) { ++ if ((tmp = *(p++))) ++ goto found_middle; ++ result += BITS_PER_LONG; ++ size -= BITS_PER_LONG; ++ } ++ if (!size) ++ return result; ++ tmp = *p; ++ ++found_first: ++ tmp &= (~0UL >> (BITS_PER_LONG - size)); ++ if (tmp == 0UL) /* Are any bits set? */ ++ return result + size; /* Nope. */ ++found_middle: ++ return result + ffs(tmp); ++} ++ ++#endif /* 2.6.0 => 2.4.6 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) ) ++void *_kc_kzalloc(size_t size, int flags) ++{ ++ void *ret = kmalloc(size, flags); ++ if (ret) ++ memset(ret, 0, size); ++ return ret; ++} ++#endif /* <= 2.6.13 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ) ++struct sk_buff *_kc_netdev_alloc_skb(struct net_device *dev, ++ unsigned int length) ++{ ++ /* 16 == NET_PAD_SKB */ ++ struct sk_buff *skb; ++ skb = alloc_skb(length + 16, GFP_ATOMIC); ++ if (likely(skb != NULL)) { ++ skb_reserve(skb, 16); ++ skb->dev = dev; ++ } ++ return skb; ++} ++#endif /* <= 2.6.17 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) ) ++#endif /* < 2.6.23 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ) ++#ifdef NAPI ++int __kc_adapter_clean(struct net_device *netdev, int *budget) ++{ ++ int work_done; ++ int work_to_do = min(*budget, netdev->quota); ++ struct adapter_struct *adapter = netdev_priv(netdev); ++#ifdef DRIVER_E1000E ++ struct napi_struct *napi = &adapter->napi; ++#else ++ struct napi_struct *napi = &adapter->rx_ring[0].napi; ++#endif ++ ++ work_done = napi->poll(napi, work_to_do); ++ *budget -= work_done; ++ netdev->quota -= work_done; ++ return work_done ? 1 : 0; ++} ++#endif /* NAPI */ ++#endif /* <= 2.6.24 */ ++ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/kcompat_ethtool.c linux-2.6.22-10/drivers/net/e1000e/kcompat_ethtool.c +--- linux-2.6.22-0/drivers/net/e1000e/kcompat_ethtool.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/kcompat_ethtool.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,1169 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++/* ++ * net/core/ethtool.c - Ethtool ioctl handler ++ * Copyright (c) 2003 Matthew Wilcox ++ * ++ * This file is where we call all the ethtool_ops commands to get ++ * the information ethtool needs. We fall back to calling do_ioctl() ++ * for drivers which haven't been converted to ethtool_ops yet. ++ * ++ * It's GPL, stupid. ++ * ++ * Modification by sfeldma@pobox.com to work as backward compat ++ * solution for pre-ethtool_ops kernels. ++ * - copied struct ethtool_ops from ethtool.h ++ * - defined SET_ETHTOOL_OPS ++ * - put in some #ifndef NETIF_F_xxx wrappers ++ * - changes refs to dev->ethtool_ops to ethtool_ops ++ * - changed dev_ethtool to ethtool_ioctl ++ * - remove EXPORT_SYMBOL()s ++ * - added _kc_ prefix in built-in ethtool_op_xxx ops. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "kcompat.h" ++ ++#undef SUPPORTED_10000baseT_Full ++#define SUPPORTED_10000baseT_Full (1 << 12) ++#undef ADVERTISED_10000baseT_Full ++#define ADVERTISED_10000baseT_Full (1 << 12) ++#undef SPEED_10000 ++#define SPEED_10000 10000 ++ ++#undef ethtool_ops ++#define ethtool_ops _kc_ethtool_ops ++ ++struct _kc_ethtool_ops { ++ int (*get_settings)(struct net_device *, struct ethtool_cmd *); ++ int (*set_settings)(struct net_device *, struct ethtool_cmd *); ++ void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); ++ int (*get_regs_len)(struct net_device *); ++ void (*get_regs)(struct net_device *, struct ethtool_regs *, void *); ++ void (*get_wol)(struct net_device *, struct ethtool_wolinfo *); ++ int (*set_wol)(struct net_device *, struct ethtool_wolinfo *); ++ u32 (*get_msglevel)(struct net_device *); ++ void (*set_msglevel)(struct net_device *, u32); ++ int (*nway_reset)(struct net_device *); ++ u32 (*get_link)(struct net_device *); ++ int (*get_eeprom_len)(struct net_device *); ++ int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); ++ int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); ++ int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *); ++ int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *); ++ void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *); ++ int (*set_ringparam)(struct net_device *, struct ethtool_ringparam *); ++ void (*get_pauseparam)(struct net_device *, ++ struct ethtool_pauseparam*); ++ int (*set_pauseparam)(struct net_device *, ++ struct ethtool_pauseparam*); ++ u32 (*get_rx_csum)(struct net_device *); ++ int (*set_rx_csum)(struct net_device *, u32); ++ u32 (*get_tx_csum)(struct net_device *); ++ int (*set_tx_csum)(struct net_device *, u32); ++ u32 (*get_sg)(struct net_device *); ++ int (*set_sg)(struct net_device *, u32); ++ u32 (*get_tso)(struct net_device *); ++ int (*set_tso)(struct net_device *, u32); ++ int (*self_test_count)(struct net_device *); ++ void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); ++ void (*get_strings)(struct net_device *, u32 stringset, u8 *); ++ int (*phys_id)(struct net_device *, u32); ++ int (*get_stats_count)(struct net_device *); ++ void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, ++ u64 *); ++} *ethtool_ops = NULL; ++ ++#undef SET_ETHTOOL_OPS ++#define SET_ETHTOOL_OPS(netdev, ops) (ethtool_ops = (ops)) ++ ++/* ++ * Some useful ethtool_ops methods that are device independent. If we find that ++ * all drivers want to do the same thing here, we can turn these into dev_() ++ * function calls. ++ */ ++ ++#undef ethtool_op_get_link ++#define ethtool_op_get_link _kc_ethtool_op_get_link ++u32 _kc_ethtool_op_get_link(struct net_device *dev) ++{ ++ return netif_carrier_ok(dev) ? 1 : 0; ++} ++ ++#undef ethtool_op_get_tx_csum ++#define ethtool_op_get_tx_csum _kc_ethtool_op_get_tx_csum ++u32 _kc_ethtool_op_get_tx_csum(struct net_device *dev) ++{ ++#ifdef NETIF_F_IP_CSUM ++ return (dev->features & NETIF_F_IP_CSUM) != 0; ++#else ++ return 0; ++#endif ++} ++ ++#undef ethtool_op_set_tx_csum ++#define ethtool_op_set_tx_csum _kc_ethtool_op_set_tx_csum ++int _kc_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) ++{ ++#ifdef NETIF_F_IP_CSUM ++ if (data) ++#ifdef NETIF_F_IPV6_CSUM ++ dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); ++ else ++ dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); ++#else ++ dev->features |= NETIF_F_IP_CSUM; ++ else ++ dev->features &= ~NETIF_F_IP_CSUM; ++#endif ++#endif ++ ++ return 0; ++} ++ ++#undef ethtool_op_get_sg ++#define ethtool_op_get_sg _kc_ethtool_op_get_sg ++u32 _kc_ethtool_op_get_sg(struct net_device *dev) ++{ ++#ifdef NETIF_F_SG ++ return (dev->features & NETIF_F_SG) != 0; ++#else ++ return 0; ++#endif ++} ++ ++#undef ethtool_op_set_sg ++#define ethtool_op_set_sg _kc_ethtool_op_set_sg ++int _kc_ethtool_op_set_sg(struct net_device *dev, u32 data) ++{ ++#ifdef NETIF_F_SG ++ if (data) ++ dev->features |= NETIF_F_SG; ++ else ++ dev->features &= ~NETIF_F_SG; ++#endif ++ ++ return 0; ++} ++ ++#undef ethtool_op_get_tso ++#define ethtool_op_get_tso _kc_ethtool_op_get_tso ++u32 _kc_ethtool_op_get_tso(struct net_device *dev) ++{ ++#ifdef NETIF_F_TSO ++ return (dev->features & NETIF_F_TSO) != 0; ++#else ++ return 0; ++#endif ++} ++ ++#undef ethtool_op_set_tso ++#define ethtool_op_set_tso _kc_ethtool_op_set_tso ++int _kc_ethtool_op_set_tso(struct net_device *dev, u32 data) ++{ ++#ifdef NETIF_F_TSO ++ if (data) ++ dev->features |= NETIF_F_TSO; ++ else ++ dev->features &= ~NETIF_F_TSO; ++#endif ++ ++ return 0; ++} ++ ++/* Handlers for each ethtool command */ ++ ++static int ethtool_get_settings(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_cmd cmd = { ETHTOOL_GSET }; ++ int err; ++ ++ if (!ethtool_ops->get_settings) ++ return -EOPNOTSUPP; ++ ++ err = ethtool_ops->get_settings(dev, &cmd); ++ if (err < 0) ++ return err; ++ ++ if (copy_to_user(useraddr, &cmd, sizeof(cmd))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_settings(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_cmd cmd; ++ ++ if (!ethtool_ops->set_settings) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&cmd, useraddr, sizeof(cmd))) ++ return -EFAULT; ++ ++ return ethtool_ops->set_settings(dev, &cmd); ++} ++ ++static int ethtool_get_drvinfo(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_drvinfo info; ++ struct ethtool_ops *ops = ethtool_ops; ++ ++ if (!ops->get_drvinfo) ++ return -EOPNOTSUPP; ++ ++ memset(&info, 0, sizeof(info)); ++ info.cmd = ETHTOOL_GDRVINFO; ++ ops->get_drvinfo(dev, &info); ++ ++ if (ops->self_test_count) ++ info.testinfo_len = ops->self_test_count(dev); ++ if (ops->get_stats_count) ++ info.n_stats = ops->get_stats_count(dev); ++ if (ops->get_regs_len) ++ info.regdump_len = ops->get_regs_len(dev); ++ if (ops->get_eeprom_len) ++ info.eedump_len = ops->get_eeprom_len(dev); ++ ++ if (copy_to_user(useraddr, &info, sizeof(info))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_get_regs(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_regs regs; ++ struct ethtool_ops *ops = ethtool_ops; ++ void *regbuf; ++ int reglen, ret; ++ ++ if (!ops->get_regs || !ops->get_regs_len) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(®s, useraddr, sizeof(regs))) ++ return -EFAULT; ++ ++ reglen = ops->get_regs_len(dev); ++ if (regs.len > reglen) ++ regs.len = reglen; ++ ++ regbuf = kmalloc(reglen, GFP_USER); ++ if (!regbuf) ++ return -ENOMEM; ++ ++ ops->get_regs(dev, ®s, regbuf); ++ ++ ret = -EFAULT; ++ if (copy_to_user(useraddr, ®s, sizeof(regs))) ++ goto out; ++ useraddr += offsetof(struct ethtool_regs, data); ++ if (copy_to_user(useraddr, regbuf, reglen)) ++ goto out; ++ ret = 0; ++ ++out: ++ kfree(regbuf); ++ return ret; ++} ++ ++static int ethtool_get_wol(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; ++ ++ if (!ethtool_ops->get_wol) ++ return -EOPNOTSUPP; ++ ++ ethtool_ops->get_wol(dev, &wol); ++ ++ if (copy_to_user(useraddr, &wol, sizeof(wol))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_wol(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_wolinfo wol; ++ ++ if (!ethtool_ops->set_wol) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&wol, useraddr, sizeof(wol))) ++ return -EFAULT; ++ ++ return ethtool_ops->set_wol(dev, &wol); ++} ++ ++static int ethtool_get_msglevel(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_value edata = { ETHTOOL_GMSGLVL }; ++ ++ if (!ethtool_ops->get_msglevel) ++ return -EOPNOTSUPP; ++ ++ edata.data = ethtool_ops->get_msglevel(dev); ++ ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_msglevel(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_value edata; ++ ++ if (!ethtool_ops->set_msglevel) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&edata, useraddr, sizeof(edata))) ++ return -EFAULT; ++ ++ ethtool_ops->set_msglevel(dev, edata.data); ++ return 0; ++} ++ ++static int ethtool_nway_reset(struct net_device *dev) ++{ ++ if (!ethtool_ops->nway_reset) ++ return -EOPNOTSUPP; ++ ++ return ethtool_ops->nway_reset(dev); ++} ++ ++static int ethtool_get_link(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_value edata = { ETHTOOL_GLINK }; ++ ++ if (!ethtool_ops->get_link) ++ return -EOPNOTSUPP; ++ ++ edata.data = ethtool_ops->get_link(dev); ++ ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_get_eeprom(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_eeprom eeprom; ++ struct ethtool_ops *ops = ethtool_ops; ++ u8 *data; ++ int ret; ++ ++ if (!ops->get_eeprom || !ops->get_eeprom_len) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) ++ return -EFAULT; ++ ++ /* Check for wrap and zero */ ++ if (eeprom.offset + eeprom.len <= eeprom.offset) ++ return -EINVAL; ++ ++ /* Check for exceeding total eeprom len */ ++ if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) ++ return -EINVAL; ++ ++ data = kmalloc(eeprom.len, GFP_USER); ++ if (!data) ++ return -ENOMEM; ++ ++ ret = -EFAULT; ++ if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) ++ goto out; ++ ++ ret = ops->get_eeprom(dev, &eeprom, data); ++ if (ret) ++ goto out; ++ ++ ret = -EFAULT; ++ if (copy_to_user(useraddr, &eeprom, sizeof(eeprom))) ++ goto out; ++ if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len)) ++ goto out; ++ ret = 0; ++ ++out: ++ kfree(data); ++ return ret; ++} ++ ++static int ethtool_set_eeprom(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_eeprom eeprom; ++ struct ethtool_ops *ops = ethtool_ops; ++ u8 *data; ++ int ret; ++ ++ if (!ops->set_eeprom || !ops->get_eeprom_len) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) ++ return -EFAULT; ++ ++ /* Check for wrap and zero */ ++ if (eeprom.offset + eeprom.len <= eeprom.offset) ++ return -EINVAL; ++ ++ /* Check for exceeding total eeprom len */ ++ if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) ++ return -EINVAL; ++ ++ data = kmalloc(eeprom.len, GFP_USER); ++ if (!data) ++ return -ENOMEM; ++ ++ ret = -EFAULT; ++ if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) ++ goto out; ++ ++ ret = ops->set_eeprom(dev, &eeprom, data); ++ if (ret) ++ goto out; ++ ++ if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len)) ++ ret = -EFAULT; ++ ++out: ++ kfree(data); ++ return ret; ++} ++ ++static int ethtool_get_coalesce(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE }; ++ ++ if (!ethtool_ops->get_coalesce) ++ return -EOPNOTSUPP; ++ ++ ethtool_ops->get_coalesce(dev, &coalesce); ++ ++ if (copy_to_user(useraddr, &coalesce, sizeof(coalesce))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_coalesce(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_coalesce coalesce; ++ ++ if (!ethtool_ops->get_coalesce) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&coalesce, useraddr, sizeof(coalesce))) ++ return -EFAULT; ++ ++ return ethtool_ops->set_coalesce(dev, &coalesce); ++} ++ ++static int ethtool_get_ringparam(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM }; ++ ++ if (!ethtool_ops->get_ringparam) ++ return -EOPNOTSUPP; ++ ++ ethtool_ops->get_ringparam(dev, &ringparam); ++ ++ if (copy_to_user(useraddr, &ringparam, sizeof(ringparam))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_ringparam(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_ringparam ringparam; ++ ++ if (!ethtool_ops->get_ringparam) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&ringparam, useraddr, sizeof(ringparam))) ++ return -EFAULT; ++ ++ return ethtool_ops->set_ringparam(dev, &ringparam); ++} ++ ++static int ethtool_get_pauseparam(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM }; ++ ++ if (!ethtool_ops->get_pauseparam) ++ return -EOPNOTSUPP; ++ ++ ethtool_ops->get_pauseparam(dev, &pauseparam); ++ ++ if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_pauseparam(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_pauseparam pauseparam; ++ ++ if (!ethtool_ops->get_pauseparam) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam))) ++ return -EFAULT; ++ ++ return ethtool_ops->set_pauseparam(dev, &pauseparam); ++} ++ ++static int ethtool_get_rx_csum(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_value edata = { ETHTOOL_GRXCSUM }; ++ ++ if (!ethtool_ops->get_rx_csum) ++ return -EOPNOTSUPP; ++ ++ edata.data = ethtool_ops->get_rx_csum(dev); ++ ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_rx_csum(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_value edata; ++ ++ if (!ethtool_ops->set_rx_csum) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&edata, useraddr, sizeof(edata))) ++ return -EFAULT; ++ ++ ethtool_ops->set_rx_csum(dev, edata.data); ++ return 0; ++} ++ ++static int ethtool_get_tx_csum(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_value edata = { ETHTOOL_GTXCSUM }; ++ ++ if (!ethtool_ops->get_tx_csum) ++ return -EOPNOTSUPP; ++ ++ edata.data = ethtool_ops->get_tx_csum(dev); ++ ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_tx_csum(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_value edata; ++ ++ if (!ethtool_ops->set_tx_csum) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&edata, useraddr, sizeof(edata))) ++ return -EFAULT; ++ ++ return ethtool_ops->set_tx_csum(dev, edata.data); ++} ++ ++static int ethtool_get_sg(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_value edata = { ETHTOOL_GSG }; ++ ++ if (!ethtool_ops->get_sg) ++ return -EOPNOTSUPP; ++ ++ edata.data = ethtool_ops->get_sg(dev); ++ ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_sg(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_value edata; ++ ++ if (!ethtool_ops->set_sg) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&edata, useraddr, sizeof(edata))) ++ return -EFAULT; ++ ++ return ethtool_ops->set_sg(dev, edata.data); ++} ++ ++static int ethtool_get_tso(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_value edata = { ETHTOOL_GTSO }; ++ ++ if (!ethtool_ops->get_tso) ++ return -EOPNOTSUPP; ++ ++ edata.data = ethtool_ops->get_tso(dev); ++ ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_tso(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_value edata; ++ ++ if (!ethtool_ops->set_tso) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&edata, useraddr, sizeof(edata))) ++ return -EFAULT; ++ ++ return ethtool_ops->set_tso(dev, edata.data); ++} ++ ++static int ethtool_self_test(struct net_device *dev, char *useraddr) ++{ ++ struct ethtool_test test; ++ struct ethtool_ops *ops = ethtool_ops; ++ u64 *data; ++ int ret; ++ ++ if (!ops->self_test || !ops->self_test_count) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&test, useraddr, sizeof(test))) ++ return -EFAULT; ++ ++ test.len = ops->self_test_count(dev); ++ data = kmalloc(test.len * sizeof(u64), GFP_USER); ++ if (!data) ++ return -ENOMEM; ++ ++ ops->self_test(dev, &test, data); ++ ++ ret = -EFAULT; ++ if (copy_to_user(useraddr, &test, sizeof(test))) ++ goto out; ++ useraddr += sizeof(test); ++ if (copy_to_user(useraddr, data, test.len * sizeof(u64))) ++ goto out; ++ ret = 0; ++ ++out: ++ kfree(data); ++ return ret; ++} ++ ++static int ethtool_get_strings(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_gstrings gstrings; ++ struct ethtool_ops *ops = ethtool_ops; ++ u8 *data; ++ int ret; ++ ++ if (!ops->get_strings) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) ++ return -EFAULT; ++ ++ switch (gstrings.string_set) { ++ case ETH_SS_TEST: ++ if (!ops->self_test_count) ++ return -EOPNOTSUPP; ++ gstrings.len = ops->self_test_count(dev); ++ break; ++ case ETH_SS_STATS: ++ if (!ops->get_stats_count) ++ return -EOPNOTSUPP; ++ gstrings.len = ops->get_stats_count(dev); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); ++ if (!data) ++ return -ENOMEM; ++ ++ ops->get_strings(dev, gstrings.string_set, data); ++ ++ ret = -EFAULT; ++ if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) ++ goto out; ++ useraddr += sizeof(gstrings); ++ if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN)) ++ goto out; ++ ret = 0; ++ ++out: ++ kfree(data); ++ return ret; ++} ++ ++static int ethtool_phys_id(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_value id; ++ ++ if (!ethtool_ops->phys_id) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&id, useraddr, sizeof(id))) ++ return -EFAULT; ++ ++ return ethtool_ops->phys_id(dev, id.data); ++} ++ ++static int ethtool_get_stats(struct net_device *dev, void *useraddr) ++{ ++ struct ethtool_stats stats; ++ struct ethtool_ops *ops = ethtool_ops; ++ u64 *data; ++ int ret; ++ ++ if (!ops->get_ethtool_stats || !ops->get_stats_count) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&stats, useraddr, sizeof(stats))) ++ return -EFAULT; ++ ++ stats.n_stats = ops->get_stats_count(dev); ++ data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER); ++ if (!data) ++ return -ENOMEM; ++ ++ ops->get_ethtool_stats(dev, &stats, data); ++ ++ ret = -EFAULT; ++ if (copy_to_user(useraddr, &stats, sizeof(stats))) ++ goto out; ++ useraddr += sizeof(stats); ++ if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64))) ++ goto out; ++ ret = 0; ++ ++out: ++ kfree(data); ++ return ret; ++} ++ ++/* The main entry point in this file. Called from net/core/dev.c */ ++ ++#define ETHTOOL_OPS_COMPAT ++int ethtool_ioctl(struct ifreq *ifr) ++{ ++ struct net_device *dev = __dev_get_by_name(ifr->ifr_name); ++ void *useraddr = (void *) ifr->ifr_data; ++ u32 ethcmd; ++ ++ /* ++ * XXX: This can be pushed down into the ethtool_* handlers that ++ * need it. Keep existing behavior for the moment. ++ */ ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ if (!dev || !netif_device_present(dev)) ++ return -ENODEV; ++ ++ if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd))) ++ return -EFAULT; ++ ++ switch (ethcmd) { ++ case ETHTOOL_GSET: ++ return ethtool_get_settings(dev, useraddr); ++ case ETHTOOL_SSET: ++ return ethtool_set_settings(dev, useraddr); ++ case ETHTOOL_GDRVINFO: ++ return ethtool_get_drvinfo(dev, useraddr); ++ case ETHTOOL_GREGS: ++ return ethtool_get_regs(dev, useraddr); ++ case ETHTOOL_GWOL: ++ return ethtool_get_wol(dev, useraddr); ++ case ETHTOOL_SWOL: ++ return ethtool_set_wol(dev, useraddr); ++ case ETHTOOL_GMSGLVL: ++ return ethtool_get_msglevel(dev, useraddr); ++ case ETHTOOL_SMSGLVL: ++ return ethtool_set_msglevel(dev, useraddr); ++ case ETHTOOL_NWAY_RST: ++ return ethtool_nway_reset(dev); ++ case ETHTOOL_GLINK: ++ return ethtool_get_link(dev, useraddr); ++ case ETHTOOL_GEEPROM: ++ return ethtool_get_eeprom(dev, useraddr); ++ case ETHTOOL_SEEPROM: ++ return ethtool_set_eeprom(dev, useraddr); ++ case ETHTOOL_GCOALESCE: ++ return ethtool_get_coalesce(dev, useraddr); ++ case ETHTOOL_SCOALESCE: ++ return ethtool_set_coalesce(dev, useraddr); ++ case ETHTOOL_GRINGPARAM: ++ return ethtool_get_ringparam(dev, useraddr); ++ case ETHTOOL_SRINGPARAM: ++ return ethtool_set_ringparam(dev, useraddr); ++ case ETHTOOL_GPAUSEPARAM: ++ return ethtool_get_pauseparam(dev, useraddr); ++ case ETHTOOL_SPAUSEPARAM: ++ return ethtool_set_pauseparam(dev, useraddr); ++ case ETHTOOL_GRXCSUM: ++ return ethtool_get_rx_csum(dev, useraddr); ++ case ETHTOOL_SRXCSUM: ++ return ethtool_set_rx_csum(dev, useraddr); ++ case ETHTOOL_GTXCSUM: ++ return ethtool_get_tx_csum(dev, useraddr); ++ case ETHTOOL_STXCSUM: ++ return ethtool_set_tx_csum(dev, useraddr); ++ case ETHTOOL_GSG: ++ return ethtool_get_sg(dev, useraddr); ++ case ETHTOOL_SSG: ++ return ethtool_set_sg(dev, useraddr); ++ case ETHTOOL_GTSO: ++ return ethtool_get_tso(dev, useraddr); ++ case ETHTOOL_STSO: ++ return ethtool_set_tso(dev, useraddr); ++ case ETHTOOL_TEST: ++ return ethtool_self_test(dev, useraddr); ++ case ETHTOOL_GSTRINGS: ++ return ethtool_get_strings(dev, useraddr); ++ case ETHTOOL_PHYS_ID: ++ return ethtool_phys_id(dev, useraddr); ++ case ETHTOOL_GSTATS: ++ return ethtool_get_stats(dev, useraddr); ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return -EOPNOTSUPP; ++} ++ ++#define mii_if_info _kc_mii_if_info ++struct _kc_mii_if_info { ++ int phy_id; ++ int advertising; ++ int phy_id_mask; ++ int reg_num_mask; ++ ++ unsigned int full_duplex : 1; /* is full duplex? */ ++ unsigned int force_media : 1; /* is autoneg. disabled? */ ++ ++ struct net_device *dev; ++ int (*mdio_read) (struct net_device *dev, int phy_id, int location); ++ void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val); ++}; ++ ++struct ethtool_cmd; ++struct mii_ioctl_data; ++ ++#undef mii_link_ok ++#define mii_link_ok _kc_mii_link_ok ++#undef mii_nway_restart ++#define mii_nway_restart _kc_mii_nway_restart ++#undef mii_ethtool_gset ++#define mii_ethtool_gset _kc_mii_ethtool_gset ++#undef mii_ethtool_sset ++#define mii_ethtool_sset _kc_mii_ethtool_sset ++#undef mii_check_link ++#define mii_check_link _kc_mii_check_link ++#undef generic_mii_ioctl ++#define generic_mii_ioctl _kc_generic_mii_ioctl ++extern int _kc_mii_link_ok (struct mii_if_info *mii); ++extern int _kc_mii_nway_restart (struct mii_if_info *mii); ++extern int _kc_mii_ethtool_gset(struct mii_if_info *mii, ++ struct ethtool_cmd *ecmd); ++extern int _kc_mii_ethtool_sset(struct mii_if_info *mii, ++ struct ethtool_cmd *ecmd); ++extern void _kc_mii_check_link (struct mii_if_info *mii); ++extern int _kc_generic_mii_ioctl(struct mii_if_info *mii_if, ++ struct mii_ioctl_data *mii_data, int cmd, ++ unsigned int *duplex_changed); ++ ++ ++struct _kc_pci_dev_ext { ++ struct pci_dev *dev; ++ void *pci_drvdata; ++ struct pci_driver *driver; ++}; ++ ++struct _kc_net_dev_ext { ++ struct net_device *dev; ++ unsigned int carrier; ++}; ++ ++ ++/**************************************/ ++/* mii support */ ++ ++int _kc_mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ++{ ++ struct net_device *dev = mii->dev; ++ u32 advert, bmcr, lpa, nego; ++ ++ ecmd->supported = ++ (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | ++ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | ++ SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); ++ ++ /* only supports twisted-pair */ ++ ecmd->port = PORT_MII; ++ ++ /* only supports internal transceiver */ ++ ecmd->transceiver = XCVR_INTERNAL; ++ ++ /* this isn't fully supported at higher layers */ ++ ecmd->phy_address = mii->phy_id; ++ ++ ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; ++ advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); ++ if (advert & ADVERTISE_10HALF) ++ ecmd->advertising |= ADVERTISED_10baseT_Half; ++ if (advert & ADVERTISE_10FULL) ++ ecmd->advertising |= ADVERTISED_10baseT_Full; ++ if (advert & ADVERTISE_100HALF) ++ ecmd->advertising |= ADVERTISED_100baseT_Half; ++ if (advert & ADVERTISE_100FULL) ++ ecmd->advertising |= ADVERTISED_100baseT_Full; ++ ++ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); ++ lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA); ++ if (bmcr & BMCR_ANENABLE) { ++ ecmd->advertising |= ADVERTISED_Autoneg; ++ ecmd->autoneg = AUTONEG_ENABLE; ++ ++ nego = mii_nway_result(advert & lpa); ++ if (nego == LPA_100FULL || nego == LPA_100HALF) ++ ecmd->speed = SPEED_100; ++ else ++ ecmd->speed = SPEED_10; ++ if (nego == LPA_100FULL || nego == LPA_10FULL) { ++ ecmd->duplex = DUPLEX_FULL; ++ mii->full_duplex = 1; ++ } else { ++ ecmd->duplex = DUPLEX_HALF; ++ mii->full_duplex = 0; ++ } ++ } else { ++ ecmd->autoneg = AUTONEG_DISABLE; ++ ++ ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; ++ ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; ++ } ++ ++ /* ignore maxtxpkt, maxrxpkt for now */ ++ ++ return 0; ++} ++ ++int _kc_mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ++{ ++ struct net_device *dev = mii->dev; ++ ++ if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) ++ return -EINVAL; ++ if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) ++ return -EINVAL; ++ if (ecmd->port != PORT_MII) ++ return -EINVAL; ++ if (ecmd->transceiver != XCVR_INTERNAL) ++ return -EINVAL; ++ if (ecmd->phy_address != mii->phy_id) ++ return -EINVAL; ++ if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) ++ return -EINVAL; ++ ++ /* ignore supported, maxtxpkt, maxrxpkt */ ++ ++ if (ecmd->autoneg == AUTONEG_ENABLE) { ++ u32 bmcr, advert, tmp; ++ ++ if ((ecmd->advertising & (ADVERTISED_10baseT_Half | ++ ADVERTISED_10baseT_Full | ++ ADVERTISED_100baseT_Half | ++ ADVERTISED_100baseT_Full)) == 0) ++ return -EINVAL; ++ ++ /* advertise only what has been requested */ ++ advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); ++ tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4); ++ if (ADVERTISED_10baseT_Half) ++ tmp |= ADVERTISE_10HALF; ++ if (ADVERTISED_10baseT_Full) ++ tmp |= ADVERTISE_10FULL; ++ if (ADVERTISED_100baseT_Half) ++ tmp |= ADVERTISE_100HALF; ++ if (ADVERTISED_100baseT_Full) ++ tmp |= ADVERTISE_100FULL; ++ if (advert != tmp) { ++ mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp); ++ mii->advertising = tmp; ++ } ++ ++ /* turn on autonegotiation, and force a renegotiate */ ++ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); ++ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); ++ mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr); ++ ++ mii->force_media = 0; ++ } else { ++ u32 bmcr, tmp; ++ ++ /* turn off auto negotiation, set speed and duplexity */ ++ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); ++ tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); ++ if (ecmd->speed == SPEED_100) ++ tmp |= BMCR_SPEED100; ++ if (ecmd->duplex == DUPLEX_FULL) { ++ tmp |= BMCR_FULLDPLX; ++ mii->full_duplex = 1; ++ } else ++ mii->full_duplex = 0; ++ if (bmcr != tmp) ++ mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp); ++ ++ mii->force_media = 1; ++ } ++ return 0; ++} ++ ++int _kc_mii_link_ok (struct mii_if_info *mii) ++{ ++ /* first, a dummy read, needed to latch some MII phys */ ++ mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); ++ if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS) ++ return 1; ++ return 0; ++} ++ ++int _kc_mii_nway_restart (struct mii_if_info *mii) ++{ ++ int bmcr; ++ int r = -EINVAL; ++ ++ /* if autoneg is off, it's an error */ ++ bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR); ++ ++ if (bmcr & BMCR_ANENABLE) { ++ bmcr |= BMCR_ANRESTART; ++ mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr); ++ r = 0; ++ } ++ ++ return r; ++} ++ ++void _kc_mii_check_link (struct mii_if_info *mii) ++{ ++ int cur_link = mii_link_ok(mii); ++ int prev_link = netif_carrier_ok(mii->dev); ++ ++ if (cur_link && !prev_link) ++ netif_carrier_on(mii->dev); ++ else if (prev_link && !cur_link) ++ netif_carrier_off(mii->dev); ++} ++ ++int _kc_generic_mii_ioctl(struct mii_if_info *mii_if, ++ struct mii_ioctl_data *mii_data, int cmd, ++ unsigned int *duplex_chg_out) ++{ ++ int rc = 0; ++ unsigned int duplex_changed = 0; ++ ++ if (duplex_chg_out) ++ *duplex_chg_out = 0; ++ ++ mii_data->phy_id &= mii_if->phy_id_mask; ++ mii_data->reg_num &= mii_if->reg_num_mask; ++ ++ switch(cmd) { ++ case SIOCDEVPRIVATE: /* binary compat, remove in 2.5 */ ++ case SIOCGMIIPHY: ++ mii_data->phy_id = mii_if->phy_id; ++ /* fall through */ ++ ++ case SIOCDEVPRIVATE + 1:/* binary compat, remove in 2.5 */ ++ case SIOCGMIIREG: ++ mii_data->val_out = ++ mii_if->mdio_read(mii_if->dev, mii_data->phy_id, ++ mii_data->reg_num); ++ break; ++ ++ case SIOCDEVPRIVATE + 2:/* binary compat, remove in 2.5 */ ++ case SIOCSMIIREG: { ++ u16 val = mii_data->val_in; ++ ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ if (mii_data->phy_id == mii_if->phy_id) { ++ switch(mii_data->reg_num) { ++ case MII_BMCR: { ++ unsigned int new_duplex = 0; ++ if (val & (BMCR_RESET|BMCR_ANENABLE)) ++ mii_if->force_media = 0; ++ else ++ mii_if->force_media = 1; ++ if (mii_if->force_media && ++ (val & BMCR_FULLDPLX)) ++ new_duplex = 1; ++ if (mii_if->full_duplex != new_duplex) { ++ duplex_changed = 1; ++ mii_if->full_duplex = new_duplex; ++ } ++ break; ++ } ++ case MII_ADVERTISE: ++ mii_if->advertising = val; ++ break; ++ default: ++ /* do nothing */ ++ break; ++ } ++ } ++ ++ mii_if->mdio_write(mii_if->dev, mii_data->phy_id, ++ mii_data->reg_num, val); ++ break; ++ } ++ ++ default: ++ rc = -EOPNOTSUPP; ++ break; ++ } ++ ++ if ((rc == 0) && (duplex_chg_out) && (duplex_changed)) ++ *duplex_chg_out = 1; ++ ++ return rc; ++} ++ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/kcompat.h linux-2.6.22-10/drivers/net/e1000e/kcompat.h +--- linux-2.6.22-0/drivers/net/e1000e/kcompat.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/kcompat.h 2008-11-10 17:29:48.000000000 +0100 +@@ -0,0 +1,1629 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _KCOMPAT_H_ ++#define _KCOMPAT_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_E1000E ++ ++/* NAPI enable/disable flags here */ ++ ++#ifdef DRIVER_E1000E ++#define NAPI ++#endif ++ ++#ifdef _E1000_H_ ++#ifdef CONFIG_E1000_NAPI ++#define NAPI ++#endif ++#ifdef E1000_NAPI ++#undef NAPI ++#define NAPI ++#endif ++#ifdef E1000E_NAPI ++#undef NAPI ++#define NAPI ++#endif ++#ifdef E1000_NO_NAPI ++#undef NAPI ++#endif ++#ifdef E1000E_NO_NAPI ++#undef NAPI ++#endif ++#endif ++ ++ ++ ++ ++ ++ ++#ifdef DRIVER_E1000E ++#define adapter_struct e1000_adapter ++#define CONFIG_E1000E_MSIX ++#endif ++ ++ ++ ++ ++/* and finally set defines so that the code sees the changes */ ++#ifdef NAPI ++#ifndef CONFIG_E1000_NAPI ++#define CONFIG_E1000_NAPI ++#endif ++#ifndef CONFIG_E1000E_NAPI ++#define CONFIG_E1000E_NAPI ++#endif ++#else ++#undef CONFIG_E1000_NAPI ++#undef CONFIG_E1000E_NAPI ++#undef CONFIG_IXGB_NAPI ++#endif ++ ++/* packet split disable/enable */ ++#ifdef DISABLE_PACKET_SPLIT ++#undef CONFIG_E1000_DISABLE_PACKET_SPLIT ++#define CONFIG_E1000_DISABLE_PACKET_SPLIT ++#undef CONFIG_IGB_DISABLE_PACKET_SPLIT ++#define CONFIG_IGB_DISABLE_PACKET_SPLIT ++#endif ++ ++/* MSI compatibility code for all kernels and drivers */ ++#ifdef DISABLE_PCI_MSI ++#undef CONFIG_PCI_MSI ++#endif ++#ifndef CONFIG_PCI_MSI ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) ) ++struct msix_entry { ++ u16 vector; /* kernel uses to write allocated vector */ ++ u16 entry; /* driver uses to specify entry, OS writes */ ++}; ++#endif ++#define pci_enable_msi(a) -ENOTSUPP ++#define pci_disable_msi(a) do {} while (0) ++#define pci_enable_msix(a, b, c) -ENOTSUPP ++#define pci_disable_msix(a) do {} while (0) ++#define msi_remove_pci_irq_vectors(a) do {} while (0) ++#endif /* CONFIG_PCI_MSI */ ++#ifdef DISABLE_PM ++#undef CONFIG_PM ++#endif ++ ++#ifdef DISABLE_NET_POLL_CONTROLLER ++#undef CONFIG_NET_POLL_CONTROLLER ++#endif ++ ++#ifndef PMSG_SUSPEND ++#define PMSG_SUSPEND 3 ++#endif ++ ++/* generic boolean compatibility */ ++#undef TRUE ++#undef FALSE ++#define TRUE true ++#define FALSE false ++#ifdef GCC_VERSION ++#if ( GCC_VERSION < 3000 ) ++#define _Bool char ++#endif ++#endif ++#ifndef bool ++#define bool _Bool ++#define true 1 ++#define false 0 ++#endif ++ ++ ++#ifndef module_param ++#define module_param(v,t,p) MODULE_PARM(v, "i"); ++#endif ++ ++#ifndef DMA_64BIT_MASK ++#define DMA_64BIT_MASK 0xffffffffffffffffULL ++#endif ++ ++#ifndef DMA_32BIT_MASK ++#define DMA_32BIT_MASK 0x00000000ffffffffULL ++#endif ++ ++#ifndef PCI_CAP_ID_EXP ++#define PCI_CAP_ID_EXP 0x10 ++#endif ++ ++#ifndef mmiowb ++#ifdef CONFIG_IA64 ++#define mmiowb() asm volatile ("mf.a" ::: "memory") ++#else ++#define mmiowb() ++#endif ++#endif ++ ++#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 ++ ++#ifndef HAVE_FREE_NETDEV ++#define free_netdev(x) kfree(x) ++#endif ++ ++#ifdef HAVE_POLL_CONTROLLER ++#define CONFIG_NET_POLL_CONTROLLER ++#endif ++ ++#ifndef NETDEV_TX_OK ++#define NETDEV_TX_OK 0 ++#endif ++ ++#ifndef NETDEV_TX_BUSY ++#define NETDEV_TX_BUSY 1 ++#endif ++ ++#ifndef NETDEV_TX_LOCKED ++#define NETDEV_TX_LOCKED -1 ++#endif ++ ++#ifndef SKB_DATAREF_SHIFT ++/* if we do not have the infrastructure to detect if skb_header is cloned ++ just return false in all cases */ ++#define skb_header_cloned(x) 0 ++#endif ++ ++#ifndef NETIF_F_GSO ++#define gso_size tso_size ++#define gso_segs tso_segs ++#endif ++ ++#ifndef CHECKSUM_PARTIAL ++#define CHECKSUM_PARTIAL CHECKSUM_HW ++#define CHECKSUM_COMPLETE CHECKSUM_HW ++#endif ++ ++#ifndef __read_mostly ++#define __read_mostly ++#endif ++ ++#ifndef HAVE_NETIF_MSG ++#define HAVE_NETIF_MSG 1 ++enum { ++ NETIF_MSG_DRV = 0x0001, ++ NETIF_MSG_PROBE = 0x0002, ++ NETIF_MSG_LINK = 0x0004, ++ NETIF_MSG_TIMER = 0x0008, ++ NETIF_MSG_IFDOWN = 0x0010, ++ NETIF_MSG_IFUP = 0x0020, ++ NETIF_MSG_RX_ERR = 0x0040, ++ NETIF_MSG_TX_ERR = 0x0080, ++ NETIF_MSG_TX_QUEUED = 0x0100, ++ NETIF_MSG_INTR = 0x0200, ++ NETIF_MSG_TX_DONE = 0x0400, ++ NETIF_MSG_RX_STATUS = 0x0800, ++ NETIF_MSG_PKTDATA = 0x1000, ++ NETIF_MSG_HW = 0x2000, ++ NETIF_MSG_WOL = 0x4000, ++}; ++ ++#else ++#define NETIF_MSG_HW 0x2000 ++#define NETIF_MSG_WOL 0x4000 ++#endif /* HAVE_NETIF_MSG */ ++ ++#ifndef MII_RESV1 ++#define MII_RESV1 0x17 /* Reserved... */ ++#endif ++ ++#ifndef unlikely ++#define unlikely(_x) _x ++#define likely(_x) _x ++#endif ++ ++#ifndef WARN_ON ++#define WARN_ON(x) ++#endif ++ ++#ifndef PCI_DEVICE ++#define PCI_DEVICE(vend,dev) \ ++ .vendor = (vend), .device = (dev), \ ++ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID ++#endif ++ ++#ifndef num_online_cpus ++#define num_online_cpus() smp_num_cpus ++#endif ++ ++#ifndef _LINUX_RANDOM_H ++#include ++#endif ++ ++#ifndef DECLARE_BITMAP ++#ifndef BITS_TO_LONGS ++#define BITS_TO_LONGS(bits) (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) ++#endif ++#define DECLARE_BITMAP(name,bits) long name[BITS_TO_LONGS(bits)] ++#endif ++ ++#ifndef VLAN_HLEN ++#define VLAN_HLEN 4 ++#endif ++ ++#ifndef VLAN_ETH_HLEN ++#define VLAN_ETH_HLEN 18 ++#endif ++ ++#ifndef VLAN_ETH_FRAME_LEN ++#define VLAN_ETH_FRAME_LEN 1518 ++#endif ++ ++#ifndef DCA_GET_TAG_TWO_ARGS ++#define dca3_get_tag(a,b) dca_get_tag(b) ++#endif ++ ++ ++/*****************************************************************************/ ++/* Installations with ethtool version without eeprom, adapter id, or statistics ++ * support */ ++ ++#ifndef ETH_GSTRING_LEN ++#define ETH_GSTRING_LEN 32 ++#endif ++ ++#ifndef ETHTOOL_GSTATS ++#define ETHTOOL_GSTATS 0x1d ++#undef ethtool_drvinfo ++#define ethtool_drvinfo k_ethtool_drvinfo ++struct k_ethtool_drvinfo { ++ u32 cmd; ++ char driver[32]; ++ char version[32]; ++ char fw_version[32]; ++ char bus_info[32]; ++ char reserved1[32]; ++ char reserved2[16]; ++ u32 n_stats; ++ u32 testinfo_len; ++ u32 eedump_len; ++ u32 regdump_len; ++}; ++ ++struct ethtool_stats { ++ u32 cmd; ++ u32 n_stats; ++ u64 data[0]; ++}; ++#endif /* ETHTOOL_GSTATS */ ++ ++#ifndef ETHTOOL_PHYS_ID ++#define ETHTOOL_PHYS_ID 0x1c ++#endif /* ETHTOOL_PHYS_ID */ ++ ++#ifndef ETHTOOL_GSTRINGS ++#define ETHTOOL_GSTRINGS 0x1b ++enum ethtool_stringset { ++ ETH_SS_TEST = 0, ++ ETH_SS_STATS, ++}; ++struct ethtool_gstrings { ++ u32 cmd; /* ETHTOOL_GSTRINGS */ ++ u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/ ++ u32 len; /* number of strings in the string set */ ++ u8 data[0]; ++}; ++#endif /* ETHTOOL_GSTRINGS */ ++ ++#ifndef ETHTOOL_TEST ++#define ETHTOOL_TEST 0x1a ++enum ethtool_test_flags { ++ ETH_TEST_FL_OFFLINE = (1 << 0), ++ ETH_TEST_FL_FAILED = (1 << 1), ++}; ++struct ethtool_test { ++ u32 cmd; ++ u32 flags; ++ u32 reserved; ++ u32 len; ++ u64 data[0]; ++}; ++#endif /* ETHTOOL_TEST */ ++ ++#ifndef ETHTOOL_GEEPROM ++#define ETHTOOL_GEEPROM 0xb ++#undef ETHTOOL_GREGS ++struct ethtool_eeprom { ++ u32 cmd; ++ u32 magic; ++ u32 offset; ++ u32 len; ++ u8 data[0]; ++}; ++ ++struct ethtool_value { ++ u32 cmd; ++ u32 data; ++}; ++#endif /* ETHTOOL_GEEPROM */ ++ ++#ifndef ETHTOOL_GLINK ++#define ETHTOOL_GLINK 0xa ++#endif /* ETHTOOL_GLINK */ ++ ++#ifndef ETHTOOL_GREGS ++#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers */ ++#define ethtool_regs _kc_ethtool_regs ++/* for passing big chunks of data */ ++struct _kc_ethtool_regs { ++ u32 cmd; ++ u32 version; /* driver-specific, indicates different chips/revs */ ++ u32 len; /* bytes */ ++ u8 data[0]; ++}; ++#endif /* ETHTOOL_GREGS */ ++ ++#ifndef ETHTOOL_GMSGLVL ++#define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */ ++#endif ++#ifndef ETHTOOL_SMSGLVL ++#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level, priv. */ ++#endif ++#ifndef ETHTOOL_NWAY_RST ++#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv */ ++#endif ++#ifndef ETHTOOL_GLINK ++#define ETHTOOL_GLINK 0x0000000a /* Get link status */ ++#endif ++#ifndef ETHTOOL_GEEPROM ++#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */ ++#endif ++#ifndef ETHTOOL_SEEPROM ++#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data */ ++#endif ++#ifndef ETHTOOL_GCOALESCE ++#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */ ++/* for configuring coalescing parameters of chip */ ++#define ethtool_coalesce _kc_ethtool_coalesce ++struct _kc_ethtool_coalesce { ++ u32 cmd; /* ETHTOOL_{G,S}COALESCE */ ++ ++ /* How many usecs to delay an RX interrupt after ++ * a packet arrives. If 0, only rx_max_coalesced_frames ++ * is used. ++ */ ++ u32 rx_coalesce_usecs; ++ ++ /* How many packets to delay an RX interrupt after ++ * a packet arrives. If 0, only rx_coalesce_usecs is ++ * used. It is illegal to set both usecs and max frames ++ * to zero as this would cause RX interrupts to never be ++ * generated. ++ */ ++ u32 rx_max_coalesced_frames; ++ ++ /* Same as above two parameters, except that these values ++ * apply while an IRQ is being serviced by the host. Not ++ * all cards support this feature and the values are ignored ++ * in that case. ++ */ ++ u32 rx_coalesce_usecs_irq; ++ u32 rx_max_coalesced_frames_irq; ++ ++ /* How many usecs to delay a TX interrupt after ++ * a packet is sent. If 0, only tx_max_coalesced_frames ++ * is used. ++ */ ++ u32 tx_coalesce_usecs; ++ ++ /* How many packets to delay a TX interrupt after ++ * a packet is sent. If 0, only tx_coalesce_usecs is ++ * used. It is illegal to set both usecs and max frames ++ * to zero as this would cause TX interrupts to never be ++ * generated. ++ */ ++ u32 tx_max_coalesced_frames; ++ ++ /* Same as above two parameters, except that these values ++ * apply while an IRQ is being serviced by the host. Not ++ * all cards support this feature and the values are ignored ++ * in that case. ++ */ ++ u32 tx_coalesce_usecs_irq; ++ u32 tx_max_coalesced_frames_irq; ++ ++ /* How many usecs to delay in-memory statistics ++ * block updates. Some drivers do not have an in-memory ++ * statistic block, and in such cases this value is ignored. ++ * This value must not be zero. ++ */ ++ u32 stats_block_coalesce_usecs; ++ ++ /* Adaptive RX/TX coalescing is an algorithm implemented by ++ * some drivers to improve latency under low packet rates and ++ * improve throughput under high packet rates. Some drivers ++ * only implement one of RX or TX adaptive coalescing. Anything ++ * not implemented by the driver causes these values to be ++ * silently ignored. ++ */ ++ u32 use_adaptive_rx_coalesce; ++ u32 use_adaptive_tx_coalesce; ++ ++ /* When the packet rate (measured in packets per second) ++ * is below pkt_rate_low, the {rx,tx}_*_low parameters are ++ * used. ++ */ ++ u32 pkt_rate_low; ++ u32 rx_coalesce_usecs_low; ++ u32 rx_max_coalesced_frames_low; ++ u32 tx_coalesce_usecs_low; ++ u32 tx_max_coalesced_frames_low; ++ ++ /* When the packet rate is below pkt_rate_high but above ++ * pkt_rate_low (both measured in packets per second) the ++ * normal {rx,tx}_* coalescing parameters are used. ++ */ ++ ++ /* When the packet rate is (measured in packets per second) ++ * is above pkt_rate_high, the {rx,tx}_*_high parameters are ++ * used. ++ */ ++ u32 pkt_rate_high; ++ u32 rx_coalesce_usecs_high; ++ u32 rx_max_coalesced_frames_high; ++ u32 tx_coalesce_usecs_high; ++ u32 tx_max_coalesced_frames_high; ++ ++ /* How often to do adaptive coalescing packet rate sampling, ++ * measured in seconds. Must not be zero. ++ */ ++ u32 rate_sample_interval; ++}; ++#endif /* ETHTOOL_GCOALESCE */ ++ ++#ifndef ETHTOOL_SCOALESCE ++#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config. */ ++#endif ++#ifndef ETHTOOL_GRINGPARAM ++#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */ ++/* for configuring RX/TX ring parameters */ ++#define ethtool_ringparam _kc_ethtool_ringparam ++struct _kc_ethtool_ringparam { ++ u32 cmd; /* ETHTOOL_{G,S}RINGPARAM */ ++ ++ /* Read only attributes. These indicate the maximum number ++ * of pending RX/TX ring entries the driver will allow the ++ * user to set. ++ */ ++ u32 rx_max_pending; ++ u32 rx_mini_max_pending; ++ u32 rx_jumbo_max_pending; ++ u32 tx_max_pending; ++ ++ /* Values changeable by the user. The valid values are ++ * in the range 1 to the "*_max_pending" counterpart above. ++ */ ++ u32 rx_pending; ++ u32 rx_mini_pending; ++ u32 rx_jumbo_pending; ++ u32 tx_pending; ++}; ++#endif /* ETHTOOL_GRINGPARAM */ ++ ++#ifndef ETHTOOL_SRINGPARAM ++#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters, priv. */ ++#endif ++#ifndef ETHTOOL_GPAUSEPARAM ++#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */ ++/* for configuring link flow control parameters */ ++#define ethtool_pauseparam _kc_ethtool_pauseparam ++struct _kc_ethtool_pauseparam { ++ u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */ ++ ++ /* If the link is being auto-negotiated (via ethtool_cmd.autoneg ++ * being true) the user may set 'autoneg' here non-zero to have the ++ * pause parameters be auto-negotiated too. In such a case, the ++ * {rx,tx}_pause values below determine what capabilities are ++ * advertised. ++ * ++ * If 'autoneg' is zero or the link is not being auto-negotiated, ++ * then {rx,tx}_pause force the driver to use/not-use pause ++ * flow control. ++ */ ++ u32 autoneg; ++ u32 rx_pause; ++ u32 tx_pause; ++}; ++#endif /* ETHTOOL_GPAUSEPARAM */ ++ ++#ifndef ETHTOOL_SPAUSEPARAM ++#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters. */ ++#endif ++#ifndef ETHTOOL_GRXCSUM ++#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */ ++#endif ++#ifndef ETHTOOL_SRXCSUM ++#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */ ++#endif ++#ifndef ETHTOOL_GTXCSUM ++#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */ ++#endif ++#ifndef ETHTOOL_STXCSUM ++#define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */ ++#endif ++#ifndef ETHTOOL_GSG ++#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable ++ * (ethtool_value) */ ++#endif ++#ifndef ETHTOOL_SSG ++#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable ++ * (ethtool_value). */ ++#endif ++#ifndef ETHTOOL_TEST ++#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test, priv. */ ++#endif ++#ifndef ETHTOOL_GSTRINGS ++#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */ ++#endif ++#ifndef ETHTOOL_PHYS_ID ++#define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */ ++#endif ++#ifndef ETHTOOL_GSTATS ++#define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */ ++#endif ++#ifndef ETHTOOL_GTSO ++#define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */ ++#endif ++#ifndef ETHTOOL_STSO ++#define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */ ++#endif ++ ++#ifndef ETHTOOL_BUSINFO_LEN ++#define ETHTOOL_BUSINFO_LEN 32 ++#endif ++ ++/*****************************************************************************/ ++/* 2.4.3 => 2.4.0 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) ) ++ ++/**************************************/ ++/* PCI DRIVER API */ ++ ++#ifndef pci_set_dma_mask ++#define pci_set_dma_mask _kc_pci_set_dma_mask ++extern int _kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask); ++#endif ++ ++#ifndef pci_request_regions ++#define pci_request_regions _kc_pci_request_regions ++extern int _kc_pci_request_regions(struct pci_dev *pdev, char *res_name); ++#endif ++ ++#ifndef pci_release_regions ++#define pci_release_regions _kc_pci_release_regions ++extern void _kc_pci_release_regions(struct pci_dev *pdev); ++#endif ++ ++/**************************************/ ++/* NETWORK DRIVER API */ ++ ++#ifndef alloc_etherdev ++#define alloc_etherdev _kc_alloc_etherdev ++extern struct net_device * _kc_alloc_etherdev(int sizeof_priv); ++#endif ++ ++#ifndef is_valid_ether_addr ++#define is_valid_ether_addr _kc_is_valid_ether_addr ++extern int _kc_is_valid_ether_addr(u8 *addr); ++#endif ++ ++/**************************************/ ++/* MISCELLANEOUS */ ++ ++#ifndef INIT_TQUEUE ++#define INIT_TQUEUE(_tq, _routine, _data) \ ++ do { \ ++ INIT_LIST_HEAD(&(_tq)->list); \ ++ (_tq)->sync = 0; \ ++ (_tq)->routine = _routine; \ ++ (_tq)->data = _data; \ ++ } while (0) ++#endif ++ ++#endif /* 2.4.3 => 2.4.0 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,5) ) ++/* Generic MII registers. */ ++#define MII_BMCR 0x00 /* Basic mode control register */ ++#define MII_BMSR 0x01 /* Basic mode status register */ ++#define MII_PHYSID1 0x02 /* PHYS ID 1 */ ++#define MII_PHYSID2 0x03 /* PHYS ID 2 */ ++#define MII_ADVERTISE 0x04 /* Advertisement control reg */ ++#define MII_LPA 0x05 /* Link partner ability reg */ ++#define MII_EXPANSION 0x06 /* Expansion register */ ++/* Basic mode control register. */ ++#define BMCR_FULLDPLX 0x0100 /* Full duplex */ ++#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ ++/* Basic mode status register. */ ++#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ ++#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ ++#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ ++#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ ++#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ ++#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ ++/* Advertisement control register. */ ++#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ ++#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ ++#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ ++#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ ++#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ ++#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ ++ ADVERTISE_100HALF | ADVERTISE_100FULL) ++/* Expansion register for auto-negotiation. */ ++#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */ ++#endif ++ ++/*****************************************************************************/ ++/* 2.4.6 => 2.4.3 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) ) ++ ++#ifndef pci_set_power_state ++#define pci_set_power_state _kc_pci_set_power_state ++extern int _kc_pci_set_power_state(struct pci_dev *dev, int state); ++#endif ++ ++#ifndef pci_save_state ++#define pci_save_state _kc_pci_save_state ++extern int _kc_pci_save_state(struct pci_dev *dev, u32 *buffer); ++#endif ++ ++#ifndef pci_restore_state ++#define pci_restore_state _kc_pci_restore_state ++extern int _kc_pci_restore_state(struct pci_dev *pdev, u32 *buffer); ++#endif ++ ++#ifndef pci_enable_wake ++#define pci_enable_wake _kc_pci_enable_wake ++extern int _kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable); ++#endif ++ ++#ifndef pci_disable_device ++#define pci_disable_device _kc_pci_disable_device ++extern void _kc_pci_disable_device(struct pci_dev *pdev); ++#endif ++ ++/* PCI PM entry point syntax changed, so don't support suspend/resume */ ++#undef CONFIG_PM ++ ++#endif /* 2.4.6 => 2.4.3 */ ++ ++#ifndef HAVE_PCI_SET_MWI ++#define pci_set_mwi(X) pci_write_config_word(X, \ ++ PCI_COMMAND, adapter->hw.bus.pci_cmd_word | \ ++ PCI_COMMAND_INVALIDATE); ++#define pci_clear_mwi(X) pci_write_config_word(X, \ ++ PCI_COMMAND, adapter->hw.bus.pci_cmd_word & \ ++ ~PCI_COMMAND_INVALIDATE); ++#endif ++ ++/*****************************************************************************/ ++/* 2.4.10 => 2.4.9 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) ) ++ ++/**************************************/ ++/* MODULE API */ ++ ++#ifndef MODULE_LICENSE ++ #define MODULE_LICENSE(X) ++#endif ++ ++/**************************************/ ++/* OTHER */ ++ ++#undef min ++#define min(x,y) ({ \ ++ const typeof(x) _x = (x); \ ++ const typeof(y) _y = (y); \ ++ (void) (&_x == &_y); \ ++ _x < _y ? _x : _y; }) ++ ++#undef max ++#define max(x,y) ({ \ ++ const typeof(x) _x = (x); \ ++ const typeof(y) _y = (y); \ ++ (void) (&_x == &_y); \ ++ _x > _y ? _x : _y; }) ++ ++#ifndef list_for_each_safe ++#define list_for_each_safe(pos, n, head) \ ++ for (pos = (head)->next, n = pos->next; pos != (head); \ ++ pos = n, n = pos->next) ++#endif ++ ++#endif /* 2.4.10 -> 2.4.6 */ ++ ++ ++/*****************************************************************************/ ++/* 2.4.13 => 2.4.10 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) ) ++ ++/**************************************/ ++/* PCI DMA MAPPING */ ++ ++#ifndef virt_to_page ++ #define virt_to_page(v) (mem_map + (virt_to_phys(v) >> PAGE_SHIFT)) ++#endif ++ ++#ifndef pci_map_page ++#define pci_map_page _kc_pci_map_page ++extern u64 _kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset, size_t size, int direction); ++#endif ++ ++#ifndef pci_unmap_page ++#define pci_unmap_page _kc_pci_unmap_page ++extern void _kc_pci_unmap_page(struct pci_dev *dev, u64 dma_addr, size_t size, int direction); ++#endif ++ ++/* pci_set_dma_mask takes dma_addr_t, which is only 32-bits prior to 2.4.13 */ ++ ++#undef DMA_32BIT_MASK ++#define DMA_32BIT_MASK 0xffffffff ++#undef DMA_64BIT_MASK ++#define DMA_64BIT_MASK 0xffffffff ++ ++/**************************************/ ++/* OTHER */ ++ ++#ifndef cpu_relax ++#define cpu_relax() rep_nop() ++#endif ++ ++#endif /* 2.4.13 => 2.4.10 */ ++ ++/*****************************************************************************/ ++/* 2.4.17 => 2.4.12 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,17) ) ++ ++#ifndef __devexit_p ++ #define __devexit_p(x) &(x) ++#endif ++ ++#endif /* 2.4.17 => 2.4.13 */ ++ ++/*****************************************************************************/ ++/* 2.4.20 => 2.4.19 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20) ) ++ ++/* we won't support NAPI on less than 2.4.20 */ ++#ifdef NAPI ++#undef CONFIG_E1000_NAPI ++#undef CONFIG_E1000E_NAPI ++#undef CONFIG_IXGB_NAPI ++#endif ++ ++#endif /* 2.4.20 => 2.4.19 */ ++/*****************************************************************************/ ++/* 2.4.22 => 2.4.17 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) ) ++#define pci_name(x) ((x)->slot_name) ++#endif ++ ++/*****************************************************************************/ ++/* 2.4.22 => 2.4.17 */ ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) ) ++#endif ++ ++/*****************************************************************************/ ++/*****************************************************************************/ ++/* 2.4.23 => 2.4.22 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) ) ++/*****************************************************************************/ ++#ifdef 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 /* NAPI */ ++#ifndef netif_tx_disable ++#define netif_tx_disable(x) _kc_netif_tx_disable(x) ++static inline void _kc_netif_tx_disable(struct net_device *dev) ++{ ++ spin_lock_bh(&dev->xmit_lock); ++ netif_stop_queue(dev); ++ spin_unlock_bh(&dev->xmit_lock); ++} ++#endif ++#endif /* 2.4.23 => 2.4.22 */ ++ ++/*****************************************************************************/ ++/* 2.6.4 => 2.6.0 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25) || \ ++ ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && \ ++ LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ) ) ++#define ETHTOOL_OPS_COMPAT ++#endif /* 2.6.4 => 2.6.0 */ ++ ++/*****************************************************************************/ ++/* 2.5.71 => 2.4.x */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71) ) ++#include ++#define sk_protocol protocol ++ ++#define pci_get_device pci_find_device ++#endif /* 2.5.70 => 2.4.x */ ++ ++/*****************************************************************************/ ++/* < 2.4.27 or 2.6.0 <= 2.6.5 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) || \ ++ ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && \ ++ LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) ) ) ++ ++#ifndef netif_msg_init ++#define netif_msg_init _kc_netif_msg_init ++static inline u32 _kc_netif_msg_init(int debug_value, int default_msg_enable_bits) ++{ ++ /* use default */ ++ if (debug_value < 0 || debug_value >= (sizeof(u32) * 8)) ++ return default_msg_enable_bits; ++ if (debug_value == 0) /* no output */ ++ return 0; ++ /* set low N bits */ ++ return (1 << debug_value) -1; ++} ++#endif ++ ++#endif /* < 2.4.27 or 2.6.0 <= 2.6.5 */ ++/*****************************************************************************/ ++#if (( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) ) || \ ++ (( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ) && \ ++ ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3) ))) ++#define netdev_priv(x) x->priv ++#endif ++ ++/*****************************************************************************/ ++/* <= 2.5.0 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ) ++#undef pci_register_driver ++#define pci_register_driver pci_module_init ++ ++#define dev_err(__unused_dev, format, arg...) \ ++ printk(KERN_ERR "%s: " format, pci_name(adapter->pdev) , ## arg) ++ ++/* hlist_* code - double linked lists */ ++struct hlist_head { ++ struct hlist_node *first; ++}; ++ ++struct hlist_node { ++ struct hlist_node *next, **pprev; ++}; ++ ++static inline void __hlist_del(struct hlist_node *n) ++{ ++ struct hlist_node *next = n->next; ++ struct hlist_node **pprev = n->pprev; ++ *pprev = next; ++ if (next) ++ next->pprev = pprev; ++} ++ ++static inline void hlist_del(struct hlist_node *n) ++{ ++ __hlist_del(n); ++ n->next = NULL; ++ n->pprev = NULL; ++} ++ ++static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) ++{ ++ struct hlist_node *first = h->first; ++ n->next = first; ++ if (first) ++ first->pprev = &n->next; ++ h->first = n; ++ n->pprev = &h->first; ++} ++ ++static inline int hlist_empty(const struct hlist_head *h) ++{ ++ return !h->first; ++} ++#define HLIST_HEAD_INIT { .first = NULL } ++#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } ++#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) ++static inline void INIT_HLIST_NODE(struct hlist_node *h) ++{ ++ h->next = NULL; ++ h->pprev = NULL; ++} ++#define hlist_entry(ptr, type, member) container_of(ptr,type,member) ++ ++#define hlist_for_each_entry(tpos, pos, head, member) \ ++ for (pos = (head)->first; \ ++ pos && ({ prefetch(pos->next); 1;}) && \ ++ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ ++ pos = pos->next) ++ ++#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ ++ for (pos = (head)->first; \ ++ pos && ({ n = pos->next; 1; }) && \ ++ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ ++ pos = n) ++ ++/* we ignore GFP here */ ++#define dma_alloc_coherent(dv, sz, dma, gfp) \ ++ pci_alloc_consistent(pdev, (sz), (dma)) ++#define dma_free_coherent(dv, sz, addr, dma_addr) \ ++ pci_free_consistent(pdev, (sz), (addr), (dma_addr)) ++ ++#ifndef might_sleep ++#define might_sleep() ++#endif ++ ++#endif /* <= 2.5.0 */ ++ ++/*****************************************************************************/ ++/* 2.5.28 => 2.4.23 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28) ) ++ ++static inline void _kc_synchronize_irq(void) ++{ ++ synchronize_irq(); ++} ++#undef synchronize_irq ++#define synchronize_irq(X) _kc_synchronize_irq() ++ ++#include ++#define work_struct tq_struct ++#undef INIT_WORK ++#define INIT_WORK(a,b) INIT_TQUEUE(a,(void (*)(void *))b,a) ++#undef container_of ++#define container_of list_entry ++#define schedule_work schedule_task ++#define flush_scheduled_work flush_scheduled_tasks ++ ++#endif /* 2.5.28 => 2.4.17 */ ++ ++/*****************************************************************************/ ++/* 2.6.0 => 2.5.28 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ) ++#define MODULE_INFO(version, _version) ++#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT ++#define CONFIG_E1000_DISABLE_PACKET_SPLIT 1 ++#endif ++#ifndef CONFIG_IGB_DISABLE_PACKET_SPLIT ++#define CONFIG_IGB_DISABLE_PACKET_SPLIT 1 ++#endif ++ ++#define pci_set_consistent_dma_mask(dev,mask) 1 ++ ++#undef dev_put ++#define dev_put(dev) __dev_put(dev) ++ ++#ifndef skb_fill_page_desc ++#define skb_fill_page_desc _kc_skb_fill_page_desc ++extern void _kc_skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size); ++#endif ++ ++#undef ALIGN ++#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1)) ++ ++/* find_first_bit and find_next bit are not defined for most ++ * 2.4 kernels (except for the redhat 2.4.21 kernels ++ */ ++#include ++#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) ++#undef find_next_bit ++#define find_next_bit _kc_find_next_bit ++extern unsigned long _kc_find_next_bit(const unsigned long *addr, ++ unsigned long size, ++ unsigned long offset); ++#define find_first_bit(addr, size) find_next_bit((addr), (size), 0) ++ ++#endif /* 2.6.0 => 2.5.28 */ ++ ++/*****************************************************************************/ ++/* 2.6.4 => 2.6.0 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ) ++#define MODULE_VERSION(_version) MODULE_INFO(version, _version) ++#endif /* 2.6.4 => 2.6.0 */ ++ ++/*****************************************************************************/ ++/* 2.6.5 => 2.6.0 */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) ) ++#define pci_dma_sync_single_for_cpu pci_dma_sync_single ++#define pci_dma_sync_single_for_device pci_dma_sync_single_for_cpu ++#endif /* 2.6.5 => 2.6.0 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6) ) ++/* taken from 2.6 include/linux/bitmap.h */ ++#undef bitmap_zero ++#define bitmap_zero _kc_bitmap_zero ++static inline void _kc_bitmap_zero(unsigned long *dst, int nbits) ++{ ++ if (nbits <= BITS_PER_LONG) ++ *dst = 0UL; ++ else { ++ int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); ++ memset(dst, 0, len); ++ } ++} ++#endif /* < 2.6.6 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) ) ++#undef if_mii ++#define if_mii _kc_if_mii ++static inline struct mii_ioctl_data *_kc_if_mii(struct ifreq *rq) ++{ ++ return (struct mii_ioctl_data *) &rq->ifr_ifru; ++} ++#endif /* < 2.6.7 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) ) ++#define msleep(x) do { set_current_state(TASK_UNINTERRUPTIBLE); \ ++ schedule_timeout((x * HZ)/1000 + 2); \ ++ } while (0) ++ ++#endif /* < 2.6.8 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) ++#include ++#define __iomem ++ ++#ifndef kcalloc ++#define kcalloc(n, size, flags) _kc_kzalloc(((n) * (size)), flags) ++extern void *_kc_kzalloc(size_t size, int flags); ++#endif ++#define MSEC_PER_SEC 1000L ++static inline unsigned int _kc_jiffies_to_msecs(const unsigned long j) ++{ ++#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) ++ return (MSEC_PER_SEC / HZ) * j; ++#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) ++ return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC); ++#else ++ return (j * MSEC_PER_SEC) / HZ; ++#endif ++} ++static inline unsigned long _kc_msecs_to_jiffies(const unsigned int m) ++{ ++ if (m > _kc_jiffies_to_msecs(MAX_JIFFY_OFFSET)) ++ return MAX_JIFFY_OFFSET; ++#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) ++ return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ); ++#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) ++ return m * (HZ / MSEC_PER_SEC); ++#else ++ return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC; ++#endif ++} ++ ++#define msleep_interruptible _kc_msleep_interruptible ++static inline unsigned long _kc_msleep_interruptible(unsigned int msecs) ++{ ++ unsigned long timeout = _kc_msecs_to_jiffies(msecs) + 1; ++ ++ while (timeout && !signal_pending(current)) { ++ __set_current_state(TASK_INTERRUPTIBLE); ++ timeout = schedule_timeout(timeout); ++ } ++ return _kc_jiffies_to_msecs(timeout); ++} ++ ++/* Basic mode control register. */ ++#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ ++ ++#ifdef pci_dma_mapping_error ++#undef pci_dma_mapping_error ++#endif ++#define pci_dma_mapping_error _kc_pci_dma_mapping_error ++static inline int _kc_pci_dma_mapping_error(struct pci_dev *pdev, ++ dma_addr_t dma_addr) ++{ ++ return dma_addr == 0; ++} ++ ++#endif /* < 2.6.9 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6) && \ ++ LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ) ++#ifdef pci_save_state ++#undef pci_save_state ++#endif ++#define pci_save_state(X) { \ ++ int i; \ ++ if (adapter->pci_state) { \ ++ for (i = 0; i < 16; i++) { \ ++ pci_read_config_dword((X), \ ++ i * 4, \ ++ &adapter->pci_state[i]); \ ++ } \ ++ } \ ++} ++ ++#ifdef pci_restore_state ++#undef pci_restore_state ++#endif ++#define pci_restore_state(X) { \ ++ int i; \ ++ if (adapter->pci_state) { \ ++ for (i = 0; i < 16; i++) { \ ++ pci_write_config_dword((X), \ ++ i * 4, \ ++ adapter->pci_state[i]); \ ++ } \ ++ } else { \ ++ for (i = 0; i < 6; i++) { \ ++ pci_write_config_dword((X), \ ++ PCI_BASE_ADDRESS_0 + (i * 4), \ ++ (X)->resource[i].start); \ ++ } \ ++ } \ ++} ++#endif /* 2.4.6 <= x < 2.6.10 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ) ++#ifdef module_param_array_named ++#undef module_param_array_named ++#define module_param_array_named(name, array, type, nump, perm) \ ++ static struct kparam_array __param_arr_##name \ ++ = { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type, \ ++ sizeof(array[0]), array }; \ ++ module_param_call(name, param_array_set, param_array_get, \ ++ &__param_arr_##name, perm) ++#endif /* module_param_array_named */ ++#endif /* < 2.6.10 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) ) ++#define PCI_D0 0 ++#define PCI_D1 1 ++#define PCI_D2 2 ++#define PCI_D3hot 3 ++#define PCI_D3cold 4 ++#define pci_choose_state(pdev,state) state ++#define PMSG_SUSPEND 3 ++ ++#undef NETIF_F_LLTX ++ ++#ifndef ARCH_HAS_PREFETCH ++#define prefetch(X) ++#endif ++ ++#ifndef NET_IP_ALIGN ++#define NET_IP_ALIGN 2 ++#endif ++ ++#define KC_USEC_PER_SEC 1000000L ++#define usecs_to_jiffies _kc_usecs_to_jiffies ++static inline unsigned int _kc_jiffies_to_usecs(const unsigned long j) ++{ ++#if HZ <= KC_USEC_PER_SEC && !(KC_USEC_PER_SEC % HZ) ++ return (KC_USEC_PER_SEC / HZ) * j; ++#elif HZ > KC_USEC_PER_SEC && !(HZ % KC_USEC_PER_SEC) ++ return (j + (HZ / KC_USEC_PER_SEC) - 1)/(HZ / KC_USEC_PER_SEC); ++#else ++ return (j * KC_USEC_PER_SEC) / HZ; ++#endif ++} ++static inline unsigned long _kc_usecs_to_jiffies(const unsigned int m) ++{ ++ if (m > _kc_jiffies_to_usecs(MAX_JIFFY_OFFSET)) ++ return MAX_JIFFY_OFFSET; ++#if HZ <= KC_USEC_PER_SEC && !(KC_USEC_PER_SEC % HZ) ++ return (m + (KC_USEC_PER_SEC / HZ) - 1) / (KC_USEC_PER_SEC / HZ); ++#elif HZ > KC_USEC_PER_SEC && !(HZ % KC_USEC_PER_SEC) ++ return m * (HZ / KC_USEC_PER_SEC); ++#else ++ return (m * HZ + KC_USEC_PER_SEC - 1) / KC_USEC_PER_SEC; ++#endif ++} ++#endif /* < 2.6.11 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) ) ++#include ++#define USE_REBOOT_NOTIFIER ++ ++/* Generic MII registers. */ ++#define MII_CTRL1000 0x09 /* 1000BASE-T control */ ++#define MII_STAT1000 0x0a /* 1000BASE-T status */ ++/* Advertisement control register. */ ++#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ ++#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymmetric pause */ ++/* 1000BASE-T Control register */ ++#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ ++#endif ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) ) ++#define pm_message_t u32 ++#ifndef kzalloc ++#define kzalloc _kc_kzalloc ++extern void *_kc_kzalloc(size_t size, int flags); ++#endif ++ ++/* Generic MII registers. */ ++#define MII_ESTATUS 0x0f /* Extended Status */ ++/* Basic mode status register. */ ++#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ ++/* Extended status register. */ ++#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */ ++#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */ ++#endif ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ) ++#undef HAVE_PCI_ERS ++#else /* 2.6.16 and above */ ++#undef HAVE_PCI_ERS ++#define HAVE_PCI_ERS ++#endif ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ) ++ ++#ifndef IRQF_PROBE_SHARED ++#ifdef SA_PROBEIRQ ++#define IRQF_PROBE_SHARED SA_PROBEIRQ ++#else ++#define IRQF_PROBE_SHARED 0 ++#endif ++#endif ++ ++#ifndef IRQF_SHARED ++#define IRQF_SHARED SA_SHIRQ ++#endif ++ ++#ifndef ARRAY_SIZE ++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) ++#endif ++ ++#ifndef netdev_alloc_skb ++#define netdev_alloc_skb _kc_netdev_alloc_skb ++extern struct sk_buff *_kc_netdev_alloc_skb(struct net_device *dev, ++ unsigned int length); ++#endif ++ ++#ifndef skb_is_gso ++#ifdef NETIF_F_TSO ++#define skb_is_gso _kc_skb_is_gso ++static inline int _kc_skb_is_gso(const struct sk_buff *skb) ++{ ++ return skb_shinfo(skb)->gso_size; ++} ++#else ++#define skb_is_gso(a) 0 ++#endif ++#endif ++ ++#endif /* < 2.6.18 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) ) ++ ++#ifndef DIV_ROUND_UP ++#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) ++#endif ++ ++#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ) ++#ifndef RHEL_RELEASE_CODE ++#define RHEL_RELEASE_CODE 0 ++#endif ++#ifndef RHEL_RELEASE_VERSION ++#define RHEL_RELEASE_VERSION(a,b) 0 ++#endif ++#ifndef AX_RELEASE_CODE ++#define AX_RELEASE_CODE 0 ++#endif ++#ifndef AX_RELEASE_VERSION ++#define AX_RELEASE_VERSION(a,b) 0 ++#endif ++#if (!(( RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(4,4) ) && ( RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,0) ) || ( RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(5,0) ) || (AX_RELEASE_CODE > AX_RELEASE_VERSION(3,0)))) ++typedef irqreturn_t (*irq_handler_t)(int, void*, struct pt_regs *); ++#endif ++typedef irqreturn_t (*new_handler_t)(int, void*); ++static inline irqreturn_t _kc_request_irq(unsigned int irq, new_handler_t handler, unsigned long flags, const char *devname, void *dev_id) ++#else /* 2.4.x */ ++typedef void (*irq_handler_t)(int, void*, struct pt_regs *); ++typedef void (*new_handler_t)(int, void*); ++static inline int _kc_request_irq(unsigned int irq, new_handler_t handler, unsigned long flags, const char *devname, void *dev_id) ++#endif ++{ ++ irq_handler_t new_handler = (irq_handler_t) handler; ++ return request_irq(irq, new_handler, flags, devname, dev_id); ++} ++ ++#undef request_irq ++#define request_irq(irq, handler, flags, devname, dev_id) _kc_request_irq((irq), (handler), (flags), (devname), (dev_id)) ++ ++#define irq_handler_t new_handler_t ++ ++/* pci_restore_state and pci_save_state handles MSI/PCIE from 2.6.19 */ ++#define PCIE_CONFIG_SPACE_LEN 256 ++#define PCI_CONFIG_SPACE_LEN 64 ++#define PCIE_LINK_STATUS 0x12 ++#ifdef DRIVER_E1000E ++#define pci_config_space_ich8lan() { \ ++ if (adapter->flags & FLAG_IS_ICH) \ ++ size = PCIE_CONFIG_SPACE_LEN; \ ++} ++#else ++#define pci_config_space_ich8lan() ++#endif ++#undef pci_save_state ++#define pci_save_state(pdev) _kc_pci_save_state(adapter) ++#define _kc_pci_save_state(adapter) 0; { \ ++ int size = PCI_CONFIG_SPACE_LEN, i; \ ++ u16 pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_EXP); \ ++ u16 pcie_link_status; \ ++ \ ++ if (pcie_cap_offset) { \ ++ if (!pci_read_config_word(pdev, pcie_cap_offset + PCIE_LINK_STATUS, \ ++ &pcie_link_status)) \ ++ size = PCIE_CONFIG_SPACE_LEN; \ ++ } \ ++ pci_config_space_ich8lan(); \ ++ WARN_ON(adapter->config_space != NULL); \ ++ adapter->config_space = kmalloc(size, GFP_KERNEL); \ ++ if (!adapter->config_space) { \ ++ printk(KERN_ERR "Out of memory in pci_save_state\n"); \ ++ return -ENOMEM; \ ++ } \ ++ for (i = 0; i < (size / 4); i++) \ ++ pci_read_config_dword(pdev, i * 4, &adapter->config_space[i]); \ ++} ++#undef pci_restore_state ++#define pci_restore_state(pdev) _kc_pci_restore_state(adapter) ++#define _kc_pci_restore_state(adapter) { \ ++ int size = PCI_CONFIG_SPACE_LEN, i; \ ++ u16 pcie_cap_offset; \ ++ u16 pcie_link_status; \ ++ \ ++ if (adapter->config_space != NULL) { \ ++ pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_EXP); \ ++ if (pcie_cap_offset) { \ ++ if (!pci_read_config_word(pdev, pcie_cap_offset + PCIE_LINK_STATUS, \ ++ &pcie_link_status)) \ ++ size = PCIE_CONFIG_SPACE_LEN; \ ++ } \ ++ pci_config_space_ich8lan(); \ ++ for (i = 0; i < (size / 4); i++) \ ++ pci_write_config_dword(pdev, i * 4, adapter->config_space[i]); \ ++ kfree(adapter->config_space); \ ++ adapter->config_space = NULL; \ ++ } \ ++} ++ ++#endif /* < 2.6.19 */ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ) ++#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) ) ++#undef INIT_WORK ++#define INIT_WORK(_work, _func) \ ++do { \ ++ INIT_LIST_HEAD(&(_work)->entry); \ ++ (_work)->pending = 0; \ ++ (_work)->func = (void (*)(void *))_func; \ ++ (_work)->data = _work; \ ++ init_timer(&(_work)->timer); \ ++} while (0) ++#endif ++ ++#ifndef PCI_VDEVICE ++#define PCI_VDEVICE(ven, dev) \ ++ PCI_VENDOR_ID_##ven, (dev), \ ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0 ++#endif ++ ++#ifndef round_jiffies ++#define round_jiffies(x) x ++#endif ++ ++#define csum_offset csum ++ ++#endif /* < 2.6.20 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) ) ++#define vlan_group_get_device(vg, id) (vg->vlan_devices[id]) ++#define vlan_group_set_device(vg, id, dev) if (vg) vg->vlan_devices[id] = dev; ++#define pci_channel_offline(pdev) (pdev->error_state && \ ++ pdev->error_state != pci_channel_io_normal) ++#endif /* < 2.6.21 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) ) ++#define tcp_hdr(skb) (skb->h.th) ++#define tcp_hdrlen(skb) (skb->h.th->doff << 2) ++#define skb_transport_offset(skb) (skb->h.raw - skb->data) ++#define skb_transport_header(skb) (skb->h.raw) ++#define ipv6_hdr(skb) (skb->nh.ipv6h) ++#define ip_hdr(skb) (skb->nh.iph) ++#define skb_network_offset(skb) (skb->nh.raw - skb->data) ++#define skb_network_header(skb) (skb->nh.raw) ++#define skb_tail_pointer(skb) skb->tail ++#define skb_copy_to_linear_data_offset(skb, offset, from, len) \ ++ memcpy(skb->data + offset, from, len) ++#define skb_network_header_len(skb) (skb->h.raw - skb->nh.raw) ++#define pci_register_driver pci_module_init ++#define skb_mac_header(skb) skb->mac.raw ++ ++#ifdef NETIF_F_MULTI_QUEUE ++#ifndef alloc_etherdev_mq ++#define alloc_etherdev_mq(_a, _b) alloc_etherdev(_a) ++#endif ++#endif /* NETIF_F_MULTI_QUEUE */ ++ ++#ifndef ETH_FCS_LEN ++#define ETH_FCS_LEN 4 ++#endif ++#endif /* < 2.6.22 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) ) ++#undef ETHTOOL_GPERMADDR ++#undef SET_MODULE_OWNER ++#define SET_MODULE_OWNER(dev) do { } while (0) ++#endif /* > 2.6.22 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ) ++/* NAPI API changes in 2.6.24 break everything */ ++struct napi_struct { ++ /* used to look up the real NAPI polling routine */ ++ int (*poll)(struct napi_struct *, int); ++ int weight; ++}; ++#ifdef NAPI ++extern int __kc_adapter_clean(struct net_device *, int *); ++#define netif_rx_complete(netdev, napi) netif_rx_complete(netdev) ++#define netif_rx_schedule_prep(netdev, napi) netif_rx_schedule_prep(netdev) ++#define netif_rx_schedule(netdev, napi) netif_rx_schedule(netdev) ++#define __netif_rx_schedule(netdev, napi) __netif_rx_schedule(netdev) ++#define napi_enable(napi) netif_poll_enable(adapter->netdev) ++#define napi_disable(napi) netif_poll_disable(adapter->netdev) ++#define netif_napi_add(_netdev, _napi, _poll, _weight) \ ++ do { \ ++ struct napi_struct *__napi = _napi; \ ++ _netdev->poll = &(__kc_adapter_clean); \ ++ _netdev->weight = (_weight); \ ++ __napi->poll = &(_poll); \ ++ __napi->weight = (_weight); \ ++ netif_poll_disable(_netdev); \ ++ } while (0) ++#else /* NAPI */ ++#define netif_napi_add(_netdev, _napi, _poll, _weight) \ ++ do { \ ++ struct napi_struct *__napi = _napi; \ ++ _netdev->poll = &(_poll); \ ++ _netdev->weight = (_weight); \ ++ __napi->poll = &(_poll); \ ++ __napi->weight = (_weight); \ ++ } while (0) ++#endif /* NAPI */ ++ ++#undef dev_get_by_name ++#define dev_get_by_name(_a, _b) dev_get_by_name(_b) ++#define __netif_subqueue_stopped(_a, _b) netif_subqueue_stopped(_a, _b) ++#endif /* < 2.6.24 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) ) ++#include ++#endif /* > 2.6.24 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) ) ++#define PM_QOS_CPU_DMA_LATENCY 1 ++ ++#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) ) ++#include ++#define PM_QOS_DEFAULT_VALUE INFINITE_LATENCY ++#define pm_qos_add_requirement(pm_qos_class, name, value) \ ++ set_acceptable_latency(name, value) ++#define pm_qos_remove_requirement(pm_qos_class, name) \ ++ remove_acceptable_latency(name) ++#define pm_qos_update_requirement(pm_qos_class, name, value) \ ++ modify_acceptable_latency(name, value) ++#else ++#define PM_QOS_DEFAULT_VALUE -1 ++#define pm_qos_add_requirement(pm_qos_class, name, value) ++#define pm_qos_remove_requirement(pm_qos_class, name) ++#define pm_qos_update_requirement(pm_qos_class, name, value) { \ ++ if (value != PM_QOS_DEFAULT_VALUE) { \ ++ printk(KERN_WARNING "%s: unable to set PM QoS requirement\n", \ ++ pci_name(adapter->pdev)); \ ++ } \ ++} ++#endif /* > 2.6.18 */ ++ ++#endif /* < 2.6.25 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) ) ++#endif /* < 2.6.26 */ ++ ++/*****************************************************************************/ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) ) ++#ifndef pci_dma_mapping_error ++#define pci_dma_mapping_error(pdev, dma_addr) pci_dma_mapping_error(dma_addr) ++#endif ++#endif /* < 2.6.27 */ ++ ++#ifndef NETIF_F_MULTI_QUEUE ++#define NETIF_F_MULTI_QUEUE 0 ++#define netif_is_multiqueue(a) 0 ++#define netif_stop_subqueue(a, b) ++#define netif_wake_subqueue(a, b) ++#define netif_start_subqueue(a, b) ++#endif /* NETIF_F_MULTI_QUEUE */ ++ ++#endif /* _KCOMPAT_H_ */ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/Makefile linux-2.6.22-10/drivers/net/e1000e/Makefile +--- linux-2.6.22-0/drivers/net/e1000e/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/Makefile 2008-11-10 00:06:14.000000000 +0100 +@@ -0,0 +1,33 @@ ++################################################################################ ++# ++# Intel PRO/1000 Linux driver ++# Copyright(c) 1999 - 2008 Intel Corporation. ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++# Contact Information: ++# Linux NICS ++# e1000-devel Mailing List ++# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++# ++################################################################################ ++ ++obj-$(CONFIG_E1000E) := e1000e.o ++ ++e1000e-objs := e1000_82571.o e1000_ich8lan.o e1000_80003es2lan.o \ ++ netdev.o ethtool.o param.o e1000_mac.o e1000_nvm.o \ ++ e1000_phy.o e1000_manage.o kcompat.o +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/netdev.c linux-2.6.22-10/drivers/net/e1000e/netdev.c +--- linux-2.6.22-0/drivers/net/e1000e/netdev.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/netdev.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,5637 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef NETIF_F_TSO ++#include ++#ifdef NETIF_F_TSO6 ++#include ++#endif ++#endif ++#include ++#include ++#include ++ ++#include "e1000.h" ++ ++#ifdef CONFIG_E1000E_NAPI ++#define DRV_NAPI "-NAPI" ++#else ++#define DRV_NAPI ++#endif ++ ++#define DRV_DEBUG ++ ++#define DRV_VERSION "0.4.1.12" DRV_NAPI DRV_DEBUG ++char e1000e_driver_name[] = "e1000e"; ++const char e1000e_driver_version[] = DRV_VERSION; ++ ++static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ static int global_quad_port_a; /* global port a indication */ ++ struct pci_dev *pdev = adapter->pdev; ++ u16 eeprom_data = 0; ++ int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1; ++ ++ /* tag quad port adapters first, it's used below */ ++ switch (pdev->device) { ++ case E1000_DEV_ID_82571EB_QUAD_COPPER: ++ case E1000_DEV_ID_82571EB_QUAD_FIBER: ++ case E1000_DEV_ID_82571EB_QUAD_COPPER_LP: ++ case E1000_DEV_ID_82571PT_QUAD_COPPER: ++ adapter->flags |= FLAG_IS_QUAD_PORT; ++ /* mark the first port */ ++ if (global_quad_port_a == 0) ++ adapter->flags |= FLAG_IS_QUAD_PORT_A; ++ /* Reset for multiple quad port adapters */ ++ global_quad_port_a++; ++ if (global_quad_port_a == 4) ++ global_quad_port_a = 0; ++ break; ++ default: ++ break; ++ } ++ ++ switch (adapter->hw.mac.type) { ++ case e1000_82571: ++ /* these dual ports don't have WoL on port B at all */ ++ if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) || ++ (pdev->device == E1000_DEV_ID_82571EB_SERDES) || ++ (pdev->device == E1000_DEV_ID_82571EB_COPPER)) && ++ (is_port_b)) ++ adapter->flags &= ~FLAG_HAS_WOL; ++ /* quad ports only support WoL on port A */ ++ if (adapter->flags & FLAG_IS_QUAD_PORT && ++ (!(adapter->flags & FLAG_IS_QUAD_PORT_A))) ++ adapter->flags &= ~FLAG_HAS_WOL; ++ /* Does not support WoL on any port */ ++ if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD) ++ adapter->flags &= ~FLAG_HAS_WOL; ++ break; ++ ++ case e1000_82573: ++ if (pdev->device == E1000_DEV_ID_82573L) { ++ adapter->hw.nvm.ops.read(&adapter->hw, NVM_INIT_3GIO_3, ++ 1, &eeprom_data); ++ if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) ++ adapter->flags |= FLAG_HAS_JUMBO_FRAMES; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct e1000_info e1000_82571_info = { ++ .mac = e1000_82571, ++ .flags = FLAG_HAS_HW_VLAN_FILTER ++ | FLAG_HAS_JUMBO_FRAMES ++ | FLAG_HAS_WOL ++ | FLAG_APME_IN_CTRL3 ++ | FLAG_RX_CSUM_ENABLED ++ | FLAG_HAS_CTRLEXT_ON_LOAD ++ | FLAG_HAS_SMART_POWER_DOWN ++ | FLAG_RESET_OVERWRITES_LAA /* errata */ ++ | FLAG_TARC_SPEED_MODE_BIT /* errata */ ++ | FLAG_APME_CHECK_PORT_B, ++ .pba = 38, ++ .init_ops = e1000_init_function_pointers_82571, ++ .get_variants = e1000_get_variants_82571, ++}; ++ ++static struct e1000_info e1000_82572_info = { ++ .mac = e1000_82572, ++ .flags = FLAG_HAS_HW_VLAN_FILTER ++ | FLAG_HAS_JUMBO_FRAMES ++ | FLAG_HAS_WOL ++ | FLAG_APME_IN_CTRL3 ++ | FLAG_RX_CSUM_ENABLED ++ | FLAG_HAS_CTRLEXT_ON_LOAD ++ | FLAG_TARC_SPEED_MODE_BIT, /* errata */ ++ .pba = 38, ++ .init_ops = e1000_init_function_pointers_82571, ++ .get_variants = e1000_get_variants_82571, ++}; ++ ++static struct e1000_info e1000_82573_info = { ++ .mac = e1000_82573, ++ .flags = FLAG_HAS_HW_VLAN_FILTER ++ | FLAG_HAS_WOL ++ | FLAG_APME_IN_CTRL3 ++ | FLAG_RX_CSUM_ENABLED ++ | FLAG_HAS_SMART_POWER_DOWN ++ | FLAG_HAS_AMT ++ | FLAG_HAS_ASPM ++ | FLAG_HAS_ERT ++ | FLAG_HAS_SWSM_ON_LOAD, ++ .pba = 20, ++ .init_ops = e1000_init_function_pointers_82571, ++ .get_variants = e1000_get_variants_82571, ++}; ++ ++static struct e1000_info e1000_82574_info = { ++ .mac = e1000_82574, ++ .flags = FLAG_HAS_HW_VLAN_FILTER ++#ifdef CONFIG_E1000E_MSIX ++ | FLAG_HAS_MSIX ++#endif ++ | FLAG_HAS_JUMBO_FRAMES ++ | FLAG_HAS_WOL ++ | FLAG_APME_IN_CTRL3 ++ | FLAG_RX_CSUM_ENABLED ++ | FLAG_HAS_SMART_POWER_DOWN ++ | FLAG_HAS_AMT ++ | FLAG_HAS_ASPM ++ | FLAG_HAS_CTRLEXT_ON_LOAD, ++ .pba = 20, ++ .init_ops = e1000_init_function_pointers_82571, ++ .get_variants = e1000_get_variants_82571, ++}; ++ ++static struct e1000_info e1000_es2_info = { ++ .mac = e1000_80003es2lan, ++ .flags = FLAG_HAS_HW_VLAN_FILTER ++ | FLAG_HAS_JUMBO_FRAMES ++ | FLAG_HAS_WOL ++ | FLAG_APME_IN_CTRL3 ++ | FLAG_RX_CSUM_ENABLED ++ | FLAG_HAS_CTRLEXT_ON_LOAD ++ | FLAG_RX_NEEDS_RESTART /* errata */ ++ | FLAG_TARC_SET_BIT_ZERO /* errata */ ++ | FLAG_APME_CHECK_PORT_B ++ | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ ++ | FLAG_TIPG_MEDIUM_FOR_80003ESLAN, ++ .pba = 38, ++ .init_ops = e1000_init_function_pointers_80003es2lan, ++ .get_variants = NULL, ++}; ++ ++static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) ++{ ++ if (adapter->hw.phy.type == e1000_phy_ife) ++ adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; ++ ++ if ((adapter->hw.mac.type == e1000_ich8lan) && ++ (adapter->hw.phy.type == e1000_phy_igp_3)) ++ adapter->flags |= FLAG_LSC_GIG_SPEED_DROP; ++ ++ return 0; ++} ++ ++static struct e1000_info e1000_ich8_info = { ++ .mac = e1000_ich8lan, ++ .flags = FLAG_HAS_WOL ++ | FLAG_IS_ICH ++ | FLAG_RX_CSUM_ENABLED ++ | FLAG_HAS_CTRLEXT_ON_LOAD ++ | FLAG_HAS_AMT ++ | FLAG_HAS_FLASH ++ | FLAG_APME_IN_WUC, ++ .pba = 8, ++ .init_ops = e1000_init_function_pointers_ich8lan, ++ .get_variants = e1000_get_variants_ich8lan, ++}; ++ ++static struct e1000_info e1000_ich9_info = { ++ .mac = e1000_ich9lan, ++ .flags = FLAG_HAS_JUMBO_FRAMES ++ | FLAG_IS_ICH ++ | FLAG_HAS_WOL ++ | FLAG_RX_CSUM_ENABLED ++ | FLAG_HAS_CTRLEXT_ON_LOAD ++ | FLAG_HAS_AMT ++ | FLAG_HAS_ERT ++ | FLAG_HAS_FLASH ++ | FLAG_APME_IN_WUC, ++ .pba = 10, ++ .init_ops = e1000_init_function_pointers_ich8lan, ++ .get_variants = e1000_get_variants_ich8lan, ++}; ++ ++static struct e1000_info e1000_ich10_info = { ++ .mac = e1000_ich10lan, ++ .flags = FLAG_HAS_JUMBO_FRAMES ++ | FLAG_IS_ICH ++ | FLAG_HAS_WOL ++ | FLAG_RX_CSUM_ENABLED ++ | FLAG_HAS_CTRLEXT_ON_LOAD ++ | FLAG_HAS_AMT ++ | FLAG_HAS_ERT ++ | FLAG_HAS_FLASH ++ | FLAG_APME_IN_WUC, ++ .pba = 10, ++ .init_ops = e1000_init_function_pointers_ich8lan, ++ .get_variants = e1000_get_variants_ich8lan, ++}; ++ ++static const struct e1000_info *e1000_info_tbl[] = { ++ [board_82571] = &e1000_82571_info, ++ [board_82572] = &e1000_82572_info, ++ [board_82573] = &e1000_82573_info, ++ [board_82574] = &e1000_82574_info, ++ [board_80003es2lan] = &e1000_es2_info, ++ [board_ich8lan] = &e1000_ich8_info, ++ [board_ich9lan] = &e1000_ich9_info, ++ [board_ich10lan] = &e1000_ich10_info, ++}; ++ ++ ++void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value) ++{ ++ struct e1000_adapter *adapter = hw->back; ++ ++ pci_read_config_word(adapter->pdev, reg, value); ++} ++ ++s32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) ++{ ++ struct e1000_adapter *adapter = hw->back; ++ u16 cap_offset; ++ ++ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); ++ if (!cap_offset) ++ return -E1000_ERR_CONFIG; ++ ++ pci_read_config_word(adapter->pdev, cap_offset + reg, value); ++ ++ return E1000_SUCCESS; ++} ++ ++s32 e1000_alloc_zeroed_dev_spec_struct(struct e1000_hw *hw, u32 size) ++{ ++ hw->dev_spec = kzalloc(size, GFP_KERNEL); ++ ++ if (!hw->dev_spec) ++ return -ENOMEM; ++ ++ return E1000_SUCCESS; ++} ++ ++void e1000_free_dev_spec_struct(struct e1000_hw *hw) ++{ ++ if (!hw->dev_spec) ++ return; ++ ++ kfree(hw->dev_spec); ++} ++ ++/** ++ * e1000_desc_unused - calculate if we have unused descriptors ++ **/ ++static int e1000_desc_unused(struct e1000_ring *ring) ++{ ++ if (ring->next_to_clean > ring->next_to_use) ++ return ring->next_to_clean - ring->next_to_use - 1; ++ ++ return ring->count + ring->next_to_clean - ring->next_to_use - 1; ++} ++ ++/** ++ * e1000_receive_skb - helper function to handle Rx indications ++ * @adapter: board private structure ++ * @status: descriptor status field as written by hardware ++ * @vlan: descriptor vlan field as written by hardware (no le/be conversion) ++ * @skb: pointer to sk_buff to be indicated to stack ++ **/ ++static void e1000_receive_skb(struct e1000_adapter *adapter, ++ struct net_device *netdev, ++ struct sk_buff *skb, ++ u8 status, u16 vlan) ++{ ++ skb->protocol = eth_type_trans(skb, netdev); ++ ++#ifdef CONFIG_E1000E_NAPI ++ if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) ++ vlan_hwaccel_receive_skb(skb, adapter->vlgrp, ++ le16_to_cpu(vlan) & ++ E1000_RXD_SPC_VLAN_MASK); ++ else ++ netif_receive_skb(skb); ++#else ++ if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) ++ vlan_hwaccel_rx(skb, adapter->vlgrp, ++ le16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK); ++ else ++ netif_rx(skb); ++#endif ++ ++ netdev->last_rx = jiffies; ++} ++ ++/** ++ * e1000_rx_checksum - Receive Checksum Offload for 82543 ++ * @adapter: board private structure ++ * @status_err: receive descriptor status and error fields ++ * @csum: receive descriptor csum field ++ * @sk_buff: socket buffer with received data ++ **/ ++static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, ++ u32 csum, struct sk_buff *skb) ++{ ++ u16 status = (u16)status_err; ++ u8 errors = (u8)(status_err >> 24); ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ /* Ignore Checksum bit is set */ ++ if (status & E1000_RXD_STAT_IXSM) ++ return; ++ /* TCP/UDP checksum error bit is set */ ++ if (errors & E1000_RXD_ERR_TCPE) { ++ /* let the stack verify checksum errors */ ++ adapter->hw_csum_err++; ++ return; ++ } ++ ++ /* TCP/UDP Checksum has not been calculated */ ++ if (!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) ++ return; ++ ++ /* It must be a TCP or UDP packet with a valid checksum */ ++ if (status & E1000_RXD_STAT_TCPCS) { ++ /* TCP checksum is good */ ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else { ++ /* ++ * 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_COMPLETE; ++ } ++ adapter->hw_csum_good++; ++} ++ ++/** ++ * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended ++ * @adapter: address of board private structure ++ **/ ++static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, ++ int cleaned_count) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ struct e1000_rx_desc *rx_desc; ++ struct e1000_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]; ++ ++ while (cleaned_count--) { ++ skb = buffer_info->skb; ++ if (skb) { ++ skb_trim(skb, 0); ++ goto map_skb; ++ } ++ ++ skb = netdev_alloc_skb(netdev, bufsz); ++ if (!skb) { ++ /* Better luck next round */ ++ 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); ++ ++ buffer_info->skb = skb; ++map_skb: ++ buffer_info->dma = pci_map_single(pdev, skb->data, ++ adapter->rx_buffer_len, ++ PCI_DMA_FROMDEVICE); ++ if (pci_dma_mapping_error(pdev, buffer_info->dma)) { ++ dev_err(&pdev->dev, "RX DMA map failed\n"); ++ adapter->rx_dma_failed++; ++ break; ++ } ++ ++ rx_desc = E1000_RX_DESC(*rx_ring, i); ++ rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); ++ ++ i++; ++ if (i == rx_ring->count) ++ i = 0; ++ buffer_info = &rx_ring->buffer_info[i]; ++ } ++ ++ if (rx_ring->next_to_use != i) { ++ rx_ring->next_to_use = i; ++ if (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->tail); ++ } ++} ++ ++/** ++ * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split ++ * @adapter: address of board private structure ++ **/ ++static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, ++ int cleaned_count) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ union e1000_rx_desc_packet_split *rx_desc; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ struct e1000_buffer *buffer_info; ++ struct e1000_ps_page *ps_page; ++ struct sk_buff *skb; ++ unsigned int i, j; ++ ++ i = rx_ring->next_to_use; ++ buffer_info = &rx_ring->buffer_info[i]; ++ ++ while (cleaned_count--) { ++ rx_desc = E1000_RX_DESC_PS(*rx_ring, i); ++ ++ for (j = 0; j < PS_PAGE_BUFFERS; j++) { ++ ps_page = &buffer_info->ps_pages[j]; ++ if (j >= adapter->rx_ps_pages) { ++ /* all unused desc entries get hw null ptr */ ++ rx_desc->read.buffer_addr[j+1] = ~0; ++ continue; ++ } ++ if (!ps_page->page) { ++ ps_page->page = alloc_page(GFP_ATOMIC); ++ if (!ps_page->page) { ++ adapter->alloc_rx_buff_failed++; ++ goto no_buffers; ++ } ++ ps_page->dma = pci_map_page(pdev, ++ ps_page->page, ++ 0, PAGE_SIZE, ++ PCI_DMA_FROMDEVICE); ++ if (pci_dma_mapping_error(pdev, ps_page->dma)) { ++ dev_err(&adapter->pdev->dev, ++ "RX DMA page map failed\n"); ++ adapter->rx_dma_failed++; ++ goto no_buffers; ++ } ++ } ++ /* ++ * Refresh the desc even if buffer_addrs ++ * didn't change because each write-back ++ * erases this info. ++ */ ++ rx_desc->read.buffer_addr[j+1] = ++ cpu_to_le64(ps_page->dma); ++ } ++ ++ skb = netdev_alloc_skb(netdev, ++ adapter->rx_ps_bsize0 + NET_IP_ALIGN); ++ ++ if (!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); ++ ++ buffer_info->skb = skb; ++ buffer_info->dma = pci_map_single(pdev, skb->data, ++ adapter->rx_ps_bsize0, ++ PCI_DMA_FROMDEVICE); ++ if (pci_dma_mapping_error(pdev, buffer_info->dma)) { ++ dev_err(&pdev->dev, "RX DMA map failed\n"); ++ adapter->rx_dma_failed++; ++ /* cleanup skb */ ++ dev_kfree_skb_any(skb); ++ buffer_info->skb = NULL; ++ break; ++ } ++ ++ rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma); ++ ++ i++; ++ if (i == rx_ring->count) ++ i = 0; ++ buffer_info = &rx_ring->buffer_info[i]; ++ } ++ ++no_buffers: ++ if (rx_ring->next_to_use != i) { ++ rx_ring->next_to_use = i; ++ ++ if (!(i--)) ++ 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, adapter->hw.hw_addr + rx_ring->tail); ++ } ++} ++ ++#ifdef CONFIG_E1000E_NAPI ++/** ++ * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers ++ * @adapter: address of board private structure ++ * @rx_ring: pointer to receive ring structure ++ * @cleaned_count: number of buffers to allocate this pass ++ **/ ++ ++static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, ++ int cleaned_count) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_rx_desc *rx_desc; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ struct e1000_buffer *buffer_info; ++ struct sk_buff *skb; ++ unsigned int i; ++ unsigned int bufsz = 256 - ++ 16 /* for skb_reserve */ - ++ NET_IP_ALIGN; ++ ++ i = rx_ring->next_to_use; ++ buffer_info = &rx_ring->buffer_info[i]; ++ ++ while (cleaned_count--) { ++ skb = buffer_info->skb; ++ if (skb) { ++ skb_trim(skb, 0); ++ goto check_page; ++ } ++ ++ skb = netdev_alloc_skb(netdev, bufsz); ++ if (unlikely(!skb)) { ++ /* Better luck next round */ ++ 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); ++ ++ buffer_info->skb = skb; ++check_page: ++ /* allocate a new page if necessary */ ++ if (!buffer_info->page) { ++ buffer_info->page = alloc_page(GFP_ATOMIC); ++ if (unlikely(!buffer_info->page)) { ++ adapter->alloc_rx_buff_failed++; ++ break; ++ } ++ } ++ ++ if (!buffer_info->dma) ++ buffer_info->dma = pci_map_page(pdev, ++ buffer_info->page, 0, ++ PAGE_SIZE, ++ PCI_DMA_FROMDEVICE); ++ ++ rx_desc = E1000_RX_DESC(*rx_ring, i); ++ rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); ++ ++ if (unlikely(++i == rx_ring->count)) ++ i = 0; ++ buffer_info = &rx_ring->buffer_info[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(); ++ writel(i, adapter->hw.hw_addr + rx_ring->tail); ++ } ++} ++#endif /* CONFIG_E1000E_NAPI */ ++ ++/** ++ * e1000_clean_rx_irq - Send received data up the network stack; legacy ++ * @adapter: board private structure ++ * ++ * the return value indicates whether actual cleaning was done, there ++ * is no guarantee that everything was cleaned ++ **/ ++#ifdef CONFIG_E1000E_NAPI ++static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, ++ int *work_done, int work_to_do) ++#else ++static bool e1000_clean_rx_irq(struct e1000_adapter *adapter) ++#endif ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ struct e1000_rx_desc *rx_desc, *next_rxd; ++ struct e1000_buffer *buffer_info, *next_buffer; ++ u32 length; ++ unsigned int i; ++ int cleaned_count = 0; ++ bool cleaned = 0; ++ unsigned int total_rx_bytes = 0, total_rx_packets = 0; ++ ++ i = rx_ring->next_to_clean; ++ rx_desc = E1000_RX_DESC(*rx_ring, i); ++ buffer_info = &rx_ring->buffer_info[i]; ++ ++ while (rx_desc->status & E1000_RXD_STAT_DD) { ++ struct sk_buff *skb; ++ u8 status; ++ ++#ifdef CONFIG_E1000E_NAPI ++ if (*work_done >= work_to_do) ++ break; ++ (*work_done)++; ++#endif ++ ++ status = rx_desc->status; ++ skb = buffer_info->skb; ++ buffer_info->skb = NULL; ++ ++ prefetch(skb->data - NET_IP_ALIGN); ++ ++ i++; ++ 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 = 1; ++ cleaned_count++; ++ pci_unmap_single(pdev, ++ buffer_info->dma, ++ adapter->rx_buffer_len, ++ PCI_DMA_FROMDEVICE); ++ buffer_info->dma = 0; ++ ++ length = le16_to_cpu(rx_desc->length); ++ ++ /* !EOP means multiple descriptors were used to store a single ++ * packet, also make sure the frame isn't just CRC only */ ++ if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) { ++ /* All receives must fit into a single buffer */ ++ e_dbg("Receive packet consumed multiple buffers\n"); ++ /* recycle */ ++ buffer_info->skb = skb; ++ goto next_desc; ++ } ++ ++ if (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { ++ /* recycle */ ++ buffer_info->skb = skb; ++ goto next_desc; ++ } ++ ++ 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 */ ++ } ++ /* end copybreak code */ ++ skb_put(skb, length); ++ ++ /* Receive Checksum Offload */ ++ e1000_rx_checksum(adapter, ++ (u32)(status) | ++ ((u32)(rx_desc->errors) << 24), ++ le16_to_cpu(rx_desc->csum), skb); ++ ++ e1000_receive_skb(adapter, netdev, skb,status,rx_desc->special); ++ ++next_desc: ++ rx_desc->status = 0; ++ ++ /* return some buffers to hardware, one at a time is too slow */ ++ if (cleaned_count >= E1000_RX_BUFFER_WRITE) { ++ adapter->alloc_rx_buf(adapter, cleaned_count); ++ cleaned_count = 0; ++ } ++ ++ /* use prefetched values */ ++ rx_desc = next_rxd; ++ buffer_info = next_buffer; ++ } ++ rx_ring->next_to_clean = i; ++ ++ cleaned_count = e1000_desc_unused(rx_ring); ++ if (cleaned_count) ++ adapter->alloc_rx_buf(adapter, 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; ++} ++ ++static void e1000_put_txbuf(struct e1000_adapter *adapter, ++ struct e1000_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; ++ } ++} ++ ++static void e1000_print_tx_hang(struct e1000_adapter *adapter) ++{ ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ unsigned int i = tx_ring->next_to_clean; ++ unsigned int eop = tx_ring->buffer_info[i].next_to_watch; ++ struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop); ++ ++ /* detected Tx unit hang */ ++ e_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" ++ " 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->head), ++ readl(adapter->hw.hw_addr + tx_ring->tail), ++ tx_ring->next_to_use, ++ tx_ring->next_to_clean, ++ tx_ring->buffer_info[eop].time_stamp, ++ eop, ++ jiffies, ++ eop_desc->upper.fields.status); ++} ++ ++/** ++ * @e1000_alloc_ring - allocate memory for a ring structure ++ **/ ++static int e1000_alloc_ring_dma(struct e1000_adapter *adapter, ++ struct e1000_ring *ring) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ ++ ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma, ++ GFP_KERNEL); ++ if (!ring->desc) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++/** ++ * e1000e_setup_tx_resources - allocate Tx resources (Descriptors) ++ * @adapter: board private structure ++ * ++ * Return 0 on success, negative on failure ++ **/ ++int e1000_setup_tx_resources(struct e1000_adapter *adapter) ++{ ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ int err = -ENOMEM, size; ++ ++ size = sizeof(struct e1000_buffer) * tx_ring->count; ++ tx_ring->buffer_info = vmalloc(size); ++ if (!tx_ring->buffer_info) ++ goto err; ++ memset(tx_ring->buffer_info, 0, size); ++ ++ /* round up to nearest 4K */ ++ tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); ++ tx_ring->size = ALIGN(tx_ring->size, 4096); ++ ++ err = e1000_alloc_ring_dma(adapter, tx_ring); ++ if (err) ++ goto err; ++ ++ tx_ring->next_to_use = 0; ++ tx_ring->next_to_clean = 0; ++ spin_lock_init(&adapter->tx_queue_lock); ++ ++ return 0; ++err: ++ vfree(tx_ring->buffer_info); ++ e_err("Unable to allocate memory for the transmit descriptor ring\n"); ++ return err; ++} ++ ++/** ++ * e1000e_setup_rx_resources - allocate Rx resources (Descriptors) ++ * @adapter: board private structure ++ * ++ * Returns 0 on success, negative on failure ++ **/ ++int e1000_setup_rx_resources(struct e1000_adapter *adapter) ++{ ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ struct e1000_buffer *buffer_info; ++ int i, size, desc_len, err = -ENOMEM; ++ ++ size = sizeof(struct e1000_buffer) * rx_ring->count; ++ rx_ring->buffer_info = vmalloc(size); ++ if (!rx_ring->buffer_info) ++ goto err; ++ memset(rx_ring->buffer_info, 0, size); ++ ++ for (i = 0; i < rx_ring->count; i++) { ++ buffer_info = &rx_ring->buffer_info[i]; ++ buffer_info->ps_pages = kcalloc(PS_PAGE_BUFFERS, ++ sizeof(struct e1000_ps_page), ++ GFP_KERNEL); ++ if (!buffer_info->ps_pages) ++ goto err_pages; ++ } ++ ++ desc_len = sizeof(union e1000_rx_desc_packet_split); ++ ++ /* Round up to nearest 4K */ ++ rx_ring->size = rx_ring->count * desc_len; ++ rx_ring->size = ALIGN(rx_ring->size, 4096); ++ ++ err = e1000_alloc_ring_dma(adapter, rx_ring); ++ if (err) ++ goto err_pages; ++ ++ rx_ring->next_to_clean = 0; ++ rx_ring->next_to_use = 0; ++ rx_ring->rx_skb_top = NULL; ++ ++ return 0; ++ ++err_pages: ++ for (i = 0; i < rx_ring->count; i++) { ++ buffer_info = &rx_ring->buffer_info[i]; ++ kfree(buffer_info->ps_pages); ++ } ++err: ++ vfree(rx_ring->buffer_info); ++ e_err("Unable to allocate memory for the transmit descriptor ring\n"); ++ return err; ++} ++ ++/** ++ * e1000_clean_tx_ring - Free Tx Buffers ++ * @adapter: board private structure ++ **/ ++static void e1000_clean_tx_ring(struct e1000_adapter *adapter) ++{ ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ struct e1000_buffer *buffer_info; ++ unsigned long size; ++ unsigned int i; ++ ++ for (i = 0; i < tx_ring->count; i++) { ++ buffer_info = &tx_ring->buffer_info[i]; ++ e1000_put_txbuf(adapter, buffer_info); ++ } ++ ++ size = sizeof(struct e1000_buffer) * tx_ring->count; ++ memset(tx_ring->buffer_info, 0, size); ++ ++ memset(tx_ring->desc, 0, tx_ring->size); ++ ++ tx_ring->next_to_use = 0; ++ tx_ring->next_to_clean = 0; ++ ++ writel(0, adapter->hw.hw_addr + tx_ring->head); ++ writel(0, adapter->hw.hw_addr + tx_ring->tail); ++} ++ ++/** ++ * e1000_free_tx_resources - Free Tx Resources per Queue ++ * @adapter: board private structure ++ * ++ * Free all transmit software resources ++ **/ ++void e1000_free_tx_resources(struct e1000_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ ++ e1000_clean_tx_ring(adapter); ++ ++ vfree(tx_ring->buffer_info); ++ tx_ring->buffer_info = NULL; ++ ++ dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc, ++ tx_ring->dma); ++ tx_ring->desc = NULL; ++} ++ ++/** ++ * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split ++ * @adapter: board private structure ++ * ++ * the return value indicates whether actual cleaning was done, there ++ * is no guarantee that everything was cleaned ++ **/ ++#ifdef CONFIG_E1000E_NAPI ++static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, ++ int *work_done, int work_to_do) ++#else ++static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) ++#endif ++{ ++ union e1000_rx_desc_packet_split *rx_desc, *next_rxd; ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ struct e1000_buffer *buffer_info, *next_buffer; ++ struct e1000_ps_page *ps_page; ++ struct sk_buff *skb; ++ unsigned int i, j; ++ u32 length, staterr; ++ int cleaned_count = 0; ++ bool cleaned = 0; ++ 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]; ++ ++ while (staterr & E1000_RXD_STAT_DD) { ++#ifdef CONFIG_E1000E_NAPI ++ if (*work_done >= work_to_do) ++ break; ++ (*work_done)++; ++#endif ++ skb = buffer_info->skb; ++ ++ /* in the packet split case this is header only */ ++ prefetch(skb->data - NET_IP_ALIGN); ++ ++ i++; ++ 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 = 1; ++ cleaned_count++; ++ pci_unmap_single(pdev, buffer_info->dma, ++ adapter->rx_ps_bsize0, ++ PCI_DMA_FROMDEVICE); ++ buffer_info->dma = 0; ++ ++ if (!(staterr & E1000_RXD_STAT_EOP)) { ++ e_dbg("Packet Split buffers didn't pick up the full" ++ " packet\n"); ++ dev_kfree_skb_irq(skb); ++ goto next_desc; ++ } ++ ++ if (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 (!length) { ++ e_dbg("Last part of the packet spanning multiple" ++ " descriptors\n"); ++ dev_kfree_skb_irq(skb); ++ goto next_desc; ++ } ++ ++ /* Good Receive */ ++ skb_put(skb, length); ++ ++#ifdef CONFIG_E1000E_NAPI ++ { ++ /* ++ * this looks ugly, but it seems compiler issues make it ++ * more efficient than reusing j ++ */ ++ int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]); ++ ++ /* ++ * page alloc/put takes too long and effects small packet ++ * throughput, so unsplit small packets and save the alloc/put ++ * only valid in softirq (napi) context to call kmap_* ++ */ ++ if (l1 && (l1 <= copybreak) && ++ ((length + l1) <= adapter->rx_ps_bsize0)) { ++ u8 *vaddr; ++ ++ ps_page = &buffer_info->ps_pages[0]; ++ ++ /* ++ * there is no documentation about how to call ++ * kmap_atomic, so we can't hold the mapping ++ * very long ++ */ ++ pci_dma_sync_single_for_cpu(pdev, ps_page->dma, ++ PAGE_SIZE, PCI_DMA_FROMDEVICE); ++ vaddr = kmap_atomic(ps_page->page, 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, ++ PAGE_SIZE, PCI_DMA_FROMDEVICE); ++ ++ skb_put(skb, l1); ++ goto copydone; ++ } /* if */ ++ } ++#endif ++ ++ for (j = 0; j < PS_PAGE_BUFFERS; j++) { ++ length = le16_to_cpu(rx_desc->wb.upper.length[j]); ++ if (!length) ++ break; ++ ++ ps_page = &buffer_info->ps_pages[j]; ++ pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE, ++ PCI_DMA_FROMDEVICE); ++ ps_page->dma = 0; ++ skb_fill_page_desc(skb, j, ps_page->page, 0, length); ++ ps_page->page = NULL; ++ skb->len += length; ++ skb->data_len += length; ++ skb->truesize += length; ++ } ++ ++#ifdef CONFIG_E1000E_NAPI ++copydone: ++#endif ++ total_rx_bytes += skb->len; ++ total_rx_packets++; ++ ++ e1000_rx_checksum(adapter, staterr, le16_to_cpu( ++ rx_desc->wb.lower.hi_dword.csum_ip.csum), skb); ++ ++ if (rx_desc->wb.upper.header_status & ++ cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP)) ++ adapter->rx_hdr_split++; ++ ++ e1000_receive_skb(adapter, netdev, skb, ++ staterr, rx_desc->wb.middle.vlan); ++ ++next_desc: ++ rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF); ++ buffer_info->skb = NULL; ++ ++ /* return some buffers to hardware, one at a time is too slow */ ++ if (cleaned_count >= E1000_RX_BUFFER_WRITE) { ++ adapter->alloc_rx_buf(adapter, 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, 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; ++} ++ ++#ifdef CONFIG_E1000E_NAPI ++/* NOTE: these new jumbo frame routines rely on NAPI because of the ++ * pskb_may_pull call, which eventually must call kmap_atomic which you cannot ++ * call from hard irq context */ ++ ++/** ++ * e1000_consume_page - helper function ++ **/ ++static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb, ++ u16 length) ++{ ++ bi->page = NULL; ++ skb->len += length; ++ skb->data_len += length; ++ skb->truesize += length; ++} ++ ++/** ++ * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy ++ * @adapter: board private structure ++ * ++ * the return value indicates whether actual cleaning was done, there ++ * is no guarantee that everything was cleaned ++ **/ ++ ++static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, ++ int *work_done, int work_to_do) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ struct e1000_rx_desc *rx_desc, *next_rxd; ++ struct e1000_buffer *buffer_info, *next_buffer; ++ u32 length; ++ unsigned int i; ++ 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(*rx_ring, i); ++ buffer_info = &rx_ring->buffer_info[i]; ++ ++ 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; ++ buffer_info->skb = NULL; ++ ++ ++i; ++ 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_page(pdev, buffer_info->dma, PAGE_SIZE, ++ PCI_DMA_FROMDEVICE); ++ buffer_info->dma = 0; ++ ++ length = le16_to_cpu(rx_desc->length); ++ ++ /* errors is only valid for DD + EOP descriptors */ ++ if (unlikely((status & E1000_RXD_STAT_EOP) && ++ (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) { ++ /* recycle both page and skb */ ++ buffer_info->skb = skb; ++ /* an error means any chain goes out the window ++ * too */ ++ if (rx_ring->rx_skb_top) ++ dev_kfree_skb(rx_ring->rx_skb_top); ++ rx_ring->rx_skb_top = NULL; ++ goto next_desc; ++ } ++ ++#define rxtop rx_ring->rx_skb_top ++ if (!(status & E1000_RXD_STAT_EOP)) { ++ /* this descriptor is only the beginning (or middle) */ ++ if (!rxtop) { ++ /* this is the beginning of a chain */ ++ rxtop = skb; ++ skb_fill_page_desc(rxtop, 0, buffer_info->page, ++ 0, length); ++ } else { ++ /* this is the middle of a chain */ ++ skb_fill_page_desc(rxtop, ++ skb_shinfo(rxtop)->nr_frags, ++ buffer_info->page, 0, length); ++ /* re-use the skb, only consumed the page */ ++ buffer_info->skb = skb; ++ } ++ e1000_consume_page(buffer_info, rxtop, length); ++ goto next_desc; ++ } else { ++ if (rxtop) { ++ /* end of the chain */ ++ skb_fill_page_desc(rxtop, ++ skb_shinfo(rxtop)->nr_frags, ++ buffer_info->page, 0, length); ++ /* re-use the current skb, we only consumed the ++ * page */ ++ buffer_info->skb = skb; ++ skb = rxtop; ++ rxtop = NULL; ++ e1000_consume_page(buffer_info, skb, length); ++ } else { ++ /* no chain, got EOP, this buf is the packet ++ * copybreak to save the put_page/alloc_page */ ++ if (length <= copybreak && ++ skb_tailroom(skb) >= length) { ++ u8 *vaddr; ++ vaddr = kmap_atomic(buffer_info->page, ++ KM_SKB_DATA_SOFTIRQ); ++ memcpy(skb_tail_pointer(skb), vaddr, ++ length); ++ kunmap_atomic(vaddr, ++ KM_SKB_DATA_SOFTIRQ); ++ /* re-use the page, so don't erase ++ * buffer_info->page */ ++ skb_put(skb, length); ++ } else { ++ skb_fill_page_desc(skb, 0, ++ buffer_info->page, 0, ++ length); ++ e1000_consume_page(buffer_info, skb, ++ length); ++ } ++ } ++ } ++ ++ /* Receive Checksum Offload XXX recompute due to CRC strip? */ ++ e1000_rx_checksum(adapter, ++ (u32)(status) | ++ ((u32)(rx_desc->errors) << 24), ++ le16_to_cpu(rx_desc->csum), skb); ++ ++ /* probably a little skewed due to removing CRC */ ++ total_rx_bytes += skb->len; ++ total_rx_packets++; ++ ++ /* eth type trans needs skb->data to point to something */ ++ if (!pskb_may_pull(skb, ETH_HLEN)) { ++ e_err("pskb_may_pull failed.\n"); ++ dev_kfree_skb(skb); ++ goto next_desc; ++ } ++ ++ e1000_receive_skb(adapter, netdev, skb, status, ++ rx_desc->special); ++ ++next_desc: ++ rx_desc->status = 0; ++ ++ /* 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, cleaned_count); ++ cleaned_count = 0; ++ } ++ ++ /* use prefetched values */ ++ rx_desc = next_rxd; ++ buffer_info = next_buffer; ++ } ++ rx_ring->next_to_clean = i; ++ ++ cleaned_count = e1000_desc_unused(rx_ring); ++ if (cleaned_count) ++ adapter->alloc_rx_buf(adapter, 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; ++} ++#endif /* CONFIG_E1000E_NAPI */ ++ ++/** ++ * e1000_clean_rx_ring - Free Rx Buffers per Queue ++ * @adapter: board private structure ++ **/ ++static void e1000_clean_rx_ring(struct e1000_adapter *adapter) ++{ ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ struct e1000_buffer *buffer_info; ++ struct e1000_ps_page *ps_page; ++ struct pci_dev *pdev = adapter->pdev; ++ 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->dma) { ++ if (adapter->clean_rx == e1000_clean_rx_irq) ++ pci_unmap_single(pdev, buffer_info->dma, ++ adapter->rx_buffer_len, ++ PCI_DMA_FROMDEVICE); ++#ifdef CONFIG_E1000E_NAPI ++ else if (adapter->clean_rx == e1000_clean_jumbo_rx_irq) ++ pci_unmap_page(pdev, buffer_info->dma, ++ PAGE_SIZE, ++ PCI_DMA_FROMDEVICE); ++#endif ++ else if (adapter->clean_rx == e1000_clean_rx_irq_ps) ++ pci_unmap_single(pdev, buffer_info->dma, ++ adapter->rx_ps_bsize0, ++ PCI_DMA_FROMDEVICE); ++ buffer_info->dma = 0; ++ } ++ ++ if (buffer_info->page) { ++ put_page(buffer_info->page); ++ buffer_info->page = NULL; ++ } ++ ++ if (buffer_info->skb) { ++ dev_kfree_skb(buffer_info->skb); ++ buffer_info->skb = NULL; ++ } ++ ++ for (j = 0; j < PS_PAGE_BUFFERS; j++) { ++ ps_page = &buffer_info->ps_pages[j]; ++ if (!ps_page->page) ++ break; ++ pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE, ++ PCI_DMA_FROMDEVICE); ++ ps_page->dma = 0; ++ put_page(ps_page->page); ++ ps_page->page = NULL; ++ } ++ } ++ ++#ifdef CONFIG_E1000E_NAPI ++ /* there also may be some cached data from a chained receive */ ++ if (rx_ring->rx_skb_top) { ++ dev_kfree_skb(rx_ring->rx_skb_top); ++ rx_ring->rx_skb_top = NULL; ++ } ++#endif ++ ++ /* 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->head); ++ writel(0, adapter->hw.hw_addr + rx_ring->tail); ++} ++ ++/** ++ * e1000_free_rx_resources - Free Rx Resources ++ * @adapter: board private structure ++ * ++ * Free all receive software resources ++ **/ ++ ++void e1000_free_rx_resources(struct e1000_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ int i; ++ ++ e1000_clean_rx_ring(adapter); ++ ++ for (i = 0; i < rx_ring->count; i++) { ++ kfree(rx_ring->buffer_info[i].ps_pages); ++ } ++ ++ vfree(rx_ring->buffer_info); ++ rx_ring->buffer_info = NULL; ++ ++ dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc, ++ rx_ring->dma); ++ rx_ring->desc = NULL; ++} ++ ++/** ++ * e1000_update_itr - update the dynamic ITR value based on statistics ++ * @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 ++ * ++ * 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. ++ **/ ++static unsigned int e1000_update_itr(struct e1000_adapter *adapter, ++ u16 itr_setting, int packets, ++ int bytes) ++{ ++ unsigned int retval = itr_setting; ++ ++ if (packets == 0) ++ goto update_itr_done; ++ ++ switch (itr_setting) { ++ case lowest_latency: ++ /* handle TSO and jumbo frames */ ++ 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) { ++ /* this if handles the TSO accounting */ ++ 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; ++ } ++ ++update_itr_done: ++ return retval; ++} ++ ++static void e1000_set_itr(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u16 current_itr; ++ u32 new_itr = adapter->itr; ++ ++ /* for non-gigabit speeds, just fix the interrupt rate at 4000 */ ++ if (adapter->link_speed != SPEED_1000) { ++ current_itr = 0; ++ new_itr = 4000; ++ goto set_itr_now; ++ } ++ ++ adapter->tx_itr = e1000_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 = e1000_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; ++#ifdef CONFIG_E1000E_MSIX ++ adapter->rx_ring->itr_val = new_itr; ++ if (adapter->msix_entries) ++ adapter->rx_ring->set_itr = 1; ++ else ++#endif ++ ew32(ITR, 1000000000 / (new_itr * 256)); ++ } ++} ++ ++/** ++ * e1000_clean_tx_irq - Reclaim resources after transmit completes ++ * @adapter: board private structure ++ * ++ * the return value indicates if there is more work to do (later) ++ **/ ++static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct e1000_hw *hw = &adapter->hw; ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ struct e1000_tx_desc *tx_desc, *eop_desc; ++ struct e1000_buffer *buffer_info; ++ unsigned int i, eop; ++ bool cleaned = 0, retval = 1; ++ 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); ++ ++ while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { ++ for (cleaned = 0; !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; ++#ifdef NETIF_F_TSO ++ unsigned int segs, bytecount; ++ segs = skb_shinfo(skb)->gso_segs ?: 1; ++ /* multiply data chunks by size of headers */ ++ bytecount = ((segs - 1) * skb_headlen(skb)) + ++ skb->len; ++ total_tx_packets += segs; ++ total_tx_bytes += bytecount; ++#else ++ total_tx_packets++; ++ total_tx_bytes += skb->len; ++#endif ++ } ++ ++ e1000_put_txbuf(adapter, buffer_info); ++ tx_desc->upper.data = 0; ++ ++ i++; ++ if (i == tx_ring->count) ++ i = 0; ++#ifdef CONFIG_E1000E_NAPI ++ if (total_tx_packets >= tx_ring->count) { ++ retval = 0; ++ goto done_cleaning; ++ } ++#endif ++ } ++ ++ eop = tx_ring->buffer_info[i].next_to_watch; ++ eop_desc = E1000_TX_DESC(*tx_ring, eop); ++ } ++ ++#ifdef CONFIG_E1000E_NAPI ++done_cleaning: ++#endif ++ tx_ring->next_to_clean = i; ++ ++#define TX_WAKE_THRESHOLD 32 ++ if (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) && ++ !(test_bit(__E1000_DOWN, &adapter->state))) { ++ netif_wake_queue(netdev); ++ ++adapter->restart_queue; ++ } ++ } ++ ++ 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 = 0; ++ if (tx_ring->buffer_info[eop].dma && ++ time_after(jiffies, tx_ring->buffer_info[eop].time_stamp ++ + (adapter->tx_timeout_factor * HZ)) ++ && !(er32(STATUS) & E1000_STATUS_TXOFF)) { ++ e1000_print_tx_hang(adapter); ++ netif_stop_queue(netdev); ++ } ++ } ++ 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 retval; ++} ++ ++/** ++ * e1000_intr_msi - Interrupt Handler ++ * @irq: interrupt number ++ * @data: pointer to a network interface device structure ++ **/ ++static irqreturn_t e1000_intr_msi(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++#ifndef CONFIG_E1000E_NAPI ++ int i; ++#endif ++ /* read ICR disables interrupts using IAM */ ++ u32 icr = er32(ICR); ++ ++ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { ++ hw->mac.get_link_status = 1; ++ /* ++ * ICH8 workaround-- Call gig speed drop workaround on cable ++ * disconnect (LSC) before accessing any PHY registers ++ */ ++ if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && ++ (!(er32(STATUS) & E1000_STATUS_LU))) ++ e1000_gig_downshift_workaround_ich8lan(hw); ++ ++ /* ++ * 80003ES2LAN workaround-- For packet buffer work-around on ++ * link down event; disable receives here in the ISR and reset ++ * adapter in watchdog ++ */ ++ if (netif_carrier_ok(netdev) && ++ adapter->flags & FLAG_RX_NEEDS_RESTART) { ++ /* disable receives */ ++ u32 rctl = er32(RCTL); ++ ew32(RCTL, rctl & ~E1000_RCTL_EN); ++ adapter->flags |= FLAG_RX_RESTART_NOW; ++ } ++ /* guard against interrupt when we're going down */ ++ if (!test_bit(__E1000_DOWN, &adapter->state)) ++ mod_timer(&adapter->watchdog_timer, jiffies + 1); ++ } ++ ++#ifdef CONFIG_E1000E_NAPI ++ if (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 ++ adapter->total_tx_bytes = 0; ++ adapter->total_rx_bytes = 0; ++ adapter->total_tx_packets = 0; ++ adapter->total_rx_packets = 0; ++ ++ for (i = 0; i < E1000_MAX_INTR; i++) { ++ int rx_cleaned = adapter->clean_rx(adapter); ++ int tx_cleaned_complete = e1000_clean_tx_irq(adapter); ++ if (!rx_cleaned && tx_cleaned_complete) ++ break; ++ } ++ ++ if (likely(adapter->itr_setting & 3)) ++ e1000_set_itr(adapter); ++#endif /* CONFIG_E1000E_NAPI */ ++ ++ return IRQ_HANDLED; ++} ++ ++/** ++ * e1000_intr - Interrupt Handler ++ * @irq: interrupt number ++ * @data: pointer to a network interface device structure ++ **/ ++static irqreturn_t e1000_intr(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++#ifndef CONFIG_E1000E_NAPI ++ int i; ++ int rx_cleaned, tx_cleaned_complete; ++#endif ++ u32 rctl, icr = er32(ICR); ++ ++ if (!icr) ++ return IRQ_NONE; /* Not our interrupt */ ++ ++#ifdef CONFIG_E1000E_NAPI ++ /* ++ * 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 (!(icr & E1000_ICR_INT_ASSERTED)) ++ return IRQ_NONE; ++ ++#endif /* CONFIG_E1000E_NAPI */ ++ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { ++ hw->mac.get_link_status = 1; ++ /* ++ * ICH8 workaround-- Call gig speed drop workaround on cable ++ * disconnect (LSC) before accessing any PHY registers ++ */ ++ if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && ++ (!(er32(STATUS) & E1000_STATUS_LU))) ++ e1000_gig_downshift_workaround_ich8lan(hw); ++ ++ /* ++ * 80003ES2LAN workaround-- ++ * For packet buffer work-around on link down event; ++ * disable receives here in the ISR and ++ * reset adapter in watchdog ++ */ ++ if (netif_carrier_ok(netdev) && ++ (adapter->flags & FLAG_RX_NEEDS_RESTART)) { ++ /* disable receives */ ++ rctl = er32(RCTL); ++ ew32(RCTL, rctl & ~E1000_RCTL_EN); ++ adapter->flags |= FLAG_RX_RESTART_NOW; ++ } ++ /* guard against interrupt when we're going down */ ++ if (!test_bit(__E1000_DOWN, &adapter->state)) ++ mod_timer(&adapter->watchdog_timer, jiffies + 1); ++ } ++ ++#ifdef CONFIG_E1000E_NAPI ++ if (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 ++ adapter->total_tx_bytes = 0; ++ adapter->total_rx_bytes = 0; ++ adapter->total_tx_packets = 0; ++ adapter->total_rx_packets = 0; ++ ++ for (i = 0; i < E1000_MAX_INTR; i++) { ++ rx_cleaned = adapter->clean_rx(adapter); ++ tx_cleaned_complete = e1000_clean_tx_irq(adapter); ++ if (!rx_cleaned && tx_cleaned_complete) ++ break; ++ } ++ ++ if (likely(adapter->itr_setting & 3)) ++ e1000_set_itr(adapter); ++#endif /* CONFIG_E1000E_NAPI */ ++ ++ return IRQ_HANDLED; ++} ++ ++#ifdef CONFIG_E1000E_MSIX ++static irqreturn_t e1000_msix_other(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 icr = er32(ICR); ++ ++ if (!(icr & E1000_ICR_INT_ASSERTED)) ++ { ++ ew32(IMS, E1000_IMS_OTHER); ++ return IRQ_NONE; ++ } ++ ++ if (icr & adapter->eiac_mask) ++ ew32(ICS, (icr & adapter->eiac_mask)); ++ ++ if (icr & E1000_ICR_OTHER) { ++ if (!(icr & E1000_ICR_LSC)) ++ goto no_link_interrupt; ++ hw->mac.get_link_status = 1; ++ /* guard against interrupt when we're going down */ ++ if (!test_bit(__E1000_DOWN, &adapter->state)) ++ mod_timer(&adapter->watchdog_timer, jiffies + 1); ++ } ++ ++no_link_interrupt: ++ ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER ++static irqreturn_t e1000_intr_msix_tx(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ ++ ++ adapter->total_tx_bytes = 0; ++ adapter->total_tx_packets = 0; ++ ++ if (!e1000_clean_tx_irq(adapter)) ++ /* Ring was not completely cleaned, so fire another interrupt */ ++ ew32(ICS, tx_ring->ims_val); ++ ++ return IRQ_HANDLED; ++} ++ ++#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */ ++static irqreturn_t e1000_intr_msix_rx(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++#ifndef CONFIG_E1000E_NAPI ++ int i; ++ struct e1000_hw *hw = &adapter->hw; ++#endif ++ ++ /* Write the ITR value calculated at the end of the ++ * previous interrupt. ++ */ ++ if (adapter->rx_ring->set_itr) { ++ writel(1000000000 / (adapter->rx_ring->itr_val * 256), ++ adapter->hw.hw_addr + adapter->rx_ring->itr_register); ++ adapter->rx_ring->set_itr = 0; ++ } ++ ++#ifdef CONFIG_E1000E_NAPI ++ if (netif_rx_schedule_prep(netdev, &adapter->napi)) { ++ adapter->total_rx_bytes = 0; ++ adapter->total_rx_packets = 0; ++#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER ++ adapter->total_tx_bytes = 0; ++ adapter->total_tx_packets = 0; ++#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */ ++ __netif_rx_schedule(netdev, &adapter->napi); ++ } ++#else ++ adapter->total_rx_bytes = 0; ++ adapter->total_rx_packets = 0; ++#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER ++ adapter->total_tx_bytes = 0; ++ adapter->total_tx_packets = 0; ++#endif ++ ++ for (i = 0; i < E1000_MAX_INTR; i++) { ++ int rx_cleaned = adapter->clean_rx(adapter); ++#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER ++ int tx_cleaned_complete = e1000_clean_tx_irq(adapter); ++ if (!rx_cleaned && tx_cleaned_complete) ++#else ++ if (!rx_cleaned) ++#endif ++ goto out; ++ } ++ /* If we got here, the ring was not completely cleaned, ++ * so fire another interrupt. ++ */ ++ ew32(ICS, adapter->rx_ring->ims_val); ++ ++out: ++#endif /* CONFIG_E1000E_NAPI */ ++ return IRQ_HANDLED; ++} ++ ++/** ++ * e1000_configure_msix - Configure MSI-X hardware ++ * ++ * e1000_configure_msix sets up the hardware to properly ++ * generate MSI-X interrupts. ++ **/ ++static void e1000_configure_msix(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ int vector = 0; ++ u32 ctrl_ext, ivar = 0; ++ ++ adapter->eiac_mask = 0; ++ ++ /* Workaround issue with spurious interrupts on 82574 in MSI-X mode */ ++ if (hw->mac.type == e1000_82574) { ++ u32 rfctl = er32(RFCTL); ++ rfctl |= E1000_RFCTL_ACK_DIS; ++ ew32(RFCTL, rfctl); ++ } ++ ++#define E1000_IVAR_INT_ALLOC_VALID 0x8 ++ /* Configure Rx vector */ ++ rx_ring->ims_val = E1000_IMS_RXQ0; ++ adapter->eiac_mask |= rx_ring->ims_val; ++ if (rx_ring->itr_val) ++ writel(1000000000 / (rx_ring->itr_val * 256), ++ hw->hw_addr + rx_ring->itr_register); ++ else ++ writel(1, hw->hw_addr + rx_ring->itr_register); ++ ivar = E1000_IVAR_INT_ALLOC_VALID | vector; ++ ++ /* Configure Tx vector */ ++ tx_ring->ims_val = E1000_IMS_TXQ0; ++#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER ++ vector++; ++ if (tx_ring->itr_val) ++ writel(1000000000 / (tx_ring->itr_val * 256), ++ hw->hw_addr + tx_ring->itr_register); ++ else ++ writel(1, hw->hw_addr + tx_ring->itr_register); ++#else ++ rx_ring->ims_val |= tx_ring->ims_val; ++#endif ++ adapter->eiac_mask |= tx_ring->ims_val; ++ ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 8); ++ ++ /* set vector for Other Causes, e.g. link changes */ ++ vector++; ++ ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 16); ++ if (rx_ring->itr_val) ++ writel(1000000000 / (rx_ring->itr_val * 256), ++ hw->hw_addr + E1000_EITR_82574(vector)); ++ else ++ writel(1, hw->hw_addr + E1000_EITR_82574(vector)); ++ ++ /* Cause Tx interrupts on every write back */ ++ ivar |= (1 << 31); ++ ++ ew32(IVAR, ivar); ++ ++ /* enable MSI-X PBA support */ ++ ctrl_ext = er32(CTRL_EXT); ++ ctrl_ext |= E1000_CTRL_EXT_PBA_CLR; ++ ++ /* Auto-Mask Other interrupts upon ICR read */ ++ ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER); ++ ctrl_ext |= E1000_CTRL_EXT_EIAME; ++ ew32(CTRL_EXT, ctrl_ext); ++ e1e_flush(); ++} ++ ++void e1000_reset_interrupt_capability(struct e1000_adapter *adapter) ++{ ++ if (adapter->msix_entries) { ++ pci_disable_msix(adapter->pdev); ++ kfree(adapter->msix_entries); ++ adapter->msix_entries = NULL; ++ } else if (adapter->flags & FLAG_MSI_ENABLED) { ++ pci_disable_msi(adapter->pdev); ++ adapter->flags &= ~FLAG_MSI_ENABLED; ++ } ++ ++ return; ++} ++ ++/** ++ * e1000_set_interrupt_capability - set MSI or MSI-X if supported ++ * ++ * Attempt to configure interrupts using the best available ++ * capabilities of the hardware and kernel. ++ **/ ++void e1000_set_interrupt_capability(struct e1000_adapter *adapter) ++{ ++ int err; ++ int numvecs, i; ++ ++ ++ switch (adapter->int_mode) { ++ case E1000E_INT_MODE_MSIX: ++ if (adapter->flags & FLAG_HAS_MSIX) { ++#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER ++ numvecs = 3; /* RxQ0, TxQ0 and other */ ++#else ++ numvecs = 2; /* RxQ0/TxQ0 and other */ ++#endif ++ adapter->msix_entries = kcalloc(numvecs, ++ sizeof(struct msix_entry), ++ GFP_KERNEL); ++ if (adapter->msix_entries) { ++ for (i=0; i < numvecs; i++) ++ adapter->msix_entries[i].entry = i; ++ ++ err = pci_enable_msix(adapter->pdev, ++ adapter->msix_entries, ++ numvecs); ++ if (err == 0) ++ return; ++ } ++ /* MSI-X failed, so fall through and try MSI */ ++ e_err("Failed to initialize MSI-X interrupts. " ++ "Falling back to MSI interrupts.\n"); ++ e1000_reset_interrupt_capability(adapter); ++ } ++ adapter->int_mode = E1000E_INT_MODE_MSI; ++ /* Fall through */ ++ case E1000E_INT_MODE_MSI: ++ if (!pci_enable_msi(adapter->pdev)) { ++ adapter->flags |= FLAG_MSI_ENABLED; ++ } else { ++ adapter->int_mode = E1000E_INT_MODE_LEGACY; ++ e_err("Failed to initialize MSI interrupts. Falling " ++ "back to legacy interrupts.\n"); ++ } ++ /* Fall through */ ++ case E1000E_INT_MODE_LEGACY: ++ /* Don't do anything; this is the system default */ ++ break; ++ } ++ ++ return; ++} ++ ++/** ++ * e1000_request_msix - Initialize MSI-X interrupts ++ * ++ * e1000_request_msix allocates MSI-X vectors and requests interrupts from the ++ * kernel. ++ **/ ++static int e1000_request_msix(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ int err = 0, vector = 0; ++ ++ if (strlen(netdev->name) < (IFNAMSIZ - 5)) ++#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER ++ sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name); ++#else ++ sprintf(adapter->rx_ring->name, "%s-Q0", netdev->name); ++#endif ++ else ++ memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ); ++ err = request_irq(adapter->msix_entries[vector].vector, ++ &e1000_intr_msix_rx, 0, adapter->rx_ring->name, ++ netdev); ++ if (err) ++ goto out; ++ adapter->rx_ring->itr_register = E1000_EITR_82574(vector); ++ adapter->rx_ring->itr_val = adapter->itr; ++ vector++; ++ ++#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER ++ if (strlen(netdev->name) < (IFNAMSIZ - 5)) ++ sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name); ++ else ++ memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ); ++ err = request_irq(adapter->msix_entries[vector].vector, ++ &e1000_intr_msix_tx, 0, adapter->tx_ring->name, ++ netdev); ++ if (err) ++ goto out; ++ adapter->tx_ring->itr_register = E1000_EITR_82574(vector); ++ adapter->tx_ring->itr_val = adapter->itr; ++ vector++; ++ ++#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */ ++ err = request_irq(adapter->msix_entries[vector].vector, ++ &e1000_msix_other, 0, netdev->name, netdev); ++ if (err) ++ goto out; ++ ++ e1000_configure_msix(adapter); ++ return 0; ++out: ++ return err; ++} ++ ++#endif /* CONFIG_E1000E_MSIX */ ++/** ++ * e1000_alloc_queues - Allocate memory for all rings ++ * @adapter: board private structure to initialize ++ **/ ++static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) ++{ ++ adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); ++ if (!adapter->tx_ring) ++ goto err; ++ ++ adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); ++ if (!adapter->rx_ring) ++ goto err; ++ ++ return 0; ++err: ++ e_err("Unable to allocate memory for queues\n"); ++ kfree(adapter->rx_ring); ++ kfree(adapter->tx_ring); ++ return -ENOMEM; ++} ++ ++/** ++ * e1000_request_irq - initialize interrupts ++ * ++ * Attempts to configure interrupts using the best available ++ * capabilities of the hardware and kernel. ++ **/ ++static int e1000_request_irq(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ int err; ++#ifdef CONFIG_E1000E_MSIX ++ ++ if (adapter->msix_entries) { ++ err = e1000_request_msix(adapter); ++ if (!err) ++ return err; ++ /* fall back to MSI */ ++ e1000_reset_interrupt_capability(adapter); ++ adapter->int_mode = E1000E_INT_MODE_MSI; ++ e1000_set_interrupt_capability(adapter); ++ } ++ if (adapter->flags & FLAG_MSI_ENABLED) { ++ err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0, ++ netdev->name, netdev); ++ if (!err) ++ return err; ++ ++ /* fall back to legacy interrupt */ ++ e1000_reset_interrupt_capability(adapter); ++ adapter->int_mode = E1000E_INT_MODE_LEGACY; ++ } ++ ++ err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED, ++ netdev->name, netdev); ++ if (err) ++ e_err("Unable to allocate interrupt, Error: %d\n", err); ++#else ++ int irq_flags = IRQF_SHARED; ++ ++ if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) { ++ err = pci_enable_msi(adapter->pdev); ++ if (!err) { ++ adapter->flags |= FLAG_MSI_ENABLED; ++ irq_flags = 0; ++ } ++ } ++ ++ err = request_irq(adapter->pdev->irq, ++ ((adapter->flags & FLAG_MSI_ENABLED) ? ++ &e1000_intr_msi : &e1000_intr), ++ irq_flags, netdev->name, netdev); ++ if (err) { ++ if (adapter->flags & FLAG_MSI_ENABLED) { ++ pci_disable_msi(adapter->pdev); ++ adapter->flags &= ~FLAG_MSI_ENABLED; ++ } ++ e_err("Unable to allocate interrupt, Error: %d\n", err); ++ } ++#endif /* CONFIG_E1000E_MSIX */ ++ ++ return err; ++} ++ ++static void e1000_free_irq(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ ++#ifdef CONFIG_E1000E_MSIX ++ if (adapter->msix_entries) { ++ int vector = 0; ++ ++ free_irq(adapter->msix_entries[vector].vector, netdev); ++ vector++; ++ ++#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER ++ free_irq(adapter->msix_entries[vector].vector, netdev); ++ vector++; ++ ++#endif ++ /* Other Causes interrupt vector */ ++ free_irq(adapter->msix_entries[vector].vector, netdev); ++ return; ++ } ++ ++#endif /* CONFIG_E1000E_MSIX */ ++ free_irq(adapter->pdev->irq, netdev); ++#ifndef CONFIG_E1000E_MSIX ++ if (adapter->flags & FLAG_MSI_ENABLED) { ++ pci_disable_msi(adapter->pdev); ++ adapter->flags &= ~FLAG_MSI_ENABLED; ++ } ++#endif ++} ++ ++/** ++ * e1000_irq_disable - Mask off interrupt generation on the NIC ++ **/ ++static void e1000_irq_disable(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ ++ ew32(IMC, ~0); ++#ifdef CONFIG_E1000E_MSIX ++ if (adapter->msix_entries) { ++ ew32(EIAC_82574, 0); ++ } ++#endif /* CONFIG_E1000E_MSIX */ ++ e1e_flush(); ++ synchronize_irq(adapter->pdev->irq); ++} ++ ++/** ++ * e1000_irq_enable - Enable default interrupt generation settings ++ **/ ++static void e1000_irq_enable(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++#ifdef CONFIG_E1000E_MSIX ++ ++ if (adapter->msix_entries) { ++ ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574); ++ ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC); ++ } else { ++ ew32(IMS, IMS_ENABLE_MASK); ++ } ++#else ++ ew32(IMS, IMS_ENABLE_MASK); ++#endif /* CONFIG_E1000E_MSIX */ ++} ++ ++/** ++ * e1000_get_hw_control - get control of the h/w from f/w ++ * @adapter: address of board private structure ++ * ++ * e1000_get_hw_control sets {CTRL_EXT|SWSM}:DRV_LOAD bit. ++ * For ASF and Pass Through versions of f/w this means that ++ * the driver is loaded. For AMT version (only with 82573) ++ * of the f/w this means that the network i/f is open. ++ **/ ++static void e1000_get_hw_control(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u32 ctrl_ext; ++ u32 swsm; ++ ++ /* Let firmware know the driver has taken over */ ++ if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { ++ swsm = er32(SWSM); ++ ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD); ++ } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { ++ ctrl_ext = er32(CTRL_EXT); ++ ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); ++ } ++} ++ ++/** ++ * e1000_release_hw_control - release control of the h/w to f/w ++ * @adapter: address of board private structure ++ * ++ * e1000_release_hw_control resets {CTRL_EXT|SWSM}:DRV_LOAD bit. ++ * For ASF and Pass Through versions of f/w this means that the ++ * driver is no longer loaded. For AMT version (only with 82573) i ++ * of the f/w this means that the network i/f is closed. ++ * ++ **/ ++static void e1000_release_hw_control(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u32 ctrl_ext; ++ u32 swsm; ++ ++ /* Let firmware taken over control of h/w */ ++ if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { ++ swsm = er32(SWSM); ++ ew32(SWSM, swsm & ~E1000_SWSM_DRV_LOAD); ++ } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { ++ ctrl_ext = er32(CTRL_EXT); ++ ew32(CTRL_EXT, ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); ++ } ++} ++ ++#ifdef CONFIG_E1000E_NAPI ++/** ++ * e1000_poll - NAPI Rx polling callback ++ * @napi: struct associated with this polling callback ++ * @budget: amount of packets driver is allowed to process this poll ++ **/ ++static int e1000_poll(struct napi_struct *napi, int budget) ++{ ++ struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, ++ napi); ++ struct net_device *netdev = adapter->netdev; ++ int tx_clean_complete = 1, work_done = 0; ++#ifdef CONFIG_E1000E_MSIX ++ struct e1000_hw *hw = &adapter->hw; ++ ++ if (adapter->msix_entries && ++ !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val)) ++ goto clean_rx; ++ ++#endif ++ /* ++ * e1000_poll is called per-cpu. This lock protects ++ * tx_ring from being cleaned by multiple cpus ++ * simultaneously. A failure obtaining the lock means ++ * tx_ring is currently being cleaned anyway. ++ */ ++ if (spin_trylock(&adapter->tx_queue_lock)) { ++ tx_clean_complete &= e1000_clean_tx_irq(adapter); ++ spin_unlock(&adapter->tx_queue_lock); ++ } ++ ++#ifdef CONFIG_E1000E_MSIX ++clean_rx: ++#endif ++ adapter->clean_rx(adapter, &work_done, budget); ++ ++ /* If Tx completed and all Rx work done, exit the polling mode */ ++ if ((tx_clean_complete && (work_done == 0)) || !netif_running(netdev)) { ++ netif_rx_complete(netdev, napi); ++ if (adapter->itr_setting & 3) ++ e1000_set_itr(adapter); ++ if (!test_bit(__E1000_DOWN, &adapter->state)) { ++#ifdef CONFIG_E1000E_MSIX ++ if (adapter->msix_entries) ++ ew32(IMS, adapter->rx_ring->ims_val); ++ else ++#endif ++ e1000_irq_enable(adapter); ++ } ++ return 0; ++ } ++ ++ if (!tx_clean_complete) ++ work_done = budget; ++ ++ return work_done; ++} ++ ++#endif /* CONFIG_E1000E_NAPI */ ++static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 vfta, index; ++ struct net_device *v_netdev; ++ ++ /* don't update vlan cookie if already programmed */ ++ if ((adapter->hw.mng_cookie.status & ++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && ++ (vid == adapter->mng_vlan_id)) ++ return; ++ /* add VID to filter table */ ++ index = (vid >> 5) & 0x7F; ++ vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); ++ vfta |= (1 << (vid & 0x1F)); ++ if (hw->mac.ops.write_vfta) ++ hw->mac.ops.write_vfta(hw, index, vfta); ++ /* ++ * Copy feature flags from netdev to the vlan netdev for this vid. ++ * This allows things like TSO to bubble down to our vlan device. ++ */ ++ v_netdev = vlan_group_get_device(adapter->vlgrp, vid); ++ v_netdev->features |= adapter->netdev->features; ++ vlan_group_set_device(adapter->vlgrp, vid, v_netdev); ++} ++ ++static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 vfta, index; ++ ++ if (!test_bit(__E1000_DOWN, &adapter->state)) ++ e1000_irq_disable(adapter); ++ vlan_group_set_device(adapter->vlgrp, vid, NULL); ++ if (!test_bit(__E1000_DOWN, &adapter->state)) ++ e1000_irq_enable(adapter); ++ ++ if ((adapter->hw.mng_cookie.status & ++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && ++ (vid == adapter->mng_vlan_id)) { ++ /* release control to f/w */ ++ e1000_release_hw_control(adapter); ++ return; ++ } ++ ++ /* remove VID from filter table */ ++ index = (vid >> 5) & 0x7F; ++ vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); ++ vfta &= ~(1 << (vid & 0x1F)); ++ if (hw->mac.ops.write_vfta) ++ hw->mac.ops.write_vfta(hw, index, vfta); ++} ++ ++static void e1000_update_mng_vlan(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ u16 vid = adapter->hw.mng_cookie.vlan_id; ++ u16 old_vid = adapter->mng_vlan_id; ++ ++ if (!adapter->vlgrp) ++ return; ++ ++ if (!vlan_group_get_device(adapter->vlgrp, vid)) { ++ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; ++ if (adapter->hw.mng_cookie.status & ++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { ++ e1000_vlan_rx_add_vid(netdev, vid); ++ adapter->mng_vlan_id = vid; ++ } ++ ++ if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && ++ (vid != old_vid) && ++ !vlan_group_get_device(adapter->vlgrp, old_vid)) ++ e1000_vlan_rx_kill_vid(netdev, old_vid); ++ } else { ++ adapter->mng_vlan_id = vid; ++ } ++} ++ ++ ++static void e1000_vlan_rx_register(struct net_device *netdev, ++ struct vlan_group *grp) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 ctrl, rctl; ++ ++ if (!test_bit(__E1000_DOWN, &adapter->state)) ++ e1000_irq_disable(adapter); ++ adapter->vlgrp = grp; ++ ++ if (grp) { ++ /* enable VLAN tag insert/strip */ ++ ctrl = er32(CTRL); ++ ctrl |= E1000_CTRL_VME; ++ ew32(CTRL, ctrl); ++ ++ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { ++ /* enable VLAN receive filtering */ ++ rctl = er32(RCTL); ++ rctl |= E1000_RCTL_VFE; ++ rctl &= ~E1000_RCTL_CFIEN; ++ ew32(RCTL, rctl); ++ e1000_update_mng_vlan(adapter); ++ } ++ } else { ++ /* disable VLAN tag insert/strip */ ++ ctrl = er32(CTRL); ++ ctrl &= ~E1000_CTRL_VME; ++ ew32(CTRL, ctrl); ++ ++ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { ++ /* disable VLAN filtering */ ++ rctl = er32(RCTL); ++ rctl &= ~E1000_RCTL_VFE; ++ ew32(RCTL, rctl); ++ if (adapter->mng_vlan_id != ++ (u16)E1000_MNG_VLAN_NONE) { ++ e1000_vlan_rx_kill_vid(netdev, ++ adapter->mng_vlan_id); ++ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; ++ } ++ } ++ } ++ ++ if (!test_bit(__E1000_DOWN, &adapter->state)) ++ e1000_irq_enable(adapter); ++} ++ ++static void e1000_restore_vlan(struct e1000_adapter *adapter) ++{ ++ u16 vid; ++ ++ e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp); ++ ++ if (!adapter->vlgrp) ++ return; ++ ++ for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { ++ if (!vlan_group_get_device(adapter->vlgrp, vid)) ++ continue; ++ e1000_vlan_rx_add_vid(adapter->netdev, vid); ++ } ++} ++ ++static void e1000_init_manageability(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u32 manc, manc2h; ++ ++ if (!(adapter->flags & FLAG_MNG_PT_ENABLED)) ++ return; ++ ++ manc = er32(MANC); ++ ++ /* ++ * enable receiving management packets to the host. this will probably ++ * generate destination unreachable messages from the host OS, but ++ * the packets will be handled on SMBUS ++ */ ++ manc |= E1000_MANC_EN_MNG2HOST; ++ manc2h = er32(MANC2H); ++#define E1000_MNG2HOST_PORT_623 (1 << 5) ++#define E1000_MNG2HOST_PORT_664 (1 << 6) ++ manc2h |= E1000_MNG2HOST_PORT_623; ++ manc2h |= E1000_MNG2HOST_PORT_664; ++ ew32(MANC2H, manc2h); ++ ew32(MANC, manc); ++} ++ ++/** ++ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset ++ * @adapter: board private structure ++ * ++ * Configure the Tx unit of the MAC after a reset. ++ **/ ++static void e1000_configure_tx(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ u64 tdba; ++ u32 tdlen, tctl, tipg, tarc; ++ u32 ipgr1, ipgr2; ++ ++ /* Setup the HW Tx Head and Tail descriptor pointers */ ++ tdba = tx_ring->dma; ++ tdlen = tx_ring->count * sizeof(struct e1000_tx_desc); ++ ew32(TDBAL(0), (tdba & DMA_32BIT_MASK)); ++ ew32(TDBAH(0), (tdba >> 32)); ++ ew32(TDLEN(0), tdlen); ++ ew32(TDH(0), 0); ++ ew32(TDT(0), 0); ++ tx_ring->head = E1000_TDH(0); ++ tx_ring->tail = E1000_TDT(0); ++ ++ /* Set the default values for the Tx Inter Packet Gap timer */ ++ tipg = DEFAULT_82543_TIPG_IPGT_COPPER; /* 8 */ ++ ipgr1 = DEFAULT_82543_TIPG_IPGR1; /* 8 */ ++ ipgr2 = DEFAULT_82543_TIPG_IPGR2; /* 6 */ ++ ++ if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN) ++ ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /* 7 */ ++ ++ tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT; ++ tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT; ++ ew32(TIPG, tipg); ++ ++ /* Set the Tx Interrupt Delay register */ ++ ew32(TIDV, adapter->tx_int_delay); ++ /* Tx irq moderation */ ++ ew32(TADV, adapter->tx_abs_int_delay); ++ ++ /* Program the Transmit Control Register */ ++ tctl = er32(TCTL); ++ tctl &= ~E1000_TCTL_CT; ++ tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | ++ (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); ++ ++ if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) { ++ tarc = er32(TARC(0)); ++ /* ++ * set the speed mode bit, we'll clear it if we're not at ++ * gigabit link later ++ */ ++#define SPEED_MODE_BIT (1 << 21) ++ tarc |= SPEED_MODE_BIT; ++ ew32(TARC(0), tarc); ++ } ++ ++ /* errata: program both queues to unweighted RR */ ++ if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) { ++ tarc = er32(TARC(0)); ++ tarc |= 1; ++ ew32(TARC(0), tarc); ++ tarc = er32(TARC(1)); ++ tarc |= 1; ++ ew32(TARC(1), tarc); ++ } ++ ++ hw->mac.ops.config_collision_dist(hw); ++ ++ /* Setup Transmit Descriptor Settings for eop descriptor */ ++ adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; ++ ++ /* only set IDE if we are delaying interrupts using the timers */ ++ if (adapter->tx_int_delay) ++ adapter->txd_cmd |= E1000_TXD_CMD_IDE; ++ ++ /* enable Report Status bit */ ++ adapter->txd_cmd |= E1000_TXD_CMD_RS; ++ ++ ew32(TCTL, tctl); ++ ++ adapter->tx_queue_len = adapter->netdev->tx_queue_len; ++} ++ ++/** ++ * e1000_setup_rctl - configure the receive control registers ++ * @adapter: Board private structure ++ **/ ++#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ ++ (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) ++static void e1000_setup_rctl(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u32 rctl, rfctl; ++ u32 psrctl = 0; ++ u32 pages = 0; ++ ++ /* Program MC offset vector base */ ++ rctl = er32(RCTL); ++ rctl &= ~(3 << E1000_RCTL_MO_SHIFT); ++ rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | ++ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | ++ (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); ++ ++ /* Do not Store bad packets */ ++ rctl &= ~E1000_RCTL_SBP; ++ ++ /* Enable Long Packet receive */ ++ if (adapter->netdev->mtu <= ETH_DATA_LEN) ++ rctl &= ~E1000_RCTL_LPE; ++ else ++ rctl |= E1000_RCTL_LPE; ++ ++ /* Enable hardware CRC frame stripping */ ++ rctl |= E1000_RCTL_SECRC; ++ ++ /* Setup buffer sizes */ ++ rctl &= ~E1000_RCTL_SZ_4096; ++ rctl |= E1000_RCTL_BSEX; ++ switch (adapter->rx_buffer_len) { ++ case 256: ++ rctl |= E1000_RCTL_SZ_256; ++ rctl &= ~E1000_RCTL_BSEX; ++ break; ++ case 512: ++ rctl |= E1000_RCTL_SZ_512; ++ rctl &= ~E1000_RCTL_BSEX; ++ break; ++ case 1024: ++ rctl |= E1000_RCTL_SZ_1024; ++ rctl &= ~E1000_RCTL_BSEX; ++ break; ++ case 2048: ++ default: ++ rctl |= E1000_RCTL_SZ_2048; ++ rctl &= ~E1000_RCTL_BSEX; ++ break; ++ case 4096: ++ rctl |= E1000_RCTL_SZ_4096; ++ break; ++ case 8192: ++ rctl |= E1000_RCTL_SZ_8192; ++ break; ++ case 16384: ++ rctl |= E1000_RCTL_SZ_16384; ++ break; ++ } ++ ++ /* ++ * 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. ++ * ++ * allocations using alloc_page take too long for regular MTU ++ * so only enable packet split for jumbo frames ++ * ++ * Using pages when the page size is greater than 16k wastes ++ * a lot of memory, since we allocate 3 pages at all times ++ * per packet. ++ */ ++ pages = PAGE_USE_COUNT(adapter->netdev->mtu); ++ if (!(adapter->flags & FLAG_IS_ICH) && (pages <= 3) && ++ (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE)) ++ adapter->rx_ps_pages = pages; ++ else ++ adapter->rx_ps_pages = 0; ++ ++ if (adapter->rx_ps_pages) { ++ /* Configure extra packet-split registers */ ++ rfctl = er32(RFCTL); ++ rfctl |= E1000_RFCTL_EXTEN; ++ /* ++ * disable packet split support for IPv6 extension headers, ++ * because some malformed IPv6 headers can hang the Rx ++ */ ++ rfctl |= (E1000_RFCTL_IPV6_EX_DIS | ++ E1000_RFCTL_NEW_IPV6_EXT_DIS); ++ ++ ew32(RFCTL, rfctl); ++ ++ /* Enable Packet split descriptors */ ++ 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; ++ } ++ ++ ew32(PSRCTL, psrctl); ++ } ++ ++ ew32(RCTL, rctl); ++ /* just started the receive unit, no need to restart */ ++ adapter->flags &= ~FLAG_RX_RESTART_NOW; ++} ++ ++/** ++ * e1000_configure_rx - Configure Receive Unit after Reset ++ * @adapter: board private structure ++ * ++ * Configure the Rx unit of the MAC after a reset. ++ **/ ++static void e1000_configure_rx(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ u64 rdba; ++ u32 rdlen, rctl, rxcsum, ctrl_ext; ++ ++ if (adapter->rx_ps_pages) { ++ /* this is a 32 byte descriptor */ ++ rdlen = rx_ring->count * ++ sizeof(union e1000_rx_desc_packet_split); ++ adapter->clean_rx = e1000_clean_rx_irq_ps; ++ adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps; ++#ifdef CONFIG_E1000E_NAPI ++ } else if (adapter->netdev->mtu > ETH_FRAME_LEN + ETH_FCS_LEN) { ++ rdlen = rx_ring->count * sizeof(struct e1000_rx_desc); ++ adapter->clean_rx = e1000_clean_jumbo_rx_irq; ++ adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers; ++#endif ++ } else { ++ rdlen = rx_ring->count * sizeof(struct e1000_rx_desc); ++ adapter->clean_rx = e1000_clean_rx_irq; ++ adapter->alloc_rx_buf = e1000_alloc_rx_buffers; ++ } ++ ++ /* disable receives while setting up the descriptors */ ++ rctl = er32(RCTL); ++ ew32(RCTL, rctl & ~E1000_RCTL_EN); ++ e1e_flush(); ++ msleep(10); ++ ++ /* set the Receive Delay Timer Register */ ++ ew32(RDTR, adapter->rx_int_delay); ++ ++ /* irq moderation */ ++ ew32(RADV, adapter->rx_abs_int_delay); ++ if (adapter->itr_setting != 0) ++ ew32(ITR, 1000000000 / (adapter->itr * 256)); ++ ++ ctrl_ext = er32(CTRL_EXT); ++ /* Reset delay timers after every interrupt */ ++ ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR; ++#ifdef CONFIG_E1000E_NAPI ++ /* Auto-Mask interrupts upon ICR access */ ++ ctrl_ext |= E1000_CTRL_EXT_IAME; ++ ew32(IAM, 0xffffffff); ++#endif ++ ew32(CTRL_EXT, ctrl_ext); ++ e1e_flush(); ++ ++ /* ++ * Setup the HW Rx Head and Tail Descriptor Pointers and ++ * the Base and Length of the Rx Descriptor Ring ++ */ ++ rdba = rx_ring->dma; ++ ew32(RDBAL(0), (rdba & DMA_32BIT_MASK)); ++ ew32(RDBAH(0), (rdba >> 32)); ++ ew32(RDLEN(0), rdlen); ++ ew32(RDH(0), 0); ++ ew32(RDT(0), 0); ++ rx_ring->head = E1000_RDH(0); ++ rx_ring->tail = E1000_RDT(0); ++ ++ /* Enable Receive Checksum Offload for TCP and UDP */ ++ rxcsum = er32(RXCSUM); ++ if (adapter->flags & FLAG_RX_CSUM_ENABLED) { ++ rxcsum |= E1000_RXCSUM_TUOFL; ++ ++ /* ++ * IPv4 payload checksum for UDP fragments must be ++ * used in conjunction with packet-split. ++ */ ++ if (adapter->rx_ps_pages) ++ rxcsum |= E1000_RXCSUM_IPPCSE; ++ } else { ++ rxcsum &= ~E1000_RXCSUM_TUOFL; ++ /* no need to clear IPPCSE as it defaults to 0 */ ++ } ++ ew32(RXCSUM, rxcsum); ++ ++ /* ++ * Enable early receives on supported devices, only takes effect when ++ * packet size is equal or larger than the specified value (in 8 byte ++ * units), e.g. using jumbo frames when setting to E1000_ERT_2048 ++ */ ++ if ((adapter->flags & FLAG_HAS_ERT) && ++ (adapter->netdev->mtu > ETH_DATA_LEN)) { ++ u32 rxdctl = er32(RXDCTL(0)); ++ ew32(RXDCTL(0), rxdctl | 0x3); ++ ew32(ERT, E1000_ERT_2048 | (1 << 13)); ++ /* ++ * With jumbo frames and early-receive enabled, excessive ++ * C4->C2 latencies result in dropped transactions. ++ */ ++ pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, ++ e1000e_driver_name, 55); ++ } else { ++ pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, ++ e1000e_driver_name, ++ PM_QOS_DEFAULT_VALUE); ++ } ++ ++ /* Enable Receives */ ++ ew32(RCTL, rctl); ++} ++ ++/** ++ * e1000_set_multi - Multicast and Promiscuous mode set ++ * @netdev: network interface device structure ++ * ++ * The set_multi entry point is called whenever the multicast address ++ * list or the network interface flags are updated. This routine is ++ * responsible for configuring the hardware for proper multicast, ++ * promiscuous mode, and all-multi behavior. ++ **/ ++static void e1000_set_multi(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ struct e1000_mac_info *mac = &hw->mac; ++ struct dev_mc_list *mc_ptr; ++ u8 *mta_list; ++ u32 rctl; ++ int i; ++ ++ /* Check for Promiscuous and All Multicast modes */ ++ ++ rctl = er32(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; ++ } else { ++ rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); ++ } ++ ++ ew32(RCTL, rctl); ++ ++ if (netdev->mc_count) { ++ mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC); ++ if (!mta_list) ++ return; ++ ++ /* prepare a packed array of only addresses. */ ++ mc_ptr = netdev->mc_list; ++ ++ for (i = 0; i < netdev->mc_count; i++) { ++ if (!mc_ptr) ++ break; ++ memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ++ ETH_ALEN); ++ mc_ptr = mc_ptr->next; ++ } ++ ++ hw->mac.ops.update_mc_addr_list(hw, mta_list, i, 1, ++ mac->rar_entry_count); ++ kfree(mta_list); ++ } else { ++ /* ++ * if we're called from probe, we might not have ++ * anything to do here, so clear out the list ++ */ ++ hw->mac.ops.update_mc_addr_list(hw, NULL, 0, 1, ++ mac->rar_entry_count); ++ } ++} ++ ++/** ++ * e1000_configure - configure the hardware for Rx and Tx ++ * @adapter: private board structure ++ **/ ++static void e1000_configure(struct e1000_adapter *adapter) ++{ ++ e1000_set_multi(adapter->netdev); ++ ++ e1000_restore_vlan(adapter); ++ e1000_init_manageability(adapter); ++ ++ e1000_configure_tx(adapter); ++ e1000_setup_rctl(adapter); ++ e1000_configure_rx(adapter); ++ adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring)); ++} ++ ++/** ++ * e1000e_reset - bring the hardware into a known good state ++ * ++ * This function boots the hardware and enables some settings that ++ * require a configuration cycle of the hardware - those cannot be ++ * set/changed during runtime. After reset the device needs to be ++ * properly configured for Rx, Tx etc. ++ */ ++void e1000_reset(struct e1000_adapter *adapter) ++{ ++ struct e1000_mac_info *mac = &adapter->hw.mac; ++ struct e1000_fc_info *fc = &adapter->hw.fc; ++ struct e1000_hw *hw = &adapter->hw; ++ u32 tx_space, min_tx_space, min_rx_space; ++ u32 pba = adapter->pba; ++ u16 hwm; ++ ++ /* reset Packet Buffer Allocation to default */ ++ ew32(PBA, pba); ++ ++ if (adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN ) { ++ /* ++ * To maintain wire speed transmits, the Tx FIFO should be ++ * large enough to accommodate two full transmit packets, ++ * rounded up to the next 1KB and expressed in KB. Likewise, ++ * the Rx FIFO should be large enough to accommodate at least ++ * one full receive packet and is similarly rounded up and ++ * expressed in KB. ++ */ ++ pba = er32(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; ++ /* ++ * the Tx fifo also stores 16 bytes of information about the tx ++ * but don't include ethernet FCS because hardware appends it ++ */ ++ min_tx_space = (adapter->max_frame_size + ++ sizeof(struct e1000_tx_desc) - ++ ETH_FCS_LEN) * 2; ++ min_tx_space = ALIGN(min_tx_space, 1024); ++ min_tx_space >>= 10; ++ /* software strips receive CRC, so leave room for it */ ++ min_rx_space = adapter->max_frame_size; ++ 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 -= min_tx_space - tx_space; ++ ++ /* ++ * if short on Rx space, Rx wins and must trump tx ++ * adjustment or use Early Receive if available ++ */ ++ if ((pba < min_rx_space) && ++ (!(adapter->flags & FLAG_HAS_ERT))) ++ /* ERT enabled in e1000_configure_rx */ ++ pba = min_rx_space; ++ } ++ ++ ew32(PBA, pba); ++ } ++ ++ ++ /* ++ * flow control settings ++ * ++ * The high water mark must be low enough to fit one full frame ++ * (or the size used for early receive) above it in the Rx FIFO. ++ * Set it to the lower of: ++ * - 90% of the Rx FIFO size, and ++ * - the full Rx FIFO size minus the early receive size (for parts ++ * with ERT support assuming ERT set to E1000_ERT_2048), or ++ * - the full Rx FIFO size minus one full frame ++ */ ++ if (adapter->flags & FLAG_HAS_ERT) ++ hwm = min(((pba << 10) * 9 / 10), ++ ((pba << 10) - (E1000_ERT_2048 << 3))); ++ else ++ hwm = min(((pba << 10) * 9 / 10), ++ ((pba << 10) - adapter->max_frame_size)); ++ ++ fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */ ++ fc->low_water = fc->high_water - 8; ++ ++ if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME) ++ fc->pause_time = 0xFFFF; ++ else ++ fc->pause_time = E1000_FC_PAUSE_TIME; ++ fc->send_xon = 1; ++ fc->type = fc->original_type; ++ ++ /* Allow time for pending master requests to run */ ++ mac->ops.reset_hw(hw); ++ ++ /* ++ * For parts with AMT enabled, let the firmware know ++ * that the network interface is in control ++ */ ++ if (adapter->flags & FLAG_HAS_AMT) ++ e1000_get_hw_control(adapter); ++ ++ ew32(WUC, 0); ++ ++ if (mac->ops.init_hw(hw)) ++ e_err("Hardware Error\n"); ++ ++ e1000_update_mng_vlan(adapter); ++ ++ /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ ++ ew32(VET, ETH_P_8021Q); ++ ++ e1000_reset_adaptive_generic(hw); ++ ++ if (!hw->phy.ops.get_info) ++ return; ++ ++ hw->phy.ops.get_info(hw); ++ ++ if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) { ++ 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 ++ */ ++ hw->phy.ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); ++ phy_data &= ~IGP02E1000_PM_SPD; ++ hw->phy.ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); ++ } ++} ++ ++int e1000_up(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ ++ /* hardware has been reset, we need to reload some things */ ++ e1000_configure(adapter); ++ ++ clear_bit(__E1000_DOWN, &adapter->state); ++ ++#ifdef CONFIG_E1000E_NAPI ++ napi_enable(&adapter->napi); ++#endif ++#ifdef CONFIG_E1000E_MSIX ++ if (adapter->msix_entries) ++ e1000_configure_msix(adapter); ++#endif /* CONFIG_E1000E_MSIX */ ++ e1000_irq_enable(adapter); ++ ++ /* fire a link change interrupt to start the watchdog */ ++ ew32(ICS, E1000_ICS_LSC); ++ return 0; ++} ++ ++void e1000_down(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct e1000_hw *hw = &adapter->hw; ++ u32 tctl, rctl; ++ ++ /* ++ * signal that we're down so the interrupt handler does not ++ * reschedule our watchdog timer ++ */ ++ set_bit(__E1000_DOWN, &adapter->state); ++ ++ /* disable receives in the hardware */ ++ rctl = er32(RCTL); ++ ew32(RCTL, rctl & ~E1000_RCTL_EN); ++ /* flush and sleep below */ ++ ++ netif_stop_queue(netdev); ++ ++ /* disable transmits in the hardware */ ++ tctl = er32(TCTL); ++ tctl &= ~E1000_TCTL_EN; ++ ew32(TCTL, tctl); ++ /* flush both disables and wait for them to finish */ ++ e1e_flush(); ++ msleep(10); ++ ++#ifdef CONFIG_E1000E_NAPI ++ napi_disable(&adapter->napi); ++#endif ++ ++ e1000_irq_disable(adapter); ++ ++ del_timer_sync(&adapter->watchdog_timer); ++ del_timer_sync(&adapter->phy_info_timer); ++ ++ netdev->tx_queue_len = adapter->tx_queue_len; ++ netif_carrier_off(netdev); ++ adapter->link_speed = 0; ++ adapter->link_duplex = 0; ++ ++ e1000_reset(adapter); ++ e1000_clean_tx_ring(adapter); ++ e1000_clean_rx_ring(adapter); ++ ++ /* ++ * TODO: for power management, we could drop the link and ++ * pci_disable_device here. ++ */ ++} ++ ++void e1000_reinit_locked(struct e1000_adapter *adapter) ++{ ++ might_sleep(); ++ while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) ++ msleep(1); ++ e1000_down(adapter); ++ e1000_up(adapter); ++ clear_bit(__E1000_RESETTING, &adapter->state); ++} ++ ++/** ++ * e1000_sw_init - Initialize general software structures (struct e1000_adapter) ++ * @adapter: board private structure to initialize ++ * ++ * e1000_sw_init initializes the Adapter private data structure. ++ * Fields are initialized based on PCI device information and ++ * OS network device settings (MTU size). ++ **/ ++static int __devinit e1000_sw_init(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ s32 rc; ++ ++ adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN; ++ adapter->rx_ps_bsize0 = 128; ++ adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; ++ adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; ++ ++ /* Set various function pointers */ ++ adapter->ei->init_ops(&adapter->hw); ++ ++ rc = adapter->hw.mac.ops.init_params(&adapter->hw); ++ if (rc) ++ return rc; ++ ++ rc = adapter->hw.nvm.ops.init_params(&adapter->hw); ++ if (rc) ++ return rc; ++ ++ rc = adapter->hw.phy.ops.init_params(&adapter->hw); ++ if (rc) ++ return rc; ++ ++#ifdef CONFIG_E1000E_MSIX ++ e1000_set_interrupt_capability(adapter); ++ ++#endif /* CONFIG_E1000E_MSIX */ ++ if (e1000_alloc_queues(adapter)) ++ return -ENOMEM; ++ ++ spin_lock_init(&adapter->tx_queue_lock); ++ ++ /* Explicitly disable IRQ since the NIC can be in any state. */ ++ e1000_irq_disable(adapter); ++ ++ spin_lock_init(&adapter->stats_lock); ++ ++ set_bit(__E1000_DOWN, &adapter->state); ++ return 0; ++} ++ ++/** ++ * e1000_intr_msi_test - Interrupt Handler ++ * @irq: interrupt number ++ * @data: pointer to a network interface device structure ++ **/ ++static irqreturn_t e1000_intr_msi_test(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 icr = er32(ICR); ++ ++ e_dbg("icr is %08X\n", icr); ++ if (icr & E1000_ICR_RXSEQ) { ++ adapter->flags &= ~FLAG_MSI_TEST_FAILED; ++ wmb(); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/** ++ * e1000_test_msi_interrupt - Returns 0 for successful test ++ * @adapter: board private struct ++ * ++ * code flow taken from tg3.c ++ **/ ++static int e1000_test_msi_interrupt(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct e1000_hw *hw = &adapter->hw; ++ int err; ++ ++ /* poll_enable hasn't been called yet, so don't need disable */ ++ /* clear any pending events */ ++ er32(ICR); ++ ++ /* free the real vector and request a test handler */ ++ e1000_free_irq(adapter); ++#ifdef CONFIG_E1000E_MSIX ++ e1000_reset_interrupt_capability(adapter); ++#endif ++ ++ /* Assume that the test fails, if it succeeds then the test ++ * MSI irq handler will unset this flag */ ++ adapter->flags |= FLAG_MSI_TEST_FAILED; ++ ++ err = pci_enable_msi(adapter->pdev); ++ if (err) ++ goto msi_test_failed; ++ ++ err = request_irq(adapter->pdev->irq, &e1000_intr_msi_test, 0, ++ netdev->name, netdev); ++ if (err) { ++ pci_disable_msi(adapter->pdev); ++ goto msi_test_failed; ++ } ++ ++ wmb(); ++ ++ e1000_irq_enable(adapter); ++ ++ /* fire an unusual interrupt on the test handler */ ++ ew32(ICS, E1000_ICS_RXSEQ); ++ e1e_flush(); ++ msleep(50); ++ ++ e1000_irq_disable(adapter); ++ ++ rmb(); ++ ++ if (adapter->flags & FLAG_MSI_TEST_FAILED) { ++#ifdef CONFIG_E1000E_MSIX ++ adapter->int_mode = E1000E_INT_MODE_LEGACY; ++#endif ++ err = -EIO; ++ e_info("MSI interrupt test failed!\n"); ++ } ++ ++ free_irq(adapter->pdev->irq, netdev); ++ pci_disable_msi(adapter->pdev); ++ ++ if (err == -EIO) ++ goto msi_test_failed; ++ ++ /* okay so the test worked, restore settings */ ++ e_dbg("MSI interrupt test succeeded!\n"); ++msi_test_failed: ++#ifdef CONFIG_E1000E_MSIX ++ e1000_set_interrupt_capability(adapter); ++#else ++ /* restore the original vector, even if it failed */ ++#endif ++ e1000_request_irq(adapter); ++ return err; ++} ++ ++/** ++ * e1000_test_msi - Returns 0 if MSI test succeeds or INTx mode is restored ++ * @adapter: board private struct ++ * ++ * code flow taken from tg3.c, called with e1000 interrupts disabled. ++ **/ ++static int e1000_test_msi(struct e1000_adapter *adapter) ++{ ++ int err; ++ u16 pci_cmd; ++ ++ if (!(adapter->flags & FLAG_MSI_ENABLED)) ++ return 0; ++ ++ /* disable SERR in case the MSI write causes a master abort */ ++ pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd); ++ pci_write_config_word(adapter->pdev, PCI_COMMAND, ++ pci_cmd & ~PCI_COMMAND_SERR); ++ ++ err = e1000_test_msi_interrupt(adapter); ++ ++ /* restore previous setting of command word */ ++ pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd); ++ ++ /* success ! */ ++ if (!err) ++ return 0; ++ ++ /* EIO means MSI test failed */ ++ if (err != -EIO) ++ return err; ++ ++ /* back to INTx mode */ ++ e_warn("MSI interrupt test failed, using legacy interrupt.\n"); ++ ++ e1000_free_irq(adapter); ++ ++ err = e1000_request_irq(adapter); ++ ++ return err; ++} ++ ++/** ++ * e1000_open - Called when a network interface is made active ++ * @netdev: network interface device structure ++ * ++ * Returns 0 on success, negative value on failure ++ * ++ * The open entry point is called when a network interface is made ++ * active by the system (IFF_UP). At this point all resources needed ++ * for transmit and receive operations are allocated, the interrupt ++ * handler is registered with the OS, the watchdog timer is started, ++ * and the stack is notified that the interface is ready. ++ **/ ++static int e1000_open(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ int err; ++ ++ /* disallow open during test */ ++ if (test_bit(__E1000_TESTING, &adapter->state)) ++ return -EBUSY; ++ ++ /* allocate transmit descriptors */ ++ err = e1000_setup_tx_resources(adapter); ++ if (err) ++ goto err_setup_tx; ++ ++ /* allocate receive descriptors */ ++ err = e1000_setup_rx_resources(adapter); ++ if (err) ++ goto err_setup_rx; ++ ++ e1000_power_up_phy(hw); ++ ++ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; ++ if ((adapter->hw.mng_cookie.status & ++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN)) ++ e1000_update_mng_vlan(adapter); ++ ++ /* ++ * If AMT is enabled, let the firmware know that the network ++ * interface is now open ++ */ ++ if (adapter->flags & FLAG_HAS_AMT) ++ e1000_get_hw_control(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. ++ */ ++ e1000_configure(adapter); ++ ++ err = e1000_request_irq(adapter); ++ if (err) ++ goto err_req_irq; ++ ++ /* ++ * Work around PCIe errata with MSI interrupts causing some chipsets to ++ * ignore e1000e MSI messages, which means we need to test our MSI ++ * interrupt now ++ */ ++#ifdef CONFIG_E1000E_MSIX ++ if (adapter->int_mode != E1000E_INT_MODE_LEGACY) ++#endif ++ { ++ err = e1000_test_msi(adapter); ++ if (err) { ++ e_err("Interrupt allocation failed\n"); ++ goto err_req_irq; ++ } ++ } ++ ++ /* From here on the code is the same as e1000_up() */ ++ clear_bit(__E1000_DOWN, &adapter->state); ++ ++#ifdef CONFIG_E1000E_NAPI ++ napi_enable(&adapter->napi); ++#endif ++ ++ e1000_irq_enable(adapter); ++ ++ /* fire a link status change interrupt to start the watchdog */ ++ ew32(ICS, E1000_ICS_LSC); ++ ++ return 0; ++ ++err_req_irq: ++ e1000_release_hw_control(adapter); ++ if (!adapter->wol && hw->phy.ops.power_down) ++ hw->phy.ops.power_down(hw); ++ e1000_free_rx_resources(adapter); ++err_setup_rx: ++ e1000_free_tx_resources(adapter); ++err_setup_tx: ++ e1000_reset(adapter); ++ ++ return err; ++} ++ ++/** ++ * e1000_close - Disables a network interface ++ * @netdev: network interface device structure ++ * ++ * Returns 0, this is not allowed to fail ++ * ++ * The close entry point is called when an interface is de-activated ++ * by the OS. The hardware is still under the drivers control, but ++ * needs to be disabled. A global MAC reset is issued to stop the ++ * hardware, and all transmit and receive resources are freed. ++ **/ ++static int e1000_close(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ ++ WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); ++ e1000_down(adapter); ++ if (!adapter->wol && hw->phy.ops.power_down) ++ hw->phy.ops.power_down(hw); ++ e1000_free_irq(adapter); ++ ++ e1000_free_tx_resources(adapter); ++ e1000_free_rx_resources(adapter); ++ ++ /* ++ * kill manageability vlan ID if supported, but not if a vlan with ++ * the same ID is registered on the host OS (let 8021q kill it) ++ */ ++ if ((adapter->hw.mng_cookie.status & ++ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && ++ !(adapter->vlgrp && ++ vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) ++ e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); ++ ++ /* ++ * If AMT is enabled, let the firmware know that the network ++ * interface is now closed ++ */ ++ if (adapter->flags & FLAG_HAS_AMT) ++ e1000_release_hw_control(adapter); ++ ++ return 0; ++} ++/** ++ * e1000_set_mac - Change the Ethernet Address of the NIC ++ * @netdev: network interface device structure ++ * @p: pointer to an address structure ++ * ++ * Returns 0 on success, negative on failure ++ **/ ++static int e1000_set_mac(struct net_device *netdev, void *p) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct sockaddr *addr = p; ++ ++ if (!is_valid_ether_addr(addr->sa_data)) ++ return -EADDRNOTAVAIL; ++ ++ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ++ memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); ++ ++ adapter->hw.mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, 0); ++ ++ if (adapter->flags & FLAG_RESET_OVERWRITES_LAA) { ++ /* activate the work around */ ++ e1000_set_laa_state_82571(&adapter->hw, 1); ++ ++ /* ++ * 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 e1000_watchdog), the actual LAA is in one ++ * of the RARs and no incoming packets directed to this port ++ * are dropped. Eventually the LAA will be in RAR[0] and ++ * RAR[14] ++ */ ++ adapter->hw.mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, ++ adapter->hw.mac.rar_entry_count - 1); ++ } ++ ++ return 0; ++} ++ ++/** ++ * Need to wait a few seconds after link up to get diagnostic information from ++ * the phy ++ **/ ++static void e1000_update_phy_info(unsigned long data) ++{ ++ struct e1000_adapter *adapter = (struct e1000_adapter *) data; ++ if (adapter->hw.phy.ops.get_info) ++ adapter->hw.phy.ops.get_info(&adapter->hw); ++} ++ ++/** ++ * e1000_update_stats - Update the board statistics counters ++ * @adapter: board private structure ++ **/ ++void e1000_update_stats(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++#ifdef HAVE_PCI_ERS ++ struct pci_dev *pdev = adapter->pdev; ++#endif ++ unsigned long irq_flags; ++ u16 phy_tmp; ++ ++#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF ++ ++ /* ++ * Prevent stats update while adapter is being reset, or if the pci ++ * connection is down. ++ */ ++ if (adapter->link_speed == 0) ++ return; ++#ifdef HAVE_PCI_ERS ++ if (pci_channel_offline(pdev)) ++ return; ++#endif ++ ++ spin_lock_irqsave(&adapter->stats_lock, irq_flags); ++ ++ /* ++ * these counters are modified from e1000_adjust_tbi_stats, ++ * called from the interrupt context, so they must only ++ * be written while holding adapter->stats_lock ++ */ ++ ++ adapter->stats.crcerrs += er32(CRCERRS); ++ adapter->stats.gprc += er32(GPRC); ++ adapter->stats.gorc += er32(GORCL); ++ er32(GORCH); /* Clear gorc */ ++ adapter->stats.bprc += er32(BPRC); ++ adapter->stats.mprc += er32(MPRC); ++ adapter->stats.roc += er32(ROC); ++ ++ adapter->stats.mpc += er32(MPC); ++ adapter->stats.scc += er32(SCC); ++ adapter->stats.ecol += er32(ECOL); ++ adapter->stats.mcc += er32(MCC); ++ adapter->stats.latecol += er32(LATECOL); ++ adapter->stats.dc += er32(DC); ++ adapter->stats.xonrxc += er32(XONRXC); ++ adapter->stats.xontxc += er32(XONTXC); ++ adapter->stats.xoffrxc += er32(XOFFRXC); ++ adapter->stats.xofftxc += er32(XOFFTXC); ++ adapter->stats.gptc += er32(GPTC); ++ adapter->stats.gotc += er32(GOTCL); ++ er32(GOTCH); /* Clear gotc */ ++ adapter->stats.rnbc += er32(RNBC); ++ adapter->stats.ruc += er32(RUC); ++ ++ adapter->stats.mptc += er32(MPTC); ++ adapter->stats.bptc += er32(BPTC); ++ ++ /* used for adaptive IFS */ ++ ++ hw->mac.tx_packet_delta = er32(TPT); ++ adapter->stats.tpt += hw->mac.tx_packet_delta; ++ hw->mac.collision_delta = er32(COLC); ++ adapter->stats.colc += hw->mac.collision_delta; ++ ++ adapter->stats.algnerrc += er32(ALGNERRC); ++ adapter->stats.rxerrc += er32(RXERRC); ++ if (hw->mac.type != e1000_82574) ++ adapter->stats.tncrs += er32(TNCRS); ++ adapter->stats.cexterr += er32(CEXTERR); ++ adapter->stats.tsctc += er32(TSCTC); ++ adapter->stats.tsctfc += er32(TSCTFC); ++ ++ /* Fill out the OS statistics structure */ ++ adapter->net_stats.multicast = adapter->stats.mprc; ++ adapter->net_stats.collisions = adapter->stats.colc; ++ ++ /* Rx Errors */ ++ ++ /* ++ * RLEC on some newer hardware can be incorrect so build ++ * our own version based on RUC and ROC ++ */ ++ adapter->net_stats.rx_errors = adapter->stats.rxerrc + ++ adapter->stats.crcerrs + adapter->stats.algnerrc + ++ adapter->stats.ruc + adapter->stats.roc + ++ adapter->stats.cexterr; ++ adapter->net_stats.rx_length_errors = adapter->stats.ruc + ++ adapter->stats.roc; ++ adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; ++ adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; ++ 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 */ ++ ++ /* Phy Stats */ ++ if (hw->phy.media_type == e1000_media_type_copper) { ++ if ((adapter->link_speed == SPEED_1000) && ++ (!hw->phy.ops.read_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { ++ phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; ++ adapter->phy_stats.idle_errors += phy_tmp; ++ } ++ } ++ ++ /* Management Stats */ ++ adapter->stats.mgptc += er32(MGTPTC); ++ adapter->stats.mgprc += er32(MGTPRC); ++ adapter->stats.mgpdc += er32(MGTPDC); ++ ++ spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); ++} ++ ++#ifdef SIOCGMIIPHY ++/** ++ * e1000_phy_read_status - Update the PHY register status snapshot ++ * @adapter: board private structure ++ **/ ++static void e1000_phy_read_status(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ struct e1000_phy_regs *phy = &adapter->phy_regs; ++ int ret_val; ++ unsigned long irq_flags; ++ ++ ++ spin_lock_irqsave(&adapter->stats_lock, irq_flags); ++ ++ if ((er32(STATUS) & E1000_STATUS_LU) && ++ (adapter->hw.phy.media_type == e1000_media_type_copper)) { ++ ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy->bmcr); ++ ret_val |= hw->phy.ops.read_reg(hw, PHY_STATUS, &phy->bmsr); ++ ret_val |= hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, ++ &phy->advertise); ++ ret_val |= hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, &phy->lpa); ++ ret_val |= hw->phy.ops.read_reg(hw, PHY_AUTONEG_EXP, ++ &phy->expansion); ++ ret_val |= hw->phy.ops.read_reg(hw, PHY_1000T_CTRL, ++ &phy->ctrl1000); ++ ret_val |= hw->phy.ops.read_reg(hw, PHY_1000T_STATUS, ++ &phy->stat1000); ++ ret_val |= hw->phy.ops.read_reg(hw, PHY_EXT_STATUS, ++ &phy->estatus); ++ if (ret_val) ++ e_warn("Error reading PHY register\n"); ++ } else { ++ /* ++ * Do not read PHY registers if link is not up ++ * Set values to typical power-on defaults ++ */ ++ phy->bmcr = (BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_FULLDPLX); ++ phy->bmsr = (BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | ++ BMSR_10HALF | BMSR_ESTATEN | BMSR_ANEGCAPABLE | ++ BMSR_ERCAP); ++ phy->advertise = (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP | ++ ADVERTISE_ALL | ADVERTISE_CSMA); ++ phy->lpa = 0; ++ phy->expansion = EXPANSION_ENABLENPAGE; ++ phy->ctrl1000 = ADVERTISE_1000FULL; ++ phy->stat1000 = 0; ++ phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF); ++ } ++ ++ spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); ++} ++ ++#endif /* SIOCGMIIPHY */ ++static void e1000_print_link_info(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u32 ctrl = er32(CTRL); ++ ++ e_info("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" ))); ++} ++ ++static bool e1000_has_link(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ bool link_active = 0; ++ s32 ret_val = 0; ++ ++ /* ++ * get_link_status is set on LSC (link status) interrupt or ++ * Rx sequence error interrupt. get_link_status will stay ++ * false until the check_for_link establishes link ++ * for copper adapters ONLY ++ */ ++ switch (hw->phy.media_type) { ++ case e1000_media_type_copper: ++ if (hw->mac.get_link_status) { ++ ret_val = hw->mac.ops.check_for_link(hw); ++ link_active = !hw->mac.get_link_status; ++ } else { ++ link_active = 1; ++ } ++ break; ++ case e1000_media_type_fiber: ++ ret_val = hw->mac.ops.check_for_link(hw); ++ link_active = !!(er32(STATUS) & E1000_STATUS_LU); ++ break; ++ case e1000_media_type_internal_serdes: ++ ret_val = hw->mac.ops.check_for_link(hw); ++ link_active = adapter->hw.mac.serdes_has_link; ++ break; ++ default: ++ case e1000_media_type_unknown: ++ break; ++ } ++ ++ if ((ret_val == E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) && ++ (er32(CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) { ++ /* See e1000_kmrn_lock_loss_workaround_ich8lan() */ ++ e_info("Gigabit has been disabled, downgrading speed\n"); ++ } ++ ++ return link_active; ++} ++ ++static void e1000e_enable_receives(struct e1000_adapter *adapter) ++{ ++ /* make sure the receive unit is started */ ++ if ((adapter->flags & FLAG_RX_NEEDS_RESTART) && ++ (adapter->flags & FLAG_RX_RESTART_NOW)) { ++ struct e1000_hw *hw = &adapter->hw; ++ u32 rctl = er32(RCTL); ++ ew32(RCTL, rctl | E1000_RCTL_EN); ++ adapter->flags &= ~FLAG_RX_RESTART_NOW; ++ } ++} ++ ++/** ++ * e1000_watchdog - Timer Call-back ++ * @data: pointer to adapter cast into an unsigned long ++ **/ ++static void e1000_watchdog(unsigned long data) ++{ ++ struct e1000_adapter *adapter = (struct e1000_adapter *) data; ++ ++ /* Do the rest outside of interrupt context */ ++ schedule_work(&adapter->watchdog_task); ++ ++ /* TODO: make this use queue_delayed_work() */ ++} ++ ++static void e1000_watchdog_task(struct work_struct *work) ++{ ++ struct e1000_adapter *adapter = container_of(work, ++ struct e1000_adapter, watchdog_task); ++ struct net_device *netdev = adapter->netdev; ++ struct e1000_mac_info *mac = &adapter->hw.mac; ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ struct e1000_hw *hw = &adapter->hw; ++ u32 link, tctl; ++ int tx_pending = 0; ++ unsigned long timer_val; ++ ++ link = e1000_has_link(adapter); ++ if ((netif_carrier_ok(netdev)) && link) { ++ e1000e_enable_receives(adapter); ++ goto link_up; ++ } ++ ++ if ((e1000_enable_tx_pkt_filtering_generic(hw)) && ++ (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id)) ++ e1000_update_mng_vlan(adapter); ++ ++ if (link) { ++ if (!netif_carrier_ok(netdev)) { ++ bool txb2b = 1; ++#ifdef SIOCGMIIPHY ++ /* update snapshot of PHY registers on LSC */ ++ e1000_phy_read_status(adapter); ++#endif ++ mac->ops.get_link_up_info(&adapter->hw, ++ &adapter->link_speed, ++ &adapter->link_duplex); ++ e1000_print_link_info(adapter); ++ ++ /* ++ * On supported PHYs, check for duplex mismatch only ++ * if link has autonegotiated at 10/100 half ++ */ ++ if ((hw->phy.type == e1000_phy_igp_3 || ++ hw->phy.type == e1000_phy_bm) && ++ (hw->mac.autoneg == TRUE) && ++ (adapter->link_speed == SPEED_10 || ++ adapter->link_speed == SPEED_100) && ++ (adapter->link_duplex == HALF_DUPLEX)) { ++ u16 autoneg_exp; ++ ++ hw->phy.ops.read_reg(hw, PHY_AUTONEG_EXP, ++ &autoneg_exp); ++ ++ if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS)) ++ e_info("Autonegotiated half duplex but" ++ " link partner cannot autoneg. " ++ " Try forcing full duplex if " ++ "link gets many collisions."); ++ } ++ ++ /* ++ * 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 = 0; ++ netdev->tx_queue_len = 10; ++ adapter->tx_timeout_factor = 16; ++ break; ++ case SPEED_100: ++ txb2b = 0; ++ netdev->tx_queue_len = 100; ++ /* maybe add some timeout factor ? */ ++ break; ++ } ++ ++ /* ++ * workaround: re-program speed mode bit after ++ * link-up event ++ */ ++ if ((adapter->flags & FLAG_TARC_SPEED_MODE_BIT) && ++ !txb2b) { ++ u32 tarc0; ++ tarc0 = er32(TARC(0)); ++ tarc0 &= ~SPEED_MODE_BIT; ++ ew32(TARC(0), tarc0); ++ } ++ ++#ifdef NETIF_F_TSO ++ /* ++ * disable TSO for pcie and 10/100 speeds, to avoid ++ * some hardware issues ++ */ ++ if (!(adapter->flags & FLAG_TSO_FORCE)) { ++ switch (adapter->link_speed) { ++ case SPEED_10: ++ case SPEED_100: ++ e_info("10/100 speed: disabling TSO\n"); ++ netdev->features &= ~NETIF_F_TSO; ++#ifdef NETIF_F_TSO6 ++ netdev->features &= ~NETIF_F_TSO6; ++#endif ++ break; ++ case SPEED_1000: ++ netdev->features |= NETIF_F_TSO; ++#ifdef NETIF_F_TSO6 ++ netdev->features |= NETIF_F_TSO6; ++#endif ++ break; ++ default: ++ /* oops */ ++ break; ++ } ++ } ++#endif ++ ++ /* ++ * enable transmits in the hardware, need to do this ++ * after setting TARC(0) ++ */ ++ tctl = er32(TCTL); ++ tctl |= E1000_TCTL_EN; ++ ew32(TCTL, tctl); ++ ++ netif_carrier_on(netdev); ++ netif_wake_queue(netdev); ++ } ++ } else { ++ if (netif_carrier_ok(netdev)) { ++ adapter->link_speed = 0; ++ adapter->link_duplex = 0; ++ e_info("Link is Down\n"); ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ ++ if (adapter->flags & FLAG_RX_NEEDS_RESTART) ++ schedule_work(&adapter->reset_task); ++ } ++ } ++ ++link_up: ++ e1000_update_stats(adapter); ++ ++ mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; ++ adapter->tpt_old = adapter->stats.tpt; ++ mac->collision_delta = adapter->stats.colc - adapter->colc_old; ++ adapter->colc_old = adapter->stats.colc; ++ ++ adapter->gorc = adapter->stats.gorc - adapter->gorc_old; ++ adapter->gorc_old = adapter->stats.gorc; ++ adapter->gotc = adapter->stats.gotc - adapter->gotc_old; ++ adapter->gotc_old = adapter->stats.gotc; ++ ++ e1000_update_adaptive_generic(&adapter->hw); ++ ++ if (!netif_carrier_ok(netdev)) { ++ tx_pending = (e1000_desc_unused(tx_ring) + 1 < ++ tx_ring->count); ++ if (tx_pending) { ++ /* ++ * 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 */ ++#ifdef CONFIG_E1000E_MSIX ++ if (adapter->msix_entries) ++ ew32(ICS, adapter->rx_ring->ims_val); ++ else ++#endif ++ ew32(ICS, E1000_ICS_RXDMT0); ++ ++ /* Force detection of hung controller every watchdog period */ ++ adapter->detect_tx_hung = 1; ++ ++ /* ++ * With 82571 controllers, LAA may be overwritten due to controller ++ * reset from the other port. Set the appropriate LAA in RAR[0] ++ */ ++ if (e1000_get_laa_state_82571(hw)) ++ hw->mac.ops.rar_set(hw, adapter->hw.mac.addr, 0); ++ ++ /* Reset the timer */ ++ if (!test_bit(__E1000_DOWN, &adapter->state)) { ++ timer_val = jiffies + usecs_to_jiffies(adapter->stats_freq_us); ++ if (adapter->stats_freq_us > 1000000) ++ timer_val = round_jiffies(timer_val); ++ mod_timer(&adapter->watchdog_timer, timer_val); ++ } ++} ++ ++#define E1000_TX_FLAGS_CSUM 0x00000001 ++#define E1000_TX_FLAGS_VLAN 0x00000002 ++#define E1000_TX_FLAGS_TSO 0x00000004 ++#define E1000_TX_FLAGS_IPV4 0x00000008 ++#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000 ++#define E1000_TX_FLAGS_VLAN_SHIFT 16 ++ ++static int e1000_tso(struct e1000_adapter *adapter, ++ struct sk_buff *skb) ++{ ++#ifdef NETIF_F_TSO ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ struct e1000_context_desc *context_desc; ++ struct e1000_buffer *buffer_info; ++ unsigned int i; ++ u32 cmd_length = 0; ++ u16 ipcse = 0, tucse, mss; ++ u8 ipcss, ipcso, tucss, tucso, hdr_len; ++ int err; ++ ++ if (!skb_is_gso(skb)) ++ return 0; ++ ++ if (skb_header_cloned(skb)) { ++ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); ++ if (err) ++ return err; ++ } ++ ++ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); ++ mss = skb_shinfo(skb)->gso_size; ++ if (skb->protocol == htons(ETH_P_IP)) { ++ 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_transport_offset(skb) - 1; ++#ifdef NETIF_F_TSO6 ++ } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { ++ 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_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 | ++ E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); ++ ++ 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; ++ context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse); ++ context_desc->upper_setup.tcp_fields.tucss = tucss; ++ context_desc->upper_setup.tcp_fields.tucso = tucso; ++ context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse); ++ context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss); ++ context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; ++ context_desc->cmd_and_length = cpu_to_le32(cmd_length); ++ ++ buffer_info->time_stamp = jiffies; ++ buffer_info->next_to_watch = i; ++ ++ i++; ++ if (i == tx_ring->count) ++ i = 0; ++ tx_ring->next_to_use = i; ++ ++ return 1; ++#else ++ return 0; ++#endif ++} ++ ++static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) ++{ ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ struct e1000_context_desc *context_desc; ++ struct e1000_buffer *buffer_info; ++ unsigned int i; ++ u8 css; ++ u32 cmd_len = E1000_TXD_CMD_DEXT; ++ ++ if (skb->ip_summed != CHECKSUM_PARTIAL) ++ return 0; ++ ++ switch (skb->protocol) { ++ case __constant_htons(ETH_P_IP): ++ if (ip_hdr(skb)->protocol == IPPROTO_TCP) ++ cmd_len |= E1000_TXD_CMD_TCP; ++ break; ++ case __constant_htons(ETH_P_IPV6): ++ /* XXX not handling all IPV6 headers */ ++ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) ++ cmd_len |= E1000_TXD_CMD_TCP; ++ break; ++ default: ++ if (unlikely(net_ratelimit())) ++ e_warn("checksum_partial proto=%x!\n", skb->protocol); ++ break; ++ } ++ ++ css = skb_transport_offset(skb); ++ ++ 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_offset; ++ context_desc->upper_setup.tcp_fields.tucse = 0; ++ context_desc->tcp_seg_setup.data = 0; ++ context_desc->cmd_and_length = cpu_to_le32(cmd_len); ++ ++ buffer_info->time_stamp = jiffies; ++ buffer_info->next_to_watch = i; ++ ++ i++; ++ if (i == tx_ring->count) ++ i = 0; ++ tx_ring->next_to_use = i; ++ ++ return 1; ++} ++ ++#define E1000_MAX_PER_TXD 8192 ++#define E1000_MAX_TXD_PWR 12 ++ ++static int e1000_tx_map(struct e1000_adapter *adapter, ++ struct sk_buff *skb, unsigned int first, ++ unsigned int max_per_txd, unsigned int nr_frags, ++ unsigned int mss) ++{ ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_buffer *buffer_info; ++ unsigned int len = skb->len - skb->data_len; ++ unsigned int offset = 0, size, count = 0, i; ++ unsigned int f; ++ ++ i = tx_ring->next_to_use; ++ ++ while (len) { ++ buffer_info = &tx_ring->buffer_info[i]; ++ size = min(len, max_per_txd); ++ ++ buffer_info->length = size; ++ /* set time_stamp *before* dma to help avoid a possible race */ ++ buffer_info->time_stamp = jiffies; ++ buffer_info->dma = ++ pci_map_single(adapter->pdev, ++ skb->data + offset, ++ size, ++ PCI_DMA_TODEVICE); ++ if (pci_dma_mapping_error(pdev, buffer_info->dma)) { ++ dev_err(&pdev->dev, "TX DMA map failed\n"); ++ adapter->tx_dma_failed++; ++ return -1; ++ } ++ buffer_info->next_to_watch = i; ++ ++ len -= size; ++ offset += size; ++ count++; ++ i++; ++ if (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); ++ ++ buffer_info->length = size; ++ buffer_info->time_stamp = jiffies; ++ buffer_info->dma = ++ pci_map_page(adapter->pdev, ++ frag->page, ++ offset, ++ size, ++ PCI_DMA_TODEVICE); ++ if (pci_dma_mapping_error(pdev, buffer_info->dma)) { ++ dev_err(&adapter->pdev->dev, ++ "TX DMA page map failed\n"); ++ adapter->tx_dma_failed++; ++ return -1; ++ } ++ ++ buffer_info->next_to_watch = i; ++ ++ len -= size; ++ offset += size; ++ count++; ++ ++ i++; ++ if (i == tx_ring->count) ++ i = 0; ++ } ++ } ++ ++ if (i == 0) ++ i = tx_ring->count - 1; ++ else ++ i--; ++ ++ tx_ring->buffer_info[i].skb = skb; ++ tx_ring->buffer_info[first].next_to_watch = i; ++ ++ return count; ++} ++ ++static void e1000_tx_queue(struct e1000_adapter *adapter, ++ int tx_flags, int count) ++{ ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ struct e1000_tx_desc *tx_desc = NULL; ++ struct e1000_buffer *buffer_info; ++ u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; ++ unsigned int i; ++ ++ if (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 << 8; ++ ++ if (tx_flags & E1000_TX_FLAGS_IPV4) ++ txd_upper |= E1000_TXD_POPTS_IXSM << 8; ++ } ++ ++ if (tx_flags & E1000_TX_FLAGS_CSUM) { ++ txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; ++ txd_upper |= E1000_TXD_POPTS_TXSM << 8; ++ } ++ ++ if (tx_flags & E1000_TX_FLAGS_VLAN) { ++ txd_lower |= E1000_TXD_CMD_VLE; ++ txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); ++ } ++ ++ i = tx_ring->next_to_use; ++ ++ 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); ++ ++ i++; ++ if (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, adapter->hw.hw_addr + tx_ring->tail); ++ /* ++ * we need this if more than one processor can write to our tail ++ * at a time, it synchronizes IO on IA64/Altix systems ++ */ ++ mmiowb(); ++} ++ ++#define MINIMUM_DHCP_PACKET_SIZE 282 ++static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter, ++ struct sk_buff *skb) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ u16 length, offset; ++ ++ 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))) ++ return 0; ++ } ++ ++ if (skb->len <= MINIMUM_DHCP_PACKET_SIZE) ++ return 0; ++ ++ if (((struct ethhdr *) skb->data)->h_proto != htons(ETH_P_IP)) ++ return 0; ++ ++ { ++ const struct iphdr *ip = (struct iphdr *)((u8 *)skb->data+14); ++ struct udphdr *udp; ++ ++ if (ip->protocol != IPPROTO_UDP) ++ return 0; ++ ++ udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2)); ++ if (ntohs(udp->dest) != 67) ++ return 0; ++ ++ offset = (u8 *)udp + 8 - skb->data; ++ length = skb->len - offset; ++ return e1000_mng_write_dhcp_info_generic(hw, (u8 *)udp + 8, ++ length); ++ } ++ ++ return 0; ++} ++ ++static int __e1000_maybe_stop_tx(struct net_device *netdev, int size) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ 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 (e1000_desc_unused(adapter->tx_ring) < size) ++ return -EBUSY; ++ ++ /* A reprieve! */ ++ netif_start_queue(netdev); ++ ++adapter->restart_queue; ++ return 0; ++} ++ ++static int e1000_maybe_stop_tx(struct net_device *netdev, int size) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ if (e1000_desc_unused(adapter->tx_ring) >= size) ++ return 0; ++ return __e1000_maybe_stop_tx(netdev, size); ++} ++ ++#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) ++static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ unsigned int first; ++ unsigned int max_per_txd = E1000_MAX_PER_TXD; ++ unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; ++ unsigned int tx_flags = 0; ++ unsigned int len = skb->len - skb->data_len; ++#ifdef NETIF_F_LLTX ++ unsigned long irq_flags; ++#endif ++ unsigned int nr_frags; ++ unsigned int mss = 0; ++ int count = 0; ++ int tso; ++ unsigned int f; ++ ++ if (test_bit(__E1000_DOWN, &adapter->state)) { ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++ ++ if (skb->len <= 0) { ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++ ++#ifdef NETIF_F_TSO ++ mss = skb_shinfo(skb)->gso_size; ++ /* ++ * The controller does a simple calculation to ++ * make sure there is enough room in the FIFO before ++ * initiating the DMA for each buffer. The calc is: ++ * 4 = ceil(buffer len/mss). To make sure we don't ++ * overrun the FIFO, adjust the max buffer len if mss ++ * drops. ++ */ ++ 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); ++ /* ++ * we do this workaround for ES2LAN, but it is un-necessary, ++ * avoiding it could save a lot of cycles ++ */ ++ if (skb->data_len && (hdr_len == len)) { ++ unsigned int pull_size; ++ ++ pull_size = min((unsigned int)4, skb->data_len); ++ if (!__pskb_pull_tail(skb, pull_size)) { ++ e_err("__pskb_pull_tail failed.\n"); ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++ len = skb->len - skb->data_len; ++ } ++ } ++ ++ /* reserve a descriptor for the offload context */ ++ if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL)) ++ count++; ++ count++; ++#else ++ if (skb->ip_summed == CHECKSUM_PARTIAL) ++ count++; ++#endif ++ ++ count += TXD_USE_COUNT(len, max_txd_pwr); ++ ++ nr_frags = skb_shinfo(skb)->nr_frags; ++ for (f = 0; f < nr_frags; f++) ++ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, ++ max_txd_pwr); ++ ++ if (adapter->hw.mac.tx_pkt_filtering) ++ e1000_transfer_dhcp_info(adapter, skb); ++ ++#ifdef NETIF_F_LLTX ++ if (!spin_trylock_irqsave(&adapter->tx_queue_lock, irq_flags)) ++ /* Collision - tell upper layer to requeue */ ++ return NETDEV_TX_LOCKED; ++#endif ++ ++ /* ++ * need: count + 2 desc gap to keep tail from touching ++ * head, otherwise try next time ++ */ ++ if (e1000_maybe_stop_tx(netdev, count + 2)) { ++#ifdef NETIF_F_LLTX ++ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); ++#endif ++ return NETDEV_TX_BUSY; ++ } ++ ++ if (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); ++ } ++ ++ first = tx_ring->next_to_use; ++ ++ tso = e1000_tso(adapter, skb); ++ if (unlikely(tso < 0)) { ++ dev_kfree_skb_any(skb); ++#ifdef NETIF_F_LLTX ++ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); ++#endif ++ return NETDEV_TX_OK; ++ } ++ ++ if (tso) ++ tx_flags |= E1000_TX_FLAGS_TSO; ++ else if (e1000_tx_csum(adapter, 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 (skb->protocol == htons(ETH_P_IP)) ++ tx_flags |= E1000_TX_FLAGS_IPV4; ++ ++ count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); ++ if (unlikely(count < 0)) { ++ /* handle pci_map_single() error in e1000_tx_map */ ++ dev_kfree_skb_any(skb); ++#ifdef NETIF_F_LLTX ++ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); ++#endif ++ return NETDEV_TX_OK; ++ } ++ ++ e1000_tx_queue(adapter, tx_flags, count); ++ ++ netdev->trans_start = jiffies; ++ ++ /* Make sure there is space in the ring for the next send. */ ++ e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2); ++ ++#ifdef NETIF_F_LLTX ++ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); ++#endif ++ return NETDEV_TX_OK; ++} ++ ++/** ++ * e1000_tx_timeout - Respond to a Tx Hang ++ * @netdev: network interface device structure ++ **/ ++static void e1000_tx_timeout(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ /* Do the reset outside of interrupt context */ ++ adapter->tx_timeout_count++; ++ schedule_work(&adapter->reset_task); ++} ++ ++static void e1000_reset_task(struct work_struct *work) ++{ ++ struct e1000_adapter *adapter; ++ adapter = container_of(work, struct e1000_adapter, reset_task); ++ ++ e1000_reinit_locked(adapter); ++} ++ ++/** ++ * e1000_get_stats - Get System Network Statistics ++ * @netdev: network interface device structure ++ * ++ * Returns the address of the device statistics structure. ++ * The statistics are actually updated from the timer callback. ++ **/ ++static struct net_device_stats *e1000_get_stats(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ /* only return the current stats */ ++ return &adapter->net_stats; ++} ++ ++/** ++ * e1000_change_mtu - Change the Maximum Transfer Unit ++ * @netdev: network interface device structure ++ * @new_mtu: new value for maximum frame size ++ * ++ * Returns 0 on success, negative on failure ++ **/ ++static int e1000_change_mtu(struct net_device *netdev, int new_mtu) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; ++ ++ if ((new_mtu < 68) || (max_frame > MAX_JUMBO_FRAME_SIZE)) { ++ e_err("Invalid MTU setting\n"); ++ return -EINVAL; ++ } ++ ++ /* Jumbo frame size limits */ ++ if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) { ++ if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { ++ e_err("Jumbo Frames not supported.\n"); ++ return -EINVAL; ++ } ++ } ++ ++#define MAX_STD_JUMBO_FRAME_SIZE 9234 ++ if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { ++ e_err("MTU > 9216 not supported.\n"); ++ return -EINVAL; ++ } ++ ++ while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) ++ msleep(1); ++ /* e1000_down has a dependency on max_frame_size */ ++ adapter->max_frame_size = max_frame; ++ if (netif_running(netdev)) ++ e1000_down(adapter); ++ ++ /* ++ * NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN ++ * means we reserve 2 more, this pushes us to allocate from the next ++ * larger slab size. ++ * i.e. RXBUFFER_2048 --> size-4096 slab ++ * However with the new *_jumbo_rx* routines, jumbo receives will use ++ * fragmented skbs ++ */ ++ ++ if (max_frame <= 256) ++ adapter->rx_buffer_len = 256; ++ else if (max_frame <= 512) ++ adapter->rx_buffer_len = 512; ++ else if (max_frame <= 1024) ++ adapter->rx_buffer_len = 1024; ++ else if (max_frame <= 2048) ++ adapter->rx_buffer_len = 2048; ++#ifdef CONFIG_E1000E_NAPI ++ else ++ adapter->rx_buffer_len = 4096; ++#else ++ else if (max_frame <= 4096) ++ adapter->rx_buffer_len = 4096; ++ else if (max_frame <= 8192) ++ adapter->rx_buffer_len = 8192; ++ else if (max_frame <= 16384) ++ adapter->rx_buffer_len = 16384; ++#endif ++ ++ /* adjust allocation if LPE protects us, and we aren't using SBP */ ++ if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) || ++ (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)) ++ adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN ++ + ETH_FCS_LEN; ++ ++ e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); ++ netdev->mtu = new_mtu; ++ ++ if (netif_running(netdev)) ++ e1000_up(adapter); ++ else ++ e1000_reset(adapter); ++ ++ clear_bit(__E1000_RESETTING, &adapter->state); ++ ++ return 0; ++} ++ ++static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, ++ int cmd) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct mii_ioctl_data *data = if_mii(ifr); ++ ++ if (adapter->hw.phy.media_type != e1000_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; ++ switch (data->reg_num & 0x1F) { ++ case MII_BMCR: ++ data->val_out = adapter->phy_regs.bmcr; ++ break; ++ case MII_BMSR: ++ data->val_out = adapter->phy_regs.bmsr; ++ break; ++ case MII_PHYSID1: ++ data->val_out = (adapter->hw.phy.id >> 16); ++ break; ++ case MII_PHYSID2: ++ data->val_out = (adapter->hw.phy.id & 0xFFFF); ++ break; ++ case MII_ADVERTISE: ++ data->val_out = adapter->phy_regs.advertise; ++ break; ++ case MII_LPA: ++ data->val_out = adapter->phy_regs.lpa; ++ break; ++ case MII_EXPANSION: ++ data->val_out = adapter->phy_regs.expansion; ++ break; ++ case MII_CTRL1000: ++ data->val_out = adapter->phy_regs.ctrl1000; ++ break; ++ case MII_STAT1000: ++ data->val_out = adapter->phy_regs.stat1000; ++ break; ++ case MII_ESTATUS: ++ data->val_out = adapter->phy_regs.estatus; ++ break; ++ default: ++ return -EIO; ++ } ++ break; ++ case SIOCSMIIREG: ++ default: ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) ++{ ++ switch (cmd) { ++ case SIOCGMIIPHY: ++ case SIOCGMIIREG: ++ case SIOCSMIIREG: ++ return e1000_mii_ioctl(netdev, ifr, cmd); ++#ifdef ETHTOOL_OPS_COMPAT ++ case SIOCETHTOOL: ++ return ethtool_ioctl(ifr); ++#endif ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 ctrl, ctrl_ext, rctl, status; ++ u32 wufc = adapter->wol; ++ int retval = 0; ++ ++ netif_device_detach(netdev); ++ ++ if (netif_running(netdev)) { ++ WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); ++ e1000_down(adapter); ++ e1000_free_irq(adapter); ++ } ++ ++#ifdef CONFIG_PM ++ retval = pci_save_state(pdev); ++ if (retval) ++ return retval; ++#endif ++ ++ status = er32(STATUS); ++ if (status & E1000_STATUS_LU) ++ wufc &= ~E1000_WUFC_LNKC; ++ ++ if (wufc) { ++ e1000_setup_rctl(adapter); ++ e1000_set_multi(netdev); ++ ++ /* turn on all-multi mode if wake on multicast is enabled */ ++ if (wufc & E1000_WUFC_MC) { ++ rctl = er32(RCTL); ++ rctl |= E1000_RCTL_MPE; ++ ew32(RCTL, rctl); ++ } ++ ++ ctrl = er32(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 | ++ E1000_CTRL_EN_PHY_PWR_MGMT; ++ ew32(CTRL, ctrl); ++ ++ if (adapter->hw.phy.media_type == e1000_media_type_fiber || ++ adapter->hw.phy.media_type == e1000_media_type_internal_serdes) { ++ /* keep the laser running in D3 */ ++ ctrl_ext = er32(CTRL_EXT); ++ ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA; ++ ew32(CTRL_EXT, ctrl_ext); ++ } ++ ++ if (adapter->flags & FLAG_IS_ICH) ++ e1000_disable_gig_wol_ich8lan(&adapter->hw); ++ ++ /* Allow time for pending master requests to run */ ++ e1000_disable_pcie_master_generic(&adapter->hw); ++ ++ ew32(WUC, E1000_WUC_PME_EN); ++ ew32(WUFC, wufc); ++ pci_enable_wake(pdev, PCI_D3hot, 1); ++ pci_enable_wake(pdev, PCI_D3cold, 1); ++ } else { ++ ew32(WUC, 0); ++ ew32(WUFC, 0); ++ pci_enable_wake(pdev, PCI_D3hot, 0); ++ pci_enable_wake(pdev, PCI_D3cold, 0); ++ } ++ ++ /* make sure adapter isn't asleep if manageability is enabled */ ++ if (adapter->flags & FLAG_MNG_PT_ENABLED) { ++ pci_enable_wake(pdev, PCI_D3hot, 1); ++ pci_enable_wake(pdev, PCI_D3cold, 1); ++ } ++ ++ if (adapter->hw.phy.type == e1000_phy_igp_3) ++ e1000_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); ++ ++ /* ++ * Release control of h/w to f/w. If f/w is AMT enabled, this ++ * would have already happened in close and is redundant. ++ */ ++ e1000_release_hw_control(adapter); ++ ++ pci_disable_device(pdev); ++ ++ pci_set_power_state(pdev, pci_choose_state(pdev, state)); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int e1000_resume(struct pci_dev *pdev) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 err; ++ ++ pci_set_power_state(pdev, PCI_D0); ++ pci_restore_state(pdev); ++ err = pci_enable_device(pdev); ++ if (err) { ++ dev_err(&pdev->dev, ++ "Cannot enable PCI device from suspend\n"); ++ return err; ++ } ++ ++ pci_set_master(pdev); ++ ++ pci_enable_wake(pdev, PCI_D3hot, 0); ++ pci_enable_wake(pdev, PCI_D3cold, 0); ++ ++ if (netif_running(netdev)) { ++ err = e1000_request_irq(adapter); ++ if (err) ++ return err; ++ } ++ ++ e1000_power_up_phy(hw); ++ e1000_reset(adapter); ++ ew32(WUS, ~0); ++ ++ e1000_init_manageability(adapter); ++ ++ if (netif_running(netdev)) ++ e1000_up(adapter); ++ ++ netif_device_attach(netdev); ++ ++ /* ++ * If the controller has AMT, do not set DRV_LOAD until the interface ++ * is up. For all other cases, let the f/w know that the h/w is now ++ * under the control of the driver. ++ */ ++ if (!(adapter->flags & FLAG_HAS_AMT)) ++ e1000_get_hw_control(adapter); ++ ++ return 0; ++} ++#endif /* CONFIG_PM */ ++ ++#ifndef USE_REBOOT_NOTIFIER ++static void e1000_shutdown(struct pci_dev *pdev) ++{ ++ e1000_suspend(pdev, PMSG_SUSPEND); ++} ++#else ++static struct pci_driver e1000_driver; ++static int e1000_notify_reboot(struct notifier_block *nb, unsigned long event, ++ void *ptr) ++{ ++ struct pci_dev *pdev = NULL; ++ ++ switch (event) { ++ case SYS_DOWN: ++ case SYS_HALT: ++ case SYS_POWER_OFF: ++ while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { ++ if (pci_dev_driver(pdev) == &e1000_driver) ++ e1000_suspend(pdev, PMSG_SUSPEND); ++ } ++ break; ++ } ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block e1000_notifier_reboot = { ++ .notifier_call = e1000_notify_reboot, ++ .next = NULL, ++ .priority = 0 ++}; ++#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 e1000_netpoll(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ disable_irq(adapter->pdev->irq); ++ e1000_intr(adapter->pdev->irq, netdev); ++ ++ e1000_clean_tx_irq(adapter); ++#ifndef CONFIG_E1000E_NAPI ++ adapter->clean_rx(adapter); ++#endif ++ ++ enable_irq(adapter->pdev->irq); ++} ++#endif ++ ++#ifdef HAVE_PCI_ERS ++/** ++ * e1000_io_error_detected - called when PCI error is detected ++ * @pdev: Pointer to PCI device ++ * @state: The current pci connection state ++ * ++ * This function is called after a PCI bus error affecting ++ * this device has been detected. ++ */ ++static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, ++ pci_channel_state_t state) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ netif_device_detach(netdev); ++ ++ if (netif_running(netdev)) ++ e1000_down(adapter); ++ pci_disable_device(pdev); ++ ++ /* Request a slot slot reset. */ ++ return PCI_ERS_RESULT_NEED_RESET; ++} ++ ++/** ++ * e1000_io_slot_reset - called after the pci bus has been reset. ++ * @pdev: Pointer to PCI device ++ * ++ * Restart the card from scratch, as if from a cold-boot. Implementation ++ * resembles the first-half of the e1000_resume routine. ++ */ ++static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ ++ if (pci_enable_device(pdev)) { ++ dev_err(&pdev->dev, ++ "Cannot re-enable PCI device after reset.\n"); ++ return PCI_ERS_RESULT_DISCONNECT; ++ } ++ pci_set_master(pdev); ++ ++ pci_enable_wake(pdev, PCI_D3hot, 0); ++ pci_enable_wake(pdev, PCI_D3cold, 0); ++ ++ e1000_reset(adapter); ++ ew32(WUS, ~0); ++ ++ return PCI_ERS_RESULT_RECOVERED; ++} ++ ++/** ++ * e1000_io_resume - called when traffic can start flowing again. ++ * @pdev: Pointer to PCI device ++ * ++ * This callback is called when the error recovery driver tells us that ++ * its OK to resume normal operation. Implementation resembles the ++ * second-half of the e1000_resume routine. ++ */ ++static void e1000_io_resume(struct pci_dev *pdev) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ e1000_init_manageability(adapter); ++ ++ if (netif_running(netdev)) { ++ if (e1000_up(adapter)) { ++ dev_err(&pdev->dev, ++ "can't bring device back up after reset\n"); ++ return; ++ } ++ } ++ ++ netif_device_attach(netdev); ++ ++ /* ++ * If the controller has AMT, do not set DRV_LOAD until the interface ++ * is up. For all other cases, let the f/w know that the h/w is now ++ * under the control of the driver. ++ */ ++ if (!(adapter->flags & FLAG_HAS_AMT)) ++ e1000_get_hw_control(adapter); ++ ++} ++#endif /* HAVE_PCI_ERS */ ++ ++static void e1000_print_device_info(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ struct net_device *netdev = adapter->netdev; ++ u32 pba_num; ++ ++ /* print bus type/speed/width info */ ++ e_info("(PCI Express:2.5GB/s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n", ++ /* bus width */ ++ ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : ++ "Width x1"), ++ /* MAC address */ ++ netdev->dev_addr[0], netdev->dev_addr[1], ++ netdev->dev_addr[2], netdev->dev_addr[3], ++ netdev->dev_addr[4], netdev->dev_addr[5]); ++ e_info("Intel(R) PRO/%s Network Connection\n", ++ (hw->phy.type == e1000_phy_ife) ? "10/100" : "1000"); ++ e1000_read_pba_num_generic(hw, &pba_num); ++ e_info("MAC: %d, PHY: %d, PBA No: %06x-%03x\n", ++ hw->mac.type, hw->phy.type, ++ (pba_num >> 8), (pba_num & 0xff)); ++} ++ ++/** ++ * e1000_probe - Device Initialization Routine ++ * @pdev: PCI device information struct ++ * @ent: entry in e1000e_pci_tbl ++ * ++ * Returns 0 on success, negative on failure ++ * ++ * e1000_probe initializes an adapter identified by a pci_dev structure. ++ * The OS initialization, configuring of the adapter private structure, ++ * and a hardware reset occur. ++ **/ ++static int __devinit e1000_probe(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct net_device *netdev; ++ struct e1000_adapter *adapter; ++ struct e1000_hw *hw; ++ const struct e1000_info *ei = e1000_info_tbl[ent->driver_data]; ++ ++ static int cards_found; ++ int i, err, pci_using_dac; ++ u16 eeprom_data = 0; ++ u16 eeprom_apme_mask = E1000_EEPROM_APME; ++ ++ err = pci_enable_device(pdev); ++ if (err) ++ return err; ++ ++ pci_using_dac = 0; ++ err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); ++ if (!err) { ++ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); ++ if (!err) ++ pci_using_dac = 1; ++ } else { ++ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); ++ if (err) { ++ err = pci_set_consistent_dma_mask(pdev, ++ DMA_32BIT_MASK); ++ if (err) { ++ printk(KERN_ERR "%s: No usable DMA " ++ "configuration, aborting\n", ++ pci_name(pdev)); ++ goto err_dma; ++ } ++ } ++ } ++ ++ err = pci_request_regions(pdev, e1000e_driver_name); ++ if (err) ++ goto err_pci_reg; ++ ++ pci_set_master(pdev); ++ ++ err = -ENOMEM; ++ netdev = alloc_etherdev(sizeof(struct e1000_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); ++ hw = &adapter->hw; ++ adapter->netdev = netdev; ++ adapter->pdev = pdev; ++ adapter->ei = ei; ++ adapter->pba = ei->pba; ++ adapter->flags = ei->flags; ++ adapter->flags2 = ei->flags2; ++ adapter->hw.back = adapter; ++ adapter->hw.mac.type = ei->mac; ++ adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; ++ adapter->stats_freq_us = 2 * 1000000; /* default watchdog timer 2sec */ ++ ++ /* PCI config space info */ ++ ++ hw->vendor_id = pdev->vendor; ++ hw->device_id = pdev->device; ++ hw->subsystem_vendor_id = pdev->subsystem_vendor; ++ hw->subsystem_device_id = pdev->subsystem_device; ++ ++ pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); ++ pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); ++ ++ err = -EIO; ++ adapter->hw.hw_addr = ioremap(pci_resource_start(pdev, 0), ++ pci_resource_len(pdev, 0)); ++ if (!adapter->hw.hw_addr) ++ goto err_ioremap; ++ ++ if ((adapter->flags & FLAG_HAS_FLASH) && ++ (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { ++ adapter->hw.flash_address = ioremap(pci_resource_start(pdev, 1), ++ pci_resource_len(pdev, 1)); ++ if (!adapter->hw.flash_address) ++ goto err_flashmap; ++ } ++ ++ adapter->bd_number = cards_found++; ++ ++ e1000_check_options(adapter); ++ ++ /* setup adapter struct */ ++ err = e1000_sw_init(adapter); ++ if (err) ++ goto err_sw_init; ++ ++ if (ei->get_variants) { ++ err = ei->get_variants(adapter); ++ if (err) ++ goto err_hw_init; ++ } ++ ++ /* construct the net_device struct */ ++ netdev->open = &e1000_open; ++ netdev->stop = &e1000_close; ++ netdev->hard_start_xmit = &e1000_xmit_frame; ++ netdev->get_stats = &e1000_get_stats; ++ netdev->set_multicast_list = &e1000_set_multi; ++ netdev->set_mac_address = &e1000_set_mac; ++ netdev->change_mtu = &e1000_change_mtu; ++ netdev->do_ioctl = &e1000_ioctl; ++ e1000_set_ethtool_ops(netdev); ++ netdev->tx_timeout = &e1000_tx_timeout; ++ netdev->watchdog_timeo = 5 * HZ; ++#ifdef CONFIG_E1000E_NAPI ++ netif_napi_add(netdev, &adapter->napi, e1000_poll, 64); ++#endif ++ netdev->vlan_rx_register = e1000_vlan_rx_register; ++ netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; ++ netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ netdev->poll_controller = e1000_netpoll; ++#endif ++ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); ++ ++ if ((adapter->flags & FLAG_IS_ICH) && ++ (adapter->flags2 & FLAG2_READ_ONLY_NVM)) ++ e1000e_write_protect_nvm_ich8lan(&adapter->hw); ++ ++ hw->mac.ops.get_bus_info(&adapter->hw); ++ ++ adapter->hw.phy.autoneg_wait_to_complete = 0; ++ ++ /* Copper options */ ++ if (adapter->hw.phy.media_type == e1000_media_type_copper) { ++ adapter->hw.phy.mdix = AUTO_ALL_MODES; ++ adapter->hw.phy.disable_polarity_correction = 0; ++ adapter->hw.phy.ms_type = e1000_ms_hw_default; ++ } ++ ++ if (hw->phy.ops.check_reset_block && ++ hw->phy.ops.check_reset_block(hw)) ++ e_info("PHY reset is blocked due to SOL/IDER session.\n"); ++ ++ netdev->features = NETIF_F_SG | ++ NETIF_F_HW_CSUM | ++ NETIF_F_HW_VLAN_TX | ++ NETIF_F_HW_VLAN_RX; ++ ++ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) ++ netdev->features |= NETIF_F_HW_VLAN_FILTER; ++ ++#ifdef NETIF_F_TSO ++ netdev->features |= NETIF_F_TSO; ++#ifdef NETIF_F_TSO6 ++ netdev->features |= NETIF_F_TSO6; ++#endif ++#endif ++ ++ if (pci_using_dac) ++ netdev->features |= NETIF_F_HIGHDMA; ++ ++#ifdef NETIF_F_LLTX ++ /* ++ * We should not be using LLTX anymore, but we are still Tx faster with ++ * it. ++ */ ++ netdev->features |= NETIF_F_LLTX; ++#endif ++ ++ if (e1000_enable_mng_pass_thru(&adapter->hw)) ++ adapter->flags |= FLAG_MNG_PT_ENABLED; ++ ++ /* ++ * before reading the NVM, reset the controller to ++ * put the device in a known good starting state ++ */ ++ adapter->hw.mac.ops.reset_hw(&adapter->hw); ++ ++ /* ++ * systems with ASPM and others may see the checksum fail on the first ++ * attempt. Let's give it a few tries ++ */ ++ for (i = 0;; i++) { ++ if (hw->nvm.ops.validate(hw) >= 0) ++ break; ++ if (i == 2) { ++ e_err("The NVM Checksum Is Not Valid\n"); ++ err = -EIO; ++ goto err_eeprom; ++ } ++ } ++ ++ /* copy the MAC address out of the NVM */ ++ if (e1000_read_mac_addr(&adapter->hw)) ++ e_err("NVM Read Error while reading MAC address\n"); ++ ++ memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len); ++#ifdef ETHTOOL_GPERMADDR ++ memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); ++ ++ if (!is_valid_ether_addr(netdev->perm_addr)) { ++#else ++ if (!is_valid_ether_addr(netdev->dev_addr)) { ++#endif ++ e_err("Invalid MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ netdev->dev_addr[0], netdev->dev_addr[1], ++ netdev->dev_addr[2], netdev->dev_addr[3], ++ netdev->dev_addr[4], netdev->dev_addr[5]); ++ err = -EIO; ++ goto err_eeprom; ++ } ++ ++ init_timer(&adapter->watchdog_timer); ++ adapter->watchdog_timer.function = &e1000_watchdog; ++ adapter->watchdog_timer.data = (unsigned long) adapter; ++ ++ init_timer(&adapter->phy_info_timer); ++ adapter->phy_info_timer.function = &e1000_update_phy_info; ++ adapter->phy_info_timer.data = (unsigned long) adapter; ++ ++ INIT_WORK(&adapter->reset_task, e1000_reset_task); ++ INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); ++ ++ /* Initialize link parameters. User can change them with ethtool */ ++ adapter->hw.mac.autoneg = 1; ++ adapter->fc_autoneg = 1; ++ adapter->hw.fc.original_type = e1000_fc_default; ++ adapter->hw.fc.type = e1000_fc_default; ++ adapter->hw.phy.autoneg_advertised = 0x2f; ++ ++ /* ring size defaults */ ++ adapter->rx_ring->count = 256; ++ adapter->tx_ring->count = 256; ++ ++ /* ++ * Initial Wake on LAN setting - If APM wake is enabled in ++ * the EEPROM, enable the ACPI Magic Packet filter ++ */ ++ if (adapter->flags & FLAG_APME_IN_WUC) { ++ /* APME bit in EEPROM is mapped to WUC.APME */ ++ eeprom_data = er32(WUC); ++ eeprom_apme_mask = E1000_WUC_APME; ++ } else if (adapter->flags & FLAG_APME_IN_CTRL3) { ++ if (adapter->flags & FLAG_APME_CHECK_PORT_B && ++ (adapter->hw.bus.func == 1)) ++ hw->nvm.ops.read(&adapter->hw, NVM_INIT_CONTROL3_PORT_B, ++ 1, &eeprom_data); ++ else ++ hw->nvm.ops.read(&adapter->hw, NVM_INIT_CONTROL3_PORT_A, ++ 1, &eeprom_data); ++ } ++ ++ /* fetch WoL from EEPROM */ ++ if (eeprom_data & eeprom_apme_mask) ++ adapter->eeprom_wol |= E1000_WUFC_MAG; ++ ++ /* ++ * now that we have the eeprom settings, apply the special cases ++ * where the eeprom may be wrong or the board simply won't support ++ * wake on lan on a particular port ++ */ ++ if (!(adapter->flags & FLAG_HAS_WOL)) ++ adapter->eeprom_wol = 0; ++ ++ /* initialize the wol settings based on the eeprom settings */ ++ adapter->wol = adapter->eeprom_wol; ++ ++ /* reset the hardware with the new settings */ ++ e1000_reset(adapter); ++ ++ /* ++ * If the controller has AMT, do not set DRV_LOAD until the interface ++ * is up. For all other cases, let the f/w know that the h/w is now ++ * under the control of the driver. ++ */ ++ if (!(adapter->flags & FLAG_HAS_AMT)) ++ e1000_get_hw_control(adapter); ++ ++ /* tell the stack to leave us alone until e1000_open() is called */ ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ ++ strcpy(netdev->name, "eth%d"); ++ err = register_netdev(netdev); ++ if (err) ++ goto err_register; ++ ++ e1000_print_device_info(adapter); ++ ++ return 0; ++ ++err_register: ++ if (!(adapter->flags & FLAG_HAS_AMT)) ++ e1000_release_hw_control(adapter); ++err_eeprom: ++ if (hw->phy.ops.check_reset_block && ++ !hw->phy.ops.check_reset_block(hw)) ++ hw->phy.ops.reset(hw); ++err_hw_init: ++ hw->mac.ops.remove_device(&adapter->hw); ++ kfree(adapter->tx_ring); ++ kfree(adapter->rx_ring); ++err_sw_init: ++ if (adapter->hw.flash_address) ++ iounmap(adapter->hw.flash_address); ++err_flashmap: ++ iounmap(adapter->hw.hw_addr); ++err_ioremap: ++ free_netdev(netdev); ++err_alloc_etherdev: ++ pci_release_regions(pdev); ++err_pci_reg: ++err_dma: ++ pci_disable_device(pdev); ++ return err; ++} ++ ++/** ++ * e1000_remove - Device Removal Routine ++ * @pdev: PCI device information struct ++ * ++ * e1000_remove is called by the PCI subsystem to alert the driver ++ * that it should release a PCI device. The could be caused by a ++ * Hot-Plug event, or because the driver is going to be removed from ++ * memory. ++ **/ ++static void __devexit e1000_remove(struct pci_dev *pdev) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ ++ /* ++ * flush_scheduled work may reschedule our watchdog task, so ++ * explicitly disable watchdog tasks from being rescheduled ++ */ ++ set_bit(__E1000_DOWN, &adapter->state); ++ del_timer_sync(&adapter->watchdog_timer); ++ del_timer_sync(&adapter->phy_info_timer); ++ ++ flush_scheduled_work(); ++ ++ /* ++ * Release control of h/w to f/w. If f/w is AMT enabled, this ++ * would have already happened in close and is redundant. ++ */ ++ e1000_release_hw_control(adapter); ++ ++ unregister_netdev(netdev); ++ ++ if (hw->phy.ops.check_reset_block && ++ !hw->phy.ops.check_reset_block(hw)) ++ hw->phy.ops.reset(hw); ++ ++#ifdef CONFIG_E1000E_MSIX ++ e1000_reset_interrupt_capability(adapter); ++#endif /* CONFIG_E1000E_MSIX */ ++ hw->mac.ops.remove_device(&adapter->hw); ++ kfree(adapter->tx_ring); ++ kfree(adapter->rx_ring); ++ ++ iounmap(adapter->hw.hw_addr); ++ if (adapter->hw.flash_address) ++ iounmap(adapter->hw.flash_address); ++ pci_release_regions(pdev); ++ ++ free_netdev(netdev); ++ ++ pci_disable_device(pdev); ++} ++ ++#ifdef HAVE_PCI_ERS ++/* PCI Error Recovery (ERS) */ ++static struct pci_error_handlers e1000_err_handler = { ++ .error_detected = e1000_io_error_detected, ++ .slot_reset = e1000_io_slot_reset, ++ .resume = e1000_io_resume, ++}; ++#endif ++ ++static struct pci_device_id e1000e_pci_tbl[] = { ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_DUAL), board_82571 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_QUAD), board_82571 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571PT_QUAD_COPPER), board_82571 }, ++ ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES), board_82572 }, ++ ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E), board_82573 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 }, ++ ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 }, ++ ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT), ++ board_80003es2lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT), ++ board_80003es2lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_DPT), ++ board_80003es2lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_SPT), ++ board_80003es2lan }, ++ ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE), board_ich8lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_G), board_ich8lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_GT), board_ich8lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_AMT), board_ich8lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan }, ++ ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_BM), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan }, ++ ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LM), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_V), board_ich9lan }, ++ ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan }, ++ ++ { } /* terminate list */ ++}; ++MODULE_DEVICE_TABLE(pci, e1000e_pci_tbl); ++ ++/* PCI Device API Driver */ ++static struct pci_driver e1000_driver = { ++ .name = e1000e_driver_name, ++ .id_table = e1000e_pci_tbl, ++ .probe = e1000_probe, ++ .remove = __devexit_p(e1000_remove), ++#ifdef CONFIG_PM ++ /* Power Management Hooks */ ++ .suspend = e1000_suspend, ++ .resume = e1000_resume, ++#endif ++#ifndef USE_REBOOT_NOTIFIER ++ .shutdown = e1000_shutdown, ++#endif ++#ifdef HAVE_PCI_ERS ++ .err_handler = &e1000_err_handler ++#endif ++}; ++ ++/** ++ * e1000_init_module - Driver Registration Routine ++ * ++ * e1000_init_module is the first routine called when the driver is ++ * loaded. All it does is register with the PCI subsystem. ++ **/ ++static int __init e1000_init_module(void) ++{ ++ int ret; ++ printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Driver - %s\n", ++ e1000e_driver_name, e1000e_driver_version); ++ printk(KERN_INFO "%s: Copyright (c) 1999-2008 Intel Corporation.\n", ++ e1000e_driver_name); ++ ret = pci_register_driver(&e1000_driver); ++ pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, e1000e_driver_name, ++ PM_QOS_DEFAULT_VALUE); ++#ifdef USE_REBOOT_NOTIFIER ++ if (ret >= 0) ++ register_reboot_notifier(&e1000_notifier_reboot); ++#endif ++ ++ return ret; ++} ++module_init(e1000_init_module); ++ ++/** ++ * e1000_exit_module - Driver Exit Cleanup Routine ++ * ++ * e1000_exit_module is called just before the driver is removed ++ * from memory. ++ **/ ++static void __exit e1000_exit_module(void) ++{ ++#ifdef USE_REBOOT_NOTIFIER ++ unregister_reboot_notifier(&e1000_notifier_reboot); ++#endif ++ pci_unregister_driver(&e1000_driver); ++ pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, e1000e_driver_name); ++} ++module_exit(e1000_exit_module); ++ ++ ++MODULE_AUTHOR("Intel Corporation, "); ++MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ ++/* netdev.c */ +diff -Nurp linux-2.6.22-0/drivers/net/e1000e/param.c linux-2.6.22-10/drivers/net/e1000e/param.c +--- linux-2.6.22-0/drivers/net/e1000e/param.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22-10/drivers/net/e1000e/param.c 2008-10-14 01:51:32.000000000 +0200 +@@ -0,0 +1,479 @@ ++/******************************************************************************* ++ ++ Intel PRO/1000 Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include ++ ++#include "e1000.h" ++ ++/* ++ * This is the only thing that needs to be changed to adjust the ++ * maximum number of ports that the driver can manage. ++ */ ++ ++#define E1000_MAX_NIC 32 ++ ++#define OPTION_UNSET -1 ++#define OPTION_DISABLED 0 ++#define OPTION_ENABLED 1 ++ ++#define COPYBREAK_DEFAULT 256 ++unsigned int copybreak = COPYBREAK_DEFAULT; ++module_param(copybreak, uint, 0644); ++MODULE_PARM_DESC(copybreak, ++ "Maximum size of packet that is copied to a new buffer on receive"); ++ ++/* ++ * All parameters are treated the same, as an integer array of values. ++ * This macro just reduces the need to repeat the same declaration code ++ * over and over (plus this helps to avoid typo bugs). ++ */ ++ ++#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } ++#ifndef module_param_array ++/* Module Parameters are always initialized to -1, so that the driver ++ * can tell the difference between no user specified value or the ++ * user asking for the default value. ++ * The true default values are loaded in when e1000_check_options is called. ++ * ++ * This is a GCC extension to ANSI C. ++ * See the item "Labeled Elements in Initializers" in the section ++ * "Extensions to the C Language Family" of the GCC documentation. ++ */ ++#define E1000_PARAM(X, desc) \ ++ static const int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \ ++ static unsigned int num_##X; \ ++ MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \ ++ MODULE_PARM_DESC(X, desc); ++#else ++#define E1000_PARAM(X, desc) \ ++ static int __devinitdata X[E1000_MAX_NIC+1] \ ++ = E1000_PARAM_INIT; \ ++ static unsigned int num_##X; \ ++ module_param_array_named(X, X, int, &num_##X, 0); \ ++ MODULE_PARM_DESC(X, desc); ++#endif ++ ++/* ++ * Transmit Interrupt Delay in units of 1.024 microseconds ++ * Tx interrupt delay needs to typically be set to something non zero ++ * ++ * Valid Range: 0-65535 ++ */ ++E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay"); ++#define DEFAULT_TIDV 8 ++#define MAX_TXDELAY 0xFFFF ++#define MIN_TXDELAY 0 ++ ++/* ++ * Transmit Absolute Interrupt Delay in units of 1.024 microseconds ++ * ++ * Valid Range: 0-65535 ++ */ ++E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay"); ++#define DEFAULT_TADV 32 ++#define MAX_TXABSDELAY 0xFFFF ++#define MIN_TXABSDELAY 0 ++ ++/* ++ * Receive Interrupt Delay in units of 1.024 microseconds ++ * hardware will likely hang if you set this to anything but zero. ++ * ++ * Valid Range: 0-65535 ++ */ ++E1000_PARAM(RxIntDelay, "Receive Interrupt Delay"); ++#define DEFAULT_RDTR 0 ++#define MAX_RXDELAY 0xFFFF ++#define MIN_RXDELAY 0 ++ ++/* ++ * Receive Absolute Interrupt Delay in units of 1.024 microseconds ++ * ++ * Valid Range: 0-65535 ++ */ ++E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay"); ++#define DEFAULT_RADV 8 ++#define MAX_RXABSDELAY 0xFFFF ++#define MIN_RXABSDELAY 0 ++ ++/* ++ * Interrupt Throttle Rate (interrupts/sec) ++ * ++ * Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative) ++ */ ++E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); ++#define DEFAULT_ITR 3 ++#define MAX_ITR 100000 ++#define MIN_ITR 100 ++ ++#ifdef CONFIG_E1000E_MSIX ++/* IntMode (Interrupt Mode) ++ * ++ * Valid Range: 0 - 2 ++ * ++ * Default Value: 2 (MSI-X) ++ */ ++E1000_PARAM(IntMode, "Interrupt Mode"); ++#define MAX_INTMODE 2 ++#define MIN_INTMODE 0 ++ ++#endif /* CONFIG_E1000E_MSIX */ ++/* ++ * Enable Smart Power Down of the PHY ++ * ++ * Valid Range: 0, 1 ++ * ++ * Default Value: 0 (disabled) ++ */ ++E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down"); ++ ++/* ++ * Enable Kumeran Lock Loss workaround ++ * ++ * Valid Range: 0, 1 ++ * ++ * Default Value: 1 (enabled) ++ */ ++E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround"); ++ ++/* ++ * Write Protect NVM ++ * ++ * Valid Range: 0, 1 ++ * ++ * Default Value: 1 (enabled) ++ */ ++E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can " ++ "lead to corrupted NVM]"); ++ ++ ++struct e1000_option { ++ enum { enable_option, range_option, list_option } type; ++ const char *name; ++ const char *err; ++ int def; ++ union { ++ struct { /* range_option info */ ++ int min; ++ int max; ++ } r; ++ struct { /* list_option info */ ++ int nr; ++ struct e1000_opt_list { int i; char *str; } *p; ++ } l; ++ } arg; ++}; ++ ++static int __devinit e1000_validate_option(unsigned int *value, ++ const struct e1000_option *opt, ++ struct e1000_adapter *adapter) ++{ ++ if (*value == OPTION_UNSET) { ++ *value = opt->def; ++ return 0; ++ } ++ ++ switch (opt->type) { ++ case enable_option: ++ switch (*value) { ++ case OPTION_ENABLED: ++ e_info("%s Enabled\n", opt->name); ++ return 0; ++ case OPTION_DISABLED: ++ e_info("%s Disabled\n", opt->name); ++ return 0; ++ } ++ break; ++ case range_option: ++ if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { ++ e_info("%s set to %i\n", opt->name, *value); ++ return 0; ++ } ++ break; ++ case list_option: { ++ int i; ++ struct e1000_opt_list *ent; ++ ++ for (i = 0; i < opt->arg.l.nr; i++) { ++ ent = &opt->arg.l.p[i]; ++ if (*value == ent->i) { ++ if (ent->str[0] != '\0') ++ e_info("%s\n", ent->str); ++ return 0; ++ } ++ } ++ } ++ break; ++ default: ++ BUG(); ++ } ++ ++ e_info("Invalid %s value specified (%i) %s\n", opt->name, *value, ++ opt->err); ++ *value = opt->def; ++ return -1; ++} ++ ++/** ++ * e1000_check_options - Range Checking for Command Line Parameters ++ * @adapter: board private structure ++ * ++ * This routine checks all command line parameters for valid user ++ * input. If an invalid value is given, or if no user specified ++ * value exists, a default value is used. The final value is stored ++ * in a variable in the adapter structure. ++ **/ ++void __devinit e1000_check_options(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ int bd = adapter->bd_number; ++ ++ if (bd >= E1000_MAX_NIC) { ++ e_notice("Warning: no configuration for board #%i\n", bd); ++ e_notice("Using defaults for all values\n"); ++ } ++ ++ { /* Transmit Interrupt Delay */ ++ const struct e1000_option opt = { ++ .type = range_option, ++ .name = "Transmit Interrupt Delay", ++ .err = "using default of " ++ __MODULE_STRING(DEFAULT_TIDV), ++ .def = DEFAULT_TIDV, ++ .arg = { .r = { .min = MIN_TXDELAY, ++ .max = MAX_TXDELAY } } ++ }; ++ ++ if (num_TxIntDelay > bd) { ++ adapter->tx_int_delay = TxIntDelay[bd]; ++ e1000_validate_option(&adapter->tx_int_delay, &opt, ++ adapter); ++ } else { ++ adapter->tx_int_delay = opt.def; ++ } ++ } ++ { /* Transmit Absolute Interrupt Delay */ ++ const struct e1000_option opt = { ++ .type = range_option, ++ .name = "Transmit Absolute Interrupt Delay", ++ .err = "using default of " ++ __MODULE_STRING(DEFAULT_TADV), ++ .def = DEFAULT_TADV, ++ .arg = { .r = { .min = MIN_TXABSDELAY, ++ .max = MAX_TXABSDELAY } } ++ }; ++ ++ if (num_TxAbsIntDelay > bd) { ++ adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; ++ e1000_validate_option(&adapter->tx_abs_int_delay, &opt, ++ adapter); ++ } else { ++ adapter->tx_abs_int_delay = opt.def; ++ } ++ } ++ { /* Receive Interrupt Delay */ ++ struct e1000_option opt = { ++ .type = range_option, ++ .name = "Receive Interrupt Delay", ++ .err = "using default of " ++ __MODULE_STRING(DEFAULT_RDTR), ++ .def = DEFAULT_RDTR, ++ .arg = { .r = { .min = MIN_RXDELAY, ++ .max = MAX_RXDELAY } } ++ }; ++ ++ /* ++ * modify min and default if 82573 for slow ping w/a, ++ * a value greater than 8 needs to be set for RDTR ++ */ ++ if (adapter->flags & FLAG_HAS_ASPM) { ++ opt.def = 32; ++ opt.arg.r.min = 8; ++ } ++ ++ if (num_RxIntDelay > bd) { ++ adapter->rx_int_delay = RxIntDelay[bd]; ++ e1000_validate_option(&adapter->rx_int_delay, &opt, ++ adapter); ++ } else { ++ adapter->rx_int_delay = opt.def; ++ } ++ } ++ { /* Receive Absolute Interrupt Delay */ ++ const struct e1000_option opt = { ++ .type = range_option, ++ .name = "Receive Absolute Interrupt Delay", ++ .err = "using default of " ++ __MODULE_STRING(DEFAULT_RADV), ++ .def = DEFAULT_RADV, ++ .arg = { .r = { .min = MIN_RXABSDELAY, ++ .max = MAX_RXABSDELAY } } ++ }; ++ ++ if (num_RxAbsIntDelay > bd) { ++ adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; ++ e1000_validate_option(&adapter->rx_abs_int_delay, &opt, ++ adapter); ++ } else { ++ adapter->rx_abs_int_delay = opt.def; ++ } ++ } ++ { /* Interrupt Throttling Rate */ ++ const struct e1000_option opt = { ++ .type = range_option, ++ .name = "Interrupt Throttling Rate (ints/sec)", ++ .err = "using default of " ++ __MODULE_STRING(DEFAULT_ITR), ++ .def = DEFAULT_ITR, ++ .arg = { .r = { .min = MIN_ITR, ++ .max = MAX_ITR } } ++ }; ++ ++ if (num_InterruptThrottleRate > bd) { ++ adapter->itr = InterruptThrottleRate[bd]; ++ switch (adapter->itr) { ++ case 0: ++ e_info("%s turned off\n", opt.name); ++ break; ++ case 1: ++ e_info("%s set to dynamic mode\n", opt.name); ++ adapter->itr_setting = adapter->itr; ++ adapter->itr = 20000; ++ break; ++ case 3: ++ e_info("%s set to dynamic conservative mode\n", ++ opt.name); ++ adapter->itr_setting = adapter->itr; ++ adapter->itr = 20000; ++ break; ++ default: ++ /* ++ * Save the setting, because the dynamic bits ++ * change itr. ++ */ ++ if (e1000_validate_option(&adapter->itr, &opt, ++ adapter) && ++ (adapter->itr == 3)) { ++ /* ++ * In case of invalid user value, ++ * default to conservative mode. ++ */ ++ adapter->itr_setting = adapter->itr; ++ adapter->itr = 20000; ++ } else { ++ /* ++ * Clear the lower two bits because ++ * they are used as control. ++ */ ++ adapter->itr_setting = ++ adapter->itr & ~3; ++ } ++ break; ++ } ++ } else { ++ adapter->itr_setting = opt.def; ++ adapter->itr = 20000; ++ } ++ } ++#ifdef CONFIG_E1000E_MSIX ++ { /* Interrupt Mode */ ++ struct e1000_option opt = { ++ .type = range_option, ++ .name = "Interrupt Mode", ++ .err = "defaulting to 2 (MSI-X)", ++ .def = E1000E_INT_MODE_MSIX, ++ .arg = { .r = { .min = MIN_INTMODE, ++ .max = MAX_INTMODE }} ++ }; ++ ++ if (num_IntMode > bd) { ++ unsigned int int_mode = IntMode[bd]; ++ e1000_validate_option(&int_mode, &opt, adapter); ++ adapter->int_mode = int_mode; ++ } else { ++ adapter->int_mode = opt.def; ++ } ++ } ++#endif /* CONFIG_E1000E_MSIX */ ++ { /* Smart Power Down */ ++ const struct e1000_option opt = { ++ .type = enable_option, ++ .name = "PHY Smart Power Down", ++ .err = "defaulting to Disabled", ++ .def = OPTION_DISABLED ++ }; ++ ++ if (num_SmartPowerDownEnable > bd) { ++ unsigned int spd = SmartPowerDownEnable[bd]; ++ e1000_validate_option(&spd, &opt, adapter); ++ if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) ++ && spd) ++ adapter->flags |= FLAG_SMART_POWER_DOWN; ++ } ++ } ++ { /* Kumeran Lock Loss Workaround */ ++ const struct e1000_option opt = { ++ .type = enable_option, ++ .name = "Kumeran Lock Loss Workaround", ++ .err = "defaulting to Enabled", ++ .def = OPTION_ENABLED ++ }; ++ ++ if (num_KumeranLockLoss > bd) { ++ unsigned int kmrn_lock_loss = KumeranLockLoss[bd]; ++ e1000_validate_option(&kmrn_lock_loss, &opt, adapter); ++ if (hw->mac.type == e1000_ich8lan) ++ e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, ++ kmrn_lock_loss); ++ } else { ++ if (hw->mac.type == e1000_ich8lan) ++ e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, ++ opt.def); ++ } ++ } ++ { /* Write-protect NVM */ ++ const struct e1000_option opt = { ++ .type = enable_option, ++ .name = "Write-protect NVM", ++ .err = "defaulting to Enabled", ++ .def = OPTION_ENABLED ++ }; ++ ++ if (adapter->flags & FLAG_IS_ICH) { ++ if (num_WriteProtectNVM > bd) { ++ unsigned int write_protect_nvm = WriteProtectNVM[bd]; ++ e1000_validate_option(&write_protect_nvm, &opt, ++ adapter); ++ if (write_protect_nvm) ++ adapter->flags2 |= FLAG2_READ_ONLY_NVM; ++ } else { ++ if (opt.def) ++ adapter->flags2 |= FLAG2_READ_ONLY_NVM; ++ } ++ } ++ } ++} +diff -Nurp linux-2.6.22-0/drivers/net/Kconfig linux-2.6.22-10/drivers/net/Kconfig +--- linux-2.6.22-0/drivers/net/Kconfig 2007-07-09 01:32:17.000000000 +0200 ++++ linux-2.6.22-10/drivers/net/Kconfig 2008-11-10 00:06:46.000000000 +0100 +@@ -1993,6 +1993,29 @@ config E1000_DISABLE_PACKET_SPLIT + + If in doubt, say N. + ++config E1000E ++ tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support" ++ depends on PCI ++ ---help--- ++ This driver supports the PCI-Express Intel(R) PRO/1000 gigabit ++ ethernet family of adapters. For PCI or PCI-X e1000 adapters, ++ use the regular e1000 driver For more information on how to ++ identify your adapter, go to the Adapter & Driver ID Guide at: ++ ++ ++ ++ For general information and support, go to the Intel support ++ website at: ++ ++ ++ ++ More specific information on configuring the driver is in ++ . ++ ++ To compile this driver as a module, choose M here and read ++ . The module ++ will be called e1000e. ++ + source "drivers/net/ixp2000/Kconfig" + + config MYRI_SBUS +diff -Nurp linux-2.6.22-0/drivers/net/Makefile linux-2.6.22-10/drivers/net/Makefile +--- linux-2.6.22-0/drivers/net/Makefile 2007-07-09 01:32:17.000000000 +0200 ++++ linux-2.6.22-10/drivers/net/Makefile 2008-11-10 00:02:57.000000000 +0100 +@@ -3,6 +3,7 @@ + # + + obj-$(CONFIG_E1000) += e1000/ ++obj-$(CONFIG_E1000E) += e1000e/ + obj-$(CONFIG_IBM_EMAC) += ibm_emac/ + obj-$(CONFIG_IXGB) += ixgb/ + obj-$(CONFIG_CHELSIO_T1) += chelsio/ diff --git a/linux-2.6-020-build-id.patch b/linux-2.6-020-build-id.patch new file mode 100644 index 000000000..f4a3b46e6 --- /dev/null +++ b/linux-2.6-020-build-id.patch @@ -0,0 +1,215 @@ +From: Roland McGrath +Date: Thu, 19 Jul 2007 08:48:40 +0000 (-0700) +Subject: Use --build-id ld option +X-Git-Tag: v2.6.23-rc1~388 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=18991197b4b588255ccabf472ebc84db7b66a19c + +Use --build-id ld option + +This change passes the --build-id when linking the kernel and when linking +modules, if ld supports it. This is a new GNU ld option that synthesizes an +ELF note section inside the read-only data. The note in this section contains +unique identifying bits called the "build ID", which are generated so as to be +different for any two linked ELF files that aren't identical. The build ID +can be recovered from stripped files, memory dumps, etc. and used to look up +the original program built, locate debuginfo or other details or history +associated with it. For normal program linking, the compiler passes +--build-id to ld by default, but the option is needed when using ld directly +as we do. + +Signed-off-by: Roland McGrath +Cc: Andi Kleen +Cc: Paul Mackerras +Cc: Benjamin Herrenschmidt +Cc: Richard Henderson +Cc: Ivan Kokshaysky +Cc: Martin Schwidefsky +Cc: Heiko Carstens +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + +diff --git a/Makefile b/Makefile +index ddbfcac..eccb03b 100644 +--- a/Makefile ++++ b/Makefile +@@ -514,6 +514,12 @@ CFLAGS += $(call cc-option,-Wdeclaration-after-statement,) + # disable pointer signed / unsigned warnings in gcc 4.0 + CFLAGS += $(call cc-option,-Wno-pointer-sign,) + ++# Use --build-id when available. ++LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\ ++ $(call ld-option, -Wl$(comma)--build-id,)) ++LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID) ++LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID) ++ + # Default kernel image to build when no specific target is given. + # KBUILD_IMAGE may be overruled on the command line or + # set in the environment + + +From: Roland McGrath +Date: Mon, 23 Jul 2007 08:12:08 +0000 (-0700) +Subject: kbuild: use LDFLAGS_MODULE only for .ko links +X-Git-Tag: v2.6.23-rc2~266^2~3 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=114f51577724b782a30f4f5ceaee9880de93d776 + +kbuild: use LDFLAGS_MODULE only for .ko links + +Sam Ravnborg pointed out that Documentation/kbuild/makefiles.txt already +says this is what it's for. This patch makes the reality live up to the +documentation. This fixes the problem of LDFLAGS_BUILD_ID getting into too +many places. + +Signed-off-by: Roland McGrath +Signed-off-by: Sam Ravnborg +--- + +diff --git a/Makefile b/Makefile +index 23f81c9..dfe3d16 100644 +--- a/Makefile ++++ b/Makefile +@@ -299,7 +299,7 @@ CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(C + MODFLAGS = -DMODULE + CFLAGS_MODULE = $(MODFLAGS) + AFLAGS_MODULE = $(MODFLAGS) +-LDFLAGS_MODULE = -r ++LDFLAGS_MODULE = + CFLAGS_KERNEL = + AFLAGS_KERNEL = + +diff --git a/scripts/Makefile.build b/scripts/Makefile.build +index 3f7b451..7fd6055 100644 +--- a/scripts/Makefile.build ++++ b/scripts/Makefile.build +@@ -315,7 +315,7 @@ quiet_cmd_link_multi-y = LD $@ + cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) + + quiet_cmd_link_multi-m = LD [M] $@ +-cmd_link_multi-m = $(LD) $(ld_flags) $(LDFLAGS_MODULE) -o $@ $(link_multi_deps) ++cmd_link_multi-m = $(cmd_link_multi-y) + + # We would rather have a list of rules like + # foo.o: $(foo-objs) +diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost +index 1818c50..d988f5d 100644 +--- a/scripts/Makefile.modpost ++++ b/scripts/Makefile.modpost +@@ -98,7 +98,7 @@ targets += $(modules:.ko=.mod.o) + + # Step 6), final link of the modules + quiet_cmd_ld_ko_o = LD [M] $@ +- cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \ ++ cmd_ld_ko_o = $(LD) -r $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \ + $(filter-out FORCE,$^) + + $(modules): %.ko :%.o %.mod.o FORCE + + + +From: Roland McGrath +Date: Thu, 19 Jul 2007 08:48:37 +0000 (-0700) +Subject: x86_64: Put allocated ELF notes in read-only data segment +X-Git-Tag: v2.6.23-rc1~393 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=2e1d5b8f24a887caded5ae3ceb2f341d4fbd1861 + +x86_64: Put allocated ELF notes in read-only data segment + +This changes the x86_64 linker script to use the asm-generic NOTES macro so +that ELF note sections with SHF_ALLOC set are linked into the kernel image +along with other read-only data. The PT_NOTE also points to their location. + +This paves the way for putting useful build-time information into ELF notes +that can be found easily later in a kernel memory dump. + +Signed-off-by: Roland McGrath +Cc: Andi Kleen +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + +diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S +index 2259069..5c57ea4 100644 +--- a/arch/x86_64/kernel/vmlinux.lds.S ++++ b/arch/x86_64/kernel/vmlinux.lds.S +@@ -48,7 +48,9 @@ SECTIONS + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } + __stop___ex_table = .; + +- BUG_TABLE ++ NOTES :text :note ++ ++ BUG_TABLE :text + + RODATA + + + + +From: Roland McGrath +Date: Thu, 19 Jul 2007 08:48:36 +0000 (-0700) +Subject: i386: Put allocated ELF notes in read-only data segment +X-Git-Tag: v2.6.23-rc1~394 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=cbe87121f1545bb3e98ae114519bf0c4db27d6ab + +i386: Put allocated ELF notes in read-only data segment + +This changes the i386 linker script and the asm-generic macro it uses so that +ELF note sections with SHF_ALLOC set are linked into the kernel image along +with other read-only data. The PT_NOTE also points to their location. + +This paves the way for putting useful build-time information into ELF notes +that can be found easily later in a kernel memory dump. + +Signed-off-by: Roland McGrath +Cc: Andi Kleen +Cc: Paul Mackerras +Cc: Benjamin Herrenschmidt +Cc: Richard Henderson +Cc: Ivan Kokshaysky +Cc: Martin Schwidefsky +Cc: Heiko Carstens +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + +diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S +index 4dc44b8..7d72cce 100644 +--- a/arch/i386/kernel/vmlinux.lds.S ++++ b/arch/i386/kernel/vmlinux.lds.S +@@ -60,7 +60,9 @@ SECTIONS + __stop___ex_table = .; + } + +- BUG_TABLE ++ NOTES :text :note ++ ++ BUG_TABLE :text + + . = ALIGN(4); + .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { +@@ -208,6 +210,4 @@ SECTIONS + STABS_DEBUG + + DWARF_DEBUG +- +- NOTES + } +diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h +index a2b09ed..0240e05 100644 +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -224,7 +224,11 @@ + } + + #define NOTES \ +- .notes : { *(.note.*) } :note ++ .notes : AT(ADDR(.notes) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start_notes) = .; \ ++ *(.note.*) \ ++ VMLINUX_SYMBOL(__stop_notes) = .; \ ++ } + + #define INITCALLS \ + *(.initcall0.init) \ + diff --git a/linux-2.6-030-netns.patch b/linux-2.6-030-netns.patch new file mode 100644 index 000000000..56f3d6306 --- /dev/null +++ b/linux-2.6-030-netns.patch @@ -0,0 +1,707332 @@ +diff -Nurp linux-2.6.22/.gitignore linux-2.6-netns/.gitignore +--- linux-2.6.22/.gitignore 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/.gitignore 2007-12-03 23:14:12.000000000 -0500 +@@ -45,3 +45,6 @@ series + + # cscope files + cscope.* ++ ++*.orig ++*.rej +diff -Nurp linux-2.6.22/Documentation/00-INDEX linux-2.6-netns/Documentation/00-INDEX +--- linux-2.6.22/Documentation/00-INDEX 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/00-INDEX 2007-12-03 23:14:12.000000000 -0500 +@@ -12,6 +12,8 @@ Following translations are available on + + 00-INDEX + - this file. ++ABI/ ++ - info on kernel <-> userspace ABI and relative interface stability. + BUG-HUNTING + - brute force method of doing binary search of patches to find bug. + Changes +@@ -25,37 +27,57 @@ DMA-mapping.txt + DocBook/ + - directory with DocBook templates etc. for kernel documentation. + HOWTO +- - The process and procedures of how to do Linux kernel development. ++ - the process and procedures of how to do Linux kernel development. + IO-mapping.txt + - how to access I/O mapped memory from within device drivers. + IPMI.txt + - info on Linux Intelligent Platform Management Interface (IPMI) Driver. + IRQ-affinity.txt + - how to select which CPU(s) handle which interrupt events on SMP. ++IRQ.txt ++ - description of what an IRQ is. + ManagementStyle + - how to (attempt to) manage kernel hackers. + MSI-HOWTO.txt + - the Message Signaled Interrupts (MSI) Driver Guide HOWTO and FAQ. ++PCIEBUS-HOWTO.txt ++ - a guide describing the PCI Express Port Bus driver. + RCU/ + - directory with info on RCU (read-copy update). + README.DAC960 + - info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux. ++README.cycladesZ ++ - info on Cyclades-Z firmware loading. + SAK.txt + - info on Secure Attention Keys. ++SecurityBugs ++ - procedure for reporting security bugs found in the kernel. ++SubmitChecklist ++ - Linux kernel patch submission checklist. + SubmittingDrivers + - procedure to get a new driver source included into the kernel tree. + SubmittingPatches + - procedure to get a source patch included into the kernel tree. + VGA-softcursor.txt + - how to change your VGA cursor from a blinking underscore. ++accounting/ ++ - documentation on accounting and taskstats. ++aoe/ ++ - description of AoE (ATA over Ethernet) along with config examples. + applying-patches.txt + - description of various trees and how to apply their patches. + arm/ + - directory with info about Linux on the ARM architecture. ++atomic_ops.txt ++ - semantics and behavior of atomic and bitmask operations. ++auxdisplay/ ++ - misc. LCD driver documentation (cfag12864b, ks0108). + basic_profiling.txt + - basic instructions for those who wants to profile Linux kernel. + binfmt_misc.txt + - info on the kernel support for extra binary formats. ++blackfin/ ++ - directory with documentation for the Blackfin arch. + block/ + - info on the Block I/O (BIO) layer. + cachetlb.txt +@@ -68,16 +90,32 @@ cli-sti-removal.txt + - cli()/sti() removal guide. + computone.txt + - info on Computone Intelliport II/Plus Multiport Serial Driver. ++connector/ ++ - docs on the netlink based userspace<->kernel space communication mod. ++console/ ++ - documentation on Linux console drivers. + cpqarray.txt + - info on using Compaq's SMART2 Intelligent Disk Array Controllers. + cpu-freq/ + - info on CPU frequency and voltage scaling. ++cpu-hotplug.txt ++ - document describing CPU hotplug support in the Linux kernel. ++cpu-load.txt ++ - document describing how CPU load statistics are collected. ++cpusets.txt ++ - documents the cpusets feature; assign CPUs and Mem to a set of tasks. ++cputopology.txt ++ - documentation on how CPU topology info is exported via sysfs. + cris/ + - directory with info about Linux on CRIS architecture. + crypto/ + - directory with info on the Crypto API. ++dcdbas.txt ++ - information on the Dell Systems Management Base Driver. + debugging-modules.txt + - some notes on debugging modules after Linux 2.6.3. ++dell_rbu.txt ++ - document demonstrating the use of the Dell Remote BIOS Update driver. + device-mapper/ + - directory with info on Device Mapper. + devices.txt +@@ -86,32 +124,52 @@ digiepca.txt + - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards. + dnotify.txt + - info about directory notification in Linux. ++dontdiff ++ - file containing a list of files that should never be diff'ed. + driver-model/ + - directory with info about Linux driver model. ++drivers/ ++ - directory with driver documentation (currently only EDAC). + dvb/ + - info on Linux Digital Video Broadcast (DVB) subsystem. + early-userspace/ + - info about initramfs, klibc, and userspace early during boot. ++ecryptfs.txt ++ - docs on eCryptfs: stacked cryptographic filesystem for Linux. + eisa.txt + - info on EISA bus support. + exception.txt + - how Linux v2.2 handles exceptions without verify_area etc. ++fault-injection/ ++ - dir with docs about the fault injection capabilities infrastructure. + fb/ + - directory with info on the frame buffer graphics abstraction layer. ++feature-removal-schedule.txt ++ - list of files and features that are going to be removed. + filesystems/ + - directory with info on the various filesystems that Linux supports. + firmware_class/ + - request_firmware() hotplug interface info. + floppy.txt + - notes and driver options for the floppy disk driver. ++fujitsu/ ++ - Fujitsu FR-V Linux documentation. ++gpio.txt ++ - overview of GPIO (General Purpose Input/Output) access conventions. + hayes-esp.txt + - info on using the Hayes ESP serial driver. + highuid.txt + - notes on the change from 16 bit to 32 bit user/group IDs. + hpet.txt + - High Precision Event Timer Driver for Linux. ++hrtimer/ ++ - info on the timer_stats debugging facility for timer (ab)use. ++hrtimers/ ++ - info on the hrtimers subsystem for high-resolution kernel timers. + hw_random.txt + - info on Linux support for random number generator in i8xx chipsets. ++hwmon/ ++ - directory with docs on various hardware monitoring drivers. + i2c/ + - directory with info about the I2C bus/protocol (2 wire, kHz speed). + i2o/ +@@ -122,16 +180,22 @@ ia64/ + - directory with info about Linux on Intel 64 bit architecture. + ide.txt + - important info for users of ATA devices (IDE/EIDE disks and CD-ROMS). ++infiniband/ ++ - directory with documents concerning Linux InfiniBand support. + initrd.txt + - how to use the RAM disk as an initial/temporary root filesystem. + input/ + - info on Linux input device support. + io_ordering.txt + - info on ordering I/O writes to memory-mapped addresses. ++ioctl/ ++ - directory with documents describing various IOCTL calls. + ioctl-number.txt + - how to implement and register device/driver ioctl calls. + iostats.txt + - info on I/O statistics Linux kernel provides. ++irqflags-tracing.txt ++ - how to use the irq-flags tracing feature. + isapnp.txt + - info on Linux ISA Plug & Play support. + isdn/ +@@ -140,26 +204,40 @@ java.txt + - info on the in-kernel binary support for Java(tm). + kbuild/ + - directory with info about the kernel build process. +-kdumpt.txt +- - mini HowTo on getting the crash dump code to work. ++kdump/ ++ - directory with mini HowTo on getting the crash dump code to work. + kernel-doc-nano-HOWTO.txt + - mini HowTo on generation and location of kernel documentation files. + kernel-docs.txt + - listing of various WWW + books that document kernel internals. + kernel-parameters.txt + - summary listing of command line / boot prompt args for the kernel. ++keys-request-key.txt ++ - description of the kernel key request service. ++keys.txt ++ - description of the kernel key retention service. + kobject.txt + - info of the kobject infrastructure of the Linux kernel. ++kprobes.txt ++ - documents the kernel probes debugging feature. ++kref.txt ++ - docs on adding reference counters (krefs) to kernel objects. + laptop-mode.txt +- - How to conserve battery power using laptop-mode. ++ - how to conserve battery power using laptop-mode. + ldm.txt + - a brief description of LDM (Windows Dynamic Disks). ++leds-class.txt ++ - documents LED handling under Linux. ++local_ops.txt ++ - semantics and behavior of local atomic operations. ++lockdep-design.txt ++ - documentation on the runtime locking correctness validator. + locks.txt + - info on file locking implementations, flock() vs. fcntl(), etc. + logo.gif +- - Full colour GIF image of Linux logo (penguin). ++ - full colour GIF image of Linux logo (penguin - Tux). + logo.txt +- - Info on creator of above logo & site to get additional images from. ++ - info on creator of above logo & site to get additional images from. + m68k/ + - directory with info about Linux on Motorola 68k architecture. + magic-number.txt +@@ -170,6 +248,8 @@ mca.txt + - info on supporting Micro Channel Architecture (e.g. PS/2) systems. + md.txt + - info on boot arguments for the multiple devices driver. ++memory-barriers.txt ++ - info on Linux kernel memory barriers. + memory.txt + - info on typical Linux memory problems. + mips/ +@@ -177,9 +257,11 @@ mips/ + mono.txt + - how to execute Mono-based .NET binaries with the help of BINFMT_MISC. + moxa-smartio +- - info on installing/using Moxa multiport serial driver. ++ - file with info on installing/using Moxa multiport serial driver. + mtrr.txt + - how to use PPro Memory Type Range Registers to increase performance. ++mutex-design.txt ++ - info on the generic mutex subsystem. + nbd.txt + - info on a TCP implementation of a network block device. + netlabel/ +@@ -190,6 +272,8 @@ nfsroot.txt + - short guide on setting up a diskless box with NFS root filesystem. + nmi_watchdog.txt + - info on NMI watchdog for SMP systems. ++nommu-mmap.txt ++ - documentation about no-mmu memory mapping support. + numastat.txt + - info on how to read Numa policy hit/miss statistics in sysfs. + oops-tracing.txt +@@ -202,8 +286,16 @@ parport.txt + - how to use the parallel-port driver. + parport-lowlevel.txt + - description and usage of the low level parallel port functions. ++pci-error-recovery.txt ++ - info on PCI error recovery. + pci.txt + - info on the PCI subsystem for device driver authors. ++pcieaer-howto.txt ++ - the PCI Express Advanced Error Reporting Driver Guide HOWTO. ++pcmcia/ ++ - info on the Linux PCMCIA driver. ++pi-futex.txt ++ - documentation on lightweight PI-futexes. + pm.txt + - info on Linux power management support. + pnp.txt +@@ -214,18 +306,32 @@ powerpc/ + - directory with info on using Linux with the PowerPC. + preempt-locking.txt + - info on locking under a preemptive kernel. ++prio_tree.txt ++ - info on radix-priority-search-tree use for indexing vmas. + ramdisk.txt + - short guide on how to set up and use the RAM disk. ++rbtree.txt ++ - info on what red-black trees are and what they are for. + riscom8.txt + - notes on using the RISCom/8 multi-port serial driver. ++robust-futex-ABI.txt ++ - documentation of the robust futex ABI. ++robust-futexes.txt ++ - a description of what robust futexes are. + rocket.txt + - info on the Comtrol RocketPort multiport serial driver. + rpc-cache.txt + - introduction to the caching mechanisms in the sunrpc layer. ++rt-mutex-design.txt ++ - description of the RealTime mutex implementation design. ++rt-mutex.txt ++ - desc. of RT-mutex subsystem with PI (Priority Inheritance) support. + rtc.txt + - notes on how to use the Real Time Clock (aka CMOS clock) driver. + s390/ + - directory with info on using Linux on the IBM S390. ++sched-arch.txt ++ - CPU Scheduler implementation hints for architecture specific code. + sched-coding.txt + - reference for various scheduler-related methods in the O(1) scheduler. + sched-design.txt +@@ -240,22 +346,32 @@ serial/ + - directory with info on the low level serial API. + serial-console.txt + - how to set up Linux with a serial line console as the default. ++sgi-ioc4.txt ++ - description of the SGI IOC4 PCI (multi function) device. + sgi-visws.txt + - short blurb on the SGI Visual Workstations. + sh/ + - directory with info on porting Linux to a new architecture. ++sharedsubtree.txt ++ - a description of shared subtrees for namespaces. + smart-config.txt + - description of the Smart Config makefile feature. + smp.txt + - a few notes on symmetric multi-processing. ++sony-laptop.txt ++ - Sony Notebook Control Driver (SNC) Readme. + sonypi.txt + - info on Linux Sony Programmable I/O Device support. + sound/ + - directory with info on sound card support. + sparc/ + - directory with info on using Linux on Sparc architecture. ++sparse.txt ++ - info on how to obtain and use the sparse tool for typechecking. + specialix.txt + - info on hardware/driver for specialix IO8+ multiport serial card. ++spi/ ++ - overview of Linux kernel Serial Peripheral Interface (SPI) support. + spinlocks.txt + - info on using spinlocks to provide exclusive access in kernel. + stable_api_nonsense.txt +@@ -274,24 +390,32 @@ sysrq.txt + - info on the magic SysRq key. + telephony/ + - directory with info on telephony (e.g. voice over IP) support. ++thinkpad-acpi.txt ++ - information on the (IBM and Lenovo) ThinkPad ACPI Extras driver. + time_interpolators.txt + - info on time interpolators. + tipar.txt + - information about Parallel link cable for Texas Instruments handhelds. + tty.txt + - guide to the locking policies of the tty layer. +-unicode.txt +- - info on the Unicode character/font mapping used in Linux. + uml/ + - directory with information about User Mode Linux. ++unicode.txt ++ - info on the Unicode character/font mapping used in Linux. ++unshare.txt ++ - description of the Linux unshare system call. + usb/ + - directory with info regarding the Universal Serial Bus. ++video-output.txt ++ - sysfs class driver interface to enable/disable a video output device. + video4linux/ + - directory with info regarding video/TV/radio cards and linux. + vm/ + - directory with info on the Linux vm code. + voyager.txt + - guide to running Linux on the Voyager architecture. ++w1/ ++ - directory with documents regarding the 1-wire (w1) subsystem. + watchdog/ + - how to auto-reboot Linux if it has "fallen and can't get up". ;-) + x86_64/ +diff -Nurp linux-2.6.22/Documentation/ABI/removed/raw1394_legacy_isochronous linux-2.6-netns/Documentation/ABI/removed/raw1394_legacy_isochronous +--- linux-2.6.22/Documentation/ABI/removed/raw1394_legacy_isochronous 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/ABI/removed/raw1394_legacy_isochronous 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,16 @@ ++What: legacy isochronous ABI of raw1394 (1st generation iso ABI) ++Date: June 2007 (scheduled), removed in kernel v2.6.23 ++Contact: linux1394-devel@lists.sourceforge.net ++Description: ++ The two request types RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN have ++ been deprecated for quite some time. They are very inefficient as they ++ come with high interrupt load and several layers of callbacks for each ++ packet. Because of these deficiencies, the video1394 and dv1394 drivers ++ and the 3rd-generation isochronous ABI in raw1394 (rawiso) were created. ++ ++Users: ++ libraw1394 users via the long deprecated API raw1394_iso_write, ++ raw1394_start_iso_write, raw1394_start_iso_rcv, raw1394_stop_iso_rcv ++ ++ libdc1394, which optionally uses these old libraw1394 calls ++ alternatively to the more efficient video1394 ABI +diff -Nurp linux-2.6.22/Documentation/ABI/testing/sysfs-bus-usb linux-2.6-netns/Documentation/ABI/testing/sysfs-bus-usb +--- linux-2.6.22/Documentation/ABI/testing/sysfs-bus-usb 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/ABI/testing/sysfs-bus-usb 2007-12-03 23:06:33.000000000 -0500 +@@ -39,3 +39,16 @@ Description: + If you want to suspend a device immediately but leave it + free to wake up in response to I/O requests, you should + write "0" to power/autosuspend. ++ ++What: /sys/bus/usb/devices/.../power/persist ++Date: May 2007 ++KernelVersion: 2.6.23 ++Contact: Alan Stern ++Description: ++ If CONFIG_USB_PERSIST is set, then each USB device directory ++ will contain a file named power/persist. The file holds a ++ boolean value (0 or 1) indicating whether or not the ++ "USB-Persist" facility is enabled for the device. Since the ++ facility is inherently dangerous, it is disabled by default ++ for all devices except hubs. For more information, see ++ Documentation/usb/persist.txt. +diff -Nurp linux-2.6.22/Documentation/CodingStyle linux-2.6-netns/Documentation/CodingStyle +--- linux-2.6.22/Documentation/CodingStyle 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/CodingStyle 2007-12-03 23:14:12.000000000 -0500 +@@ -218,6 +218,18 @@ no space after the prefix increment & de + + and no space around the '.' and "->" structure member operators. + ++Do not leave trailing whitespace at the ends of lines. Some editors with ++"smart" indentation will insert whitespace at the beginning of new lines as ++appropriate, so you can start typing the next line of code right away. ++However, some such editors do not remove the whitespace if you end up not ++putting a line of code there, such as if you leave a blank line. As a result, ++you end up with lines containing trailing whitespace. ++ ++Git will warn you about patches that introduce trailing whitespace, and can ++optionally strip the trailing whitespace for you; however, if applying a series ++of patches, this may make later patches in the series fail by changing their ++context lines. ++ + + Chapter 4: Naming + +@@ -621,12 +633,27 @@ covers RTL which is used frequently with + + Kernel developers like to be seen as literate. Do mind the spelling + of kernel messages to make a good impression. Do not use crippled +-words like "dont" and use "do not" or "don't" instead. ++words like "dont"; use "do not" or "don't" instead. Make the messages ++concise, clear, and unambiguous. + + Kernel messages do not have to be terminated with a period. + + Printing numbers in parentheses (%d) adds no value and should be avoided. + ++There are a number of driver model diagnostic macros in ++which you should use to make sure messages are matched to the right device ++and driver, and are tagged with the right level: dev_err(), dev_warn(), ++dev_info(), and so forth. For messages that aren't associated with a ++particular device, defines pr_debug() and pr_info(). ++ ++Coming up with good debugging messages can be quite a challenge; and once ++you have them, they can be a huge help for remote troubleshooting. Such ++messages should be compiled out when the DEBUG symbol is not defined (that ++is, by default they are not included). When you use dev_dbg() or pr_debug(), ++that's automatic. Many subsystems have Kconfig options to turn on -DDEBUG. ++A related convention uses VERBOSE_DEBUG to add dev_vdbg() messages to the ++ones already enabled by DEBUG. ++ + + Chapter 14: Allocating memory + +@@ -726,6 +753,33 @@ need them. Feel free to peruse that hea + defined that you shouldn't reproduce in your code. + + ++ Chapter 18: Editor modelines and other cruft ++ ++Some editors can interpret configuration information embedded in source files, ++indicated with special markers. For example, emacs interprets lines marked ++like this: ++ ++-*- mode: c -*- ++ ++Or like this: ++ ++/* ++Local Variables: ++compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" ++End: ++*/ ++ ++Vim interprets markers that look like this: ++ ++/* vim:set sw=8 noet */ ++ ++Do not include any of these in source files. People have their own personal ++editor configurations, and your source files should not override them. This ++includes markers for indentation and mode configuration. People may use their ++own custom mode, or may have some other magic method for making indentation ++work correctly. ++ ++ + + Appendix I: References + +@@ -751,4 +805,5 @@ Kernel CodingStyle, by greg@kroah.com at + http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/ + + -- +-Last updated on 2006-December-06. ++Last updated on 2007-July-13. ++ +diff -Nurp linux-2.6.22/Documentation/DMA-mapping.txt linux-2.6-netns/Documentation/DMA-mapping.txt +--- linux-2.6.22/Documentation/DMA-mapping.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/DMA-mapping.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -664,109 +664,6 @@ It is that simple. + Well, not for some odd devices. See the next section for information + about that. + +- DAC Addressing for Address Space Hungry Devices +- +-There exists a class of devices which do not mesh well with the PCI +-DMA mapping API. By definition these "mappings" are a finite +-resource. The number of total available mappings per bus is platform +-specific, but there will always be a reasonable amount. +- +-What is "reasonable"? Reasonable means that networking and block I/O +-devices need not worry about using too many mappings. +- +-As an example of a problematic device, consider compute cluster cards. +-They can potentially need to access gigabytes of memory at once via +-DMA. Dynamic mappings are unsuitable for this kind of access pattern. +- +-To this end we've provided a small API by which a device driver +-may use DAC cycles to directly address all of physical memory. +-Not all platforms support this, but most do. It is easy to determine +-whether the platform will work properly at probe time. +- +-First, understand that there may be a SEVERE performance penalty for +-using these interfaces on some platforms. Therefore, you MUST only +-use these interfaces if it is absolutely required. %99 of devices can +-use the normal APIs without any problems. +- +-Note that for streaming type mappings you must either use these +-interfaces, or the dynamic mapping interfaces above. You may not mix +-usage of both for the same device. Such an act is illegal and is +-guaranteed to put a banana in your tailpipe. +- +-However, consistent mappings may in fact be used in conjunction with +-these interfaces. Remember that, as defined, consistent mappings are +-always going to be SAC addressable. +- +-The first thing your driver needs to do is query the PCI platform +-layer if it is capable of handling your devices DAC addressing +-capabilities: +- +- int pci_dac_dma_supported(struct pci_dev *hwdev, u64 mask); +- +-You may not use the following interfaces if this routine fails. +- +-Next, DMA addresses using this API are kept track of using the +-dma64_addr_t type. It is guaranteed to be big enough to hold any +-DAC address the platform layer will give to you from the following +-routines. If you have consistent mappings as well, you still +-use plain dma_addr_t to keep track of those. +- +-All mappings obtained here will be direct. The mappings are not +-translated, and this is the purpose of this dialect of the DMA API. +- +-All routines work with page/offset pairs. This is the _ONLY_ way to +-portably refer to any piece of memory. If you have a cpu pointer +-(which may be validly DMA'd too) you may easily obtain the page +-and offset using something like this: +- +- struct page *page = virt_to_page(ptr); +- unsigned long offset = offset_in_page(ptr); +- +-Here are the interfaces: +- +- dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, +- struct page *page, +- unsigned long offset, +- int direction); +- +-The DAC address for the tuple PAGE/OFFSET are returned. The direction +-argument is the same as for pci_{map,unmap}_single(). The same rules +-for cpu/device access apply here as for the streaming mapping +-interfaces. To reiterate: +- +- The cpu may touch the buffer before pci_dac_page_to_dma. +- The device may touch the buffer after pci_dac_page_to_dma +- is made, but the cpu may NOT. +- +-When the DMA transfer is complete, invoke: +- +- void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, +- dma64_addr_t dma_addr, +- size_t len, int direction); +- +-This must be done before the CPU looks at the buffer again. +-This interface behaves identically to pci_dma_sync_{single,sg}_for_cpu(). +- +-And likewise, if you wish to let the device get back at the buffer after +-the cpu has read/written it, invoke: +- +- void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, +- dma64_addr_t dma_addr, +- size_t len, int direction); +- +-before letting the device access the DMA area again. +- +-If you need to get back to the PAGE/OFFSET tuple from a dma64_addr_t +-the following interfaces are provided: +- +- struct page *pci_dac_dma_to_page(struct pci_dev *pdev, +- dma64_addr_t dma_addr); +- unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, +- dma64_addr_t dma_addr); +- +-This is possible with the DAC interfaces purely because they are +-not translated in any way. +- + Optimizing Unmap State Space Consumption + + On many platforms, pci_unmap_{single,page}() is simply a nop. +diff -Nurp linux-2.6.22/Documentation/DocBook/kernel-api.tmpl linux-2.6-netns/Documentation/DocBook/kernel-api.tmpl +--- linux-2.6.22/Documentation/DocBook/kernel-api.tmpl 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/DocBook/kernel-api.tmpl 2007-12-03 23:14:12.000000000 -0500 +@@ -139,8 +139,10 @@ X!Ilib/string.c + !Elib/cmdline.c + + +- CRC Functions ++ CRC Functions ++!Elib/crc7.c + !Elib/crc16.c ++!Elib/crc-itu-t.c + !Elib/crc32.c + !Elib/crc-ccitt.c + +@@ -406,6 +408,10 @@ X!Edrivers/pnp/system.c + !Edrivers/pnp/manager.c + !Edrivers/pnp/support.c + ++ Userspace IO devices ++!Edrivers/uio/uio.c ++!Iinclude/linux/uio_driver.h ++ + + + +@@ -643,4 +649,70 @@ X!Idrivers/video/console/fonts.c + !Edrivers/spi/spi.c + + ++ ++ I<superscript>2</superscript>C and SMBus Subsystem ++ ++ ++ I2C (or without fancy typography, "I2C") ++ is an acronym for the "Inter-IC" bus, a simple bus protocol which is ++ widely used where low data rate communications suffice. ++ Since it's also a licensed trademark, some vendors use another ++ name (such as "Two-Wire Interface", TWI) for the same bus. ++ I2C only needs two signals (SCL for clock, SDA for data), conserving ++ board real estate and minimizing signal quality issues. ++ Most I2C devices use seven bit addresses, and bus speeds of up ++ to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet ++ found wide use. ++ I2C is a multi-master bus; open drain signaling is used to ++ arbitrate between masters, as well as to handshake and to ++ synchronize clocks from slower clients. ++ ++ ++ ++ The Linux I2C programming interfaces support only the master ++ side of bus interactions, not the slave side. ++ The programming interface is structured around two kinds of driver, ++ and two kinds of device. ++ An I2C "Adapter Driver" abstracts the controller hardware; it binds ++ to a physical device (perhaps a PCI device or platform_device) and ++ exposes a struct i2c_adapter representing ++ each I2C bus segment it manages. ++ On each I2C bus segment will be I2C devices represented by a ++ struct i2c_client. Those devices will ++ be bound to a struct i2c_driver, ++ which should follow the standard Linux driver model. ++ (At this writing, a legacy model is more widely used.) ++ There are functions to perform various I2C protocol operations; at ++ this writing all such functions are usable only from task context. ++ ++ ++ ++ The System Management Bus (SMBus) is a sibling protocol. Most SMBus ++ systems are also I2C conformant. The electrical constraints are ++ tighter for SMBus, and it standardizes particular protocol messages ++ and idioms. Controllers that support I2C can also support most ++ SMBus operations, but SMBus controllers don't support all the protocol ++ options that an I2C controller will. ++ There are functions to perform various SMBus protocol operations, ++ either using I2C primitives or by issuing SMBus commands to ++ i2c_adapter devices which don't support those I2C operations. ++ ++ ++!Iinclude/linux/i2c.h ++!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info ++!Edrivers/i2c/i2c-core.c ++ ++ ++ ++ splice API ++ ) ++ splice is a method for moving blocks of data around inside the ++ kernel, without continually transferring it between the kernel ++ and user space. ++ ++!Iinclude/linux/splice.h ++!Ffs/splice.c ++ ++ ++ + +diff -Nurp linux-2.6.22/Documentation/DocBook/procfs-guide.tmpl linux-2.6-netns/Documentation/DocBook/procfs-guide.tmpl +--- linux-2.6.22/Documentation/DocBook/procfs-guide.tmpl 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/DocBook/procfs-guide.tmpl 2007-12-03 23:06:33.000000000 -0500 +@@ -352,49 +352,93 @@ entry->write_proc = write_proc_foo; + + + int read_func +- char* page ++ char* buffer + char** start + off_t off + int count +- int* eof ++ int* peof + void* data + + + + + The read function should write its information into the +- page. For proper use, the function +- should start writing at an offset of +- off in page and +- write at most count bytes, but because +- most read functions are quite simple and only return a small +- amount of information, these two parameters are usually +- ignored (it breaks pagers like more and +- less, but cat still +- works). ++ buffer, which will be exactly ++ PAGE_SIZE bytes long. + + + +- If the off and +- count parameters are properly used, +- eof should be used to signal that the ++ The parameter ++ peof should be used to signal that the + end of the file has been reached by writing + 1 to the memory location +- eof points to. ++ peof points to. + + + +- The parameter start doesn't seem to be +- used anywhere in the kernel. The data ++ The data + parameter can be used to create a single call back function for + several files, see . + + + +- The read_func function must return the +- number of bytes written into the page. ++ The rest of the parameters and the return value are described ++ by a comment in fs/proc/generic.c as follows: + + ++
++ ++ You have three ways to return data: ++ ++ ++ ++ ++ Leave *start = NULL. (This is the default.) ++ Put the data of the requested offset at that ++ offset within the buffer. Return the number (n) ++ of bytes there are from the beginning of the ++ buffer up to the last byte of data. If the ++ number of supplied bytes (= n - offset) is ++ greater than zero and you didn't signal eof ++ and the reader is prepared to take more data ++ you will be called again with the requested ++ offset advanced by the number of bytes ++ absorbed. This interface is useful for files ++ no larger than the buffer. ++ ++ ++ ++ ++ Set *start to an unsigned long value less than ++ the buffer address but greater than zero. ++ Put the data of the requested offset at the ++ beginning of the buffer. Return the number of ++ bytes of data placed there. If this number is ++ greater than zero and you didn't signal eof ++ and the reader is prepared to take more data ++ you will be called again with the requested ++ offset advanced by *start. This interface is ++ useful when you have a large file consisting ++ of a series of blocks which you want to count ++ and return as wholes. ++ (Hack by Paul.Russell@rustcorp.com.au) ++ ++ ++ ++ ++ Set *start to an address within the buffer. ++ Put the data of the requested offset at *start. ++ Return the number of bytes of data placed there. ++ If this number is greater than zero and you ++ didn't signal eof and the reader is prepared to ++ take more data you will be called again with the ++ requested offset advanced by the number of bytes ++ absorbed. ++ ++ ++ ++
++ + + shows how to use a read call back + function. +diff -Nurp linux-2.6.22/Documentation/DocBook/uio-howto.tmpl linux-2.6-netns/Documentation/DocBook/uio-howto.tmpl +--- linux-2.6.22/Documentation/DocBook/uio-howto.tmpl 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/DocBook/uio-howto.tmpl 2007-12-03 23:14:12.000000000 -0500 +@@ -0,0 +1,611 @@ ++ ++ ++ ++ ++ ++The Userspace I/O HOWTO ++ ++ ++ Hans-Jürgen ++ Koch ++ Linux developer, Linutronix ++ ++ ++ Linutronix ++ ++ ++
++ hjk@linutronix.de ++
++
++
++ ++2006-12-11 ++ ++ ++ This HOWTO describes concept and usage of Linux kernel's ++ Userspace I/O system. ++ ++ ++ ++ ++ 0.3 ++ 2007-04-29 ++ hjk ++ Added section about userspace drivers. ++ ++ ++ 0.2 ++ 2007-02-13 ++ hjk ++ Update after multiple mappings were added. ++ ++ ++ 0.1 ++ 2006-12-11 ++ hjk ++ First draft. ++ ++ ++
++ ++ ++ ++About this document ++ ++ ++ ++Copyright and License ++ ++ Copyright (c) 2006 by Hans-Jürgen Koch. ++ ++This documentation is Free Software licensed under the terms of the ++GPL version 2. ++ ++ ++ ++ ++ ++Translations ++ ++If you know of any translations for this document, or you are ++interested in translating it, please email me ++hjk@linutronix.de. ++ ++ ++ ++ ++Preface ++ ++ For many types of devices, creating a Linux kernel driver is ++ overkill. All that is really needed is some way to handle an ++ interrupt and provide access to the memory space of the ++ device. The logic of controlling the device does not ++ necessarily have to be within the kernel, as the device does ++ not need to take advantage of any of other resources that the ++ kernel provides. One such common class of devices that are ++ like this are for industrial I/O cards. ++ ++ ++ To address this situation, the userspace I/O system (UIO) was ++ designed. For typical industrial I/O cards, only a very small ++ kernel module is needed. The main part of the driver will run in ++ user space. This simplifies development and reduces the risk of ++ serious bugs within a kernel module. ++ ++ ++ ++ ++Acknowledgments ++ I'd like to thank Thomas Gleixner and Benedikt Spranger of ++ Linutronix, who have not only written most of the UIO code, but also ++ helped greatly writing this HOWTO by giving me all kinds of background ++ information. ++ ++ ++ ++Feedback ++ Find something wrong with this document? (Or perhaps something ++ right?) I would love to hear from you. Please email me at ++ hjk@linutronix.de. ++ ++ ++ ++ ++ ++About UIO ++ ++If you use UIO for your card's driver, here's what you get: ++ ++ ++ ++ only one small kernel module to write and maintain. ++ ++ ++ develop the main part of your driver in user space, ++ with all the tools and libraries you're used to. ++ ++ ++ bugs in your driver won't crash the kernel. ++ ++ ++ updates of your driver can take place without recompiling ++ the kernel. ++ ++ ++ if you need to keep some parts of your driver closed source, ++ you can do so without violating the GPL license on the kernel. ++ ++ ++ ++ ++How UIO works ++ ++ Each UIO device is accessed through a device file and several ++ sysfs attribute files. The device file will be called ++ /dev/uio0 for the first device, and ++ /dev/uio1, /dev/uio2 ++ and so on for subsequent devices. ++ ++ ++ /dev/uioX is used to access the ++ address space of the card. Just use ++ mmap() to access registers or RAM ++ locations of your card. ++ ++ ++ ++ Interrupts are handled by reading from ++ /dev/uioX. A blocking ++ read() from ++ /dev/uioX will return as soon as an ++ interrupt occurs. You can also use ++ select() on ++ /dev/uioX to wait for an interrupt. The ++ integer value read from /dev/uioX ++ represents the total interrupt count. You can use this number ++ to figure out if you missed some interrupts. ++ ++ ++ ++ To handle interrupts properly, your custom kernel module can ++ provide its own interrupt handler. It will automatically be ++ called by the built-in handler. ++ ++ ++ ++ For cards that don't generate interrupts but need to be ++ polled, there is the possibility to set up a timer that ++ triggers the interrupt handler at configurable time intervals. ++ See drivers/uio/uio_dummy.c for an ++ example of this technique. ++ ++ ++ ++ Each driver provides attributes that are used to read or write ++ variables. These attributes are accessible through sysfs ++ files. A custom kernel driver module can add its own ++ attributes to the device owned by the uio driver, but not added ++ to the UIO device itself at this time. This might change in the ++ future if it would be found to be useful. ++ ++ ++ ++ The following standard attributes are provided by the UIO ++ framework: ++ ++ ++ ++ ++ name: The name of your device. It is ++ recommended to use the name of your kernel module for this. ++ ++ ++ ++ ++ version: A version string defined by your ++ driver. This allows the user space part of your driver to deal ++ with different versions of the kernel module. ++ ++ ++ ++ ++ event: The total number of interrupts ++ handled by the driver since the last time the device node was ++ read. ++ ++ ++ ++ ++ These attributes appear under the ++ /sys/class/uio/uioX directory. Please ++ note that this directory might be a symlink, and not a real ++ directory. Any userspace code that accesses it must be able ++ to handle this. ++ ++ ++ Each UIO device can make one or more memory regions available for ++ memory mapping. This is necessary because some industrial I/O cards ++ require access to more than one PCI memory region in a driver. ++ ++ ++ Each mapping has its own directory in sysfs, the first mapping ++ appears as /sys/class/uio/uioX/maps/map0/. ++ Subsequent mappings create directories map1/, ++ map2/, and so on. These directories will only ++ appear if the size of the mapping is not 0. ++ ++ ++ Each mapX/ directory contains two read-only files ++ that show start address and size of the memory: ++ ++ ++ ++ ++ addr: The address of memory that can be mapped. ++ ++ ++ ++ ++ size: The size, in bytes, of the memory ++ pointed to by addr. ++ ++ ++ ++ ++ ++ From userspace, the different mappings are distinguished by adjusting ++ the offset parameter of the ++ mmap() call. To map the memory of mapping N, you ++ have to use N times the page size as your offset: ++ ++ ++offset = N * getpagesize(); ++ ++ ++ ++ ++ ++ ++ ++Using uio_dummy ++ ++ Well, there is no real use for uio_dummy. Its only purpose is ++ to test most parts of the UIO system (everything except ++ hardware interrupts), and to serve as an example for the ++ kernel module that you will have to write yourself. ++ ++ ++ ++What uio_dummy does ++ ++ The kernel module uio_dummy.ko creates a ++ device that uses a timer to generate periodic interrupts. The ++ interrupt handler does nothing but increment a counter. The ++ driver adds two custom attributes, count ++ and freq, that appear under ++ /sys/devices/platform/uio_dummy/. ++ ++ ++ ++ The attribute count can be read and ++ written. The associated file ++ /sys/devices/platform/uio_dummy/count ++ appears as a normal text file and contains the total number of ++ timer interrupts. If you look at it (e.g. using ++ cat), you'll notice it is slowly counting ++ up. ++ ++ ++ ++ The attribute freq can be read and written. ++ The content of ++ /sys/devices/platform/uio_dummy/freq ++ represents the number of system timer ticks between two timer ++ interrupts. The default value of freq is ++ the value of the kernel variable HZ, which ++ gives you an interval of one second. Lower values will ++ increase the frequency. Try the following: ++ ++ ++cd /sys/devices/platform/uio_dummy/ ++echo 100 > freq ++ ++ ++ Use cat count to see how the interrupt ++ frequency changes. ++ ++ ++ ++ ++ ++ ++Writing your own kernel module ++ ++ Please have a look at uio_dummy.c as an ++ example. The following paragraphs explain the different ++ sections of this file. ++ ++ ++ ++struct uio_info ++ ++ This structure tells the framework the details of your driver, ++ Some of the members are required, others are optional. ++ ++ ++ ++ ++char *name: Required. The name of your driver as ++it will appear in sysfs. I recommend using the name of your module for this. ++ ++ ++ ++char *version: Required. This string appears in ++/sys/class/uio/uioX/version. ++ ++ ++ ++struct uio_mem mem[ MAX_UIO_MAPS ]: Required if you ++have memory that can be mapped with mmap(). For each ++mapping you need to fill one of the uio_mem structures. ++See the description below for details. ++ ++ ++ ++long irq: Required. If your hardware generates an ++interrupt, it's your modules task to determine the irq number during ++initialization. If you don't have a hardware generated interrupt but ++want to trigger the interrupt handler in some other way, set ++irq to UIO_IRQ_CUSTOM. The ++uio_dummy module does this as it triggers the event mechanism in a timer ++routine. If you had no interrupt at all, you could set ++irq to UIO_IRQ_NONE, though this ++rarely makes sense. ++ ++ ++ ++unsigned long irq_flags: Required if you've set ++irq to a hardware interrupt number. The flags given ++here will be used in the call to request_irq(). ++ ++ ++ ++int (*mmap)(struct uio_info *info, struct vm_area_struct ++*vma): Optional. If you need a special ++mmap() function, you can set it here. If this ++pointer is not NULL, your mmap() will be called ++instead of the built-in one. ++ ++ ++ ++int (*open)(struct uio_info *info, struct inode *inode) ++: Optional. You might want to have your own ++open(), e.g. to enable interrupts only when your ++device is actually used. ++ ++ ++ ++int (*release)(struct uio_info *info, struct inode *inode) ++: Optional. If you define your own ++open(), you will probably also want a custom ++release() function. ++ ++ ++ ++ ++Usually, your device will have one or more memory regions that can be mapped ++to user space. For each region, you have to set up a ++struct uio_mem in the mem[] array. ++Here's a description of the fields of struct uio_mem: ++ ++ ++ ++ ++int memtype: Required if the mapping is used. Set this to ++UIO_MEM_PHYS if you you have physical memory on your ++card to be mapped. Use UIO_MEM_LOGICAL for logical ++memory (e.g. allocated with kmalloc()). There's also ++UIO_MEM_VIRTUAL for virtual memory. ++ ++ ++ ++unsigned long addr: Required if the mapping is used. ++Fill in the address of your memory block. This address is the one that ++appears in sysfs. ++ ++ ++ ++unsigned long size: Fill in the size of the ++memory block that addr points to. If size ++is zero, the mapping is considered unused. Note that you ++must initialize size with zero for ++all unused mappings. ++ ++ ++ ++void *internal_addr: If you have to access this memory ++region from within your kernel module, you will want to map it internally by ++using something like ioremap(). Addresses ++returned by this function cannot be mapped to user space, so you must not ++store it in addr. Use internal_addr ++instead to remember such an address. ++ ++ ++ ++ ++Please do not touch the kobj element of ++struct uio_mem! It is used by the UIO framework ++to set up sysfs files for this mapping. Simply leave it alone. ++ ++ ++ ++ ++Adding an interrupt handler ++ ++ What you need to do in your interrupt handler depends on your ++ hardware and on how you want to handle it. You should try to ++ keep the amount of code in your kernel interrupt handler low. ++ If your hardware requires no action that you ++ have to perform after each interrupt, ++ then your handler can be empty. If, on the other ++ hand, your hardware needs some action to ++ be performed after each interrupt, then you ++ must do it in your kernel module. Note ++ that you cannot rely on the userspace part of your driver. Your ++ userspace program can terminate at any time, possibly leaving ++ your hardware in a state where proper interrupt handling is ++ still required. ++ ++ ++ ++ There might also be applications where you want to read data ++ from your hardware at each interrupt and buffer it in a piece ++ of kernel memory you've allocated for that purpose. With this ++ technique you could avoid loss of data if your userspace ++ program misses an interrupt. ++ ++ ++ ++ A note on shared interrupts: Your driver should support ++ interrupt sharing whenever this is possible. It is possible if ++ and only if your driver can detect whether your hardware has ++ triggered the interrupt or not. This is usually done by looking ++ at an interrupt status register. If your driver sees that the ++ IRQ bit is actually set, it will perform its actions, and the ++ handler returns IRQ_HANDLED. If the driver detects that it was ++ not your hardware that caused the interrupt, it will do nothing ++ and return IRQ_NONE, allowing the kernel to call the next ++ possible interrupt handler. ++ ++ ++ ++ If you decide not to support shared interrupts, your card ++ won't work in computers with no free interrupts. As this ++ frequently happens on the PC platform, you can save yourself a ++ lot of trouble by supporting interrupt sharing. ++ ++ ++ ++ ++ ++ ++ ++Writing a driver in userspace ++ ++ Once you have a working kernel module for your hardware, you can ++ write the userspace part of your driver. You don't need any special ++ libraries, your driver can be written in any reasonable language, ++ you can use floating point numbers and so on. In short, you can ++ use all the tools and libraries you'd normally use for writing a ++ userspace application. ++ ++ ++ ++Getting information about your UIO device ++ ++ Information about all UIO devices is available in sysfs. The ++ first thing you should do in your driver is check ++ name and version to ++ make sure your talking to the right device and that its kernel ++ driver has the version you expect. ++ ++ ++ You should also make sure that the memory mapping you need ++ exists and has the size you expect. ++ ++ ++ There is a tool called lsuio that lists ++ UIO devices and their attributes. It is available here: ++ ++ ++ ++ http://www.osadl.org/projects/downloads/UIO/user/ ++ ++ ++ With lsuio you can quickly check if your ++ kernel module is loaded and which attributes it exports. ++ Have a look at the manpage for details. ++ ++ ++ The source code of lsuio can serve as an ++ example for getting information about an UIO device. ++ The file uio_helper.c contains a lot of ++ functions you could use in your userspace driver code. ++ ++ ++ ++ ++mmap() device memory ++ ++ After you made sure you've got the right device with the ++ memory mappings you need, all you have to do is to call ++ mmap() to map the device's memory ++ to userspace. ++ ++ ++ The parameter offset of the ++ mmap() call has a special meaning ++ for UIO devices: It is used to select which mapping of ++ your device you want to map. To map the memory of ++ mapping N, you have to use N times the page size as ++ your offset: ++ ++ ++ offset = N * getpagesize(); ++ ++ ++ N starts from zero, so if you've got only one memory ++ range to map, set offset = 0. ++ A drawback of this technique is that memory is always ++ mapped beginning with its start address. ++ ++ ++ ++ ++Waiting for interrupts ++ ++ After you successfully mapped your devices memory, you ++ can access it like an ordinary array. Usually, you will ++ perform some initialization. After that, your hardware ++ starts working and will generate an interrupt as soon ++ as it's finished, has some data available, or needs your ++ attention because an error occured. ++ ++ ++ /dev/uioX is a read-only file. A ++ read() will always block until an ++ interrupt occurs. There is only one legal value for the ++ count parameter of ++ read(), and that is the size of a ++ signed 32 bit integer (4). Any other value for ++ count causes read() ++ to fail. The signed 32 bit integer read is the interrupt ++ count of your device. If the value is one more than the value ++ you read the last time, everything is OK. If the difference ++ is greater than one, you missed interrupts. ++ ++ ++ You can also use select() on ++ /dev/uioX. ++ ++ ++ ++ ++ ++ ++Further information ++ ++ ++ ++ OSADL homepage. ++ ++ ++ ++ Linutronix homepage. ++ ++ ++ ++ ++
+diff -Nurp linux-2.6.22/Documentation/HOWTO linux-2.6-netns/Documentation/HOWTO +--- linux-2.6.22/Documentation/HOWTO 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/HOWTO 2007-12-03 23:14:12.000000000 -0500 +@@ -249,6 +249,9 @@ process is as follows: + release a new -rc kernel every week. + - Process continues until the kernel is considered "ready", the + process should last around 6 weeks. ++ - A list of known regressions present in each -rc release is ++ tracked at the following URI: ++ http://kernelnewbies.org/known_regressions + + It is worth mentioning what Andrew Morton wrote on the linux-kernel + mailing list about kernel releases: +diff -Nurp linux-2.6.22/Documentation/RCU/checklist.txt linux-2.6-netns/Documentation/RCU/checklist.txt +--- linux-2.6.22/Documentation/RCU/checklist.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/RCU/checklist.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -222,7 +222,15 @@ over a rather long period of time, but i + deadlock as soon as the RCU callback happens to interrupt that + acquisition's critical section. + +-13. SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu()) ++13. RCU callbacks can be and are executed in parallel. In many cases, ++ the callback code simply wrappers around kfree(), so that this ++ is not an issue (or, more accurately, to the extent that it is ++ an issue, the memory-allocator locking handles it). However, ++ if the callbacks do manipulate a shared data structure, they ++ must use whatever locking or other synchronization is required ++ to safely access and/or modify that data structure. ++ ++14. SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu()) + may only be invoked from process context. Unlike other forms of + RCU, it -is- permissible to block in an SRCU read-side critical + section (demarked by srcu_read_lock() and srcu_read_unlock()), +diff -Nurp linux-2.6.22/Documentation/SubmitChecklist linux-2.6-netns/Documentation/SubmitChecklist +--- linux-2.6.22/Documentation/SubmitChecklist 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/SubmitChecklist 2007-12-03 23:14:12.000000000 -0500 +@@ -1,4 +1,4 @@ +-Linux Kernel patch sumbittal checklist ++Linux Kernel patch submission checklist + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Here are some basic things that developers should do if they want to see their +@@ -9,7 +9,6 @@ Documentation/SubmittingPatches and else + kernel patches. + + +- + 1: Builds cleanly with applicable or modified CONFIG options =y, =m, and + =n. No gcc warnings/errors, no linker warnings/errors. + +diff -Nurp linux-2.6.22/Documentation/SubmittingPatches linux-2.6-netns/Documentation/SubmittingPatches +--- linux-2.6.22/Documentation/SubmittingPatches 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/SubmittingPatches 2007-12-03 23:14:12.000000000 -0500 +@@ -464,9 +464,25 @@ section Linus Computer Science 101. + Nuff said. If your code deviates too much from this, it is likely + to be rejected without further review, and without comment. + ++Once significant exception is when moving code from one file to ++another in this case you should not modify the moved code at all in ++the same patch which moves it. This clearly delineates the act of ++moving the code and your changes. This greatly aids review of the ++actual differences and allows tools to better track the history of ++the code itself. ++ + Check your patches with the patch style checker prior to submission +-(scripts/checkpatch.pl). You should be able to justify all +-violations that remain in your patch. ++(scripts/checkpatch.pl). The style checker should be viewed as ++a guide not as the final word. If your code looks better with ++a violation then its probably best left alone. ++ ++The checker reports at three levels: ++ - ERROR: things that are very likely to be wrong ++ - WARNING: things requiring careful review ++ - CHECK: things requiring thought ++ ++You should be able to justify all violations that remain in your ++patch. + + + +diff -Nurp linux-2.6.22/Documentation/accounting/getdelays.c linux-2.6-netns/Documentation/accounting/getdelays.c +--- linux-2.6.22/Documentation/accounting/getdelays.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/accounting/getdelays.c 2007-12-03 23:14:12.000000000 -0500 +@@ -49,6 +49,7 @@ char name[100]; + int dbg; + int print_delays; + int print_io_accounting; ++int print_task_context_switch_counts; + __u64 stime, utime; + + #define PRINTF(fmt, arg...) { \ +@@ -195,7 +196,7 @@ void print_delayacct(struct taskstats *t + "IO %15s%15s\n" + " %15llu%15llu\n" + "MEM %15s%15s\n" +- " %15llu%15llu\n\n", ++ " %15llu%15llu\n" + "count", "real total", "virtual total", "delay total", + t->cpu_count, t->cpu_run_real_total, t->cpu_run_virtual_total, + t->cpu_delay_total, +@@ -204,6 +205,14 @@ void print_delayacct(struct taskstats *t + "count", "delay total", t->swapin_count, t->swapin_delay_total); + } + ++void task_context_switch_counts(struct taskstats *t) ++{ ++ printf("\n\nTask %15s%15s\n" ++ " %15lu%15lu\n", ++ "voluntary", "nonvoluntary", ++ t->nvcsw, t->nivcsw); ++} ++ + void print_ioacct(struct taskstats *t) + { + printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n", +@@ -235,7 +244,7 @@ int main(int argc, char *argv[]) + struct msgtemplate msg; + + while (1) { +- c = getopt(argc, argv, "diw:r:m:t:p:vl"); ++ c = getopt(argc, argv, "qdiw:r:m:t:p:vl"); + if (c < 0) + break; + +@@ -248,6 +257,10 @@ int main(int argc, char *argv[]) + printf("printing IO accounting\n"); + print_io_accounting = 1; + break; ++ case 'q': ++ printf("printing task/process context switch rates\n"); ++ print_task_context_switch_counts = 1; ++ break; + case 'w': + logfile = strdup(optarg); + printf("write to file %s\n", logfile); +@@ -389,6 +402,8 @@ int main(int argc, char *argv[]) + print_delayacct((struct taskstats *) NLA_DATA(na)); + if (print_io_accounting) + print_ioacct((struct taskstats *) NLA_DATA(na)); ++ if (print_task_context_switch_counts) ++ task_context_switch_counts((struct taskstats *) NLA_DATA(na)); + if (fd) { + if (write(fd, NLA_DATA(na), na->nla_len) < 0) { + err(1,"write error\n"); +diff -Nurp linux-2.6.22/Documentation/accounting/taskstats-struct.txt linux-2.6-netns/Documentation/accounting/taskstats-struct.txt +--- linux-2.6.22/Documentation/accounting/taskstats-struct.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/accounting/taskstats-struct.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -22,6 +22,8 @@ There are three different groups of fiel + /* Extended accounting fields end */ + Their values are collected if CONFIG_TASK_XACCT is set. + ++4) Per-task and per-thread context switch count statistics ++ + Future extension should add fields to the end of the taskstats struct, and + should not change the relative position of each field within the struct. + +@@ -158,4 +160,8 @@ struct taskstats { + + /* Extended accounting fields end */ + ++4) Per-task and per-thread statistics ++ __u64 nvcsw; /* Context voluntary switch counter */ ++ __u64 nivcsw; /* Context involuntary switch counter */ ++ + } +diff -Nurp linux-2.6.22/Documentation/blackfin/kgdb.txt linux-2.6-netns/Documentation/blackfin/kgdb.txt +--- linux-2.6.22/Documentation/blackfin/kgdb.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/blackfin/kgdb.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,155 @@ ++ A Simple Guide to Configure KGDB ++ ++ Sonic Zhang ++ Aug. 24th 2006 ++ ++ ++This KGDB patch enables the kernel developer to do source level debugging on ++the kernel for the Blackfin architecture. The debugging works over either the ++ethernet interface or one of the uarts. Both software breakpoints and ++hardware breakpoints are supported in this version. ++http://docs.blackfin.uclinux.org/doku.php?id=kgdb ++ ++ ++2 known issues: ++1. This bug: ++ http://blackfin.uclinux.org/tracker/index.php?func=detail&aid=544&group_id=18&atid=145 ++ The GDB client for Blackfin uClinux causes incorrect values of local ++ variables to be displayed when the user breaks the running of kernel in GDB. ++2. Because of a hardware bug in Blackfin 533 v1.0.3: ++ 05000067 - Watchpoints (Hardware Breakpoints) are not supported ++ Hardware breakpoints cannot be set properly. ++ ++ ++Debug over Ethernet: ++ ++1. Compile and install the cross platform version of gdb for blackfin, which ++ can be found at $(BINROOT)/bfin-elf-gdb. ++ ++2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under ++ "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb". ++ With this selected, option "Full Symbolic/Source Debugging support" and ++ "Compile the kernel with frame pointers" are also selected. ++ ++3. Select option "KGDB: connect over (Ethernet)". Add "kgdboe=@target-IP/,@host-IP/" to ++ the option "Compiled-in Kernel Boot Parameter" under "Kernel hacking". ++ ++4. Connect minicom to the serial port and boot the kernel image. ++ ++5. Configure the IP "/> ifconfig eth0 target-IP" ++ ++6. Start GDB client "bfin-elf-gdb vmlinux". ++ ++7. Connect to the target "(gdb) target remote udp:target-IP:6443". ++ ++8. Set software breakpoint "(gdb) break sys_open". ++ ++9. Continue "(gdb) c". ++ ++10. Run ls in the target console "/> ls". ++ ++11. Breakpoint hits. "Breakpoint 1: sys_open(..." ++ ++12. Display local variables and function paramters. ++ (*) This operation gives wrong results, see known issue 1. ++ ++13. Single stepping "(gdb) si". ++ ++14. Remove breakpoint 1. "(gdb) del 1" ++ ++15. Set hardware breakpoint "(gdb) hbreak sys_open". ++ ++16. Continue "(gdb) c". ++ ++17. Run ls in the target console "/> ls". ++ ++18. Hardware breakpoint hits. "Breakpoint 1: sys_open(...". ++ (*) This hardware breakpoint will not be hit, see known issue 2. ++ ++19. Continue "(gdb) c". ++ ++20. Interrupt the target in GDB "Ctrl+C". ++ ++21. Detach from the target "(gdb) detach". ++ ++22. Exit GDB "(gdb) quit". ++ ++ ++Debug over the UART: ++ ++1. Compile and install the cross platform version of gdb for blackfin, which ++ can be found at $(BINROOT)/bfin-elf-gdb. ++ ++2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under ++ "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb". ++ With this selected, option "Full Symbolic/Source Debugging support" and ++ "Compile the kernel with frame pointers" are also selected. ++ ++3. Select option "KGDB: connect over (UART)". Set "KGDB: UART port number" to be ++ a different one from the console. Don't forget to change the mode of ++ blackfin serial driver to PIO. Otherwise kgdb works incorrectly on UART. ++ ++4. If you want connect to kgdb when the kernel boots, enable ++ "KGDB: Wait for gdb connection early" ++ ++5. Compile kernel. ++ ++6. Connect minicom to the serial port of the console and boot the kernel image. ++ ++7. Start GDB client "bfin-elf-gdb vmlinux". ++ ++8. Set the baud rate in GDB "(gdb) set remotebaud 57600". ++ ++9. Connect to the target on the second serial port "(gdb) target remote /dev/ttyS1". ++ ++10. Set software breakpoint "(gdb) break sys_open". ++ ++11. Continue "(gdb) c". ++ ++12. Run ls in the target console "/> ls". ++ ++13. A breakpoint is hit. "Breakpoint 1: sys_open(..." ++ ++14. All other operations are the same as that in KGDB over Ethernet. ++ ++ ++Debug over the same UART as console: ++ ++1. Compile and install the cross platform version of gdb for blackfin, which ++ can be found at $(BINROOT)/bfin-elf-gdb. ++ ++2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under ++ "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb". ++ With this selected, option "Full Symbolic/Source Debugging support" and ++ "Compile the kernel with frame pointers" are also selected. ++ ++3. Select option "KGDB: connect over UART". Set "KGDB: UART port number" to console. ++ Don't forget to change the mode of blackfin serial driver to PIO. ++ Otherwise kgdb works incorrectly on UART. ++ ++4. If you want connect to kgdb when the kernel boots, enable ++ "KGDB: Wait for gdb connection early" ++ ++5. Connect minicom to the serial port and boot the kernel image. ++ ++6. (Optional) Ask target to wait for gdb connection by entering Ctrl+A. In minicom, you should enter Ctrl+A+A. ++ ++7. Start GDB client "bfin-elf-gdb vmlinux". ++ ++8. Set the baud rate in GDB "(gdb) set remotebaud 57600". ++ ++9. Connect to the target "(gdb) target remote /dev/ttyS0". ++ ++10. Set software breakpoint "(gdb) break sys_open". ++ ++11. Continue "(gdb) c". Then enter Ctrl+C twice to stop GDB connection. ++ ++12. Run ls in the target console "/> ls". Dummy string can be seen on the console. ++ ++13. Then connect the gdb to target again. "(gdb) target remote /dev/ttyS0". ++ Now you will find a breakpoint is hit. "Breakpoint 1: sys_open(..." ++ ++14. All other operations are the same as that in KGDB over Ethernet. The only ++ difference is that after continue command in GDB, please stop GDB ++ connection by 2 "Ctrl+C"s and connect again after breakpoints are hit or ++ Ctrl+A is entered. +diff -Nurp linux-2.6.22/Documentation/block/barrier.txt linux-2.6-netns/Documentation/block/barrier.txt +--- linux-2.6.22/Documentation/block/barrier.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/block/barrier.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -82,23 +82,12 @@ including draining and flushing. + typedef void (prepare_flush_fn)(request_queue_t *q, struct request *rq); + + int blk_queue_ordered(request_queue_t *q, unsigned ordered, +- prepare_flush_fn *prepare_flush_fn, +- unsigned gfp_mask); +- +-int blk_queue_ordered_locked(request_queue_t *q, unsigned ordered, +- prepare_flush_fn *prepare_flush_fn, +- unsigned gfp_mask); +- +-The only difference between the two functions is whether or not the +-caller is holding q->queue_lock on entry. The latter expects the +-caller is holding the lock. ++ prepare_flush_fn *prepare_flush_fn); + + @q : the queue in question + @ordered : the ordered mode the driver/device supports + @prepare_flush_fn : this function should prepare @rq such that it + flushes cache to physical medium when executed +-@gfp_mask : gfp_mask used when allocating data structures +- for ordered processing + + For example, SCSI disk driver's prepare_flush_fn looks like the + following. +@@ -106,9 +95,10 @@ following. + static void sd_prepare_flush(request_queue_t *q, struct request *rq) + { + memset(rq->cmd, 0, sizeof(rq->cmd)); +- rq->flags |= REQ_BLOCK_PC; ++ rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->timeout = SD_TIMEOUT; + rq->cmd[0] = SYNCHRONIZE_CACHE; ++ rq->cmd_len = 10; + } + + The following seven ordered modes are supported. The following table +diff -Nurp linux-2.6.22/Documentation/cachetlb.txt linux-2.6-netns/Documentation/cachetlb.txt +--- linux-2.6.22/Documentation/cachetlb.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cachetlb.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -253,7 +253,7 @@ Here are the routines, one by one: + + The first of these two routines is invoked after map_vm_area() + has installed the page table entries. The second is invoked +- before unmap_vm_area() deletes the page table entries. ++ before unmap_kernel_range() deletes the page table entries. + + There exists another whole class of cpu cache issues which currently + require a whole different set of interfaces to handle properly. +diff -Nurp linux-2.6.22/Documentation/cdrom/00-INDEX linux-2.6-netns/Documentation/cdrom/00-INDEX +--- linux-2.6.22/Documentation/cdrom/00-INDEX 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/00-INDEX 2007-12-03 23:06:33.000000000 -0500 +@@ -2,32 +2,10 @@ + - this file (info on CD-ROMs and Linux) + Makefile + - only used to generate TeX output from the documentation. +-aztcd +- - info on Aztech/Orchid/Okano/Wearnes/Conrad/CyCDROM driver. + cdrom-standard.tex + - LaTeX document on standardizing the CD-ROM programming interface. +-cdu31a +- - info on the Sony CDU31A/CDU33A CD-ROM driver. +-cm206 +- - info on the Philips/LMS cm206/cm260 CD-ROM driver. +-gscd +- - info on the Goldstar R420 CD-ROM driver. + ide-cd + - info on setting up and using ATAPI (aka IDE) CD-ROMs. +-isp16 +- - info on the CD-ROM interface on ISP16, MAD16 or Mozart sound card. +-mcd +- - info on limitations of standard Mitsumi CD-ROM driver. +-mcdx +- - info on improved Mitsumi CD-ROM driver. +-optcd +- - info on the Optics Storage 8000 AT CD-ROM driver + packet-writing.txt + - Info on the CDRW packet writing module +-sbpcd +- - info on the SoundBlaster/Panasonic CD-ROM interface driver. +-sjcd +- - info on the SANYO CDR-H94A CD-ROM interface driver. +-sonycd535 +- - info on the Sony CDU-535 (and 531) CD-ROM driver. + +diff -Nurp linux-2.6.22/Documentation/cdrom/aztcd linux-2.6-netns/Documentation/cdrom/aztcd +--- linux-2.6.22/Documentation/cdrom/aztcd 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/aztcd 1969-12-31 19:00:00.000000000 -0500 +@@ -1,822 +0,0 @@ +-$Id: README.aztcd,v 2.60 1997/11/29 09:51:25 root Exp root $ +- Readme-File Documentation/cdrom/aztcd +- for +- AZTECH CD-ROM CDA268-01A, ORCHID CD-3110, +- OKANO/WEARNES CDD110, CONRAD TXC, CyCDROM CR520, CR540 +- CD-ROM Drives +- Version 2.6 and newer +- (for other drives see 6.-8.) +- +-NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE +- A PROPRIETARY INTERFACE (implemented on a sound card or on an +- ISA-AT-bus card). +- IT WILL DEFINITELY NOT WORK WITH CD-ROM DRIVES WITH *IDE*-INTERFACE, +- such as the Aztech CDA269-031SE !!! (The only known exceptions are +- 'faked' IDE drives like the CyCDROM CR520ie which work with aztcd +- under certain conditions, see 7.). IF YOU'RE USING A CD-ROM DRIVE +- WITH IDE-INTERFACE, SOMETIMES ALSO CALLED ATAPI-COMPATIBLE, PLEASE +- USE THE ide-cd.c DRIVER, WRITTEN BY MARK LORD AND SCOTT SNYDER ! +- THE STANDARD-KERNEL 1.2.x NOW ALSO SUPPORTS IDE-CDROM-DRIVES, SEE THE +- HARDDISK (!) SECTION OF make config, WHEN COMPILING A NEW KERNEL!!! +----------------------------------------------------------------------------- +- +-Contents of this file: +- 1. NOTE +- 2. INSTALLATION +- 3. CONFIGURING YOUR KERNEL +- 4. RECOMPILING YOUR KERNEL +- 4.1 AZTCD AS A RUN-TIME LOADABLE MODULE +- 4.2 CDROM CONNECTED TO A SOUNDCARD +- 5. KNOWN PROBLEMS, FUTURE DEVELOPMENTS +- 5.1 MULTISESSION SUPPORT +- 5.2 STATUS RECOGNITION +- 5.3 DOSEMU's CDROM SUPPORT +- 6. BUG REPORTS +- 7. OTHER DRIVES +- 8. IF YOU DON'T SUCCEED ... DEBUGGING +- 9. TECHNICAL HISTORY OF THE DRIVER +- 10. ACKNOWLEDGMENTS +- 11. PROGRAMMING ADD ONS: CDPLAY.C +- APPENDIX: Source code of cdplay.c +----------------------------------------------------------------------------- +- +-1. NOTE +-This software has been successfully in alpha and beta test and is part of +-the standard kernel since kernel 1.1.8x since December 1994. It works with +-AZTECH CDA268-01A, ORCHID CDS-3110, ORCHID/WEARNES CDD110 and CONRAD TXC +-(Nr.99 31 23 -series 04) and has proven to be stable with kernel +-versions 1.0.9 and newer. But with any software there still may be bugs in it. +-So if you encounter problems, you are invited to help us improve this software. +-Please send me a detailed bug report (see chapter BUG REPORTS). You are also +-invited in helping us to increase the number of drives, which are supported. +- +-Please read the README-files carefully and always keep a backup copy of your +-old kernel, in order to reboot if something goes wrong! +- +-2. INSTALLATION +-The driver consists of a header file 'aztcd.h', which normally should reside +-in /usr/src/linux/drivers/cdrom and the source code 'aztcd.c', which normally +-resides in the same place. It uses /dev/aztcd (/dev/aztcd0 in some distri- +-butions), which must be a valid block device with major number 29 and reside +-in directory /dev. To mount a CD-ROM, your kernel needs to have the ISO9660- +-filesystem support included. +- +-PLEASE NOTE: aztcd.c has been developed in parallel to the linux kernel, +-which had and is having many major and minor changes which are not backward +-compatible. Quite definitely aztcd.c version 1.80 and newer will NOT work +-in kernels older than 1.3.33. So please always use the most recent version +-of aztcd.c with the appropriate linux-kernel. +- +-3. CONFIGURING YOUR KERNEL +-If your kernel is already configured for using the AZTECH driver you will +-see the following message while Linux boots: +- Aztech CD-ROM Init: DriverVersion= BaseAddress= +- Aztech CD-ROM Init: FirmwareVersion=>> +- Aztech CD-ROM Init: detected +- Aztech CD-ROM Init: End +-If the message looks different and you are sure to have a supported drive, +-it may have a different base address. The Aztech driver does look for the +-CD-ROM drive at the base address specified in aztcd.h at compile time. This +-address can be overwritten by boot parameter aztcd=....You should reboot and +-start Linux with boot parameter aztcd=, e.g. aztcd=0x320. If +-you do not know the base address, start your PC with DOS and look at the boot +-message of your CD-ROM's DOS driver. If that still does not help, use boot +-parameter aztcd=,0x79 , this tells aztcd to try a little harder. +-aztcd may be configured to use autoprobing the base address by recompiling +-it (see chapter 4.). +- +-If the message looks correct, as user 'root' you should be able to mount the +-drive by +- mount -t iso9660 -r /dev/aztcd0 /mnt +-and use it as any other filesystem. (If this does not work, check if +-/dev/aztcd0 and /mnt do exist and create them, if necessary by doing +- mknod /dev/aztcd0 b 29 0 +- mkdir /mnt +- +-If you still get a different message while Linux boots or when you get the +-message, that the ISO9660-filesystem is not supported by your kernel, when +-you try to mount the CD-ROM drive, you have to recompile your kernel. +- +-If you do *not* have an Aztech/Orchid/Okano/Wearnes/TXC drive and want to +-bypass drive detection during Linux boot up, start with boot parameter aztcd=0. +- +-Most distributions nowadays do contain a boot disk image containing aztcd. +-Please note, that this driver will not work with IDE/ATAPI drives! With these +-you must use ide-cd.c instead. +- +-4. RECOMPILING YOUR KERNEL +-If your kernel is not yet configured for the AZTECH driver and the ISO9660- +-filesystem, you have to recompile your kernel: +- +-- Edit aztcd.h to set the I/O-address to your I/O-Base address (AZT_BASE_ADDR), +- the driver does not use interrupts or DMA, so if you are using an AZTECH +- CD268, an ORCHID CD-3110 or ORCHID/WEARNES CDD110 that's the only item you +- have to set up. If you have a soundcard, read chapter 4.2. +- Users of other drives should read chapter OTHER DRIVES of this file. +- You also can configure that address by kernel boot parameter aztcd=... +-- aztcd may be configured to use autoprobing the base address by setting +- AZT_BASE_ADDR to '-1'. In that case aztcd probes the addresses listed +- under AZT_BASE_AUTO. But please remember, that autoprobing always may +- incorrectly influence other hardware components too! +-- There are some other points, which may be configured, e.g. auto-eject the +- CD when unmounting a drive, tray locking etc., see aztcd.h for details. +-- If you're using a linux kernel version prior to 2.1.0, in aztcd.h +- uncomment the line '#define AZT_KERNEL_PRIOR_2_1' +-- Build a new kernel, configure it for 'Aztech/Orchid/Okano/Wearnes support' +- (if you want aztcd to be part of the kernel). Do not configure it for +- 'Aztech... support', if you want to use aztcd as a run time loadable module. +- But in any case you must have the ISO9660-filesystem included in your +- kernel. +-- Activate the new kernel, normally this is done by running LILO (don't for- +- get to configure it before and to keep a copy of your old kernel in case +- something goes wrong!). +-- Reboot +-- If you've included aztcd in your kernel, you now should see during boot +- some messages like +- Aztech CD-ROM Init: DriverVersion= BaseAddress= +- Aztech CD-ROM Init: FirmwareVersion= +- Aztech CD-ROM Init: detected +- Aztech CD-ROM Init: End +-- If you have not included aztcd in your kernel, but want to load aztcd as a +- run time loadable module see 4.1. +-- If the message looks correct, as user 'root' you should be able to mount +- the drive by +- mount -t iso9660 -r /dev/aztcd0 /mnt +- and use it as any other filesystem. (If this does not work, check if +- /dev/aztcd0 and /mnt do exist and create them, if necessary by doing +- mknod /dev/aztcd0 b 29 0 +- mkdir /mnt +-- If this still does not help, see chapters OTHER DRIVES and DEBUGGING. +- +-4.1 AZTCD AS A RUN-TIME LOADABLE MODULE +-If you do not need aztcd permanently, you can also load and remove the driver +-during runtime via insmod and rmmod. To build aztcd as a loadable module you +-must configure your kernel for AZTECH module support (answer 'm' when con- +-figuring the kernel). Anyhow, you may run into problems, if the version of +-your boot kernel is not the same than the source kernel version, from which +-you create the modules. So rebuild your kernel, if necessary. +- +-Now edit the base address of your AZTECH interface card in +-/usr/src/linux/drivers/cdrom/aztcd.h to the appropriate value. +-aztcd may be configured to use autoprobing the base address by setting +-AZT_BASE_ADDR to '-1'. In that case aztcd probes the addresses listed +-under AZT_BASE_AUTO. But please remember, that autoprobing always may +-incorrectly influence other hardware components too! +-There are also some special features which may be configured, e.g. +-auto-eject a CD when unmounting the drive etc; see aztcd.h for details. +-Then change to /usr/src/linux and do a +- make modules +- make modules_install +-After that you can run-time load the driver via +- insmod /lib/modules/X.X.X/misc/aztcd.o +-and remove it via rmmod aztcd. +-If you did not set the correct base address in aztcd.h, you can also supply the +-base address when loading the driver via +- insmod /lib/modules/X.X.X/misc/aztcd.o aztcd= +-Again specifying aztcd=-1 will cause autoprobing. +-If you do not have the iso9660-filesystem in your boot kernel, you also have +-to load it before you can mount the CDROM: +- insmod /lib/modules/X.X.X/fs/isofs.o +-The mount procedure works as described in 4. above. +-(In all commands 'X.X.X' is the current linux kernel version number) +- +-4.2 CDROM CONNECTED TO A SOUNDCARD +-Most soundcards do have a bus interface to the CDROM-drive. In many cases +-this soundcard needs to be configured, before the CDROM can be used. This +-configuration procedure consists of writing some kind of initialization +-data to the soundcard registers. The AZTECH-CDROM driver in the moment does +-only support one type of soundcard (SoundWave32). Users of other soundcards +-should try to boot DOS first and let their DOS drivers initialize the +-soundcard and CDROM, then warm boot (or use loadlin) their PC to start +-Linux. +-Support for the CDROM-interface of SoundWave32-soundcards is directly +-implemented in the AZTECH driver. Please edit linux/drivers/cdrom/aztdc.h, +-uncomment line '#define AZT_SW32' and set the appropriate value for +-AZT_BASE_ADDR and AZT_SW32_BASE_ADDR. This support was tested with an Orchid +-CDS-3110 connected to a SoundWave32. +-If you want your soundcard to be supported, find out, how it needs to be +-configured and mail me (see 6.) the appropriate information. +- +-5. KNOWN PROBLEMS, FUTURE DEVELOPMENTS +-5.1 MULTISESSION SUPPORT +-Multisession support for CD's still is a myth. I implemented and tested a basic +-support for multisession and XA CDs, but I still have not enough CDs and appli- +-cations to test it rigorously. So if you'd like to help me, please contact me +-(Email address see below). As of version 1.4 and newer you can enable the +-multisession support in aztcd.h by setting AZT_MULTISESSION to 1. Doing so +-will cause the ISO9660-filesystem to deal with multisession CDs, ie. redirect +-requests to the Table of Contents (TOC) information from the last session, +-which contains the info of all previous sessions etc.. If you do set +-AZT_MULTISESSION to 0, you can use multisession CDs anyway. In that case the +-drive's firmware will do automatic redirection. For the ISO9660-filesystem any +-multisession CD will then look like a 'normal' single session CD. But never- +-theless the data of all sessions are viewable and accessible. So with practical- +-ly all real world applications you won't notice the difference. But as future +-applications may make use of advanced multisession features, I've started to +-implement the interface for the ISO9660 multisession interface via ioctl +-CDROMMULTISESSION. +- +-5.2 STATUS RECOGNITION +-The drive status recognition does not work correctly in all cases. Changing +-a disk or having the door open, when a drive is already mounted, is detected +-by the Aztech driver itself, but nevertheless causes multiple read attempts +-by the different layers of the ISO9660-filesystem driver, which finally timeout, +-so you have to wait quite a little... But isn't it bad style to change a disk +-in a mounted drive, anyhow ?! +- +-The driver uses busy wait in most cases for the drive handshake (macros +-STEN_LOW and DTEN_LOW). I tested with a 486/DX2 at 66MHz and a Pentium at +-60MHz and 90MHz. Whenever you use a much faster machine you are likely to get +-timeout messages. In that case edit aztcd.h and increase the timeout value +-AZT_TIMEOUT. +- +-For some 'slow' drive commands I implemented waiting with a timer waitqueue +-(macro STEN_LOW_WAIT). If you get this timeout message, you may also edit +-aztcd.h and increase the timeout value AZT_STATUS_DELAY. The waitqueue has +-shown to be a little critical. If you get kernel panic messages, edit aztcd.c +-and substitute STEN_LOW_WAIT by STEN_LOW. Busy waiting with STEN_LOW is more +-stable, but also causes CPU overhead. +- +-5.3 DOSEMU's CD-ROM SUPPORT +-With release 1.20 aztcd was modified to allow access to CD-ROMS when running +-under dosemu-0.60.0 aztcd-versions before 1.20 are most likely to crash +-Linux, when a CD-ROM is accessed under dosemu. This problem has partly been +-fixed, but still when accessing a directory for the first time the system +-might hang for some 30sec. So be patient, when using dosemu's CD-ROM support +-in combination with aztcd :-) ! +-This problem has now (July 1995) been fixed by a modification to dosemu's +-CD-ROM driver. The new version came with dosemu-0.60.2, see dosemu's +-README.CDROM. +- +-6. BUG REPORTS +-Please send detailed bug reports and bug fixes via EMail to +- +- Werner.Zimmermann@fht-esslingen.de +- +-Please include a description of your CD-ROM drive type and interface card, +-the exact firmware message during Linux bootup, the version number of the +-AZTECH-CDROM-driver and the Linux kernel version. Also a description of your +-system's other hardware could be of interest, especially microprocessor type, +-clock frequency, other interface cards such as soundcards, ethernet adapter, +-game cards etc.. +- +-I will try to collect the reports and make the necessary modifications from +-time to time. I may also come back to you directly with some bug fixes and +-ask you to do further testing and debugging. +- +-Editors of CD-ROMs are invited to send a 'cooperation' copy of their +-CD-ROMs to the volunteers, who provided the CD-ROM support for Linux. My +-snail mail address for such 'stuff' is +- Prof. Dr. W. Zimmermann +- Fachhochschule fuer Technik Esslingen +- Fachbereich IT +- Flandernstrasse 101 +- D-73732 Esslingen +- Germany +- +- +-7. OTHER DRIVES +-The following drives ORCHID CDS3110, OKANO CDD110, WEARNES CDD110 and Conrad +-TXC Nr. 993123-series 04 nearly look the same as AZTECH CDA268-01A, especially +-they seem to use the same command codes. So it was quite simple to make the +-AZTECH driver work with these drives. +- +-Unfortunately I do not have any of these drives available, so I couldn't test +-it myself. In some installations, it seems necessary to initialize the drive +-with the DOS driver before (especially if combined with a sound card) and then +-do a warm boot (CTRL-ALT-RESET) or start Linux from DOS, e.g. with 'loadlin'. +- +-If you do not succeed, read chapter DEBUGGING. Thanks in advance! +- +-Sorry for the inconvenience, but it is difficult to develop for hardware, +-which you don't have available for testing. So if you like, please help us. +- +-If you do have a CyCDROM CR520ie thanks to Hilmar Berger's help your chances +-are good, that it will work with aztcd. The CR520ie is sold as an IDE-drive +-and really is connected to the IDE interface (primary at 0x1F0 or secondary +-at 0x170, configured as slave, not as master). Nevertheless it is not ATAPI +-compatible but still uses Aztech's command codes. +- +- +-8. DEBUGGING : IF YOU DON'T SUCCEED, TRY THE FOLLOWING +--reread the complete README file +--make sure, that your drive is hardware configured for +- transfer mode: polled +- IRQ: not used +- DMA: not used +- Base Address: something like 300, 320 ... +- You can check this, when you start the DOS driver, which came with your +- drive. By appropriately configuring the drive and the DOS driver you can +- check, whether your drive does operate in this mode correctly under DOS. If +- it does not operate under DOS, it won't under Linux. +- If your drive's base address is something like 0x170 or 0x1F0 (and it is +- not a CyCDROM CR520ie or CR 940ie) you most likely are having an IDE/ATAPI- +- compatible drive, which is not supported by aztcd.c, use ide-cd.c instead. +- Make sure the Base Address is configured correctly in aztcd.h, also make +- sure, that /dev/aztcd0 exists with the correct major number (compare it with +- the entry in file /usr/include/linux/major.h for the Aztech drive). +--insert a CD-ROM and close the tray +--cold boot your PC (i.e. via the power on switch or the reset button) +--if you start Linux via DOS, e.g. using loadlin, make sure, that the DOS +- driver for the CD-ROM drive is not loaded (comment out the calling lines +- in DOS' config.sys!) +--look for the aztcd: init message during Linux init and note them exactly +--log in as root and do a mount -t iso9660 /dev/aztcd0 /mnt +--if you don't succeed in the first time, try several times. Try also to open +- and close the tray, then mount again. Please note carefully all commands +- you typed in and the aztcd-messages, which you get. +--if you get an 'Aztech CD-ROM init: aborted' message, read the remarks about +- the version string below. +- +-If this does not help, do the same with the following differences +--start DOS before; make now sure, that the DOS driver for the CD-ROM is +- loaded under DOS (i.e. uncomment it again in config.sys) +--warm boot your PC (i.e. via CTRL-ALT-DEL) +- if you have it, you can also start via loadlin (try both). +- ... +- Again note all commands and the aztcd-messages. +- +-If you see STEN_LOW or STEN_LOW_WAIT error messages, increase the timeout +-values. +- +-If this still does not help, +--look in aztcd.c for the lines #if 0 +- #define AZT_TEST1 +- ... +- #endif +- and substitute '#if 0' by '#if 1'. +--recompile your kernel and repeat the above two procedures. You will now get +- a bundle of debugging messages from the driver. Again note your commands +- and the appropriate messages. If you have syslogd running, these messages +- may also be found in syslogd's kernel log file. Nevertheless in some +- installations syslogd does not yet run, when init() is called, thus look for +- the aztcd-messages during init, before the login-prompt appears. +- Then look in aztcd.c, to find out, what happened. The normal calling sequence +- is: aztcd_init() during Linux bootup procedure init() +- after doing a 'mount -t iso9660 /dev/aztcd0 /mnt' the normal calling sequence is +- aztcd_open() -> Status 2c after cold reboot with CDROM or audio CD inserted +- -> Status 8 after warm reboot with CDROM inserted +- -> Status 2e after cold reboot with no disk, closed tray +- -> Status 6e after cold reboot, mount with door open +- aztUpdateToc() +- aztGetDiskInfo() +- aztGetQChannelInfo() repeated several times +- aztGetToc() +- aztGetQChannelInfo() repeated several times +- a list of track information +- do_aztcd_request() } +- azt_transfer() } repeated several times +- azt_poll } +- Check, if there is a difference in the calling sequence or the status flags! +- +- There are a lot of other messages, eg. the ACMD-command code (defined in +- aztcd.h), status info from the getAztStatus-command and the state sequence of +- the finite state machine in azt_poll(). The most important are the status +- messages, look how they are defined and try to understand, if they make +- sense in the context where they appear. With a CD-ROM inserted the status +- should always be 8, except in aztcd_open(). Try to open the tray, insert an +- audio disk, insert no disk or reinsert the CD-ROM and check, if the status +- bits change accordingly. The status bits are the most likely point, where +- the drive manufacturers may implement changes. +- +-If you still don't succeed, a good point to start is to look in aztcd.c in +-function aztcd_init, where the drive should be detected during init. Do the +-following: +--reboot the system with boot parameter 'aztcd=,0x79'. With +- parameter 0x79 most of the drive version detection is bypassed. After that +- you should see the complete version string including leading and trailing +- blanks during init. +- Now adapt the statement +- if ((result[1]=='A')&&(result[2]=='Z' ...) +- in aztcd_init() to exactly match the first 3 or 4 letters you have seen. +--Another point is the 'smart' card detection feature in aztcd_init(). Normally +- the CD-ROM drive is ready, when aztcd_init is trying to read the version +- string and a time consuming ACMD_SOFT_RESET command can be avoided. This is +- detected by looking, if AFL_OP_OK can be read correctly. If the CD-ROM drive +- hangs in some unknown state, e.g. because of an error before a warm start or +- because you first operated under DOS, even the version string may be correct, +- but the following commands will not. Then change the code in such a way, +- that the ACMD_SOFT_RESET is issued in any case, by substituting the +- if-statement 'if ( ...=AFL_OP_OK)' by 'if (1)'. +- +-If you succeed, please mail me the exact version string of your drive and +-the code modifications, you have made together with a short explanation. +-If you don't succeed, you may mail me the output of the debugging messages. +-But remember, they are only useful, if they are exact and complete and you +-describe in detail your hardware setup and what you did (cold/warm reboot, +-with/without DOS, DOS-driver started/not started, which Linux-commands etc.) +- +- +-9. TECHNICAL HISTORY OF THE DRIVER +-The AZTECH-Driver is a rework of the Mitsumi-Driver. Four major items had to +-be reworked: +- +-a) The Mitsumi drive does issue complete status information acknowledging +-each command, the Aztech drive does only signal that the command was +-processed. So whenever the complete status information is needed, an extra +-ACMD_GET_STATUS command is issued. The handshake procedure for the drive +-can be found in the functions aztSendCmd(), sendAztCmd() and getAztStatus(). +- +-b) The Aztech Drive does not have a ACMD_GET_DISK_INFO command, so the +-necessary info about the number of tracks (firstTrack, lastTrack), disk +-length etc. has to be read from the TOC in the lead in track (see function +-aztGetDiskInfo()). +- +-c) Whenever data is read from the drive, the Mitsumi drive is started with a +-command to read an indefinite (0xffffff) number of sectors. When the appropriate +-number of sectors is read, the drive is stopped by a ACDM_STOP command. This +-does not work with the Aztech drive. I did not find a way to stop it. The +-stop and pause commands do only work in AUDIO mode but not in DATA mode. +-Therefore I had to modify the 'finite state machine' in function azt_poll to +-only read a certain number of sectors and then start a new read on demand. As I +-have not completely understood, how the buffer/caching scheme of the Mitsumi +-driver was implemented, I am not sure, if I have covered all cases correctly, +-whenever you get timeout messages, the bug is most likely to be in that +-function azt_poll() around switch(cmd) .... case ACD_S_DATA. +- +-d) I did not get information about changing drive mode. So I doubt, that the +-code around function azt_poll() case AZT_S_MODE does work. In my test I have +-not been able to switch to reading in raw mode. For reading raw mode, Aztech +-uses a different command than for cooked mode, which I only have implemen- +-ted in the ioctl-section but not in the section which is used by the ISO9660. +- +-The driver was developed on an AST PC with Intel 486/DX2, 8MB RAM, 340MB IDE +-hard disk and on an AST PC with Intel Pentium 60MHz, 16MB RAM, 520MB IDE +-running Linux kernel version 1.0.9 from the LST 1.8 Distribution. The kernel +-was compiled with gcc.2.5.8. My CD-ROM drive is an Aztech CDA268-01A. My +-drive says, that it has Firmware Version AZT26801A1.3. It came with an ISA-bus +-interface card and works with polled I/O without DMA and without interrupts. +-The code for all other drives was 'remote' tested and debugged by a number of +-volunteers on the Internet. +- +-Points, where I feel that possible problems might be and all points where I +-did not completely understand the drive's behaviour or trust my own code are +-marked with /*???*/ in the source code. There are also some parts in the +-Mitsumi driver, where I did not completely understand their code. +- +- +-10. ACKNOWLEDGMENTS +-Without the help of P.Bush, Aztech, who delivered technical information +-about the Aztech Drive and without the help of E.Moenkeberg, GWDG, who did a +-great job in analyzing the command structure of various CD-ROM drives, this +-work would not have been possible. E.Moenkeberg was also a great help in +-making the software 'kernel ready' and in answering many of the CDROM-related +-questions in the newsgroups. He really is *the* Linux CD-ROM guru. Thanks +-also to all the guys on the Internet, who collected valuable technical +-information about CDROMs. +- +-Joe Nardone (joe@access.digex.net) was a patient tester even for my first +-trial, which was more than slow, and made suggestions for code improvement. +-Especially the 'finite state machine' azt_poll() was rewritten by Joe to get +-clean C code and avoid the ugly 'gotos', which I copied from mcd.c. +- +-Robby Schirmer (schirmer@fmi.uni-passau.de) tested the audio stuff (ioctls) +-and suggested a lot of patches for them. +- +-Joseph Piskor and Peter Nugent were the first users with the ORCHID CD3110 +-and also were very patient with the problems which occurred. +- +-Reinhard Max delivered the information for the CDROM-interface of the +-SoundWave32 soundcards. +- +-Jochen Kunz and Olaf Kaluza delivered the information for supporting Conrad's +-TXC drive. +- +-Hilmar Berger delivered the patches for supporting CyCDROM CR520ie. +- +-Anybody, who is interested in these items should have a look at 'ftp.gwdg.de', +-directory 'pub/linux/cdrom' and at 'ftp.cdrom.com', directory 'pub/cdrom'. +- +-11. PROGRAMMING ADD ONs: cdplay.c +-You can use the ioctl-functions included in aztcd.c in your own programs. As +-an example on how to do this, you will find a tiny CD Player for audio CDs +-named 'cdplay.c'. It allows you to play audio CDs. You can play a specified +-track, pause and resume or skip tracks forward and backwards. If you quit the +-program without stopping the drive, playing is continued. You can also +-(mis)use cdplay to read and hexdump data disks. You can find the code in the +-APPENDIX of this file, which you should cut out with an editor and store in a +-separate file 'cdplay.c'. To compile it and make it executable, do +- gcc -s -Wall -O2 -L/usr/lib cdplay.c -o /usr/local/bin/cdplay # compiles it +- chmod +755 /usr/local/bin/cdplay # makes it executable +- ln -s /dev/aztcd0 /dev/cdrom # creates a link +- (for /usr/lib substitute the top level directory, where your include files +- reside, and for /usr/local/bin the directory, where you want the executable +- binary to reside ) +- +-You have to set the correct permissions for cdplay *and* for /dev/mcd0 or +-/dev/aztcd0 in order to use it. Remember, that you should not have /dev/cdrom +-mounted, when you're playing audio CDs. +- +-This program is just a hack for testing the ioctl-functions in aztcd.c. I will +-not maintain it, so if you run into problems, discard it or have a look into +-the source code 'cdplay.c'. The program does only contain a minimum of user +-protection and input error detection. If you use the commands in the wrong +-order or if you try to read a CD at wrong addresses, you may get error messages +-or even hang your machine. If you get STEN_LOW, STEN_LOW_WAIT or segment violation +-error messages when using cdplay, after that, the system might not be stable +-any more, so you'd better reboot. As the ioctl-functions run in kernel mode, +-most normal Linux-multitasking protection features do not work. By using +-uninitialized 'wild' pointers etc., it is easy to write to other users' data +-and program areas, destroy kernel tables etc.. So if you experiment with ioctls +-as always when you are doing systems programming and kernel hacking, you +-should have a backup copy of your system in a safe place (and you also +-should try restoring from a backup copy first)! +- +-A reworked and improved version called 'cdtester.c', which has yet more +-features for testing CDROM-drives can be found in +-Documentation/cdrom/sbpcd, written by E.Moenkeberg. +- +-Werner Zimmermann +-Fachhochschule fuer Technik Esslingen +-(EMail: Werner.Zimmermann@fht-esslingen.de) +-October, 1997 +- +---------------------------------------------------------------------------- +-APPENDIX: Source code of cdplay.c +- +-/* Tiny Audio CD Player +- +- Copyright 1994, 1995, 1996 Werner Zimmermann (Werner.Zimmermann@fht-esslingen.de) +- +-This program originally was written to test the audio functions of the +-AZTECH.CDROM-driver, but it should work with every CD-ROM drive. Before +-using it, you should set a symlink from /dev/cdrom to your real CDROM +-device. +- +-The GNU General Public License applies to this program. +- +-History: V0.1 W.Zimmermann: First release. Nov. 8, 1994 +- V0.2 W.Zimmermann: Enhanced functionality. Nov. 9, 1994 +- V0.3 W.Zimmermann: Additional functions. Nov. 28, 1994 +- V0.4 W.Zimmermann: fixed some bugs. Dec. 17, 1994 +- V0.5 W.Zimmermann: clean 'scanf' commands without compiler warnings +- Jan. 6, 1995 +- V0.6 W.Zimmermann: volume control (still experimental). Jan. 24, 1995 +- V0.7 W.Zimmermann: read raw modified. July 26, 95 +-*/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-void help(void) +-{ printf("Available Commands: STOP s EJECT/CLOSE e QUIT q\n"); +- printf(" PLAY TRACK t PAUSE p RESUME r\n"); +- printf(" NEXT TRACK n REPEAT LAST l HELP h\n"); +- printf(" SUB CHANNEL c TRACK INFO i PLAY AT a\n"); +- printf(" READ d READ RAW w VOLUME v\n"); +-} +- +-int main(void) +-{ int handle; +- unsigned char command=' ', ini=0, first=1, last=1; +- unsigned int cmd, i,j,k, arg1,arg2,arg3; +- struct cdrom_ti ti; +- struct cdrom_tochdr tocHdr; +- struct cdrom_subchnl subchnl; +- struct cdrom_tocentry entry; +- struct cdrom_msf msf; +- union { struct cdrom_msf msf; +- unsigned char buf[CD_FRAMESIZE_RAW]; +- } azt; +- struct cdrom_volctrl volctrl; +- +- printf("\nMini-Audio CD-Player V0.72 (C) 1994,1995,1996 W.Zimmermann\n"); +- handle=open("/dev/cdrom",O_RDWR); +- ioctl(handle,CDROMRESUME); +- +- if (handle<=0) +- { printf("Drive Error: already playing, no audio disk, door open\n"); +- printf(" or no permission (you must be ROOT in order to use this program)\n"); +- } +- else +- { help(); +- while (1) +- { printf("Type command (h = help): "); +- scanf("%s",&command); +- switch (command) +- { case 'e': cmd=CDROMEJECT; +- ioctl(handle,cmd); +- break; +- case 'p': if (!ini) +- { printf("Command not allowed - play track first\n"); +- } +- else +- { cmd=CDROMPAUSE; +- if (ioctl(handle,cmd)) printf("Drive Error\n"); +- } +- break; +- case 'r': if (!ini) +- { printf("Command not allowed - play track first\n"); +- } +- else +- { cmd=CDROMRESUME; +- if (ioctl(handle,cmd)) printf("Drive Error\n"); +- } +- break; +- case 's': cmd=CDROMPAUSE; +- if (ioctl(handle,cmd)) printf("Drive error or already stopped\n"); +- cmd=CDROMSTOP; +- if (ioctl(handle,cmd)) printf("Drive error\n"); +- break; +- case 't': cmd=CDROMREADTOCHDR; +- if (ioctl(handle,cmd,&tocHdr)) printf("Drive Error\n"); +- first=tocHdr.cdth_trk0; +- last= tocHdr.cdth_trk1; +- if ((first==0)||(first>last)) +- { printf ("--could not read TOC\n"); +- } +- else +- { printf("--first track: %d --last track: %d --enter track number: ",first,last); +- cmd=CDROMPLAYTRKIND; +- scanf("%i",&arg1); +- ti.cdti_trk0=arg1; +- if (ti.cdti_trk0last) ti.cdti_trk0=last; +- ti.cdti_ind0=0; +- ti.cdti_trk1=last; +- ti.cdti_ind1=0; +- if (ioctl(handle,cmd,&ti)) printf("Drive Error\n"); +- ini=1; +- } +- break; +- case 'n': if (!ini++) +- { if (ioctl(handle,CDROMREADTOCHDR,&tocHdr)) printf("Drive Error\n"); +- first=tocHdr.cdth_trk0; +- last= tocHdr.cdth_trk1; +- ti.cdti_trk0=first-1; +- } +- if ((first==0)||(first>last)) +- { printf ("--could not read TOC\n"); +- } +- else +- { cmd=CDROMPLAYTRKIND; +- if (++ti.cdti_trk0 > last) ti.cdti_trk0=last; +- ti.cdti_ind0=0; +- ti.cdti_trk1=last; +- ti.cdti_ind1=0; +- if (ioctl(handle,cmd,&ti)) printf("Drive Error\n"); +- ini=1; +- } +- break; +- case 'l': if (!ini++) +- { if (ioctl(handle,CDROMREADTOCHDR,&tocHdr)) printf("Drive Error\n"); +- first=tocHdr.cdth_trk0; +- last= tocHdr.cdth_trk1; +- ti.cdti_trk0=first+1; +- } +- if ((first==0)||(first>last)) +- { printf ("--could not read TOC\n"); +- } +- else +- { cmd=CDROMPLAYTRKIND; +- if (--ti.cdti_trk0 < first) ti.cdti_trk0=first; +- ti.cdti_ind0=0; +- ti.cdti_trk1=last; +- ti.cdti_ind1=0; +- if (ioctl(handle,cmd,&ti)) printf("Drive Error\n"); +- ini=1; +- } +- break; +- case 'c': subchnl.cdsc_format=CDROM_MSF; +- if (ioctl(handle,CDROMSUBCHNL,&subchnl)) +- printf("Drive Error\n"); +- else +- { printf("AudioStatus:%s Track:%d Mode:%d MSF=%d:%d:%d\n", \ +- subchnl.cdsc_audiostatus==CDROM_AUDIO_PLAY ? "PLAYING":"NOT PLAYING",\ +- subchnl.cdsc_trk,subchnl.cdsc_adr, \ +- subchnl.cdsc_absaddr.msf.minute, subchnl.cdsc_absaddr.msf.second, \ +- subchnl.cdsc_absaddr.msf.frame); +- } +- break; +- case 'i': if (!ini) +- { printf("Command not allowed - play track first\n"); +- } +- else +- { cmd=CDROMREADTOCENTRY; +- printf("Track No.: "); +- scanf("%d",&arg1); +- entry.cdte_track=arg1; +- if (entry.cdte_tracklast) entry.cdte_track=last; +- entry.cdte_format=CDROM_MSF; +- if (ioctl(handle,cmd,&entry)) +- { printf("Drive error or invalid track no.\n"); +- } +- else +- { printf("Mode %d Track, starts at %d:%d:%d\n", \ +- entry.cdte_adr,entry.cdte_addr.msf.minute, \ +- entry.cdte_addr.msf.second,entry.cdte_addr.msf.frame); +- } +- } +- break; +- case 'a': cmd=CDROMPLAYMSF; +- printf("Address (min:sec:frame) "); +- scanf("%d:%d:%d",&arg1,&arg2,&arg3); +- msf.cdmsf_min0 =arg1; +- msf.cdmsf_sec0 =arg2; +- msf.cdmsf_frame0=arg3; +- if (msf.cdmsf_sec0 > 59) msf.cdmsf_sec0 =59; +- if (msf.cdmsf_frame0> 74) msf.cdmsf_frame0=74; +- msf.cdmsf_min1=60; +- msf.cdmsf_sec1=00; +- msf.cdmsf_frame1=00; +- if (ioctl(handle,cmd,&msf)) +- { printf("Drive error or invalid address\n"); +- } +- break; +-#ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/ +- case 'd': cmd=CDROMREADCOOKED; +- printf("Address (min:sec:frame) "); +- scanf("%d:%d:%d",&arg1,&arg2,&arg3); +- azt.msf.cdmsf_min0 =arg1; +- azt.msf.cdmsf_sec0 =arg2; +- azt.msf.cdmsf_frame0=arg3; +- if (azt.msf.cdmsf_sec0 > 59) azt.msf.cdmsf_sec0 =59; +- if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74; +- if (ioctl(handle,cmd,&azt.msf)) +- { printf("Drive error, invalid address or unsupported command\n"); +- } +- k=0; +- getchar(); +- for (i=0;i<128;i++) +- { printf("%4d:",i*16); +- for (j=0;j<16;j++) +- { printf("%2x ",azt.buf[i*16+j]); +- } +- for (j=0;j<16;j++) +- { if (isalnum(azt.buf[i*16+j])) +- printf("%c",azt.buf[i*16+j]); +- else +- printf("."); +- } +- printf("\n"); +- k++; +- if (k>=20) +- { printf("press ENTER to continue\n"); +- getchar(); +- k=0; +- } +- } +- break; +- case 'w': cmd=CDROMREADRAW; +- printf("Address (min:sec:frame) "); +- scanf("%d:%d:%d",&arg1,&arg2,&arg3); +- azt.msf.cdmsf_min0 =arg1; +- azt.msf.cdmsf_sec0 =arg2; +- azt.msf.cdmsf_frame0=arg3; +- if (azt.msf.cdmsf_sec0 > 59) azt.msf.cdmsf_sec0 =59; +- if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74; +- if (ioctl(handle,cmd,&azt)) +- { printf("Drive error, invalid address or unsupported command\n"); +- } +- k=0; +- for (i=0;i<147;i++) +- { printf("%4d:",i*16); +- for (j=0;j<16;j++) +- { printf("%2x ",azt.buf[i*16+j]); +- } +- for (j=0;j<16;j++) +- { if (isalnum(azt.buf[i*16+j])) +- printf("%c",azt.buf[i*16+j]); +- else +- printf("."); +- } +- printf("\n"); +- k++; +- if (k>=20) +- { getchar(); +- k=0; +- } +- } +- break; +-#endif +- case 'v': cmd=CDROMVOLCTRL; +- printf("--Channel 0 Left (0-255): "); +- scanf("%d",&arg1); +- printf("--Channel 1 Right (0-255): "); +- scanf("%d",&arg2); +- volctrl.channel0=arg1; +- volctrl.channel1=arg2; +- volctrl.channel2=0; +- volctrl.channel3=0; +- if (ioctl(handle,cmd,&volctrl)) +- { printf("Drive error or unsupported command\n"); +- } +- break; +- case 'q': if (close(handle)) printf("Drive Error: CLOSE\n"); +- exit(0); +- case 'h': help(); +- break; +- default: printf("unknown command\n"); +- break; +- } +- } +- } +- return 0; +-} +diff -Nurp linux-2.6.22/Documentation/cdrom/cdu31a linux-2.6-netns/Documentation/cdrom/cdu31a +--- linux-2.6.22/Documentation/cdrom/cdu31a 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/cdu31a 1969-12-31 19:00:00.000000000 -0500 +@@ -1,196 +0,0 @@ +- +- CDU31A/CDU33A Driver Info +- ------------------------- +- +-Information on the Sony CDU31A/CDU33A CDROM driver for the Linux +-kernel. +- +- Corey Minyard (minyard@metronet.com) +- +- Colossians 3:17 +- +-Crude Table of Contents +------------------------ +- +- Setting Up the Hardware +- Configuring the Kernel +- Configuring as a Module +- Driver Special Features +- +- +-This device driver handles Sony CDU31A/CDU33A CDROM drives and +-provides a complete block-level interface as well as an ioctl() +-interface as specified in include/linux/cdrom.h). With this +-interface, CDROMs can be accessed, standard audio CDs can be played +-back normally, and CD audio information can be read off the drive. +- +-Note that this will only work for CDU31A/CDU33A drives. Some vendors +-market their drives as CDU31A compatible. They lie. Their drives are +-really CDU31A hardware interface compatible (they can plug into the +-same card). They are not software compatible. +- +-Setting Up the Hardware +------------------------ +- +-The CDU31A driver is unable to safely tell if an interface card is +-present that it can use because the interface card does not announce +-its presence in any way besides placing 4 I/O locations in memory. It +-used to just probe memory and attempt commands, but Linus wisely asked +-me to remove that because it could really screw up other hardware in +-the system. +- +-Because of this, you must tell the kernel where the drive interface +-is, what interrupts are used, and possibly if you are on a PAS-16 +-soundcard. +- +-If you have the Sony CDU31A/CDU33A drive interface card, the following +-diagram will help you set it up. If you have another card, you are on +-your own. You need to make sure that the I/O address and interrupt is +-not used by another card in the system. You will need to know the I/O +-address and interrupt you have set. Note that use of interrupts is +-highly recommended, if possible, it really cuts down on CPU used. +-Unfortunately, most soundcards do not support interrupts for their +-CDROM interfaces. By default, the Sony interface card comes with +-interrupts disabled. +- +- +----------+-----------------+----------------------+ +- | JP1 | 34 Pin Conn | | +- | JP2 +-----------------+ | +- | JP3 | +- | JP4 | +- | +--+ +- | | +-+ +- | | | | External +- | | | | Connector +- | | | | +- | | +-+ +- | +--+ +- | | +- | +--------+ +- | | +- +------------------------------------------+ +- +- JP1 sets the Base Address, using the following settings: +- +- Address Pin 1 Pin 2 +- ------- ----- ----- +- 0x320 Short Short +- 0x330 Short Open +- 0x340 Open Short +- 0x360 Open Open +- +- JP2 and JP3 configure the DMA channel; they must be set the same. +- +- DMA Pin 1 Pin 2 Pin 3 +- --- ----- ----- ----- +- 1 On Off On +- 2 Off On Off +- 3 Off Off On +- +- JP4 Configures the IRQ: +- +- IRQ Pin 1 Pin 2 Pin 3 Pin 4 +- --- ----- ----- ----- ----- +- 3 Off Off On Off +- 4 Off Off* Off On +- 5 On Off Off Off +- 6 Off On Off Off +- +- The documentation states to set this for interrupt +- 4, but I think that is a mistake. +- +-Note that if you have another interface card, you will need to look at +-the documentation to find the I/O base address. This is specified to +-the SLCD.SYS driver for DOS with the /B: parameter, so you can look at +-you DOS driver setup to find the address, if necessary. +- +-Configuring the Kernel +----------------------- +- +-You must tell the kernel where the drive is at boot time. This can be +-done at the Linux boot prompt, by using LILO, or by using Bootlin. +-Note that this is no substitute for HOWTOs and LILO documentation, if +-you are confused please read those for info on bootline configuration +-and LILO. +- +-At the linux boot prompt, press the ALT key and add the following line +-after the boot name (you can let the kernel boot, it will tell you the +-default boot name while booting): +- +- cdu31a=,[,PAS] +- +-The base address needs to have "0x" in front of it, since it is in +-hex. For instance, to configure a drive at address 320 on interrupt 5, +-use the following: +- +- cdu31a=0x320,5 +- +-I use the following boot line: +- +- cdu31a=0x1f88,0,PAS +- +-because I have a PAS-16 which does not support interrupt for the +-CDU31A interface. +- +-Adding this as an append line at the beginning of the /etc/lilo.conf +-file will set it for lilo configurations. I have the following as the +-first line in my lilo.conf file: +- +- append="cdu31a=0x1f88,0" +- +-I'm not sure how to set up Bootlin (I have never used it), if someone +-would like to fill in this section please do. +- +- +-Configuring as a Module +------------------------ +- +-The driver supports loading as a module. However, you must specify +-the boot address and interrupt on the boot line to insmod. You can't +-use modprobe to load it, since modprobe doesn't support setting +-variables. +- +-Anyway, I use the following line to load my driver as a module +- +- /sbin/insmod /lib/modules/`uname -r`/misc/cdu31a.o cdu31a_port=0x1f88 +- +-You can set the following variables in the driver: +- +- cdu31a_port= - sets the base I/O. If hex, put 0x in +- front of it. This must be specified. +- +- cdu31a_irq= - Sets the interrupt number. Leaving this +- off will turn interrupts off. +- +- +-Driver Special Features +------------------------ +- +-This section describes features beyond the normal audio and CD-ROM +-functions of the drive. +- +-2048 byte buffer mode +- +-If a disk is mounted with -o block=2048, data is copied straight from +-the drive data port to the buffer. Otherwise, the readahead buffer +-must be involved to hold the other 1K of data when a 1K block +-operation is done. Note that with 2048 byte blocks you cannot execute +-files from the CD. +- +-XA compatibility +- +-The driver should support XA disks for both the CDU31A and CDU33A. It +-does this transparently, the using program doesn't need to set it. +- +-Multi-Session +- +-A multi-session disk looks just like a normal disk to the user. Just +-mount one normally, and all the data should be there. A special +-thanks to Koen for help with this! +- +-Raw sector I/O +- +-Using the CDROMREADAUDIO it is possible to read raw audio and data +-tracks. Both operations return 2352 bytes per sector. On the data +-tracks, the first 12 bytes is not returned by the drive and the value +-of that data is indeterminate. +diff -Nurp linux-2.6.22/Documentation/cdrom/cm206 linux-2.6-netns/Documentation/cdrom/cm206 +--- linux-2.6.22/Documentation/cdrom/cm206 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/cm206 1969-12-31 19:00:00.000000000 -0500 +@@ -1,185 +0,0 @@ +-This is the readme file for the driver for the Philips/LMS cdrom drive +-cm206 in combination with the cm260 host adapter card. +- +- (c) 1995 David A. van Leeuwen +- +-Changes since version 0.99 +--------------------------- +-- Interfacing to the kernel is routed though an extra interface layer, +- cdrom.c. This allows runtime-configurable `behavior' of the cdrom-drive, +- independent of the driver. +- +-Features since version 0.33 +---------------------------- +-- Full audio support, that is, both workman, workbone and cdp work +- now reasonably. Reading TOC still takes some time. xmcd has been +- reported to run successfully. +-- Made auto-probe code a little better, I hope +- +-Features since version 0.28 +---------------------------- +-- Full speed transfer rate (300 kB/s). +-- Minimum kernel memory usage for buffering (less than 3 kB). +-- Multisession support. +-- Tray locking. +-- Statistics of driver accessible to the user. +-- Module support. +-- Auto-probing of adapter card's base port and irq line, +- also configurable at boot time or module load time. +- +- +-Decide how you are going to use the driver. There are two +-options: +- +- (a) installing the driver as a resident part of the kernel +- (b) compiling the driver as a loadable module +- +- Further, you must decide if you are going to specify the base port +- address and the interrupt request line of the adapter card cm260 as +- boot options for (a), module parameters for (b), use automatic +- probing of these values, or hard-wire your adaptor card's settings +- into the source code. If you don't care, you can choose +- autoprobing, which is the default. In that case you can move on to +- the next step. +- +-Compiling the kernel +--------------------- +-1) move to /usr/src/linux and do a +- +- make config +- +- If you have chosen option (a), answer yes to CONFIG_CM206 and +- CONFIG_ISO9660_FS. +- +- If you have chosen option (b), answer yes to CONFIG_MODVERSIONS +- and no (!) to CONFIG_CM206 and CONFIG_ISO9660_FS. +- +-2) then do a +- +- make clean; make zImage; make modules +- +-3) do the usual things to install a new image (backup the old one, run +- `rdev -R zImage 1', copy the new image in place, run lilo). Might +- be `make zlilo'. +- +-Using the driver as a module +----------------------------- +-If you will only occasionally use the cd-rom driver, you can choose +-option (b), install as a loadable module. You may have to re-compile +-the module when you upgrade the kernel to a new version. +- +-Since version 0.96, much of the functionality has been transferred to +-a generic cdrom interface in the file cdrom.c. The module cm206.o +-depends on cdrom.o. If the latter is not compiled into the kernel, +-you must explicitly load it before cm206.o: +- +- insmod /usr/src/linux/modules/cdrom.o +- +-To install the module, you use the command, as root +- +- insmod /usr/src/linux/modules/cm206.o +- +-You can specify the base address on the command line as well as the irq +-line to be used, e.g. +- +- insmod /usr/src/linux/modules/cm206.o cm206=0x300,11 +- +-The order of base port and irq line doesn't matter; if you specify only +-one, the other will have the value of the compiled-in default. You +-may also have to install the file-system module `iso9660.o', if you +-didn't compile that into the kernel. +- +- +-Using the driver as part of the kernel +--------------------------------------- +-If you have chosen option (a), you can specify the base-port +-address and irq on the lilo boot command line, e.g.: +- +- LILO: linux cm206=0x340,11 +- +-This assumes that your linux kernel image keyword is `linux'. +-If you specify either IRQ (3--11) or base port (0x300--0x370), +-auto probing is turned off for both settings, thus setting the +-other value to the compiled-in default. +- +-Note that you can also put these parameters in the lilo configuration file: +- +-# linux config +-image = /vmlinuz +- root = /dev/hda1 +- label = Linux +- append = "cm206=0x340,11" +- read-only +- +- +-If module parameters and LILO config options don't work +-------------------------------------------------------- +-If autoprobing does not work, you can hard-wire the default values +-of the base port address (CM206_BASE) and interrupt request line +-(CM206_IRQ) into the file /usr/src/linux/drivers/cdrom/cm206.h. Change +-the defines of CM206_IRQ and CM206_BASE. +- +- +-Mounting the cdrom +------------------- +-1) Make sure that the right device is installed in /dev. +- +- mknod /dev/cm206cd b 32 0 +- +-2) Make sure there is a mount point, e.g., /cdrom +- +- mkdir /cdrom +- +-3) mount using a command like this (run as root): +- +- mount -rt iso9660 /dev/cm206cd /cdrom +- +-4) For user-mounts, add a line in /etc/fstab +- +- /dev/cm206cd /cdrom iso9660 ro,noauto,user +- +- This will allow users to give the commands +- +- mount /cdrom +- umount /cdrom +- +-If things don't work +--------------------- +- +-- Try to do a `dmesg' to find out if the driver said anything about +- what is going wrong during the initialization. +- +-- Try to do a `dd if=/dev/cm206cd | od -tc | less' to read from the +- CD. +- +-- Look in the /proc directory to see if `cm206' shows up under one of +- `interrupts', `ioports', `devices' or `modules' (if applicable). +- +- +-DISCLAIMER +----------- +-I cannot guarantee that this driver works, or that the hardware will +-not be harmed, although I consider it most unlikely. +- +-I hope that you'll find this driver in some way useful. +- +- David van Leeuwen +- david@tm.tno.nl +- +-Note for Linux CDROM vendors +------------------------------ +-You are encouraged to include this driver on your Linux CDROM. If +-you do, you might consider sending me a free copy of that cd-rom. +-You can contact me through my e-mail address, david@tm.tno.nl. +-If this driver is compiled into a kernel to boot off a cdrom, +-you should actually send me a free copy of that cd-rom. +- +-Copyright +---------- +-The copyright of the cm206 driver for Linux is +- +- (c) 1995 David A. van Leeuwen +- +-The driver is released under the conditions of the GNU general public +-license, which can be found in the file COPYING in the root of this +-source tree. +diff -Nurp linux-2.6.22/Documentation/cdrom/gscd linux-2.6-netns/Documentation/cdrom/gscd +--- linux-2.6.22/Documentation/cdrom/gscd 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/gscd 1969-12-31 19:00:00.000000000 -0500 +@@ -1,60 +0,0 @@ +- Goldstar R420 CD-Rom device driver README +- +-For all kind of other information about the GoldStar R420 CDROM +-and this Linux device driver see the WWW page: +- +- http://linux.rz.fh-hannover.de/~raupach +- +- +- If you are the editor of a Linux CD, you should +- enable gscd.c within your boot floppy kernel. Please, +- send me one of your CDs for free. +- +- +-This current driver version 0.4a only supports reading data from the disk. +-Currently we have no audio and no multisession or XA support. +-The polling interface is used, no DMA. +- +- +-Sometimes the GoldStar R420 is sold in a 'Reveal Multimedia Kit'. This kit's +-drive interface is compatible, too. +- +- +-Installation +------------- +- +-Change to '/usr/src/linux/drivers/cdrom' and edit the file 'gscd.h'. Insert +-the i/o address of your interface card. +- +-The default base address is 0x340. This will work for most applications. +-Address selection is accomplished by jumpers PN801-1 to PN801-4 on the +-GoldStar Interface Card. +-Appropriate settings are: 0x300, 0x310, 0x320, 0x330, 0x340, 0x350, 0x360 +-0x370, 0x380, 0x390, 0x3A0, 0x3B0, 0x3C0, 0x3D0, 0x3E0, 0x3F0 +- +-Then go back to '/usr/src/linux/' and 'make config' to build the new +-configuration for your kernel. If you want to use the GoldStar driver +-like a module, don't select 'GoldStar CDROM support'. By the way, you +-have to include the iso9660 filesystem. +- +-Now start compiling the kernel with 'make zImage'. +-If you want to use the driver as a module, you have to do 'make modules' +-and 'make modules_install', additionally. +-Install your new kernel as usual - maybe you do it with 'make zlilo'. +- +-Before you can use the driver, you have to +- mknod /dev/gscd0 b 16 0 +-to create the appropriate device file (you only need to do this once). +- +-If you use modules, you can try to insert the driver. +-Say: 'insmod /usr/src/linux/modules/gscd.o' +-or: 'insmod /usr/src/linux/modules/gscd.o gscd=
' +-The driver should report its results. +- +-That's it! Mount a disk, i.e. 'mount -rt iso9660 /dev/gscd0 /cdrom' +- +-Feel free to report errors and suggestions to the following address. +-Be sure, I'm very happy to receive your comments! +- +- Oliver Raupach Hannover, Juni 1995 +-(raupach@nwfs1.rz.fh-hannover.de) +diff -Nurp linux-2.6.22/Documentation/cdrom/isp16 linux-2.6-netns/Documentation/cdrom/isp16 +--- linux-2.6.22/Documentation/cdrom/isp16 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/isp16 1969-12-31 19:00:00.000000000 -0500 +@@ -1,100 +0,0 @@ +- -- Documentation/cdrom/isp16 +- +-Docs by Eric van der Maarel +- +-This is the README for version 0.6 of the cdrom interface on an +-ISP16, MAD16 or Mozart sound card. +- +-The detection and configuration of this interface used to be included +-in both the sjcd and optcd cdrom driver. Drives supported by these +-drivers came packed with Media Magic's multi media kit, which also +-included the ISP16 card. The idea (thanks Leo Spiekman) +-to move it from these drivers into a separate module and moreover, not to +-rely on the MAD16 sound driver, are as follows: +--duplication of code in the kernel is a waste of resources and should +- be avoided; +--however, kernels and notably those included with Linux distributions +- (cf Slackware 3.0 included version 0.5 of the isp16 configuration +- code included in the drivers) don't always come with sound support +- included. Especially when they already include a bunch of cdrom drivers. +- Hence, the cdrom interface should be configurable _independently_ of +- sound support. +- +-The ISP16, MAD16 and Mozart sound cards have an OPTi 82C928 or an +-OPTi 82C929 chip. The interface on these cards should work with +-any cdrom attached to the card, which is 'electrically' compatible +-with Sanyo/Panasonic, Sony or Mitsumi non-ide drives. However, the +-command sets for any proprietary drives may differ +-(and hence may not be supported in the kernel) from these four types. +-For a fact I know the interface works and the way of configuration +-as described in this documentation works in combination with the +-sjcd (in Sanyo/Panasonic compatibility mode) cdrom drivers +-(probably with the optcd (in Sony compatibility mode) as well). +-If you have such an OPTi based sound card and you want to use the +-cdrom interface with a cdrom drive supported by any of the other cdrom +-drivers, it will probably work. Please let me know any experience you +-might have). +-I understand that cards based on the OPTi 82C929 chips may be configured +-(hardware jumpers that is) as an IDE interface. Initialisation of such a +-card in this mode is not supported (yet?). +- +-The suggestion to configure the ISP16 etc. sound card by booting DOS and +-do a warm reboot to boot Linux somehow doesn't work, at least not +-on my machine (IPC P90), with the OPTi 82C928 based card. +- +-Booting the kernel through the boot manager LILO allows the use +-of some command line options on the 'LILO boot:' prompt. At boot time +-press Alt or Shift while the LILO prompt is written on the screen and enter +-any kernel options. Alternatively these options may be used in +-the appropriate section in /etc/lilo.conf. Adding 'append=""' +-will do the trick as well. +-The syntax of 'cmd_line_options' is +- +- isp16=[[,[,]]][[,]] +- +-If there is no ISP16 or compatibles detected, there's probably no harm done. +-These options indicate the values that your cdrom drive has been (or will be) +-configured to use. +-Valid values for the base i/o address are: +- port=0x340,0x320,0x330,0x360 +-for the interrupt request number +- irq=0,3,5,7,9,10,11 +-for the direct memory access line +- dma=0,3,5,6,7 +-and for the type of drive +- drive_type=noisp16,Sanyo,Panasonic,Sony,Mitsumi. +-Note that these options are case sensitive. +-The values 0 for irq and dma indicate that they are not used, and +-the drive will be used in 'polling' mode. The values 5 and 7 for irq +-should be avoided in order to avoid any conflicts with optional +-sound card configuration. +-The syntax of the command line does not allow the specification of +-irq when there's nothing specified for the base address and no +-specification of dma when there is no specification of irq. +-The value 'noisp16' for drive_type, which may be used as the first +-non-integer option value (e.g. 'isp16=noisp16'), makes sure that probing +-for and subsequent configuration of an ISP16-compatible card is skipped +-all together. This can be useful to overcome possible conflicts which +-may arise while the kernel is probing your hardware. +-The default values are +- port=0x340 +- irq=0 +- dma=0 +- drive_type=Sanyo +-reflecting my own configuration. The defaults can be changed in +-the file linux/drivers/cdrom/ips16.h. +- +-The cdrom interface can be configured at run time by loading the +-initialisation driver as a module. In that case, the interface +-parameters can be set by giving appropriate values on the command +-line. Configuring the driver can then be done by the following +-command (assuming you have iso16.o installed in a proper place): +- +- insmod isp16.o isp16_cdrom_base= isp16_cdrom_irq= \ +- isp16_cdrom_dma= isp16_cdrom_type= +- +-where port, irq, dma and drive_type can have any of the values mentioned +-above. +- +- +-Have fun! +diff -Nurp linux-2.6.22/Documentation/cdrom/mcdx linux-2.6-netns/Documentation/cdrom/mcdx +--- linux-2.6.22/Documentation/cdrom/mcdx 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/mcdx 1969-12-31 19:00:00.000000000 -0500 +@@ -1,29 +0,0 @@ +-If you are using the driver as a module, you can specify your ports and IRQs +-like +- +- # insmod mcdx.o mcdx=0x300,11,0x304,5 +- +-and so on ("address,IRQ" pairs). +-This will override the configuration in mcdx.h. +- +-This driver: +- +- o handles XA and (hopefully) multi session CDs as well as +- ordinary CDs; +- o supports up to 5 drives (of course, you'll need free +- IRQs, i/o ports and slots); +- o plays audio +- +-This version doesn't support yet: +- +- o shared IRQs (but it seems to be possible - I've successfully +- connected two drives to the same irq. So it's `only' a +- problem of the driver.) +- +-This driver never will: +- +- o Read digital audio (i.e. copy directly), due to missing +- hardware features. +- +- +-heiko@lotte.sax.de +diff -Nurp linux-2.6.22/Documentation/cdrom/optcd linux-2.6-netns/Documentation/cdrom/optcd +--- linux-2.6.22/Documentation/cdrom/optcd 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/optcd 1969-12-31 19:00:00.000000000 -0500 +@@ -1,57 +0,0 @@ +-This is the README file for the Optics Storage 8000 AT CDROM device driver. +- +-This is the driver for the so-called 'DOLPHIN' drive, with the 34-pin +-Sony-compatible interface. For the IDE-compatible Optics Storage 8001 +-drive, you will want the ATAPI CDROM driver. The driver also seems to +-work with the Lasermate CR328A. If you have a drive that works with +-this driver, and that doesn't report itself as DOLPHIN, please drop me +-a mail. +- +-The support for multisession CDs is in ALPHA stage. If you use it, +-please mail me your experiences. Multisession support can be disabled +-at compile time. +- +-You can find some older versions of the driver at +- dutette.et.tudelft.nl:/pub/linux/ +-and at Eberhard's mirror +- ftp.gwdg.de:/pub/linux/cdrom/drivers/optics/ +- +-Before you can use the driver, you have to create the device file once: +- # mknod /dev/optcd0 b 17 0 +- +-To specify the base address if the driver is "compiled-in" to your kernel, +-you can use the kernel command line item (LILO option) +- optcd=0x340 +-with the right address. +- +-If you have compiled optcd as a module, you can load it with +- # insmod /usr/src/linux/modules/optcd.o +-or +- # insmod /usr/src/linux/modules/optcd.o optcd=0x340 +-with the matching address value of your interface card. +- +-The driver employs a number of buffers to do read-ahead and block size +-conversion. The number of buffers is configurable in optcd.h, and has +-influence on the driver performance. For my machine (a P75), 6 buffers +-seems optimal, as can be seen from this table: +- +-#bufs kb/s %cpu +-1 97 0.1 +-2 191 0.3 +-3 188 0.2 +-4 246 0.3 +-5 189 19 +-6 280 0.4 +-7 281 7.0 +-8 246 2.8 +-16 281 3.4 +- +-If you get a throughput significantly below 300 kb/s, try tweaking +-N_BUFS, and don't forget to mail me your results! +- +-I'd appreciate success/failure reports. If you find a bug, try +-recompiling the driver with some strategically chosen debug options +-(these can be found in optcd.h) and include the messages generated in +-your bug report. Good luck. +- +-Leo Spiekman (spiekman@dutette.et.tudelft.nl) +diff -Nurp linux-2.6.22/Documentation/cdrom/sbpcd linux-2.6-netns/Documentation/cdrom/sbpcd +--- linux-2.6.22/Documentation/cdrom/sbpcd 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/sbpcd 1969-12-31 19:00:00.000000000 -0500 +@@ -1,1061 +0,0 @@ +-This README belongs to release 4.2 or newer of the SoundBlaster Pro +-(Matsushita, Kotobuki, Panasonic, CreativeLabs, Longshine and Teac) +-CD-ROM driver for Linux. +- +-sbpcd really, really is NOT for ANY IDE/ATAPI drive! +-Not even if you have an "original" SoundBlaster card with an IDE interface! +-So, you'd better have a look into README.ide if your port address is 0x1F0, +-0x170, 0x1E8, 0x168 or similar. +-I get tons of mails from IDE/ATAPI drive users - I really can't continue +-any more to answer them all. So, if your drive/interface information sheets +-mention "IDE" (primary, secondary, tertiary, quaternary) and the DOS driver +-invoking line within your CONFIG.SYS is using an address below 0x230: +-DON'T ROB MY LAST NERVE - jumper your interface to address 0x170 and IRQ 15 +-(that is the "secondary IDE" configuration), set your drive to "master" and +-use ide-cd as your driver. If you do not have a second IDE hard disk, use the +-LILO commands +- hdb=noprobe hdc=cdrom +-and get lucky. +-To make it fully clear to you: if you mail me about IDE/ATAPI drive problems, +-my answer is above, and I simply will discard your mail, hoping to stop the +-flood and to find time to lead my 12-year old son towards happy computing. +- +-The driver is able to drive the whole family of "traditional" AT-style (that +-is NOT the new "Enhanced IDE" or "ATAPI" drive standard) Matsushita, +-Kotobuki, Panasonic drives, sometimes labelled as "CreativeLabs". The +-well-known drives are CR-521, CR-522, CR-523, CR-562, CR-563. +-CR-574 is an IDE/ATAPI drive. +- +-The Longshine LCS-7260 is a double-speed drive which uses the "old" +-Matsushita command set. It is supported - with help by Serge Robyns. +-Vertos ("Elitegroup Computer Systems", ECS) has a similar drive - support +-has started; get in contact if you have such a "Vertos 100" or "ECS-AT" +-drive. +- +-There exists an "IBM External ISA CD-ROM Drive" which in fact is a CR-563 +-with a special controller board. This drive is supported (the interface is +-of the "LaserMate" type), and it is possibly the best buy today (cheaper than +-an internal drive, and you can use it as an internal, too - e.g. plug it into +-a soundcard). +- +-CreativeLabs has a new drive "CD200" and a similar drive "CD200F". The latter +-is made by Funai and sometimes named "E2550UA", newer models may be named +-"MK4015". The CD200F drives should fully work. +-CD200 drives without "F" are still giving problems: drive detection and +-playing audio should work, data access will result in errors. I need qualified +-feedback about the bugs within the data functions or a drive (I never saw a +-CD200). +- +-The quad-speed Teac CD-55A drive is supported, but still does not reach "full +-speed". The data rate already reaches 500 kB/sec if you set SBP_BUFFER_FRAMES +-to 64 (it is not recommended to do that for normal "file access" usage, but it +-can speed up things a lot if you use something like "dd" to read from the +-drive; I use it for verifying self-written CDs this way). +-The drive itself is able to deliver 600 kB/sec, so this needs +-work; with the normal setup, the performance currently is not even as good as +-double-speed. +- +-This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives, +-and again: this driver is in no way usable for any IDE/ATAPI drive. If you +-think your drive should work and it doesn't: send me the DOS driver for your +-beast (gzipped + uuencoded) and your CONFIG.SYS if you want to ask me for help, +-and include an original log message excerpt, and try to give all information +-a complete idiot needs to understand your hassle already with your first +-mail. And if you want to say "as I have mailed you before", be sure that I +-don't remember your "case" by such remarks; at the moment, I have some +-hundreds of open correspondences about Linux CDROM questions (hope to reduce if +-the IDE/ATAPI user questions disappear). +- +- +-This driver will work with the soundcard interfaces (SB Pro, SB 16, Galaxy, +-SoundFX, Mozart, MAD16 ...) and with the "no-sound" cards (Panasonic CI-101P, +-LaserMate, WDH-7001C, Longshine LCS-6853, Teac ...). +- +-It works with the "configurable" interface "Sequoia S-1000", too, which is +-used on the Spea Media FX and Ensonic Soundscape sound cards. You have to +-specify the type "SBPRO 2" and the true CDROM port address with it, not the +-"configuration port" address. +- +-If you have a sound card which needs a "configuration driver" instead of +-jumpers for interface types and addresses (like Mozart cards) - those +-drivers get invoked before the DOS CDROM driver in your CONFIG.SYS, typical +-names are "cdsetup.sys" and "mztinit.sys" - let the sound driver do the +-CDROM port configuration (the leading comments in linux/drivers/sound/mad16.c +-are just for you!). Hannu Savolainen's mad16.c code is able to set up my +-Mozart card - I simply had to add +- #define MAD16_CONF 0x06 +- #define MAD16_CDSEL 0x03 +-to configure the CDROM interface for type "Panasonic" (LaserMate) and address +-0x340. +- +-The interface type has to get configured in linux/drivers/cdrom/sbpcd.h, +-because the register layout is different between the "SoundBlaster" and the +-"LaserMate" type. +- +-I got a report that the Teac interface card "I/F E117098" is of type +-"SoundBlaster" (i.e. you have to set SBPRO to 1) even with the addresses +-0x300 and above. This is unusual, and it can't get covered by the auto +-probing scheme. +-The Teac 16-bit interface cards (like P/N E950228-00A, default address 0x2C0) +-need the SBPRO 3 setup. +- +-If auto-probing found the drive, the address is correct. The reported type +-may be wrong. A "mount" will give success only if the interface type is set +-right. Playing audio should work with a wrong set interface type, too. +- +-With some Teac and some CD200 drives I have seen interface cards which seem +-to lack the "drive select" lines; always drive 0 gets addressed. To avoid +-"mirror drives" (four drives detected where you only have one) with such +-interface cards, set MAX_DRIVES to 1 and jumper your drive to ID 0 (if +-possible). +- +- +-Up to 4 drives per interface card, and up to 4 interface cards are supported. +-All supported drive families can be mixed, but the CR-521 drives are +-hard-wired to drive ID 0. The drives have to use different drive IDs, and each +-drive has to get a unique minor number (0...3), corresponding indirectly to +-its drive ID. +-The drive IDs may be selected freely from 0 to 3 - they do not have to be in +-consecutive order. +- +-As Don Carroll, don@ds9.us.dell.com or FIDO 1:382/14, told me, it is possible +-to change old drives to any ID, too. He writes in this sense: +- "In order to be able to use more than one single speed drive +- (they do not have the ID jumpers) you must add a DIP switch +- and two resistors. The pads are already on the board next to +- the power connector. You will see the silkscreen for the +- switch if you remove the top cover. +- 1 2 3 4 +- ID 0 = x F F x O = "on" +- ID 1 = x O F x F = "off" +- ID 2 = x F O x x = "don't care" +- ID 3 = x O O x +- Next to the switch are the positions for R76 (7k) and R78 +- (12k). I had to play around with the resistor values - ID 3 +- did not work with other values. If the values are not good, +- ID 3 behaves like ID 0." +- +-To use more than 4 drives, you simply need a second controller card at a +-different address and a second cable. +- +-The driver supports reading of data from the CD and playing of audio tracks. +-The audio part should run with WorkMan, xcdplayer, with the "non-X11" products +-CDplayer and WorkBone - tell me if it is not compatible with other software. +-The only accepted measure for correctness with the audio functions is the +-"cdtester" utility (appended) - most audio player programmers seem to be +-better musicians than programmers. ;-) +- +-With the CR-56x and the CD200 drives, the reading of audio frames is possible. +-This is implemented by an IOCTL function which reads READ_AUDIO frames of +-2352 bytes at once (configurable with the "READ_AUDIO" define, default is 0). +-Reading the same frame a second time gives different data; the frame data +-start at a different position, but all read bytes are valid, and we always +-read 98 consecutive chunks (of 24 Bytes) as a frame. Reading more than 1 frame +-at once possibly misses some chunks at each frame boundary. This lack has to +-get corrected by external, "higher level" software which reads the same frame +-again and tries to find and eliminate overlapping chunks (24-byte-pieces). +- +-The transfer rate with reading audio (1-frame-pieces) currently is very slow. +-This can be better reading bigger chunks, but the "missing" chunks possibly +-occur at the beginning of each single frame. +-The software interface possibly may change a bit the day the SCSI driver +-supports it too. +- +-With all but the CR-52x drives, MultiSession is supported. +-Photo CDs work (the "old" drives like CR-521 can access only the first +-session of a photoCD). +-At ftp.gwdg.de:/pub/linux/hpcdtoppm/ you will find Hadmut Danisch's package to +-convert photo CD image files and Gerd Knorr's viewing utility. +- +-The transfer rate will reach 150 kB/sec with CR-52x drives, 300 kB/sec with +-CR-56x drives, and currently not more than 500 kB/sec (usually less than +-250 kB/sec) with the Teac quad speed drives. +-XA (PhotoCD) disks with "old" drives give only 50 kB/sec. +- +-This release consists of +-- this README file +-- the driver file linux/drivers/cdrom/sbpcd.c +-- the stub files linux/drivers/cdrom/sbpcd[234].c +-- the header file linux/drivers/cdrom/sbpcd.h. +- +- +-To install: +------------ +- +-1. Setup your hardware parameters. Though the driver does "auto-probing" at a +- lot of (not all possible!) addresses, this step is recommended for +- everyday use. You should let sbpcd auto-probe once and use the reported +- address if a drive got found. The reported type may be incorrect; it is +- correct if you can mount a data CD. There is no choice for you with the +- type; only one is right, the others are deadly wrong. +- +- a. Go into /usr/src/linux/drivers/cdrom/sbpcd.h and configure it for your +- hardware (near the beginning): +- a1. Set it up for the appropriate type of interface board. +- "Original" CreativeLabs sound cards need "SBPRO 1". +- Most "compatible" sound cards (almost all "non-CreativeLabs" cards) +- need "SBPRO 0". +- The "no-sound" board from OmniCd needs the "SBPRO 1" setup. +- The Teac 8-bit "no-sound" boards need the "SBPRO 1" setup. +- The Teac 16-bit "no-sound" boards need the "SBPRO 3" setup. +- All other "no-sound" boards need the "SBPRO 0" setup. +- The Spea Media FX and Ensoniq SoundScape cards need "SBPRO 2". +- sbpcd.c holds some examples in its auto-probe list. +- If you configure "SBPRO" wrong, the playing of audio CDs will work, +- but you will not be able to mount a data CD. +- a2. Tell the address of your CDROM_PORT (not of the sound port). +- a3. If 4 drives get found, but you have only one, set MAX_DRIVES to 1. +- a4. Set DISTRIBUTION to 0. +- b. Additionally for 2.a1 and 2.a2, the setup may be done during +- boot time (via the "kernel command line" or "LILO option"): +- sbpcd=0x320,LaserMate +- or +- sbpcd=0x230,SoundBlaster +- or +- sbpcd=0x338,SoundScape +- or +- sbpcd=0x2C0,Teac16bit +- This is especially useful if you install a fresh distribution. +- If the second parameter is a number, it gets taken as the type +- setting; 0 is "LaserMate", 1 is "SoundBlaster", 2 is "SoundScape", +- 3 is "Teac16bit". +- So, for example +- sbpcd=0x230,1 +- is equivalent to +- sbpcd=0x230,SoundBlaster +- +-2. "cd /usr/src/linux" and do a "make config" and select "y" for Matsushita +- CD-ROM support and for ISO9660 FileSystem support. If you do not have a +- second, third, or fourth controller installed, do not say "y" to the +- secondary Matsushita CD-ROM questions. +- +-3. Then make the kernel image ("make zlilo" or similar). +- +-4. Make the device file(s). This step usually already has been done by the +- MAKEDEV script. +- The driver uses MAJOR 25, so, if necessary, do +- mknod /dev/sbpcd b 25 0 (if you have only one drive) +- and/or +- mknod /dev/sbpcd0 b 25 0 +- mknod /dev/sbpcd1 b 25 1 +- mknod /dev/sbpcd2 b 25 2 +- mknod /dev/sbpcd3 b 25 3 +- to make the node(s). +- +- The "first found" drive gets MINOR 0 (regardless of its jumpered ID), the +- "next found" (at the same cable) gets MINOR 1, ... +- +- For a second interface board, you have to make nodes like +- mknod /dev/sbpcd4 b 26 0 +- mknod /dev/sbpcd5 b 26 1 +- and so on. Use the MAJORs 26, 27, 28. +- +- If you further make a link like +- ln -s sbpcd /dev/cdrom +- you can use the name /dev/cdrom, too. +- +-5. Reboot with the new kernel. +- +-You should now be able to do +- mkdir /CD +-and +- mount -rt iso9660 /dev/sbpcd /CD +-or +- mount -rt iso9660 -o block=2048 /dev/sbpcd /CD +-and see the contents of your CD in the /CD directory. +-To use audio CDs, a mounting is not recommended (and it would fail if the +-first track is not a data track). +- +- +-Using sbpcd as a "loadable module": +------------------------------------ +- +-If you do NOT select "Matsushita/Panasonic CDROM driver support" during the +-"make config" of your kernel, you can build the "loadable module" sbpcd.o. +- +-If sbpcd gets used as a module, the support of more than one interface +-card (i.e. drives 4...15) is disabled. +- +-You can specify interface address and type with the "insmod" command like: +- # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x340,0 +-or +- # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x230,1 +-or +- # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x338,2 +-where the last number represents the SBPRO setting (no strings allowed here). +- +- +-Things of interest: +-------------------- +- +-The driver is configured to try the LaserMate type of interface at I/O port +-0x0340 first. If this is not appropriate, sbpcd.h should get changed +-(you will find the right place - just at the beginning). +- +-No DMA and no IRQ is used. +- +-To reduce or increase the amount of kernel messages, edit sbpcd.c and play +-with the "DBG_xxx" switches (initialization of the variable "sbpcd_debug"). +-Don't forget to reflect on what you do; enabling all DBG_xxx switches at once +-may crash your system, and each message line is accompanied by a delay. +- +-The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to +-specify "block=2048" as a mount option. Doing this will disable the direct +-execution of a binary from the CD; you have to copy it to a device with the +-standard BLOCK_SIZE (1024) first. So, do not use this if your system is +-directly "running from the CDROM" (like some of Yggdrasil's installation +-variants). There are CDs on the market (like the German "unifix" Linux +-distribution) which MUST get handled with a block_size of 1024. Generally, +-one can say all the CDs which hold files of the name YMTRANS.TBL are defective; +-do not use block=2048 with those. +- +-Within sbpcd.h, you will find some "#define"s (e.g. EJECT and JUKEBOX). With +-these, you can configure the driver for some special things. +-You can use the appended program "cdtester" to set the auto-eject feature +-during runtime. Jeff Tranter's "eject" utility can do this, too (and more) +-for you. +- +-There is an ioctl CDROMMULTISESSION to obtain with a user program if +-the CD is an XA disk and - if it is - where the last session starts. The +-"cdtester" program illustrates how to call it. +- +- +-Auto-probing at boot time: +--------------------------- +- +-The driver does auto-probing at many well-known interface card addresses, +-but not all: +-Some probings can cause a hang if an NE2000 ethernet card gets touched, because +-SBPCD's auto-probing happens before the initialization of the net drivers. +-Those "hazardous" addresses are excluded from auto-probing; the "kernel +-command line" feature has to be used during installation if you have your +-drive at those addresses. The "module" version is allowed to probe at those +-addresses, too. +- +-The auto-probing looks first at the configured address resp. the address +-submitted by the kernel command line. With this, it is possible to use this +-driver within installation boot floppies, and for any non-standard address, +-too. +- +-Auto-probing will make an assumption about the interface type ("SBPRO" or not), +-based upon the address. That assumption may be wrong (initialization will be +-o.k., but you will get I/O errors during mount). In that case, use the "kernel +-command line" feature and specify address & type at boot time to find out the +-right setup. +- +-For everyday use, address and type should get configured within sbpcd.h. That +-will stop the auto-probing due to success with the first try. +- +-The kernel command "sbpcd=0" suppresses each auto-probing and causes +-the driver not to find any drive; it is meant for people who love sbpcd +-so much that they do not want to miss it, even if they miss the drives. ;-) +- +-If you configure "#define CDROM_PORT 0" in sbpcd.h, the auto-probing is +-initially disabled and needs an explicit kernel command to get activated. +-Once activated, it does not stop before success or end-of-list. This may be +-useful within "universal" CDROM installation boot floppies (but using the +-loadable module would be better because it allows an "extended" auto-probing +-without fearing NE2000 cards). +- +-To shorten the auto-probing list to a single entry, set DISTRIBUTION 0 within +-sbpcd.h. +- +- +-Setting up address and interface type: +--------------------------------------- +- +-If your I/O port address is not 0x340, you have to look for the #defines near +-the beginning of sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and +-change CDROM_PORT to the address of your CDROM I/O port. +- +-Almost all of the "SoundBlaster compatible" cards behave like the no-sound +-interfaces, i.e. need SBPRO 0! +- +-With "original" SB Pro cards, an initial setting of CD_volume through the +-sound card's MIXER register gets done. +-If you are using a "compatible" sound card of types "LaserMate" or "SPEA", +-you can set SOUND_BASE (in sbpcd.h) to get it done with your card, too... +- +- +-Using audio CDs: +----------------- +- +-Workman, WorkBone, xcdplayer, cdplayer and the nice little tool "cdplay" (see +-README.aztcd from the Aztech driver package) should work. +- +-The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer wants +-"/dev/rsr0", workman loves "/dev/sr0" or "/dev/cdrom" - so, make the +-appropriate links to use them without the need to supply parameters. +- +- +-Copying audio tracks: +---------------------- +- +-The following program will copy track 1 (or a piece of it) from an audio CD +-into the file "track01": +- +-/*=================== begin program ========================================*/ +-/* +- * read an audio track from a CD +- * +- * (c) 1994 Eberhard Moenkeberg +- * may be used & enhanced freely +- * +- * Due to non-existent sync bytes at the beginning of each audio frame (or due +- * to a firmware bug within all known drives?), it is currently a kind of +- * fortune if two consecutive frames fit together. +- * Usually, they overlap, or a little piece is missing. This happens in units +- * of 24-byte chunks. It has to get fixed by higher-level software (reading +- * until an overlap occurs, and then eliminate the overlapping chunks). +- * ftp.gwdg.de:/pub/linux/misc/cdda2wav-sbpcd.*.tar.gz holds an example of +- * such an algorithm. +- * This example program further is missing to obtain the SubChannel data +- * which belong to each frame. +- * +- * This is only an example of the low-level access routine. The read data are +- * pure 16-bit CDDA values; they have to get converted to make sound out of +- * them. +- * It is no fun to listen to it without prior overlap/underlap correction! +- */ +-#include +-#include +-#include +-#include +- +-static struct cdrom_tochdr hdr; +-static struct cdrom_tocentry entry[101]; +-static struct cdrom_read_audio arg; +-static u_char buffer[CD_FRAMESIZE_RAW]; +-static int datafile, drive; +-static int i, j, limit, track, err; +-static char filename[32]; +- +-int main(int argc, char *argv[]) +-{ +-/* +- * open /dev/cdrom +- */ +- drive=open("/dev/cdrom", 0); +- if (drive<0) +- { +- fprintf(stderr, "can't open drive.\n"); +- exit (-1); +- } +-/* +- * get TocHeader +- */ +- fprintf(stdout, "getting TocHeader...\n"); +- err=ioctl(drive, CDROMREADTOCHDR, &hdr); +- if (err!=0) +- { +- fprintf(stderr, "can't get TocHeader (error %d).\n", err); +- exit (-1); +- } +- else +- fprintf(stdout, "TocHeader: %d %d\n", hdr.cdth_trk0, hdr.cdth_trk1); +-/* +- * get and display all TocEntries +- */ +- fprintf(stdout, "getting TocEntries...\n"); +- for (i=1;i<=hdr.cdth_trk1+1;i++) +- { +- if (i!=hdr.cdth_trk1+1) entry[i].cdte_track = i; +- else entry[i].cdte_track = CDROM_LEADOUT; +- entry[i].cdte_format = CDROM_LBA; +- err=ioctl(drive, CDROMREADTOCENTRY, &entry[i]); +- if (err!=0) +- { +- fprintf(stderr, "can't get TocEntry #%d (error %d).\n", i, err); +- exit (-1); +- } +- else +- { +- fprintf(stdout, "TocEntry #%d: %1X %1X %06X %02X\n", +- entry[i].cdte_track, +- entry[i].cdte_adr, +- entry[i].cdte_ctrl, +- entry[i].cdte_addr.lba, +- entry[i].cdte_datamode); +- } +- } +- fprintf(stdout, "got all TocEntries.\n"); +-/* +- * ask for track number (not implemented here) +- */ +-track=1; +-#if 0 /* just read a little piece (4 seconds) */ +-entry[track+1].cdte_addr.lba=entry[track].cdte_addr.lba+300; +-#endif +-/* +- * read track into file +- */ +- sprintf(filename, "track%02d\0", track); +- datafile=creat(filename, 0755); +- if (datafile<0) +- { +- fprintf(stderr, "can't open datafile %s.\n", filename); +- exit (-1); +- } +- arg.addr.lba=entry[track].cdte_addr.lba; +- arg.addr_format=CDROM_LBA; /* CDROM_MSF would be possible here, too. */ +- arg.nframes=1; +- arg.buf=&buffer[0]; +- limit=entry[track+1].cdte_addr.lba; +- for (;arg.addr.lba +- * published under the GPL +- * +- * made under heavy use of the "Tiny Audio CD Player" +- * from Werner Zimmermann +- * (see linux/drivers/block/README.aztcd) +- */ +-#undef AZT_PRIVATE_IOCTLS /* not supported by every CDROM driver */ +-#define SBP_PRIVATE_IOCTLS /* not supported by every CDROM driver */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#ifdef AZT_PRIVATE_IOCTLS +-#include +-#endif /* AZT_PRIVATE_IOCTLS */ +-#ifdef SBP_PRIVATE_IOCTLS +-#include +-#include +-#endif /* SBP_PRIVATE_IOCTLS */ +- +-struct cdrom_tochdr hdr; +-struct cdrom_tochdr tocHdr; +-struct cdrom_tocentry TocEntry[101]; +-struct cdrom_tocentry entry; +-struct cdrom_multisession ms_info; +-struct cdrom_read_audio read_audio; +-struct cdrom_ti ti; +-struct cdrom_subchnl subchnl; +-struct cdrom_msf msf; +-struct cdrom_volctrl volctrl; +-#ifdef AZT_PRIVATE_IOCTLS +-union +-{ +- struct cdrom_msf msf; +- unsigned char buf[CD_FRAMESIZE_RAW]; +-} azt; +-#endif /* AZT_PRIVATE_IOCTLS */ +-int i, i1, i2, i3, j, k; +-unsigned char sequence=0; +-unsigned char command[80]; +-unsigned char first=1, last=1; +-char *default_device="/dev/cdrom"; +-char dev[20]; +-char filename[20]; +-int drive; +-int datafile; +-int rc; +- +-void help(void) +-{ +- printf("Available Commands:\n"); +- printf("STOP s EJECT e QUIT q\n"); +- printf("PLAY TRACK t PAUSE p RESUME r\n"); +- printf("NEXT TRACK n REPEAT LAST l HELP h\n"); +- printf("SUBCHANNEL_Q c TRACK INFO i PLAY AT a\n"); +- printf("READ d READ RAW w READ AUDIO A\n"); +- printf("MS-INFO M TOC T START S\n"); +- printf("SET EJECTSW X DEVICE D DEBUG Y\n"); +- printf("AUDIO_BUFSIZ Z RESET R SET VOLUME v\n"); +- printf("GET VOLUME V\n"); +-} +- +-/* +- * convert MSF number (3 bytes only) to Logical_Block_Address +- */ +-int msf2lba(u_char *msf) +-{ +- int i; +- +- i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_BLOCK_OFFSET; +- if (i<0) return (0); +- return (i); +-} +-/* +- * convert logical_block_address to m-s-f_number (3 bytes only) +- */ +-void lba2msf(int lba, unsigned char *msf) +-{ +- lba += CD_BLOCK_OFFSET; +- msf[0] = lba / (CD_SECS*CD_FRAMES); +- lba %= CD_SECS*CD_FRAMES; +- msf[1] = lba / CD_FRAMES; +- msf[2] = lba % CD_FRAMES; +-} +- +-int init_drive(char *dev) +-{ +- unsigned char msf_ent[3]; +- +- /* +- * open the device +- */ +- drive=open(dev,0); +- if (drive<0) return (-1); +- /* +- * get TocHeader +- */ +- printf("getting TocHeader...\n"); +- rc=ioctl(drive,CDROMREADTOCHDR,&hdr); +- if (rc!=0) +- { +- printf("can't get TocHeader (error %d).\n",rc); +- return (-2); +- } +- else +- first=hdr.cdth_trk0; +- last=hdr.cdth_trk1; +- printf("TocHeader: %d %d\n",hdr.cdth_trk0,hdr.cdth_trk1); +- /* +- * get and display all TocEntries +- */ +- printf("getting TocEntries...\n"); +- for (i=1;i<=hdr.cdth_trk1+1;i++) +- { +- if (i!=hdr.cdth_trk1+1) TocEntry[i].cdte_track = i; +- else TocEntry[i].cdte_track = CDROM_LEADOUT; +- TocEntry[i].cdte_format = CDROM_LBA; +- rc=ioctl(drive,CDROMREADTOCENTRY,&TocEntry[i]); +- if (rc!=0) +- { +- printf("can't get TocEntry #%d (error %d).\n",i,rc); +- } +- else +- { +- lba2msf(TocEntry[i].cdte_addr.lba,&msf_ent[0]); +- if (TocEntry[i].cdte_track==CDROM_LEADOUT) +- { +- printf("TocEntry #%02X: %1X %1X %02d:%02d:%02d (lba: 0x%06X) %02X\n", +- TocEntry[i].cdte_track, +- TocEntry[i].cdte_adr, +- TocEntry[i].cdte_ctrl, +- msf_ent[0], +- msf_ent[1], +- msf_ent[2], +- TocEntry[i].cdte_addr.lba, +- TocEntry[i].cdte_datamode); +- } +- else +- { +- printf("TocEntry #%02d: %1X %1X %02d:%02d:%02d (lba: 0x%06X) %02X\n", +- TocEntry[i].cdte_track, +- TocEntry[i].cdte_adr, +- TocEntry[i].cdte_ctrl, +- msf_ent[0], +- msf_ent[1], +- msf_ent[2], +- TocEntry[i].cdte_addr.lba, +- TocEntry[i].cdte_datamode); +- } +- } +- } +- return (hdr.cdth_trk1); /* number of tracks */ +-} +- +-void display(int size,unsigned char *buffer) +-{ +- k=0; +- getchar(); +- for (i=0;i<(size+1)/16;i++) +- { +- printf("%4d:",i*16); +- for (j=0;j<16;j++) +- { +- printf(" %02X",buffer[i*16+j]); +- } +- printf(" "); +- for (j=0;j<16;j++) +- { +- if (isalnum(buffer[i*16+j])) +- printf("%c",buffer[i*16+j]); +- else +- printf("."); +- } +- printf("\n"); +- k++; +- if (k>=20) +- { +- printf("press ENTER to continue\n"); +- getchar(); +- k=0; +- } +- } +-} +- +-int main(int argc, char *argv[]) +-{ +- printf("\nTesting tool for a CDROM driver's audio functions V0.1\n"); +- printf("(C) 1995 Eberhard Moenkeberg \n"); +- printf("initializing...\n"); +- +- rc=init_drive(default_device); +- if (rc<0) printf("could not open %s (rc=%d).\n",default_device,rc); +- help(); +- while (1) +- { +- printf("Give a one-letter command (h = help): "); +- scanf("%s",command); +- command[1]=0; +- switch (command[0]) +- { +- case 'D': +- printf("device name (f.e. /dev/sbpcd3): ? "); +- scanf("%s",&dev); +- close(drive); +- rc=init_drive(dev); +- if (rc<0) printf("could not open %s (rc %d).\n",dev,rc); +- break; +- case 'e': +- rc=ioctl(drive,CDROMEJECT); +- if (rc<0) printf("CDROMEJECT: rc=%d.\n",rc); +- break; +- case 'p': +- rc=ioctl(drive,CDROMPAUSE); +- if (rc<0) printf("CDROMPAUSE: rc=%d.\n",rc); +- break; +- case 'r': +- rc=ioctl(drive,CDROMRESUME); +- if (rc<0) printf("CDROMRESUME: rc=%d.\n",rc); +- break; +- case 's': +- rc=ioctl(drive,CDROMSTOP); +- if (rc<0) printf("CDROMSTOP: rc=%d.\n",rc); +- break; +- case 'S': +- rc=ioctl(drive,CDROMSTART); +- if (rc<0) printf("CDROMSTART: rc=%d.\n",rc); +- break; +- case 't': +- rc=ioctl(drive,CDROMREADTOCHDR,&tocHdr); +- if (rc<0) +- { +- printf("CDROMREADTOCHDR: rc=%d.\n",rc); +- break; +- } +- first=tocHdr.cdth_trk0; +- last= tocHdr.cdth_trk1; +- if ((first==0)||(first>last)) +- { +- printf ("--got invalid TOC data.\n"); +- } +- else +- { +- printf("--enter track number(first=%d, last=%d): ",first,last); +- scanf("%d",&i1); +- ti.cdti_trk0=i1; +- if (ti.cdti_trk0last) ti.cdti_trk0=last; +- ti.cdti_ind0=0; +- ti.cdti_trk1=last; +- ti.cdti_ind1=0; +- rc=ioctl(drive,CDROMSTOP); +- rc=ioctl(drive,CDROMPLAYTRKIND,&ti); +- if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc); +- } +- break; +- case 'n': +- rc=ioctl(drive,CDROMSTOP); +- if (++ti.cdti_trk0>last) ti.cdti_trk0=last; +- ti.cdti_ind0=0; +- ti.cdti_trk1=last; +- ti.cdti_ind1=0; +- rc=ioctl(drive,CDROMPLAYTRKIND,&ti); +- if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc); +- break; +- case 'l': +- rc=ioctl(drive,CDROMSTOP); +- if (--ti.cdti_trk0last) entry.cdte_track=last; +- entry.cdte_format=CDROM_MSF; +- rc=ioctl(drive,CDROMREADTOCENTRY,&entry); +- if (rc<0) printf("CDROMREADTOCENTRY: rc=%d.\n",rc); +- else +- { +- printf("Mode %d Track, starts at %02d:%02d:%02d\n", +- entry.cdte_adr, +- entry.cdte_addr.msf.minute, +- entry.cdte_addr.msf.second, +- entry.cdte_addr.msf.frame); +- } +- break; +- case 'a': +- printf("Address (min:sec:frm) "); +- scanf("%d:%d:%d",&i1,&i2,&i3); +- msf.cdmsf_min0=i1; +- msf.cdmsf_sec0=i2; +- msf.cdmsf_frame0=i3; +- if (msf.cdmsf_sec0>59) msf.cdmsf_sec0=59; +- if (msf.cdmsf_frame0>74) msf.cdmsf_frame0=74; +- lba2msf(TocEntry[last+1].cdte_addr.lba-1,&msf.cdmsf_min1); +- rc=ioctl(drive,CDROMSTOP); +- rc=ioctl(drive,CDROMPLAYMSF,&msf); +- if (rc<0) printf("CDROMPLAYMSF: rc=%d.\n",rc); +- break; +- case 'V': +- rc=ioctl(drive,CDROMVOLREAD,&volctrl); +- if (rc<0) printf("CDROMVOLCTRL: rc=%d.\n",rc); +- printf("Volume: channel 0 (left) %d, channel 1 (right) %d\n",volctrl.channel0,volctrl.channel1); +- break; +- case 'R': +- rc=ioctl(drive,CDROMRESET); +- if (rc<0) printf("CDROMRESET: rc=%d.\n",rc); +- break; +-#ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/ +- case 'd': +- printf("Address (min:sec:frm) "); +- scanf("%d:%d:%d",&i1,&i2,&i3); +- azt.msf.cdmsf_min0=i1; +- azt.msf.cdmsf_sec0=i2; +- azt.msf.cdmsf_frame0=i3; +- if (azt.msf.cdmsf_sec0>59) azt.msf.cdmsf_sec0=59; +- if (azt.msf.cdmsf_frame0>74) azt.msf.cdmsf_frame0=74; +- rc=ioctl(drive,CDROMREADMODE1,&azt.msf); +- if (rc<0) printf("CDROMREADMODE1: rc=%d.\n",rc); +- else display(CD_FRAMESIZE,azt.buf); +- break; +- case 'w': +- printf("Address (min:sec:frame) "); +- scanf("%d:%d:%d",&i1,&i2,&i3); +- azt.msf.cdmsf_min0=i1; +- azt.msf.cdmsf_sec0=i2; +- azt.msf.cdmsf_frame0=i3; +- if (azt.msf.cdmsf_sec0>59) azt.msf.cdmsf_sec0=59; +- if (azt.msf.cdmsf_frame0>74) azt.msf.cdmsf_frame0=74; +- rc=ioctl(drive,CDROMREADMODE2,&azt.msf); +- if (rc<0) printf("CDROMREADMODE2: rc=%d.\n",rc); +- else display(CD_FRAMESIZE_RAW,azt.buf); /* currently only 2336 */ +- break; +-#endif +- case 'v': +- printf("--Channel 0 (Left) (0-255): "); +- scanf("%d",&i1); +- volctrl.channel0=i1; +- printf("--Channel 1 (Right) (0-255): "); +- scanf("%d",&i1); +- volctrl.channel1=i1; +- volctrl.channel2=0; +- volctrl.channel3=0; +- rc=ioctl(drive,CDROMVOLCTRL,&volctrl); +- if (rc<0) printf("CDROMVOLCTRL: rc=%d.\n",rc); +- break; +- case 'q': +- close(drive); +- exit(0); +- case 'h': +- help(); +- break; +- case 'T': /* display TOC entry - without involving the driver */ +- scanf("%d",&i); +- if ((ihdr.cdth_trk1)) +- printf("invalid track number.\n"); +- else +- printf("TocEntry %02d: adr=%01X ctrl=%01X msf=%02d:%02d:%02d mode=%02X\n", +- TocEntry[i].cdte_track, +- TocEntry[i].cdte_adr, +- TocEntry[i].cdte_ctrl, +- TocEntry[i].cdte_addr.msf.minute, +- TocEntry[i].cdte_addr.msf.second, +- TocEntry[i].cdte_addr.msf.frame, +- TocEntry[i].cdte_datamode); +- break; +- case 'A': /* read audio data into file */ +- printf("Address (min:sec:frm) ? "); +- scanf("%d:%d:%d",&i1,&i2,&i3); +- read_audio.addr.msf.minute=i1; +- read_audio.addr.msf.second=i2; +- read_audio.addr.msf.frame=i3; +- read_audio.addr_format=CDROM_MSF; +- printf("# of frames ? "); +- scanf("%d",&i1); +- read_audio.nframes=i1; +- k=read_audio.nframes*CD_FRAMESIZE_RAW; +- read_audio.buf=malloc(k); +- if (read_audio.buf==NULL) +- { +- printf("can't malloc %d bytes.\n",k); +- break; +- } +- sprintf(filename,"audio_%02d%02d%02d_%02d.%02d\0", +- read_audio.addr.msf.minute, +- read_audio.addr.msf.second, +- read_audio.addr.msf.frame, +- read_audio.nframes, +- ++sequence); +- datafile=creat(filename, 0755); +- if (datafile<0) +- { +- printf("can't open datafile %s.\n",filename); +- break; +- } +- rc=ioctl(drive,CDROMREADAUDIO,&read_audio); +- if (rc!=0) +- { +- printf("CDROMREADAUDIO: rc=%d.\n",rc); +- } +- else +- { +- rc=write(datafile,&read_audio.buf,k); +- if (rc!=k) printf("datafile I/O error (%d).\n",rc); +- } +- close(datafile); +- break; +- case 'X': /* set EJECT_SW (0: disable, 1: enable auto-ejecting) */ +- scanf("%d",&i); +- rc=ioctl(drive,CDROMEJECT_SW,i); +- if (rc!=0) +- printf("CDROMEJECT_SW: rc=%d.\n",rc); +- else +- printf("EJECT_SW set to %d\n",i); +- break; +- case 'M': /* get the multisession redirection info */ +- ms_info.addr_format=CDROM_LBA; +- rc=ioctl(drive,CDROMMULTISESSION,&ms_info); +- if (rc!=0) +- { +- printf("CDROMMULTISESSION(lba): rc=%d.\n",rc); +- } +- else +- { +- if (ms_info.xa_flag) printf("MultiSession offset (lba): %d (0x%06X)\n",ms_info.addr.lba,ms_info.addr.lba); +- else +- { +- printf("this CD is not an XA disk.\n"); +- break; +- } +- } +- ms_info.addr_format=CDROM_MSF; +- rc=ioctl(drive,CDROMMULTISESSION,&ms_info); +- if (rc!=0) +- { +- printf("CDROMMULTISESSION(msf): rc=%d.\n",rc); +- } +- else +- { +- if (ms_info.xa_flag) +- printf("MultiSession offset (msf): %02d:%02d:%02d (0x%02X%02X%02X)\n", +- ms_info.addr.msf.minute, +- ms_info.addr.msf.second, +- ms_info.addr.msf.frame, +- ms_info.addr.msf.minute, +- ms_info.addr.msf.second, +- ms_info.addr.msf.frame); +- else printf("this CD is not an XA disk.\n"); +- } +- break; +-#ifdef SBP_PRIVATE_IOCTLS +- case 'Y': /* set the driver's message level */ +-#if 0 /* not implemented yet */ +- printf("enter switch name (f.e. DBG_CMD): "); +- scanf("%s",&dbg_switch); +- j=get_dbg_num(dbg_switch); +-#else +- printf("enter DDIOCSDBG switch number: "); +- scanf("%d",&j); +-#endif +- printf("enter 0 for \"off\", 1 for \"on\": "); +- scanf("%d",&i); +- if (i==0) j|=0x80; +- printf("calling \"ioctl(drive,DDIOCSDBG,%d)\"\n",j); +- rc=ioctl(drive,DDIOCSDBG,j); +- printf("DDIOCSDBG: rc=%d.\n",rc); +- break; +- case 'Z': /* set the audio buffer size */ +- printf("# frames wanted: ? "); +- scanf("%d",&j); +- rc=ioctl(drive,CDROMAUDIOBUFSIZ,j); +- printf("%d frames granted.\n",rc); +- break; +-#endif /* SBP_PRIVATE_IOCTLS */ +- default: +- printf("unknown command: \"%s\".\n",command); +- break; +- } +- } +- return 0; +-} +-/*==========================================================================*/ +- +diff -Nurp linux-2.6.22/Documentation/cdrom/sjcd linux-2.6-netns/Documentation/cdrom/sjcd +--- linux-2.6.22/Documentation/cdrom/sjcd 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/sjcd 1969-12-31 19:00:00.000000000 -0500 +@@ -1,60 +0,0 @@ +- -- Documentation/cdrom/sjcd +- 80% of the work takes 20% of the time, +- 20% of the work takes 80% of the time... +- (Murphy's law) +- +- Once started, training can not be stopped... +- (Star Wars) +- +-This is the README for the sjcd cdrom driver, version 1.6. +- +-This file is meant as a tips & tricks edge for the usage of the SANYO CDR-H94A +-cdrom drive. It will grow as the questions arise. ;-) +-For info on configuring the ISP16 sound card look at Documentation/cdrom/isp16. +- +-The driver should work with any of the Panasonic, Sony or Mitsumi style +-CDROM interfaces. +-The cdrom interface on Media Magic's soft configurable sound card ISP16, +-which used to be included in the driver, is now supported in a separate module. +-This initialisation module will probably also work with other interfaces +-based on an OPTi 82C928 or 82C929 chip (like MAD16 and Mozart): see the +-documentation Documentation/cdrom/isp16. +- +-The device major for sjcd is 18, and minor is 0. Create a block special +-file in your /dev directory (e.g., /dev/sjcd) with these numbers. +-(For those who don't know, being root and doing the following should do +-the trick: +- mknod -m 644 /dev/sjcd b 18 0 +-and mount the cdrom by /dev/sjcd). +- +-The default configuration parameters are: +- base address 0x340 +- no irq +- no dma +-(Actually the CDR-H94A doesn't know how to use irq and dma.) +-As of version 1.2, setting base address at boot time is supported +-through the use of command line options: type at the "boot:" prompt: +- linux sjcd= +-(where you would use the kernel labeled "linux" in lilo's configuration +-file /etc/lilo.conf). You could also use 'append="sjcd="' +-in the appropriate section of /etc/lilo.conf +-If you're building a kernel yourself you can set your default base +-i/o address with SJCD_BASE_ADDR in /usr/src/linux/drivers/cdrom/sjcd.h. +- +-The sjcd driver supports being loaded as a module. The following +-command will set the base i/o address on the fly (assuming you +-have installed the module in an appropriate place). +- insmod sjcd.o sjcd_base= +- +- +-Have fun! +- +-If something is wrong, please email to vadim@rbrf.ru +- or vadim@ipsun.ras.ru +- or model@cecmow.enet.dec.com +- or H.T.M.v.d.Maarel@marin.nl +- +-It happens sometimes that Vadim is not reachable by mail. For these +-instances, Eric van der Maarel will help too. +- +- Vadim V. Model, Eric van der Maarel, Eberhard Moenkeberg +diff -Nurp linux-2.6.22/Documentation/cdrom/sonycd535 linux-2.6-netns/Documentation/cdrom/sonycd535 +--- linux-2.6.22/Documentation/cdrom/sonycd535 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/cdrom/sonycd535 1969-12-31 19:00:00.000000000 -0500 +@@ -1,122 +0,0 @@ +- README FOR LINUX SONY CDU-535/531 DRIVER +- ======================================== +- +-This is the Sony CDU-535 (and 531) driver version 0.7 for Linux. +-I do not think I have the documentation to add features like DMA support +-so if anyone else wants to pursue it or help me with it, please do. +-(I need to see what was done for the CDU-31A driver -- perhaps I can +-steal some of that code.) +- +-This is a Linux device driver for the Sony CDU-535 CDROM drive. This is +-one of the older Sony drives with its own interface card (Sony bus). +-The DOS driver for this drive is named SONY_CDU.SYS - when you boot DOS +-your drive should be identified as a SONY CDU-535. The driver works +-with a CDU-531 also. One user reported that the driver worked on drives +-OEM'ed by Procomm, drive and interface board were labelled Procomm. +- +-The Linux driver is based on Corey Minyard's sonycd 0.3 driver for +-the CDU-31A. Ron Jeppesen just changed the commands that were sent +-to the drive to correspond to the CDU-535 commands and registers. +-There were enough changes to let bugs creep in but it seems to be stable. +-Ron was able to tar an entire CDROM (should read all blocks) and built +-ghostview and xfig off Walnut Creek's X11R5/GNU CDROM. xcdplayer and +-workman work with the driver. Others have used the driver without +-problems except those dealing with wait loops (fixed in third release). +-Like Minyard's original driver this one uses a polled interface (this +-is also the default setup for the DOS driver). It has not been tried +-with interrupts or DMA enabled on the board. +- +-REQUIREMENTS +-============ +- +- - Sony CDU-535 drive, preferably without interrupts and DMA +- enabled on the card. +- +- - Drive must be set up as unit 1. Only the first unit will be +- recognized +- +- - You must enter your interface address into +- /usr/src/linux/drivers/cdrom/sonycd535.h and build the +- appropriate kernel or use the "kernel command line" parameter +- sonycd535=0x320 +- with the correct interface address. +- +-NOTES: +-====== +- +-1) The drive MUST be turned on when booting or it will not be recognized! +- (but see comments on modularized version below) +- +-2) when the cdrom device is opened the eject button is disabled to keep the +- user from ejecting a mounted disk and replacing it with another. +- Unfortunately xcdplayer and workman also open the cdrom device so you +- have to use the eject button in the software. Keep this in mind if your +- cdrom player refuses to give up its disk -- exit workman or xcdplayer, or +- umount the drive if it has been mounted. +- +-THANKS +-====== +- +-Many thanks to Ron Jeppesen (ronj.an@site007.saic.com) for getting +-this project off the ground. He wrote the initial release +-and the first two patches to this driver (0.1, 0.2, and 0.3). +-Thanks also to Eberhard Moenkeberg (emoenke@gwdg.de) for prodding +-me to place this code into the mainstream Linux source tree +-(as of Linux version 1.1.91), as well as some patches to make +-it a better device citizen. Further thanks to Joel Katz +- for his MODULE patches (see details below), +-Porfiri Claudio for patches +-to make the driver work with the older CDU-510/515 series, and +-Heiko Eissfeldt for pointing out that +-the verify_area() checks were ignoring the results of said checks +-(note: verify_area() has since been replaced by access_ok()). +- +-(Acknowledgments from Ron Jeppesen in the 0.3 release:) +-Thanks to Corey Minyard who wrote the original CDU-31A driver on which +-this driver is based. Thanks to Ken Pizzini and Bob Blair who provided +-patches and feedback on the first release of this driver. +- +-Ken Pizzini +-ken@halcyon.com +- +------------------------------------------------------------------------------- +-(The following is from Joel Katz .) +- +- To build a version of sony535.o that can be installed as a module, +-use the following command: +- +-gcc -c -D__KERNEL__ -DMODULE -O2 sonycd535.c -o sonycd535.o +- +- To install the module, simply type: +- +-insmod sony535.o +- or +-insmod sony535.o sonycd535=
+- +- And to remove it: +- +-rmmod sony535 +- +- The code checks to see if MODULE is defined and behaves as it used +-to if MODULE is not defined. That means your patched file should behave +-exactly as it used to if compiled into the kernel. +- +- I have an external drive, and I usually leave it powered off. I used +-to have to reboot if I needed to use the CDROM drive. Now I don't. +- +- Even if you have an internal drive, why waste the 96K of memory +-(unswappable) that the driver uses if you use your CD-ROM drive infrequently? +- +- This driver will not install (whether compiled in or loaded as a +-module) if the CDROM drive is not available during its initialization. This +-means that you can have the driver compiled into the kernel and still load +-the module later (assuming the driver doesn't install itself during +-power-on). This only wastes 12K when you boot with the CDROM drive off. +- +- This is what I usually do; I leave the driver compiled into the +-kernel, but load it as a module if I powered the system up with the drive +-off and then later decided to use the CDROM drive. +- +- Since the driver only uses a single page to point to the chunks, +-attempting to set the buffer cache to more than 2 Megabytes would be very +-bad; don't do that. +diff -Nurp linux-2.6.22/Documentation/driver-model/devres.txt linux-2.6-netns/Documentation/driver-model/devres.txt +--- linux-2.6.22/Documentation/driver-model/devres.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/driver-model/devres.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -207,7 +207,7 @@ responsibility. This is usually non-iss + resource allocations already do the job. + + For an example of single-instance devres type, read pcim_iomap_table() +-in lib/iomap.c. ++in lib/devres.c. + + All devres interface functions can be called without context if the + right gfp mask is given. +diff -Nurp linux-2.6.22/Documentation/dvb/bt8xx.txt linux-2.6-netns/Documentation/dvb/bt8xx.txt +--- linux-2.6.22/Documentation/dvb/bt8xx.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/dvb/bt8xx.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -9,19 +9,29 @@ for accessing the i2c bus and the gpio p + Please see Documentation/dvb/cards.txt => o Cards based on the Conexant Bt8xx PCI bridge: + + Compiling kernel please enable: +-a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "BT848 Video For Linux" +-b.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" +- => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards" ++a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "Enable Video for Linux API 1 (DEPRECATED)" ++b.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "Video Capture Adapters" => "BT848 Video For Linux" ++c.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards" ++ ++Please use the following options with care as deselection of drivers which are in fact necessary ++may result in DVB devices that cannot be tuned due to lack of driver support: ++You can save RAM by deselecting every frontend module that your DVB card does not need. ++ ++First please remove the static dependency of DVB card drivers on all frontend modules for all possible card variants by enabling: ++d.) "Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" ++ => "DVB for Linux" "DVB Core Support" "Load and attach frontend modules as needed" ++ ++If you know the frontend driver that your card needs please enable: ++e.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" ++ => "DVB for Linux" "DVB Core Support" "Customise DVB Frontends" => "Customise the frontend modules to build" ++ Then please select your card-specific frontend module. + + 2) Loading Modules + ================== + +-In default cases bttv is loaded automatically. +-To load the backend either place dvb-bt8xx in etc/modules, or apply manually: +- +- $ modprobe dvb-bt8xx +- +-All frontends will be loaded automatically. ++Regular case: If the bttv driver detects a bt8xx-based DVB card, all frontend and backend modules will be loaded automatically. ++Exceptions are: ++- Old TwinHan DST cards or clones with or without CA slot and not containing an Eeprom. + People running udev please see Documentation/dvb/udev.txt. + + In the following cases overriding the PCI type detection for dvb-bt8xx might be necessary: +@@ -30,7 +40,6 @@ In the following cases overriding the PC + ------------------------------ + + $ modprobe bttv card=113 +- $ modprobe dvb-bt8xx + $ modprobe dst + + Useful parameters for verbosity level and debugging the dst module: +@@ -65,10 +74,9 @@ DViCO FusionHDTV 5 Lite: 135 + Notice: The order of the card ID should be uprising: + Example: + $ modprobe bttv card=113 card=135 +- $ modprobe dvb-bt8xx + + For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv. +-In case of further problems send questions to the mailing list: www.linuxdvb.org. ++In case of further problems please subscribe and send questions to the mailing list: linux-dvb@linuxtv.org. + + Authors: Richard Walker, + Jamie Honan, +diff -Nurp linux-2.6.22/Documentation/dvb/get_dvb_firmware linux-2.6-netns/Documentation/dvb/get_dvb_firmware +--- linux-2.6.22/Documentation/dvb/get_dvb_firmware 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/dvb/get_dvb_firmware 2007-12-03 23:14:12.000000000 -0500 +@@ -24,7 +24,8 @@ use IO::Handle; + @components = ( "sp8870", "sp887x", "tda10045", "tda10046", + "tda10046lifeview", "av7110", "dec2000t", "dec2540t", + "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004", +- "or51211", "or51132_qam", "or51132_vsb", "bluebird"); ++ "or51211", "or51132_qam", "or51132_vsb", "bluebird", ++ "opera1"); + + # Check args + syntax() if (scalar(@ARGV) != 1); +@@ -56,7 +57,7 @@ syntax(); + + sub sp8870 { + my $sourcefile = "tt_Premium_217g.zip"; +- my $url = "http://www.technotrend.de/new/217g/$sourcefile"; ++ my $url = "http://www.softwarepatch.pl/9999ccd06a4813cb827dbb0005071c71/$sourcefile"; + my $hash = "53970ec17a538945a6d8cb608a7b3899"; + my $outfile = "dvb-fe-sp8870.fw"; + my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); +@@ -210,6 +211,45 @@ sub dec3000s { + + $outfile; + } ++sub opera1{ ++ my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0); ++ ++ checkstandard(); ++ my $fwfile1="dvb-usb-opera1-fpga-01.fw"; ++ my $fwfile2="dvb-usb-opera-01.fw"; ++ extract("2830SCap2.sys", 0x62e8, 55024, "$tmpdir/opera1-fpga.fw"); ++ extract("2830SLoad2.sys",0x3178,0x3685-0x3178,"$tmpdir/fw1part1"); ++ extract("2830SLoad2.sys",0x0980,0x3150-0x0980,"$tmpdir/fw1part2"); ++ delzero("$tmpdir/fw1part1","$tmpdir/fw1part1-1"); ++ delzero("$tmpdir/fw1part2","$tmpdir/fw1part2-1"); ++ verify("$tmpdir/fw1part1-1","5e0909858fdf0b5b09ad48b9fe622e70"); ++ verify("$tmpdir/fw1part2-1","d6e146f321427e931df2c6fcadac37a1"); ++ verify("$tmpdir/opera1-fpga.fw","0f8133f5e9051f5f3c1928f7e5a1b07d"); ++ ++ my $RES1="\x01\x92\x7f\x00\x01\x00"; ++ my $RES0="\x01\x92\x7f\x00\x00\x00"; ++ my $DAT1="\x01\x00\xe6\x00\x01\x00"; ++ my $DAT0="\x01\x00\xe6\x00\x00\x00"; ++ open FW,">$tmpdir/opera.fw"; ++ print FW "$RES1"; ++ print FW "$DAT1"; ++ print FW "$RES1"; ++ print FW "$DAT1"; ++ appendfile(FW,"$tmpdir/fw1part1-1"); ++ print FW "$RES0"; ++ print FW "$DAT0"; ++ print FW "$RES1"; ++ print FW "$DAT1"; ++ appendfile(FW,"$tmpdir/fw1part2-1"); ++ print FW "$RES1"; ++ print FW "$DAT1"; ++ print FW "$RES0"; ++ print FW "$DAT0"; ++ copy ("$tmpdir/opera1-fpga.fw",$fwfile1); ++ copy ("$tmpdir/opera.fw",$fwfile2); ++ ++ $fwfile1.",".$fwfile2; ++} + + sub vp7041 { + my $sourcefile = "2.422.zip"; +@@ -440,6 +480,25 @@ sub appendfile { + close(INFILE); + } + ++sub delzero{ ++ my ($infile,$outfile) =@_; ++ ++ open INFILE,"<$infile"; ++ open OUTFILE,">$outfile"; ++ while (1){ ++ $rcount=sysread(INFILE,$buf,22); ++ $len=ord(substr($buf,0,1)); ++ print OUTFILE substr($buf,0,1); ++ print OUTFILE substr($buf,2,$len+3); ++ last if ($rcount<1); ++ printf OUTFILE "%c",0; ++#print $len." ".length($buf)."\n"; ++ ++ } ++ close(INFILE); ++ close(OUTFILE); ++} ++ + sub syntax() { + print STDERR "syntax: get_dvb_firmware \n"; + print STDERR "Supported components:\n"; +diff -Nurp linux-2.6.22/Documentation/dvb/opera-firmware.txt linux-2.6-netns/Documentation/dvb/opera-firmware.txt +--- linux-2.6.22/Documentation/dvb/opera-firmware.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/dvb/opera-firmware.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,27 @@ ++To extract the firmware for the Opera DVB-S1 USB-Box ++you need to copy the files: ++ ++2830SCap2.sys ++2830SLoad2.sys ++ ++from the windriver disk into this directory. ++ ++Then run ++ ++./get_dvb_firware opera1 ++ ++and after that you have 2 files: ++ ++dvb-usb-opera-01.fw ++dvb-usb-opera1-fpga-01.fw ++ ++in here. ++ ++Copy them into /lib/firmware/ . ++ ++After that the driver can load the firmware ++(if you have enabled firmware loading ++in kernel config and have hotplug running). ++ ++ ++Marco Gittler +\ No newline at end of file +diff -Nurp linux-2.6.22/Documentation/ecryptfs.txt linux-2.6-netns/Documentation/ecryptfs.txt +--- linux-2.6.22/Documentation/ecryptfs.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/ecryptfs.txt 1969-12-31 19:00:00.000000000 -0500 +@@ -1,77 +0,0 @@ +-eCryptfs: A stacked cryptographic filesystem for Linux +- +-eCryptfs is free software. Please see the file COPYING for details. +-For documentation, please see the files in the doc/ subdirectory. For +-building and installation instructions please see the INSTALL file. +- +-Maintainer: Phillip Hellewell +-Lead developer: Michael A. Halcrow +-Developers: Michael C. Thompson +- Kent Yoder +-Web Site: http://ecryptfs.sf.net +- +-This software is currently undergoing development. Make sure to +-maintain a backup copy of any data you write into eCryptfs. +- +-eCryptfs requires the userspace tools downloadable from the +-SourceForge site: +- +-http://sourceforge.net/projects/ecryptfs/ +- +-Userspace requirements include: +- - David Howells' userspace keyring headers and libraries (version +- 1.0 or higher), obtainable from +- http://people.redhat.com/~dhowells/keyutils/ +- - Libgcrypt +- +- +-NOTES +- +-In the beta/experimental releases of eCryptfs, when you upgrade +-eCryptfs, you should copy the files to an unencrypted location and +-then copy the files back into the new eCryptfs mount to migrate the +-files. +- +- +-MOUNT-WIDE PASSPHRASE +- +-Create a new directory into which eCryptfs will write its encrypted +-files (i.e., /root/crypt). Then, create the mount point directory +-(i.e., /mnt/crypt). Now it's time to mount eCryptfs: +- +-mount -t ecryptfs /root/crypt /mnt/crypt +- +-You should be prompted for a passphrase and a salt (the salt may be +-blank). +- +-Try writing a new file: +- +-echo "Hello, World" > /mnt/crypt/hello.txt +- +-The operation will complete. Notice that there is a new file in +-/root/crypt that is at least 12288 bytes in size (depending on your +-host page size). This is the encrypted underlying file for what you +-just wrote. To test reading, from start to finish, you need to clear +-the user session keyring: +- +-keyctl clear @u +- +-Then umount /mnt/crypt and mount again per the instructions given +-above. +- +-cat /mnt/crypt/hello.txt +- +- +-NOTES +- +-eCryptfs version 0.1 should only be mounted on (1) empty directories +-or (2) directories containing files only created by eCryptfs. If you +-mount a directory that has pre-existing files not created by eCryptfs, +-then behavior is undefined. Do not run eCryptfs in higher verbosity +-levels unless you are doing so for the sole purpose of debugging or +-development, since secret values will be written out to the system log +-in that case. +- +- +-Mike Halcrow +-mhalcrow@us.ibm.com +diff -Nurp linux-2.6.22/Documentation/fault-injection/failcmd.sh linux-2.6-netns/Documentation/fault-injection/failcmd.sh +--- linux-2.6.22/Documentation/fault-injection/failcmd.sh 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/fault-injection/failcmd.sh 1969-12-31 19:00:00.000000000 -0500 +@@ -1,4 +0,0 @@ +-#!/bin/bash +- +-echo 1 > /proc/self/make-it-fail +-exec $* +diff -Nurp linux-2.6.22/Documentation/fault-injection/failmodule.sh linux-2.6-netns/Documentation/fault-injection/failmodule.sh +--- linux-2.6.22/Documentation/fault-injection/failmodule.sh 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/fault-injection/failmodule.sh 1969-12-31 19:00:00.000000000 -0500 +@@ -1,31 +0,0 @@ +-#!/bin/bash +-# +-# Usage: failmodule [stacktrace-depth] +-# +-# : "failslab", "fail_alloc_page", or "fail_make_request" +-# +-# : module name that you want to inject faults. +-# +-# [stacktrace-depth]: the maximum number of stacktrace walking allowed +-# +- +-STACKTRACE_DEPTH=5 +-if [ $# -gt 2 ]; then +- STACKTRACE_DEPTH=$3 +-fi +- +-if [ ! -d /debug/$1 ]; then +- echo "Fault-injection $1 does not exist" >&2 +- exit 1 +-fi +-if [ ! -d /sys/module/$2 ]; then +- echo "Module $2 does not exist" >&2 +- exit 1 +-fi +- +-# Disable any fault injection +-echo 0 > /debug/$1/stacktrace-depth +- +-echo `cat /sys/module/$2/sections/.text` > /debug/$1/require-start +-echo `cat /sys/module/$2/sections/.exit.text` > /debug/$1/require-end +-echo $STACKTRACE_DEPTH > /debug/$1/stacktrace-depth +diff -Nurp linux-2.6.22/Documentation/fault-injection/fault-injection.txt linux-2.6-netns/Documentation/fault-injection/fault-injection.txt +--- linux-2.6.22/Documentation/fault-injection/fault-injection.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/fault-injection/fault-injection.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -103,6 +103,11 @@ configuration of fault-injection capabil + default is 'N', setting it to 'Y' will inject failures + only into non-sleep allocations (GFP_ATOMIC allocations). + ++- /debug/fail_page_alloc/min-order: ++ ++ specifies the minimum page allocation order to be injected ++ failures. ++ + o Boot option + + In order to inject faults while debugfs is not available (early boot time), +@@ -156,70 +161,77 @@ o add a hook to insert failures + Application Examples + -------------------- + +-o inject slab allocation failures into module init/cleanup code ++o Inject slab allocation failures into module init/exit code + +------------------------------------------------------------------------------- + #!/bin/bash + +-FAILCMD=Documentation/fault-injection/failcmd.sh +-BLACKLIST="root_plug evbug" ++FAILTYPE=failslab ++echo Y > /debug/$FAILTYPE/task-filter ++echo 10 > /debug/$FAILTYPE/probability ++echo 100 > /debug/$FAILTYPE/interval ++echo -1 > /debug/$FAILTYPE/times ++echo 0 > /debug/$FAILTYPE/space ++echo 2 > /debug/$FAILTYPE/verbose ++echo 1 > /debug/$FAILTYPE/ignore-gfp-wait + +-FAILNAME=failslab +-echo Y > /debug/$FAILNAME/task-filter +-echo 10 > /debug/$FAILNAME/probability +-echo 100 > /debug/$FAILNAME/interval +-echo -1 > /debug/$FAILNAME/times +-echo 2 > /debug/$FAILNAME/verbose +-echo 1 > /debug/$FAILNAME/ignore-gfp-wait +- +-blacklist() ++faulty_system() + { +- echo $BLACKLIST | grep $1 > /dev/null 2>&1 ++ bash -c "echo 1 > /proc/self/make-it-fail && exec $*" + } + +-oops() +-{ +- dmesg | grep BUG > /dev/null 2>&1 +-} +- +-find /lib/modules/`uname -r` -name '*.ko' -exec basename {} .ko \; | +- while read i +- do +- oops && exit 1 +- +- if ! blacklist $i +- then +- echo inserting $i... +- bash $FAILCMD modprobe $i +- fi +- done +- +-lsmod | awk '{ if ($3 == 0) { print $1 } }' | +- while read i +- do +- oops && exit 1 +- +- if ! blacklist $i +- then +- echo removing $i... +- bash $FAILCMD modprobe -r $i +- fi +- done ++if [ $# -eq 0 ] ++then ++ echo "Usage: $0 modulename [ modulename ... ]" ++ exit 1 ++fi ++ ++for m in $* ++do ++ echo inserting $m... ++ faulty_system modprobe $m ++ ++ echo removing $m... ++ faulty_system modprobe -r $m ++done + + ------------------------------------------------------------------------------ + +-o inject slab allocation failures only for a specific module ++o Inject page allocation failures only for a specific module + +------------------------------------------------------------------------------- + #!/bin/bash + +-FAILMOD=Documentation/fault-injection/failmodule.sh ++FAILTYPE=fail_page_alloc ++module=$1 + +-echo injecting errors into the module $1... ++if [ -z $module ] ++then ++ echo "Usage: $0 " ++ exit 1 ++fi ++ ++modprobe $module ++ ++if [ ! -d /sys/module/$module/sections ] ++then ++ echo Module $module is not loaded ++ exit 1 ++fi ++ ++cat /sys/module/$module/sections/.text > /debug/$FAILTYPE/require-start ++cat /sys/module/$module/sections/.data > /debug/$FAILTYPE/require-end ++ ++echo N > /debug/$FAILTYPE/task-filter ++echo 10 > /debug/$FAILTYPE/probability ++echo 100 > /debug/$FAILTYPE/interval ++echo -1 > /debug/$FAILTYPE/times ++echo 0 > /debug/$FAILTYPE/space ++echo 2 > /debug/$FAILTYPE/verbose ++echo 1 > /debug/$FAILTYPE/ignore-gfp-wait ++echo 1 > /debug/$FAILTYPE/ignore-gfp-highmem ++echo 10 > /debug/$FAILTYPE/stacktrace-depth + +-modprobe $1 +-bash $FAILMOD failslab $1 10 +-echo 25 > /debug/failslab/probability ++trap "echo 0 > /debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT + +------------------------------------------------------------------------------- ++echo "Injecting errors into the module $module... (interrupt to stop)" ++sleep 1000000 + +diff -Nurp linux-2.6.22/Documentation/feature-removal-schedule.txt linux-2.6-netns/Documentation/feature-removal-schedule.txt +--- linux-2.6.22/Documentation/feature-removal-schedule.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/feature-removal-schedule.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -26,9 +26,7 @@ Who: Hans Verkuil a + + --------------------------- + +-What: /sys/devices/.../power/state +- dev->power.power_state +- dpm_runtime_{suspend,resume)() ++What: dev->power.power_state + When: July 2007 + Why: Broken design for runtime control over driver power states, confusing + driver-internal runtime power management with: mechanisms to support +@@ -41,24 +39,6 @@ Who: Pavel Machek + + --------------------------- + +-What: RAW driver (CONFIG_RAW_DRIVER) +-When: December 2005 +-Why: declared obsolete since kernel 2.6.3 +- O_DIRECT can be used instead +-Who: Adrian Bunk +- +---------------------------- +- +-What: raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN +-When: June 2007 +-Why: Deprecated in favour of the more efficient and robust rawiso interface. +- Affected are applications which use the deprecated part of libraw1394 +- (raw1394_iso_write, raw1394_start_iso_write, raw1394_start_iso_rcv, +- raw1394_stop_iso_rcv) or bypass libraw1394. +-Who: Dan Dennedy , Stefan Richter +- +---------------------------- +- + What: old NCR53C9x driver + When: October 2007 + Why: Replaced by the much better esp_scsi driver. Actual low-level +@@ -129,13 +109,6 @@ Who: Adrian Bunk + + --------------------------- + +-What: drivers depending on OSS_OBSOLETE_DRIVER +-When: options in 2.6.20, code in 2.6.22 +-Why: OSS drivers with ALSA replacements +-Who: Adrian Bunk +- +---------------------------- +- + What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports + (temporary transition config option provided until then) + The transition config option will also be removed at the same time. +@@ -206,28 +179,6 @@ Who: Adrian Bunk + + --------------------------- + +-What: ACPI hooks (X86_SPEEDSTEP_CENTRINO_ACPI) in speedstep-centrino driver +-When: December 2006 +-Why: Speedstep-centrino driver with ACPI hooks and acpi-cpufreq driver are +- functionally very much similar. They talk to ACPI in same way. Only +- difference between them is the way they do frequency transitions. +- One uses MSRs and the other one uses IO ports. Functionaliy of +- speedstep_centrino with ACPI hooks is now merged into acpi-cpufreq. +- That means one common driver will support all Intel Enhanced Speedstep +- capable CPUs. That means less confusion over name of +- speedstep-centrino driver (with that driver supposed to be used on +- non-centrino platforms). That means less duplication of code and +- less maintenance effort and no possibility of these two drivers +- going out of sync. +- Current users of speedstep_centrino with ACPI hooks are requested to +- switch over to acpi-cpufreq driver. speedstep-centrino will continue +- to work using older non-ACPI static table based scheme even after this +- date. +- +-Who: Venkatesh Pallipadi +- +---------------------------- +- + What: /sys/firmware/acpi/namespace + When: 2.6.21 + Why: The ACPI namespace is effectively the symbol list for +@@ -258,14 +209,6 @@ Who: Len Brown + + --------------------------- + +-What: sk98lin network driver +-When: July 2007 +-Why: In kernel tree version of driver is unmaintained. Sk98lin driver +- replaced by the skge driver. +-Who: Stephen Hemminger +- +---------------------------- +- + What: Compaq touchscreen device emulation + When: Oct 2007 + Files: drivers/input/tsdev.c +@@ -280,25 +223,6 @@ Who: Richard Purdie + + --------------------------- + +-What: Multipath cached routing support in ipv4 +-When: in 2.6.23 +-Why: Code was merged, then submitter immediately disappeared leaving +- us with no maintainer and lots of bugs. The code should not have +- been merged in the first place, and many aspects of it's +- implementation are blocking more critical core networking +- development. It's marked EXPERIMENTAL and no distribution +- enables it because it cause obscure crashes due to unfixable bugs +- (interfaces don't return errors so memory allocation can't be +- handled, calling contexts of these interfaces make handling +- errors impossible too because they get called after we've +- totally commited to creating a route object, for example). +- This problem has existed for years and no forward progress +- has ever been made, and nobody steps up to try and salvage +- this code, so we're going to finally just get rid of it. +-Who: David S. Miller +- +---------------------------- +- + What: read_dev_chars(), read_conf_data{,_lpm}() (s390 common I/O layer) + When: December 2007 + Why: These functions are a leftover from 2.4 times. They have several +@@ -323,6 +247,14 @@ Who: Jean Delvare + + --------------------------- + ++What: 'time' kernel boot parameter ++When: January 2008 ++Why: replaced by 'printk.time=' so that printk timestamps can be ++ enabled or disabled as needed ++Who: Randy Dunlap ++ ++--------------------------- ++ + What: drivers depending on OSS_OBSOLETE + When: options in 2.6.23, code in 2.6.25 + Why: obsolete OSS drivers +@@ -348,3 +280,41 @@ Who: Tejun Heo + + --------------------------- + ++What: Legacy RTC drivers (under drivers/i2c/chips) ++When: November 2007 ++Why: Obsolete. We have a RTC subsystem with better drivers. ++Who: Jean Delvare ++ ++--------------------------- ++ ++What: iptables SAME target ++When: 1.1. 2008 ++Files: net/ipv4/netfilter/ipt_SAME.c, include/linux/netfilter_ipv4/ipt_SAME.h ++Why: Obsolete for multiple years now, NAT core provides the same behaviour. ++ Unfixable broken wrt. 32/64 bit cleanness. ++Who: Patrick McHardy ++ ++--------------------------- ++ ++What: The arch/ppc and include/asm-ppc directories ++When: Jun 2008 ++Why: The arch/powerpc tree is the merged architecture for ppc32 and ppc64 ++ platforms. Currently there are efforts underway to port the remaining ++ arch/ppc platforms to the merged tree. New submissions to the arch/ppc ++ tree have been frozen with the 2.6.22 kernel release and that tree will ++ remain in bug-fix only mode until its scheduled removal. Platforms ++ that are not ported by June 2008 will be removed due to the lack of an ++ interested maintainer. ++Who: linuxppc-dev@ozlabs.org ++ ++--------------------------- ++ ++What: mthca driver's MSI support ++When: January 2008 ++Files: drivers/infiniband/hw/mthca/*.[ch] ++Why: All mthca hardware also supports MSI-X, which provides ++ strictly more functionality than MSI. So there is no point in ++ having both MSI-X and MSI support in the driver. ++Who: Roland Dreier ++ ++--------------------------- +diff -Nurp linux-2.6.22/Documentation/filesystems/configfs/configfs.txt linux-2.6-netns/Documentation/filesystems/configfs/configfs.txt +--- linux-2.6.22/Documentation/filesystems/configfs/configfs.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/filesystems/configfs/configfs.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -238,6 +238,8 @@ config_item_type. + struct config_group *(*make_group)(struct config_group *group, + const char *name); + int (*commit_item)(struct config_item *item); ++ void (*disconnect_notify)(struct config_group *group, ++ struct config_item *item); + void (*drop_item)(struct config_group *group, + struct config_item *item); + }; +@@ -268,6 +270,16 @@ the item in other threads, the memory is + for the item to actually disappear from the subsystem's usage. But it + is gone from configfs. + ++When drop_item() is called, the item's linkage has already been torn ++down. It no longer has a reference on its parent and has no place in ++the item hierarchy. If a client needs to do some cleanup before this ++teardown happens, the subsystem can implement the ++ct_group_ops->disconnect_notify() method. The method is called after ++configfs has removed the item from the filesystem view but before the ++item is removed from its parent group. Like drop_item(), ++disconnect_notify() is void and cannot fail. Client subsystems should ++not drop any references here, as they still must do it in drop_item(). ++ + A config_group cannot be removed while it still has child items. This + is implemented in the configfs rmdir(2) code. ->drop_item() will not be + called, as the item has not been dropped. rmdir(2) will fail, as the +@@ -280,18 +292,18 @@ tells configfs to make the subsystem app + + struct configfs_subsystem { + struct config_group su_group; +- struct semaphore su_sem; ++ struct mutex su_mutex; + }; + + int configfs_register_subsystem(struct configfs_subsystem *subsys); + void configfs_unregister_subsystem(struct configfs_subsystem *subsys); + +- A subsystem consists of a toplevel config_group and a semaphore. ++ A subsystem consists of a toplevel config_group and a mutex. + The group is where child config_items are created. For a subsystem, + this group is usually defined statically. Before calling + configfs_register_subsystem(), the subsystem must have initialized the + group via the usual group _init() functions, and it must also have +-initialized the semaphore. ++initialized the mutex. + When the register call returns, the subsystem is live, and it + will be visible via configfs. At that point, mkdir(2) can be called and + the subsystem must be ready for it. +@@ -303,7 +315,7 @@ subsystem/group and the simple_child ite + shows a trivial object displaying and storing an attribute, and a simple + group creating and destroying these children. + +-[Hierarchy Navigation and the Subsystem Semaphore] ++[Hierarchy Navigation and the Subsystem Mutex] + + There is an extra bonus that configfs provides. The config_groups and + config_items are arranged in a hierarchy due to the fact that they +@@ -314,19 +326,19 @@ and config_item->ci_parent structure mem + + A subsystem can navigate the cg_children list and the ci_parent pointer + to see the tree created by the subsystem. This can race with configfs' +-management of the hierarchy, so configfs uses the subsystem semaphore to ++management of the hierarchy, so configfs uses the subsystem mutex to + protect modifications. Whenever a subsystem wants to navigate the + hierarchy, it must do so under the protection of the subsystem +-semaphore. ++mutex. + +-A subsystem will be prevented from acquiring the semaphore while a newly ++A subsystem will be prevented from acquiring the mutex while a newly + allocated item has not been linked into this hierarchy. Similarly, it +-will not be able to acquire the semaphore while a dropping item has not ++will not be able to acquire the mutex while a dropping item has not + yet been unlinked. This means that an item's ci_parent pointer will + never be NULL while the item is in configfs, and that an item will only + be in its parent's cg_children list for the same duration. This allows + a subsystem to trust ci_parent and cg_children while they hold the +-semaphore. ++mutex. + + [Item Aggregation Via symlink(2)] + +@@ -386,6 +398,33 @@ As a consequence of this, default_groups + rmdir(2). They also are not considered when rmdir(2) on the parent + group is checking for children. + ++[Dependant Subsystems] ++ ++Sometimes other drivers depend on particular configfs items. For ++example, ocfs2 mounts depend on a heartbeat region item. If that ++region item is removed with rmdir(2), the ocfs2 mount must BUG or go ++readonly. Not happy. ++ ++configfs provides two additional API calls: configfs_depend_item() and ++configfs_undepend_item(). A client driver can call ++configfs_depend_item() on an existing item to tell configfs that it is ++depended on. configfs will then return -EBUSY from rmdir(2) for that ++item. When the item is no longer depended on, the client driver calls ++configfs_undepend_item() on it. ++ ++These API cannot be called underneath any configfs callbacks, as ++they will conflict. They can block and allocate. A client driver ++probably shouldn't calling them of its own gumption. Rather it should ++be providing an API that external subsystems call. ++ ++How does this work? Imagine the ocfs2 mount process. When it mounts, ++it asks for a heartbeat region item. This is done via a call into the ++heartbeat code. Inside the heartbeat code, the region item is looked ++up. Here, the heartbeat code calls configfs_depend_item(). If it ++succeeds, then heartbeat knows the region is safe to give to ocfs2. ++If it fails, it was being torn down anyway, and heartbeat can gracefully ++pass up an error. ++ + [Committable Items] + + NOTE: Committable items are currently unimplemented. +diff -Nurp linux-2.6.22/Documentation/filesystems/configfs/configfs_example.c linux-2.6-netns/Documentation/filesystems/configfs/configfs_example.c +--- linux-2.6.22/Documentation/filesystems/configfs/configfs_example.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/filesystems/configfs/configfs_example.c 2007-12-03 23:14:12.000000000 -0500 +@@ -453,7 +453,7 @@ static int __init configfs_example_init( + subsys = example_subsys[i]; + + config_group_init(&subsys->su_group); +- init_MUTEX(&subsys->su_sem); ++ mutex_init(&subsys->su_mutex); + ret = configfs_register_subsystem(subsys); + if (ret) { + printk(KERN_ERR "Error %d while registering subsystem %s\n", +diff -Nurp linux-2.6.22/Documentation/filesystems/ecryptfs.txt linux-2.6-netns/Documentation/filesystems/ecryptfs.txt +--- linux-2.6.22/Documentation/filesystems/ecryptfs.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/filesystems/ecryptfs.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,77 @@ ++eCryptfs: A stacked cryptographic filesystem for Linux ++ ++eCryptfs is free software. Please see the file COPYING for details. ++For documentation, please see the files in the doc/ subdirectory. For ++building and installation instructions please see the INSTALL file. ++ ++Maintainer: Phillip Hellewell ++Lead developer: Michael A. Halcrow ++Developers: Michael C. Thompson ++ Kent Yoder ++Web Site: http://ecryptfs.sf.net ++ ++This software is currently undergoing development. Make sure to ++maintain a backup copy of any data you write into eCryptfs. ++ ++eCryptfs requires the userspace tools downloadable from the ++SourceForge site: ++ ++http://sourceforge.net/projects/ecryptfs/ ++ ++Userspace requirements include: ++ - David Howells' userspace keyring headers and libraries (version ++ 1.0 or higher), obtainable from ++ http://people.redhat.com/~dhowells/keyutils/ ++ - Libgcrypt ++ ++ ++NOTES ++ ++In the beta/experimental releases of eCryptfs, when you upgrade ++eCryptfs, you should copy the files to an unencrypted location and ++then copy the files back into the new eCryptfs mount to migrate the ++files. ++ ++ ++MOUNT-WIDE PASSPHRASE ++ ++Create a new directory into which eCryptfs will write its encrypted ++files (i.e., /root/crypt). Then, create the mount point directory ++(i.e., /mnt/crypt). Now it's time to mount eCryptfs: ++ ++mount -t ecryptfs /root/crypt /mnt/crypt ++ ++You should be prompted for a passphrase and a salt (the salt may be ++blank). ++ ++Try writing a new file: ++ ++echo "Hello, World" > /mnt/crypt/hello.txt ++ ++The operation will complete. Notice that there is a new file in ++/root/crypt that is at least 12288 bytes in size (depending on your ++host page size). This is the encrypted underlying file for what you ++just wrote. To test reading, from start to finish, you need to clear ++the user session keyring: ++ ++keyctl clear @u ++ ++Then umount /mnt/crypt and mount again per the instructions given ++above. ++ ++cat /mnt/crypt/hello.txt ++ ++ ++NOTES ++ ++eCryptfs version 0.1 should only be mounted on (1) empty directories ++or (2) directories containing files only created by eCryptfs. If you ++mount a directory that has pre-existing files not created by eCryptfs, ++then behavior is undefined. Do not run eCryptfs in higher verbosity ++levels unless you are doing so for the sole purpose of debugging or ++development, since secret values will be written out to the system log ++in that case. ++ ++ ++Mike Halcrow ++mhalcrow@us.ibm.com +diff -Nurp linux-2.6.22/Documentation/filesystems/proc.txt linux-2.6-netns/Documentation/filesystems/proc.txt +--- linux-2.6.22/Documentation/filesystems/proc.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/filesystems/proc.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -171,7 +171,9 @@ read the file /proc/PID/status: + This shows you nearly the same information you would get if you viewed it with + the ps command. In fact, ps uses the proc file system to obtain its + information. The statm file contains more detailed information about the +-process memory usage. Its seven fields are explained in Table 1-2. ++process memory usage. Its seven fields are explained in Table 1-2. The stat ++file contains details information about the process itself. Its fields are ++explained in Table 1-3. + + + Table 1-2: Contents of the statm files (as of 2.6.8-rc3) +@@ -188,16 +190,65 @@ Table 1-2: Contents of the statm files ( + dt number of dirty pages (always 0 on 2.6) + .............................................................................. + ++ ++Table 1-3: Contents of the stat files (as of 2.6.22-rc3) ++.............................................................................. ++ Field Content ++ pid process id ++ tcomm filename of the executable ++ state state (R is running, S is sleeping, D is sleeping in an ++ uninterruptible wait, Z is zombie, T is traced or stopped) ++ ppid process id of the parent process ++ pgrp pgrp of the process ++ sid session id ++ tty_nr tty the process uses ++ tty_pgrp pgrp of the tty ++ flags task flags ++ min_flt number of minor faults ++ cmin_flt number of minor faults with child's ++ maj_flt number of major faults ++ cmaj_flt number of major faults with child's ++ utime user mode jiffies ++ stime kernel mode jiffies ++ cutime user mode jiffies with child's ++ cstime kernel mode jiffies with child's ++ priority priority level ++ nice nice level ++ num_threads number of threads ++ start_time time the process started after system boot ++ vsize virtual memory size ++ rss resident set memory size ++ rsslim current limit in bytes on the rss ++ start_code address above which program text can run ++ end_code address below which program text can run ++ start_stack address of the start of the stack ++ esp current value of ESP ++ eip current value of EIP ++ pending bitmap of pending signals (obsolete) ++ blocked bitmap of blocked signals (obsolete) ++ sigign bitmap of ignored signals (obsolete) ++ sigcatch bitmap of catched signals (obsolete) ++ wchan address where process went to sleep ++ 0 (place holder) ++ 0 (place holder) ++ exit_signal signal to send to parent thread on exit ++ task_cpu which CPU the task is scheduled on ++ rt_priority realtime priority ++ policy scheduling policy (man sched_setscheduler) ++ blkio_ticks time spent waiting for block IO ++.............................................................................. ++ ++ + 1.2 Kernel data + --------------- + + Similar to the process entries, the kernel data files give information about + the running kernel. The files used to obtain this information are contained in +-/proc and are listed in Table 1-3. Not all of these will be present in your ++/proc and are listed in Table 1-4. Not all of these will be present in your + system. It depends on the kernel configuration and the loaded modules, which + files are there, and which are missing. + +-Table 1-3: Kernel info in /proc ++Table 1-4: Kernel info in /proc + .............................................................................. + File Content + apm Advanced power management info +@@ -473,10 +524,10 @@ IDE devices: + + More detailed information can be found in the controller specific + subdirectories. These are named ide0, ide1 and so on. Each of these +-directories contains the files shown in table 1-4. ++directories contains the files shown in table 1-5. + + +-Table 1-4: IDE controller info in /proc/ide/ide? ++Table 1-5: IDE controller info in /proc/ide/ide? + .............................................................................. + File Content + channel IDE channel (0 or 1) +@@ -486,11 +537,11 @@ Table 1-4: IDE controller info in /proc + .............................................................................. + + Each device connected to a controller has a separate subdirectory in the +-controllers directory. The files listed in table 1-5 are contained in these ++controllers directory. The files listed in table 1-6 are contained in these + directories. + + +-Table 1-5: IDE device information ++Table 1-6: IDE device information + .............................................................................. + File Content + cache The cache +@@ -1297,6 +1348,21 @@ nr_hugepages configures number of hugetl + hugetlb_shm_group contains group id that is allowed to create SysV shared + memory segment using hugetlb page. + ++hugepages_treat_as_movable ++-------------------------- ++ ++This parameter is only useful when kernelcore= is specified at boot time to ++create ZONE_MOVABLE for pages that may be reclaimed or migrated. Huge pages ++are not movable so are not normally allocated from ZONE_MOVABLE. A non-zero ++value written to hugepages_treat_as_movable allows huge pages to be allocated ++from ZONE_MOVABLE. ++ ++Once enabled, the ZONE_MOVABLE is treated as an area of memory the huge ++pages pool can easily grow or shrink within. Assuming that applications are ++not running that mlock() a lot of memory, it is likely the huge pages pool ++can grow to the size of ZONE_MOVABLE by repeatedly entering the desired value ++into nr_hugepages and triggering page reclaim. ++ + laptop_mode + ----------- + +diff -Nurp linux-2.6.22/Documentation/filesystems/vfs.txt linux-2.6-netns/Documentation/filesystems/vfs.txt +--- linux-2.6.22/Documentation/filesystems/vfs.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/filesystems/vfs.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -3,7 +3,7 @@ + + Original author: Richard Gooch + +- Last updated on October 28, 2005 ++ Last updated on June 24, 2007. + + Copyright (C) 1999 Richard Gooch + Copyright (C) 2005 Pekka Enberg +@@ -107,7 +107,7 @@ file /proc/filesystems. + struct file_system_type + ----------------------- + +-This describes the filesystem. As of kernel 2.6.13, the following ++This describes the filesystem. As of kernel 2.6.22, the following + members are defined: + + struct file_system_type { +@@ -119,6 +119,8 @@ struct file_system_type { + struct module *owner; + struct file_system_type * next; + struct list_head fs_supers; ++ struct lock_class_key s_lock_key; ++ struct lock_class_key s_umount_key; + }; + + name: the name of the filesystem type, such as "ext2", "iso9660", +@@ -137,11 +139,12 @@ struct file_system_type { + + next: for internal VFS use: you should initialize this to NULL + ++ s_lock_key, s_umount_key: lockdep-specific ++ + The get_sb() method has the following arguments: + +- struct super_block *sb: the superblock structure. This is partially +- initialized by the VFS and the rest must be initialized by the +- get_sb() method ++ struct file_system_type *fs_type: decribes the filesystem, partly initialized ++ by the specific filesystem code + + int flags: mount flags + +@@ -150,12 +153,13 @@ The get_sb() method has the following ar + void *data: arbitrary mount options, usually comes as an ASCII + string + +- int silent: whether or not to be silent on error ++ struct vfsmount *mnt: a vfs-internal representation of a mount point + + The get_sb() method must determine if the block device specified +-in the superblock contains a filesystem of the type the method +-supports. On success the method returns the superblock pointer, on +-failure it returns NULL. ++in the dev_name and fs_type contains a filesystem of the type the method ++supports. If it succeeds in opening the named block device, it initializes a ++struct super_block descriptor for the filesystem contained by the block device. ++On failure it returns an error. + + The most interesting member of the superblock structure that the + get_sb() method fills in is the "s_op" field. This is a pointer to +@@ -193,7 +197,7 @@ struct super_operations + ----------------------- + + This describes how the VFS can manipulate the superblock of your +-filesystem. As of kernel 2.6.13, the following members are defined: ++filesystem. As of kernel 2.6.22, the following members are defined: + + struct super_operations { + struct inode *(*alloc_inode)(struct super_block *sb); +@@ -216,8 +220,6 @@ struct super_operations { + void (*clear_inode) (struct inode *); + void (*umount_begin) (struct super_block *); + +- void (*sync_inodes) (struct super_block *sb, +- struct writeback_control *wbc); + int (*show_options)(struct seq_file *, struct vfsmount *); + + ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); +@@ -300,9 +302,6 @@ or bottom half). + + umount_begin: called when the VFS is unmounting a filesystem. + +- sync_inodes: called when the VFS is writing out dirty data associated with +- a superblock. +- + show_options: called by the VFS to show mount options for /proc//mounts. + + quota_read: called by the VFS to read from filesystem quota file. +@@ -324,7 +323,7 @@ struct inode_operations + ----------------------- + + This describes how the VFS can manipulate an inode in your +-filesystem. As of kernel 2.6.13, the following members are defined: ++filesystem. As of kernel 2.6.22, the following members are defined: + + struct inode_operations { + int (*create) (struct inode *,struct dentry *,int, struct nameidata *); +@@ -348,6 +347,7 @@ struct inode_operations { + ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); + ssize_t (*listxattr) (struct dentry *, char *, size_t); + int (*removexattr) (struct dentry *, const char *); ++ void (*truncate_range)(struct inode *, loff_t, loff_t); + }; + + Again, all methods are called without any locks being held, unless +@@ -444,6 +444,9 @@ otherwise noted. + removexattr: called by the VFS to remove an extended attribute from + a file. This method is called by removexattr(2) system call. + ++ truncate_range: a method provided by the underlying filesystem to truncate a ++ range of blocks , i.e. punch a hole somewhere in a file. ++ + + The Address Space Object + ======================== +@@ -522,7 +525,7 @@ struct address_space_operations + ------------------------------- + + This describes how the VFS can manipulate mapping of a file to page cache in +-your filesystem. As of kernel 2.6.16, the following members are defined: ++your filesystem. As of kernel 2.6.22, the following members are defined: + + struct address_space_operations { + int (*writepage)(struct page *page, struct writeback_control *wbc); +@@ -543,6 +546,7 @@ struct address_space_operations { + int); + /* migrate the contents of a page to the specified target */ + int (*migratepage) (struct page *, struct page *); ++ int (*launder_page) (struct page *); + }; + + writepage: called by the VM to write a dirty page to backing store. +@@ -689,6 +693,10 @@ struct address_space_operations { + transfer any private data across and update any references + that it has to the page. + ++ launder_page: Called before freeing a page - it writes back the dirty page. To ++ prevent redirtying the page, it is kept locked during the whole ++ operation. ++ + The File Object + =============== + +@@ -699,9 +707,10 @@ struct file_operations + ---------------------- + + This describes how the VFS can manipulate an open file. As of kernel +-2.6.17, the following members are defined: ++2.6.22, the following members are defined: + + struct file_operations { ++ struct module *owner; + loff_t (*llseek) (struct file *, loff_t, int); + ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); + ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); +@@ -728,10 +737,8 @@ struct file_operations { + int (*check_flags)(int); + int (*dir_notify)(struct file *filp, unsigned long arg); + int (*flock) (struct file *, int, struct file_lock *); +- ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned +-int); +- ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned +-int); ++ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int); ++ ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int); + }; + + Again, all methods are called without any locks being held, unless +diff -Nurp linux-2.6.22/Documentation/firmware_class/firmware_sample_firmware_class.c linux-2.6-netns/Documentation/firmware_class/firmware_sample_firmware_class.c +--- linux-2.6.22/Documentation/firmware_class/firmware_sample_firmware_class.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/firmware_class/firmware_sample_firmware_class.c 2007-12-03 23:14:12.000000000 -0500 +@@ -78,6 +78,7 @@ static CLASS_DEVICE_ATTR(loading, 0644, + firmware_loading_show, firmware_loading_store); + + static ssize_t firmware_data_read(struct kobject *kobj, ++ struct bin_attribute *bin_attr, + char *buffer, loff_t offset, size_t count) + { + struct class_device *class_dev = to_class_dev(kobj); +@@ -88,6 +89,7 @@ static ssize_t firmware_data_read(struct + return count; + } + static ssize_t firmware_data_write(struct kobject *kobj, ++ struct bin_attribute *bin_attr, + char *buffer, loff_t offset, size_t count) + { + struct class_device *class_dev = to_class_dev(kobj); +diff -Nurp linux-2.6.22/Documentation/hrtimer/timer_stats.txt linux-2.6-netns/Documentation/hrtimer/timer_stats.txt +--- linux-2.6.22/Documentation/hrtimer/timer_stats.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/hrtimer/timer_stats.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -67,3 +67,7 @@ executed on expiry. + + Thomas, Ingo + ++Added flag to indicate 'deferrable timer' in /proc/timer_stats. A deferrable ++timer will appear as follows ++ 10D, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) ++ +diff -Nurp linux-2.6.22/Documentation/i2c/busses/i2c-i801 linux-2.6-netns/Documentation/i2c/busses/i2c-i801 +--- linux-2.6.22/Documentation/i2c/busses/i2c-i801 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/i2c/busses/i2c-i801 2007-12-03 23:14:12.000000000 -0500 +@@ -5,8 +5,8 @@ Supported adapters: + '810' and '810E' chipsets) + * Intel 82801BA (ICH2 - part of the '815E' chipset) + * Intel 82801CA/CAM (ICH3) +- * Intel 82801DB (ICH4) (HW PEC supported, 32 byte buffer not supported) +- * Intel 82801EB/ER (ICH5) (HW PEC supported, 32 byte buffer not supported) ++ * Intel 82801DB (ICH4) (HW PEC supported) ++ * Intel 82801EB/ER (ICH5) (HW PEC supported) + * Intel 6300ESB + * Intel 82801FB/FR/FW/FRW (ICH6) + * Intel 82801G (ICH7) +diff -Nurp linux-2.6.22/Documentation/i2c/busses/i2c-piix4 linux-2.6-netns/Documentation/i2c/busses/i2c-piix4 +--- linux-2.6.22/Documentation/i2c/busses/i2c-piix4 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/i2c/busses/i2c-piix4 2007-12-03 23:14:12.000000000 -0500 +@@ -6,7 +6,7 @@ Supported adapters: + Datasheet: Publicly available at the Intel website + * ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges + Datasheet: Only available via NDA from ServerWorks +- * ATI IXP200, IXP300, IXP400 and SB600 southbridges ++ * ATI IXP200, IXP300, IXP400, SB600 and SB700 southbridges + Datasheet: Not publicly available + * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge + Datasheet: Publicly available at the SMSC website http://www.smsc.com +diff -Nurp linux-2.6.22/Documentation/i2c/busses/i2c-taos-evm linux-2.6-netns/Documentation/i2c/busses/i2c-taos-evm +--- linux-2.6.22/Documentation/i2c/busses/i2c-taos-evm 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/i2c/busses/i2c-taos-evm 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,46 @@ ++Kernel driver i2c-taos-evm ++ ++Author: Jean Delvare ++ ++This is a driver for the evaluation modules for TAOS I2C/SMBus chips. ++The modules include an SMBus master with limited capabilities, which can ++be controlled over the serial port. Virtually all evaluation modules ++are supported, but a few lines of code need to be added for each new ++module to instantiate the right I2C chip on the bus. Obviously, a driver ++for the chip in question is also needed. ++ ++Currently supported devices are: ++ ++* TAOS TSL2550 EVM ++ ++For addtional information on TAOS products, please see ++ http://www.taosinc.com/ ++ ++ ++Using this driver ++----------------- ++ ++In order to use this driver, you'll need the serport driver, and the ++inputattach tool, which is part of the input-utils package. The following ++commands will tell the kernel that you have a TAOS EVM on the first ++serial port: ++ ++# modprobe serport ++# inputattach --taos-evm /dev/ttyS0 ++ ++ ++Technical details ++----------------- ++ ++Only 4 SMBus transaction types are supported by the TAOS evaluation ++modules: ++* Receive Byte ++* Send Byte ++* Read Byte ++* Write Byte ++ ++The communication protocol is text-based and pretty simple. It is ++described in a PDF document on the CD which comes with the evaluation ++module. The communication is rather slow, because the serial port has ++to operate at 1200 bps. However, I don't think this is a big concern in ++practice, as these modules are meant for evaluation and testing only. +diff -Nurp linux-2.6.22/Documentation/i2c/chips/max6875 linux-2.6-netns/Documentation/i2c/chips/max6875 +--- linux-2.6.22/Documentation/i2c/chips/max6875 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/i2c/chips/max6875 2007-12-03 23:06:33.000000000 -0500 +@@ -99,7 +99,7 @@ And then read the data + + or + +- count = i2c_smbus_read_i2c_block_data(fd, 0x84, buffer); ++ count = i2c_smbus_read_i2c_block_data(fd, 0x84, 16, buffer); + + The block read should read 16 bytes. + 0x84 is the block read command. +diff -Nurp linux-2.6.22/Documentation/i2c/chips/x1205 linux-2.6-netns/Documentation/i2c/chips/x1205 +--- linux-2.6.22/Documentation/i2c/chips/x1205 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/i2c/chips/x1205 1969-12-31 19:00:00.000000000 -0500 +@@ -1,38 +0,0 @@ +-Kernel driver x1205 +-=================== +- +-Supported chips: +- * Xicor X1205 RTC +- Prefix: 'x1205' +- Addresses scanned: none +- Datasheet: http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html +- +-Authors: +- Karen Spearel , +- Alessandro Zummo +- +-Description +------------ +- +-This module aims to provide complete access to the Xicor X1205 RTC. +-Recently Xicor has merged with Intersil, but the chip is +-still sold under the Xicor brand. +- +-This chip is located at address 0x6f and uses a 2-byte register addressing. +-Two bytes need to be written to read a single register, while most +-other chips just require one and take the second one as the data +-to be written. To prevent corrupting unknown chips, the user must +-explicitely set the probe parameter. +- +-example: +- +-modprobe x1205 probe=0,0x6f +- +-The module supports one more option, hctosys, which is used to set the +-software clock from the x1205. On systems where the x1205 is the +-only hardware rtc, this parameter could be used to achieve a correct +-date/time earlier in the system boot sequence. +- +-example: +- +-modprobe x1205 probe=0,0x6f hctosys=1 +diff -Nurp linux-2.6.22/Documentation/i2c/summary linux-2.6-netns/Documentation/i2c/summary +--- linux-2.6.22/Documentation/i2c/summary 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/i2c/summary 2007-12-03 23:06:33.000000000 -0500 +@@ -67,7 +67,6 @@ i2c-proc: The /proc/sys/dev/sensors inte + Algorithm drivers + ----------------- + +-i2c-algo-8xx: An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT) + i2c-algo-bit: A bit-banging algorithm + i2c-algo-pcf: A PCF 8584 style algorithm + i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT) +@@ -81,6 +80,5 @@ i2c-pcf-epp: PCF8584 on a EPP parall + i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit) + i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT) + i2c-pport: Primitive parallel port adapter (uses i2c-algo-bit) +-i2c-rpx: RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT) + i2c-velleman: Velleman K8000 parallel port adapter (uses i2c-algo-bit) + +diff -Nurp linux-2.6.22/Documentation/i2c/writing-clients linux-2.6-netns/Documentation/i2c/writing-clients +--- linux-2.6.22/Documentation/i2c/writing-clients 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/i2c/writing-clients 2007-12-03 23:06:33.000000000 -0500 +@@ -571,7 +571,7 @@ SMBus communication + u8 command, u8 length, + u8 *values); + extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, +- u8 command, u8 *values); ++ u8 command, u8 length, u8 *values); + + These ones were removed in Linux 2.6.10 because they had no users, but could + be added back later if needed: +diff -Nurp linux-2.6.22/Documentation/i386/zero-page.txt linux-2.6-netns/Documentation/i386/zero-page.txt +--- linux-2.6.22/Documentation/i386/zero-page.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/i386/zero-page.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -37,6 +37,7 @@ Offset Type Description + 0x1d0 unsigned long EFI memory descriptor map pointer + 0x1d4 unsigned long EFI memory descriptor map size + 0x1e0 unsigned long ALT_MEM_K, alternative mem check, in Kb ++0x1e4 unsigned long Scratch field for the kernel setup code + 0x1e8 char number of entries in E820MAP (below) + 0x1e9 unsigned char number of entries in EDDBUF (below) + 0x1ea unsigned char number of entries in EDD_MBR_SIG_BUFFER (below) +diff -Nurp linux-2.6.22/Documentation/ia64/aliasing-test.c linux-2.6-netns/Documentation/ia64/aliasing-test.c +--- linux-2.6.22/Documentation/ia64/aliasing-test.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/ia64/aliasing-test.c 2007-12-03 23:06:33.000000000 -0500 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + int sum; + +@@ -34,13 +35,19 @@ int map_mem(char *path, off_t offset, si + return -1; + } + ++ if (fnmatch("/proc/bus/pci/*", path, 0) == 0) { ++ rc = ioctl(fd, PCIIOC_MMAP_IS_MEM); ++ if (rc == -1) ++ perror("PCIIOC_MMAP_IS_MEM ioctl"); ++ } ++ + addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset); + if (addr == MAP_FAILED) + return 1; + + if (touch) { + c = (int *) addr; +- while (c < (int *) (offset + length)) ++ while (c < (int *) (addr + length)) + sum += *c++; + } + +@@ -54,7 +61,7 @@ int map_mem(char *path, off_t offset, si + return 0; + } + +-int scan_sysfs(char *path, char *file, off_t offset, size_t length, int touch) ++int scan_tree(char *path, char *file, off_t offset, size_t length, int touch) + { + struct dirent **namelist; + char *name, *path2; +@@ -93,7 +100,7 @@ int scan_sysfs(char *path, char *file, o + } else { + r = lstat(path2, &buf); + if (r == 0 && S_ISDIR(buf.st_mode)) { +- rc = scan_sysfs(path2, file, offset, length, touch); ++ rc = scan_tree(path2, file, offset, length, touch); + if (rc < 0) + return rc; + } +@@ -238,10 +245,15 @@ int main() + else + fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n"); + +- scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1); +- scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0); +- scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1); +- scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0); ++ scan_tree("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1); ++ scan_tree("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0); ++ scan_tree("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1); ++ scan_tree("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0); + + scan_rom("/sys/devices", "rom"); ++ ++ scan_tree("/proc/bus/pci", "??.?", 0, 0xA0000, 1); ++ scan_tree("/proc/bus/pci", "??.?", 0xA0000, 0x20000, 0); ++ scan_tree("/proc/bus/pci", "??.?", 0xC0000, 0x40000, 1); ++ scan_tree("/proc/bus/pci", "??.?", 0, 1024*1024, 0); + } +diff -Nurp linux-2.6.22/Documentation/ia64/aliasing.txt linux-2.6-netns/Documentation/ia64/aliasing.txt +--- linux-2.6.22/Documentation/ia64/aliasing.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/ia64/aliasing.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -112,6 +112,18 @@ POTENTIAL ATTRIBUTE ALIASING CASES + + The /dev/mem mmap constraints apply. + ++ mmap of /proc/bus/pci/.../??.? ++ ++ This is an MMIO mmap of PCI functions, which additionally may or ++ may not be requested as using the WC attribute. ++ ++ If WC is requested, and the region in kern_memmap is either WC ++ or UC, and the EFI memory map designates the region as WC, then ++ the WC mapping is allowed. ++ ++ Otherwise, the user mapping must use the same attribute as the ++ kernel mapping. ++ + read/write of /dev/mem + + This uses copy_from_user(), which implicitly uses a kernel +diff -Nurp linux-2.6.22/Documentation/ioctl-number.txt linux-2.6-netns/Documentation/ioctl-number.txt +--- linux-2.6.22/Documentation/ioctl-number.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/ioctl-number.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -67,7 +67,7 @@ Code Seq# Include File Comments + 0x00 00-1F linux/wavefront.h conflict! + 0x02 all linux/fd.h + 0x03 all linux/hdreg.h +-0x04 all linux/umsdos_fs.h ++0x04 D2-DC linux/umsdos_fs.h Dead since 2.6.11, but don't reuse these. + 0x06 all linux/lp.h + 0x09 all linux/md.h + 0x12 all linux/fs.h +diff -Nurp linux-2.6.22/Documentation/ja_JP/HOWTO linux-2.6-netns/Documentation/ja_JP/HOWTO +--- linux-2.6.22/Documentation/ja_JP/HOWTO 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/ja_JP/HOWTO 2007-12-03 23:14:12.000000000 -0500 +@@ -0,0 +1,650 @@ ++NOTE: ++This is Japanese translated version of "Documentation/HOWTO". ++This one is maintained by Tsugikazu Shibata ++and JF Project team . ++If you find difference with original file or problem in translation, ++please contact maintainer of this file or JF project. ++ ++Please also note that purpose of this file is easier to read for non ++English natives and not to be intended to fork. So, if you have any ++comments or updates of this file, please try to update Original(English) ++file at first. ++ ++Last Updated: 2007/06/04 ++================================== ++これは、 ++linux-2.6.21/Documentation/HOWTO ++の和訳です。 ++ ++翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ > ++翻訳日: 2007/06/04 ++翻訳者: Tsugikazu Shibata ++校正者: 松倉さん ++ 小林 雅典さん (Masanori Kobayasi) ++ 武井伸光さん、 ++ かねこさん (Seiji Kaneko) ++ 野口さん (Kenji Noguchi) ++ 河内さん (Takayoshi Kochi) ++ 岩本さん (iwamoto) ++================================== ++ ++Linux カーネル開発のやり方 ++------------------------------- ++ ++これは上のトピック( Linux カーネル開発のやり方)の重要な事柄を網羅した ++ドキュメントです。ここには Linux カーネル開発者になるための方法と ++Linux カーネル開発コミュニティと共に活動するやり方を学ぶ方法が含まれて ++います。カーネルプログラミングに関する技術的な項目に関することは何も含 ++めないようにしていますが、カーネル開発者となるための正しい方向に向かう ++手助けになります。 ++ ++もし、このドキュメントのどこかが古くなっていた場合には、このドキュメン ++トの最後にリストしたメンテナーにパッチを送ってください。 ++ ++はじめに ++--------- ++ ++あなたは Linux カーネルの開発者になる方法を学びたいのでしょうか? そ ++れともあなたは上司から「このデバイスの Linux ドライバを書くように」と ++言われているのでしょうか?  ++この文書の目的は、あなたが踏むべき手順と、コミュニティと一緒にうまく働 ++くヒントを書き下すことで、あなたが知るべき全てのことを教えることです。 ++また、このコミュニティがなぜ今うまくまわっているのかという理由の一部も ++説明しようと試みています。 ++ ++カーネルは 少量のアーキテクチャ依存部分がアセンブリ言語で書かれている ++以外は大部分は C 言語で書かれています。C言語をよく理解していることはカー ++ネル開発者には必要です。アーキテクチャ向けの低レベル部分の開発をするの ++でなければ、(どんなアーキテクチャでも)アセンブリ(訳注: 言語)は必要あり ++ません。以下の本は、C 言語の十分な知識や何年もの経験に取って代わるもの ++ではありませんが、少なくともリファレンスとしてはいい本です。 ++ - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall] ++ -『プログラミング言語C第2版』(B.W. カーニハン/D.M. リッチー著 石田晴久訳) [共立出版] ++ - "Practical C Programming" by Steve Oualline [O'Reilly] ++ - 『C実践プログラミング第3版』(Steve Oualline著 望月康司監訳 谷口功訳) [オライリージャパン] ++ - "C: A Reference Manual" by Harbison and Steele [Prentice Hall] ++ - 『新・詳説 C 言語 H&S リファレンス』 ++ (サミュエル P ハービソン/ガイ L スティール共著 斉藤 信男監訳)[ソフトバンク] ++ ++カーネルは GNU C と GNU ツールチェインを使って書かれています。カーネル ++は ISO C89 仕様に準拠して書く一方で、標準には無い言語拡張を多く使って ++います。カーネルは標準 C ライブラリとは関係がないといった、C 言語フリー ++スタンディング環境です。そのため、C の標準で使えないものもあります。任 ++意の long long の除算や浮動小数点は使えません。 ++ときどき、カーネルがツールチェインや C 言語拡張に置いている前提がどう ++なっているのかわかりにくいことがあり、また、残念なことに決定的なリファ ++レンスは存在しません。情報を得るには、gcc の info ページ( info gcc )を ++みてください。 ++ ++あなたは既存の開発コミュニティと一緒に作業する方法を学ぼうとしているこ ++とに留意してください。そのコミュニティは、コーディング、スタイル、 ++開発手順について高度な標準を持つ、多様な人の集まりです。 ++地理的に分散した大規模なチームに対してもっともうまくいくとわかったこと ++をベースにしながら、これらの標準は長い時間をかけて築かれてきました。 ++これらはきちんと文書化されていますから、事前にこれらの標準についてでき ++るだけたくさん学んでください。また皆があなたやあなたの会社のやり方に合わ ++せてくれると思わないでください。 ++ ++法的問題 ++------------ ++ ++Linux カーネルのソースコードは GPL ライセンスの下でリリースされていま ++す。ライセンスの詳細については、ソースツリーのメインディレクトリに存在 ++する、COPYING のファイルをみてください。もしライセンスについてさらに質 ++問があれば、Linux Kernel メーリングリストに質問するのではなく、どうぞ ++法律家に相談してください。メーリングリストの人達は法律家ではなく、法的 ++問題については彼らの声明はあてにするべきではありません。 ++ ++GPL に関する共通の質問や回答については、以下を参照してください。 ++ http://www.gnu.org/licenses/gpl-faq.html ++ ++ドキュメント ++------------ ++ ++Linux カーネルソースツリーは幅広い範囲のドキュメントを含んでおり、それ ++らはカーネルコミュニティと会話する方法を学ぶのに非常に貴重なものです。 ++新しい機能がカーネルに追加される場合、その機能の使い方について説明した ++新しいドキュメントファイルも追加することを勧めます。 ++カーネルの変更が、カーネルがユーザ空間に公開しているインターフェイスの ++変更を引き起こす場合、その変更を説明するマニュアルページのパッチや情報 ++をマニュアルページのメンテナ mtk-manpages@gmx.net に送ることを勧めます。 ++ ++以下はカーネルソースツリーに含まれている読んでおくべきファイルの一覧で ++す- ++ ++ README ++ このファイルは Linuxカーネルの簡単な背景とカーネルを設定(訳注 ++ configure )し、生成(訳注 build )するために必要なことは何かが書かれ ++ ています。カーネルに関して初めての人はここからスタートするとよいで ++ しょう。 ++ ++ Documentation/Changes ++ このファイルはカーネルをうまく生成(訳注 build )し、走らせるのに最 ++ 小限のレベルで必要な数々のソフトウェアパッケージの一覧を示してい ++ ます。 ++ ++ Documentation/CodingStyle ++ これは Linux カーネルのコーディングスタイルと背景にある理由を記述 ++ しています。全ての新しいコードはこのドキュメントにあるガイドライン ++ に従っていることを期待されています。大部分のメンテナーはこれらのルー ++ ルに従っているものだけを受け付け、多くの人は正しいスタイルのコード ++ だけをレビューします。 ++ ++ Documentation/SubmittingPatches ++ Documentation/SubmittingDrivers ++ これらのファイルには、どうやってうまくパッチを作って投稿するかに ++ ついて非常に詳しく書かれており、以下を含みます(これだけに限らない ++ けれども) ++ - Email に含むこと ++ - Email の形式 ++ - だれに送るか ++ これらのルールに従えばうまくいくことを保証することではありません ++ が (すべてのパッチは内容とスタイルについて精査を受けるので)、 ++ ルールに従わなければ間違いなくうまくいかないでしょう。 ++ この他にパッチを作る方法についてのよくできた記述は- ++ ++ "The Perfect Patch" ++ http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt ++ "Linux kernel patch submission format" ++ http://linux.yyz.us/patch-format.html ++ ++ Documentation/stable_api_nonsense.txt ++ このファイルはカーネルの中に不変のAPIを持たないことにした意識的な ++ 決断の背景にある理由について書かれています。以下のようなことを含 ++ んでいます- ++ - サブシステムとの間に層を作ること(コンパチビリティのため?) ++ - オペレーティングシステム間のドライバの移植性 ++ - カーネルソースツリーの素早い変更を遅らせる(もしくは素早い変更 ++ を妨げる) ++ このドキュメントは Linux 開発の思想を理解するのに非常に重要です。 ++ そして、他のOSでの開発者が Linux に移る時にとても重要です。 ++ ++ Documentation/SecurityBugs ++ もし Linux カーネルでセキュリティ問題を発見したように思ったら、こ ++ のドキュメントのステップに従ってカーネル開発者に連絡し、問題解決を ++ 支援してください。 ++ ++ Documentation/ManagementStyle ++ このドキュメントは Linux カーネルのメンテナー達がどう行動するか、 ++ 彼らの手法の背景にある共有されている精神について記述しています。こ ++ れはカーネル開発の初心者なら(もしくは、単に興味があるだけの人でも) ++ 重要です。なぜならこのドキュメントは、カーネルメンテナー達の独特な ++ 行動についての多くの誤解や混乱を解消するからです。 ++ ++ Documentation/stable_kernel_rules.txt ++ このファイルはどのように stable カーネルのリリースが行われるかのルー ++ ルが記述されています。そしてこれらのリリースの中のどこかで変更を取 ++ り入れてもらいたい場合に何をすればいいかが示されています。 ++ ++ Documentation/kernel-docs.txt ++  カーネル開発に付随する外部ドキュメントのリストです。もしあなたが ++ 探しているものがカーネル内のドキュメントでみつからなかった場合、 ++ このリストをあたってみてください。 ++ ++ Documentation/applying-patches.txt ++ パッチとはなにか、パッチをどうやって様々なカーネルの開発ブランチに ++ 適用するのかについて正確に記述した良い入門書です。 ++ ++カーネルはソースコードから自動的に生成可能な多数のドキュメントを自分自 ++身でもっています。これにはカーネル内 API のすべての記述や、どう正しく ++ロックをかけるかの規則が含まれます。このドキュメントは ++Documentation/DocBook/ ディレクトリに作られ、以下のように ++ make pdfdocs ++ make psdocs ++ make htmldocs ++ make mandocs ++コマンドを実行するとメインカーネルのソースディレクトリから ++それぞれ、PDF, Postscript, HTML, man page の形式で生成されます。 ++ ++カーネル開発者になるには ++--------------------------- ++ ++もしあなたが、Linux カーネル開発について何も知らないならば、 ++KernelNewbies プロジェクトを見るべきです ++ http://kernelnewbies.org ++ ++このサイトには役に立つメーリングリストがあり、基本的なカーネル開発に関 ++するほとんどどんな種類の質問もできます (既に回答されているようなことを ++聞く前にまずはアーカイブを調べてください)。 ++またここには、リアルタイムで質問を聞くことができる IRC チャネルや、Linux ++カーネルの開発に関して学ぶのに便利なたくさんの役に立つドキュメントがあ ++ります。 ++ ++web サイトには、コードの構成、サブシステム、現在存在するプロジェクト(ツ ++リーにあるもの無いものの両方)の基本的な管理情報があります。 ++ここには、また、カーネルのコンパイルのやり方やパッチの当て方などの間接 ++的な基本情報も記述されています。 ++ ++あなたがどこからスタートしてよいかわからないが、Linux カーネル開発コミュ ++ニティに参加して何かすることをさがしている場合には、Linux kernel ++Janitor's プロジェクトにいけばよいでしょう - ++ http://janitor.kernelnewbies.org/ ++ここはそのようなスタートをするのにうってつけの場所です。ここには、 ++Linux カーネルソースツリーの中に含まれる、きれいにし、修正しなければな ++らない、単純な問題のリストが記述されています。このプロジェクトに関わる ++開発者と一緒に作業することで、あなたのパッチを Linuxカーネルツリーに入 ++れるための基礎を学ぶことができ、そしてもしあなたがまだアイディアを持っ ++ていない場合には、次にやる仕事の方向性が見えてくるかもしれません。 ++ ++もしあなたが、すでにひとまとまりコードを書いていて、カーネルツリーに入 ++れたいと思っていたり、それに関する適切な支援を求めたい場合、カーネル ++メンターズプロジェクトはそのような皆さんを助けるためにできました。 ++ここにはメーリングリストがあり、以下から参照できます ++ http://selenic.com/mailman/listinfo/kernel-mentors ++ ++実際に Linux カーネルのコードについて修正を加える前に、どうやってその ++コードが動作するのかを理解することが必要です。そのためには、特別なツー ++ルの助けを借りてでも、それを直接よく読むことが最良の方法です(ほとんど ++のトリッキーな部分は十分にコメントしてありますから)。そういうツールで ++特におすすめなのは、Linux クロスリファレンスプロジェクトです。これは、 ++自己参照方式で、索引がついた web 形式で、ソースコードを参照することが ++できます。この最新の素晴しいカーネルコードのリポジトリは以下で見つかり ++ます- ++ http://sosdg.org/~coywolf/lxr/ ++ ++開発プロセス ++----------------------- ++ ++Linux カーネルの開発プロセスは現在幾つかの異なるメインカーネル「ブラン ++チ」と多数のサブシステム毎のカーネルブランチから構成されます。 ++これらのブランチとは- ++ - メインの 2.6.x カーネルツリー ++ - 2.6.x.y -stable カーネルツリー ++ - 2.6.x -git カーネルパッチ ++ - 2.6.x -mm カーネルパッチ ++ - サブシステム毎のカーネルツリーとパッチ ++ ++2.6.x カーネルツリー ++----------------- ++ ++2.6.x カーネルは Linus Torvalds によってメンテナンスされ、kernel.org ++の pub/linux/kernel/v2.6/ ディレクトリに存在します。この開発プロセスは ++以下のとおり- ++ ++ - 新しいカーネルがリリースされた直後に、2週間の特別期間が設けられ、 ++ この期間中に、メンテナー達は Linus に大きな差分を送ることができま ++ す。このような差分は通常 -mm カーネルに数週間含まれてきたパッチで ++ す。 大きな変更は git(カーネルのソース管理ツール、詳細は ++ http://git.or.cz/ 参照) を使って送るのが好ましいやり方ですが、パッ ++ チファイルの形式のまま送るのでも十分です。 ++ ++ - 2週間後、-rc1 カーネルがリリースされ、この後にはカーネル全体の安定 ++ 性に影響をあたえるような新機能は含まない類のパッチしか取り込むこと ++ はできません。新しいドライバ(もしくはファイルシステム)のパッチは ++ -rc1 の後で受け付けられることもあることを覚えておいてください。な ++ ぜなら、変更が独立していて、追加されたコードの外の領域に影響を与え ++ ない限り、退行のリスクは無いからです。-rc1 がリリースされた後、 ++ Linus へパッチを送付するのに git を使うこともできますが、パッチは ++ レビューのために、パブリックなメーリングリストへも同時に送る必要が ++ あります。 ++ ++ - 新しい -rc は Linus が、最新の git ツリーがテスト目的であれば十分 ++ に安定した状態にあると判断したときにリリースされます。目標は毎週新 ++ しい -rc カーネルをリリースすることです。 ++ ++ - このプロセスはカーネルが 「準備ができた」と考えられるまで継続しま ++ す。このプロセスはだいたい 6週間継続します。 ++ ++Andrew Morton が Linux-kernel メーリングリストにカーネルリリースについ ++て書いたことをここで言っておくことは価値があります- ++ 「カーネルがいつリリースされるかは誰も知りません。なぜなら、これは現 ++ 実に認識されたバグの状況によりリリースされるのであり、前もって決めら ++ れた計画によってリリースされるものではないからです。」 ++ ++2.6.x.y -stable カーネルツリー ++--------------------------- ++ ++バージョンに4つ目の数字がついたカーネルは -stable カーネルです。これに ++は、2.6.x カーネルで見つかったセキュリティ問題や重大な後戻りに対する比 ++較的小さい重要な修正が含まれます。 ++ ++これは、開発/実験的バージョンのテストに協力することに興味が無く、 ++最新の安定したカーネルを使いたいユーザに推奨するブランチです。 ++ ++もし、2.6.x.y カーネルが存在しない場合には、番号が一番大きい 2.6.x ++が最新の安定版カーネルです。 ++ ++2.6.x.y は "stable" チーム でメンテされており、だ ++いたい隔週でリリースされています。 ++ ++カーネルツリーに入っている、Documentation/stable_kernel_rules.txt ファ ++イルにはどのような種類の変更が -stable ツリーに受け入れ可能か、またリ ++リースプロセスがどう動くかが記述されています。 ++ ++2.6.x -git パッチ ++------------------ ++ ++git リポジトリで管理されているLinus のカーネルツリーの毎日のスナップ ++ショットがあります。(だから -git という名前がついています)。これらのパッ ++チはおおむね毎日リリースされており、Linus のツリーの現状を表します。こ ++れは -rc カーネルと比べて、パッチが大丈夫かどうかも確認しないで自動的 ++に生成されるので、より実験的です。 ++ ++2.6.x -mm カーネルパッチ ++------------------------ ++ ++Andrew Morton によってリリースされる実験的なカーネルパッチ群です。 ++Andrew は個別のサブシステムカーネルツリーとパッチを全て集めてきて ++linux-kernel メーリングリストで収集された多数のパッチと同時に一つにま ++とめます。 ++このツリーは新機能とパッチが検証される場となります。ある期間の間パッチ ++が -mm に入って価値を証明されたら、Andrew やサブシステムメンテナが、メ ++インラインへ入れるように Linus にプッシュします。 ++ ++メインカーネルツリーに含めるために Linus に送る前に、すべての新しいパッ ++チが -mm ツリーでテストされることが強く推奨されます。 ++ ++これらのカーネルは安定して動作すべきシステムとして使うのには適切ではあ ++りませんし、カーネルブランチの中でももっとも動作にリスクが高いものです。 ++ ++もしあなたが、カーネル開発プロセスの支援をしたいと思っているのであれば、 ++どうぞこれらのカーネルリリースをテストに使ってみて、そしてもし問題があ ++れば、またもし全てが正しく動作したとしても、linux-kernel メーリングリ ++ストにフィードバックを提供してください。 ++ ++すべての他の実験的パッチに加えて、これらのカーネルは通常リリース時点で ++メインラインの -git カーネルに含まれる全ての変更も含んでいます。 ++ ++-mm カーネルは決まったスケジュールではリリースされません、しかし通常幾 ++つかの -mm カーネル (1 から 3 が普通)が各-rc カーネルの間にリリースさ ++れます。 ++ ++サブシステム毎のカーネルツリーとパッチ ++------------------------------------------- ++ ++カーネルの様々な領域で何が起きているかを見られるようにするため、多くの ++カーネルサブシステム開発者は彼らの開発ツリーを公開しています。これらの ++ツリーは説明したように -mm カーネルリリースに入れ込まれます。 ++ ++以下はさまざまなカーネルツリーの中のいくつかのリスト- ++ ++ git ツリー- ++ - Kbuild の開発ツリー、Sam Ravnborg ++ kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git ++ ++ - ACPI の開発ツリー、 Len Brown ++ kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git ++ ++ - Block の開発ツリー、Jens Axboe ++ kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git ++ ++ - DRM の開発ツリー、Dave Airlie ++ kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git ++ ++ - ia64 の開発ツリー、Tony Luck ++ kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git ++ ++ - ieee1394 の開発ツリー、Jody McIntyre ++ kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394.git ++ ++ - infiniband, Roland Dreier ++ kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git ++ ++ - libata, Jeff Garzik ++ kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git ++ ++ - ネットワークドライバ, Jeff Garzik ++ kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git ++ ++ - pcmcia, Dominik Brodowski ++ kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git ++ ++ - SCSI, James Bottomley ++ kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git ++ ++ その他の git カーネルツリーは http://kernel.org/git に一覧表がありま ++ す。 ++ ++ quilt ツリー- ++ - USB, PCI ドライバコアと I2C, Greg Kroah-Hartman ++ kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ ++ ++バグレポート ++------------- ++ ++bugzilla.kernel.org は Linux カーネル開発者がカーネルのバグを追跡する ++場所です。ユーザは見つけたバグの全てをこのツールで報告すべきです。 ++どう kernel bugzilla を使うかの詳細は、以下を参照してください- ++ http://test.kernel.org/bugzilla/faq.html ++ ++メインカーネルソースディレクトリにあるファイル REPORTING-BUGS はカーネ ++ルバグらしいものについてどうレポートするかの良いテンプレートであり、問 ++題の追跡を助けるためにカーネル開発者にとってどんな情報が必要なのかの詳 ++細が書かれています。 ++ ++メーリングリスト ++------------- ++ ++上のいくつかのドキュメントで述べていますが、コアカーネル開発者の大部分 ++は Linux kernel メーリングリストに参加しています。このリストの登録/脱 ++退の方法については以下を参照してください- ++ http://vger.kernel.org/vger-lists.html#linux-kernel ++ ++このメーリングリストのアーカイブは web 上の多数の場所に存在します。こ ++れらのアーカイブを探すにはサーチエンジンを使いましょう。例えば- ++ http://dir.gmane.org/gmane.linux.kernel ++ ++リストに投稿する前にすでにその話題がアーカイブに存在するかどうかを検索 ++することを是非やってください。多数の事がすでに詳細に渡って議論されて ++おり、アーカイブにのみ記録されています。 ++ ++大部分のカーネルサブシステムも自分の個別の開発を実施するメーリングリス ++トを持っています。個々のグループがどんなリストを持っているかは、 ++MAINTAINERS ファイルにリストがありますので参照してください。 ++ ++多くのリストは kernel.org でホストされています。これらの情報は以下にあ ++ります- ++ http://vger.kernel.org/vger-lists.html ++ ++メーリングリストを使う場合、良い行動習慣に従うようにしましょう。 ++少し安っぽいが、以下の URL は上のリスト(や他のリスト)で会話する場合の ++シンプルなガイドラインを示しています- ++ http://www.albion.com/netiquette/ ++ ++もし複数の人があなたのメールに返事をした場合、CC: で受ける人のリストは ++だいぶ多くなるでしょう。良い理由がない場合、CC: リストから誰かを削除を ++しないように、また、メーリングリストのアドレスだけにリプライすることの ++ないようにしましょう。1つは送信者から、もう1つはリストからのように、メー ++ルを2回受けることになってもそれに慣れ、しゃれたメールヘッダーを追加し ++てこの状態を変えようとしないように。人々はそのようなことは好みません。 ++ ++今までのメールでのやりとりとその間のあなたの発言はそのまま残し、 ++"John Kernlehacker wrote ...:" の行をあなたのリプライの先頭行にして、 ++メールの先頭でなく、各引用行の間にあなたの言いたいことを追加するべきで ++す。 ++ ++もしパッチをメールに付ける場合は、Documentaion/SubmittingPatches に提 ++示されているように、それは プレーンな可読テキストにすることを忘れない ++ようにしましょう。カーネル開発者は 添付や圧縮したパッチを扱いたがりま ++せん- ++彼らはあなたのパッチの行毎にコメントを入れたいので、そのためにはそうす ++るしかありません。あなたのメールプログラムが空白やタブを圧縮しないよう ++に確認した方がいいです。最初の良いテストとしては、自分にメールを送って ++みて、そのパッチを自分で当ててみることです。もしそれがうまく行かないな ++ら、あなたのメールプログラムを直してもらうか、正しく動くように変えるべ ++きです。 ++ ++とりわけ、他の登録者に対する尊敬を表すようにすることを覚えておいてくだ ++さい。 ++ ++コミュニティと共に働くこと ++-------------------------- ++ ++カーネルコミュニティのゴールは可能なかぎり最高のカーネルを提供すること ++です。あなたがパッチを受け入れてもらうために投稿した場合、それは、技術 ++的メリットだけがレビューされます。その際、あなたは何を予想すべきでしょ ++うか? ++ - 批判 ++ - コメント ++ - 変更の要求 ++ - パッチの正当性の証明要求 ++ - 沈黙 ++ ++思い出してください、ここはあなたのパッチをカーネルに入れる話です。あ ++なたは、あなたのパッチに対する批判とコメントを受け入れるべきで、それら ++を技術的レベルで評価して、パッチを再作成するか、なぜそれらの変更をすべ ++きでないかを明確で簡潔な理由の説明を提供してください。 ++もし、あなたのパッチに何も反応がない場合、たまにはメールの山に埋もれて ++見逃され、あなたの投稿が忘れられてしまうこともあるので、数日待って再度 ++投稿してください。 ++ ++あなたがやるべきでないものは? ++ - 質問なしにあなたのパッチが受け入れられると想像すること ++ - 守りに入ること ++ - コメントを無視すること ++ - 要求された変更を何もしないでパッチを出し直すこと ++ ++可能な限り最高の技術的解決を求めているコミュニティでは、パッチがどのく ++らい有益なのかについては常に異なる意見があります。あなたは協調的である ++べきですし、また、あなたのアイディアをカーネルに対してうまく合わせるよ ++うにすることが望まれています。もしくは、最低限あなたのアイディアがそれ ++だけの価値があるとすすんで証明するようにしなければなりません。 ++正しい解決に向かって進もうという意志がある限り、間違うことがあっても許 ++容されることを忘れないでください。 ++ ++あなたの最初のパッチに単に 1ダースもの修正を求めるリストの返答になるこ ++とも普通のことです。これはあなたのパッチが受け入れられないということで ++は *ありません*、そしてあなた自身に反対することを意味するのでも *ありま ++せん*。単に自分のパッチに対して指摘された問題を全て修正して再送すれば ++いいのです。 ++ ++カーネルコミュニティと企業組織のちがい ++----------------------------------------------------------------- ++ ++カーネルコミュニティは大部分の伝統的な会社の開発環境とは異ったやり方で ++動いています。以下は問題を避けるためにできるとよいことののリストです- ++ ++ あなたの提案する変更について言うときのうまい言い方: ++ ++ - "これは複数の問題を解決します" ++ - "これは2000行のコードを削除します" ++ - "以下のパッチは、私が言おうとしていることを説明するものです" ++ - "私はこれを5つの異なるアーキテクチャでテストしたのですが..." ++ - "以下は一連の小さなパッチ群ですが..." ++ - "これは典型的なマシンでの性能を向上させます.." ++ ++ やめた方がいい悪い言い方: ++ ++ - このやり方で AIX/ptx/Solaris ではできたので、できるはずだ ++ - 私はこれを20年もの間やってきた、だから ++ - これは、私の会社が金儲けをするために必要だ ++ - これは我々のエンタープライズ向け商品ラインのためである ++ - これは 私が自分のアイディアを記述した、1000ページの設計資料である ++ - 私はこれについて、6ケ月作業している。 ++ - 以下は ... に関する5000行のパッチです ++ - 私は現在のぐちゃぐちゃを全部書き直した、それが以下です... ++ - 私は〆切がある、そのためこのパッチは今すぐ適用される必要がある ++ ++カーネルコミュニティが大部分の伝統的なソフトウェアエンジニアリングの労 ++働環境と異なるもう一つの点は、やりとりに顔を合わせないということです。 ++email と irc を第一のコミュニケーションの形とする一つの利点は、性別や ++民族の差別がないことです。Linux カーネルの職場環境は女性や少数民族を受 ++容します。なぜなら、email アドレスによってのみあなたが認識されるからで ++す。 ++国際的な側面からも活動領域を均等にするようにします。なぜならば、あなた ++は人の名前で性別を想像できないからです。ある男性が アンドレアという名 ++前で、女性の名前は パット かもしれません (訳注 Andrea は米国では女性、 ++それ以外(欧州など)では男性名として使われることが多い。同様に、Pat は ++Patricia (主に女性名)や Patrick (主に男性名)の略称)。 ++Linux カーネルの活動をして、意見を表明したことがある大部分の女性は、前 ++向きな経験をもっています。 ++ ++言葉の壁は英語が得意でない一部の人には問題になります。 ++メーリングリストの中できちんとアイディアを交換するには、相当うまく英語 ++を操れる必要があることもあります。そのため、あなたは自分のメール ++を送る前に英語で意味が通じているかをチェックすることをお薦めします。 ++ ++変更を分割する ++--------------------- ++ ++Linux カーネルコミュニティは、一度に大量のコードの塊を喜んで受容するこ ++とはありません。変更は正確に説明される必要があり、議論され、小さい、個 ++別の部分に分割する必要があります。これはこれまで多くの会社がやり慣れて ++きたことと全く正反対のことです。あなたのプロポーザルは、開発プロセスのと ++ても早い段階から紹介されるべきです。そうすれば あなたは自分のやってい ++ることにフィードバックを得られます。これは、コミュニティからみれば、あ ++なたが彼らと一緒にやっているように感じられ、単にあなたの提案する機能の ++ゴミ捨て場として使っているのではない、と感じられるでしょう。 ++しかし、一度に 50 もの email をメーリングリストに送りつけるようなことは ++やってはいけません、あなたのパッチ群はいつもどんな時でもそれよりは小さ ++くなければなりません。 ++ ++パッチを分割する理由は以下です- ++ ++1) 小さいパッチはあなたのパッチが適用される見込みを大きくします、カー ++ ネルの人達はパッチが正しいかどうかを確認する時間や労力をかけないか ++ らです。5行のパッチはメンテナがたった1秒見るだけで適用できます。し ++ かし、500行のパッチは、正しいことをレビューするのに数時間かかるかも ++ しれません(時間はパッチのサイズなどにより指数関数に比例してかかりま ++ す) ++ 小さいパッチは何かあったときにデバッグもとても簡単になります。パッ ++ チを1個1個取り除くのは、とても大きなパッチを当てた後に(かつ、何かお ++ かしくなった後で)解剖するのに比べればとても簡単です。 ++ ++2) 小さいパッチを送るだけでなく、送るまえに、書き直して、シンプルにす ++ る(もしくは、単に順番を変えるだけでも)ことも、とても重要です。 ++ ++以下はカーネル開発者の Al Viro のたとえ話しです: ++ ++ "生徒の数学の宿題を採点する先生のことを考えてみてください、先 ++ 生は生徒が解に到達するまでの試行錯誤をみたいとは思わないでしょ ++ う。先生は簡潔な最高の解をみたいのです。良い生徒はこれを知って ++ おり、そして最終解の前の中間作業を提出することは決してないので ++ す" ++ カーネル開発でもこれは同じです。メンテナー達とレビューア達は、 ++ 問題を解決する解の背後になる思考プロセスをみたいとは思いません。 ++ 彼らは単純であざやかな解決方法をみたいのです。 ++ ++あざやかな解を説明するのと、コミュニティと共に仕事をし、未解決の仕事を ++議論することのバランスをキープするのは難しいかもしれません。 ++ですから、開発プロセスの早期段階で改善のためのフィードバックをもらうよ ++うにするのもいいですが、変更点を小さい部分に分割して全体ではまだ完成し ++ていない仕事を(部分的に)取り込んでもらえるようにすることもいいことです。 ++ ++また、でき上がっていないものや、"将来直す" ようなパッチを、本流に含め ++てもらうように送っても、それは受け付けられないことを理解してください。 ++ ++あなたの変更を正当化する ++------------------- ++ ++あなたのパッチを分割するのと同時に、なぜその変更を追加しなければならな ++いかを Linux コミュニティに知らせることはとても重要です。新機能は必要 ++性と有用性で正当化されなければなりません。 ++ ++あなたの変更の説明 ++-------------------- ++ ++あなたのパッチを送付する場合には、メールの中のテキストで何を言うかにつ ++いて、特別に注意を払ってください。この情報はパッチの ChangeLog に使わ ++れ、いつも皆がみられるように保管されます。これは次のような項目を含め、 ++パッチを完全に記述するべきです- ++ ++ - なぜ変更が必要か ++ - パッチ全体の設計アプローチ ++ - 実装の詳細 ++ - テスト結果 ++ ++これについて全てがどのようにあるべきかについての詳細は、以下のドキュメ ++ントの ChangeLog セクションをみてください- ++ "The Perfect Patch" ++ http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt ++ ++これらのどれもが、時にはとても困難です。これらの慣例を完璧に実施するに ++は数年かかるかもしれません。これは継続的な改善のプロセスであり、そのた ++めには多数の忍耐と決意を必要とするものです。でも、諦めないで、これは可 ++能なことです。多数の人がすでにできていますし、彼らも皆最初はあなたと同 ++じところからスタートしたのですから。 ++ ++Paolo Ciarrocchi に感謝、彼は彼の書いた "Development Process" ++(http://linux.tar.bz/articles/2.6-development_process)セクショ ++ンをこのテキストの原型にすることを許可してくれました。 ++Rundy Dunlap と Gerrit Huizenga はメーリングリストでやるべきこととやっ ++てはいけないことのリストを提供してくれました。 ++以下の人々のレビュー、コメント、貢献に感謝。 ++Pat Mochel, Hanna Linder, Randy Dunlap, Kay Sievers, ++Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook, Andrew Morton, Andi ++Kleen, Vadim Lobanov, Jesper Juhl, Adrian Bunk, Keri Harris, Frans Pop, ++David A. Wheeler, Junio Hamano, Michael Kerrisk, と Alex Shepard ++彼らの支援なしでは、このドキュメントはできなかったでしょう。 ++ ++Maintainer: Greg Kroah-Hartman +diff -Nurp linux-2.6.22/Documentation/ja_JP/stable_api_nonsense.txt linux-2.6-netns/Documentation/ja_JP/stable_api_nonsense.txt +--- linux-2.6.22/Documentation/ja_JP/stable_api_nonsense.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/ja_JP/stable_api_nonsense.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -0,0 +1,263 @@ ++NOTE: ++This is a Japanese translated version of ++"Documentation/stable_api_nonsense.txt". ++This one is maintained by ++IKEDA, Munehiro ++and JF Project team . ++If you find difference with original file or problem in translation, ++please contact the maintainer of this file or JF project. ++ ++Please also note that purpose of this file is easier to read for non ++English natives and not to be intended to fork. So, if you have any ++comments or updates of this file, please try to update ++Original(English) file at first. ++ ++================================== ++これは、 ++linux-2.6.22-rc4/Documentation/stable_api_nonsense.txt の和訳 ++です。 ++翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ > ++翻訳日 : 2007/06/11 ++原著作者: Greg Kroah-Hartman < greg at kroah dot com > ++翻訳者 : 池田 宗広 < m-ikeda at ds dot jp dot nec dot com > ++校正者 : Masanori Kobayashi さん < zap03216 at nifty dot ne dot jp > ++ Seiji Kaneko さん < skaneko at a2 dot mbn dot or dot jp > ++================================== ++ ++ ++ ++Linux カーネルのドライバインターフェース ++(あなたの質問すべてに対する回答とその他諸々) ++ ++Greg Kroah-Hartman ++ ++ ++この文書は、なぜ Linux ではバイナリカーネルインターフェースが定義 ++されていないのか、またはなぜ不変のカーネルインターフェースを持たな ++いのか、ということを説明するために書かれた。ここでの話題は「カーネ ++ル内部の」インターフェースについてであり、ユーザー空間とのインター ++フェースではないことを理解してほしい。カーネルとユーザー空間とのイ ++ンターフェースとはアプリケーションプログラムが使用するものであり、 ++つまりシステムコールのインターフェースがこれに当たる。これは今まで ++長きに渡り、かつ今後も「まさしく」不変である。私は確か 0.9 か何か ++より前のカーネルを使ってビルドした古いプログラムを持っているが、そ ++れは最新の 2.6 カーネルでもきちんと動作する。ユーザー空間とのイン ++ターフェースは、ユーザーとアプリケーションプログラマが不変性を信頼 ++してよいものの一つである。 ++ ++ ++要旨 ++---- ++ ++あなたは不変のカーネルインターフェースが必要だと考えているかもしれ ++ないが、実際のところはそうではない。あなたは必要としているものが分 ++かっていない。あなたが必要としているものは安定して動作するドライバ ++であり、それはドライバがメインのカーネルツリーに含まれる場合のみ得 ++ることができる。ドライバがメインのカーネルツリーに含まれていると、 ++他にも多くの良いことがある。それは、Linux をより強固で、安定な、成 ++熟したオペレーティングシステムにすることができるということだ。これ ++こそ、そもそもあなたが Linux を使う理由のはずだ。 ++ ++ ++はじめに ++-------- ++ ++カーネル内部のインターフェース変更を心配しなければならないドライバ ++を書きたいなどというのは、変わり者だけだ。この世界のほとんどの人は、 ++そのようなドライバがどんなインターフェースを使っているかなど知らな ++いし、そんなドライバのことなど全く気にもかけていない。 ++ ++ ++まず初めに、クローズソースとか、ソースコードの隠蔽とか、バイナリの ++みが配布される使い物にならない代物[訳注(1)]とか、実体はバイナリ ++コードでそれを読み込むためのラッパー部分のみソースコードが公開され ++ているとか、その他用語は何であれ GPL の下にソースコードがリリース ++されていないカーネルドライバに関する法的な問題について、私は「いか ++なる議論も」行うつもりがない。法的な疑問があるのならば、プログラマ ++である私ではなく、弁護士に相談して欲しい。ここでは単に、技術的な問 ++題について述べることにする。(法的な問題を軽視しているわけではない。 ++それらは実際に存在するし、あなたはそれをいつも気にかけておく必要が ++ある) ++ ++訳注(1) ++「使い物にならない代物」の原文は "blob" ++ ++ ++さてここでは、バイナリカーネルインターフェースについてと、ソースレ ++ベルでのインターフェースの不変性について、という二つの話題を取り上 ++げる。この二つは互いに依存する関係にあるが、まずはバイナリインター ++フェースについて議論を行いやっつけてしまおう。 ++ ++ ++バイナリカーネルインターフェース ++-------------------------------- ++ ++もしソースレベルでのインターフェースが不変ならば、バイナリインター ++フェースも当然のように不変である、というのは正しいだろうか?正しく ++ない。Linux カーネルに関する以下の事実を考えてみてほしい。 ++ - あなたが使用するCコンパイラのバージョンによって、カーネル内部 ++ の構造体の配置構造は異なったものになる。また、関数は異なった方 ++ 法でカーネルに含まれることになるかもしれない(例えばインライン ++ 関数として扱われたり、扱われなかったりする)。個々の関数がどの ++ ようにコンパイルされるかはそれほど重要ではないが、構造体のパデ ++ ィングが異なるというのは非常に重要である。 ++ - あなたがカーネルのビルドオプションをどのように設定するかによっ ++ て、カーネルには広い範囲で異なった事態が起こり得る。 ++ - データ構造は異なるデータフィールドを持つかもしれない ++ - いくつかの関数は全く実装されていない状態になり得る ++ (例:SMP向けではないビルドでは、いくつかのロックは中身が ++ カラにコンパイルされる) ++ - カーネル内のメモリは、異なった方法で配置され得る。これはビ ++ ルドオプションに依存している。 ++ - Linux は様々な異なるプロセッサアーキテクチャ上で動作する。 ++ あるアーキテクチャ用のバイナリドライバを、他のアーキテクチャで ++ 正常に動作させる方法はない。 ++ ++ ++ある特定のカーネル設定を使用し、カーネルをビルドしたのと正確に同じ ++Cコンパイラを使用して単にカーネルモジュールをコンパイルするだけで ++も、あなたはこれらいくつもの問題に直面することになる。ある特定の ++Linux ディストリビューションの、ある特定のリリースバージョン用にモ ++ジュールを提供しようと思っただけでも、これらの問題を引き起こすには ++十分である。にも関わらず Linux ディストリビューションの数と、サ ++ポートするディストリビューションのリリース数を掛け算し、それら一つ ++一つについてビルドを行ったとしたら、今度はリリースごとのビルドオプ ++ションの違いという悪夢にすぐさま悩まされることになる。また、ディス ++トリビューションの各リリースバージョンには、異なるハードウェア(プ ++ロセッサタイプや種々のオプション)に対応するため、何種類かのカーネ ++ルが含まれているということも理解して欲しい。従って、ある一つのリ ++リースバージョンだけのためにモジュールを作成する場合でも、あなたは ++何バージョンものモジュールを用意しなければならない。 ++ ++ ++信じて欲しい。このような方法でサポートを続けようとするなら、あなた ++はいずれ正気を失うだろう。遠い昔、私はそれがいかに困難なことか、身 ++をもって学んだのだ・・・ ++ ++ ++不変のカーネルソースレベルインターフェース ++------------------------------------------ ++ ++メインカーネルツリーに含まれていない Linux カーネルドライバを継続 ++してサポートしていこうとしている人たちとの議論においては、これは極 ++めて「引火性の高い」話題である。[訳注(2)] ++ ++訳注(2) ++「引火性の高い」の原文は "volatile"。 ++volatile には「揮発性の」「爆発しやすい」という意味の他、「変わり ++やすい」「移り気な」という意味がある。 ++「(この話題は)爆発的に激しい論争を巻き起こしかねない」ということ ++を、「(カーネルのソースレベルインターフェースは)移ろい行くもので ++ある」ということを連想させる "volatile" という単語で表現している。 ++ ++ ++Linux カーネルの開発は継続的に速いペースで行われ、決して歩みを緩め ++ることがない。その中でカーネル開発者達は、現状のインターフェースに ++あるバグを見つけ、より良い方法を考え出す。彼らはやがて、現状のイン ++ターフェースがより正しく動作するように修正を行う。その過程で関数の ++名前は変更されるかもしれず、構造体は大きく、または小さくなるかもし ++れず、関数の引数は検討しなおされるかもしれない。そのような場合、引 ++き続き全てが正常に動作するよう、カーネル内でこれらのインターフェー ++スを使用している個所も全て同時に修正される。 ++ ++ ++具体的な例として、カーネル内の USB インターフェースを挙げる。USB ++サブシステムはこれまでに少なくとも3回の書き直しが行われ、その結果 ++インターフェースが変更された。これらの書き直しはいくつかの異なった ++問題を修正するために行われた。 ++ - 同期的データストリームが非同期に変更された。これにより多数のド ++ ライバを単純化でき、全てのドライバのスループットが向上した。今 ++ やほとんど全ての USB デバイスは、考えられる最高の速度で動作し ++ ている。 ++ - USB ドライバが USB サブシステムのコアから行う、データパケット ++ 用のメモリ確保方法が変更された。これに伴い、いくつもの文書化さ ++ れたデッドロック条件を回避するため、全ての USB ドライバはより ++ 多くの情報を USB コアに提供しなければならないようになっている。 ++ ++ ++このできごとは、数多く存在するクローズソースのオペレーティングシス ++テムとは全く対照的だ。それらは長期に渡り古い USB インターフェース ++をメンテナンスしなければならない。古いインターフェースが残ることで、 ++新たな開発者が偶然古いインターフェースを使い、正しくない方法で開発 ++を行ってしまう可能性が生じる。これによりシステムの安定性は危険にさ ++らされることになる。 ++ ++ ++上に挙げたどちらの例においても、開発者達はその変更が重要かつ必要で ++あることに合意し、比較的楽にそれを実行した。もし Linux がソースレ ++ベルでインターフェースの不変性を保証しなければならないとしたら、新 ++しいインターフェースを作ると同時に、古い、問題のある方を今後ともメ ++ンテナンスするという余計な仕事を USB の開発者にさせなければならな ++い。Linux の USB 開発者は、自分の時間を使って仕事をしている。よっ ++て、価値のない余計な仕事を報酬もなしに実行しろと言うことはできない。 ++ ++ ++セキュリティ問題も、Linux にとっては非常に重要である。ひとたびセキ ++ュリティに関する問題が発見されれば、それは極めて短期間のうちに修正 ++される。セキュリティ問題の発生を防ぐための修正は、カーネルの内部イ ++ンターフェースの変更を何度も引き起こしてきた。その際同時に、変更さ ++れたインターフェースを使用する全てのドライバもまた変更された。これ ++により問題が解消し、将来偶然に問題が再発してしまわないことが保証さ ++れる。もし内部インターフェースの変更が許されないとしたら、このよう ++にセキュリティ問題を修正し、将来再発しないことを保証することなど不 ++可能なのだ。 ++ ++ ++カーネルのインターフェースは時が経つにつれクリーンナップを受ける。 ++誰も使っていないインターフェースは削除される。これにより、可能な限 ++りカーネルが小さく保たれ、現役の全てのインターフェースが可能な限り ++テストされることを保証しているのだ。(使われていないインターフェー ++スの妥当性をテストすることは不可能と言っていいだろう) ++ ++ ++ ++これから何をすべきか ++----------------------- ++ ++では、もしメインのカーネルツリーに含まれない Linux カーネルドライ ++バがあったとして、あなたは、つまり開発者は何をするべきだろうか?全 ++てのディストリビューションの全てのカーネルバージョン向けにバイナリ ++のドライバを供給することは悪夢であり、カーネルインターフェースの変 ++更を追いかけ続けることもまた過酷な仕事だ。 ++ ++ ++答えは簡単。そのドライバをメインのカーネルツリーに入れてしまえばよ ++い。(ここで言及しているのは、GPL に従って公開されるドライバのこと ++だということに注意してほしい。あなたのコードがそれに該当しないなら ++ば、さよなら。幸運を祈ります。ご自分で何とかしてください。Andrew ++と Linus からのコメント<Andrew と Linus のコメントへのリンクをこ ++こに置く>をどうぞ)ドライバがメインツリーに入れば、カーネルのイン ++ターフェースが変更された場合、変更を行った開発者によってドライバも ++修正されることになるだろう。あなたはほとんど労力を払うことなしに、 ++常にビルド可能できちんと動作するドライバを手に入れることができる。 ++ ++ ++ドライバをメインのカーネルツリーに入れると、非常に好ましい以下の効 ++果がある。 ++ - ドライバの品質が向上する一方で、(元の開発者にとっての)メンテ ++ ナンスコストは下がる。 ++ - あなたのドライバに他の開発者が機能を追加してくれる。 ++ - 誰かがあなたのドライバにあるバグを見つけ、修正してくれる。 ++ - 誰かがあなたのドライバにある改善点を見つけてくれる。 ++ - 外部インターフェースが変更されドライバの更新が必要になった場合、 ++ 誰かがあなたの代わりに更新してくれる。 ++ - ドライバを入れてくれとディストロに頼まなくても、そのドライバは ++ 全ての Linux ディストリビューションに自動的に含まれてリリース ++ される。 ++ ++ ++Linux では、他のどのオペレーティングシステムよりも数多くのデバイス ++が「そのまま」使用できるようになった。また Linux は、どのオペレー ++ティングシステムよりも数多くのプロセッサアーキテクチャ上でそれらの ++デバイスを使用することができるようにもなった。このように、Linux の ++開発モデルは実証されており、今後も間違いなく正しい方向へと進んでい ++くだろう。:) ++ ++ ++ ++------ ++ ++この文書の初期の草稿に対し、Randy Dunlap, Andrew Morton, David ++Brownell, Hanna Linder, Robert Love, Nishanth Aravamudan から査読 ++と助言を頂きました。感謝申し上げます。 ++ +diff -Nurp linux-2.6.22/Documentation/kernel-parameters.txt linux-2.6-netns/Documentation/kernel-parameters.txt +--- linux-2.6.22/Documentation/kernel-parameters.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/kernel-parameters.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -34,7 +34,6 @@ parameter is applicable: + APIC APIC support is enabled. + APM Advanced Power Management support is enabled. + AX25 Appropriate AX.25 support is enabled. +- CD Appropriate CD support is enabled. + DRM Direct Rendering Management support is enabled. + EDD BIOS Enhanced Disk Drive Services (EDD) is enabled + EFI EFI Partitioning (GPT) is enabled +@@ -238,16 +237,9 @@ and is between 256 and 4096 characters. + Disable PIN 1 of APIC timer + Can be useful to work around chipset bugs. + +- ad1816= [HW,OSS] +- Format: ,,, +- See also Documentation/sound/oss/AD1816. +- + ad1848= [HW,OSS] + Format: ,,,, + +- adlib= [HW,OSS] +- Format: +- + advansys= [HW,SCSI] + See header of drivers/scsi/advansys.c. + +@@ -326,9 +318,6 @@ and is between 256 and 4096 characters. + + autotest [IA64] + +- aztcd= [HW,CD] Aztech CD268 CDROM driver +- Format: ,0x79 (?) +- + baycom_epp= [HW,AX25] + Format: , + +@@ -371,10 +360,6 @@ and is between 256 and 4096 characters. + possible to determine what the correct size should be. + This option provides an override for these situations. + +- cdu31a= [HW,CD] +- Format: ,[,PAS] +- See header of drivers/cdrom/cdu31a.c. +- + chandev= [HW,NET] Generic channel device initialisation + + checkreqprot [SELINUX] Set initial checkreqprot flag value. +@@ -428,9 +413,6 @@ and is between 256 and 4096 characters. + hpet= [IA-32,HPET] option to disable HPET and use PIT. + Format: disable + +- cm206= [HW,CD] +- Format: { auto | [,][] } +- + com20020= [HW,NET] ARCnet - COM20020 chipset + Format: + [,[,[,[,[,]]]]] +@@ -462,13 +444,20 @@ and is between 256 and 4096 characters. + Documentation/networking/netconsole.txt for an + alternative. + +- uart,io,[,options] +- uart,mmio,[,options] ++ uart[8250],io,[,options] ++ uart[8250],mmio,[,options] + Start an early, polled-mode console on the 8250/16550 + UART at the specified I/O port or MMIO address, + switching to the matching ttyS device later. The + options are the same as for ttyS, above. + ++ earlycon= [KNL] Output early console device and options. ++ uart[8250],io,[,options] ++ uart[8250],mmio,[,options] ++ Start an early, polled-mode console on the 8250/16550 ++ UART at the specified I/O port or MMIO address. ++ The options are the same as for ttyS, above. ++ + cpcihp_generic= [HW,PCI] Generic port I/O CompactPCI driver + Format: + ,,,[,] +@@ -660,9 +649,6 @@ and is between 256 and 4096 characters. + gpt [EFI] Forces disk with valid GPT signature but + invalid Protective MBR to be treated as GPT. + +- gscd= [HW,CD] +- Format: +- + gvp11= [HW,SCSI] + + hashdist= [KNL,NUMA] Large hashes allocated during boot +@@ -826,14 +812,37 @@ and is between 256 and 4096 characters. + tasks in the system -- can cause problems and + suboptimal load balancer performance. + +- isp16= [HW,CD] +- Format: ,,, +- + iucv= [HW,NET] + + js= [HW,JOY] Analog joystick + See Documentation/input/joystick.txt. + ++ kernelcore=nn[KMG] [KNL,IA-32,IA-64,PPC,X86-64] This parameter ++ specifies the amount of memory usable by the kernel ++ for non-movable allocations. The requested amount is ++ spread evenly throughout all nodes in the system. The ++ remaining memory in each node is used for Movable ++ pages. In the event, a node is too small to have both ++ kernelcore and Movable pages, kernelcore pages will ++ take priority and other nodes will have a larger number ++ of kernelcore pages. The Movable zone is used for the ++ allocation of pages that may be reclaimed or moved ++ by the page migration subsystem. This means that ++ HugeTLB pages may not be allocated from this zone. ++ Note that allocations like PTEs-from-HighMem still ++ use the HighMem zone if it exists, and the Normal ++ zone if it does not. ++ ++ movablecore=nn[KMG] [KNL,IA-32,IA-64,PPC,X86-64] This parameter ++ is similar to kernelcore except it specifies the ++ amount of memory used for migratable allocations. ++ If both kernelcore and movablecore is specified, ++ then kernelcore will be at *least* the specified ++ value but may be more. If movablecore on its own ++ is specified, the administrator must be careful ++ that the amount of memory usable for all allocations ++ is not too small. ++ + keepinitrd [HW,ARM] + + kstack=N [IA-32,X86-64] Print N words from the kernel stack +@@ -967,11 +976,6 @@ and is between 256 and 4096 characters. + + mcatest= [IA-64] + +- mcd= [HW,CD] +- Format: ,, +- +- mcdx= [HW,CD] +- + mce [IA-32] Machine Check Exception + + md= [HW] RAID subsystems devices and level +@@ -1014,49 +1018,6 @@ and is between 256 and 4096 characters. + + mga= [HW,DRM] + +- migration_cost= +- [KNL,SMP] debug: override scheduler migration costs +- Format: ,,... +- This debugging option can be used to override the +- default scheduler migration cost matrix. The numbers +- are indexed by 'CPU domain distance'. +- E.g. migration_cost=1000,2000,3000 on an SMT NUMA +- box will set up an intra-core migration cost of +- 1 msec, an inter-core migration cost of 2 msecs, +- and an inter-node migration cost of 3 msecs. +- +- WARNING: using the wrong values here can break +- scheduler performance, so it's only for scheduler +- development purposes, not production environments. +- +- migration_debug= +- [KNL,SMP] migration cost auto-detect verbosity +- Format=<0|1|2> +- If a system's migration matrix reported at bootup +- seems erroneous then this option can be used to +- increase verbosity of the detection process. +- We default to 0 (no extra messages), 1 will print +- some more information, and 2 will be really +- verbose (probably only useful if you also have a +- serial console attached to the system). +- +- migration_factor= +- [KNL,SMP] multiply/divide migration costs by a factor +- Format= +- This debug option can be used to proportionally +- increase or decrease the auto-detected migration +- costs for all entries of the migration matrix. +- E.g. migration_factor=150 will increase migration +- costs by 50%. (and thus the scheduler will be less +- eager migrating cache-hot tasks) +- migration_factor=80 will decrease migration costs +- by 20%. (thus the scheduler will be more eager to +- migrate tasks) +- +- WARNING: using the wrong values here can break +- scheduler performance, so it's only for scheduler +- development purposes, not production environments. +- + mousedev.tap_time= + [MOUSE] Maximum time between finger touching and + leaving touchpad surface for touch to be considered +@@ -1224,6 +1185,8 @@ and is between 256 and 4096 characters. + + nosmp [SMP] Tells an SMP kernel to act as a UP kernel. + ++ nosoftlockup [KNL] Disable the soft-lockup detector. ++ + nosync [HW,M68K] Disables sync negotiation for all devices. + + notsc [BUGS=IA-32] Disable Time Stamp Counter +@@ -1232,20 +1195,19 @@ and is between 256 and 4096 characters. + + nowb [ARM] + ++ numa_zonelist_order= [KNL, BOOT] Select zonelist order for NUMA. ++ one of ['zone', 'node', 'default'] can be specified ++ This can be set from sysctl after boot. ++ See Documentation/sysctl/vm.txt for details. ++ + nr_uarts= [SERIAL] maximum number of UARTs to be registered. + + opl3= [HW,OSS] + Format: + +- opl3sa2= [HW,OSS] Format: +- ,,,,,,,[,, +- + osst= [HW,SCSI] SCSI Tape Driver + Format: , + See also Documentation/scsi/st.txt. +@@ -1424,6 +1386,15 @@ and is between 256 and 4096 characters. + autoconfiguration. + Ranges are in pairs (memory base and size). + ++ print-fatal-signals= ++ [KNL] debug: print fatal signals ++ print-fatal-signals=1: print segfault info to ++ the kernel console. ++ default: off. ++ ++ printk.time= Show timing data prefixed to each printk message line ++ Format: (1/Y/y=enable, 0/N/n=disable) ++ + profile= [KNL] Enable kernel profiling via /proc/profile + Format: [schedule,] + Param: "schedule" - profile schedule points. +@@ -1536,6 +1507,10 @@ and is between 256 and 4096 characters. + + rootfstype= [KNL] Set root filesystem type + ++ rootwait [KNL] Wait (indefinitely) for root device to show up. ++ Useful for devices that are detected asynchronously ++ (e.g. USB and MMC devices). ++ + rw [KNL] Mount root device read-write on boot + + S [KNL] Run init in single mode +@@ -1548,11 +1523,6 @@ and is between 256 and 4096 characters. + + sbni= [NET] Granch SBNI12 leased line adapter + +- sbpcd= [HW,CD] Soundblaster CD adapter +- Format: , +- See a comment before function sbpcd_setup() in +- drivers/cdrom/sbpcd.c. +- + sc1200wdt= [HW,WDT] SC1200 WDT (watchdog) driver + Format: [,[,]] + +@@ -1605,41 +1575,41 @@ and is between 256 and 4096 characters. + simeth= [IA-64] + simscsi= + +- sjcd= [HW,CD] +- Format: ,, +- See header of drivers/cdrom/sjcd.c. +- + slram= [HW,MTD] + +- slub_debug [MM, SLUB] +- Enabling slub_debug allows one to determine the culprit +- if slab objects become corrupted. Enabling slub_debug +- creates guard zones around objects and poisons objects +- when not in use. Also tracks the last alloc / free. +- For more information see Documentation/vm/slub.txt. ++ slub_debug[=options[,slabs]] [MM, SLUB] ++ Enabling slub_debug allows one to determine the ++ culprit if slab objects become corrupted. Enabling ++ slub_debug can create guard zones around objects and ++ may poison objects when not in use. Also tracks the ++ last alloc / free. For more information see ++ Documentation/vm/slub.txt. + + slub_max_order= [MM, SLUB] +- Determines the maximum allowed order for slabs. Setting +- this too high may cause fragmentation. +- For more information see Documentation/vm/slub.txt. ++ Determines the maximum allowed order for slabs. ++ A high setting may cause OOMs due to memory ++ fragmentation. For more information see ++ Documentation/vm/slub.txt. + + slub_min_objects= [MM, SLUB] +- The minimum objects per slab. SLUB will increase the +- slab order up to slub_max_order to generate a +- sufficiently big slab to satisfy the number of objects. +- The higher the number of objects the smaller the overhead +- of tracking slabs. ++ The minimum number of objects per slab. SLUB will ++ increase the slab order up to slub_max_order to ++ generate a sufficiently large slab able to contain ++ the number of objects indicated. The higher the number ++ of objects the smaller the overhead of tracking slabs ++ and the less frequently locks need to be acquired. + For more information see Documentation/vm/slub.txt. + + slub_min_order= [MM, SLUB] + Determines the mininum page order for slabs. Must be +- lower than slub_max_order ++ lower than slub_max_order. + For more information see Documentation/vm/slub.txt. + + slub_nomerge [MM, SLUB] +- Disable merging of slabs of similar size. May be ++ Disable merging of slabs with similar size. May be + necessary if there is some reason to distinguish +- allocs to different slabs. ++ allocs to different slabs. Debug options disable ++ merging on their own. + For more information see Documentation/vm/slub.txt. + + smart2= [HW] +@@ -1781,9 +1751,6 @@ and is between 256 and 4096 characters. + + snd-ymfpci= [HW,ALSA] + +- sonycd535= [HW,CD] +- Format: [,] +- + sonypi.*= [HW] Sony Programmable I/O Control Device driver + See Documentation/sonypi.txt + +@@ -1855,6 +1822,7 @@ and is between 256 and 4096 characters. + Set number of hash buckets for TCP connection + + time Show timing data prefixed to each printk message line ++ [deprecated, see 'printk.time'] + + tipar.timeout= [HW,PPT] + Set communications timeout in tenths of a second +diff -Nurp linux-2.6.22/Documentation/m68k/kernel-options.txt linux-2.6-netns/Documentation/m68k/kernel-options.txt +--- linux-2.6.22/Documentation/m68k/kernel-options.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/m68k/kernel-options.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -82,13 +82,6 @@ Valid names are: + /dev/fd : -> 0x0200 (floppy disk) + /dev/xda: -> 0x0c00 (first XT disk, unused in Linux/m68k) + /dev/xdb: -> 0x0c40 (second XT disk, unused in Linux/m68k) +- /dev/ada: -> 0x1c00 (first ACSI device) +- /dev/adb: -> 0x1c10 (second ACSI device) +- /dev/adc: -> 0x1c20 (third ACSI device) +- /dev/add: -> 0x1c30 (forth ACSI device) +- +-The last four names are available only if the kernel has been compiled +-with Atari and ACSI support. + + The name must be followed by a decimal number, that stands for the + partition number. Internally, the value of the number is just +diff -Nurp linux-2.6.22/Documentation/networking/00-INDEX linux-2.6-netns/Documentation/networking/00-INDEX +--- linux-2.6.22/Documentation/networking/00-INDEX 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/networking/00-INDEX 2007-12-03 23:14:12.000000000 -0500 +@@ -96,9 +96,6 @@ routing.txt + - the new routing mechanism + shaper.txt + - info on the module that can shape/limit transmitted traffic. +-sk98lin.txt +- - Marvell Yukon Chipset / SysKonnect SK-98xx compliant Gigabit +- Ethernet Adapter family driver info + skfp.txt + - SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info. + smc9.txt +diff -Nurp linux-2.6.22/Documentation/networking/ip-sysctl.txt linux-2.6-netns/Documentation/networking/ip-sysctl.txt +--- linux-2.6.22/Documentation/networking/ip-sysctl.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/networking/ip-sysctl.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -433,6 +433,12 @@ tcp_workaround_signed_windows - BOOLEAN + not receive a window scaling option from them. + Default: 0 + ++tcp_dma_copybreak - INTEGER ++ Lower limit, in bytes, of the size of socket reads that will be ++ offloaded to a DMA copy engine, if one is present in the system ++ and CONFIG_NET_DMA is enabled. ++ Default: 4096 ++ + CIPSOv4 Variables: + + cipso_cache_enable - BOOLEAN +@@ -874,8 +880,7 @@ accept_redirects - BOOLEAN + accept_source_route - INTEGER + Accept source routing (routing extension header). + +- > 0: Accept routing header. +- = 0: Accept only routing header type 2. ++ >= 0: Accept only routing header type 2. + < 0: Do not accept routing header. + + Default: 0 +diff -Nurp linux-2.6.22/Documentation/networking/l2tp.txt linux-2.6-netns/Documentation/networking/l2tp.txt +--- linux-2.6.22/Documentation/networking/l2tp.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/networking/l2tp.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,169 @@ ++This brief document describes how to use the kernel's PPPoL2TP driver ++to provide L2TP functionality. L2TP is a protocol that tunnels one or ++more PPP sessions over a UDP tunnel. It is commonly used for VPNs ++(L2TP/IPSec) and by ISPs to tunnel subscriber PPP sessions over an IP ++network infrastructure. ++ ++Design ++====== ++ ++The PPPoL2TP driver, drivers/net/pppol2tp.c, provides a mechanism by ++which PPP frames carried through an L2TP session are passed through ++the kernel's PPP subsystem. The standard PPP daemon, pppd, handles all ++PPP interaction with the peer. PPP network interfaces are created for ++each local PPP endpoint. ++ ++The L2TP protocol http://www.faqs.org/rfcs/rfc2661.html defines L2TP ++control and data frames. L2TP control frames carry messages between ++L2TP clients/servers and are used to setup / teardown tunnels and ++sessions. An L2TP client or server is implemented in userspace and ++will use a regular UDP socket per tunnel. L2TP data frames carry PPP ++frames, which may be PPP control or PPP data. The kernel's PPP ++subsystem arranges for PPP control frames to be delivered to pppd, ++while data frames are forwarded as usual. ++ ++Each tunnel and session within a tunnel is assigned a unique tunnel_id ++and session_id. These ids are carried in the L2TP header of every ++control and data packet. The pppol2tp driver uses them to lookup ++internal tunnel and/or session contexts. Zero tunnel / session ids are ++treated specially - zero ids are never assigned to tunnels or sessions ++in the network. In the driver, the tunnel context keeps a pointer to ++the tunnel UDP socket. The session context keeps a pointer to the ++PPPoL2TP socket, as well as other data that lets the driver interface ++to the kernel PPP subsystem. ++ ++Note that the pppol2tp kernel driver handles only L2TP data frames; ++L2TP control frames are simply passed up to userspace in the UDP ++tunnel socket. The kernel handles all datapath aspects of the ++protocol, including data packet resequencing (if enabled). ++ ++There are a number of requirements on the userspace L2TP daemon in ++order to use the pppol2tp driver. ++ ++1. Use a UDP socket per tunnel. ++ ++2. Create a single PPPoL2TP socket per tunnel bound to a special null ++ session id. This is used only for communicating with the driver but ++ must remain open while the tunnel is active. Opening this tunnel ++ management socket causes the driver to mark the tunnel socket as an ++ L2TP UDP encapsulation socket and flags it for use by the ++ referenced tunnel id. This hooks up the UDP receive path via ++ udp_encap_rcv() in net/ipv4/udp.c. PPP data frames are never passed ++ in this special PPPoX socket. ++ ++3. Create a PPPoL2TP socket per L2TP session. This is typically done ++ by starting pppd with the pppol2tp plugin and appropriate ++ arguments. A PPPoL2TP tunnel management socket (Step 2) must be ++ created before the first PPPoL2TP session socket is created. ++ ++When creating PPPoL2TP sockets, the application provides information ++to the driver about the socket in a socket connect() call. Source and ++destination tunnel and session ids are provided, as well as the file ++descriptor of a UDP socket. See struct pppol2tp_addr in ++include/linux/if_ppp.h. Note that zero tunnel / session ids are ++treated specially. When creating the per-tunnel PPPoL2TP management ++socket in Step 2 above, zero source and destination session ids are ++specified, which tells the driver to prepare the supplied UDP file ++descriptor for use as an L2TP tunnel socket. ++ ++Userspace may control behavior of the tunnel or session using ++setsockopt and ioctl on the PPPoX socket. The following socket ++options are supported:- ++ ++DEBUG - bitmask of debug message categories. See below. ++SENDSEQ - 0 => don't send packets with sequence numbers ++ 1 => send packets with sequence numbers ++RECVSEQ - 0 => receive packet sequence numbers are optional ++ 1 => drop receive packets without sequence numbers ++LNSMODE - 0 => act as LAC. ++ 1 => act as LNS. ++REORDERTO - reorder timeout (in millisecs). If 0, don't try to reorder. ++ ++Only the DEBUG option is supported by the special tunnel management ++PPPoX socket. ++ ++In addition to the standard PPP ioctls, a PPPIOCGL2TPSTATS is provided ++to retrieve tunnel and session statistics from the kernel using the ++PPPoX socket of the appropriate tunnel or session. ++ ++Debugging ++========= ++ ++The driver supports a flexible debug scheme where kernel trace ++messages may be optionally enabled per tunnel and per session. Care is ++needed when debugging a live system since the messages are not ++rate-limited and a busy system could be swamped. Userspace uses ++setsockopt on the PPPoX socket to set a debug mask. ++ ++The following debug mask bits are available: ++ ++PPPOL2TP_MSG_DEBUG verbose debug (if compiled in) ++PPPOL2TP_MSG_CONTROL userspace - kernel interface ++PPPOL2TP_MSG_SEQ sequence numbers handling ++PPPOL2TP_MSG_DATA data packets ++ ++Sample Userspace Code ++===================== ++ ++1. Create tunnel management PPPoX socket ++ ++ kernel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); ++ if (kernel_fd >= 0) { ++ struct sockaddr_pppol2tp sax; ++ struct sockaddr_in const *peer_addr; ++ ++ peer_addr = l2tp_tunnel_get_peer_addr(tunnel); ++ memset(&sax, 0, sizeof(sax)); ++ sax.sa_family = AF_PPPOX; ++ sax.sa_protocol = PX_PROTO_OL2TP; ++ sax.pppol2tp.fd = udp_fd; /* fd of tunnel UDP socket */ ++ sax.pppol2tp.addr.sin_addr.s_addr = peer_addr->sin_addr.s_addr; ++ sax.pppol2tp.addr.sin_port = peer_addr->sin_port; ++ sax.pppol2tp.addr.sin_family = AF_INET; ++ sax.pppol2tp.s_tunnel = tunnel_id; ++ sax.pppol2tp.s_session = 0; /* special case: mgmt socket */ ++ sax.pppol2tp.d_tunnel = 0; ++ sax.pppol2tp.d_session = 0; /* special case: mgmt socket */ ++ ++ if(connect(kernel_fd, (struct sockaddr *)&sax, sizeof(sax) ) < 0 ) { ++ perror("connect failed"); ++ result = -errno; ++ goto err; ++ } ++ } ++ ++2. Create session PPPoX data socket ++ ++ struct sockaddr_pppol2tp sax; ++ int fd; ++ ++ /* Note, the target socket must be bound already, else it will not be ready */ ++ sax.sa_family = AF_PPPOX; ++ sax.sa_protocol = PX_PROTO_OL2TP; ++ sax.pppol2tp.fd = tunnel_fd; ++ sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr; ++ sax.pppol2tp.addr.sin_port = addr->sin_port; ++ sax.pppol2tp.addr.sin_family = AF_INET; ++ sax.pppol2tp.s_tunnel = tunnel_id; ++ sax.pppol2tp.s_session = session_id; ++ sax.pppol2tp.d_tunnel = peer_tunnel_id; ++ sax.pppol2tp.d_session = peer_session_id; ++ ++ /* session_fd is the fd of the session's PPPoL2TP socket. ++ * tunnel_fd is the fd of the tunnel UDP socket. ++ */ ++ fd = connect(session_fd, (struct sockaddr *)&sax, sizeof(sax)); ++ if (fd < 0 ) { ++ return -errno; ++ } ++ return 0; ++ ++Miscellanous ++============ ++ ++The PPPoL2TP driver was developed as part of the OpenL2TP project by ++Katalix Systems Ltd. OpenL2TP is a full-featured L2TP client / server, ++designed from the ground up to have the L2TP datapath in the ++kernel. The project also implemented the pppol2tp plugin for pppd ++which allows pppd to use the kernel driver. Details can be found at ++http://openl2tp.sourceforge.net. +diff -Nurp linux-2.6.22/Documentation/networking/mac80211-injection.txt linux-2.6-netns/Documentation/networking/mac80211-injection.txt +--- linux-2.6.22/Documentation/networking/mac80211-injection.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/networking/mac80211-injection.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -0,0 +1,59 @@ ++How to use packet injection with mac80211 ++========================================= ++ ++mac80211 now allows arbitrary packets to be injected down any Monitor Mode ++interface from userland. The packet you inject needs to be composed in the ++following format: ++ ++ [ radiotap header ] ++ [ ieee80211 header ] ++ [ payload ] ++ ++The radiotap format is discussed in ++./Documentation/networking/radiotap-headers.txt. ++ ++Despite 13 radiotap argument types are currently defined, most only make sense ++to appear on received packets. Currently three kinds of argument are used by ++the injection code, although it knows to skip any other arguments that are ++present (facilitating replay of captured radiotap headers directly): ++ ++ - IEEE80211_RADIOTAP_RATE - u8 arg in 500kbps units (0x02 --> 1Mbps) ++ ++ - IEEE80211_RADIOTAP_ANTENNA - u8 arg, 0x00 = ant1, 0x01 = ant2 ++ ++ - IEEE80211_RADIOTAP_DBM_TX_POWER - u8 arg, dBm ++ ++Here is an example valid radiotap header defining these three parameters ++ ++ 0x00, 0x00, // <-- radiotap version ++ 0x0b, 0x00, // <- radiotap header length ++ 0x04, 0x0c, 0x00, 0x00, // <-- bitmap ++ 0x6c, // <-- rate ++ 0x0c, //<-- tx power ++ 0x01 //<-- antenna ++ ++The ieee80211 header follows immediately afterwards, looking for example like ++this: ++ ++ 0x08, 0x01, 0x00, 0x00, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, ++ 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, ++ 0x10, 0x86 ++ ++Then lastly there is the payload. ++ ++After composing the packet contents, it is sent by send()-ing it to a logical ++mac80211 interface that is in Monitor mode. Libpcap can also be used, ++(which is easier than doing the work to bind the socket to the right ++interface), along the following lines: ++ ++ ppcap = pcap_open_live(szInterfaceName, 800, 1, 20, szErrbuf); ++... ++ r = pcap_inject(ppcap, u8aSendBuffer, nLength); ++ ++You can also find sources for a complete inject test applet here: ++ ++http://penumbra.warmcat.com/_twk/tiki-index.php?page=packetspammer ++ ++Andy Green +diff -Nurp linux-2.6.22/Documentation/networking/multiqueue.txt linux-2.6-netns/Documentation/networking/multiqueue.txt +--- linux-2.6.22/Documentation/networking/multiqueue.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/networking/multiqueue.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -0,0 +1,111 @@ ++ ++ HOWTO for multiqueue network device support ++ =========================================== ++ ++Section 1: Base driver requirements for implementing multiqueue support ++Section 2: Qdisc support for multiqueue devices ++Section 3: Brief howto using PRIO or RR for multiqueue devices ++ ++ ++Intro: Kernel support for multiqueue devices ++--------------------------------------------------------- ++ ++Kernel support for multiqueue devices is only an API that is presented to the ++netdevice layer for base drivers to implement. This feature is part of the ++core networking stack, and all network devices will be running on the ++multiqueue-aware stack. If a base driver only has one queue, then these ++changes are transparent to that driver. ++ ++ ++Section 1: Base driver requirements for implementing multiqueue support ++----------------------------------------------------------------------- ++ ++Base drivers are required to use the new alloc_etherdev_mq() or ++alloc_netdev_mq() functions to allocate the subqueues for the device. The ++underlying kernel API will take care of the allocation and deallocation of ++the subqueue memory, as well as netdev configuration of where the queues ++exist in memory. ++ ++The base driver will also need to manage the queues as it does the global ++netdev->queue_lock today. Therefore base drivers should use the ++netif_{start|stop|wake}_subqueue() functions to manage each queue while the ++device is still operational. netdev->queue_lock is still used when the device ++comes online or when it's completely shut down (unregister_netdev(), etc.). ++ ++Finally, the base driver should indicate that it is a multiqueue device. The ++feature flag NETIF_F_MULTI_QUEUE should be added to the netdev->features ++bitmap on device initialization. Below is an example from e1000: ++ ++#ifdef CONFIG_E1000_MQ ++ if ( (adapter->hw.mac.type == e1000_82571) || ++ (adapter->hw.mac.type == e1000_82572) || ++ (adapter->hw.mac.type == e1000_80003es2lan)) ++ netdev->features |= NETIF_F_MULTI_QUEUE; ++#endif ++ ++ ++Section 2: Qdisc support for multiqueue devices ++----------------------------------------------- ++ ++Currently two qdiscs support multiqueue devices. A new round-robin qdisc, ++sch_rr, and sch_prio. The qdisc is responsible for classifying the skb's to ++bands and queues, and will store the queue mapping into skb->queue_mapping. ++Use this field in the base driver to determine which queue to send the skb ++to. ++ ++sch_rr has been added for hardware that doesn't want scheduling policies from ++software, so it's a straight round-robin qdisc. It uses the same syntax and ++classification priomap that sch_prio uses, so it should be intuitive to ++configure for people who've used sch_prio. ++ ++The PRIO qdisc naturally plugs into a multiqueue device. If PRIO has been ++built with NET_SCH_PRIO_MQ, then upon load, it will make sure the number of ++bands requested is equal to the number of queues on the hardware. If they ++are equal, it sets a one-to-one mapping up between the queues and bands. If ++they're not equal, it will not load the qdisc. This is the same behavior ++for RR. Once the association is made, any skb that is classified will have ++skb->queue_mapping set, which will allow the driver to properly queue skb's ++to multiple queues. ++ ++ ++Section 3: Brief howto using PRIO and RR for multiqueue devices ++--------------------------------------------------------------- ++ ++The userspace command 'tc,' part of the iproute2 package, is used to configure ++qdiscs. To add the PRIO qdisc to your network device, assuming the device is ++called eth0, run the following command: ++ ++# tc qdisc add dev eth0 root handle 1: prio bands 4 multiqueue ++ ++This will create 4 bands, 0 being highest priority, and associate those bands ++to the queues on your NIC. Assuming eth0 has 4 Tx queues, the band mapping ++would look like: ++ ++band 0 => queue 0 ++band 1 => queue 1 ++band 2 => queue 2 ++band 3 => queue 3 ++ ++Traffic will begin flowing through each queue if your TOS values are assigning ++traffic across the various bands. For example, ssh traffic will always try to ++go out band 0 based on TOS -> Linux priority conversion (realtime traffic), ++so it will be sent out queue 0. ICMP traffic (pings) fall into the "normal" ++traffic classification, which is band 1. Therefore pings will be send out ++queue 1 on the NIC. ++ ++Note the use of the multiqueue keyword. This is only in versions of iproute2 ++that support multiqueue networking devices; if this is omitted when loading ++a qdisc onto a multiqueue device, the qdisc will load and operate the same ++if it were loaded onto a single-queue device (i.e. - sends all traffic to ++queue 0). ++ ++Another alternative to multiqueue band allocation can be done by using the ++multiqueue option and specify 0 bands. If this is the case, the qdisc will ++allocate the number of bands to equal the number of queues that the device ++reports, and bring the qdisc online. ++ ++The behavior of tc filters remains the same, where it will override TOS priority ++classification. ++ ++ ++Author: Peter P. Waskiewicz Jr. +diff -Nurp linux-2.6.22/Documentation/networking/net-modules.txt linux-2.6-netns/Documentation/networking/net-modules.txt +--- linux-2.6.22/Documentation/networking/net-modules.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/networking/net-modules.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -146,12 +146,6 @@ at1700.c: + irq = 0 + (Probes ports: 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300) + +-atari_bionet.c: +- Supports full autoprobing. (m68k/Atari) +- +-atari_pamsnet.c: +- Supports full autoprobing. (m68k/Atari) +- + atarilance.c: + Supports full autoprobing. (m68k/Atari) + +diff -Nurp linux-2.6.22/Documentation/networking/netdevices.txt linux-2.6-netns/Documentation/networking/netdevices.txt +--- linux-2.6.22/Documentation/networking/netdevices.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/networking/netdevices.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -20,6 +20,30 @@ private data which gets freed when the n + separately allocated data is attached to the network device + (dev->priv) then it is up to the module exit handler to free that. + ++MTU ++=== ++Each network device has a Maximum Transfer Unit. The MTU does not ++include any link layer protocol overhead. Upper layer protocols must ++not pass a socket buffer (skb) to a device to transmit with more data ++than the mtu. The MTU does not include link layer header overhead, so ++for example on Ethernet if the standard MTU is 1500 bytes used, the ++actual skb will contain up to 1514 bytes because of the Ethernet ++header. Devices should allow for the 4 byte VLAN header as well. ++ ++Segmentation Offload (GSO, TSO) is an exception to this rule. The ++upper layer protocol may pass a large socket buffer to the device ++transmit routine, and the device will break that up into separate ++packets based on the current MTU. ++ ++MTU is symmetrical and applies both to receive and transmit. A device ++must be able to receive at least the maximum size packet allowed by ++the MTU. A network device may use the MTU as mechanism to size receive ++buffers, but the device should allow packets with VLAN header. With ++standard Ethernet mtu of 1500 bytes, the device should allow up to ++1518 byte packets (1500 + 14 header + 4 tag). The device may either: ++drop, truncate, or pass up oversize packets, but dropping oversize ++packets is preferred. ++ + + struct net_device synchronization rules + ======================================= +@@ -43,16 +67,17 @@ dev->get_stats: + + dev->hard_start_xmit: + Synchronization: netif_tx_lock spinlock. ++ + When the driver sets NETIF_F_LLTX in dev->features this will be + called without holding netif_tx_lock. In this case the driver + has to lock by itself when needed. It is recommended to use a try lock +- for this and return -1 when the spin lock fails. ++ for this and return NETDEV_TX_LOCKED when the spin lock fails. + The locking there should also properly protect against +- set_multicast_list +- Context: Process with BHs disabled or BH (timer). +- Notes: netif_queue_stopped() is guaranteed false +- Interrupts must be enabled when calling hard_start_xmit. +- (Interrupts must also be enabled when enabling the BH handler.) ++ set_multicast_list. ++ ++ Context: Process with BHs disabled or BH (timer), ++ will be called with interrupts disabled by netconsole. ++ + Return codes: + o NETDEV_TX_OK everything ok. + o NETDEV_TX_BUSY Cannot transmit packet, try later +@@ -74,4 +99,5 @@ dev->poll: + Synchronization: __LINK_STATE_RX_SCHED bit in dev->state. See + dev_close code and comments in net/core/dev.c for more info. + Context: softirq ++ will be called with interrupts disabled by netconsole. + +diff -Nurp linux-2.6.22/Documentation/networking/radiotap-headers.txt linux-2.6-netns/Documentation/networking/radiotap-headers.txt +--- linux-2.6.22/Documentation/networking/radiotap-headers.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/networking/radiotap-headers.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,152 @@ ++How to use radiotap headers ++=========================== ++ ++Pointer to the radiotap include file ++------------------------------------ ++ ++Radiotap headers are variable-length and extensible, you can get most of the ++information you need to know on them from: ++ ++./include/net/ieee80211_radiotap.h ++ ++This document gives an overview and warns on some corner cases. ++ ++ ++Structure of the header ++----------------------- ++ ++There is a fixed portion at the start which contains a u32 bitmap that defines ++if the possible argument associated with that bit is present or not. So if b0 ++of the it_present member of ieee80211_radiotap_header is set, it means that ++the header for argument index 0 (IEEE80211_RADIOTAP_TSFT) is present in the ++argument area. ++ ++ < 8-byte ieee80211_radiotap_header > ++ [ ] ++ [ ... ] ++ ++At the moment there are only 13 possible argument indexes defined, but in case ++we run out of space in the u32 it_present member, it is defined that b31 set ++indicates that there is another u32 bitmap following (shown as "possible ++argument bitmap extensions..." above), and the start of the arguments is moved ++forward 4 bytes each time. ++ ++Note also that the it_len member __le16 is set to the total number of bytes ++covered by the ieee80211_radiotap_header and any arguments following. ++ ++ ++Requirements for arguments ++-------------------------- ++ ++After the fixed part of the header, the arguments follow for each argument ++index whose matching bit is set in the it_present member of ++ieee80211_radiotap_header. ++ ++ - the arguments are all stored little-endian! ++ ++ - the argument payload for a given argument index has a fixed size. So ++ IEEE80211_RADIOTAP_TSFT being present always indicates an 8-byte argument is ++ present. See the comments in ./include/net/ieee80211_radiotap.h for a nice ++ breakdown of all the argument sizes ++ ++ - the arguments must be aligned to a boundary of the argument size using ++ padding. So a u16 argument must start on the next u16 boundary if it isn't ++ already on one, a u32 must start on the next u32 boundary and so on. ++ ++ - "alignment" is relative to the start of the ieee80211_radiotap_header, ie, ++ the first byte of the radiotap header. The absolute alignment of that first ++ byte isn't defined. So even if the whole radiotap header is starting at, eg, ++ address 0x00000003, still the first byte of the radiotap header is treated as ++ 0 for alignment purposes. ++ ++ - the above point that there may be no absolute alignment for multibyte ++ entities in the fixed radiotap header or the argument region means that you ++ have to take special evasive action when trying to access these multibyte ++ entities. Some arches like Blackfin cannot deal with an attempt to ++ dereference, eg, a u16 pointer that is pointing to an odd address. Instead ++ you have to use a kernel API get_unaligned() to dereference the pointer, ++ which will do it bytewise on the arches that require that. ++ ++ - The arguments for a given argument index can be a compound of multiple types ++ together. For example IEEE80211_RADIOTAP_CHANNEL has an argument payload ++ consisting of two u16s of total length 4. When this happens, the padding ++ rule is applied dealing with a u16, NOT dealing with a 4-byte single entity. ++ ++ ++Example valid radiotap header ++----------------------------- ++ ++ 0x00, 0x00, // <-- radiotap version + pad byte ++ 0x0b, 0x00, // <- radiotap header length ++ 0x04, 0x0c, 0x00, 0x00, // <-- bitmap ++ 0x6c, // <-- rate (in 500kHz units) ++ 0x0c, //<-- tx power ++ 0x01 //<-- antenna ++ ++ ++Using the Radiotap Parser ++------------------------- ++ ++If you are having to parse a radiotap struct, you can radically simplify the ++job by using the radiotap parser that lives in net/wireless/radiotap.c and has ++its prototypes available in include/net/cfg80211.h. You use it like this: ++ ++#include ++ ++/* buf points to the start of the radiotap header part */ ++ ++int MyFunction(u8 * buf, int buflen) ++{ ++ int pkt_rate_100kHz = 0, antenna = 0, pwr = 0; ++ struct ieee80211_radiotap_iterator iterator; ++ int ret = ieee80211_radiotap_iterator_init(&iterator, buf, buflen); ++ ++ while (!ret) { ++ ++ ret = ieee80211_radiotap_iterator_next(&iterator); ++ ++ if (ret) ++ continue; ++ ++ /* see if this argument is something we can use */ ++ ++ switch (iterator.this_arg_index) { ++ /* ++ * You must take care when dereferencing iterator.this_arg ++ * for multibyte types... the pointer is not aligned. Use ++ * get_unaligned((type *)iterator.this_arg) to dereference ++ * iterator.this_arg for type "type" safely on all arches. ++ */ ++ case IEEE80211_RADIOTAP_RATE: ++ /* radiotap "rate" u8 is in ++ * 500kbps units, eg, 0x02=1Mbps ++ */ ++ pkt_rate_100kHz = (*iterator.this_arg) * 5; ++ break; ++ ++ case IEEE80211_RADIOTAP_ANTENNA: ++ /* radiotap uses 0 for 1st ant */ ++ antenna = *iterator.this_arg); ++ break; ++ ++ case IEEE80211_RADIOTAP_DBM_TX_POWER: ++ pwr = *iterator.this_arg; ++ break; ++ ++ default: ++ break; ++ } ++ } /* while more rt headers */ ++ ++ if (ret != -ENOENT) ++ return TXRX_DROP; ++ ++ /* discard the radiotap header part */ ++ buf += iterator.max_length; ++ buflen -= iterator.max_length; ++ ++ ... ++ ++} ++ ++Andy Green +diff -Nurp linux-2.6.22/Documentation/networking/sk98lin.txt linux-2.6-netns/Documentation/networking/sk98lin.txt +--- linux-2.6.22/Documentation/networking/sk98lin.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/networking/sk98lin.txt 1969-12-31 19:00:00.000000000 -0500 +@@ -1,568 +0,0 @@ +-(C)Copyright 1999-2004 Marvell(R). +-All rights reserved +-=========================================================================== +- +-sk98lin.txt created 13-Feb-2004 +- +-Readme File for sk98lin v6.23 +-Marvell Yukon/SysKonnect SK-98xx Gigabit Ethernet Adapter family driver for LINUX +- +-This file contains +- 1 Overview +- 2 Required Files +- 3 Installation +- 3.1 Driver Installation +- 3.2 Inclusion of adapter at system start +- 4 Driver Parameters +- 4.1 Per-Port Parameters +- 4.2 Adapter Parameters +- 5 Large Frame Support +- 6 VLAN and Link Aggregation Support (IEEE 802.1, 802.1q, 802.3ad) +- 7 Troubleshooting +- +-=========================================================================== +- +- +-1 Overview +-=========== +- +-The sk98lin driver supports the Marvell Yukon and SysKonnect +-SK-98xx/SK-95xx compliant Gigabit Ethernet Adapter on Linux. It has +-been tested with Linux on Intel/x86 machines. +-*** +- +- +-2 Required Files +-================= +- +-The linux kernel source. +-No additional files required. +-*** +- +- +-3 Installation +-=============== +- +-It is recommended to download the latest version of the driver from the +-SysKonnect web site www.syskonnect.com. If you have downloaded the latest +-driver, the Linux kernel has to be patched before the driver can be +-installed. For details on how to patch a Linux kernel, refer to the +-patch.txt file. +- +-3.1 Driver Installation +------------------------- +- +-The following steps describe the actions that are required to install +-the driver and to start it manually. These steps should be carried +-out for the initial driver setup. Once confirmed to be ok, they can +-be included in the system start. +- +-NOTE 1: To perform the following tasks you need 'root' access. +- +-NOTE 2: In case of problems, please read the section "Troubleshooting" +- below. +- +-The driver can either be integrated into the kernel or it can be compiled +-as a module. Select the appropriate option during the kernel +-configuration. +- +-Compile/use the driver as a module +----------------------------------- +-To compile the driver, go to the directory /usr/src/linux and +-execute the command "make menuconfig" or "make xconfig" and proceed as +-follows: +- +-To integrate the driver permanently into the kernel, proceed as follows: +- +-1. Select the menu "Network device support" and then "Ethernet(1000Mbit)" +-2. Mark "Marvell Yukon Chipset / SysKonnect SK-98xx family support" +- with (*) +-3. Build a new kernel when the configuration of the above options is +- finished. +-4. Install the new kernel. +-5. Reboot your system. +- +-To use the driver as a module, proceed as follows: +- +-1. Enable 'loadable module support' in the kernel. +-2. For automatic driver start, enable the 'Kernel module loader'. +-3. Select the menu "Network device support" and then "Ethernet(1000Mbit)" +-4. Mark "Marvell Yukon Chipset / SysKonnect SK-98xx family support" +- with (M) +-5. Execute the command "make modules". +-6. Execute the command "make modules_install". +- The appropriate modules will be installed. +-7. Reboot your system. +- +- +-Load the module manually +------------------------- +-To load the module manually, proceed as follows: +- +-1. Enter "modprobe sk98lin". +-2. If a Marvell Yukon or SysKonnect SK-98xx adapter is installed in +- your computer and you have a /proc file system, execute the command: +- "ls /proc/net/sk98lin/" +- This should produce an output containing a line with the following +- format: +- eth0 eth1 ... +- which indicates that your adapter has been found and initialized. +- +- NOTE 1: If you have more than one Marvell Yukon or SysKonnect SK-98xx +- adapter installed, the adapters will be listed as 'eth0', +- 'eth1', 'eth2', etc. +- For each adapter, repeat steps 3 and 4 below. +- +- NOTE 2: If you have other Ethernet adapters installed, your Marvell +- Yukon or SysKonnect SK-98xx adapter will be mapped to the +- next available number, e.g. 'eth1'. The mapping is executed +- automatically. +- The module installation message (displayed either in a system +- log file or on the console) prints a line for each adapter +- found containing the corresponding 'ethX'. +- +-3. Select an IP address and assign it to the respective adapter by +- entering: +- ifconfig eth0 +- With this command, the adapter is connected to the Ethernet. +- +- SK-98xx Gigabit Ethernet Server Adapters: The yellow LED on the adapter +- is now active, the link status LED of the primary port is active and +- the link status LED of the secondary port (on dual port adapters) is +- blinking (if the ports are connected to a switch or hub). +- SK-98xx V2.0 Gigabit Ethernet Adapters: The link status LED is active. +- In addition, you will receive a status message on the console stating +- "ethX: network connection up using port Y" and showing the selected +- connection parameters (x stands for the ethernet device number +- (0,1,2, etc), y stands for the port name (A or B)). +- +- NOTE: If you are in doubt about IP addresses, ask your network +- administrator for assistance. +- +-4. Your adapter should now be fully operational. +- Use 'ping ' to verify the connection to other computers +- on your network. +-5. To check the adapter configuration view /proc/net/sk98lin/[devicename]. +- For example by executing: +- "cat /proc/net/sk98lin/eth0" +- +-Unload the module +------------------ +-To stop and unload the driver modules, proceed as follows: +- +-1. Execute the command "ifconfig eth0 down". +-2. Execute the command "rmmod sk98lin". +- +-3.2 Inclusion of adapter at system start +------------------------------------------ +- +-Since a large number of different Linux distributions are +-available, we are unable to describe a general installation procedure +-for the driver module. +-Because the driver is now integrated in the kernel, installation should +-be easy, using the standard mechanism of your distribution. +-Refer to the distribution's manual for installation of ethernet adapters. +- +-*** +- +-4 Driver Parameters +-==================== +- +-Parameters can be set at the command line after the module has been +-loaded with the command 'modprobe'. +-In some distributions, the configuration tools are able to pass parameters +-to the driver module. +- +-If you use the kernel module loader, you can set driver parameters +-in the file /etc/modprobe.conf (or /etc/modules.conf in 2.4 or earlier). +-To set the driver parameters in this file, proceed as follows: +- +-1. Insert a line of the form : +- options sk98lin ... +- For "...", the same syntax is required as described for the command +- line parameters of modprobe below. +-2. To activate the new parameters, either reboot your computer +- or +- unload and reload the driver. +- The syntax of the driver parameters is: +- +- modprobe sk98lin parameter=value1[,value2[,value3...]] +- +- where value1 refers to the first adapter, value2 to the second etc. +- +-NOTE: All parameters are case sensitive. Write them exactly as shown +- below. +- +-Example: +-Suppose you have two adapters. You want to set auto-negotiation +-on the first adapter to ON and on the second adapter to OFF. +-You also want to set DuplexCapabilities on the first adapter +-to FULL, and on the second adapter to HALF. +-Then, you must enter: +- +- modprobe sk98lin AutoNeg_A=On,Off DupCap_A=Full,Half +- +-NOTE: The number of adapters that can be configured this way is +- limited in the driver (file skge.c, constant SK_MAX_CARD_PARAM). +- The current limit is 16. If you happen to install +- more adapters, adjust this and recompile. +- +- +-4.1 Per-Port Parameters +------------------------- +- +-These settings are available for each port on the adapter. +-In the following description, '?' stands for the port for +-which you set the parameter (A or B). +- +-Speed +------ +-Parameter: Speed_? +-Values: 10, 100, 1000, Auto +-Default: Auto +- +-This parameter is used to set the speed capabilities. It is only valid +-for the SK-98xx V2.0 copper adapters. +-Usually, the speed is negotiated between the two ports during link +-establishment. If this fails, a port can be forced to a specific setting +-with this parameter. +- +-Auto-Negotiation +----------------- +-Parameter: AutoNeg_? +-Values: On, Off, Sense +-Default: On +- +-The "Sense"-mode automatically detects whether the link partner supports +-auto-negotiation or not. +- +-Duplex Capabilities +-------------------- +-Parameter: DupCap_? +-Values: Half, Full, Both +-Default: Both +- +-This parameters is only relevant if auto-negotiation for this port is +-not set to "Sense". If auto-negotiation is set to "On", all three values +-are possible. If it is set to "Off", only "Full" and "Half" are allowed. +-This parameter is useful if your link partner does not support all +-possible combinations. +- +-Flow Control +------------- +-Parameter: FlowCtrl_? +-Values: Sym, SymOrRem, LocSend, None +-Default: SymOrRem +- +-This parameter can be used to set the flow control capabilities the +-port reports during auto-negotiation. It can be set for each port +-individually. +-Possible modes: +- -- Sym = Symmetric: both link partners are allowed to send +- PAUSE frames +- -- SymOrRem = SymmetricOrRemote: both or only remote partner +- are allowed to send PAUSE frames +- -- LocSend = LocalSend: only local link partner is allowed +- to send PAUSE frames +- -- None = no link partner is allowed to send PAUSE frames +- +-NOTE: This parameter is ignored if auto-negotiation is set to "Off". +- +-Role in Master-Slave-Negotiation (1000Base-T only) +--------------------------------------------------- +-Parameter: Role_? +-Values: Auto, Master, Slave +-Default: Auto +- +-This parameter is only valid for the SK-9821 and SK-9822 adapters. +-For two 1000Base-T ports to communicate, one must take the role of the +-master (providing timing information), while the other must be the +-slave. Usually, this is negotiated between the two ports during link +-establishment. If this fails, a port can be forced to a specific setting +-with this parameter. +- +- +-4.2 Adapter Parameters +------------------------ +- +-Connection Type (SK-98xx V2.0 copper adapters only) +---------------- +-Parameter: ConType +-Values: Auto, 100FD, 100HD, 10FD, 10HD +-Default: Auto +- +-The parameter 'ConType' is a combination of all five per-port parameters +-within one single parameter. This simplifies the configuration of both ports +-of an adapter card! The different values of this variable reflect the most +-meaningful combinations of port parameters. +- +-The following table shows the values of 'ConType' and the corresponding +-combinations of the per-port parameters: +- +- ConType | DupCap AutoNeg FlowCtrl Role Speed +- ----------+------------------------------------------------------ +- Auto | Both On SymOrRem Auto Auto +- 100FD | Full Off None Auto (ignored) 100 +- 100HD | Half Off None Auto (ignored) 100 +- 10FD | Full Off None Auto (ignored) 10 +- 10HD | Half Off None Auto (ignored) 10 +- +-Stating any other port parameter together with this 'ConType' variable +-will result in a merged configuration of those settings. This due to +-the fact, that the per-port parameters (e.g. Speed_? ) have a higher +-priority than the combined variable 'ConType'. +- +-NOTE: This parameter is always used on both ports of the adapter card. +- +-Interrupt Moderation +--------------------- +-Parameter: Moderation +-Values: None, Static, Dynamic +-Default: None +- +-Interrupt moderation is employed to limit the maximum number of interrupts +-the driver has to serve. That is, one or more interrupts (which indicate any +-transmit or receive packet to be processed) are queued until the driver +-processes them. When queued interrupts are to be served, is determined by the +-'IntsPerSec' parameter, which is explained later below. +- +-Possible modes: +- +- -- None - No interrupt moderation is applied on the adapter card. +- Therefore, each transmit or receive interrupt is served immediately +- as soon as it appears on the interrupt line of the adapter card. +- +- -- Static - Interrupt moderation is applied on the adapter card. +- All transmit and receive interrupts are queued until a complete +- moderation interval ends. If such a moderation interval ends, all +- queued interrupts are processed in one big bunch without any delay. +- The term 'static' reflects the fact, that interrupt moderation is +- always enabled, regardless how much network load is currently +- passing via a particular interface. In addition, the duration of +- the moderation interval has a fixed length that never changes while +- the driver is operational. +- +- -- Dynamic - Interrupt moderation might be applied on the adapter card, +- depending on the load of the system. If the driver detects that the +- system load is too high, the driver tries to shield the system against +- too much network load by enabling interrupt moderation. If - at a later +- time - the CPU utilization decreases again (or if the network load is +- negligible) the interrupt moderation will automatically be disabled. +- +-Interrupt moderation should be used when the driver has to handle one or more +-interfaces with a high network load, which - as a consequence - leads also to a +-high CPU utilization. When moderation is applied in such high network load +-situations, CPU load might be reduced by 20-30%. +- +-NOTE: The drawback of using interrupt moderation is an increase of the round- +-trip-time (RTT), due to the queueing and serving of interrupts at dedicated +-moderation times. +- +-Interrupts per second +---------------------- +-Parameter: IntsPerSec +-Values: 30...40000 (interrupts per second) +-Default: 2000 +- +-This parameter is only used if either static or dynamic interrupt moderation +-is used on a network adapter card. Using this parameter if no moderation is +-applied will lead to no action performed. +- +-This parameter determines the length of any interrupt moderation interval. +-Assuming that static interrupt moderation is to be used, an 'IntsPerSec' +-parameter value of 2000 will lead to an interrupt moderation interval of +-500 microseconds. +- +-NOTE: The duration of the moderation interval is to be chosen with care. +-At first glance, selecting a very long duration (e.g. only 100 interrupts per +-second) seems to be meaningful, but the increase of packet-processing delay +-is tremendous. On the other hand, selecting a very short moderation time might +-compensate the use of any moderation being applied. +- +- +-Preferred Port +--------------- +-Parameter: PrefPort +-Values: A, B +-Default: A +- +-This is used to force the preferred port to A or B (on dual-port network +-adapters). The preferred port is the one that is used if both are detected +-as fully functional. +- +-RLMT Mode (Redundant Link Management Technology) +------------------------------------------------- +-Parameter: RlmtMode +-Values: CheckLinkState,CheckLocalPort, CheckSeg, DualNet +-Default: CheckLinkState +- +-RLMT monitors the status of the port. If the link of the active port +-fails, RLMT switches immediately to the standby link. The virtual link is +-maintained as long as at least one 'physical' link is up. +- +-Possible modes: +- +- -- CheckLinkState - Check link state only: RLMT uses the link state +- reported by the adapter hardware for each individual port to +- determine whether a port can be used for all network traffic or +- not. +- +- -- CheckLocalPort - In this mode, RLMT monitors the network path +- between the two ports of an adapter by regularly exchanging packets +- between them. This mode requires a network configuration in which +- the two ports are able to "see" each other (i.e. there must not be +- any router between the ports). +- +- -- CheckSeg - Check local port and segmentation: This mode supports the +- same functions as the CheckLocalPort mode and additionally checks +- network segmentation between the ports. Therefore, this mode is only +- to be used if Gigabit Ethernet switches are installed on the network +- that have been configured to use the Spanning Tree protocol. +- +- -- DualNet - In this mode, ports A and B are used as separate devices. +- If you have a dual port adapter, port A will be configured as eth0 +- and port B as eth1. Both ports can be used independently with +- distinct IP addresses. The preferred port setting is not used. +- RLMT is turned off. +- +-NOTE: RLMT modes CLP and CLPSS are designed to operate in configurations +- where a network path between the ports on one adapter exists. +- Moreover, they are not designed to work where adapters are connected +- back-to-back. +-*** +- +- +-5 Large Frame Support +-====================== +- +-The driver supports large frames (also called jumbo frames). Using large +-frames can result in an improved throughput if transferring large amounts +-of data. +-To enable large frames, set the MTU (maximum transfer unit) of the +-interface to the desired value (up to 9000), execute the following +-command: +- ifconfig eth0 mtu 9000 +-This will only work if you have two adapters connected back-to-back +-or if you use a switch that supports large frames. When using a switch, +-it should be configured to allow large frames and auto-negotiation should +-be set to OFF. The setting must be configured on all adapters that can be +-reached by the large frames. If one adapter is not set to receive large +-frames, it will simply drop them. +- +-You can switch back to the standard ethernet frame size by executing the +-following command: +- ifconfig eth0 mtu 1500 +- +-To permanently configure this setting, add a script with the 'ifconfig' +-line to the system startup sequence (named something like "S99sk98lin" +-in /etc/rc.d/rc2.d). +-*** +- +- +-6 VLAN and Link Aggregation Support (IEEE 802.1, 802.1q, 802.3ad) +-================================================================== +- +-The Marvell Yukon/SysKonnect Linux drivers are able to support VLAN and +-Link Aggregation according to IEEE standards 802.1, 802.1q, and 802.3ad. +-These features are only available after installation of open source +-modules available on the Internet: +-For VLAN go to: http://www.candelatech.com/~greear/vlan.html +-For Link Aggregation go to: http://www.st.rim.or.jp/~yumo +- +-NOTE: SysKonnect GmbH does not offer any support for these open source +- modules and does not take the responsibility for any kind of +- failures or problems arising in connection with these modules. +- +-NOTE: Configuring Link Aggregation on a SysKonnect dual link adapter may +- cause problems when unloading the driver. +- +- +-7 Troubleshooting +-================== +- +-If any problems occur during the installation process, check the +-following list: +- +- +-Problem: The SK-98xx adapter cannot be found by the driver. +-Solution: In /proc/pci search for the following entry: +- 'Ethernet controller: SysKonnect SK-98xx ...' +- If this entry exists, the SK-98xx or SK-98xx V2.0 adapter has +- been found by the system and should be operational. +- If this entry does not exist or if the file '/proc/pci' is not +- found, there may be a hardware problem or the PCI support may +- not be enabled in your kernel. +- The adapter can be checked using the diagnostics program which +- is available on the SysKonnect web site: +- www.syskonnect.com +- +- Some COMPAQ machines have problems dealing with PCI under Linux. +- This problem is described in the 'PCI howto' document +- (included in some distributions or available from the +- web, e.g. at 'www.linux.org'). +- +- +-Problem: Programs such as 'ifconfig' or 'route' cannot be found or the +- error message 'Operation not permitted' is displayed. +-Reason: You are not logged in as user 'root'. +-Solution: Logout and login as 'root' or change to 'root' via 'su'. +- +- +-Problem: Upon use of the command 'ping
' the message +- "ping: sendto: Network is unreachable" is displayed. +-Reason: Your route is not set correctly. +-Solution: If you are using RedHat, you probably forgot to set up the +- route in the 'network configuration'. +- Check the existing routes with the 'route' command and check +- if an entry for 'eth0' exists, and if so, if it is set correctly. +- +- +-Problem: The driver can be started, the adapter is connected to the +- network, but you cannot receive or transmit any packets; +- e.g. 'ping' does not work. +-Reason: There is an incorrect route in your routing table. +-Solution: Check the routing table with the command 'route' and read the +- manual help pages dealing with routes (enter 'man route'). +- +-NOTE: Although the 2.2.x kernel versions generate the routing entry +- automatically, problems of this kind may occur here as well. We've +- come across a situation in which the driver started correctly at +- system start, but after the driver has been removed and reloaded, +- the route of the adapter's network pointed to the 'dummy0'device +- and had to be corrected manually. +- +- +-Problem: Your computer should act as a router between multiple +- IP subnetworks (using multiple adapters), but computers in +- other subnetworks cannot be reached. +-Reason: Either the router's kernel is not configured for IP forwarding +- or the routing table and gateway configuration of at least one +- computer is not working. +- +-Problem: Upon driver start, the following error message is displayed: +- "eth0: -- ERROR -- +- Class: internal Software error +- Nr: 0xcc +- Msg: SkGeInitPort() cannot init running ports" +-Reason: You are using a driver compiled for single processor machines +- on a multiprocessor machine with SMP (Symmetric MultiProcessor) +- kernel. +-Solution: Configure your kernel appropriately and recompile the kernel or +- the modules. +- +- +- +-If your problem is not listed here, please contact SysKonnect's technical +-support for help (linux@syskonnect.de). +-When contacting our technical support, please ensure that the following +-information is available: +-- System Manufacturer and HW Informations (CPU, Memory... ) +-- PCI-Boards in your system +-- Distribution +-- Kernel version +-- Driver version +-*** +- +- +- +-***End of Readme File*** +diff -Nurp linux-2.6.22/Documentation/networking/spider_net.txt linux-2.6-netns/Documentation/networking/spider_net.txt +--- linux-2.6.22/Documentation/networking/spider_net.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/networking/spider_net.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,204 @@ ++ ++ The Spidernet Device Driver ++ =========================== ++ ++Written by Linas Vepstas ++ ++Version of 7 June 2007 ++ ++Abstract ++======== ++This document sketches the structure of portions of the spidernet ++device driver in the Linux kernel tree. The spidernet is a gigabit ++ethernet device built into the Toshiba southbridge commonly used ++in the SONY Playstation 3 and the IBM QS20 Cell blade. ++ ++The Structure of the RX Ring. ++============================= ++The receive (RX) ring is a circular linked list of RX descriptors, ++together with three pointers into the ring that are used to manage its ++contents. ++ ++The elements of the ring are called "descriptors" or "descrs"; they ++describe the received data. This includes a pointer to a buffer ++containing the received data, the buffer size, and various status bits. ++ ++There are three primary states that a descriptor can be in: "empty", ++"full" and "not-in-use". An "empty" or "ready" descriptor is ready ++to receive data from the hardware. A "full" descriptor has data in it, ++and is waiting to be emptied and processed by the OS. A "not-in-use" ++descriptor is neither empty or full; it is simply not ready. It may ++not even have a data buffer in it, or is otherwise unusable. ++ ++During normal operation, on device startup, the OS (specifically, the ++spidernet device driver) allocates a set of RX descriptors and RX ++buffers. These are all marked "empty", ready to receive data. This ++ring is handed off to the hardware, which sequentially fills in the ++buffers, and marks them "full". The OS follows up, taking the full ++buffers, processing them, and re-marking them empty. ++ ++This filling and emptying is managed by three pointers, the "head" ++and "tail" pointers, managed by the OS, and a hardware current ++descriptor pointer (GDACTDPA). The GDACTDPA points at the descr ++currently being filled. When this descr is filled, the hardware ++marks it full, and advances the GDACTDPA by one. Thus, when there is ++flowing RX traffic, every descr behind it should be marked "full", ++and everything in front of it should be "empty". If the hardware ++discovers that the current descr is not empty, it will signal an ++interrupt, and halt processing. ++ ++The tail pointer tails or trails the hardware pointer. When the ++hardware is ahead, the tail pointer will be pointing at a "full" ++descr. The OS will process this descr, and then mark it "not-in-use", ++and advance the tail pointer. Thus, when there is flowing RX traffic, ++all of the descrs in front of the tail pointer should be "full", and ++all of those behind it should be "not-in-use". When RX traffic is not ++flowing, then the tail pointer can catch up to the hardware pointer. ++The OS will then note that the current tail is "empty", and halt ++processing. ++ ++The head pointer (somewhat mis-named) follows after the tail pointer. ++When traffic is flowing, then the head pointer will be pointing at ++a "not-in-use" descr. The OS will perform various housekeeping duties ++on this descr. This includes allocating a new data buffer and ++dma-mapping it so as to make it visible to the hardware. The OS will ++then mark the descr as "empty", ready to receive data. Thus, when there ++is flowing RX traffic, everything in front of the head pointer should ++be "not-in-use", and everything behind it should be "empty". If no ++RX traffic is flowing, then the head pointer can catch up to the tail ++pointer, at which point the OS will notice that the head descr is ++"empty", and it will halt processing. ++ ++Thus, in an idle system, the GDACTDPA, tail and head pointers will ++all be pointing at the same descr, which should be "empty". All of the ++other descrs in the ring should be "empty" as well. ++ ++The show_rx_chain() routine will print out the the locations of the ++GDACTDPA, tail and head pointers. It will also summarize the contents ++of the ring, starting at the tail pointer, and listing the status ++of the descrs that follow. ++ ++A typical example of the output, for a nearly idle system, might be ++ ++net eth1: Total number of descrs=256 ++net eth1: Chain tail located at descr=20 ++net eth1: Chain head is at 20 ++net eth1: HW curr desc (GDACTDPA) is at 21 ++net eth1: Have 1 descrs with stat=x40800101 ++net eth1: HW next desc (GDACNEXTDA) is at 22 ++net eth1: Last 255 descrs with stat=xa0800000 ++ ++In the above, the hardware has filled in one descr, number 20. Both ++head and tail are pointing at 20, because it has not yet been emptied. ++Meanwhile, hw is pointing at 21, which is free. ++ ++The "Have nnn decrs" refers to the descr starting at the tail: in this ++case, nnn=1 descr, starting at descr 20. The "Last nnn descrs" refers ++to all of the rest of the descrs, from the last status change. The "nnn" ++is a count of how many descrs have exactly the same status. ++ ++The status x4... corresponds to "full" and status xa... corresponds ++to "empty". The actual value printed is RXCOMST_A. ++ ++In the device driver source code, a different set of names are ++used for these same concepts, so that ++ ++"empty" == SPIDER_NET_DESCR_CARDOWNED == 0xa ++"full" == SPIDER_NET_DESCR_FRAME_END == 0x4 ++"not in use" == SPIDER_NET_DESCR_NOT_IN_USE == 0xf ++ ++ ++The RX RAM full bug/feature ++=========================== ++ ++As long as the OS can empty out the RX buffers at a rate faster than ++the hardware can fill them, there is no problem. If, for some reason, ++the OS fails to empty the RX ring fast enough, the hardware GDACTDPA ++pointer will catch up to the head, notice the not-empty condition, ++ad stop. However, RX packets may still continue arriving on the wire. ++The spidernet chip can save some limited number of these in local RAM. ++When this local ram fills up, the spider chip will issue an interrupt ++indicating this (GHIINT0STS will show ERRINT, and the GRMFLLINT bit ++will be set in GHIINT1STS). When the RX ram full condition occurs, ++a certain bug/feature is triggered that has to be specially handled. ++This section describes the special handling for this condition. ++ ++When the OS finally has a chance to run, it will empty out the RX ring. ++In particular, it will clear the descriptor on which the hardware had ++stopped. However, once the hardware has decided that a certain ++descriptor is invalid, it will not restart at that descriptor; instead ++it will restart at the next descr. This potentially will lead to a ++deadlock condition, as the tail pointer will be pointing at this descr, ++which, from the OS point of view, is empty; the OS will be waiting for ++this descr to be filled. However, the hardware has skipped this descr, ++and is filling the next descrs. Since the OS doesn't see this, there ++is a potential deadlock, with the OS waiting for one descr to fill, ++while the hardware is waiting for a different set of descrs to become ++empty. ++ ++A call to show_rx_chain() at this point indicates the nature of the ++problem. A typical print when the network is hung shows the following: ++ ++net eth1: Spider RX RAM full, incoming packets might be discarded! ++net eth1: Total number of descrs=256 ++net eth1: Chain tail located at descr=255 ++net eth1: Chain head is at 255 ++net eth1: HW curr desc (GDACTDPA) is at 0 ++net eth1: Have 1 descrs with stat=xa0800000 ++net eth1: HW next desc (GDACNEXTDA) is at 1 ++net eth1: Have 127 descrs with stat=x40800101 ++net eth1: Have 1 descrs with stat=x40800001 ++net eth1: Have 126 descrs with stat=x40800101 ++net eth1: Last 1 descrs with stat=xa0800000 ++ ++Both the tail and head pointers are pointing at descr 255, which is ++marked xa... which is "empty". Thus, from the OS point of view, there ++is nothing to be done. In particular, there is the implicit assumption ++that everything in front of the "empty" descr must surely also be empty, ++as explained in the last section. The OS is waiting for descr 255 to ++become non-empty, which, in this case, will never happen. ++ ++The HW pointer is at descr 0. This descr is marked 0x4.. or "full". ++Since its already full, the hardware can do nothing more, and thus has ++halted processing. Notice that descrs 0 through 254 are all marked ++"full", while descr 254 and 255 are empty. (The "Last 1 descrs" is ++descr 254, since tail was at 255.) Thus, the system is deadlocked, ++and there can be no forward progress; the OS thinks there's nothing ++to do, and the hardware has nowhere to put incoming data. ++ ++This bug/feature is worked around with the spider_net_resync_head_ptr() ++routine. When the driver receives RX interrupts, but an examination ++of the RX chain seems to show it is empty, then it is probable that ++the hardware has skipped a descr or two (sometimes dozens under heavy ++network conditions). The spider_net_resync_head_ptr() subroutine will ++search the ring for the next full descr, and the driver will resume ++operations there. Since this will leave "holes" in the ring, there ++is also a spider_net_resync_tail_ptr() that will skip over such holes. ++ ++As of this writing, the spider_net_resync() strategy seems to work very ++well, even under heavy network loads. ++ ++ ++The TX ring ++=========== ++The TX ring uses a low-watermark interrupt scheme to make sure that ++the TX queue is appropriately serviced for large packet sizes. ++ ++For packet sizes greater than about 1KBytes, the kernel can fill ++the TX ring quicker than the device can drain it. Once the ring ++is full, the netdev is stopped. When there is room in the ring, ++the netdev needs to be reawakened, so that more TX packets are placed ++in the ring. The hardware can empty the ring about four times per jiffy, ++so its not appropriate to wait for the poll routine to refill, since ++the poll routine runs only once per jiffy. The low-watermark mechanism ++marks a descr about 1/4th of the way from the bottom of the queue, so ++that an interrupt is generated when the descr is processed. This ++interrupt wakes up the netdev, which can then refill the queue. ++For large packets, this mechanism generates a relatively small number ++of interrupts, about 1K/sec. For smaller packets, this will drop to zero ++interrupts, as the hardware can empty the queue faster than the kernel ++can fill it. ++ ++ ++ ======= END OF DOCUMENT ======== ++ +diff -Nurp linux-2.6.22/Documentation/oops-tracing.txt linux-2.6-netns/Documentation/oops-tracing.txt +--- linux-2.6.22/Documentation/oops-tracing.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/oops-tracing.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -86,6 +86,20 @@ stuff are the values reported by the Oop + and do a replace of spaces to "\x" - that's what I do, as I'm too lazy + to write a program to automate this all). + ++Alternatively, you can use the shell script in scripts/decodecode. ++Its usage is: decodecode < oops.txt ++ ++The hex bytes that follow "Code:" may (in some architectures) have a series ++of bytes that precede the current instruction pointer as well as bytes at and ++following the current instruction pointer. In some cases, one instruction ++byte or word is surrounded by <> or (), as in "<86>" or "(f00d)". These ++<> or () markings indicate the current instruction pointer. Example from ++i386, split into multiple lines for readability: ++ ++Code: f9 0f 8d f9 00 00 00 8d 42 0c e8 dd 26 11 c7 a1 60 ea 2b f9 8b 50 08 a1 ++64 ea 2b f9 8d 34 82 8b 1e 85 db 74 6d 8b 15 60 ea 2b f9 <8b> 43 04 39 42 54 ++7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0 ++ + Finally, if you want to see where the code comes from, you can do + + cd /usr/src/linux +@@ -237,6 +251,8 @@ characters, each representing a particul + 7: 'U' if a user or user application specifically requested that the + Tainted flag be set, ' ' otherwise. + ++ 8: 'D' if the kernel has died recently, i.e. there was an OOPS or BUG. ++ + The primary reason for the 'Tainted: ' string is to tell kernel + debuggers if this is a clean kernel or if anything unusual has + occurred. Tainting is permanent: even if an offending module is +diff -Nurp linux-2.6.22/Documentation/pci.txt linux-2.6-netns/Documentation/pci.txt +--- linux-2.6.22/Documentation/pci.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/pci.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -113,9 +113,6 @@ initialization with a pointer to a struc + (Please see Documentation/power/pci.txt for descriptions + of PCI Power Management and the related functions.) + +- enable_wake Enable device to generate wake events from a low power +- state. +- + shutdown Hook into reboot_notifier_list (kernel/sys.c). + Intended to stop any idling DMA operations. + Useful for enabling wake-on-lan (NIC) or changing +@@ -299,7 +296,10 @@ If the PCI device can use the PCI Memory + call pci_set_mwi(). This enables the PCI_COMMAND bit for Mem-Wr-Inval + and also ensures that the cache line size register is set correctly. + Check the return value of pci_set_mwi() as not all architectures +-or chip-sets may support Memory-Write-Invalidate. ++or chip-sets may support Memory-Write-Invalidate. Alternatively, ++if Mem-Wr-Inval would be nice to have but is not required, call ++pci_try_set_mwi() to have the system do its best effort at enabling ++Mem-Wr-Inval. + + + 3.2 Request MMIO/IOP resources +diff -Nurp linux-2.6.22/Documentation/power/freezing-of-tasks.txt linux-2.6-netns/Documentation/power/freezing-of-tasks.txt +--- linux-2.6.22/Documentation/power/freezing-of-tasks.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/power/freezing-of-tasks.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -0,0 +1,160 @@ ++Freezing of tasks ++ (C) 2007 Rafael J. Wysocki , GPL ++ ++I. What is the freezing of tasks? ++ ++The freezing of tasks is a mechanism by which user space processes and some ++kernel threads are controlled during hibernation or system-wide suspend (on some ++architectures). ++ ++II. How does it work? ++ ++There are four per-task flags used for that, PF_NOFREEZE, PF_FROZEN, TIF_FREEZE ++and PF_FREEZER_SKIP (the last one is auxiliary). The tasks that have ++PF_NOFREEZE unset (all user space processes and some kernel threads) are ++regarded as 'freezable' and treated in a special way before the system enters a ++suspend state as well as before a hibernation image is created (in what follows ++we only consider hibernation, but the description also applies to suspend). ++ ++Namely, as the first step of the hibernation procedure the function ++freeze_processes() (defined in kernel/power/process.c) is called. It executes ++try_to_freeze_tasks() that sets TIF_FREEZE for all of the freezable tasks and ++sends a fake signal to each of them. A task that receives such a signal and has ++TIF_FREEZE set, should react to it by calling the refrigerator() function ++(defined in kernel/power/process.c), which sets the task's PF_FROZEN flag, ++changes its state to TASK_UNINTERRUPTIBLE and makes it loop until PF_FROZEN is ++cleared for it. Then, we say that the task is 'frozen' and therefore the set of ++functions handling this mechanism is called 'the freezer' (these functions are ++defined in kernel/power/process.c and include/linux/freezer.h). User space ++processes are generally frozen before kernel threads. ++ ++It is not recommended to call refrigerator() directly. Instead, it is ++recommended to use the try_to_freeze() function (defined in ++include/linux/freezer.h), that checks the task's TIF_FREEZE flag and makes the ++task enter refrigerator() if the flag is set. ++ ++For user space processes try_to_freeze() is called automatically from the ++signal-handling code, but the freezable kernel threads need to call it ++explicitly in suitable places. The code to do this may look like the following: ++ ++ do { ++ hub_events(); ++ wait_event_interruptible(khubd_wait, ++ !list_empty(&hub_event_list)); ++ try_to_freeze(); ++ } while (!signal_pending(current)); ++ ++(from drivers/usb/core/hub.c::hub_thread()). ++ ++If a freezable kernel thread fails to call try_to_freeze() after the freezer has ++set TIF_FREEZE for it, the freezing of tasks will fail and the entire ++hibernation operation will be cancelled. For this reason, freezable kernel ++threads must call try_to_freeze() somewhere. ++ ++After the system memory state has been restored from a hibernation image and ++devices have been reinitialized, the function thaw_processes() is called in ++order to clear the PF_FROZEN flag for each frozen task. Then, the tasks that ++have been frozen leave refrigerator() and continue running. ++ ++III. Which kernel threads are freezable? ++ ++Kernel threads are not freezable by default. However, a kernel thread may clear ++PF_NOFREEZE for itself by calling set_freezable() (the resetting of PF_NOFREEZE ++directly is strongly discouraged). From this point it is regarded as freezable ++and must call try_to_freeze() in a suitable place. ++ ++IV. Why do we do that? ++ ++Generally speaking, there is a couple of reasons to use the freezing of tasks: ++ ++1. The principal reason is to prevent filesystems from being damaged after ++hibernation. At the moment we have no simple means of checkpointing ++filesystems, so if there are any modifications made to filesystem data and/or ++metadata on disks, we cannot bring them back to the state from before the ++modifications. At the same time each hibernation image contains some ++filesystem-related information that must be consistent with the state of the ++on-disk data and metadata after the system memory state has been restored from ++the image (otherwise the filesystems will be damaged in a nasty way, usually ++making them almost impossible to repair). We therefore freeze tasks that might ++cause the on-disk filesystems' data and metadata to be modified after the ++hibernation image has been created and before the system is finally powered off. ++The majority of these are user space processes, but if any of the kernel threads ++may cause something like this to happen, they have to be freezable. ++ ++2. The second reason is to prevent user space processes and some kernel threads ++from interfering with the suspending and resuming of devices. A user space ++process running on a second CPU while we are suspending devices may, for ++example, be troublesome and without the freezing of tasks we would need some ++safeguards against race conditions that might occur in such a case. ++ ++Although Linus Torvalds doesn't like the freezing of tasks, he said this in one ++of the discussions on LKML (http://lkml.org/lkml/2007/4/27/608): ++ ++"RJW:> Why we freeze tasks at all or why we freeze kernel threads? ++ ++Linus: In many ways, 'at all'. ++ ++I _do_ realize the IO request queue issues, and that we cannot actually do ++s2ram with some devices in the middle of a DMA. So we want to be able to ++avoid *that*, there's no question about that. And I suspect that stopping ++user threads and then waiting for a sync is practically one of the easier ++ways to do so. ++ ++So in practice, the 'at all' may become a 'why freeze kernel threads?' and ++freezing user threads I don't find really objectionable." ++ ++Still, there are kernel threads that may want to be freezable. For example, if ++a kernel that belongs to a device driver accesses the device directly, it in ++principle needs to know when the device is suspended, so that it doesn't try to ++access it at that time. However, if the kernel thread is freezable, it will be ++frozen before the driver's .suspend() callback is executed and it will be ++thawed after the driver's .resume() callback has run, so it won't be accessing ++the device while it's suspended. ++ ++3. Another reason for freezing tasks is to prevent user space processes from ++realizing that hibernation (or suspend) operation takes place. Ideally, user ++space processes should not notice that such a system-wide operation has occurred ++and should continue running without any problems after the restore (or resume ++from suspend). Unfortunately, in the most general case this is quite difficult ++to achieve without the freezing of tasks. Consider, for example, a process ++that depends on all CPUs being online while it's running. Since we need to ++disable nonboot CPUs during the hibernation, if this process is not frozen, it ++may notice that the number of CPUs has changed and may start to work incorrectly ++because of that. ++ ++V. Are there any problems related to the freezing of tasks? ++ ++Yes, there are. ++ ++First of all, the freezing of kernel threads may be tricky if they depend one ++on another. For example, if kernel thread A waits for a completion (in the ++TASK_UNINTERRUPTIBLE state) that needs to be done by freezable kernel thread B ++and B is frozen in the meantime, then A will be blocked until B is thawed, which ++may be undesirable. That's why kernel threads are not freezable by default. ++ ++Second, there are the following two problems related to the freezing of user ++space processes: ++1. Putting processes into an uninterruptible sleep distorts the load average. ++2. Now that we have FUSE, plus the framework for doing device drivers in ++userspace, it gets even more complicated because some userspace processes are ++now doing the sorts of things that kernel threads do ++(https://lists.linux-foundation.org/pipermail/linux-pm/2007-May/012309.html). ++ ++The problem 1. seems to be fixable, although it hasn't been fixed so far. The ++other one is more serious, but it seems that we can work around it by using ++hibernation (and suspend) notifiers (in that case, though, we won't be able to ++avoid the realization by the user space processes that the hibernation is taking ++place). ++ ++There are also problems that the freezing of tasks tends to expose, although ++they are not directly related to it. For example, if request_firmware() is ++called from a device driver's .resume() routine, it will timeout and eventually ++fail, because the user land process that should respond to the request is frozen ++at this point. So, seemingly, the failure is due to the freezing of tasks. ++Suppose, however, that the firmware file is located on a filesystem accessible ++only through another device that hasn't been resumed yet. In that case, ++request_firmware() will fail regardless of whether or not the freezing of tasks ++is used. Consequently, the problem is not really related to the freezing of ++tasks, since it generally exists anyway. [The solution to this particular ++problem is to keep the firmware in memory after it's loaded for the first time ++and upload if from memory to the device whenever necessary.] +diff -Nurp linux-2.6.22/Documentation/power/kernel_threads.txt linux-2.6-netns/Documentation/power/kernel_threads.txt +--- linux-2.6.22/Documentation/power/kernel_threads.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/power/kernel_threads.txt 1969-12-31 19:00:00.000000000 -0500 +@@ -1,40 +0,0 @@ +-KERNEL THREADS +- +- +-Freezer +- +-Upon entering a suspended state the system will freeze all +-tasks. This is done by delivering pseudosignals. This affects +-kernel threads, too. To successfully freeze a kernel thread +-the thread has to check for the pseudosignal and enter the +-refrigerator. Code to do this looks like this: +- +- do { +- hub_events(); +- wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); +- try_to_freeze(); +- } while (!signal_pending(current)); +- +-from drivers/usb/core/hub.c::hub_thread() +- +- +-The Unfreezable +- +-Some kernel threads however, must not be frozen. The kernel must +-be able to finish pending IO operations and later on be able to +-write the memory image to disk. Kernel threads needed to do IO +-must stay awake. Such threads must mark themselves unfreezable +-like this: +- +- /* +- * This thread doesn't need any user-level access, +- * so get rid of all our resources. +- */ +- daemonize("usb-storage"); +- +- current->flags |= PF_NOFREEZE; +- +-from drivers/usb/storage/usb.c::usb_stor_control_thread() +- +-Such drivers are themselves responsible for staying quiet during +-the actual snapshotting. +diff -Nurp linux-2.6.22/Documentation/power/pci.txt linux-2.6-netns/Documentation/power/pci.txt +--- linux-2.6.22/Documentation/power/pci.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/power/pci.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -164,7 +164,6 @@ struct pci_driver: + + int (*suspend) (struct pci_dev *dev, pm_message_t state); + int (*resume) (struct pci_dev *dev); +- int (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable); + + + suspend +@@ -251,42 +250,6 @@ The driver should update the current_sta + this function, except for PM-capable devices when pci_set_power_state is used. + + +-enable_wake +------------ +- +-Usage: +- +-if (dev->driver && dev->driver->enable_wake) +- dev->driver->enable_wake(dev,state,enable); +- +-This callback is generally only relevant for devices that support the PCI PM +-spec and have the ability to generate a PME# (Power Management Event Signal) +-to wake the system up. (However, it is possible that a device may support +-some non-standard way of generating a wake event on sleep.) +- +-Bits 15:11 of the PMC (Power Mgmt Capabilities) Register in a device's +-PM Capabilities describe what power states the device supports generating a +-wake event from: +- +-+------------------+ +-| Bit | State | +-+------------------+ +-| 11 | D0 | +-| 12 | D1 | +-| 13 | D2 | +-| 14 | D3hot | +-| 15 | D3cold | +-+------------------+ +- +-A device can use this to enable wake events: +- +- pci_enable_wake(dev,state,enable); +- +-Note that to enable PME# from D3cold, a value of 4 should be passed to +-pci_enable_wake (since it uses an index into a bitmask). If a driver gets +-a request to enable wake events from D3, two calls should be made to +-pci_enable_wake (one for both D3hot and D3cold). +- + + A reference implementation + ------------------------- +diff -Nurp linux-2.6.22/Documentation/power/swsusp.txt linux-2.6-netns/Documentation/power/swsusp.txt +--- linux-2.6.22/Documentation/power/swsusp.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/power/swsusp.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -140,21 +140,11 @@ should be sent to the mailing list avail + website, and not to the Linux Kernel Mailing List. We are working + toward merging suspend2 into the mainline kernel. + +-Q: A kernel thread must voluntarily freeze itself (call 'refrigerator'). +-I found some kernel threads that don't do it, and they don't freeze +-so the system can't sleep. Is this a known behavior? +- +-A: All such kernel threads need to be fixed, one by one. Select the +-place where the thread is safe to be frozen (no kernel semaphores +-should be held at that point and it must be safe to sleep there), and +-add: +- +- try_to_freeze(); +- +-If the thread is needed for writing the image to storage, you should +-instead set the PF_NOFREEZE process flag when creating the thread (and +-be very careful). ++Q: What is the freezing of tasks and why are we using it? + ++A: The freezing of tasks is a mechanism by which user space processes and some ++kernel threads are controlled during hibernation or system-wide suspend (on some ++architectures). See freezing-of-tasks.txt for details. + + Q: What is the difference between "platform" and "shutdown"? + +@@ -393,6 +383,9 @@ safest thing is to unmount all filesyste + Firewire, CompactFlash, MMC, external SATA, or even IDE hotplug bays) + before suspending; then remount them after resuming. + ++There is a work-around for this problem. For more information, see ++Documentation/usb/persist.txt. ++ + Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were + compiled with the similar configuration files. Anyway I found that + suspend to disk (and resume) is much slower on 2.6.16 compared to +diff -Nurp linux-2.6.22/Documentation/power_supply_class.txt linux-2.6-netns/Documentation/power_supply_class.txt +--- linux-2.6.22/Documentation/power_supply_class.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/power_supply_class.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,167 @@ ++Linux power supply class ++======================== ++ ++Synopsis ++~~~~~~~~ ++Power supply class used to represent battery, UPS, AC or DC power supply ++properties to user-space. ++ ++It defines core set of attributes, which should be applicable to (almost) ++every power supply out there. Attributes are available via sysfs and uevent ++interfaces. ++ ++Each attribute has well defined meaning, up to unit of measure used. While ++the attributes provided are believed to be universally applicable to any ++power supply, specific monitoring hardware may not be able to provide them ++all, so any of them may be skipped. ++ ++Power supply class is extensible, and allows to define drivers own attributes. ++The core attribute set is subject to the standard Linux evolution (i.e. ++if it will be found that some attribute is applicable to many power supply ++types or their drivers, it can be added to the core set). ++ ++It also integrates with LED framework, for the purpose of providing ++typically expected feedback of battery charging/fully charged status and ++AC/USB power supply online status. (Note that specific details of the ++indication (including whether to use it at all) are fully controllable by ++user and/or specific machine defaults, per design principles of LED ++framework). ++ ++ ++Attributes/properties ++~~~~~~~~~~~~~~~~~~~~~ ++Power supply class has predefined set of attributes, this eliminates code ++duplication across drivers. Power supply class insist on reusing its ++predefined attributes *and* their units. ++ ++So, userspace gets predictable set of attributes and their units for any ++kind of power supply, and can process/present them to a user in consistent ++manner. Results for different power supplies and machines are also directly ++comparable. ++ ++See drivers/power/ds2760_battery.c and drivers/power/pda_power.c for the ++example how to declare and handle attributes. ++ ++ ++Units ++~~~~~ ++Quoting include/linux/power_supply.h: ++ ++ All voltages, currents, charges, energies, time and temperatures in µV, ++ µA, µAh, µWh, seconds and tenths of degree Celsius unless otherwise ++ stated. It's driver's job to convert its raw values to units in which ++ this class operates. ++ ++ ++Attributes/properties detailed ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++~ ~ ~ ~ ~ ~ ~ Charge/Energy/Capacity - how to not confuse ~ ~ ~ ~ ~ ~ ~ ++~ ~ ++~ Because both "charge" (µAh) and "energy" (µWh) represents "capacity" ~ ++~ of battery, this class distinguish these terms. Don't mix them! ~ ++~ ~ ++~ CHARGE_* attributes represents capacity in µAh only. ~ ++~ ENERGY_* attributes represents capacity in µWh only. ~ ++~ CAPACITY attribute represents capacity in *percents*, from 0 to 100. ~ ++~ ~ ++~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ++ ++Postfixes: ++_AVG - *hardware* averaged value, use it if your hardware is really able to ++report averaged values. ++_NOW - momentary/instantaneous values. ++ ++STATUS - this attribute represents operating status (charging, full, ++discharging (i.e. powering a load), etc.). This corresponds to ++BATTERY_STATUS_* values, as defined in battery.h. ++ ++HEALTH - represents health of the battery, values corresponds to ++POWER_SUPPLY_HEALTH_*, defined in battery.h. ++ ++VOLTAGE_MAX_DESIGN, VOLTAGE_MIN_DESIGN - design values for maximal and ++minimal power supply voltages. Maximal/minimal means values of voltages ++when battery considered "full"/"empty" at normal conditions. Yes, there is ++no direct relation between voltage and battery capacity, but some dumb ++batteries use voltage for very approximated calculation of capacity. ++Battery driver also can use this attribute just to inform userspace ++about maximal and minimal voltage thresholds of a given battery. ++ ++CHARGE_FULL_DESIGN, CHARGE_EMPTY_DESIGN - design charge values, when ++battery considered full/empty. ++ ++ENERGY_FULL_DESIGN, ENERGY_EMPTY_DESIGN - same as above but for energy. ++ ++CHARGE_FULL, CHARGE_EMPTY - These attributes means "last remembered value ++of charge when battery became full/empty". It also could mean "value of ++charge when battery considered full/empty at given conditions (temperature, ++age)". I.e. these attributes represents real thresholds, not design values. ++ ++ENERGY_FULL, ENERGY_EMPTY - same as above but for energy. ++ ++CAPACITY - capacity in percents. ++CAPACITY_LEVEL - capacity level. This corresponds to ++POWER_SUPPLY_CAPACITY_LEVEL_*. ++ ++TEMP - temperature of the power supply. ++TEMP_AMBIENT - ambient temperature. ++ ++TIME_TO_EMPTY - seconds left for battery to be considered empty (i.e. ++while battery powers a load) ++TIME_TO_FULL - seconds left for battery to be considered full (i.e. ++while battery is charging) ++ ++ ++Battery <-> external power supply interaction ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Often power supplies are acting as supplies and supplicants at the same ++time. Batteries are good example. So, batteries usually care if they're ++externally powered or not. ++ ++For that case, power supply class implements notification mechanism for ++batteries. ++ ++External power supply (AC) lists supplicants (batteries) names in ++"supplied_to" struct member, and each power_supply_changed() call ++issued by external power supply will notify supplicants via ++external_power_changed callback. ++ ++ ++QA ++~~ ++Q: Where is POWER_SUPPLY_PROP_XYZ attribute? ++A: If you cannot find attribute suitable for your driver needs, feel free ++ to add it and send patch along with your driver. ++ ++ The attributes available currently are the ones currently provided by the ++ drivers written. ++ ++ Good candidates to add in future: model/part#, cycle_time, manufacturer, ++ etc. ++ ++ ++Q: I have some very specific attribute (e.g. battery color), should I add ++ this attribute to standard ones? ++A: Most likely, no. Such attribute can be placed in the driver itself, if ++ it is useful. Of course, if the attribute in question applicable to ++ large set of batteries, provided by many drivers, and/or comes from ++ some general battery specification/standard, it may be a candidate to ++ be added to the core attribute set. ++ ++ ++Q: Suppose, my battery monitoring chip/firmware does not provides capacity ++ in percents, but provides charge_{now,full,empty}. Should I calculate ++ percentage capacity manually, inside the driver, and register CAPACITY ++ attribute? The same question about time_to_empty/time_to_full. ++A: Most likely, no. This class is designed to export properties which are ++ directly measurable by the specific hardware available. ++ ++ Inferring not available properties using some heuristics or mathematical ++ model is not subject of work for a battery driver. Such functionality ++ should be factored out, and in fact, apm_power, the driver to serve ++ legacy APM API on top of power supply class, uses a simple heuristic of ++ approximating remaining battery capacity based on its charge, current, ++ voltage and so on. But full-fledged battery model is likely not subject ++ for kernel at all, as it would require floating point calculation to deal ++ with things like differential equations and Kalman filters. This is ++ better be handled by batteryd/libbattery, yet to be written. +diff -Nurp linux-2.6.22/Documentation/powerpc/booting-without-of.txt linux-2.6-netns/Documentation/powerpc/booting-without-of.txt +--- linux-2.6.22/Documentation/powerpc/booting-without-of.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/powerpc/booting-without-of.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -42,15 +42,16 @@ Table of Contents + 1) Defining child nodes of an SOC + 2) Representing devices without a current OF specification + a) MDIO IO device +- c) PHY nodes + b) Gianfar-compatible ethernet nodes ++ c) PHY nodes + d) Interrupt controllers + e) I2C + f) Freescale SOC USB controllers + g) Freescale SOC SEC Security Engines + h) Board Control and Status (BCSR) + i) Freescale QUICC Engine module (QE) +- g) Flash chip nodes ++ j) Flash chip nodes ++ k) Global Utilities Block + + VII - Specifying interrupt information for devices + 1) interrupts property +@@ -626,6 +627,14 @@ So the node content can be summarized as + a list of properties, a list of child nodes, and an end token. Every + child node is a full node structure itself as defined above. + ++NOTE: The above definition requires that all property definitions for ++a particular node MUST precede any subnode definitions for that node. ++Although the structure would not be ambiguous if properties and ++subnodes were intermingled, the kernel parser requires that the ++properties come first (up until at least 2.6.22). Any tools ++manipulating a flattened tree must take care to preserve this ++constraint. ++ + 4) Device tree "strings" block + + In order to save space, property names, which are generally redundant, +@@ -1241,6 +1250,12 @@ platforms are moved over to use the flat + network device. This is used by the bootwrapper to interpret + MAC addresses passed by the firmware when no information other + than indices is available to associate an address with a device. ++ - phy-connection-type : a string naming the controller/PHY interface type, ++ i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "sgmii", ++ "tbi", or "rtbi". This property is only really needed if the connection ++ is of type "rgmii-id", as all other connection types are detected by ++ hardware. ++ + + Example: + +@@ -1782,6 +1797,33 @@ platforms are moved over to use the flat + partition-names = "fs\0firmware"; + }; + ++ k) Global Utilities Block ++ ++ The global utilities block controls power management, I/O device ++ enabling, power-on-reset configuration monitoring, general-purpose ++ I/O signal configuration, alternate function selection for multiplexed ++ signals, and clock control. ++ ++ Required properties: ++ ++ - compatible : Should define the compatible device type for ++ global-utilities. ++ - reg : Offset and length of the register set for the device. ++ ++ Recommended properties: ++ ++ - fsl,has-rstcr : Indicates that the global utilities register set ++ contains a functioning "reset control register" (i.e. the board ++ is wired to reset upon setting the HRESET_REQ bit in this register). ++ ++ Example: ++ ++ global-utilities@e0000 { /* global utilities block */ ++ compatible = "fsl,mpc8548-guts"; ++ reg = ; ++ fsl,has-rstcr; ++ }; ++ + More devices will be defined as this spec matures. + + VII - Specifying interrupt information for devices +diff -Nurp linux-2.6.22/Documentation/rtc.txt linux-2.6-netns/Documentation/rtc.txt +--- linux-2.6.22/Documentation/rtc.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/rtc.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -385,7 +385,7 @@ test_PIE: + /* not all RTCs support periodic IRQs */ + if (errno == ENOTTY) { + fprintf(stderr, "\nNo periodic IRQ support\n"); +- return 0; ++ goto done; + } + perror("RTC_IRQP_READ ioctl"); + exit(errno); +diff -Nurp linux-2.6.22/Documentation/sched-design-CFS.txt linux-2.6-netns/Documentation/sched-design-CFS.txt +--- linux-2.6.22/Documentation/sched-design-CFS.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/sched-design-CFS.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -0,0 +1,119 @@ ++ ++This is the CFS scheduler. ++ ++80% of CFS's design can be summed up in a single sentence: CFS basically ++models an "ideal, precise multi-tasking CPU" on real hardware. ++ ++"Ideal multi-tasking CPU" is a (non-existent :-)) CPU that has 100% ++physical power and which can run each task at precise equal speed, in ++parallel, each at 1/nr_running speed. For example: if there are 2 tasks ++running then it runs each at 50% physical power - totally in parallel. ++ ++On real hardware, we can run only a single task at once, so while that ++one task runs, the other tasks that are waiting for the CPU are at a ++disadvantage - the current task gets an unfair amount of CPU time. In ++CFS this fairness imbalance is expressed and tracked via the per-task ++p->wait_runtime (nanosec-unit) value. "wait_runtime" is the amount of ++time the task should now run on the CPU for it to become completely fair ++and balanced. ++ ++( small detail: on 'ideal' hardware, the p->wait_runtime value would ++ always be zero - no task would ever get 'out of balance' from the ++ 'ideal' share of CPU time. ) ++ ++CFS's task picking logic is based on this p->wait_runtime value and it ++is thus very simple: it always tries to run the task with the largest ++p->wait_runtime value. In other words, CFS tries to run the task with ++the 'gravest need' for more CPU time. So CFS always tries to split up ++CPU time between runnable tasks as close to 'ideal multitasking ++hardware' as possible. ++ ++Most of the rest of CFS's design just falls out of this really simple ++concept, with a few add-on embellishments like nice levels, ++multiprocessing and various algorithm variants to recognize sleepers. ++ ++In practice it works like this: the system runs a task a bit, and when ++the task schedules (or a scheduler tick happens) the task's CPU usage is ++'accounted for': the (small) time it just spent using the physical CPU ++is deducted from p->wait_runtime. [minus the 'fair share' it would have ++gotten anyway]. Once p->wait_runtime gets low enough so that another ++task becomes the 'leftmost task' of the time-ordered rbtree it maintains ++(plus a small amount of 'granularity' distance relative to the leftmost ++task so that we do not over-schedule tasks and trash the cache) then the ++new leftmost task is picked and the current task is preempted. ++ ++The rq->fair_clock value tracks the 'CPU time a runnable task would have ++fairly gotten, had it been runnable during that time'. So by using ++rq->fair_clock values we can accurately timestamp and measure the ++'expected CPU time' a task should have gotten. All runnable tasks are ++sorted in the rbtree by the "rq->fair_clock - p->wait_runtime" key, and ++CFS picks the 'leftmost' task and sticks to it. As the system progresses ++forwards, newly woken tasks are put into the tree more and more to the ++right - slowly but surely giving a chance for every task to become the ++'leftmost task' and thus get on the CPU within a deterministic amount of ++time. ++ ++Some implementation details: ++ ++ - the introduction of Scheduling Classes: an extensible hierarchy of ++ scheduler modules. These modules encapsulate scheduling policy ++ details and are handled by the scheduler core without the core ++ code assuming about them too much. ++ ++ - sched_fair.c implements the 'CFS desktop scheduler': it is a ++ replacement for the vanilla scheduler's SCHED_OTHER interactivity ++ code. ++ ++ I'd like to give credit to Con Kolivas for the general approach here: ++ he has proven via RSDL/SD that 'fair scheduling' is possible and that ++ it results in better desktop scheduling. Kudos Con! ++ ++ The CFS patch uses a completely different approach and implementation ++ from RSDL/SD. My goal was to make CFS's interactivity quality exceed ++ that of RSDL/SD, which is a high standard to meet :-) Testing ++ feedback is welcome to decide this one way or another. [ and, in any ++ case, all of SD's logic could be added via a kernel/sched_sd.c module ++ as well, if Con is interested in such an approach. ] ++ ++ CFS's design is quite radical: it does not use runqueues, it uses a ++ time-ordered rbtree to build a 'timeline' of future task execution, ++ and thus has no 'array switch' artifacts (by which both the vanilla ++ scheduler and RSDL/SD are affected). ++ ++ CFS uses nanosecond granularity accounting and does not rely on any ++ jiffies or other HZ detail. Thus the CFS scheduler has no notion of ++ 'timeslices' and has no heuristics whatsoever. There is only one ++ central tunable: ++ ++ /proc/sys/kernel/sched_granularity_ns ++ ++ which can be used to tune the scheduler from 'desktop' (low ++ latencies) to 'server' (good batching) workloads. It defaults to a ++ setting suitable for desktop workloads. SCHED_BATCH is handled by the ++ CFS scheduler module too. ++ ++ Due to its design, the CFS scheduler is not prone to any of the ++ 'attacks' that exist today against the heuristics of the stock ++ scheduler: fiftyp.c, thud.c, chew.c, ring-test.c, massive_intr.c all ++ work fine and do not impact interactivity and produce the expected ++ behavior. ++ ++ the CFS scheduler has a much stronger handling of nice levels and ++ SCHED_BATCH: both types of workloads should be isolated much more ++ agressively than under the vanilla scheduler. ++ ++ ( another detail: due to nanosec accounting and timeline sorting, ++ sched_yield() support is very simple under CFS, and in fact under ++ CFS sched_yield() behaves much better than under any other ++ scheduler i have tested so far. ) ++ ++ - sched_rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler ++ way than the vanilla scheduler does. It uses 100 runqueues (for all ++ 100 RT priority levels, instead of 140 in the vanilla scheduler) ++ and it needs no expired array. ++ ++ - reworked/sanitized SMP load-balancing: the runqueue-walking ++ assumptions are gone from the load-balancing code now, and ++ iterators of the scheduling modules are used. The balancing code got ++ quite a bit simpler as a result. ++ +diff -Nurp linux-2.6.22/Documentation/scsi/aacraid.txt linux-2.6-netns/Documentation/scsi/aacraid.txt +--- linux-2.6.22/Documentation/scsi/aacraid.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/scsi/aacraid.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -50,6 +50,9 @@ Supported Cards/Chipsets + 9005:0285:9005:02be Adaptec 31605 (Marauder160) + 9005:0285:9005:02c3 Adaptec 51205 (Voodoo120) + 9005:0285:9005:02c4 Adaptec 51605 (Voodoo160) ++ 9005:0285:9005:02ce Adaptec 51245 (Voodoo124) ++ 9005:0285:9005:02cf Adaptec 51645 (Voodoo164) ++ 9005:0285:9005:02d0 Adaptec 52445 (Voodoo244) + 1011:0046:9005:0364 Adaptec 5400S (Mustang) + 9005:0287:9005:0800 Adaptec Themisto (Jupiter) + 9005:0200:9005:0200 Adaptec Themisto (Jupiter) +diff -Nurp linux-2.6.22/Documentation/scsi/scsi_fc_transport.txt linux-2.6-netns/Documentation/scsi/scsi_fc_transport.txt +--- linux-2.6.22/Documentation/scsi/scsi_fc_transport.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/scsi/scsi_fc_transport.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,450 @@ ++ SCSI FC Tansport ++ ============================================= ++ ++Date: 4/12/2007 ++Kernel Revisions for features: ++ rports : <> ++ vports : 2.6.22 (? TBD) ++ ++ ++Introduction ++============ ++This file documents the features and components of the SCSI FC Transport. ++It also provides documents the API between the transport and FC LLDDs. ++The FC transport can be found at: ++ drivers/scsi/scsi_transport_fc.c ++ include/scsi/scsi_transport_fc.h ++ include/scsi/scsi_netlink_fc.h ++ ++This file is found at Documentation/scsi/scsi_fc_transport.txt ++ ++ ++FC Remote Ports (rports) ++======================================================================== ++<< To Be Supplied >> ++ ++ ++FC Virtual Ports (vports) ++======================================================================== ++ ++Overview: ++------------------------------- ++ ++ New FC standards have defined mechanisms which allows for a single physical ++ port to appear on as multiple communication ports. Using the N_Port Id ++ Virtualization (NPIV) mechanism, a point-to-point connection to a Fabric ++ can be assigned more than 1 N_Port_ID. Each N_Port_ID appears as a ++ separate port to other endpoints on the fabric, even though it shares one ++ physical link to the switch for communication. Each N_Port_ID can have a ++ unique view of the fabric based on fabric zoning and array lun-masking ++ (just like a normal non-NPIV adapter). Using the Virtual Fabric (VF) ++ mechanism, adding a fabric header to each frame allows the port to ++ interact with the Fabric Port to join multiple fabrics. The port will ++ obtain an N_Port_ID on each fabric it joins. Each fabric will have its ++ own unique view of endpoints and configuration parameters. NPIV may be ++ used together with VF so that the port can obtain multiple N_Port_IDs ++ on each virtual fabric. ++ ++ The FC transport is now recognizing a new object - a vport. A vport is ++ an entity that has a world-wide unique World Wide Port Name (wwpn) and ++ World Wide Node Name (wwnn). The transport also allows for the FC4's to ++ be specified for the vport, with FCP_Initiator being the primary role ++ expected. Once instantiated by one of the above methods, it will have a ++ distinct N_Port_ID and view of fabric endpoints and storage entities. ++ The fc_host associated with the physical adapter will export the ability ++ to create vports. The transport will create the vport object within the ++ Linux device tree, and instruct the fc_host's driver to instantiate the ++ virtual port. Typically, the driver will create a new scsi_host instance ++ on the vport, resulting in a unique namespace for the vport. ++ Thus, whether a FC port is based on a physical port or on a virtual port, ++ each will appear as a unique scsi_host with its own target and lun space. ++ ++ Note: At this time, the transport is written to create only NPIV-based ++ vports. However, consideration was given to VF-based vports and it ++ should be a minor change to add support if needed. The remaining ++ discussion will concentrate on NPIV. ++ ++ Note: World Wide Name assignment (and uniqueness guarantees) are left ++ up to an administrative entity controling the vport. For example, ++ if vports are to be associated with virtual machines, a XEN mgmt ++ utility would be responsible for creating wwpn/wwnn's for the vport, ++ using it's own naming authority and OUI. (Note: it already does this ++ for virtual MAC addresses). ++ ++ ++Device Trees and Vport Objects: ++------------------------------- ++ ++ Today, the device tree typically contains the scsi_host object, ++ with rports and scsi target objects underneath it. Currently the FC ++ transport creates the vport object and places it under the scsi_host ++ object corresponding to the physical adapter. The LLDD will allocate ++ a new scsi_host for the vport and link it's object under the vport. ++ The remainder of the tree under the vports scsi_host is the same ++ as the non-NPIV case. The transport is written currently to easily ++ allow the parent of the vport to be something other than the scsi_host. ++ This could be used in the future to link the object onto a vm-specific ++ device tree. If the vport's parent is not the physical port's scsi_host, ++ a symbolic link to the vport object will be placed in the physical ++ port's scsi_host. ++ ++ Here's what to expect in the device tree : ++ The typical Physical Port's Scsi_Host: ++ /sys/devices/.../host17/ ++ and it has the typical decendent tree: ++ /sys/devices/.../host17/rport-17:0-0/target17:0:0/17:0:0:0: ++ and then the vport is created on the Physical Port: ++ /sys/devices/.../host17/vport-17:0-0 ++ and the vport's Scsi_Host is then created: ++ /sys/devices/.../host17/vport-17:0-0/host18 ++ and then the rest of the tree progresses, such as: ++ /sys/devices/.../host17/vport-17:0-0/host18/rport-18:0-0/target18:0:0/18:0:0:0: ++ ++ Here's what to expect in the sysfs tree : ++ scsi_hosts: ++ /sys/class/scsi_host/host17 physical port's scsi_host ++ /sys/class/scsi_host/host18 vport's scsi_host ++ fc_hosts: ++ /sys/class/fc_host/host17 physical port's fc_host ++ /sys/class/fc_host/host18 vport's fc_host ++ fc_vports: ++ /sys/class/fc_vports/vport-17:0-0 the vport's fc_vport ++ fc_rports: ++ /sys/class/fc_remote_ports/rport-17:0-0 rport on the physical port ++ /sys/class/fc_remote_ports/rport-18:0-0 rport on the vport ++ ++ ++Vport Attributes: ++------------------------------- ++ ++ The new fc_vport class object has the following attributes ++ ++ node_name: Read_Only ++ The WWNN of the vport ++ ++ port_name: Read_Only ++ The WWPN of the vport ++ ++ roles: Read_Only ++ Indicates the FC4 roles enabled on the vport. ++ ++ symbolic_name: Read_Write ++ A string, appended to the driver's symbolic port name string, which ++ is registered with the switch to identify the vport. For example, ++ a hypervisor could set this string to "Xen Domain 2 VM 5 Vport 2", ++ and this set of identifiers can be seen on switch management screens ++ to identify the port. ++ ++ vport_delete: Write_Only ++ When written with a "1", will tear down the vport. ++ ++ vport_disable: Write_Only ++ When written with a "1", will transition the vport to a disabled. ++ state. The vport will still be instantiated with the Linux kernel, ++ but it will not be active on the FC link. ++ When written with a "0", will enable the vport. ++ ++ vport_last_state: Read_Only ++ Indicates the previous state of the vport. See the section below on ++ "Vport States". ++ ++ vport_state: Read_Only ++ Indicates the state of the vport. See the section below on ++ "Vport States". ++ ++ vport_type: Read_Only ++ Reflects the FC mechanism used to create the virtual port. ++ Only NPIV is supported currently. ++ ++ ++ For the fc_host class object, the following attributes are added for vports: ++ ++ max_npiv_vports: Read_Only ++ Indicates the maximum number of NPIV-based vports that the ++ driver/adapter can support on the fc_host. ++ ++ npiv_vports_inuse: Read_Only ++ Indicates how many NPIV-based vports have been instantiated on the ++ fc_host. ++ ++ vport_create: Write_Only ++ A "simple" create interface to instantiate a vport on an fc_host. ++ A ":" string is written to the attribute. The transport ++ then instantiates the vport object and calls the LLDD to create the ++ vport with the role of FCP_Initiator. Each WWN is specified as 16 ++ hex characters and may *not* contain any prefixes (e.g. 0x, x, etc). ++ ++ vport_delete: Write_Only ++ A "simple" delete interface to teardown a vport. A ":" ++ string is written to the attribute. The transport will locate the ++ vport on the fc_host with the same WWNs and tear it down. Each WWN ++ is specified as 16 hex characters and may *not* contain any prefixes ++ (e.g. 0x, x, etc). ++ ++ ++Vport States: ++------------------------------- ++ ++ Vport instantiation consists of two parts: ++ - Creation with the kernel and LLDD. This means all transport and ++ driver data structures are built up, and device objects created. ++ This is equivalent to a driver "attach" on an adapter, which is ++ independent of the adapter's link state. ++ - Instantiation of the vport on the FC link via ELS traffic, etc. ++ This is equivalent to a "link up" and successfull link initialization. ++ Futher information can be found in the interfaces section below for ++ Vport Creation. ++ ++ Once a vport has been instantiated with the kernel/LLDD, a vport state ++ can be reported via the sysfs attribute. The following states exist: ++ ++ FC_VPORT_UNKNOWN - Unknown ++ An temporary state, typically set only while the vport is being ++ instantiated with the kernel and LLDD. ++ ++ FC_VPORT_ACTIVE - Active ++ The vport has been successfully been created on the FC link. ++ It is fully functional. ++ ++ FC_VPORT_DISABLED - Disabled ++ The vport instantiated, but "disabled". The vport is not instantiated ++ on the FC link. This is equivalent to a physical port with the ++ link "down". ++ ++ FC_VPORT_LINKDOWN - Linkdown ++ The vport is not operational as the physical link is not operational. ++ ++ FC_VPORT_INITIALIZING - Initializing ++ The vport is in the process of instantiating on the FC link. ++ The LLDD will set this state just prior to starting the ELS traffic ++ to create the vport. This state will persist until the vport is ++ successfully created (state becomes FC_VPORT_ACTIVE) or it fails ++ (state is one of the values below). As this state is transitory, ++ it will not be preserved in the "vport_last_state". ++ ++ FC_VPORT_NO_FABRIC_SUPP - No Fabric Support ++ The vport is not operational. One of the following conditions were ++ encountered: ++ - The FC topology is not Point-to-Point ++ - The FC port is not connected to an F_Port ++ - The F_Port has indicated that NPIV is not supported. ++ ++ FC_VPORT_NO_FABRIC_RSCS - No Fabric Resources ++ The vport is not operational. The Fabric failed FDISC with a status ++ indicating that it does not have sufficient resources to complete ++ the operation. ++ ++ FC_VPORT_FABRIC_LOGOUT - Fabric Logout ++ The vport is not operational. The Fabric has LOGO'd the N_Port_ID ++ associated with the vport. ++ ++ FC_VPORT_FABRIC_REJ_WWN - Fabric Rejected WWN ++ The vport is not operational. The Fabric failed FDISC with a status ++ indicating that the WWN's are not valid. ++ ++ FC_VPORT_FAILED - VPort Failed ++ The vport is not operational. This is a catchall for all other ++ error conditions. ++ ++ ++ The following state table indicates the different state transitions: ++ ++ State Event New State ++ -------------------------------------------------------------------- ++ n/a Initialization Unknown ++ Unknown: Link Down Linkdown ++ Link Up & Loop No Fabric Support ++ Link Up & no Fabric No Fabric Support ++ Link Up & FLOGI response No Fabric Support ++ indicates no NPIV support ++ Link Up & FDISC being sent Initializing ++ Disable request Disable ++ Linkdown: Link Up Unknown ++ Initializing: FDISC ACC Active ++ FDISC LS_RJT w/ no resources No Fabric Resources ++ FDISC LS_RJT w/ invalid Fabric Rejected WWN ++ pname or invalid nport_id ++ FDISC LS_RJT failed for Vport Failed ++ other reasons ++ Link Down Linkdown ++ Disable request Disable ++ Disable: Enable request Unknown ++ Active: LOGO received from fabric Fabric Logout ++ Link Down Linkdown ++ Disable request Disable ++ Fabric Logout: Link still up Unknown ++ ++ The following 4 error states all have the same transitions: ++ No Fabric Support: ++ No Fabric Resources: ++ Fabric Rejected WWN: ++ Vport Failed: ++ Disable request Disable ++ Link goes down Linkdown ++ ++ ++Transport <-> LLDD Interfaces : ++------------------------------- ++ ++Vport support by LLDD: ++ ++ The LLDD indicates support for vports by supplying a vport_create() ++ function in the transport template. The presense of this function will ++ cause the creation of the new attributes on the fc_host. As part of ++ the physical port completing its initialization relative to the ++ transport, it should set the max_npiv_vports attribute to indicate the ++ maximum number of vports the driver and/or adapter supports. ++ ++ ++Vport Creation: ++ ++ The LLDD vport_create() syntax is: ++ ++ int vport_create(struct fc_vport *vport, bool disable) ++ ++ where: ++ vport: Is the newly allocated vport object ++ disable: If "true", the vport is to be created in a disabled stated. ++ If "false", the vport is to be enabled upon creation. ++ ++ When a request is made to create a new vport (via sgio/netlink, or the ++ vport_create fc_host attribute), the transport will validate that the LLDD ++ can support another vport (e.g. max_npiv_vports > npiv_vports_inuse). ++ If not, the create request will be failed. If space remains, the transport ++ will increment the vport count, create the vport object, and then call the ++ LLDD's vport_create() function with the newly allocated vport object. ++ ++ As mentioned above, vport creation is divided into two parts: ++ - Creation with the kernel and LLDD. This means all transport and ++ driver data structures are built up, and device objects created. ++ This is equivalent to a driver "attach" on an adapter, which is ++ independent of the adapter's link state. ++ - Instantiation of the vport on the FC link via ELS traffic, etc. ++ This is equivalent to a "link up" and successfull link initialization. ++ ++ The LLDD's vport_create() function will not synchronously wait for both ++ parts to be fully completed before returning. It must validate that the ++ infrastructure exists to support NPIV, and complete the first part of ++ vport creation (data structure build up) before returning. We do not ++ hinge vport_create() on the link-side operation mainly because: ++ - The link may be down. It is not a failure if it is. It simply ++ means the vport is in an inoperable state until the link comes up. ++ This is consistent with the link bouncing post vport creation. ++ - The vport may be created in a disabled state. ++ - This is consistent with a model where: the vport equates to a ++ FC adapter. The vport_create is synonymous with driver attachment ++ to the adapter, which is independent of link state. ++ ++ Note: special error codes have been defined to delineate infrastructure ++ failure cases for quicker resolution. ++ ++ The expected behavior for the LLDD's vport_create() function is: ++ - Validate Infrastructure: ++ - If the driver or adapter cannot support another vport, whether ++ due to improper firmware, (a lie about) max_npiv, or a lack of ++ some other resource - return VPCERR_UNSUPPORTED. ++ - If the driver validates the WWN's against those already active on ++ the adapter and detects an overlap - return VPCERR_BAD_WWN. ++ - If the driver detects the topology is loop, non-fabric, or the ++ FLOGI did not support NPIV - return VPCERR_NO_FABRIC_SUPP. ++ - Allocate data structures. If errors are encountered, such as out ++ of memory conditions, return the respective negative Exxx error code. ++ - If the role is FCP Initiator, the LLDD is to : ++ - Call scsi_host_alloc() to allocate a scsi_host for the vport. ++ - Call scsi_add_host(new_shost, &vport->dev) to start the scsi_host ++ and bind it as a child of the vport device. ++ - Initializes the fc_host attribute values. ++ - Kick of further vport state transitions based on the disable flag and ++ link state - and return success (zero). ++ ++ LLDD Implementers Notes: ++ - It is suggested that there be a different fc_function_templates for ++ the physical port and the virtual port. The physical port's template ++ would have the vport_create, vport_delete, and vport_disable functions, ++ while the vports would not. ++ - It is suggested that there be different scsi_host_templates ++ for the physical port and virtual port. Likely, there are driver ++ attributes, embedded into the scsi_host_template, that are applicable ++ for the physical port only (link speed, topology setting, etc). This ++ ensures that the attributes are applicable to the respective scsi_host. ++ ++ ++Vport Disable/Enable: ++ ++ The LLDD vport_disable() syntax is: ++ ++ int vport_disable(struct fc_vport *vport, bool disable) ++ ++ where: ++ vport: Is vport to to be enabled or disabled ++ disable: If "true", the vport is to be disabled. ++ If "false", the vport is to be enabled. ++ ++ When a request is made to change the disabled state on a vport, the ++ transport will validate the request against the existing vport state. ++ If the request is to disable and the vport is already disabled, the ++ request will fail. Similarly, if the request is to enable, and the ++ vport is not in a disabled state, the request will fail. If the request ++ is valid for the vport state, the transport will call the LLDD to ++ change the vport's state. ++ ++ Within the LLDD, if a vport is disabled, it remains instantiated with ++ the kernel and LLDD, but it is not active or visible on the FC link in ++ any way. (see Vport Creation and the 2 part instantiation discussion). ++ The vport will remain in this state until it is deleted or re-enabled. ++ When enabling a vport, the LLDD reinstantiates the vport on the FC ++ link - essentially restarting the LLDD statemachine (see Vport States ++ above). ++ ++ ++Vport Deletion: ++ ++ The LLDD vport_delete() syntax is: ++ ++ int vport_delete(struct fc_vport *vport) ++ ++ where: ++ vport: Is vport to delete ++ ++ When a request is made to delete a vport (via sgio/netlink, or via the ++ fc_host or fc_vport vport_delete attributes), the transport will call ++ the LLDD to terminate the vport on the FC link, and teardown all other ++ datastructures and references. If the LLDD completes successfully, ++ the transport will teardown the vport objects and complete the vport ++ removal. If the LLDD delete request fails, the vport object will remain, ++ but will be in an indeterminate state. ++ ++ Within the LLDD, the normal code paths for a scsi_host teardown should ++ be followed. E.g. If the vport has a FCP Initiator role, the LLDD ++ will call fc_remove_host() for the vports scsi_host, followed by ++ scsi_remove_host() and scsi_host_put() for the vports scsi_host. ++ ++ ++Other: ++ fc_host port_type attribute: ++ There is a new fc_host port_type value - FC_PORTTYPE_NPIV. This value ++ must be set on all vport-based fc_hosts. Normally, on a physical port, ++ the port_type attribute would be set to NPORT, NLPORT, etc based on the ++ topology type and existence of the fabric. As this is not applicable to ++ a vport, it makes more sense to report the FC mechanism used to create ++ the vport. ++ ++ Driver unload: ++ FC drivers are required to call fc_remove_host() prior to calling ++ scsi_remove_host(). This allows the fc_host to tear down all remote ++ ports prior the scsi_host being torn down. The fc_remove_host() call ++ was updated to remove all vports for the fc_host as well. ++ ++ ++Credits ++======= ++The following people have contributed to this document: ++ ++ ++ ++ ++ ++ ++James Smart ++james.smart@emulex.com ++ +diff -Nurp linux-2.6.22/Documentation/sound/oss/AD1816 linux-2.6-netns/Documentation/sound/oss/AD1816 +--- linux-2.6.22/Documentation/sound/oss/AD1816 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/sound/oss/AD1816 1969-12-31 19:00:00.000000000 -0500 +@@ -1,84 +0,0 @@ +-Documentation for the AD1816(A) sound driver +-============================================ +- +-Installation: +-------------- +- +-To get your AD1816(A) based sound card work, you'll have to enable support for +-experimental code ("Prompt for development and/or incomplete code/drivers") +-and isapnp ("Plug and Play support", "ISA Plug and Play support"). Enable +-"Sound card support", "OSS modules support" and "Support for AD1816(A) based +-cards (EXPERIMENTAL)" in the sound configuration menu, too. Now build, install +-and reboot the new kernel as usual. +- +-Features: +---------- +- +-List of features supported by this driver: +-- full-duplex support +-- supported audio formats: unsigned 8bit, signed 16bit little endian, +- signed 16bit big endian, µ-law, A-law +-- supported channels: mono and stereo +-- supported recording sources: Master, CD, Line, Line1, Line2, Mic +-- supports phat 3d stereo circuit (Line 3) +- +- +-Supported cards: +----------------- +- +-The following cards are known to work with this driver: +-- Terratec Base 1 +-- Terratec Base 64 +-- HP Kayak +-- Acer FX-3D +-- SY-1816 +-- Highscreen Sound-Boostar 32 Wave 3D +-- Highscreen Sound-Boostar 16 +-- AVM Apex Pro card +-- (Aztech SC-16 3D) +-- (Newcom SC-16 3D) +-- (Terratec EWS64S) +- +-Cards listed in brackets are not supported reliable. If you have such a card +-you should add the extra parameter: +- options=1 +-when loading the ad1816 module via modprobe. +- +- +-Troubleshooting: +----------------- +- +-First of all you should check, if the driver has been loaded +-properly. +- +-If loading of the driver succeeds, but playback/capture fails, check +-if you used the correct values for irq, dma and dma2 when loading the module. +-If one of them is wrong you usually get the following error message: +- +-Nov 6 17:06:13 tek01 kernel: Sound: DMA (output) timed out - IRQ/DRQ config error? +- +-If playback/capture is too fast or to slow, you should have a look at +-the clock chip of your sound card. The AD1816 was designed for a 33MHz +-oscillator, however most sound card manufacturer use slightly +-different oscillators as they are cheaper than 33MHz oscillators. If +-you have such a card you have to adjust the ad1816_clockfreq parameter +-above. For example: For a card using a 32.875MHz oscillator use +-ad1816_clockfreq=32875 instead of ad1816_clockfreq=33000. +- +- +-Updates, bugfixes and bugreports: +--------------------------------- +- +-As the driver is still experimental and under development, you should +-watch out for updates. Updates of the driver are available on the +-Internet from one of my home pages: +- http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html +-or: +- http://www.tu-darmstadt.de/~tek01/projects/linux.html +- +-Bugreports, bugfixes and related questions should be sent via E-Mail to: +- tek@rbg.informatik.tu-darmstadt.de +- +-Thorsten Knabe +-Christoph Hellwig +- Last modified: 2000/09/20 +diff -Nurp linux-2.6.22/Documentation/sound/oss/NM256 linux-2.6-netns/Documentation/sound/oss/NM256 +--- linux-2.6.22/Documentation/sound/oss/NM256 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/sound/oss/NM256 1969-12-31 19:00:00.000000000 -0500 +@@ -1,280 +0,0 @@ +-======================================================= +-Documentation for the NeoMagic 256AV/256ZX sound driver +-======================================================= +- +-You're looking at version 1.1 of the driver. (Woohoo!) It has been +-successfully tested against the following laptop models: +- +- Sony Z505S/Z505SX/Z505DX/Z505RX +- Sony F150, F160, F180, F250, F270, F280, PCG-F26 +- Dell Latitude CPi, CPt (various submodels) +- +-There are a few caveats, which is why you should read the entirety of +-this document first. +- +-This driver was developed without any support or assistance from +-NeoMagic. There is no warranty, expressed, implied, or otherwise. It +-is free software in the public domain; feel free to use it, sell it, +-give it to your best friends, even claim that you wrote it (but why?!) +-but don't go whining to me, NeoMagic, Sony, Dell, or anyone else +-when it blows up your computer. +- +-Version 1.1 contains a change to try and detect non-AC97 versions of +-the hardware, and not install itself appropriately. It should also +-reinitialize the hardware on an APM resume event, assuming that APM +-was configured into your kernel. +- +-============ +-Installation +-============ +- +-Enable the sound drivers, the OSS sound drivers, and then the NM256 +-driver. The NM256 driver *must* be configured as a module (it won't +-give you any other choice). +- +-Next, do the usual "make modules" and "make modules_install". +-Finally, insmod the soundcore, sound and nm256 modules. +- +-When the nm256 driver module is loaded, you should see a couple of +-confirmation messages in the kernel logfile indicating that it found +-the device (the device does *not* use any I/O ports or DMA channels). +-Now try playing a wav file, futz with the CD-ROM if you have one, etc. +- +-The NM256 is entirely a PCI-based device, and all the necessary +-information is automatically obtained from the card. It can only be +-configured as a module in a vain attempt to prevent people from +-hurting themselves. It works correctly if it shares an IRQ with +-another device (it normally shares IRQ 9 with the builtin eepro100 +-ethernet on the Sony Z505 laptops). +- +-It does not run the card in any sort of compatibility mode. It will +-not work on laptops that have the SB16-compatible, AD1848-compatible +-or CS4232-compatible codec/mixer; you will want to use the appropriate +-compatible OSS driver with these chipsets. I cannot provide any +-assistance with machines using the SB16, AD1848 or CS4232 compatible +-versions. (The driver now attempts to detect the mixer version, and +-will refuse to load if it believes the hardware is not +-AC97-compatible.) +- +-The sound support is very basic, but it does include simultaneous +-playback and record capability. The mixer support is also quite +-simple, although this is in keeping with the rather limited +-functionality of the chipset. +- +-There is no hardware synthesizer available, as the Losedows OPL-3 and +-MIDI support is done via hardware emulation. +- +-Only three recording devices are available on the Sony: the +-microphone, the CD-ROM input, and the volume device (which corresponds +-to the stereo output). (Other devices may be available on other +-models of laptops.) The Z505 series does not have a builtin CD-ROM, +-so of course the CD-ROM input doesn't work. It does work on laptops +-with a builtin CD-ROM drive. +- +-The mixer device does not appear to have any tone controls, at least +-on the Z505 series. The mixer module checks for tone controls in the +-AC97 mixer, and will enable them if they are available. +- +-============== +-Known problems +-============== +- +- * There are known problems with PCMCIA cards and the eepro100 ethernet +- driver on the Z505S/Z505SX/Z505DX. Keep reading. +- +- * There are also potential problems with using a virtual X display, and +- also problems loading the module after the X server has been started. +- Keep reading. +- +- * The volume control isn't anywhere near linear. Sorry. This will be +- fixed eventually, when I get sufficiently annoyed with it. (I doubt +- it will ever be fixed now, since I've never gotten sufficiently +- annoyed with it and nobody else seems to care.) +- +- * There are reports that the CD-ROM volume is very low. Since I do not +- have a CD-ROM equipped laptop, I cannot test this (it's kinda hard to +- do remotely). +- +- * Only 8 fixed-rate speeds are supported. This is mainly a chipset +- limitation. It may be possible to support other speeds in the future. +- +- * There is no support for the telephone mixer/codec. There is support +- for a phonein/phoneout device in the mixer driver; whether or not +- it does anything is anyone's guess. (Reports on this would be +- appreciated. You'll have to figure out how to get the phone to +- go off-hook before it'll work, tho.) +- +- * This driver was not written with any cooperation or support from +- NeoMagic. If you have any questions about this, see their website +- for their official stance on supporting open source drivers. +- +-============ +-Video memory +-============ +- +-The NeoMagic sound engine uses a portion of the display memory to hold +-the sound buffer. (Crazy, eh?) The NeoMagic video BIOS sets up a +-special pointer at the top of video RAM to indicate where the top of +-the audio buffer should be placed. +- +-At the present time XFree86 is apparently not aware of this. It will +-thus write over either the pointer or the sound buffer with abandon. +-(Accelerated-X seems to do a better job here.) +- +-This implies a few things: +- +- * Sometimes the NM256 driver has to guess at where the buffer +- should be placed, especially if the module is loaded after the +- X server is started. It's usually correct, but it will consistently +- fail on the Sony F250. +- +- * Virtual screens greater than 1024x768x16 under XFree86 are +- problematic on laptops with only 2.5MB of screen RAM. This +- includes all of the 256AV-equipped laptops. (Virtual displays +- may or may not work on the 256ZX, which has at least 4MB of +- video RAM.) +- +-If you start having problems with random noise being output either +-constantly (this is the usual symptom on the F250), or when windows +-are moved around (this is the usual symptom when using a virtual +-screen), the best fix is to +- +- * Don't use a virtual frame buffer. +- * Make sure you load the NM256 module before the X server is +- started. +- +-On the F250, it is possible to force the driver to load properly even +-after the XFree86 server is started by doing: +- +- insmod nm256 buffertop=0x25a800 +- +-This forces the audio buffers to the correct offset in screen RAM. +- +-One user has reported a similar problem on the Sony F270, although +-others apparently aren't seeing any problems. His suggested command +-is +- +- insmod nm256 buffertop=0x272800 +- +-================= +-Official WWW site +-================= +- +-The official site for the NM256 driver is: +- +- http://www.uglx.org/sony.html +- +-You should always be able to get the latest version of the driver there, +-and the driver will be supported for the foreseeable future. +- +-============== +-Z505RX and IDE +-============== +- +-There appears to be a problem with the IDE chipset on the Z505RX; one +-of the symptoms is that sound playback periodically hangs (when the +-disk is accessed). The user reporting the problem also reported that +-enabling all of the IDE chipset workarounds in the kernel solved the +-problem, tho obviously only one of them should be needed--if someone +-can give me more details I would appreciate it. +- +-============================== +-Z505S/Z505SX on-board Ethernet +-============================== +- +-If you're using the on-board Ethernet Pro/100 ethernet support on the Z505 +-series, I strongly encourage you to download the latest eepro100 driver from +-Donald Becker's site: +- +- ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/test/eepro100.c +- +-There was a reported problem on the Z505SX that if the ethernet +-interface is disabled and reenabled while the sound driver is loaded, +-the machine would lock up. I have included a workaround that is +-working satisfactorily. However, you may occasionally see a message +-about "Releasing interrupts, over 1000 bad interrupts" which indicates +-that the workaround is doing its job. +- +-================================== +-PCMCIA and the Z505S/Z505SX/Z505DX +-================================== +- +-There is also a known problem with the Sony Z505S and Z505SX hanging +-if a PCMCIA card is inserted while the ethernet driver is loaded, or +-in some cases if the laptop is suspended. This is caused by tons of +-spurious IRQ 9s, probably generated from the PCMCIA or ACPI bridges. +- +-There is currently no fix for the problem that works in every case. +-The only known workarounds are to disable the ethernet interface +-before inserting or removing a PCMCIA card, or with some cards +-disabling the PCMCIA card before ejecting it will also help the +-problem with the laptop hanging when the card is ejected. +- +-One user has reported that setting the tcic's cs_irq to some value +-other than 9 (like 11) fixed the problem. This doesn't work on my +-Z505S, however--changing the value causes the cardmgr to stop seeing +-card insertions and removals, cards don't seem to work correctly, and +-I still get hangs if a card is inserted when the kernel is booted. +- +-Using the latest ethernet driver and pcmcia package allows me to +-insert an Adaptec 1480A SlimScsi card without the laptop hanging, +-although I still have to shut down the card before ejecting or +-powering down the laptop. However, similar experiments with a DE-660 +-ethernet card still result in hangs when the card is inserted. I am +-beginning to think that the interrupts are CardBus-related, since the +-Adaptec card is a CardBus card, and the DE-660 is not; however, I +-don't have any other CardBus cards to test with. +- +-====== +-Thanks +-====== +- +-First, I want to thank everyone (except NeoMagic of course) for their +-generous support and encouragement. I'd like to list everyone's name +-here that replied during the development phase, but the list is +-amazingly long. +- +-I will be rather unfair and single out a few people, however: +- +- Justin Maurer, for being the first random net.person to try it, +- and for letting me login to his Z505SX to get it working there +- +- Edi Weitz for trying out several different versions, and giving +- me a lot of useful feedback +- +- Greg Rumple for letting me login remotely to get the driver +- functional on the 256ZX, for his assistance on tracking +- down all sorts of random stuff, and for trying out Accel-X +- +- Zach Brown, for the initial AC97 mixer interface design +- +- Jeff Garzik, for various helpful suggestions on the AC97 +- interface +- +- "Mr. Bumpy" for feedback on the Z505RX +- +- Bill Nottingham, for generous assistance in getting the mixer ID +- code working +- +-================= +-Previous versions +-================= +- +-Versions prior to 0.3 (aka `noname') had problems with weird artifacts +-in the output and failed to set the recording rate properly. These +-problems have long since been fixed. +- +-Versions prior to 0.5 had problems with clicks in the output when +-anything other than 16-bit stereo sound was being played, and also had +-periodic clicks when recording. +- +-Version 0.7 first incorporated support for the NM256ZX chipset, which +-is found on some Dell Latitude laptops (the CPt, and apparently +-some CPi models as well). It also included the generic AC97 +-mixer module. +- +-Version 0.75 renamed all the functions and files with slightly more +-generic names. +- +-Note that previous versions of this document claimed that recording was +-8-bit only; it actually has been working for 16-bits all along. +diff -Nurp linux-2.6.22/Documentation/sound/oss/OPL3-SA2 linux-2.6-netns/Documentation/sound/oss/OPL3-SA2 +--- linux-2.6.22/Documentation/sound/oss/OPL3-SA2 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/sound/oss/OPL3-SA2 1969-12-31 19:00:00.000000000 -0500 +@@ -1,210 +0,0 @@ +-Documentation for the OPL3-SA2, SA3, and SAx driver (opl3sa2.o) +---------------------------------------------------------------- +- +-Scott Murray, scott@spiteful.org +-January 7, 2001 +- +-NOTE: All trade-marked terms mentioned below are properties of their +- respective owners. +- +- +-Supported Devices +------------------ +- +-This driver is for PnP soundcards based on the following Yamaha audio +-controller chipsets: +- +-YMF711 aka OPL3-SA2 +-YMF715 and YMF719 aka OPL3-SA3 +- +-Up until recently (December 2000), I'd thought the 719 to be a +-different chipset, the OPL3-SAx. After an email exhange with +-Yamaha, however, it turns out that the 719 is just a re-badged +-715, and the chipsets are identical. The chipset detection code +-has been updated to reflect this. +- +-Anyways, all of these chipsets implement the following devices: +- +-OPL3 FM synthesizer +-Soundblaster Pro +-Microsoft/Windows Sound System +-MPU401 MIDI interface +- +-Note that this driver uses the MSS device, and to my knowledge these +-chipsets enforce an either/or situation with the Soundblaster Pro +-device and the MSS device. Since the MSS device has better +-capabilities, I have implemented the driver to use it. +- +- +-Mixer Channels +--------------- +- +-Older versions of this driver (pre-December 2000) had two mixers, +-an OPL3-SA2 or SA3 mixer and a MSS mixer. The OPL3-SA[23] mixer +-device contained a superset of mixer channels consisting of its own +-channels and all of the MSS mixer channels. To simplify the driver +-considerably, and to partition functionality better, the OPL3-SA[23] +-mixer device now contains has its own specific mixer channels. They +-are: +- +-Volume - Hardware master volume control +-Bass - SA3 only, now supports left and right channels +-Treble - SA3 only, now supports left and right channels +-Microphone - Hardware microphone input volume control +-Digital1 - Yamaha 3D enhancement "Wide" mixer +- +-All other mixer channels (e.g. "PCM", "CD", etc.) now have to be +-controlled via the "MS Sound System (CS4231)" mixer. To facilitate +-this, the mixer device creation order has been switched so that +-the MSS mixer is created first. This allows accessing the majority +-of the useful mixer channels even via single mixer-aware tools +-such as "aumix". +- +- +-Plug 'n Play +------------- +- +-In previous kernels (2.2.x), some configuration was required to +-get the driver to talk to the card. Being the new millennium and +-all, the 2.4.x kernels now support auto-configuration if ISA PnP +-support is configured in. Theoretically, the driver even supports +-having more than one card in this case. +- +-With the addition of PnP support to the driver, two new parameters +-have been added to control it: +- +-isapnp - set to 0 to disable ISA PnP card detection +- +-multiple - set to 0 to disable multiple PnP card detection +- +- +-Optional Parameters +-------------------- +- +-Recent (December 2000) additions to the driver (based on a patch +-provided by Peter Englmaier) are two new parameters: +- +-ymode - Set Yamaha 3D enhancement mode: +- 0 = Desktop/Normal 5-12 cm speakers +- 1 = Notebook PC (1) 3 cm speakers +- 2 = Notebook PC (2) 1.5 cm speakers +- 3 = Hi-Fi 16-38 cm speakers +- +-loopback - Set A/D input source. Useful for echo cancellation: +- 0 = Mic Right channel (default) +- 1 = Mono output loopback +- +-The ymode parameter has been tested and does work. The loopback +-parameter, however, is untested. Any feedback on its usefulness +-would be appreciated. +- +- +-Manual Configuration +--------------------- +- +-If for some reason you decide not to compile ISA PnP support into +-your kernel, or disabled the driver's usage of it by setting the +-isapnp parameter as discussed above, then you will need to do some +-manual configuration. There are two ways of doing this. The most +-common is to use the isapnptools package to initialize the card, and +-use the kernel module form of the sound subsystem and sound drivers. +-Alternatively, some BIOS's allow manual configuration of installed +-PnP devices in a BIOS menu, which should allow using the non-modular +-sound drivers, i.e. built into the kernel. +- +-I personally use isapnp and modules, and do not have access to a PnP +-BIOS machine to test. If you have such a beast, configuring the +-driver to be built into the kernel should just work (thanks to work +-done by David Luyer ). You will still need +-to specify settings, which can be done by adding: +- +-opl3sa2=,,,,, +- +-to the kernel command line. For example: +- +-opl3sa2=0x370,5,0,1,0x530,0x330 +- +-If you are instead using the isapnp tools (as most people have been +-before Linux 2.4.x), follow the directions in their documentation to +-produce a configuration file. Here is the relevant excerpt I used to +-use for my SA3 card from my isapnp.conf: +- +-(CONFIGURE YMH0800/-1 (LD 0 +- +-# NOTE: IO 0 is for the unused SoundBlaster part of the chipset. +-(IO 0 (BASE 0x0220)) +-(IO 1 (BASE 0x0530)) +-(IO 2 (BASE 0x0388)) +-(IO 3 (BASE 0x0330)) +-(IO 4 (BASE 0x0370)) +-(INT 0 (IRQ 5 (MODE +E))) +-(DMA 0 (CHANNEL 0)) +-(DMA 1 (CHANNEL 1)) +- +-Here, note that: +- +-Port Acceptable Range Purpose +----- ---------------- ------- +-IO 0 0x0220 - 0x0280 SB base address, unused. +-IO 1 0x0530 - 0x0F48 MSS base address +-IO 2 0x0388 - 0x03F8 OPL3 base address +-IO 3 0x0300 - 0x0334 MPU base address +-IO 4 0x0100 - 0x0FFE card's own base address for its control I/O ports +- +-The IRQ and DMA values can be any that are considered acceptable for a +-MSS. Assuming you've got isapnp all happy, then you should be able to +-do something like the following (which matches up with the isapnp +-configuration above): +- +-modprobe mpu401 +-modprobe ad1848 +-modprobe opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=5 dma=0 dma2=1 +-modprobe opl3 io=0x388 +- +-See the section "Automatic Module Loading" below for how to set up +-/etc/modprobe.conf to automate this. +- +-An important thing to remember that the opl3sa2 module's io argument is +-for it's own control port, which handles the card's master mixer for +-volume (on all cards), and bass and treble (on SA3 cards). +- +- +-Troubleshooting +---------------- +- +-If all goes well and you see no error messages, you should be able to +-start using the sound capabilities of your system. If you get an +-error message while trying to insert the opl3sa2 module, then make +-sure that the values of the various arguments match what you specified +-in your isapnp configuration file, and that there is no conflict with +-another device for an I/O port or interrupt. Checking the contents of +-/proc/ioports and /proc/interrupts can be useful to see if you're +-butting heads with another device. +- +-If you still cannot get the module to load, look at the contents of +-your system log file, usually /var/log/messages. If you see the +-message "opl3sa2: Unknown Yamaha audio controller version", then you +-have a different chipset version than I've encountered so far. Look +-for all messages in the log file that start with "opl3sa2: " and see +-if they provide any clues. If you do not see the chipset version +-message, and none of the other messages present in the system log are +-helpful, email me some details and I'll try my best to help. +- +- +-Automatic Module Loading +------------------------- +- +-Lastly, if you're using modules and want to set up automatic module +-loading with kmod, the kernel module loader, here is the section I +-currently use in my modprobe.conf file: +- +-# Sound +-alias sound-slot-0 opl3sa2 +-options opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=7 dma=0 dma2=3 +-options opl3 io=0x388 +- +-That's all it currently takes to get an OPL3-SA3 card working on my +-system. Once again, if you have any other problems, email me at the +-address listed above. +- +-Scott +diff -Nurp linux-2.6.22/Documentation/sound/oss/VIA-chipset linux-2.6-netns/Documentation/sound/oss/VIA-chipset +--- linux-2.6.22/Documentation/sound/oss/VIA-chipset 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/sound/oss/VIA-chipset 1969-12-31 19:00:00.000000000 -0500 +@@ -1,43 +0,0 @@ +-Running sound cards on VIA chipsets +- +-o There are problems with VIA chipsets and sound cards that appear to +- lock the hardware solidly. Test programs under DOS have verified the +- problem exists on at least some (but apparently not all) VIA boards +- +-o VIA have so far failed to bother to answer support mail on the subject +- so if you are a VIA engineer feeling aggrieved as you read this +- document go chase your own people. If there is a workaround please +- let us know so we can implement it. +- +- +-Certain patterns of ISA DMA access used for most PC sound cards cause the +-VIA chipsets to lock up. From the collected reports this appears to cover a +-wide range of boards. Some also lock up with sound cards under Win* as well. +- +-Linux implements a workaround providing your chipset is PCI and you compiled +-with PCI Quirks enabled. If so you will see a message +- "Activating ISA DMA bug workarounds" +- +-during booting. If you have a VIA PCI chipset that hangs when you use the +-sound and is not generating this message even with PCI quirks enabled +-please report the information to the linux-kernel list (see REPORTING-BUGS). +- +-If you are one of the tiny number of unfortunates with a 486 ISA/VLB VIA +-chipset board you need to do the following to build a special kernel for +-your board +- +- edit linux/include/asm-i386/dma.h +- +-change +- +-#define isa_dma_bridge_buggy (0) +- +-to +- +-#define isa_dma_bridge_buggy (1) +- +-and rebuild a kernel without PCI quirk support. +- +- +-Other than this particular glitch the VIA [M]VP* chipsets appear to work +-perfectly with Linux. +diff -Nurp linux-2.6.22/Documentation/sound/oss/cs46xx linux-2.6-netns/Documentation/sound/oss/cs46xx +--- linux-2.6.22/Documentation/sound/oss/cs46xx 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/sound/oss/cs46xx 1969-12-31 19:00:00.000000000 -0500 +@@ -1,138 +0,0 @@ +- +-Documentation for the Cirrus Logic/Crystal SoundFusion cs46xx/cs4280 audio +-controller chips (2001/05/11) +- +-The cs46xx audio driver supports the DSP line of Cirrus controllers. +-Specifically, the cs4610, cs4612, cs4614, cs4622, cs4624, cs4630 and the cs4280 +-products. This driver uses the generic ac97_codec driver for AC97 codec +-support. +- +- +-Features: +- +-Full Duplex Playback/Capture supported from 8k-48k. +-16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported. +- +-APM/PM - 2.2.x PM is enabled and functional. APM can also +-be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro +-definition. +- +-DMA playback buffer size is configurable from 16k (defaultorder=2) up to 2Meg +-(defaultorder=11). DMA capture buffer size is fixed at a single 4k page as +-two 2k fragments. +- +-MMAP seems to work well with QuakeIII, and test XMMS plugin. +- +-Myth2 works, but the polling logic is not fully correct, but is functional. +- +-The 2.4.4-ac6 gameport code in the cs461x joystick driver has been tested +-with a Microsoft Sidewinder joystick (cs461x.o and sidewinder.o). This +-audio driver must be loaded prior to the joystick driver to enable the +-DSP task image supporting the joystick device. +- +- +-Limitations: +- +-SPDIF is currently not supported. +- +-Primary codec support only. No secondary codec support is implemented. +- +- +- +-NOTES: +- +-Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp, +-and has been tested. +-Module parameter hercules_egpio_disable set to 1, will force a 0 to EGPIODR +-to disable the external amplifier. +- +-VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control +-the external amplifier for the "back" speakers, since we do not +-support the secondary codec then this external amp is not +-turned on. The primary codec external amplifier is supported but +-note that the AC97 EAPD bit is inverted logic (amp_voyetra()). +- +-DMA buffer size - there are issues with many of the Linux applications +-concerning the optimal buffer size. Several applications request a +-certain fragment size and number and then do not verify that the driver +-has the ability to support the requested configuration. +-SNDCTL_DSP_SETFRAGMENT ioctl is used to request a fragment size and +-number of fragments. Some applications exit if an error is returned +-on this particular ioctl. Therefore, in alignment with the other OSS audio +-drivers, no error is returned when a SETFRAGs IOCTL is received, but the +-values passed from the app are not used in any buffer calculation +-(ossfragshift/ossmaxfrags are not used). +-Use the "defaultorder=N" module parameter to change the buffer size if +-you have an application that requires a specific number of fragments +-or a specific buffer size (see below). +- +-Debug Interface +---------------- +-There is an ioctl debug interface to allow runtime modification of the +-debug print levels. This debug interface code can be disabled from the +-compilation process with commenting the following define: +-#define CSDEBUG_INTERFACE 1 +-There is also a debug print methodolgy to select printf statements from +-different areas of the driver. A debug print level is also used to allow +-additional printfs to be active. Comment out the following line in the +-driver to disable compilation of the CS_DBGOUT print statements: +-#define CSDEBUG 1 +- +-Please see the definitions for cs_debuglevel and cs_debugmask for additional +-information on the debug levels and sections. +- +-There is also a csdbg executable to allow runtime manipulation of these +-parameters. for a copy email: twoller@crystal.cirrus.com +- +- +- +-MODULE_PARMS definitions +------------------------- +-module_param(defaultorder, ulong, 0); +-defaultorder=N +-where N is a value from 1 to 12 +-The buffer order determines the size of the dma buffer for the driver. +-under Linux, a smaller buffer allows more responsiveness from many of the +-applications (e.g. games). A larger buffer allows some of the apps (esound) +-to not underrun the dma buffer as easily. As default, use 32k (order=3) +-rather than 64k as some of the games work more responsively. +-(2^N) * PAGE_SIZE = allocated buffer size +- +-module_param(cs_debuglevel, ulong, 0644); +-module_param(cs_debugmask, ulong, 0644); +-cs_debuglevel=N +-cs_debugmask=0xMMMMMMMM +-where N is a value from 0 (no debug printfs), to 9 (maximum) +-0xMMMMMMMM is a debug mask corresponding to the CS_xxx bits (see driver source). +- +-module_param(hercules_egpio_disable, ulong, 0); +-hercules_egpio_disable=N +-where N is a 0 (enable egpio), or a 1 (disable egpio support) +- +-module_param(initdelay, ulong, 0); +-initdelay=N +-This value is used to determine the millescond delay during the initialization +-code prior to powering up the PLL. On laptops this value can be used to +-assist with errors on resume, mostly with IBM laptops. Basically, if the +-system is booted under battery power then the mdelay()/udelay() functions fail to +-properly delay the required time. Also, if the system is booted under AC power +-and then the power removed, the mdelay()/udelay() functions will not delay properly. +- +-module_param(powerdown, ulong, 0); +-powerdown=N +-where N is 0 (disable any powerdown of the internal blocks) or 1 (enable powerdown) +- +- +-module_param(external_amp, bool, 0); +-external_amp=1 +-if N is set to 1, then force enabling the EAPD support in the primary AC97 codec. +-override the detection logic and force the external amp bit in the AC97 0x26 register +-to be reset (0). EAPD should be 0 for powerup, and 1 for powerdown. The VTB Santa Cruz +-card has inverted logic, so there is a special function for these cards. +- +-module_param(thinkpad, bool, 0); +-thinkpad=1 +-if N is set to 1, then force enabling the clkrun functionality. +-Currently, when the part is being used, then clkrun is disabled for the entire system, +-but re-enabled when the driver is released or there is no outstanding open count. +- +diff -Nurp linux-2.6.22/Documentation/spi/spi-lm70llp linux-2.6-netns/Documentation/spi/spi-lm70llp +--- linux-2.6.22/Documentation/spi/spi-lm70llp 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/spi/spi-lm70llp 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,69 @@ ++spi_lm70llp : LM70-LLP parport-to-SPI adapter ++============================================== ++ ++Supported board/chip: ++ * National Semiconductor LM70 LLP evaluation board ++ Datasheet: http://www.national.com/pf/LM/LM70.html ++ ++Author: ++ Kaiwan N Billimoria ++ ++Description ++----------- ++This driver provides glue code connecting a National Semiconductor LM70 LLP ++temperature sensor evaluation board to the kernel's SPI core subsystem. ++ ++In effect, this driver turns the parallel port interface on the eval board ++into a SPI bus with a single device, which will be driven by the generic ++LM70 driver (drivers/hwmon/lm70.c). ++ ++The hardware interfacing on the LM70 LLP eval board is as follows: ++ ++ Parallel LM70 LLP ++ Port Direction JP2 Header ++ ----------- --------- ---------------- ++ D0 2 - - ++ D1 3 --> V+ 5 ++ D2 4 --> V+ 5 ++ D3 5 --> V+ 5 ++ D4 6 --> V+ 5 ++ D5 7 --> nCS 8 ++ D6 8 --> SCLK 3 ++ D7 9 --> SI/O 5 ++ GND 25 - GND 7 ++ Select 13 <-- SI/O 1 ++ ----------- --------- ---------------- ++ ++Note that since the LM70 uses a "3-wire" variant of SPI, the SI/SO pin ++is connected to both pin D7 (as Master Out) and Select (as Master In) ++using an arrangment that lets either the parport or the LM70 pull the ++pin low. This can't be shared with true SPI devices, but other 3-wire ++devices might share the same SI/SO pin. ++ ++The bitbanger routine in this driver (lm70_txrx) is called back from ++the bound "hwmon/lm70" protocol driver through its sysfs hook, using a ++spi_write_then_read() call. It performs Mode 0 (SPI/Microwire) bitbanging. ++The lm70 driver then inteprets the resulting digital temperature value ++and exports it through sysfs. ++ ++A "gotcha": National Semiconductor's LM70 LLP eval board circuit schematic ++shows that the SI/O line from the LM70 chip is connected to the base of a ++transistor Q1 (and also a pullup, and a zener diode to D7); while the ++collector is tied to VCC. ++ ++Interpreting this circuit, when the LM70 SI/O line is High (or tristate ++and not grounded by the host via D7), the transistor conducts and switches ++the collector to zero, which is reflected on pin 13 of the DB25 parport ++connector. When SI/O is Low (driven by the LM70 or the host) on the other ++hand, the transistor is cut off and the voltage tied to it's collector is ++reflected on pin 13 as a High level. ++ ++So: the getmiso inline routine in this driver takes this fact into account, ++inverting the value read at pin 13. ++ ++ ++Thanks to ++--------- ++o David Brownell for mentoring the SPI-side driver development. ++o Dr.Craig Hollabaugh for the (early) "manual" bitbanging driver version. ++o Nadir Billimoria for help interpreting the circuit schematic. +diff -Nurp linux-2.6.22/Documentation/spinlocks.txt linux-2.6-netns/Documentation/spinlocks.txt +--- linux-2.6.22/Documentation/spinlocks.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/spinlocks.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -1,7 +1,12 @@ +-UPDATE March 21 2005 Amit Gud ++SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED defeat lockdep state tracking and ++are hence deprecated. + +-Macros SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED are deprecated and will be +-removed soon. So for any new code dynamic initialization should be used: ++Please use DEFINE_SPINLOCK()/DEFINE_RWLOCK() or ++__SPIN_LOCK_UNLOCKED()/__RW_LOCK_UNLOCKED() as appropriate for static ++initialization. ++ ++Dynamic initialization, when necessary, may be performed as ++demonstrated below. + + spinlock_t xxx_lock; + rwlock_t xxx_rw_lock; +@@ -15,12 +20,9 @@ removed soon. So for any new code dynami + + module_init(xxx_init); + +-Reasons for deprecation +- - it hurts automatic lock validators +- - it becomes intrusive for the realtime preemption patches +- +-Following discussion is still valid, however, with the dynamic initialization +-of spinlocks instead of static. ++The following discussion is still valid, however, with the dynamic ++initialization of spinlocks or with DEFINE_SPINLOCK, etc., used ++instead of SPIN_LOCK_UNLOCKED. + + ----------------------- + +diff -Nurp linux-2.6.22/Documentation/sysctl/ctl_unnumbered.txt linux-2.6-netns/Documentation/sysctl/ctl_unnumbered.txt +--- linux-2.6.22/Documentation/sysctl/ctl_unnumbered.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/sysctl/ctl_unnumbered.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,22 @@ ++ ++Except for a few extremely rare exceptions user space applications do not use ++the binary sysctl interface. Instead everyone uses /proc/sys/... with ++readable ascii names. ++ ++Recently the kernel has started supporting setting the binary sysctl value to ++CTL_UNNUMBERED so we no longer need to assign a binary sysctl path to allow ++sysctls to show up in /proc/sys. ++ ++Assigning binary sysctl numbers is an endless source of conflicts in sysctl.h, ++breaking of the user space ABI (because of those conflicts), and maintenance ++problems. A complete pass through all of the sysctl users revealed multiple ++instances where the sysctl binary interface was broken and had gone undetected ++for years. ++ ++So please do not add new binary sysctl numbers. They are unneeded and ++problematic. ++ ++If you really need a new binary sysctl number please first merge your sysctl ++into the kernel and then as a separate patch allocate a binary sysctl number. ++ ++(ebiederm@xmission.com, June 2007) +diff -Nurp linux-2.6.22/Documentation/sysctl/vm.txt linux-2.6-netns/Documentation/sysctl/vm.txt +--- linux-2.6.22/Documentation/sysctl/vm.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/sysctl/vm.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -31,12 +31,15 @@ Currently, these files are in /proc/sys/ + - min_unmapped_ratio + - min_slab_ratio + - panic_on_oom ++- mmap_min_address ++- numa_zonelist_order + + ============================================================== + + dirty_ratio, dirty_background_ratio, dirty_expire_centisecs, + dirty_writeback_centisecs, vfs_cache_pressure, laptop_mode, +-block_dump, swap_token_timeout, drop-caches: ++block_dump, swap_token_timeout, drop-caches, ++hugepages_treat_as_movable: + + See Documentation/filesystems/proc.txt + +@@ -216,3 +219,61 @@ above-mentioned. + The default value is 0. + 1 and 2 are for failover of clustering. Please select either + according to your policy of failover. ++ ++============================================================== ++ ++mmap_min_addr ++ ++This file indicates the amount of address space which a user process will ++be restricted from mmaping. Since kernel null dereference bugs could ++accidentally operate based on the information in the first couple of pages ++of memory userspace processes should not be allowed to write to them. By ++default this value is set to 0 and no protections will be enforced by the ++security module. Setting this value to something like 64k will allow the ++vast majority of applications to work correctly and provide defense in depth ++against future potential kernel bugs. ++ ++============================================================== ++ ++numa_zonelist_order ++ ++This sysctl is only for NUMA. ++'where the memory is allocated from' is controlled by zonelists. ++(This documentation ignores ZONE_HIGHMEM/ZONE_DMA32 for simple explanation. ++ you may be able to read ZONE_DMA as ZONE_DMA32...) ++ ++In non-NUMA case, a zonelist for GFP_KERNEL is ordered as following. ++ZONE_NORMAL -> ZONE_DMA ++This means that a memory allocation request for GFP_KERNEL will ++get memory from ZONE_DMA only when ZONE_NORMAL is not available. ++ ++In NUMA case, you can think of following 2 types of order. ++Assume 2 node NUMA and below is zonelist of Node(0)'s GFP_KERNEL ++ ++(A) Node(0) ZONE_NORMAL -> Node(0) ZONE_DMA -> Node(1) ZONE_NORMAL ++(B) Node(0) ZONE_NORMAL -> Node(1) ZONE_NORMAL -> Node(0) ZONE_DMA. ++ ++Type(A) offers the best locality for processes on Node(0), but ZONE_DMA ++will be used before ZONE_NORMAL exhaustion. This increases possibility of ++out-of-memory(OOM) of ZONE_DMA because ZONE_DMA is tend to be small. ++ ++Type(B) cannot offer the best locality but is more robust against OOM of ++the DMA zone. ++ ++Type(A) is called as "Node" order. Type (B) is "Zone" order. ++ ++"Node order" orders the zonelists by node, then by zone within each node. ++Specify "[Nn]ode" for zone order ++ ++"Zone Order" orders the zonelists by zone type, then by node within each ++zone. Specify "[Zz]one"for zode order. ++ ++Specify "[Dd]efault" to request automatic configuration. Autoconfiguration ++will select "node" order in following case. ++(1) if the DMA zone does not exist or ++(2) if the DMA zone comprises greater than 50% of the available memory or ++(3) if any node's DMA zone comprises greater than 60% of its local memory and ++ the amount of local memory is big enough. ++ ++Otherwise, "zone" order will be selected. Default order is recommended unless ++this is causing problems for your system/application. +diff -Nurp linux-2.6.22/Documentation/sysfs-rules.txt linux-2.6-netns/Documentation/sysfs-rules.txt +--- linux-2.6.22/Documentation/sysfs-rules.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/sysfs-rules.txt 2007-12-03 23:14:12.000000000 -0500 +@@ -0,0 +1,166 @@ ++Rules on how to access information in the Linux kernel sysfs ++ ++The kernel exported sysfs exports internal kernel implementation-details ++and depends on internal kernel structures and layout. It is agreed upon ++by the kernel developers that the Linux kernel does not provide a stable ++internal API. As sysfs is a direct export of kernel internal ++structures, the sysfs interface can not provide a stable interface eighter, ++it may always change along with internal kernel changes. ++ ++To minimize the risk of breaking users of sysfs, which are in most cases ++low-level userspace applications, with a new kernel release, the users ++of sysfs must follow some rules to use an as abstract-as-possible way to ++access this filesystem. The current udev and HAL programs already ++implement this and users are encouraged to plug, if possible, into the ++abstractions these programs provide instead of accessing sysfs ++directly. ++ ++But if you really do want or need to access sysfs directly, please follow ++the following rules and then your programs should work with future ++versions of the sysfs interface. ++ ++- Do not use libsysfs ++ It makes assumptions about sysfs which are not true. Its API does not ++ offer any abstraction, it exposes all the kernel driver-core ++ implementation details in its own API. Therefore it is not better than ++ reading directories and opening the files yourself. ++ Also, it is not actively maintained, in the sense of reflecting the ++ current kernel-development. The goal of providing a stable interface ++ to sysfs has failed, it causes more problems, than it solves. It ++ violates many of the rules in this document. ++ ++- sysfs is always at /sys ++ Parsing /proc/mounts is a waste of time. Other mount points are a ++ system configuration bug you should not try to solve. For test cases, ++ possibly support a SYSFS_PATH environment variable to overwrite the ++ applications behavior, but never try to search for sysfs. Never try ++ to mount it, if you are not an early boot script. ++ ++- devices are only "devices" ++ There is no such thing like class-, bus-, physical devices, ++ interfaces, and such that you can rely on in userspace. Everything is ++ just simply a "device". Class-, bus-, physical, ... types are just ++ kernel implementation details, which should not be expected by ++ applications that look for devices in sysfs. ++ ++ The properties of a device are: ++ o devpath (/devices/pci0000:00/0000:00:1d.1/usb2/2-2/2-2:1.0) ++ - identical to the DEVPATH value in the event sent from the kernel ++ at device creation and removal ++ - the unique key to the device at that point in time ++ - the kernels path to the device-directory without the leading ++ /sys, and always starting with with a slash ++ - all elements of a devpath must be real directories. Symlinks ++ pointing to /sys/devices must always be resolved to their real ++ target, and the target path must be used to access the device. ++ That way the devpath to the device matches the devpath of the ++ kernel used at event time. ++ - using or exposing symlink values as elements in a devpath string ++ is a bug in the application ++ ++ o kernel name (sda, tty, 0000:00:1f.2, ...) ++ - a directory name, identical to the last element of the devpath ++ - applications need to handle spaces and characters like '!' in ++ the name ++ ++ o subsystem (block, tty, pci, ...) ++ - simple string, never a path or a link ++ - retrieved by reading the "subsystem"-link and using only the ++ last element of the target path ++ ++ o driver (tg3, ata_piix, uhci_hcd) ++ - a simple string, which may contain spaces, never a path or a ++ link ++ - it is retrieved by reading the "driver"-link and using only the ++ last element of the target path ++ - devices which do not have "driver"-link, just do not have a ++ driver; copying the driver value in a child device context, is a ++ bug in the application ++ ++ o attributes ++ - the files in the device directory or files below a subdirectories ++ of the same device directory ++ - accessing attributes reached by a symlink pointing to another device, ++ like the "device"-link, is a bug in the application ++ ++ Everything else is just a kernel driver-core implementation detail, ++ that should not be assumed to be stable across kernel releases. ++ ++- Properties of parent devices never belong into a child device. ++ Always look at the parent devices themselves for determining device ++ context properties. If the device 'eth0' or 'sda' does not have a ++ "driver"-link, then this device does not have a driver. Its value is empty. ++ Never copy any property of the parent-device into a child-device. Parent ++ device-properties may change dynamically without any notice to the ++ child device. ++ ++- Hierarchy in a single device-tree ++ There is only one valid place in sysfs where hierarchy can be examined ++ and this is below: /sys/devices. ++ It is planned, that all device directories will end up in the tree ++ below this directory. ++ ++- Classification by subsystem ++ There are currently three places for classification of devices: ++ /sys/block, /sys/class and /sys/bus. It is planned that these will ++ not contain any device-directories themselves, but only flat lists of ++ symlinks pointing to the unified /sys/devices tree. ++ All three places have completely different rules on how to access ++ device information. It is planned to merge all three ++ classification-directories into one place at /sys/subsystem, ++ following the layout of the bus-directories. All buses and ++ classes, including the converted block-subsystem, will show up ++ there. ++ The devices belonging to a subsystem will create a symlink in the ++ "devices" directory at /sys/subsystem//devices. ++ ++ If /sys/subsystem exists, /sys/bus, /sys/class and /sys/block can be ++ ignored. If it does not exist, you have always to scan all three ++ places, as the kernel is free to move a subsystem from one place to ++ the other, as long as the devices are still reachable by the same ++ subsystem name. ++ ++ Assuming /sys/class/ and /sys/bus/, or ++ /sys/block and /sys/class/block are not interchangeable, is a bug in ++ the application. ++ ++- Block ++ The converted block-subsystem at /sys/class/block, or ++ /sys/subsystem/block will contain the links for disks and partitions ++ at the same level, never in a hierarchy. Assuming the block-subsytem to ++ contain only disks and not partition-devices in the same flat list is ++ a bug in the application. ++ ++- "device"-link and :-links ++ Never depend on the "device"-link. The "device"-link is a workaround ++ for the old layout, where class-devices are not created in ++ /sys/devices/ like the bus-devices. If the link-resolving of a ++ device-directory does not end in /sys/devices/, you can use the ++ "device"-link to find the parent devices in /sys/devices/. That is the ++ single valid use of the "device"-link, it must never appear in any ++ path as an element. Assuming the existence of the "device"-link for ++ a device in /sys/devices/ is a bug in the application. ++ Accessing /sys/class/net/eth0/device is a bug in the application. ++ ++ Never depend on the class-specific links back to the /sys/class ++ directory. These links are also a workaround for the design mistake ++ that class-devices are not created in /sys/devices. If a device ++ directory does not contain directories for child devices, these links ++ may be used to find the child devices in /sys/class. That is the single ++ valid use of these links, they must never appear in any path as an ++ element. Assuming the existence of these links for devices which are ++ real child device directories in the /sys/devices tree, is a bug in ++ the application. ++ ++ It is planned to remove all these links when when all class-device ++ directories live in /sys/devices. ++ ++- Position of devices along device chain can change. ++ Never depend on a specific parent device position in the devpath, ++ or the chain of parent devices. The kernel is free to insert devices into ++ the chain. You must always request the parent device you are looking for ++ by its subsystem value. You need to walk up the chain until you find ++ the device that matches the expected subsystem. Depending on a specific ++ position of a parent device, or exposing relative paths, using "../" to ++ access the chain of parents, is a bug in the application. ++ +diff -Nurp linux-2.6.22/Documentation/usb/dma.txt linux-2.6-netns/Documentation/usb/dma.txt +--- linux-2.6.22/Documentation/usb/dma.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/usb/dma.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -32,12 +32,15 @@ ELIMINATING COPIES + It's good to avoid making CPUs copy data needlessly. The costs can add up, + and effects like cache-trashing can impose subtle penalties. + +-- When you're allocating a buffer for DMA purposes anyway, use the buffer +- primitives. Think of them as kmalloc and kfree that give you the right +- kind of addresses to store in urb->transfer_buffer and urb->transfer_dma, +- while guaranteeing that no hidden copies through DMA "bounce" buffers will +- slow things down. You'd also set URB_NO_TRANSFER_DMA_MAP in +- urb->transfer_flags: ++- If you're doing lots of small data transfers from the same buffer all ++ the time, that can really burn up resources on systems which use an ++ IOMMU to manage the DMA mappings. It can cost MUCH more to set up and ++ tear down the IOMMU mappings with each request than perform the I/O! ++ ++ For those specific cases, USB has primitives to allocate less expensive ++ memory. They work like kmalloc and kfree versions that give you the right ++ kind of addresses to store in urb->transfer_buffer and urb->transfer_dma. ++ You'd also set URB_NO_TRANSFER_DMA_MAP in urb->transfer_flags: + + void *usb_buffer_alloc (struct usb_device *dev, size_t size, + int mem_flags, dma_addr_t *dma); +@@ -45,6 +48,10 @@ and effects like cache-trashing can impo + void usb_buffer_free (struct usb_device *dev, size_t size, + void *addr, dma_addr_t dma); + ++ Most drivers should *NOT* be using these primitives; they don't need ++ to use this type of memory ("dma-coherent"), and memory returned from ++ kmalloc() will work just fine. ++ + For control transfers you can use the buffer primitives or not for each + of the transfer buffer and setup buffer independently. Set the flag bits + URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP to indicate which +@@ -54,29 +61,39 @@ and effects like cache-trashing can impo + The memory buffer returned is "dma-coherent"; sometimes you might need to + force a consistent memory access ordering by using memory barriers. It's + not using a streaming DMA mapping, so it's good for small transfers on +- systems where the I/O would otherwise tie up an IOMMU mapping. (See ++ systems where the I/O would otherwise thrash an IOMMU mapping. (See + Documentation/DMA-mapping.txt for definitions of "coherent" and "streaming" + DMA mappings.) + + Asking for 1/Nth of a page (as well as asking for N pages) is reasonably + space-efficient. + +-- Devices on some EHCI controllers could handle DMA to/from high memory. +- Driver probe() routines can notice this using a generic DMA call, then +- tell higher level code (network, scsi, etc) about it like this: ++ On most systems the memory returned will be uncached, because the ++ semantics of dma-coherent memory require either bypassing CPU caches ++ or using cache hardware with bus-snooping support. While x86 hardware ++ has such bus-snooping, many other systems use software to flush cache ++ lines to prevent DMA conflicts. + +- if (dma_supported (&intf->dev, 0xffffffffffffffffULL)) +- net->features |= NETIF_F_HIGHDMA; ++- Devices on some EHCI controllers could handle DMA to/from high memory. + +- That can eliminate dma bounce buffering of requests that originate (or +- terminate) in high memory, in cases where the buffers aren't allocated +- with usb_buffer_alloc() but instead are dma-mapped. ++ Unfortunately, the current Linux DMA infrastructure doesn't have a sane ++ way to expose these capabilities ... and in any case, HIGHMEM is mostly a ++ design wart specific to x86_32. So your best bet is to ensure you never ++ pass a highmem buffer into a USB driver. That's easy; it's the default ++ behavior. Just don't override it; e.g. with NETIF_F_HIGHDMA. ++ ++ This may force your callers to do some bounce buffering, copying from ++ high memory to "normal" DMA memory. If you can come up with a good way ++ to fix this issue (for x86_32 machines with over 1 GByte of memory), ++ feel free to submit patches. + + + WORKING WITH EXISTING BUFFERS + + Existing buffers aren't usable for DMA without first being mapped into the +-DMA address space of the device. ++DMA address space of the device. However, most buffers passed to your ++driver can safely be used with such DMA mapping. (See the first section ++of DMA-mapping.txt, titled "What memory is DMA-able?") + + - When you're using scatterlists, you can map everything at once. On some + systems, this kicks in an IOMMU and turns the scatterlists into single +@@ -114,3 +131,8 @@ DMA address space of the device. + The calls manage urb->transfer_dma for you, and set URB_NO_TRANSFER_DMA_MAP + so that usbcore won't map or unmap the buffer. The same goes for + urb->setup_dma and URB_NO_SETUP_DMA_MAP for control requests. ++ ++Note that several of those interfaces are currently commented out, since ++they don't have current users. See the source code. Other than the dmasync ++calls (where the underlying DMA primitives have changed), most of them can ++easily be commented back in if you want to use them. +diff -Nurp linux-2.6.22/Documentation/usb/persist.txt linux-2.6-netns/Documentation/usb/persist.txt +--- linux-2.6.22/Documentation/usb/persist.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/usb/persist.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,156 @@ ++ USB device persistence during system suspend ++ ++ Alan Stern ++ ++ September 2, 2006 (Updated May 29, 2007) ++ ++ ++ What is the problem? ++ ++According to the USB specification, when a USB bus is suspended the ++bus must continue to supply suspend current (around 1-5 mA). This ++is so that devices can maintain their internal state and hubs can ++detect connect-change events (devices being plugged in or unplugged). ++The technical term is "power session". ++ ++If a USB device's power session is interrupted then the system is ++required to behave as though the device has been unplugged. It's a ++conservative approach; in the absence of suspend current the computer ++has no way to know what has actually happened. Perhaps the same ++device is still attached or perhaps it was removed and a different ++device plugged into the port. The system must assume the worst. ++ ++By default, Linux behaves according to the spec. If a USB host ++controller loses power during a system suspend, then when the system ++wakes up all the devices attached to that controller are treated as ++though they had disconnected. This is always safe and it is the ++"officially correct" thing to do. ++ ++For many sorts of devices this behavior doesn't matter in the least. ++If the kernel wants to believe that your USB keyboard was unplugged ++while the system was asleep and a new keyboard was plugged in when the ++system woke up, who cares? It'll still work the same when you type on ++it. ++ ++Unfortunately problems _can_ arise, particularly with mass-storage ++devices. The effect is exactly the same as if the device really had ++been unplugged while the system was suspended. If you had a mounted ++filesystem on the device, you're out of luck -- everything in that ++filesystem is now inaccessible. This is especially annoying if your ++root filesystem was located on the device, since your system will ++instantly crash. ++ ++Loss of power isn't the only mechanism to worry about. Anything that ++interrupts a power session will have the same effect. For example, ++even though suspend current may have been maintained while the system ++was asleep, on many systems during the initial stages of wakeup the ++firmware (i.e., the BIOS) resets the motherboard's USB host ++controllers. Result: all the power sessions are destroyed and again ++it's as though you had unplugged all the USB devices. Yes, it's ++entirely the BIOS's fault, but that doesn't do _you_ any good unless ++you can convince the BIOS supplier to fix the problem (lots of luck!). ++ ++On many systems the USB host controllers will get reset after a ++suspend-to-RAM. On almost all systems, no suspend current is ++available during hibernation (also known as swsusp or suspend-to-disk). ++You can check the kernel log after resuming to see if either of these ++has happened; look for lines saying "root hub lost power or was reset". ++ ++In practice, people are forced to unmount any filesystems on a USB ++device before suspending. If the root filesystem is on a USB device, ++the system can't be suspended at all. (All right, it _can_ be ++suspended -- but it will crash as soon as it wakes up, which isn't ++much better.) ++ ++ ++ What is the solution? ++ ++Setting CONFIG_USB_PERSIST will cause the kernel to work around these ++issues. It enables a mode in which the core USB device data ++structures are allowed to persist across a power-session disruption. ++It works like this. If the kernel sees that a USB host controller is ++not in the expected state during resume (i.e., if the controller was ++reset or otherwise had lost power) then it applies a persistence check ++to each of the USB devices below that controller for which the ++"persist" attribute is set. It doesn't try to resume the device; that ++can't work once the power session is gone. Instead it issues a USB ++port reset and then re-enumerates the device. (This is exactly the ++same thing that happens whenever a USB device is reset.) If the ++re-enumeration shows that the device now attached to that port has the ++same descriptors as before, including the Vendor and Product IDs, then ++the kernel continues to use the same device structure. In effect, the ++kernel treats the device as though it had merely been reset instead of ++unplugged. ++ ++If no device is now attached to the port, or if the descriptors are ++different from what the kernel remembers, then the treatment is what ++you would expect. The kernel destroys the old device structure and ++behaves as though the old device had been unplugged and a new device ++plugged in, just as it would without the CONFIG_USB_PERSIST option. ++ ++The end result is that the USB device remains available and usable. ++Filesystem mounts and memory mappings are unaffected, and the world is ++now a good and happy place. ++ ++Note that even when CONFIG_USB_PERSIST is set, the "persist" feature ++will be applied only to those devices for which it is enabled. You ++can enable the feature by doing (as root): ++ ++ echo 1 >/sys/bus/usb/devices/.../power/persist ++ ++where the "..." should be filled in the with the device's ID. Disable ++the feature by writing 0 instead of 1. For hubs the feature is ++automatically and permanently enabled, so you only have to worry about ++setting it for devices where it really matters. ++ ++ ++ Is this the best solution? ++ ++Perhaps not. Arguably, keeping track of mounted filesystems and ++memory mappings across device disconnects should be handled by a ++centralized Logical Volume Manager. Such a solution would allow you ++to plug in a USB flash device, create a persistent volume associated ++with it, unplug the flash device, plug it back in later, and still ++have the same persistent volume associated with the device. As such ++it would be more far-reaching than CONFIG_USB_PERSIST. ++ ++On the other hand, writing a persistent volume manager would be a big ++job and using it would require significant input from the user. This ++solution is much quicker and easier -- and it exists now, a giant ++point in its favor! ++ ++Furthermore, the USB_PERSIST option applies to _all_ USB devices, not ++just mass-storage devices. It might turn out to be equally useful for ++other device types, such as network interfaces. ++ ++ ++ WARNING: Using CONFIG_USB_PERSIST can be dangerous!! ++ ++When recovering an interrupted power session the kernel does its best ++to make sure the USB device hasn't been changed; that is, the same ++device is still plugged into the port as before. But the checks ++aren't guaranteed to be 100% accurate. ++ ++If you replace one USB device with another of the same type (same ++manufacturer, same IDs, and so on) there's an excellent chance the ++kernel won't detect the change. Serial numbers and other strings are ++not compared. In many cases it wouldn't help if they were, because ++manufacturers frequently omit serial numbers entirely in their ++devices. ++ ++Furthermore it's quite possible to leave a USB device exactly the same ++while changing its media. If you replace the flash memory card in a ++USB card reader while the system is asleep, the kernel will have no ++way to know you did it. The kernel will assume that nothing has ++happened and will continue to use the partition tables, inodes, and ++memory mappings for the old card. ++ ++If the kernel gets fooled in this way, it's almost certain to cause ++data corruption and to crash your system. You'll have no one to blame ++but yourself. ++ ++YOU HAVE BEEN WARNED! USE AT YOUR OWN RISK! ++ ++That having been said, most of the time there shouldn't be any trouble ++at all. The "persist" feature can be extremely useful. Make the most ++of it. +diff -Nurp linux-2.6.22/Documentation/video4linux/CARDLIST.bttv linux-2.6-netns/Documentation/video4linux/CARDLIST.bttv +--- linux-2.6.22/Documentation/video4linux/CARDLIST.bttv 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/video4linux/CARDLIST.bttv 2007-12-03 23:14:12.000000000 -0500 +@@ -66,7 +66,7 @@ + 65 -> Lifeview FlyVideo 2000S LR90 + 66 -> Terratec TValueRadio [153b:1135,153b:ff3b] + 67 -> IODATA GV-BCTV4/PCI [10fc:4050] +- 68 -> 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA) [121a:3000,10b4:2637] ++ 68 -> 3Dfx VoodooTV FM (Euro) [10b4:2637] + 69 -> Active Imaging AIMMS + 70 -> Prolink Pixelview PV-BT878P+ (Rev.4C,8E) + 71 -> Lifeview FlyVideo 98EZ (capture only) LR51 [1851:1851] +@@ -145,3 +145,5 @@ + 144 -> MagicTV + 145 -> SSAI Security Video Interface [4149:5353] + 146 -> SSAI Ultrasound Video Interface [414a:5353] ++147 -> VoodooTV 200 (USA) [121a:3000] ++148 -> DViCO FusionHDTV 2 [dbc0:d200] +diff -Nurp linux-2.6.22/Documentation/video4linux/CARDLIST.cx88 linux-2.6-netns/Documentation/video4linux/CARDLIST.cx88 +--- linux-2.6.22/Documentation/video4linux/CARDLIST.cx88 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/video4linux/CARDLIST.cx88 2007-12-03 23:06:33.000000000 -0500 +@@ -55,3 +55,4 @@ + 54 -> Norwood Micro TV Tuner + 55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM [c180:c980] + 56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder [0070:9600,0070:9601,0070:9602] ++ 57 -> ADS Tech Instant Video PCI [1421:0390] +diff -Nurp linux-2.6.22/Documentation/video4linux/CARDLIST.saa7134 linux-2.6-netns/Documentation/video4linux/CARDLIST.saa7134 +--- linux-2.6.22/Documentation/video4linux/CARDLIST.saa7134 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/video4linux/CARDLIST.saa7134 2007-12-03 23:14:12.000000000 -0500 +@@ -114,3 +114,4 @@ + 113 -> Elitegroup ECS TVP3XP FM1246 Tuner Card (PAL,FM) [1019:4cb6] + 114 -> KWorld DVB-T 210 [17de:7250] + 115 -> Sabrent PCMCIA TV-PCB05 [0919:2003] ++116 -> 10MOONS TM300 TV Card [1131:2304] +diff -Nurp linux-2.6.22/Documentation/video4linux/CARDLIST.tuner linux-2.6-netns/Documentation/video4linux/CARDLIST.tuner +--- linux-2.6.22/Documentation/video4linux/CARDLIST.tuner 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/video4linux/CARDLIST.tuner 2007-12-03 23:06:33.000000000 -0500 +@@ -40,7 +40,7 @@ tuner=38 - Philips PAL/SECAM multi (FM12 + tuner=39 - LG NTSC (newer TAPC series) + tuner=40 - HITACHI V7-J180AT + tuner=41 - Philips PAL_MK (FI1216 MK) +-tuner=42 - Philips 1236D ATSC/NTSC dual in ++tuner=42 - Philips FCV1236D ATSC/NTSC dual in + tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F) + tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant) + tuner=45 - Microtune 4049 FM5 +@@ -72,3 +72,4 @@ tuner=70 - Samsung TCPN 2121P30A + tuner=71 - Xceive xc3028 + tuner=72 - Thomson FE6600 + tuner=73 - Samsung TCPG 6121P30A ++tuner=75 - Philips TEA5761 FM Radio +diff -Nurp linux-2.6.22/Documentation/video4linux/sn9c102.txt linux-2.6-netns/Documentation/video4linux/sn9c102.txt +--- linux-2.6.22/Documentation/video4linux/sn9c102.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/video4linux/sn9c102.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -436,7 +436,7 @@ HV7131D Hynix Semiconductor | Yes + HV7131R Hynix Semiconductor | No Yes Yes Yes + MI-0343 Micron Technology | Yes No No No + MI-0360 Micron Technology | No Yes Yes Yes +-OV7630 OmniVision Technologies | Yes Yes No No ++OV7630 OmniVision Technologies | Yes Yes Yes Yes + OV7660 OmniVision Technologies | No No Yes Yes + PAS106B PixArt Imaging | Yes No No No + PAS202B PixArt Imaging | Yes Yes No No +@@ -583,6 +583,7 @@ order): + - Bertrik Sikken, who reverse-engineered and documented the Huffman compression + algorithm used in the SN9C101, SN9C102 and SN9C103 controllers and + implemented the first decoder; ++- Ronny Standke for the donation of a webcam; + - Mizuno Takafumi for the donation of a webcam; + - an "anonymous" donator (who didn't want his name to be revealed) for the + donation of a webcam. +diff -Nurp linux-2.6.22/Documentation/video4linux/zr364xx.txt linux-2.6-netns/Documentation/video4linux/zr364xx.txt +--- linux-2.6.22/Documentation/video4linux/zr364xx.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/video4linux/zr364xx.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -62,4 +62,4 @@ Vendor Product Distributor Model + 0x0784 0x0040 Traveler Slimline X5 + 0x06d6 0x0034 Trust Powerc@m 750 + 0x0a17 0x0062 Pentax Optio 50L +- ++0x06d6 0x003b Trust Powerc@m 970Z +diff -Nurp linux-2.6.22/Documentation/vm/hugetlbpage.txt linux-2.6-netns/Documentation/vm/hugetlbpage.txt +--- linux-2.6.22/Documentation/vm/hugetlbpage.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/vm/hugetlbpage.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -77,8 +77,9 @@ If the user applications are going to re + call, then it is required that system administrator mount a file system of + type hugetlbfs: + +- mount none /mnt/huge -t hugetlbfs +- ++ mount -t hugetlbfs \ ++ -o uid=,gid=,mode=,size=,nr_inodes= \ ++ none /mnt/huge + + This command mounts a (pseudo) filesystem of type hugetlbfs on the directory + /mnt/huge. Any files created on /mnt/huge uses hugepages. The uid and gid +@@ -88,11 +89,10 @@ mode of root of file system to value & 0 + By default the value 0755 is picked. The size option sets the maximum value of + memory (huge pages) allowed for that filesystem (/mnt/huge). The size is + rounded down to HPAGE_SIZE. The option nr_inodes sets the maximum number of +-inodes that /mnt/huge can use. If the size or nr_inodes options are not ++inodes that /mnt/huge can use. If the size or nr_inodes option is not + provided on command line then no limits are set. For size and nr_inodes + options, you can use [G|g]/[M|m]/[K|k] to represent giga/mega/kilo. For +-example, size=2K has the same meaning as size=2048. An example is given at +-the end of this document. ++example, size=2K has the same meaning as size=2048. + + read and write system calls are not supported on files that reside on hugetlb + file systems. +diff -Nurp linux-2.6.22/Documentation/vm/slub.txt linux-2.6-netns/Documentation/vm/slub.txt +--- linux-2.6.22/Documentation/vm/slub.txt 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Documentation/vm/slub.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -41,6 +41,8 @@ Possible debug options are + P Poisoning (object and padding) + U User tracking (free and alloc) + T Trace (please only use on single slabs) ++ - Switch all debugging off (useful if the kernel is ++ configured with CONFIG_SLUB_DEBUG_ON) + + F.e. in order to boot just with sanity checks and red zoning one would specify: + +@@ -125,13 +127,20 @@ SLUB Debug output + + Here is a sample of slub debug output: + +-*** SLUB kmalloc-8: Redzone Active@0xc90f6d20 slab 0xc528c530 offset=3360 flags=0x400000c3 inuse=61 freelist=0xc90f6d58 +- Bytes b4 0xc90f6d10: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ +- Object 0xc90f6d20: 31 30 31 39 2e 30 30 35 1019.005 +- Redzone 0xc90f6d28: 00 cc cc cc . +-FreePointer 0xc90f6d2c -> 0xc90f6d58 +-Last alloc: get_modalias+0x61/0xf5 jiffies_ago=53 cpu=1 pid=554 +-Filler 0xc90f6d50: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ ++==================================================================== ++BUG kmalloc-8: Redzone overwritten ++-------------------------------------------------------------------- ++ ++INFO: 0xc90f6d28-0xc90f6d2b. First byte 0x00 instead of 0xcc ++INFO: Slab 0xc528c530 flags=0x400000c3 inuse=61 fp=0xc90f6d58 ++INFO: Object 0xc90f6d20 @offset=3360 fp=0xc90f6d58 ++INFO: Allocated in get_modalias+0x61/0xf5 age=53 cpu=1 pid=554 ++ ++Bytes b4 0xc90f6d10: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ ++ Object 0xc90f6d20: 31 30 31 39 2e 30 30 35 1019.005 ++ Redzone 0xc90f6d28: 00 cc cc cc . ++ Padding 0xc90f6d50: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ ++ + [] dump_trace+0x63/0x1eb + [] show_trace_log_lvl+0x1a/0x2f + [] show_trace+0x12/0x14 +@@ -153,74 +162,108 @@ Filler 0xc90f6d50: 5a 5a 5a 5a 5a 5a 5a + [] sysenter_past_esp+0x5f/0x99 + [] 0xb7f7b410 + ======================= +-@@@ SLUB kmalloc-8: Restoring redzone (0xcc) from 0xc90f6d28-0xc90f6d2b +- + ++FIX kmalloc-8: Restoring Redzone 0xc90f6d28-0xc90f6d2b=0xcc + +-If SLUB encounters a corrupted object then it will perform the following +-actions: ++If SLUB encounters a corrupted object (full detection requires the kernel ++to be booted with slub_debug) then the following output will be dumped ++into the syslog: + +-1. Isolation and report of the issue ++1. Description of the problem encountered + + This will be a message in the system log starting with + +-*** SLUB : @ +-offset= flags= +-inuse= freelist= ++=============================================== ++BUG : ++----------------------------------------------- ++ ++INFO: - ++INFO: Slab
++INFO: Object
++INFO: Allocated in age= cpu= pid= ++INFO: Freed in age= cpu= ++ pid= + +-2. Report on how the problem was dealt with in order to ensure the continued +-operation of the system. +- +-These are messages in the system log beginning with ++(Object allocation / free information is only available if SLAB_STORE_USER is ++set for the slab. slub_debug sets that option) + +-@@@ SLUB : ++2. The object contents if an object was involved. + +- +-In the above sample SLUB found that the Redzone of an active object has +-been overwritten. Here a string of 8 characters was written into a slab that +-has the length of 8 characters. However, a 8 character string needs a +-terminating 0. That zero has overwritten the first byte of the Redzone field. +-After reporting the details of the issue encountered the @@@ SLUB message +-tell us that SLUB has restored the redzone to its proper value and then +-system operations continue. +- +-Various types of lines can follow the @@@ SLUB line: ++Various types of lines can follow the BUG SLUB line: + + Bytes b4
: +- Show a few bytes before the object where the problem was detected. ++ Shows a few bytes before the object where the problem was detected. + Can be useful if the corruption does not stop with the start of the + object. + + Object
: + The bytes of the object. If the object is inactive then the bytes +- typically contain poisoning values. Any non-poison value shows a ++ typically contain poison values. Any non-poison value shows a + corruption by a write after free. + + Redzone
: +- The redzone following the object. The redzone is used to detect ++ The Redzone following the object. The Redzone is used to detect + writes after the object. All bytes should always have the same + value. If there is any deviation then it is due to a write after + the object boundary. + +-Freepointer +- The pointer to the next free object in the slab. May become +- corrupted if overwriting continues after the red zone. +- +-Last alloc: +-Last free: +- Shows the address from which the object was allocated/freed last. +- We note the pid, the time and the CPU that did so. This is usually +- the most useful information to figure out where things went wrong. +- Here get_modalias() did an kmalloc(8) instead of a kmalloc(9). ++ (Redzone information is only available if SLAB_RED_ZONE is set. ++ slub_debug sets that option) + +-Filler
: ++Padding
: + Unused data to fill up the space in order to get the next object + properly aligned. In the debug case we make sure that there are +- at least 4 bytes of filler. This allow for the detection of writes ++ at least 4 bytes of padding. This allows the detection of writes + before the object. + +-Following the filler will be a stackdump. That stackdump describes the +-location where the error was detected. The cause of the corruption is more +-likely to be found by looking at the information about the last alloc / free. ++3. A stackdump ++ ++The stackdump describes the location where the error was detected. The cause ++of the corruption is may be more likely found by looking at the function that ++allocated or freed the object. ++ ++4. Report on how the problem was dealt with in order to ensure the continued ++operation of the system. ++ ++These are messages in the system log beginning with ++ ++FIX : ++ ++In the above sample SLUB found that the Redzone of an active object has ++been overwritten. Here a string of 8 characters was written into a slab that ++has the length of 8 characters. However, a 8 character string needs a ++terminating 0. That zero has overwritten the first byte of the Redzone field. ++After reporting the details of the issue encountered the FIX SLUB message ++tell us that SLUB has restored the Redzone to its proper value and then ++system operations continue. ++ ++Emergency operations: ++--------------------- ++ ++Minimal debugging (sanity checks alone) can be enabled by booting with ++ ++ slub_debug=F ++ ++This will be generally be enough to enable the resiliency features of slub ++which will keep the system running even if a bad kernel component will ++keep corrupting objects. This may be important for production systems. ++Performance will be impacted by the sanity checks and there will be a ++continual stream of error messages to the syslog but no additional memory ++will be used (unlike full debugging). ++ ++No guarantees. The kernel component still needs to be fixed. Performance ++may be optimized further by locating the slab that experiences corruption ++and enabling debugging only for that cache ++ ++I.e. ++ ++ slub_debug=F,dentry ++ ++If the corruption occurs by writing after the end of the object then it ++may be advisable to enable a Redzone to avoid corrupting the beginning ++of other objects. ++ ++ slub_debug=FZ,dentry + +-Christoph Lameter, , May 23, 2007 ++Christoph Lameter, , May 30, 2007 +diff -Nurp linux-2.6.22/Documentation/zh_CN/HOWTO linux-2.6-netns/Documentation/zh_CN/HOWTO +--- linux-2.6.22/Documentation/zh_CN/HOWTO 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/zh_CN/HOWTO 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,536 @@ ++Chinese translated version of Documentation/HOWTO ++ ++If you have any comment or update to the content, please contact the ++original document maintainer directly. However, if you have problem ++communicating in English you can also ask the Chinese maintainer for ++help. Contact the Chinese maintainer, if this translation is outdated ++or there is problem with translation. ++ ++Maintainer: Greg Kroah-Hartman ++Chinese maintainer: Li Yang ++--------------------------------------------------------------------- ++Documentation/HOWTO 的中文翻译 ++ ++如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 ++交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 ++译存在问题,请联系中文版维护者。 ++ ++英文版维护者: Greg Kroah-Hartman ++中文版维护者: 李阳 Li Yang ++中文版翻译者: 李阳 Li Yang ++中文版校译者: 钟宇 TripleX Chung ++ 陈琦 Maggie Chen ++ 王聪 Wang Cong ++ ++以下为正文 ++--------------------------------------------------------------------- ++ ++如何参与Linux内核开发 ++--------------------- ++ ++这是一篇将如何参与Linux内核开发的相关问题一网打尽的终极秘笈。它将指导你 ++成为一名Linux内核开发者,并且学会如何同Linux内核开发社区合作。它尽可能不 ++包括任何关于内核编程的技术细节,但会给你指引一条获得这些知识的正确途径。 ++ ++如果这篇文章中的任何内容不再适用,请给文末列出的文件维护者发送补丁。 ++ ++ ++入门 ++---- ++ ++你想了解如何成为一名Linux内核开发者?或者老板吩咐你“给这个设备写个Linux ++驱动程序”?这篇文章的目的就是教会你达成这些目标的全部诀窍,它将描述你需 ++要经过的流程以及给出如何同内核社区合作的一些提示。它还将试图解释内核社区 ++为何这样运作。 ++ ++Linux内核大部分是由C语言写成的,一些体系结构相关的代码用到了汇编语言。要 ++参与内核开发,你必须精通C语言。除非你想为某个架构开发底层代码,否则你并 ++不需要了解(任何体系结构的)汇编语言。下面列举的书籍虽然不能替代扎实的C ++语言教育和多年的开发经验,但如果需要的话,做为参考还是不错的: ++ - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall] ++ 《C程序设计语言(第2版·新版)》(徐宝文 李志 译)[机械工业出版社] ++ - "Practical C Programming" by Steve Oualline [O'Reilly] ++ 《实用C语言编程(第三版)》(郭大海 译)[中国电力出版社] ++ - "C: A Reference Manual" by Harbison and Steele [Prentice Hall] ++ 《C语言参考手册(原书第5版)》(邱仲潘 等译)[机械工业出版社] ++ ++Linux内核使用GNU C和GNU工具链开发。虽然它遵循ISO C89标准,但也用到了一些 ++标准中没有定义的扩展。内核是自给自足的C环境,不依赖于标准C库的支持,所以 ++并不支持C标准中的部分定义。比如long long类型的大数除法和浮点运算就不允许 ++使用。有时候确实很难弄清楚内核对工具链的要求和它所使用的扩展,不幸的是目 ++前还没有明确的参考资料可以解释它们。请查阅gcc信息页(使用“info gcc”命令 ++显示)获得一些这方面信息。 ++ ++请记住你是在学习怎么和已经存在的开发社区打交道。它由一群形形色色的人组成, ++他们对代码、风格和过程有着很高的标准。这些标准是在长期实践中总结出来的, ++适应于地理上分散的大型开发团队。它们已经被很好得整理成档,建议你在开发 ++之前尽可能多的学习这些标准,而不要期望别人来适应你或者你公司的行为方式。 ++ ++ ++法律问题 ++-------- ++ ++Linux内核源代码都是在GPL(通用公共许可证)的保护下发布的。要了解这种许可 ++的细节请查看源代码主目录下的COPYING文件。如果你对它还有更深入问题请联系 ++律师,而不要在Linux内核邮件组上提问。因为邮件组里的人并不是律师,不要期 ++望他们的话有法律效力。 ++ ++对于GPL的常见问题和解答,请访问以下链接: ++ http://www.gnu.org/licenses/gpl-faq.html ++ ++ ++文档 ++---- ++ ++Linux内核代码中包含有大量的文档。这些文档对于学习如何与内核社区互动有着 ++不可估量的价值。当一个新的功能被加入内核,最好把解释如何使用这个功能的文 ++档也放进内核。当内核的改动导致面向用户空间的接口发生变化时,最好将相关信 ++息或手册页(manpages)的补丁发到mtk-manpages@gmx.net,以向手册页(manpages) ++的维护者解释这些变化。 ++ ++以下是内核代码中需要阅读的文档: ++ README ++ 文件简要介绍了Linux内核的背景,并且描述了如何配置和编译内核。内核的 ++ 新用户应该从这里开始。 ++ ++ Documentation/Changes ++ 文件给出了用来编译和使用内核所需要的最小软件包列表。 ++ ++ Documentation/CodingStyle ++ 描述Linux内核的代码风格和理由。所有新代码需要遵守这篇文档中定义的规 ++ 范。大多数维护者只会接收符合规定的补丁,很多人也只会帮忙检查符合风格 ++ 的代码。 ++ ++ Documentation/SubmittingPatches ++ Documentation/SubmittingDrivers ++ 这两份文档明确描述如何创建和发送补丁,其中包括(但不仅限于): ++ - 邮件内容 ++ - 邮件格式 ++ - 选择收件人 ++ 遵守这些规定并不能保证提交成功(因为所有补丁需要通过严格的内容和风格 ++ 审查),但是忽视他们几乎就意味着失败。 ++ ++ 其他关于如何正确地生成补丁的优秀文档包括: ++ "The Perfect Patch" ++ http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt ++ "Linux kernel patch submission format" ++ http://linux.yyz.us/patch-format.html ++ ++ Documentation/stable_api_nonsense.txt ++ 论证内核为什么特意不包括稳定的内核内部API,也就是说不包括像这样的特 ++ 性: ++ - 子系统中间层(为了兼容性?) ++ - 在不同操作系统间易于移植的驱动程序 ++ - 减缓(甚至阻止)内核代码的快速变化 ++ 这篇文档对于理解Linux的开发哲学至关重要。对于将开发平台从其他操作系 ++ 统转移到Linux的人来说也很重要。 ++ ++ Documentation/SecurityBugs ++ 如果你认为自己发现了Linux内核的安全性问题,请根据这篇文档中的步骤来 ++ 提醒其他内核开发者并帮助解决这个问题。 ++ ++ Documentation/ManagementStyle ++ 描述内核维护者的工作方法及其共有特点。这对于刚刚接触内核开发(或者对 ++ 它感到好奇)的人来说很重要,因为它解释了很多对于内核维护者独特行为的 ++ 普遍误解与迷惑。 ++ ++ Documentation/stable_kernel_rules.txt ++ 解释了稳定版内核发布的规则,以及如何将改动放入这些版本的步骤。 ++ ++ Documentation/kernel-docs.txt ++ 有助于内核开发的外部文档列表。如果你在内核自带的文档中没有找到你想找 ++ 的内容,可以查看这些文档。 ++ ++ Documentation/applying-patches.txt ++ 关于补丁是什么以及如何将它打在不同内核开发分支上的好介绍 ++ ++内核还拥有大量从代码自动生成的文档。它包含内核内部API的全面介绍以及如何 ++妥善处理加锁的规则。生成的文档会放在 Documentation/DocBook/目录下。在内 ++核源码的主目录中使用以下不同命令将会分别生成PDF、Postscript、HTML和手册 ++页等不同格式的文档: ++ make pdfdocs ++ make psdocs ++ make htmldocs ++ make mandocs ++ ++ ++如何成为内核开发者 ++------------------ ++如果你对Linux内核开发一无所知,你应该访问“Linux内核新手”计划: ++ http://kernelnewbies.org ++它拥有一个可以问各种最基本的内核开发问题的邮件列表(在提问之前一定要记得 ++查找已往的邮件,确认是否有人已经回答过相同的问题)。它还拥有一个可以获得 ++实时反馈的IRC聊天频道,以及大量对于学习Linux内核开发相当有帮助的文档。 ++ ++网站简要介绍了源代码组织结构、子系统划分以及目前正在进行的项目(包括内核 ++中的和单独维护的)。它还提供了一些基本的帮助信息,比如如何编译内核和打补 ++丁。 ++ ++如果你想加入内核开发社区并协助完成一些任务,却找不到从哪里开始,可以访问 ++“Linux内核房管员”计划: ++ http://janitor.kernelnewbies.org/ ++这是极佳的起点。它提供一个相对简单的任务列表,列出内核代码中需要被重新 ++整理或者改正的地方。通过和负责这个计划的开发者们一同工作,你会学到将补丁 ++集成进内核的基本原理。如果还没有决定下一步要做什么的话,你还可能会得到方 ++向性的指点。 ++ ++如果你已经有一些现成的代码想要放到内核中,但是需要一些帮助来使它们拥有正 ++确的格式。请访问“内核导师”计划。这个计划就是用来帮助你完成这个目标的。它 ++是一个邮件列表,地址如下: ++ http://selenic.com/mailman/listinfo/kernel-mentors ++ ++在真正动手修改内核代码之前,理解要修改的代码如何运作是必需的。要达到这个 ++目的,没什么办法比直接读代码更有效了(大多数花招都会有相应的注释),而且 ++一些特制的工具还可以提供帮助。例如,“Linux代码交叉引用”项目就是一个值得 ++特别推荐的帮助工具,它将源代码显示在有编目和索引的网页上。其中一个更新及 ++时的内核源码库,可以通过以下地址访问: ++ http://sosdg.org/~coywolf/lxr/ ++ ++ ++开发流程 ++-------- ++ ++目前Linux内核开发流程包括几个“主内核分支”和很多子系统相关的内核分支。这 ++些分支包括: ++ - 2.6.x主内核源码树 ++ - 2.6.x.y -stable内核源码树 ++ - 2.6.x -git内核补丁集 ++ - 2.6.x -mm内核补丁集 ++ - 子系统相关的内核源码树和补丁集 ++ ++ ++2.6.x内核主源码树 ++----------------- ++2.6.x内核是由Linus Torvalds(Linux的创造者)亲自维护的。你可以在 ++kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循以下步 ++骤: ++ - 每当一个新版本的内核被发布,为期两周的集成窗口将被打开。在这段时间里 ++ 维护者可以向Linus提交大段的修改,通常这些修改已经被放到-mm内核中几个 ++ 星期了。提交大量修改的首选方式是使用git工具(内核的代码版本管理工具 ++ ,更多的信息可以在http://git.or.cz/获取),不过使用普通补丁也是可以 ++ 的。 ++ - 两个星期以后-rc1版本内核发布。之后只有不包含可能影响整个内核稳定性的 ++ 新功能的补丁才可能被接受。请注意一个全新的驱动程序(或者文件系统)有 ++ 可能在-rc1后被接受是因为这样的修改完全独立,不会影响其他的代码,所以 ++ 没有造成内核退步的风险。在-rc1以后也可以用git向Linus提交补丁,不过所 ++ 有的补丁需要同时被发送到相应的公众邮件列表以征询意见。 ++ - 当Linus认为当前的git源码树已经达到一个合理健全的状态足以发布供人测试 ++ 时,一个新的-rc版本就会被发布。计划是每周都发布新的-rc版本。 ++ - 这个过程一直持续下去直到内核被认为达到足够稳定的状态,持续时间大概是 ++ 6个星期。 ++ ++关于内核发布,值得一提的是Andrew Morton在linux-kernel邮件列表中如是说: ++ “没有人知道新内核何时会被发布,因为发布是根据已知bug的情况来决定 ++ 的,而不是根据一个事先制定好的时间表。” ++ ++ ++2.6.x.y -stable(稳定版)内核源码树 ++----------------------------------- ++由4个数字组成的内核版本号说明此内核是-stable版本。它们包含基于2.6.x版本 ++内核的相对较小且至关重要的修补,这些修补针对安全性问题或者严重的内核退步。 ++ ++这种版本的内核适用于那些期望获得最新的稳定版内核并且不想参与测试开发版或 ++者实验版的用户。 ++ ++如果没有2.6.x.y版本内核存在,那么最新的2.6.x版本内核就相当于是当前的稳定 ++版内核。 ++ ++2.6.x.y版本由“稳定版”小组(邮件地址)维护,一般隔周发 ++布新版本。 ++ ++内核源码中的Documentation/stable_kernel_rules.txt文件具体描述了可被稳定 ++版内核接受的修改类型以及发布的流程。 ++ ++ ++2.6.x -git补丁集 ++---------------- ++Linus的内核源码树的每日快照,这个源码树是由git工具管理的(由此得名)。这 ++些补丁通常每天更新以反映Linus的源码树的最新状态。它们比-rc版本的内核源码 ++树更具试验性质,因为这个补丁集是全自动生成的,没有任何人来确认其是否真正 ++健全。 ++ ++ ++2.6.x -mm补丁集 ++--------------- ++这是由Andrew Morton维护的试验性内核补丁集。Andrew将所有子系统的内核源码 ++和补丁拼凑到一起,并且加入了大量从linux-kernel邮件列表中采集的补丁。这个 ++源码树是新功能和补丁的试炼场。当补丁在-mm补丁集里证明了其价值以后Andrew ++或者相应子系统的维护者会将补丁发给Linus以便集成进主内核源码树。 ++ ++在将所有新补丁发给Linus以集成到主内核源码树之前,我们非常鼓励先把这些补 ++丁放在-mm版内核源码树中进行测试。 ++ ++这些内核版本不适合在需要稳定运行的系统上运行,因为运行它们比运行任何其他 ++内核分支都更具有风险。 ++ ++如果你想为内核开发进程提供帮助,请尝试并使用这些内核版本,并在 ++linux-kernel邮件列表中提供反馈,告诉大家你遇到了问题还是一切正常。 ++ ++通常-mm版补丁集不光包括这些额外的试验性补丁,还包括发布时-git版主源码树 ++中的改动。 ++ ++-mm版内核没有固定的发布周期,但是通常在每两个-rc版内核发布之间都会有若干 ++个-mm版内核发布(一般是1至3个)。 ++ ++ ++子系统相关内核源码树和补丁集 ++---------------------------- ++相当一部分内核子系统开发者会公开他们自己的开发源码树,以便其他人能了解内 ++核的不同领域正在发生的事情。如上所述,这些源码树会被集成到-mm版本内核中。 ++ ++下面是目前可用的一些内核源码树的列表: ++ 通过git管理的源码树: ++ - Kbuild开发源码树, Sam Ravnborg ++ git.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git ++ ++ - ACPI开发源码树, Len Brown ++ git.kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git ++ ++ - 块设备开发源码树, Jens Axboe ++ git.kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git ++ ++ - DRM开发源码树, Dave Airlie ++ git.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git ++ ++ - ia64开发源码树, Tony Luck ++ git.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git ++ ++ - ieee1394开发源码树, Jody McIntyre ++ git.kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394.git ++ ++ - infiniband开发源码树, Roland Dreier ++ git.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git ++ ++ - libata开发源码树, Jeff Garzik ++ git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git ++ ++ - 网络驱动程序开发源码树, Jeff Garzik ++ git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git ++ ++ - pcmcia开发源码树, Dominik Brodowski ++ git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git ++ ++ - SCSI开发源码树, James Bottomley ++ git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git ++ ++ 使用quilt管理的补丁集: ++ - USB, PCI, 驱动程序核心和I2C, Greg Kroah-Hartman ++ kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ ++ - x86-64, 部分i386, Andi Kleen ++ ftp.firstfloor.org:/pub/ak/x86_64/quilt/ ++ ++ 其他内核源码树可以在http://git.kernel.org的列表中和MAINTAINERS文件里 ++ 找到。 ++ ++报告bug ++------- ++ ++bugzilla.kernel.org是Linux内核开发者们用来跟踪内核Bug的网站。我们鼓励用 ++户在这个工具中报告找到的所有bug。如何使用内核bugzilla的细节请访问: ++ http://test.kernel.org/bugzilla/faq.html ++ ++内核源码主目录中的REPORTING-BUGS文件里有一个很好的模板。它指导用户如何报 ++告可能的内核bug以及需要提供哪些信息来帮助内核开发者们找到问题的根源。 ++ ++ ++利用bug报告 ++----------- ++ ++练习内核开发技能的最好办法就是修改其他人报告的bug。你不光可以帮助内核变 ++得更加稳定,还可以学会如何解决实际问题从而提高自己的技能,并且让其他开发 ++者感受到你的存在。修改bug是赢得其他开发者赞誉的最好办法,因为并不是很多 ++人都喜欢浪费时间去修改别人报告的bug。 ++ ++要尝试修改已知的bug,请访问http://bugzilla.kernel.org网址。如果你想获得 ++最新bug的通知,可以订阅bugme-new邮件列表(只有新的bug报告会被寄到这里) ++或者订阅bugme-janitor邮件列表(所有bugzilla的变动都会被寄到这里)。 ++ ++ http://lists.osdl.org/mailman/listinfo/bugme-new ++ http://lists.osdl.org/mailman/listinfo/bugme-janitors ++ ++ ++邮件列表 ++-------- ++ ++正如上面的文档所描述,大多数的骨干内核开发者都加入了Linux Kernel邮件列 ++表。如何订阅和退订列表的细节可以在这里找到: ++ http://vger.kernel.org/vger-lists.html#linux-kernel ++网上很多地方都有这个邮件列表的存档(archive)。可以使用搜索引擎来找到这些 ++存档。比如: ++ http://dir.gmane.org/gmane.linux.kernel ++在发信之前,我们强烈建议你先在存档中搜索你想要讨论的问题。很多已经被详细 ++讨论过的问题只在邮件列表的存档中可以找到。 ++ ++大多数内核子系统也有自己独立的邮件列表来协调各自的开发工作。从 ++MAINTAINERS文件中可以找到不同话题对应的邮件列表。 ++ ++很多邮件列表架设在kernel.org服务器上。这些列表的信息可以在这里找到: ++ http://vger.kernel.org/vger-lists.html ++ ++在使用这些邮件列表时,请记住保持良好的行为习惯。下面的链接提供了与这些列 ++表(或任何其它邮件列表)交流的一些简单规则,虽然内容有点滥竽充数。 ++ http://www.albion.com/netiquette/ ++ ++当有很多人回复你的邮件时,邮件的抄送列表会变得很长。请不要将任何人从抄送 ++列表中删除,除非你有足够的理由这么做。也不要只回复到邮件列表。请习惯于同 ++一封邮件接收两次(一封来自发送者一封来自邮件列表),而不要试图通过添加一 ++些奇特的邮件头来解决这个问题,人们不会喜欢的。 ++ ++记住保留你所回复内容的上下文和源头。在你回复邮件的顶部保留“某某某说到……” ++这几行。将你的评论加在被引用的段落之间而不要放在邮件的顶部。 ++ ++如果你在邮件中附带补丁,请确认它们是可以直接阅读的纯文本(如 ++Documentation/SubmittingPatches文档中所述)。内核开发者们不希望遇到附件 ++或者被压缩了的补丁。只有这样才能保证他们可以直接评论你的每行代码。请确保 ++你使用的邮件发送程序不会修改空格和制表符。一个防范性的测试方法是先将邮件 ++发送给自己,然后自己尝试是否可以顺利地打上收到的补丁。如果测试不成功,请 ++调整或者更换你的邮件发送程序直到它正确工作为止。 ++ ++总而言之,请尊重其他的邮件列表订阅者。 ++ ++ ++同内核社区合作 ++---------------- ++ ++内核社区的目标就是提供尽善尽美的内核。所以当你提交补丁期望被接受进内核的 ++时候,它的技术价值以及其他方面都将被评审。那么你可能会得到什么呢? ++ - 批评 ++ - 评论 ++ - 要求修改 ++ - 要求证明修改的必要性 ++ - 沉默 ++ ++要记住,这些是把补丁放进内核的正常情况。你必须学会听取对补丁的批评和评论, ++从技术层面评估它们,然后要么重写你的补丁要么简明扼要地论证修改是不必要 ++的。如果你发的邮件没有得到任何回应,请过几天后再试一次,因为有时信件会湮 ++没在茫茫信海中。 ++ ++你不应该做的事情: ++ - 期望自己的补丁不受任何质疑就直接被接受 ++ - 翻脸 ++ - 忽略别人的评论 ++ - 没有按照别人的要求做任何修改就重新提交 ++ ++在一个努力追寻最好技术方案的社区里,对于一个补丁有多少好处总会有不同的见 ++解。你必须要抱着合作的态度,愿意改变自己的观点来适应内核的风格。或者至少 ++愿意去证明你的想法是有价值的。记住,犯错误是允许的,只要你愿意朝着正确的 ++方案去努力。 ++ ++如果你的第一个补丁换来的是一堆修改建议,这是很正常的。这并不代表你的补丁 ++不会被接受,也不意味着有人和你作对。你只需要改正所有提出的问题然后重新发 ++送你的补丁。 ++ ++内核社区和公司文化的差异 ++------------------------ ++ ++内核社区的工作模式同大多数传统公司开发队伍的工作模式并不相同。下面这些例 ++子,可以帮助你避免某些可能发生问题: ++ 用这些话介绍你的修改提案会有好处: ++ - 它同时解决了多个问题 ++ - 它删除了2000行代码 ++ - 这是补丁,它已经解释了我想要说明的 ++ - 我在5种不同的体系结构上测试过它…… ++ - 这是一系列小补丁用来…… ++ - 这个修改提高了普通机器的性能…… ++ ++ 应该避免如下的说法: ++ - 我们在AIX/ptx/Solaris就是这么做的,所以这么做肯定是好的…… ++ - 我做这行已经20年了,所以…… ++ - 为了我们公司赚钱考虑必须这么做 ++ - 这是我们的企业产品线所需要的 ++ - 这里是描述我观点的1000页设计文档 ++ - 这是一个5000行的补丁用来…… ++ - 我重写了现在乱七八糟的代码,这就是…… ++ - 我被规定了最后期限,所以这个补丁需要立刻被接受 ++ ++另外一个内核社区与大部分传统公司的软件开发队伍不同的地方是无法面对面地交 ++流。使用电子邮件和IRC聊天工具做为主要沟通工具的一个好处是性别和种族歧视 ++将会更少。Linux内核的工作环境更能接受妇女和少数族群,因为每个人在别人眼 ++里只是一个邮件地址。国际化也帮助了公平的实现,因为你无法通过姓名来判断人 ++的性别。男人有可能叫李丽,女人也有可能叫王刚。大多数在Linux内核上工作过 ++并表达过看法的女性对在linux上工作的经历都给出了正面的评价。 ++ ++对于一些不习惯使用英语的人来说,语言可能是一个引起问题的障碍。在邮件列表 ++中要正确地表达想法必需良好地掌握语言,所以建议你在发送邮件之前最好检查一 ++下英文写得是否正确。 ++ ++ ++拆分修改 ++-------- ++ ++Linux内核社区并不喜欢一下接收大段的代码。修改需要被恰当地介绍、讨论并且 ++拆分成独立的小段。这几乎完全和公司中的习惯背道而驰。你的想法应该在开发最 ++开始的阶段就让大家知道,这样你就可以及时获得对你正在进行的开发的反馈。这 ++样也会让社区觉得你是在和他们协作,而不是仅仅把他们当作倾销新功能的对象。 ++无论如何,你不要一次性地向邮件列表发送50封信,你的补丁序列应该永远用不到 ++这么多。 ++ ++将补丁拆开的原因如下: ++ ++1) 小的补丁更有可能被接受,因为它们不需要太多的时间和精力去验证其正确性。 ++ 一个5行的补丁,可能在维护者看了一眼以后就会被接受。而500行的补丁则 ++ 需要数个小时来审查其正确性(所需时间随补丁大小增加大约呈指数级增长)。 ++ ++ 当出了问题的时候,小的补丁也会让调试变得非常容易。一个一个补丁地回溯 ++ 将会比仔细剖析一个被打上的大补丁(这个补丁破坏了其他东西)容易得多。 ++ ++2)不光发送小的补丁很重要,在提交之前重新编排、化简(或者仅仅重新排列) ++ 补丁也是很重要的。 ++ ++这里有内核开发者Al Viro打的一个比方: ++ “想象一个老师正在给学生批改数学作业。老师并不希望看到学生为了得 ++ 到正确解法所进行的尝试和产生的错误。他希望看到的是最干净最优雅的 ++ 解答。好学生了解这点,绝不会把最终解决之前的中间方案提交上去。” ++ ++ 内核开发也是这样。维护者和评审者不希望看到一个人在解决问题时的思 ++ 考过程。他们只希望看到简单和优雅的解决方案。 ++ ++直接给出一流的解决方案,和社区一起协作讨论尚未完成的工作,这两者之间似乎 ++很难找到一个平衡点。所以最好尽早开始收集有利于你进行改进的反馈;同时也要 ++保证修改分成很多小块,这样在整个项目都准备好被包含进内核之前,其中的一部 ++分可能会先被接收。 ++ ++必须了解这样做是不可接受的:试图将未完成的工作提交进内核,然后再找时间修 ++复。 ++ ++ ++证明修改的必要性 ++---------------- ++除了将补丁拆成小块,很重要的一点是让Linux社区了解他们为什么需要这样修改。 ++你必须证明新功能是有人需要的并且是有用的。 ++ ++ ++记录修改 ++-------- ++ ++当你发送补丁的时候,需要特别留意邮件正文的内容。因为这里的信息将会做为补 ++丁的修改记录(ChangeLog),会被一直保留以备大家查阅。它需要完全地描述补丁, ++包括: ++ - 为什么需要这个修改 ++ - 补丁的总体设计 ++ - 实现细节 ++ - 测试结果 ++ ++想了解它具体应该看起来像什么,请查阅以下文档中的“ChangeLog”章节: ++ “The Perfect Patch” ++ http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt ++ ++ ++这些事情有时候做起来很难。要在任何方面都做到完美可能需要好几年时间。这是 ++一个持续提高的过程,它需要大量的耐心和决心。只要不放弃,你一定可以做到。 ++很多人已经做到了,而他们都曾经和现在的你站在同样的起点上。 ++ ++ ++--------------- ++感谢Paolo Ciarrocchi允许“开发流程”部分基于他所写的文章 ++(http://linux.tar.bz/articles/2.6-development_process),感谢Randy ++Dunlap和Gerrit Huizenga完善了应该说和不该说的列表。感谢Pat Mochel, Hanna ++Linder, Randy Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer, ++Kees Cook, Andrew Morton, Andi Kleen, Vadim Lobanov, Jesper Juhl, Adrian ++Bunk, Keri Harris, Frans Pop, David A. Wheeler, Junio Hamano, Michael ++Kerrisk和Alex Shepard的评审、建议和贡献。没有他们的帮助,这篇文档是不可 ++能完成的。 ++ ++ ++ ++英文版维护者: Greg Kroah-Hartman +diff -Nurp linux-2.6.22/Documentation/zh_CN/stable_api_nonsense.txt linux-2.6-netns/Documentation/zh_CN/stable_api_nonsense.txt +--- linux-2.6.22/Documentation/zh_CN/stable_api_nonsense.txt 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6-netns/Documentation/zh_CN/stable_api_nonsense.txt 2007-12-03 23:06:33.000000000 -0500 +@@ -0,0 +1,157 @@ ++Chinese translated version of Documentation/stable_api_nonsense.txt ++ ++If you have any comment or update to the content, please contact the ++original document maintainer directly. However, if you have problem ++communicating in English you can also ask the Chinese maintainer for help. ++Contact the Chinese maintainer, if this translation is outdated or there ++is problem with translation. ++ ++Maintainer: Greg Kroah-Hartman ++Chinese maintainer: TripleX Chung ++--------------------------------------------------------------------- ++Documentation/stable_api_nonsense.txt 的中文翻译 ++ ++如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 ++交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 ++译存在问题,请联系中文版维护者。 ++ ++英文版维护者: Greg Kroah-Hartman ++中文版维护者: 钟宇 TripleX Chung ++中文版翻译者: 钟宇 TripleX Chung ++中文版校译者: 李阳 Li Yang ++以下为正文 ++--------------------------------------------------------------------- ++ ++写作本文档的目的,是为了解释为什么Linux既没有二进制内核接口,也没有稳定 ++的内核接口。这里所说的内核接口,是指内核里的接口,而不是内核和用户空间 ++的接口。内核到用户空间的接口,是提供给应用程序使用的系统调用,系统调用 ++在历史上几乎没有过变化,将来也不会有变化。我有一些老应用程序是在0.9版本 ++或者更早版本的内核上编译的,在使用2.6版本内核的Linux发布上依然用得很好 ++。用户和应用程序作者可以将这个接口看成是稳定的。 ++ ++ ++执行纲要 ++-------- ++ ++你也许以为自己想要稳定的内核接口,但是你不清楚你要的实际上不是它。你需 ++要的其实是稳定的驱动程序,而你只有将驱动程序放到公版内核的源代码树里, ++才有可能达到这个目的。而且这样做还有很多其它好处,正是因为这些好处使得 ++Linux能成为强壮,稳定,成熟的操作系统,这也是你最开始选择Linux的原因。 ++ ++ ++入门 ++----- ++ ++只有那些写驱动程序的“怪人”才会担心内核接口的改变,对广大用户来说,既 ++看不到内核接口,也不需要去关心它。 ++ ++首先,我不打算讨论关于任何非GPL许可的内核驱动的法律问题,这些非GPL许可 ++的驱动程序包括不公开源代码,隐藏源代码,二进制或者是用源代码包装,或者 ++是其它任何形式的不能以GPL许可公开源代码的驱动程序。如果有法律问题,请咨 ++询律师,我只是一个程序员,所以我只打算探讨技术问题(不是小看法律问题, ++法律问题很实际,并且需要一直关注)。 ++ ++既然只谈技术问题,我们就有了下面两个主题:二进制内核接口和稳定的内核源 ++代码接口。这两个问题是互相关联的,让我们先解决掉二进制接口的问题。 ++ ++ ++二进制内核接口 ++-------------- ++假如我们有一个稳定的内核源代码接口,那么自然而然的,我们就拥有了稳定的 ++二进制接口,是这样的吗?错。让我们看看关于Linux内核的几点事实: ++ - 取决于所用的C编译器的版本,不同的内核数据结构里的结构体的对齐方 ++式会有差别,代码中不同函数的表现形式也不一样(函数是不是被inline编译取 ++决于编译器行为)。不同的函数的表现形式并不重要,但是数据结构内部的对齐 ++方式很关键。 ++ - 取决于内核的配置选项,不同的选项会让内核的很多东西发生改变: ++ - 同一个结构体可能包含不同的成员变量 ++ - 有的函数可能根本不会被实现(比如编译的时候没有选择SMP支持 ++,一些锁函数就会被定义成空函数)。 ++ - 内核使用的内存会以不同的方式对齐,这取决于不同的内核配置选 ++项。 ++ - Linux可以在很多的不同体系结构的处理器上运行。在某个体系结构上编 ++译好的二进制驱动程序,不可能在另外一个体系结构上正确的运行。 ++ ++对于一个特定的内核,满足这些条件并不难,使用同一个C编译器和同样的内核配 ++置选项来编译驱动程序模块就可以了。这对于给一个特定Linux发布的特定版本提 ++供驱动程序,是完全可以满足需求的。但是如果你要给不同发布的不同版本都发 ++布一个驱动程序,就需要在每个发布上用不同的内核设置参数都编译一次内核, ++这简直跟噩梦一样。而且还要注意到,每个Linux发布还提供不同的Linux内核, ++这些内核都针对不同的硬件类型进行了优化(有很多种不同的处理器,还有不同 ++的内核设置选项)。所以每发布一次驱动程序,都需要提供很多不同版本的内核 ++模块。 ++ ++相信我,如果你真的要采取这种发布方式,一定会慢慢疯掉,我很久以前就有过 ++深刻的教训... ++ ++ ++稳定的内核源代码接口 ++-------------------- ++ ++如果有人不将他的内核驱动程序,放入公版内核的源代码树,而又想让驱动程序 ++一直保持在最新的内核中可用,那么这个话题将会变得没完没了。 ++ 内核开发是持续而且快节奏的,从来都不会慢下来。内核开发人员在当前接口中 ++找到bug,或者找到更好的实现方式。一旦发现这些,他们就很快会去修改当前的 ++接口。修改接口意味着,函数名可能会改变,结构体可能被扩充或者删减,函数 ++的参数也可能发生改变。一旦接口被修改,内核中使用这些接口的地方需要同时 ++修正,这样才能保证所有的东西继续工作。 ++ ++举一个例子,内核的USB驱动程序接口在USB子系统的整个生命周期中,至少经历 ++了三次重写。这些重写解决以下问题: ++ - 把数据流从同步模式改成非同步模式,这个改动减少了一些驱动程序的 ++复杂度,提高了所有USB驱动程序的吞吐率,这样几乎所有的USB设备都能以最大 ++速率工作了。 ++ - 修改了USB核心代码中为USB驱动分配数据包内存的方式,所有的驱动都 ++需要提供更多的参数给USB核心,以修正了很多已经被记录在案的死锁。 ++ ++这和一些封闭源代码的操作系统形成鲜明的对比,在那些操作系统上,不得不额 ++外的维护旧的USB接口。这导致了一个可能性,新的开发者依然会不小心使用旧的 ++接口,以不恰当的方式编写代码,进而影响到操作系统的稳定性。 ++ 在上面的例子中,所有的开发者都同意这些重要的改动,在这样的情况下修改代 ++价很低。如果Linux保持一个稳定的内核源代码接口,那么就得创建一个新的接口 ++;旧的,有问题的接口必须一直维护,给Linux USB开发者带来额外的工作。既然 ++所有的Linux USB驱动的作者都是利用自己的时间工作,那么要求他们去做毫无意 ++义的免费额外工作,是不可能的。 ++ 安全问题对Linux来说十分重要。一个安全问题被发现,就会在短时间内得到修 ++正。在很多情况下,这将导致Linux内核中的一些接口被重写,以从根本上避免安 ++全问题。一旦接口被重写,所有使用这些接口的驱动程序,必须同时得到修正, ++以确定安全问题已经得到修复并且不可能在未来还有同样的安全问题。如果内核 ++内部接口不允许改变,那么就不可能修复这样的安全问题,也不可能确认这样的 ++安全问题以后不会发生。 ++开发者一直在清理内核接口。如果一个接口没有人在使用了,它就会被删除。这 ++样可以确保内核尽可能的小,而且所有潜在的接口都会得到尽可能完整的测试 ++(没有人使用的接口是不可能得到良好的测试的)。 ++ ++ ++要做什么 ++------- ++ ++如果你写了一个Linux内核驱动,但是它还不在Linux源代码树里,作为一个开发 ++者,你应该怎么做?为每个发布的每个版本提供一个二进制驱动,那简直是一个 ++噩梦,要跟上永远处于变化之中的内核接口,也是一件辛苦活。 ++很简单,让你的驱动进入内核源代码树(要记得我们在谈论的是以GPL许可发行 ++的驱动,如果你的代码不符合GPL,那么祝你好运,你只能自己解决这个问题了, ++你这个吸血鬼<把Andrew和Linus对吸血鬼的定义链接到这里>)。当你的代码加入 ++公版内核源代码树之后,如果一个内核接口改变,你的驱动会直接被修改接口的 ++那个人修改。保证你的驱动永远都可以编译通过,并且一直工作,你几乎不需要 ++做什么事情。 ++ ++把驱动放到内核源代码树里会有很多的好处: ++ - 驱动的质量会提升,而维护成本(对原始作者来说)会下降。 ++ - 其他人会给驱动添加新特性。 ++ - 其他人会找到驱动中的bug并修复。 ++ - 其他人会在驱动中找到性能优化的机会。 ++ - 当外部的接口的改变需要修改驱动程序的时候,其他人会修改驱动程序 ++。 ++ - 不需要联系任何发行商,这个驱动会自动的随着所有的Linux发布一起发 ++布。 ++ ++和别的操作系统相比,Linux为更多不同的设备提供现成的驱动,而且能在更多不 ++同体系结构的处理器上支持这些设备。这个经过考验的开发模式,必然是错不了 ++的 :) ++ ++------------- ++感谢 Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder, ++Robert Love, and Nishanth Aravamudan 对于本文档早期版本的评审和建议。 ++ ++英文版维护者: Greg Kroah-Hartman +diff -Nurp linux-2.6.22/MAINTAINERS linux-2.6-netns/MAINTAINERS +--- linux-2.6.22/MAINTAINERS 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/MAINTAINERS 2007-12-03 23:14:12.000000000 -0500 +@@ -194,13 +194,6 @@ M: jes@trained-monkey.org + L: linux-acenic@sunsite.dk + S: Maintained + +-ACI MIXER DRIVER +-P: Robert Siemer +-M: Robert.Siemer@gmx.de +-L: linux-sound@vger.kernel.org +-W: http://www.stud.uni-karlsruhe.de/~uh1b/ +-S: Maintained +- + IPS SCSI RAID DRIVER + P: Adaptec OEM Raid Solutions + M: aacraid@adaptec.com +@@ -272,21 +265,6 @@ L: linux-acpi@vger.kernel.org + W: http://acpi.sourceforge.net/ + S: Supported + +-AD1816 SOUND DRIVER +-P: Thorsten Knabe +-M: Thorsten Knabe +-W: http://linux.thorsten-knabe.de +-S: Maintained +- +-AD1889 SOUND DRIVER +-P: Kyle McMartin +-M: kyle@parisc-linux.org +-P: Thibaut Varene +-M: T-Bone@parisc-linux.org +-W: http://wiki.parisc-linux.org/AD1889 +-L: parisc-linux@lists.parisc-linux.org +-S: Maintained +- + ADM1025 HARDWARE MONITOR DRIVER + P: Jean Delvare + M: khali@linux-fr.org +@@ -315,10 +293,9 @@ M: zippel@linux-m68k.org + S: Maintained + + AGPGART DRIVER +-P: Dave Jones +-M: davej@codemonkey.org.uk +-W: http://www.codemonkey.org.uk/projects/agp/ +-T: git kernel.org:/pub/scm/linux/kernel/git/davej/agpgart.git ++P: David Airlie ++M: airlied@linux.ie ++T: git kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git + S: Maintained + + AHA152X SCSI DRIVER +@@ -371,7 +348,7 @@ P: Tom Tucker + M: tom@opengridcomputing.com + P: Steve Wise + M: swise@opengridcomputing.com +-L: openib-general@openib.org ++L: general@lists.openfabrics.org + S: Maintained + + AOA (Apple Onboard Audio) ALSA DRIVER +@@ -755,6 +732,13 @@ L: uclinux-dist-devel@blackfin.uclinux.o + W: http://blackfin.uclinux.org + S: Supported + ++BLACKFIN EMAC DRIVER ++P: Bryan Wu ++M: bryan.wu@analog.com ++L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) ++W: http://blackfin.uclinux.org ++S: Supported ++ + BLACKFIN RTC DRIVER + P: Mike Frysinger + M: michael.frysinger@analog.com +@@ -936,6 +920,12 @@ M: mchan@broadcom.com + L: netdev@vger.kernel.org + S: Supported + ++BSG (block layer generic sg v4 driver) ++P: FUJITA Tomonori ++M: fujita.tomonori@lab.ntt.co.jp ++L: linux-scsi@vger.kernel.org ++S: Supported ++ + BTTV VIDEO4LINUX DRIVER + P: Mauro Carvalho Chehab + M: mchehab@infradead.org +@@ -1277,6 +1267,12 @@ M: tori@unhappy.mine.nu + L: netdev@vger.kernel.org + S: Maintained + ++DMA GENERIC MEMCPY SUBSYSTEM ++P: Shannon Nelson ++M: shannon.nelson@intel.com ++L: linux-kernel@vger.kernel.org ++S: Maintained ++ + DOCBOOK FOR DOCUMENTATION + P: Randy Dunlap + M: rdunlap@xenotime.net +@@ -1396,16 +1392,9 @@ P: Hoang-Nam Nguyen + M: hnguyen@de.ibm.com + P: Christoph Raisch + M: raisch@de.ibm.com +-L: openib-general@openib.org ++L: general@lists.openfabrics.org + S: Supported + +-EMU10K1 SOUND DRIVER +-P: James Courtier-Dutton +-M: James@superbug.demon.co.uk +-L: emu10k1-devel@lists.sourceforge.net +-W: http://sourceforge.net/projects/emu10k1/ +-S: Maintained +- + EMULEX LPFC FC SCSI DRIVER + P: James Smart + M: james.smart@emulex.com +@@ -1750,14 +1739,15 @@ T: http://www.harbaum.org/till/i2c_tiny_ + S: Maintained + + i386 BOOT CODE +-P: Riley H. Williams +-M: Riley@Williams.Name ++P: H. Peter Anvin ++M: hpa@zytor.com + L: Linux-Kernel@vger.kernel.org + S: Maintained + + i386 SETUP CODE / CPU ERRATA WORKAROUNDS + P: H. Peter Anvin + M: hpa@zytor.com ++T: git.kernel.org:/pub/scm/linux/kernel/git/hpa/linux-2.6-x86setup.git + S: Maintained + + IA64 (Itanium) PLATFORM +@@ -1850,13 +1840,13 @@ M: rolandd@cisco.com + P: Sean Hefty + M: mshefty@ichips.intel.com + P: Hal Rosenstock +-M: halr@voltaire.com +-L: openib-general@openib.org ++M: hal.rosenstock@gmail.com ++L: general@lists.openfabrics.org + W: http://www.openib.org/ + T: git kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git + S: Supported + +-INPUT (KEYBOARD, MOUSE, JOYSTICK) DRIVERS ++INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS + P: Dmitry Torokhov + M: dmitry.torokhov@gmail.com + M: dtor@mail.ru +@@ -1901,6 +1891,12 @@ P: Tigran Aivazian + M: tigran@aivazian.fsnet.co.uk + S: Maintained + ++INTEL I/OAT DMA DRIVER ++P: Shannon Nelson ++M: shannon.nelson@intel.com ++L: linux-kernel@vger.kernel.org ++S: Supported ++ + INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT + P: Deepak Saxena + M: dsaxena@plexity.net +@@ -1989,9 +1985,10 @@ M: jjciarla@raiz.uncu.edu.ar + S: Maintained + + IPATH DRIVER: +-P: Bryan O'Sullivan +-M: support@pathscale.com +-L: openib-general@openib.org ++P: Arthur Jones ++M: infinipath@qlogic.com ++L: general@lists.openfabrics.org ++T: git git://git.qlogic.com/ipath-linux-2.6 + S: Supported + + IPMI SUBSYSTEM +@@ -2297,6 +2294,14 @@ M: matthew@wil.cx + L: linux-scsi@vger.kernel.org + S: Maintained + ++M32R ARCHITECTURE ++P: Hirokazu Takata ++M: takata@linux-m32r.org ++L: linux-m32r@ml.linux-m32r.org ++L: linux-m32r-ja@ml.linux-m32r.org (in Japanese) ++W: http://www.linux-m32r.org/ ++S: Maintained ++ + M68K ARCHITECTURE + P: Geert Uytterhoeven + M: geert@linux-m68k.org +@@ -2330,6 +2335,12 @@ W: http://linuxwireless.org/ + T: git kernel.org:/pub/scm/linux/kernel/git/jbenc/mac80211.git + S: Maintained + ++MACVLAN DRIVER ++P: Patrick McHardy ++M: kaber@trash.net ++L: netdev@vger.kernel.org ++S: Maintained ++ + MARVELL YUKON / SYSKONNECT DRIVER + P: Mirko Lindner + M: mlindner@syskonnect.de +@@ -2390,7 +2401,7 @@ P: Artem Bityutskiy + M: dedekind@infradead.org + W: http://www.linux-mtd.infradead.org/ + L: linux-mtd@lists.infradead.org +-T: git git://git.infradead.org/ubi-2.6.git ++T: git git://git.infradead.org/~dedekind/ubi-2.6.git + S: Maintained + + MICROTEK X6 SCANNER +@@ -2616,12 +2627,6 @@ M: yokota@netlab.is.tsukuba.ac.jp + W: http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/ + S: Maintained + +-NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility) +-P: Eberhard Moenkeberg +-M: emoenke@gwdg.de +-L: linux-kernel@vger.kernel.org +-S: Maintained +- + NTFS FILESYSTEM + P: Anton Altaparmakov + M: aia21@cantab.net +@@ -2704,12 +2709,6 @@ L: osst-users@lists.sourceforge.net + L: linux-scsi@vger.kernel.org + S: Maintained + +-OPL3-SA2, SA3, and SAx DRIVER +-P: Zwane Mwaikambo +-M: zwane@arm.linux.org.uk +-L: linux-sound@vger.kernel.org +-S: Maintained +- + OPROFILE + P: Philippe Elie + M: phil.el@wanadoo.fr +@@ -2814,11 +2813,6 @@ P: Kristen Carlson Accardi + M: kristen.c.accardi@intel.com + S: Supported + +-PCI HOTPLUG COMPAQ DRIVER +-P: Greg Kroah-Hartman +-M: greg@kroah.com +-S: Maintained +- + PCIE HOTPLUG DRIVER + P: Kristen Carlson Accardi + M: kristen.c.accardi@intel.com +@@ -2868,6 +2862,16 @@ M: george@mvista.com + L: linux-kernel@vger.kernel.org + S: Supported + ++POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS ++P: Anton Vorontsov ++M: cbou@mail.ru ++P: David Woodhouse ++M: dwmw2@infradead.org ++L: linux-kernel@vger.kernel.org ++L: kernel-discuss@handhelds.org ++T: git git.infradead.org/battery-2.6.git ++S: Maintained ++ + POWERPC 4xx EMAC DRIVER + P: Eugene Surovegin + M: ebs@ebshome.net +@@ -2903,6 +2907,11 @@ P: Michal Ostrowski + M: mostrows@speakeasy.net + S: Maintained + ++PPP OVER L2TP ++P: James Chapman ++M: jchapman@katalix.com ++S: Maintained ++ + PREEMPTIBLE KERNEL + P: Robert Love + M: rml@tech9.net +@@ -2930,6 +2939,13 @@ M: mikpe@it.uu.se + L: linux-ide@vger.kernel.org + S: Maintained + ++PS3 NETWORK SUPPORT ++P: Masakazu Mokuno ++M: mokuno@sm.sony.co.jp ++L: netdev@vger.kernel.org ++L: cbe-oss-dev@ozlabs.org ++S: Supported ++ + PS3 PLATFORM SUPPORT + P: Geoff Levand + M: geoffrey.levand@am.sony.com +@@ -3049,6 +3065,16 @@ S: Maintained + RISCOM8 DRIVER + S: Orphan + ++RTL818X WIRELESS DRIVER ++P: Michael Wu ++M: flamingice@sourmilk.net ++P: Andrea Merello ++M: andreamrl@tiscali.it ++L: linux-wireless@vger.kernel.org ++W: http://linuxwireless.org/ ++T: git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git ++S: Maintained ++ + S3 SAVAGE FRAMEBUFFER DRIVER + P: Antonino Daplas + M: adaplas@gmail.com +@@ -3087,12 +3113,6 @@ M: michael@mihu.de + W: http://www.mihu.de/linux/saa7146 + S: Maintained + +-SBPCD CDROM DRIVER +-P: Eberhard Moenkeberg +-M: emoenke@gwdg.de +-L: linux-kernel@vger.kernel.org +-S: Maintained +- + SC1200 WDT DRIVER + P: Zwane Mwaikambo + M: zwane@arm.linux.org.uk +@@ -3707,12 +3727,12 @@ L: netdev@vger.kernel.org + W: http://pegasus2.sourceforge.net/ + S: Maintained + +-USB PRINTER DRIVER +-P: Vojtech Pavlik +-M: vojtech@suse.cz ++USB PRINTER DRIVER (usblp) ++P: Pete Zaitcev ++M: zaitcev@redhat.com + L: linux-usb-users@lists.sourceforge.net + L: linux-usb-devel@lists.sourceforge.net +-S: Maintained ++S: Supported + + USB RTL8150 DRIVER + P: Petko Manolov +@@ -4098,6 +4118,11 @@ W: http://www.polyware.nl/~middelin/En/h + W: http://www.polyware.nl/~middelin/hobbies.html + S: Maintained + ++ZS DECSTATION Z85C30 SERIAL DRIVER ++P: Maciej W. Rozycki ++M: macro@linux-mips.org ++S: Maintained ++ + THE REST + P: Linus Torvalds + S: Buried alive in reporters +diff -Nurp linux-2.6.22/Makefile linux-2.6-netns/Makefile +--- linux-2.6.22/Makefile 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/Makefile 2007-12-03 23:14:12.000000000 -0500 +@@ -313,7 +313,8 @@ LINUXINCLUDE := -Iinclude \ + CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE) + + CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ +- -fno-strict-aliasing -fno-common ++ -fno-strict-aliasing -fno-common \ ++ -Werror-implicit-function-declaration + AFLAGS := -D__ASSEMBLY__ + + # Read KERNELRELEASE from include/config/kernel.release (if it exists) +diff -Nurp linux-2.6.22/arch/alpha/Kconfig linux-2.6-netns/arch/alpha/Kconfig +--- linux-2.6.22/arch/alpha/Kconfig 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/alpha/Kconfig 2007-12-03 23:14:12.000000000 -0500 +@@ -327,6 +327,9 @@ config PCI_DOMAINS + bool + default y + ++config PCI_SYSCALL ++ def_bool PCI ++ + config ALPHA_CORE_AGP + bool + depends on ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL +diff -Nurp linux-2.6.22/arch/alpha/kernel/pci_iommu.c linux-2.6-netns/arch/alpha/kernel/pci_iommu.c +--- linux-2.6.22/arch/alpha/kernel/pci_iommu.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/alpha/kernel/pci_iommu.c 2007-12-03 23:14:12.000000000 -0500 +@@ -207,6 +207,10 @@ iommu_arena_free(struct pci_iommu_arena + p[i] = 0; + } + ++/* True if the machine supports DAC addressing, and DEV can ++ make use of it given MASK. */ ++static int pci_dac_dma_supported(struct pci_dev *hwdev, u64 mask); ++ + /* Map a single buffer of the indicated size for PCI DMA in streaming + mode. The 32-bit PCI bus mastering address to use is returned. + Once the device is given the dma address, the device owns this memory +@@ -897,7 +901,7 @@ iommu_unbind(struct pci_iommu_arena *are + /* True if the machine supports DAC addressing, and DEV can + make use of it given MASK. */ + +-int ++static int + pci_dac_dma_supported(struct pci_dev *dev, u64 mask) + { + dma64_addr_t dac_offset = alpha_mv.pci_dac_offset; +@@ -917,32 +921,6 @@ pci_dac_dma_supported(struct pci_dev *de + + return ok; + } +-EXPORT_SYMBOL(pci_dac_dma_supported); +- +-dma64_addr_t +-pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, +- unsigned long offset, int direction) +-{ +- return (alpha_mv.pci_dac_offset +- + __pa(page_address(page)) +- + (dma64_addr_t) offset); +-} +-EXPORT_SYMBOL(pci_dac_page_to_dma); +- +-struct page * +-pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) +-{ +- unsigned long paddr = (dma_addr & PAGE_MASK) - alpha_mv.pci_dac_offset; +- return virt_to_page(__va(paddr)); +-} +-EXPORT_SYMBOL(pci_dac_dma_to_page); +- +-unsigned long +-pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) +-{ +- return (dma_addr & ~PAGE_MASK); +-} +-EXPORT_SYMBOL(pci_dac_dma_to_offset); + + /* Helper for generic DMA-mapping functions. */ + +diff -Nurp linux-2.6.22/arch/alpha/kernel/ptrace.c linux-2.6-netns/arch/alpha/kernel/ptrace.c +--- linux-2.6.22/arch/alpha/kernel/ptrace.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/alpha/kernel/ptrace.c 2007-12-03 23:14:12.000000000 -0500 +@@ -315,9 +315,7 @@ do_sys_ptrace(long request, long pid, lo + /* When I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: +- tmp = data; +- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1); +- ret = (copied == sizeof(tmp)) ? 0 : -EIO; ++ ret = generic_ptrace_pokedata(child, addr, data); + break; + + case PTRACE_POKEUSR: /* write the specified register */ +diff -Nurp linux-2.6.22/arch/alpha/kernel/smp.c linux-2.6-netns/arch/alpha/kernel/smp.c +--- linux-2.6.22/arch/alpha/kernel/smp.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/alpha/kernel/smp.c 2007-12-03 23:14:12.000000000 -0500 +@@ -65,7 +65,7 @@ enum ipi_message_type { + }; + + /* Set to a secondary's cpuid when it comes online. */ +-static int smp_secondary_alive __initdata = 0; ++static int smp_secondary_alive __devinitdata = 0; + + /* Which cpus ids came online. */ + cpumask_t cpu_online_map; +@@ -173,7 +173,7 @@ smp_callin(void) + } + + /* Wait until hwrpb->txrdy is clear for cpu. Return -1 on timeout. */ +-static int __init ++static int __devinit + wait_for_txrdy (unsigned long cpumask) + { + unsigned long timeout; +@@ -358,7 +358,7 @@ secondary_cpu_start(int cpuid, struct ta + /* + * Bring one cpu online. + */ +-static int __init ++static int __devinit + smp_boot_one_cpu(int cpuid) + { + struct task_struct *idle; +diff -Nurp linux-2.6.22/arch/alpha/kernel/srmcons.c linux-2.6-netns/arch/alpha/kernel/srmcons.c +--- linux-2.6.22/arch/alpha/kernel/srmcons.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/alpha/kernel/srmcons.c 2007-12-03 23:06:33.000000000 -0500 +@@ -289,7 +289,7 @@ srm_console_device(struct console *co, i + return srmcons_driver; + } + +-static int __init ++static int + srm_console_setup(struct console *co, char *options) + { + return 0; +diff -Nurp linux-2.6.22/arch/alpha/kernel/sys_marvel.c linux-2.6-netns/arch/alpha/kernel/sys_marvel.c +--- linux-2.6.22/arch/alpha/kernel/sys_marvel.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/alpha/kernel/sys_marvel.c 2007-12-03 23:06:33.000000000 -0500 +@@ -420,7 +420,7 @@ marvel_init_pci(void) + io7_clear_errors(io7); + } + +-static void ++static void __init + marvel_init_rtc(void) + { + init_rtc_irq(); +diff -Nurp linux-2.6.22/arch/alpha/kernel/time.c linux-2.6-netns/arch/alpha/kernel/time.c +--- linux-2.6.22/arch/alpha/kernel/time.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/alpha/kernel/time.c 2007-12-03 23:06:33.000000000 -0500 +@@ -144,7 +144,7 @@ irqreturn_t timer_interrupt(int irq, voi + return IRQ_HANDLED; + } + +-void ++void __init + common_init_rtc(void) + { + unsigned char x; +diff -Nurp linux-2.6.22/arch/alpha/kernel/traps.c linux-2.6-netns/arch/alpha/kernel/traps.c +--- linux-2.6.22/arch/alpha/kernel/traps.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/alpha/kernel/traps.c 2007-12-03 23:14:12.000000000 -0500 +@@ -184,6 +184,7 @@ die_if_kernel(char * str, struct pt_regs + #endif + printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); + dik_show_regs(regs, r9_15); ++ add_taint(TAINT_DIE); + dik_show_trace((unsigned long *)(regs+1)); + dik_show_code((unsigned int *)regs->pc); + +diff -Nurp linux-2.6.22/arch/alpha/lib/checksum.c linux-2.6-netns/arch/alpha/lib/checksum.c +--- linux-2.6.22/arch/alpha/lib/checksum.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/alpha/lib/checksum.c 2007-12-03 23:14:12.000000000 -0500 +@@ -69,6 +69,7 @@ __wsum csum_tcpudp_nofold(__be32 saddr, + result = (result & 0xffffffff) + (result >> 32); + return (__force __wsum)result; + } ++EXPORT_SYMBOL(csum_tcpudp_nofold); + + /* + * Do a 64-bit checksum on an arbitrary memory area.. +diff -Nurp linux-2.6.22/arch/arm/Kconfig linux-2.6-netns/arch/arm/Kconfig +--- linux-2.6.22/arch/arm/Kconfig 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/Kconfig 2007-12-03 23:14:12.000000000 -0500 +@@ -241,6 +241,9 @@ config ARCH_H720X + + config ARCH_IMX + bool "IMX" ++ select GENERIC_GPIO ++ select GENERIC_TIME ++ select GENERIC_CLOCKEVENTS + help + Support for Motorola's i.MX family of processors (MX1, MXL). + +@@ -308,6 +311,7 @@ config ARCH_L7200 + + config ARCH_KS8695 + bool "Micrel/Kendin KS8695" ++ select GENERIC_GPIO + help + Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based + System-on-Chip devices. +@@ -384,6 +388,7 @@ config ARCH_DAVINCI + bool "TI DaVinci" + select GENERIC_TIME + select GENERIC_CLOCKEVENTS ++ select GENERIC_GPIO + help + Support for TI's DaVinci platform. + +@@ -531,6 +536,9 @@ config PCI + information about which PCI hardware does work under Linux and which + doesn't. + ++config PCI_SYSCALL ++ def_bool PCI ++ + # Select the host bridge type + config PCI_HOST_VIA82C505 + bool +@@ -1034,6 +1042,8 @@ source "drivers/mmc/Kconfig" + + source "drivers/rtc/Kconfig" + ++source "drivers/dma/Kconfig" ++ + endmenu + + source "fs/Kconfig" +diff -Nurp linux-2.6.22/arch/arm/boot/compressed/.gitignore linux-2.6-netns/arch/arm/boot/compressed/.gitignore +--- linux-2.6.22/arch/arm/boot/compressed/.gitignore 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/boot/compressed/.gitignore 2007-12-03 23:06:33.000000000 -0500 +@@ -1 +1,2 @@ + piggy.gz ++font.c +diff -Nurp linux-2.6.22/arch/arm/boot/compressed/Makefile linux-2.6-netns/arch/arm/boot/compressed/Makefile +--- linux-2.6.22/arch/arm/boot/compressed/Makefile 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/boot/compressed/Makefile 2007-12-03 23:14:12.000000000 -0500 +@@ -6,15 +6,13 @@ + + HEAD = head.o + OBJS = misc.o +-FONTC = drivers/video/console/font_acorn_8x8.c +- +-FONT = $(addprefix ../../../../drivers/video/console/, font_acorn_8x8.o) ++FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c + + # + # Architecture dependencies + # + ifeq ($(CONFIG_ARCH_ACORN),y) +-OBJS += ll_char_wr.o $(FONT) ++OBJS += ll_char_wr.o font.o + endif + + ifeq ($(CONFIG_ARCH_SHARK),y) +@@ -73,7 +71,7 @@ endif + + SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ + +-targets := vmlinux vmlinux.lds piggy.gz piggy.o $(FONT) \ ++targets := vmlinux vmlinux.lds piggy.gz piggy.o font.o font.c \ + head.o misc.o $(OBJS) + EXTRA_CFLAGS := -fpic + EXTRA_AFLAGS := +@@ -105,7 +103,10 @@ $(obj)/piggy.gz: $(obj)/../Image FORCE + + $(obj)/piggy.o: $(obj)/piggy.gz FORCE + +-CFLAGS_font_acorn_8x8.o := -Dstatic= ++CFLAGS_font.o := -Dstatic= ++ ++$(obj)/font.c: $(FONTC) ++ $(call cmd,shipped) + + $(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config + @sed "$(SEDFLAGS)" < $< > $@ +diff -Nurp linux-2.6.22/arch/arm/boot/compressed/head-xscale.S linux-2.6-netns/arch/arm/boot/compressed/head-xscale.S +--- linux-2.6.22/arch/arm/boot/compressed/head-xscale.S 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/boot/compressed/head-xscale.S 2007-12-03 23:14:12.000000000 -0500 +@@ -41,11 +41,6 @@ __XScale_start: + mov r7, #MACH_TYPE_COTULLA_IDP + #endif + +-#ifdef CONFIG_MACH_GTWX5715 +- mov r7, #(MACH_TYPE_GTWX5715 & 0xff) +- orr r7, r7, #(MACH_TYPE_GTWX5715 & 0xff00) +-#endif +- + #ifdef CONFIG_ARCH_IXP2000 + mov r1, #-1 + mov r0, #0xd6000000 +diff -Nurp linux-2.6.22/arch/arm/boot/compressed/head.S linux-2.6-netns/arch/arm/boot/compressed/head.S +--- linux-2.6.22/arch/arm/boot/compressed/head.S 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/boot/compressed/head.S 2007-12-03 23:14:12.000000000 -0500 +@@ -436,6 +436,28 @@ __armv4_mmu_cache_on: + mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs + mov pc, r12 + ++__armv7_mmu_cache_on: ++ mov r12, lr ++ mrc p15, 0, r11, c0, c1, 4 @ read ID_MMFR0 ++ tst r11, #0xf @ VMSA ++ blne __setup_mmu ++ mov r0, #0 ++ mcr p15, 0, r0, c7, c10, 4 @ drain write buffer ++ tst r11, #0xf @ VMSA ++ mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs ++ mrc p15, 0, r0, c1, c0, 0 @ read control reg ++ orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement ++ orr r0, r0, #0x003c @ write buffer ++ orrne r0, r0, #1 @ MMU enabled ++ movne r1, #-1 ++ mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer ++ mcrne p15, 0, r1, c3, c0, 0 @ load domain access control ++ mcr p15, 0, r0, c1, c0, 0 @ load control register ++ mrc p15, 0, r0, c1, c0, 0 @ and read it back ++ mov r0, #0 ++ mcr p15, 0, r0, c7, c5, 4 @ ISB ++ mov pc, r12 ++ + __arm6_mmu_cache_on: + mov r12, lr + bl __setup_mmu +@@ -622,11 +644,17 @@ proc_types: + b __armv4_mmu_cache_flush + + .word 0x0007b000 @ ARMv6 +- .word 0x0007f000 ++ .word 0x000ff000 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + b __armv6_mmu_cache_flush + ++ .word 0x000f0000 @ new CPU Id ++ .word 0x000f0000 ++ b __armv7_mmu_cache_on ++ b __armv7_mmu_cache_off ++ b __armv7_mmu_cache_flush ++ + .word 0 @ unrecognised type + .word 0 + mov pc, lr +@@ -674,6 +702,16 @@ __armv4_mmu_cache_off: + mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4 + mov pc, lr + ++__armv7_mmu_cache_off: ++ mrc p15, 0, r0, c1, c0 ++ bic r0, r0, #0x000d ++ mcr p15, 0, r0, c1, c0 @ turn MMU and cache off ++ mov r12, lr ++ bl __armv7_mmu_cache_flush ++ mov r0, #0 ++ mcr p15, 0, r0, c8, c7, 0 @ invalidate whole TLB ++ mov pc, r12 ++ + __arm6_mmu_cache_off: + mov r0, #0x00000030 @ ARM6 control reg. + b __armv3_mmu_cache_off +@@ -730,6 +768,59 @@ __armv6_mmu_cache_flush: + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + ++__armv7_mmu_cache_flush: ++ mrc p15, 0, r10, c0, c1, 5 @ read ID_MMFR1 ++ tst r10, #0xf << 16 @ hierarchical cache (ARMv7) ++ beq hierarchical ++ mov r10, #0 ++ mcr p15, 0, r10, c7, c14, 0 @ clean+invalidate D ++ b iflush ++hierarchical: ++ stmfd sp!, {r0-r5, r7, r9-r11} ++ mrc p15, 1, r0, c0, c0, 1 @ read clidr ++ ands r3, r0, #0x7000000 @ extract loc from clidr ++ mov r3, r3, lsr #23 @ left align loc bit field ++ beq finished @ if loc is 0, then no need to clean ++ mov r10, #0 @ start clean at cache level 0 ++loop1: ++ add r2, r10, r10, lsr #1 @ work out 3x current cache level ++ mov r1, r0, lsr r2 @ extract cache type bits from clidr ++ and r1, r1, #7 @ mask of the bits for current cache only ++ cmp r1, #2 @ see what cache we have at this level ++ blt skip @ skip if no cache, or just i-cache ++ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr ++ mcr p15, 0, r10, c7, c5, 4 @ isb to sych the new cssr&csidr ++ mrc p15, 1, r1, c0, c0, 0 @ read the new csidr ++ and r2, r1, #7 @ extract the length of the cache lines ++ add r2, r2, #4 @ add 4 (line length offset) ++ ldr r4, =0x3ff ++ ands r4, r4, r1, lsr #3 @ find maximum number on the way size ++ .word 0xe16f5f14 @ clz r5, r4 - find bit position of way size increment ++ ldr r7, =0x7fff ++ ands r7, r7, r1, lsr #13 @ extract max number of the index size ++loop2: ++ mov r9, r4 @ create working copy of max way size ++loop3: ++ orr r11, r10, r9, lsl r5 @ factor way and cache number into r11 ++ orr r11, r11, r7, lsl r2 @ factor index number into r11 ++ mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way ++ subs r9, r9, #1 @ decrement the way ++ bge loop3 ++ subs r7, r7, #1 @ decrement the index ++ bge loop2 ++skip: ++ add r10, r10, #2 @ increment cache number ++ cmp r3, r10 ++ bgt loop1 ++finished: ++ mov r10, #0 @ swith back to cache level 0 ++ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr ++ ldmfd sp!, {r0-r5, r7, r9-r11} ++iflush: ++ mcr p15, 0, r10, c7, c5, 0 @ invalidate I+BTB ++ mcr p15, 0, r10, c7, c10, 4 @ drain WB ++ mov pc, lr ++ + __armv4_mmu_cache_flush: + mov r2, #64*1024 @ default: 32K dcache size (*2) + mov r11, #32 @ default: 32 byte line size +diff -Nurp linux-2.6.22/arch/arm/common/locomo.c linux-2.6-netns/arch/arm/common/locomo.c +--- linux-2.6.22/arch/arm/common/locomo.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/common/locomo.c 2007-12-03 23:06:33.000000000 -0500 +@@ -60,6 +60,9 @@ struct locomo { + unsigned int irq; + spinlock_t lock; + void __iomem *base; ++#ifdef CONFIG_PM ++ void *saved_state; ++#endif + }; + + struct locomo_dev_info { +@@ -565,7 +568,7 @@ static int locomo_suspend(struct platfor + if (!save) + return -ENOMEM; + +- dev->dev.power.saved_state = (void *) save; ++ lchip->saved_state = save; + + spin_lock_irqsave(&lchip->lock, flags); + +@@ -605,8 +608,8 @@ static int locomo_resume(struct platform + struct locomo_save_data *save; + unsigned long r; + unsigned long flags; +- +- save = (struct locomo_save_data *) dev->dev.power.saved_state; ++ ++ save = lchip->saved_state; + if (!save) + return 0; + +@@ -628,6 +631,8 @@ static int locomo_resume(struct platform + locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD); + + spin_unlock_irqrestore(&lchip->lock, flags); ++ ++ lchip->saved_state = NULL; + kfree(save); + + return 0; +diff -Nurp linux-2.6.22/arch/arm/common/sa1111.c linux-2.6-netns/arch/arm/common/sa1111.c +--- linux-2.6.22/arch/arm/common/sa1111.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/common/sa1111.c 2007-12-03 23:06:33.000000000 -0500 +@@ -51,6 +51,9 @@ struct sa1111 { + int irq; + spinlock_t lock; + void __iomem *base; ++#ifdef CONFIG_PM ++ void *saved_state; ++#endif + }; + + /* +@@ -822,7 +825,7 @@ static int sa1111_suspend(struct platfor + save = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL); + if (!save) + return -ENOMEM; +- dev->dev.power.saved_state = save; ++ sachip->saved_state = save; + + spin_lock_irqsave(&sachip->lock, flags); + +@@ -878,7 +881,7 @@ static int sa1111_resume(struct platform + unsigned long flags, id; + void __iomem *base; + +- save = (struct sa1111_save_data *)dev->dev.power.saved_state; ++ save = sachip->saved_state; + if (!save) + return 0; + +@@ -923,7 +926,7 @@ static int sa1111_resume(struct platform + + spin_unlock_irqrestore(&sachip->lock, flags); + +- dev->dev.power.saved_state = NULL; ++ sachip->saved_state = NULL; + kfree(save); + + return 0; +@@ -958,8 +961,8 @@ static int sa1111_remove(struct platform + platform_set_drvdata(pdev, NULL); + + #ifdef CONFIG_PM +- kfree(pdev->dev.power.saved_state); +- pdev->dev.power.saved_state = NULL; ++ kfree(sachip->saved_state); ++ sachip->saved_state = NULL; + #endif + } + +diff -Nurp linux-2.6.22/arch/arm/common/sharpsl_pm.c linux-2.6-netns/arch/arm/common/sharpsl_pm.c +--- linux-2.6.22/arch/arm/common/sharpsl_pm.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/common/sharpsl_pm.c 2007-12-03 23:14:12.000000000 -0500 +@@ -766,9 +766,7 @@ static void sharpsl_apm_get_power_status + } + + static struct pm_ops sharpsl_pm_ops = { +- .prepare = pxa_pm_prepare, + .enter = corgi_pxa_pm_enter, +- .finish = pxa_pm_finish, + .valid = pm_valid_only_mem, + }; + +diff -Nurp linux-2.6.22/arch/arm/kernel/head-common.S linux-2.6-netns/arch/arm/kernel/head-common.S +--- linux-2.6.22/arch/arm/kernel/head-common.S 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/kernel/head-common.S 2007-12-03 23:06:33.000000000 -0500 +@@ -20,7 +20,8 @@ __switch_data: + .long _end @ r7 + .long processor_id @ r4 + .long __machine_arch_type @ r5 +- .long cr_alignment @ r6 ++ .long __atags_pointer @ r6 ++ .long cr_alignment @ r7 + .long init_thread_union + THREAD_START_SP @ sp + + /* +@@ -29,6 +30,7 @@ __switch_data: + * + * r0 = cp#15 control register + * r1 = machine ID ++ * r2 = atags pointer + * r9 = processor ID + */ + .type __mmap_switched, %function +@@ -47,11 +49,12 @@ __mmap_switched: + strcc fp, [r6],#4 + bcc 1b + +- ldmia r3, {r4, r5, r6, sp} ++ ldmia r3, {r4, r5, r6, r7, sp} + str r9, [r4] @ Save processor ID + str r1, [r5] @ Save machine type ++ str r2, [r6] @ Save atags pointer + bic r4, r0, #CR_A @ Clear 'A' bit +- stmia r6, {r0, r4} @ Save control register values ++ stmia r7, {r0, r4} @ Save control register values + b start_kernel + + /* +@@ -215,3 +218,34 @@ ENTRY(lookup_machine_type) + bl __lookup_machine_type + mov r0, r5 + ldmfd sp!, {r4 - r6, pc} ++ ++/* Determine validity of the r2 atags pointer. The heuristic requires ++ * that the pointer be aligned, in the first 16k of physical RAM and ++ * that the ATAG_CORE marker is first and present. Future revisions ++ * of this function may be more lenient with the physical address and ++ * may also be able to move the ATAGS block if necessary. ++ * ++ * r8 = machinfo ++ * ++ * Returns: ++ * r2 either valid atags pointer, or zero ++ * r5, r6 corrupted ++ */ ++ ++ .type __vet_atags, %function ++__vet_atags: ++ tst r2, #0x3 @ aligned? ++ bne 1f ++ ++ ldr r5, [r2, #0] @ is first tag ATAG_CORE? ++ subs r5, r5, #ATAG_CORE_SIZE ++ bne 1f ++ ldr r5, [r2, #4] ++ ldr r6, =ATAG_CORE ++ cmp r5, r6 ++ bne 1f ++ ++ mov pc, lr @ atag pointer is ok ++ ++1: mov r2, #0 ++ mov pc, lr +diff -Nurp linux-2.6.22/arch/arm/kernel/head.S linux-2.6-netns/arch/arm/kernel/head.S +--- linux-2.6.22/arch/arm/kernel/head.S 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/kernel/head.S 2007-12-03 23:06:33.000000000 -0500 +@@ -29,6 +29,10 @@ + #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) + #define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET) + ++#define ATAG_CORE 0x54410001 ++#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) ++ ++ + /* + * swapper_pg_dir is the virtual address of the initial page table. + * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must +@@ -61,7 +65,7 @@ + * + * This is normally called from the decompressor code. The requirements + * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, +- * r1 = machine nr. ++ * r1 = machine nr, r2 = atags pointer. + * + * This code is mostly position independent, so if you link the kernel at + * 0xc0008000, you call this at __pa(0xc0008000). +@@ -85,6 +89,7 @@ ENTRY(stext) + bl __lookup_machine_type @ r5=machinfo + movs r8, r5 @ invalid machine (r5=0)? + beq __error_a @ yes, error 'a' ++ bl __vet_atags + bl __create_page_tables + + /* +diff -Nurp linux-2.6.22/arch/arm/kernel/process.c linux-2.6-netns/arch/arm/kernel/process.c +--- linux-2.6.22/arch/arm/kernel/process.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/kernel/process.c 2007-12-03 23:14:12.000000000 -0500 +@@ -44,6 +44,10 @@ static const char *processor_modes[] = { + "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32" + }; + ++static const char *isa_modes[] = { ++ "ARM" , "Thumb" , "Jazelle", "ThumbEE" ++}; ++ + extern void setup_mm_for_reboot(char mode); + + static volatile int hlt_counter; +@@ -230,11 +234,11 @@ void __show_regs(struct pt_regs *regs) + buf[3] = flags & PSR_V_BIT ? 'V' : 'v'; + buf[4] = '\0'; + +- printk("Flags: %s IRQs o%s FIQs o%s Mode %s%s Segment %s\n", ++ printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n", + buf, interrupts_enabled(regs) ? "n" : "ff", + fast_interrupts_enabled(regs) ? "n" : "ff", + processor_modes[processor_mode(regs)], +- thumb_mode(regs) ? " (T)" : "", ++ isa_modes[isa_mode(regs)], + get_fs() == get_ds() ? "kernel" : "user"); + #ifdef CONFIG_CPU_CP15 + { +diff -Nurp linux-2.6.22/arch/arm/kernel/ptrace.c linux-2.6-netns/arch/arm/kernel/ptrace.c +--- linux-2.6.22/arch/arm/kernel/ptrace.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/kernel/ptrace.c 2007-12-03 23:14:12.000000000 -0500 +@@ -657,7 +657,6 @@ static int ptrace_setcrunchregs(struct t + + long arch_ptrace(struct task_struct *child, long request, long addr, long data) + { +- unsigned long tmp; + int ret; + + switch (request) { +@@ -666,12 +665,7 @@ long arch_ptrace(struct task_struct *chi + */ + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: +- ret = access_process_vm(child, addr, &tmp, +- sizeof(unsigned long), 0); +- if (ret == sizeof(unsigned long)) +- ret = put_user(tmp, (unsigned long __user *) data); +- else +- ret = -EIO; ++ ret = generic_ptrace_peekdata(child, addr, data); + break; + + case PTRACE_PEEKUSR: +@@ -683,12 +677,7 @@ long arch_ptrace(struct task_struct *chi + */ + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: +- ret = access_process_vm(child, addr, &data, +- sizeof(unsigned long), 1); +- if (ret == sizeof(unsigned long)) +- ret = 0; +- else +- ret = -EIO; ++ ret = generic_ptrace_pokedata(child, addr, data); + break; + + case PTRACE_POKEUSR: +diff -Nurp linux-2.6.22/arch/arm/kernel/setup.c linux-2.6-netns/arch/arm/kernel/setup.c +--- linux-2.6.22/arch/arm/kernel/setup.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/kernel/setup.c 2007-12-03 23:14:12.000000000 -0500 +@@ -63,6 +63,8 @@ unsigned int processor_id; + unsigned int __machine_arch_type; + EXPORT_SYMBOL(__machine_arch_type); + ++unsigned int __atags_pointer __initdata; ++ + unsigned int system_rev; + EXPORT_SYMBOL(system_rev); + +@@ -780,7 +782,9 @@ void __init setup_arch(char **cmdline_p) + if (mdesc->soft_reboot) + reboot_setup("s"); + +- if (mdesc->boot_params) ++ if (__atags_pointer) ++ tags = phys_to_virt(__atags_pointer); ++ else if (mdesc->boot_params) + tags = phys_to_virt(mdesc->boot_params); + + /* +diff -Nurp linux-2.6.22/arch/arm/kernel/traps.c linux-2.6-netns/arch/arm/kernel/traps.c +--- linux-2.6.22/arch/arm/kernel/traps.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/kernel/traps.c 2007-12-03 23:14:12.000000000 -0500 +@@ -249,6 +249,7 @@ NORET_TYPE void die(const char *str, str + bust_spinlocks(1); + __die(str, err, thread, regs); + bust_spinlocks(0); ++ add_taint(TAINT_DIE); + spin_unlock_irq(&die_lock); + + if (in_interrupt()) +diff -Nurp linux-2.6.22/arch/arm/mach-at91/board-csb337.c linux-2.6-netns/arch/arm/mach-at91/board-csb337.c +--- linux-2.6.22/arch/arm/mach-at91/board-csb337.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/mach-at91/board-csb337.c 2007-12-03 23:06:33.000000000 -0500 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -83,6 +84,13 @@ static struct at91_udc_data __initdata c + .pullup_pin = AT91_PIN_PA24, + }; + ++static struct i2c_board_info __initdata csb337_i2c_devices[] = { ++ { I2C_BOARD_INFO("rtc-ds1307", 0x68), ++ .type = "ds1307", ++ }, ++}; ++ ++ + static struct at91_cf_data __initdata csb337_cf_data = { + /* + * connector P4 on the CSB 337 mates to +@@ -161,6 +169,8 @@ static void __init csb337_board_init(voi + at91_add_device_udc(&csb337_udc_data); + /* I2C */ + at91_add_device_i2c(); ++ i2c_register_board_info(0, csb337_i2c_devices, ++ ARRAY_SIZE(csb337_i2c_devices)); + /* Compact Flash */ + at91_set_gpio_input(AT91_PIN_PB22, 1); /* IOIS16 */ + at91_add_device_cf(&csb337_cf_data); +diff -Nurp linux-2.6.22/arch/arm/mach-at91/board-sam9261ek.c linux-2.6-netns/arch/arm/mach-at91/board-sam9261ek.c +--- linux-2.6.22/arch/arm/mach-at91/board-sam9261ek.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6-netns/arch/arm/mach-at91/board-sam9261ek.c 2007-12-03 23:06:33.000000000 -0500 +@@ -27,6 +27,11 @@ + #include + #include + #include ++#include ++#include ++#include ++ ++#include