Applying e1000e patch to the Debian 2.6.26 kernel
Hi there,
There's more and more e1000e hardware around these days, and I was
wondering if it was possible to have the attached patch applied to the
current kernel of Lenny. This patch, I made it by taking the sources
from 2.6.27 and back porting it. I tested it, and my ethernet e1000e was
seen and working. Maybe that could be added to the next point release of
Debian (Lenny and a half)? I think it's a quite safe patch...
Thanks for your attention,
Thomas
P.S: Please Cc: to me for this thread, I'm not registered to this list
(I know I shouldn't be asking this, sorry...).
diff -u -r linux-source-2.6.26.orig/drivers/net/e1000e/defines.h linux-source-2.6.26/drivers/net/e1000e/defines.h
--- linux-source-2.6.26.orig/drivers/net/e1000e/defines.h 2008-12-18 17:55:01.000000000 +0800
+++ linux-source-2.6.26/drivers/net/e1000e/defines.h 2008-12-18 17:56:21.000000000 +0800
@@ -389,7 +389,7 @@
/* Interrupt Cause Set */
#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
-#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* Rx sequence error */
#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* Rx desc min. threshold */
/* Transmit Descriptor Control */
diff -u -r linux-source-2.6.26.orig/drivers/net/e1000e/e1000.h linux-source-2.6.26/drivers/net/e1000e/e1000.h
--- linux-source-2.6.26.orig/drivers/net/e1000e/e1000.h 2008-12-18 17:55:01.000000000 +0800
+++ linux-source-2.6.26/drivers/net/e1000e/e1000.h 2008-12-18 17:56:21.000000000 +0800
@@ -41,24 +41,25 @@
struct e1000_info;
-#define ndev_printk(level, netdev, format, arg...) \
- printk(level "%s: " format, (netdev)->name, ## arg)
+#define e_printk(level, adapter, format, arg...) \
+ printk(level "%s: %s: " format, pci_name(adapter->pdev), \
+ adapter->netdev->name, ## arg)
#ifdef DEBUG
-#define ndev_dbg(netdev, format, arg...) \
- ndev_printk(KERN_DEBUG , netdev, format, ## arg)
+#define e_dbg(format, arg...) \
+ e_printk(KERN_DEBUG , adapter, format, ## arg)
#else
-#define ndev_dbg(netdev, format, arg...) do { (void)(netdev); } while (0)
+#define e_dbg(format, arg...) do { (void)(adapter); } while (0)
#endif
-#define ndev_err(netdev, format, arg...) \
- ndev_printk(KERN_ERR , netdev, format, ## arg)
-#define ndev_info(netdev, format, arg...) \
- ndev_printk(KERN_INFO , netdev, format, ## arg)
-#define ndev_warn(netdev, format, arg...) \
- ndev_printk(KERN_WARNING , netdev, format, ## arg)
-#define ndev_notice(netdev, format, arg...) \
- ndev_printk(KERN_NOTICE , netdev, format, ## arg)
+#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)
/* Tx/Rx descriptor defines */
@@ -256,7 +257,6 @@
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;
@@ -283,6 +283,8 @@
unsigned long led_status;
unsigned int flags;
+ struct work_struct downshift_task;
+ struct work_struct update_phy_task;
};
struct e1000_info {
@@ -304,6 +306,7 @@
#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_READ_ONLY_NVM (1 << 8)
#define FLAG_IS_ICH (1 << 9)
#define FLAG_HAS_SMART_POWER_DOWN (1 << 11)
#define FLAG_IS_QUAD_PORT_A (1 << 12)
@@ -325,6 +328,7 @@
#define FLAG_RX_CSUM_ENABLED (1 << 28)
#define FLAG_TSO_FORCE (1 << 29)
#define FLAG_RX_RESTART_NOW (1 << 30)
+#define FLAG_MSI_TEST_FAILED (1 << 31)
#define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
@@ -383,6 +387,7 @@
extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
+extern void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw);
extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
bool state);
extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
diff -u -r linux-source-2.6.26.orig/drivers/net/e1000e/ethtool.c linux-source-2.6.26/drivers/net/e1000e/ethtool.c
--- linux-source-2.6.26.orig/drivers/net/e1000e/ethtool.c 2008-12-18 17:55:01.000000000 +0800
+++ linux-source-2.6.26/drivers/net/e1000e/ethtool.c 2008-12-18 18:19:49.000000000 +0800
@@ -177,7 +177,7 @@
u32 status;
status = er32(STATUS);
- return (status & E1000_STATUS_LU);
+ return (status & E1000_STATUS_LU) ? 1 : 0;
}
static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
@@ -189,8 +189,7 @@
/* Fiber NICs only allow 1000 gbps Full duplex */
if ((adapter->hw.phy.media_type == e1000_media_type_fiber) &&
spddplx != (SPEED_1000 + DUPLEX_FULL)) {
- ndev_err(adapter->netdev, "Unsupported Speed/Duplex "
- "configuration\n");
+ e_err("Unsupported Speed/Duplex configuration\n");
return -EINVAL;
}
@@ -213,8 +212,7 @@
break;
case SPEED_1000 + DUPLEX_HALF: /* not supported */
default:
- ndev_err(adapter->netdev, "Unsupported Speed/Duplex "
- "configuration\n");
+ e_err("Unsupported Speed/Duplex configuration\n");
return -EINVAL;
}
return 0;
@@ -231,8 +229,8 @@
* cannot be changed
*/
if (e1000_check_reset_block(hw)) {
- ndev_err(netdev, "Cannot change link "
- "characteristics when SoL/IDER is active.\n");
+ e_err("Cannot change link characteristics when SoL/IDER is "
+ "active.\n");
return -EINVAL;
}
@@ -380,8 +378,7 @@
netdev->features &= ~NETIF_F_TSO6;
}
- ndev_info(netdev, "TSO is %s\n",
- data ? "Enabled" : "Disabled");
+ e_info("TSO is %s\n", data ? "Enabled" : "Disabled");
adapter->flags |= FLAG_TSO_FORCE;
return 0;
}
@@ -435,6 +432,10 @@
regs_buff[11] = er32(TIDV);
regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */
+
+ /* ethtool doesn't use anything past this point, so all this
+ * code is likely legacy junk for apps that may or may not
+ * exist */
if (hw->phy.type == e1000_phy_m88) {
e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
regs_buff[13] = (u32)phy_data; /* cable length */
@@ -450,7 +451,7 @@
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 */
+ regs_buff[21] = 0; /* was idle_errors */
e1e_rphy(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 */
@@ -532,6 +533,9 @@
if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16)))
return -EFAULT;
+ if (adapter->flags & FLAG_READ_ONLY_NVM)
+ return -EINVAL;
+
max_len = hw->nvm.word_size * 2;
first_word = eeprom->offset >> 1;
@@ -722,10 +726,9 @@
(test[pat] & write));
val = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset);
if (val != (test[pat] & write & mask)) {
- ndev_err(adapter->netdev, "pattern test reg %04X "
- "failed: got 0x%08X expected 0x%08X\n",
- reg + offset,
- 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;
}
@@ -740,9 +743,8 @@
__ew32(&adapter->hw, reg, write & mask);
val = __er32(&adapter->hw, reg);
if ((write & mask) != (val & mask)) {
- ndev_err(adapter->netdev, "set/check reg %04X test failed: "
- "got 0x%08X expected 0x%08X\n", reg, (val & mask),
- (write & 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;
}
@@ -766,7 +768,6 @@
{
struct e1000_hw *hw = &adapter->hw;
struct e1000_mac_info *mac = &adapter->hw.mac;
- struct net_device *netdev = adapter->netdev;
u32 value;
u32 before;
u32 after;
@@ -799,8 +800,8 @@
ew32(STATUS, toggle);
after = er32(STATUS) & toggle;
if (value != after) {
- ndev_err(netdev, "failed STATUS register test got: "
- "0x%08X expected: 0x%08X\n", after, value);
+ e_err("failed STATUS register test got: 0x%08X expected: "
+ "0x%08X\n", after, value);
*data = 1;
return 1;
}
@@ -903,8 +904,7 @@
*data = 1;
return -1;
}
- ndev_info(netdev, "testing %s interrupt\n",
- (shared_int ? "shared" : "unshared"));
+ e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared"));
/* Disable all the interrupts */
ew32(IMC, 0xFFFFFFFF);
@@ -1526,8 +1526,7 @@
* sessions are active
*/
if (e1000_check_reset_block(&adapter->hw)) {
- ndev_err(adapter->netdev, "Cannot do PHY loopback test "
- "when SoL/IDER is active.\n");
+ e_err("Cannot do PHY loopback test when SoL/IDER is active.\n");
*data = 0;
goto out;
}
@@ -1612,7 +1611,7 @@
forced_speed_duplex = adapter->hw.mac.forced_speed_duplex;
autoneg = adapter->hw.mac.autoneg;
- ndev_info(netdev, "offline testing starting\n");
+ e_info("offline testing starting\n");
/*
* Link test performed before hardware reset so autoneg doesn't
@@ -1658,7 +1657,7 @@
if (if_running)
dev_open(netdev);
} else {
- ndev_info(netdev, "online testing starting\n");
+ e_info("online testing starting\n");
/* Online tests */
if (e1000_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1694,8 +1693,8 @@
wol->supported &= ~WAKE_UCAST;
if (adapter->wol & E1000_WUFC_EX)
- ndev_err(netdev, "Interface does not support "
- "directed (unicast) frame wake-up packets\n");
+ e_err("Interface does not support directed (unicast) "
+ "frame wake-up packets\n");
}
if (adapter->wol & E1000_WUFC_EX)
diff -u -r linux-source-2.6.26.orig/drivers/net/e1000e/ich8lan.c linux-source-2.6.26/drivers/net/e1000e/ich8lan.c
--- linux-source-2.6.26.orig/drivers/net/e1000e/ich8lan.c 2008-12-18 17:55:01.000000000 +0800
+++ linux-source-2.6.26/drivers/net/e1000e/ich8lan.c 2008-12-19 17:34:45.000000000 +0800
@@ -58,6 +58,7 @@
#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
@@ -150,6 +151,19 @@
u16 regval;
};
+/* 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;
+};
+
static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
@@ -366,6 +380,26 @@
return 0;
}
+#ifndef __WARN
+#define __WARN() warn_on_slowpath(__FILE__, __LINE__)
+#define __WARN_printf(arg...) warn_slowpath(__FILE__, __LINE__, arg)
+#else
+#define __WARN_printf(arg...) __WARN()
+#endif
+
+#ifndef WARN
+#define WARN(condition, format...) ({ \
+ int __ret_warn_on = !!(condition); \
+ if (unlikely(__ret_warn_on)) \
+ __WARN_printf(format); \
+ unlikely(__ret_warn_on); \
+})
+#endif
+
+
+static DEFINE_MUTEX(nvm_mutex);
+static pid_t nvm_owner = -1;
+
/**
* e1000_acquire_swflag_ich8lan - Acquire software control flag
* @hw: pointer to the HW structure
@@ -379,6 +413,15 @@
u32 extcnf_ctrl;
u32 timeout = PHY_CFG_TIMEOUT;
+ might_sleep();
+
+ if (!mutex_trylock(&nvm_mutex)) {
+ WARN(1, KERN_ERR "e1000e mutex contention. Owned by pid %d\n",
+ nvm_owner);
+ mutex_lock(&nvm_mutex);
+ }
+ nvm_owner = current->pid;
+
while (timeout) {
extcnf_ctrl = er32(EXTCNF_CTRL);
extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
@@ -393,6 +436,8 @@
if (!timeout) {
hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
+ nvm_owner = -1;
+ mutex_unlock(&nvm_mutex);
return -E1000_ERR_CONFIG;
}
@@ -414,6 +459,9 @@
extcnf_ctrl = er32(EXTCNF_CTRL);
extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+ nvm_owner = -1;
+ mutex_unlock(&nvm_mutex);
}
/**
@@ -1284,6 +1332,7 @@
* programming failed.
*/
if (ret_val) {
+ /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
hw_dbg(hw, "Flash commit failed.\n");
e1000_release_swflag_ich8lan(hw);
return ret_val;
@@ -1374,6 +1423,49 @@
}
/**
+ * 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 = er32flash(ICH_FLASH_GFPREG);
+
+ /* Write-protect GbE Sector of NVM */
+ pr0.regval = er32flash(ICH_FLASH_PR0);
+ pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK;
+ pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK);
+ pr0.range.wpe = true;
+ ew32flash(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 = er16flash(ICH_FLASH_HSFSTS);
+ hsfsts.hsf_status.flockdn = true;
+ ew32flash(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.
@@ -1720,6 +1812,9 @@
ew32(CTRL, (ctrl | E1000_CTRL_RST));
msleep(20);
+ /* release the swflag because it is not reset by hardware reset */
+ e1000_release_swflag_ich8lan(hw);
+
ret_val = e1000e_get_auto_rd_done(hw);
if (ret_val) {
/*
diff -u -r linux-source-2.6.26.orig/drivers/net/e1000e/netdev.c linux-source-2.6.26/drivers/net/e1000e/netdev.c
--- linux-source-2.6.26.orig/drivers/net/e1000e/netdev.c 2008-12-18 17:55:01.000000000 +0800
+++ linux-source-2.6.26/drivers/net/e1000e/netdev.c 2008-12-18 18:24:00.000000000 +0800
@@ -47,7 +47,7 @@
#include "e1000.h"
-#define DRV_VERSION "0.3.3.3-k2"
+#define DRV_VERSION "0.3.3.3-k6"
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
@@ -98,8 +98,7 @@
if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))
vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
- le16_to_cpu(vlan) &
- E1000_RXD_SPC_VLAN_MASK);
+ le16_to_cpu(vlan));
else
netif_receive_skb(skb);
@@ -485,8 +484,8 @@
* 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 */
- ndev_dbg(netdev, "%s: Receive packet consumed "
- "multiple buffers\n", netdev->name);
+ e_dbg("%s: Receive packet consumed multiple buffers\n",
+ netdev->name);
/* recycle */
buffer_info->skb = skb;
goto next_desc;
@@ -511,9 +510,12 @@
netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
if (new_skb) {
skb_reserve(new_skb, NET_IP_ALIGN);
- memcpy(new_skb->data - NET_IP_ALIGN,
- skb->data - NET_IP_ALIGN,
- length + 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;
@@ -577,28 +579,26 @@
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);
- struct net_device *netdev = adapter->netdev;
/* detected Tx unit hang */
- ndev_err(netdev,
- "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);
+ 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);
}
/**
@@ -748,8 +748,8 @@
buffer_info->dma = 0;
if (!(staterr & E1000_RXD_STAT_EOP)) {
- ndev_dbg(netdev, "%s: Packet Split buffers didn't pick "
- "up the full packet\n", netdev->name);
+ e_dbg("%s: Packet Split buffers didn't pick up the "
+ "full packet\n", netdev->name);
dev_kfree_skb_irq(skb);
goto next_desc;
}
@@ -762,8 +762,8 @@
length = le16_to_cpu(rx_desc->wb.middle.length0);
if (!length) {
- ndev_dbg(netdev, "%s: Last part of the packet spanning"
- " multiple descriptors\n", netdev->name);
+ e_dbg("%s: Last part of the packet spanning multiple "
+ "descriptors\n", netdev->name);
dev_kfree_skb_irq(skb);
goto next_desc;
}
@@ -1012,7 +1012,7 @@
/* eth type trans needs skb->data to point to something */
if (!pskb_may_pull(skb, ETH_HLEN)) {
- ndev_err(netdev, "pskb_may_pull failed.\n");
+ e_err("pskb_may_pull failed.\n");
dev_kfree_skb(skb);
goto next_desc;
}
@@ -1115,6 +1115,14 @@
writel(0, adapter->hw.hw_addr + rx_ring->tail);
}
+static void e1000e_downshift_workaround(struct work_struct *work)
+{
+ struct e1000_adapter *adapter = container_of(work,
+ struct e1000_adapter, downshift_task);
+
+ e1000e_gig_downshift_workaround_ich8lan(&adapter->hw);
+}
+
/**
* e1000_intr_msi - Interrupt Handler
* @irq: interrupt number
@@ -1139,7 +1147,7 @@
*/
if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
(!(er32(STATUS) & E1000_STATUS_LU)))
- e1000e_gig_downshift_workaround_ich8lan(hw);
+ schedule_work(&adapter->downshift_task);
/*
* 80003ES2LAN workaround-- For packet buffer work-around on
@@ -1205,7 +1213,7 @@
*/
if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
(!(er32(STATUS) & E1000_STATUS_LU)))
- e1000e_gig_downshift_workaround_ich8lan(hw);
+ schedule_work(&adapter->downshift_task);
/*
* 80003ES2LAN workaround--
@@ -1236,28 +1244,36 @@
return IRQ_HANDLED;
}
+/**
+ * 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;
- irq_handler_t handler = e1000_intr;
int irq_flags = IRQF_SHARED;
int err;
- if (!pci_enable_msi(adapter->pdev)) {
- adapter->flags |= FLAG_MSI_ENABLED;
- handler = e1000_intr_msi;
- irq_flags = 0;
+ 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, handler, irq_flags, netdev->name,
- netdev);
+ err = request_irq(adapter->pdev->irq,
+ ((adapter->flags & FLAG_MSI_ENABLED) ?
+ &e1000_intr_msi : &e1000_intr),
+ irq_flags, netdev->name, netdev);
if (err) {
- ndev_err(netdev,
- "Unable to allocate %s interrupt (return: %d)\n",
- adapter->flags & FLAG_MSI_ENABLED ? "MSI":"INTx",
- err);
- if (adapter->flags & FLAG_MSI_ENABLED)
+ 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);
}
return err;
@@ -1396,8 +1412,7 @@
return 0;
err:
vfree(tx_ring->buffer_info);
- ndev_err(adapter->netdev,
- "Unable to allocate memory for the transmit descriptor ring\n");
+ e_err("Unable to allocate memory for the transmit descriptor ring\n");
return err;
}
@@ -1451,8 +1466,7 @@
}
err:
vfree(rx_ring->buffer_info);
- ndev_err(adapter->netdev,
- "Unable to allocate memory for the transmit descriptor ring\n");
+ e_err("Unable to allocate memory for the transmit descriptor ring\n");
return err;
}
@@ -1793,7 +1807,6 @@
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);
@@ -1805,10 +1818,6 @@
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,
@@ -2231,11 +2240,16 @@
if (netdev->flags & IFF_PROMISC) {
rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
- } else if (netdev->flags & IFF_ALLMULTI) {
- rctl |= E1000_RCTL_MPE;
- rctl &= ~E1000_RCTL_UPE;
+ rctl &= ~E1000_RCTL_VFE;
} else {
- rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+ if (netdev->flags & IFF_ALLMULTI) {
+ rctl |= E1000_RCTL_MPE;
+ rctl &= ~E1000_RCTL_UPE;
+ } else {
+ rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+ }
+ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER)
+ rctl |= E1000_RCTL_VFE;
}
ew32(RCTL, rctl);
@@ -2451,13 +2465,13 @@
* For parts with AMT enabled, let the firmware know
* that the network interface is in control
*/
- if ((adapter->flags & FLAG_HAS_AMT) && e1000e_check_mng_mode(hw))
+ if (adapter->flags & FLAG_HAS_AMT)
e1000_get_hw_control(adapter);
ew32(WUC, 0);
if (mac->ops.init_hw(hw))
- ndev_err(adapter->netdev, "Hardware Error\n");
+ e_err("Hardware Error\n");
e1000_update_mng_vlan(adapter);
@@ -2586,19 +2600,146 @@
/* 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;
err:
- ndev_err(netdev, "Unable to allocate memory for queues\n");
+ e_err("Unable to allocate memory for queues\n");
kfree(adapter->rx_ring);
kfree(adapter->tx_ring);
return -ENOMEM;
}
/**
+ * 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("%s: icr is %08X\n", netdev->name, 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);
+
+ /* 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) {
+ 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("%s: MSI interrupt test succeeded!\n", netdev->name);
+msi_test_failed:
+ /* restore the original vector, even if it failed */
+ 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
*
@@ -2641,8 +2782,7 @@
* If AMT is enabled, let the firmware know that the network
* interface is now open
*/
- if ((adapter->flags & FLAG_HAS_AMT) &&
- e1000e_check_mng_mode(&adapter->hw))
+ if (adapter->flags & FLAG_HAS_AMT)
e1000_get_hw_control(adapter);
/*
@@ -2657,6 +2797,19 @@
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
+ */
+ {
+ 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 e1000e_up() */
clear_bit(__E1000_DOWN, &adapter->state);
@@ -2664,6 +2817,8 @@
e1000_irq_enable(adapter);
+ netif_start_queue(netdev);
+
/* fire a link status change interrupt to start the watchdog */
ew32(ICS, E1000_ICS_LSC);
@@ -2718,8 +2873,7 @@
* If AMT is enabled, let the firmware know that the network
* interface is now closed
*/
- if ((adapter->flags & FLAG_HAS_AMT) &&
- e1000e_check_mng_mode(&adapter->hw))
+ if (adapter->flags & FLAG_HAS_AMT)
e1000_release_hw_control(adapter);
return 0;
@@ -2764,6 +2918,21 @@
return 0;
}
+/**
+ * e1000e_update_phy_task - work thread to update phy
+ * @work: pointer to our work struct
+ *
+ * this worker thread exists because we must acquire a
+ * semaphore to read the phy, which we could msleep while
+ * waiting for it, and we can't msleep in a timer.
+ **/
+static void e1000e_update_phy_task(struct work_struct *work)
+{
+ struct e1000_adapter *adapter = container_of(work,
+ struct e1000_adapter, update_phy_task);
+ e1000_get_phy_info(&adapter->hw);
+}
+
/*
* Need to wait a few seconds after link up to get diagnostic information from
* the phy
@@ -2771,7 +2940,7 @@
static void e1000_update_phy_info(unsigned long data)
{
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
- e1000_get_phy_info(&adapter->hw);
+ schedule_work(&adapter->update_phy_task);
}
/**
@@ -2782,10 +2951,6 @@
{
struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
- 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
@@ -2796,14 +2961,6 @@
if (pci_channel_offline(pdev))
return;
- 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);
@@ -2874,21 +3031,10 @@
/* Tx Dropped needs to be maintained elsewhere */
- /* Phy Stats */
- if (hw->phy.media_type == e1000_media_type_copper) {
- if ((adapter->link_speed == SPEED_1000) &&
- (!e1e_rphy(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);
}
/**
@@ -2900,10 +3046,6 @@
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)) {
@@ -2916,8 +3058,7 @@
ret_val |= e1e_rphy(hw, PHY_1000T_STATUS, &phy->stat1000);
ret_val |= e1e_rphy(hw, PHY_EXT_STATUS, &phy->estatus);
if (ret_val)
- ndev_warn(adapter->netdev,
- "Error reading PHY register\n");
+ e_warn("Error reading PHY register\n");
} else {
/*
* Do not read PHY registers if link is not up
@@ -2935,25 +3076,21 @@
phy->stat1000 = 0;
phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF);
}
-
- spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
}
static void e1000_print_link_info(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
- struct net_device *netdev = adapter->netdev;
u32 ctrl = er32(CTRL);
- ndev_info(netdev,
- "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" )));
+ 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)
@@ -2993,8 +3130,7 @@
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() */
- ndev_info(adapter->netdev,
- "Gigabit has been disabled, downgrading speed\n");
+ e_info("Gigabit has been disabled, downgrading speed\n");
}
return link_active;
@@ -3066,7 +3202,7 @@
case SPEED_10:
txb2b = 0;
netdev->tx_queue_len = 10;
- adapter->tx_timeout_factor = 14;
+ adapter->tx_timeout_factor = 16;
break;
case SPEED_100:
txb2b = 0;
@@ -3095,8 +3231,7 @@
switch (adapter->link_speed) {
case SPEED_10:
case SPEED_100:
- ndev_info(netdev,
- "10/100 speed: disabling TSO\n");
+ e_info("10/100 speed: disabling TSO\n");
netdev->features &= ~NETIF_F_TSO;
netdev->features &= ~NETIF_F_TSO6;
break;
@@ -3129,7 +3264,7 @@
if (netif_carrier_ok(netdev)) {
adapter->link_speed = 0;
adapter->link_duplex = 0;
- ndev_info(netdev, "Link is Down\n");
+ e_info("Link is Down\n");
netif_carrier_off(netdev);
netif_stop_queue(netdev);
if (!test_bit(__E1000_DOWN, &adapter->state))
@@ -3602,8 +3737,7 @@
pull_size = min((unsigned int)4, skb->data_len);
if (!__pskb_pull_tail(skb, pull_size)) {
- ndev_err(netdev,
- "__pskb_pull_tail failed.\n");
+ e_err("__pskb_pull_tail failed.\n");
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -3733,27 +3867,27 @@
struct e1000_adapter *adapter = netdev_priv(netdev);
int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
- if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
+ if ((new_mtu < ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) ||
(max_frame > MAX_JUMBO_FRAME_SIZE)) {
- ndev_err(netdev, "Invalid MTU setting\n");
+ 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)) {
- ndev_err(netdev, "Jumbo Frames not supported.\n");
+ e_err("Jumbo Frames not supported.\n");
return -EINVAL;
}
if (adapter->hw.phy.type == e1000_phy_ife) {
- ndev_err(netdev, "Jumbo Frames not supported.\n");
+ e_err("Jumbo Frames not supported.\n");
return -EINVAL;
}
}
#define MAX_STD_JUMBO_FRAME_SIZE 9234
if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
- ndev_err(netdev, "MTU > 9216 not supported.\n");
+ e_err("MTU > 9216 not supported.\n");
return -EINVAL;
}
@@ -3790,8 +3924,7 @@
adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN
+ ETH_FCS_LEN;
- ndev_info(netdev, "changing MTU from %d to %d\n",
- netdev->mtu, new_mtu);
+ e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu);
netdev->mtu = new_mtu;
if (netif_running(netdev))
@@ -4003,7 +4136,8 @@
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
e1000e_disable_l1aspm(pdev);
- err = pci_enable_device(pdev);
+
+ err = pci_enable_device_mem(pdev);
if (err) {
dev_err(&pdev->dev,
"Cannot enable PCI device from suspend\n");
@@ -4037,7 +4171,7 @@
* 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) || !e1000e_check_mng_mode(&adapter->hw))
+ if (!(adapter->flags & FLAG_HAS_AMT))
e1000_get_hw_control(adapter);
return 0;
@@ -4062,8 +4196,6 @@
disable_irq(adapter->pdev->irq);
e1000_intr(adapter->pdev->irq, netdev);
- e1000_clean_tx_irq(adapter);
-
enable_irq(adapter->pdev->irq);
}
#endif
@@ -4104,9 +4236,11 @@
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
+ int err;
e1000e_disable_l1aspm(pdev);
- if (pci_enable_device(pdev)) {
+ err = pci_enable_device_mem(pdev);
+ if (err) {
dev_err(&pdev->dev,
"Cannot re-enable PCI device after reset.\n");
return PCI_ERS_RESULT_DISCONNECT;
@@ -4153,8 +4287,7 @@
* 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) ||
- !e1000e_check_mng_mode(&adapter->hw))
+ if (!(adapter->flags & FLAG_HAS_AMT))
e1000_get_hw_control(adapter);
}
@@ -4166,22 +4299,41 @@
u32 pba_num;
/* print bus type/speed/width info */
- ndev_info(netdev, "(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]);
- ndev_info(netdev, "Intel(R) PRO/%s Network Connection\n",
- (hw->phy.type == e1000_phy_ife)
- ? "10/100" : "1000");
+ 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");
e1000e_read_pba_num(hw, &pba_num);
- ndev_info(netdev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
- hw->mac.type, hw->phy.type,
- (pba_num >> 8), (pba_num & 0xff));
+ e_info("MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+ hw->mac.type, hw->phy.type, (pba_num >> 8), (pba_num & 0xff));
+}
+
+static void e1000_eeprom_checks(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ int ret_val;
+ u16 buf = 0;
+
+ if (hw->mac.type != e1000_82573)
+ return;
+
+ ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &buf);
+ if (!(le16_to_cpu(buf) & (1 << 0))) {
+ /* Deep Smart Power Down (DSPD) */
+ e_warn("Warning: detected DSPD enabled in EEPROM\n");
+ }
+
+ ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf);
+ if (le16_to_cpu(buf) & (3 << 2)) {
+ /* ASPM enable */
+ e_warn("Warning: detected ASPM enabled in EEPROM\n");
+ }
}
/**
@@ -4211,7 +4363,8 @@
u16 eeprom_apme_mask = E1000_EEPROM_APME;
e1000e_disable_l1aspm(pdev);
- err = pci_enable_device(pdev);
+
+ err = pci_enable_device_mem(pdev);
if (err)
return err;
@@ -4234,7 +4387,9 @@
}
}
- err = pci_request_regions(pdev, e1000e_driver_name);
+ err = pci_request_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM),
+ e1000e_driver_name);
if (err)
goto err_pci_reg;
@@ -4303,6 +4458,8 @@
adapter->bd_number = cards_found++;
+ e1000e_check_options(adapter);
+
/* setup adapter struct */
err = e1000_sw_init(adapter);
if (err)
@@ -4318,6 +4475,10 @@
if (err)
goto err_hw_init;
+ if ((adapter->flags & FLAG_IS_ICH) &&
+ (adapter->flags & FLAG_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;
@@ -4330,8 +4491,7 @@
}
if (e1000_check_reset_block(&adapter->hw))
- ndev_info(netdev,
- "PHY reset is blocked due to SOL/IDER session.\n");
+ e_info("PHY reset is blocked due to SOL/IDER session.\n");
netdev->features = NETIF_F_SG |
NETIF_F_HW_CSUM |
@@ -4344,6 +4504,11 @@
netdev->features |= NETIF_F_TSO;
netdev->features |= NETIF_F_TSO6;
+ netdev->vlan_features |= NETIF_F_TSO;
+ netdev->vlan_features |= NETIF_F_TSO6;
+ netdev->vlan_features |= NETIF_F_HW_CSUM;
+ netdev->vlan_features |= NETIF_F_SG;
+
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
@@ -4370,25 +4535,26 @@
if (e1000_validate_nvm_checksum(&adapter->hw) >= 0)
break;
if (i == 2) {
- ndev_err(netdev, "The NVM Checksum Is Not Valid\n");
+ e_err("The NVM Checksum Is Not Valid\n");
err = -EIO;
goto err_eeprom;
}
}
+ e1000_eeprom_checks(adapter);
+
/* copy the MAC address out of the NVM */
if (e1000e_read_mac_addr(&adapter->hw))
- ndev_err(netdev, "NVM Read Error while reading MAC address\n");
+ e_err("NVM Read Error while reading MAC address\n");
memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
if (!is_valid_ether_addr(netdev->perm_addr)) {
- ndev_err(netdev, "Invalid MAC Address: "
- "%02x:%02x:%02x:%02x:%02x:%02x\n",
- netdev->perm_addr[0], netdev->perm_addr[1],
- netdev->perm_addr[2], netdev->perm_addr[3],
- netdev->perm_addr[4], netdev->perm_addr[5]);
+ e_err("Invalid MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ netdev->perm_addr[0], netdev->perm_addr[1],
+ netdev->perm_addr[2], netdev->perm_addr[3],
+ netdev->perm_addr[4], netdev->perm_addr[5]);
err = -EIO;
goto err_eeprom;
}
@@ -4403,8 +4569,8 @@
INIT_WORK(&adapter->reset_task, e1000_reset_task);
INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
-
- e1000e_check_options(adapter);
+ INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround);
+ INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task);
/* Initialize link parameters. User can change them with ethtool */
adapter->hw.mac.autoneg = 1;
@@ -4458,8 +4624,7 @@
* 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) ||
- !e1000e_check_mng_mode(&adapter->hw))
+ if (!(adapter->flags & FLAG_HAS_AMT))
e1000_get_hw_control(adapter);
/* tell the stack to leave us alone until e1000_open() is called */
@@ -4476,24 +4641,25 @@
return 0;
err_register:
-err_hw_init:
- e1000_release_hw_control(adapter);
+ if (!(adapter->flags & FLAG_HAS_AMT))
+ e1000_release_hw_control(adapter);
err_eeprom:
if (!e1000_check_reset_block(&adapter->hw))
e1000_phy_hw_reset(&adapter->hw);
+err_hw_init:
- if (adapter->hw.flash_address)
- iounmap(adapter->hw.flash_address);
-
-err_flashmap:
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);
+ pci_release_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM));
err_pci_reg:
err_dma:
pci_disable_device(pdev);
@@ -4541,7 +4707,8 @@
iounmap(adapter->hw.hw_addr);
if (adapter->hw.flash_address)
iounmap(adapter->hw.flash_address);
- pci_release_regions(pdev);
+ pci_release_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM));
free_netdev(netdev);
diff -u -r linux-source-2.6.26.orig/drivers/net/e1000e/param.c linux-source-2.6.26/drivers/net/e1000e/param.c
--- linux-source-2.6.26.orig/drivers/net/e1000e/param.c 2008-12-18 17:55:01.000000000 +0800
+++ linux-source-2.6.26/drivers/net/e1000e/param.c 2008-12-18 17:56:21.000000000 +0800
@@ -27,6 +27,7 @@
*******************************************************************************/
#include <linux/netdevice.h>
+#include <linux/pci.h>
#include "e1000.h"
@@ -132,6 +133,15 @@
*/
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;
@@ -162,17 +172,16 @@
case enable_option:
switch (*value) {
case OPTION_ENABLED:
- ndev_info(adapter->netdev, "%s Enabled\n", opt->name);
+ e_info("%s Enabled\n", opt->name);
return 0;
case OPTION_DISABLED:
- ndev_info(adapter->netdev, "%s Disabled\n", opt->name);
+ e_info("%s Disabled\n", opt->name);
return 0;
}
break;
case range_option:
if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
- ndev_info(adapter->netdev,
- "%s set to %i\n", opt->name, *value);
+ e_info("%s set to %i\n", opt->name, *value);
return 0;
}
break;
@@ -184,8 +193,7 @@
ent = &opt->arg.l.p[i];
if (*value == ent->i) {
if (ent->str[0] != '\0')
- ndev_info(adapter->netdev, "%s\n",
- ent->str);
+ e_info("%s\n", ent->str);
return 0;
}
}
@@ -195,8 +203,8 @@
BUG();
}
- ndev_info(adapter->netdev, "Invalid %s value specified (%i) %s\n",
- opt->name, *value, opt->err);
+ e_info("Invalid %s value specified (%i) %s\n", opt->name, *value,
+ opt->err);
*value = opt->def;
return -1;
}
@@ -213,13 +221,11 @@
void __devinit e1000e_check_options(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
- struct net_device *netdev = adapter->netdev;
int bd = adapter->bd_number;
if (bd >= E1000_MAX_NIC) {
- ndev_notice(netdev,
- "Warning: no configuration for board #%i\n", bd);
- ndev_notice(netdev, "Using defaults for all values\n");
+ e_notice("Warning: no configuration for board #%i\n", bd);
+ e_notice("Using defaults for all values\n");
}
{ /* Transmit Interrupt Delay */
@@ -313,32 +319,41 @@
adapter->itr = InterruptThrottleRate[bd];
switch (adapter->itr) {
case 0:
- ndev_info(netdev, "%s turned off\n",
- opt.name);
+ e_info("%s turned off\n", opt.name);
break;
case 1:
- ndev_info(netdev,
- "%s set to dynamic mode\n",
- opt.name);
+ e_info("%s set to dynamic mode\n", opt.name);
adapter->itr_setting = adapter->itr;
adapter->itr = 20000;
break;
case 3:
- ndev_info(netdev,
- "%s set to dynamic conservative mode\n",
+ e_info("%s set to dynamic conservative mode\n",
opt.name);
adapter->itr_setting = adapter->itr;
adapter->itr = 20000;
break;
default:
- e1000_validate_option(&adapter->itr, &opt,
- adapter);
/*
- * save the setting, because the dynamic bits
- * change itr. clear the lower two bits
- * because they are used as control
+ * Save the setting, because the dynamic bits
+ * change itr.
*/
- adapter->itr_setting = adapter->itr & ~3;
+ 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 {
@@ -382,4 +397,25 @@
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->flags |= FLAG_READ_ONLY_NVM;
+ } else {
+ if (opt.def)
+ adapter->flags |= FLAG_READ_ONLY_NVM;
+ }
+ }
+ }
}
Reply to: