From c9257433f2eaf8803a1f3d3be5d984232db41ffe Mon Sep 17 00:00:00 2001 From: Vladimir Sokolovsky Date: Tue, 2 Sep 2008 13:38:29 -0700 Subject: mlx4_core: Set RAE and init mtt_sz field in FRMR MPT entries Set the RAE (remote access enable) bit and correctly initialize the MTT size in MPT entries being set up for fast register memory regions. Otherwise the callers can't enable remote access and in fact can't fast register at all (since the HCA will think no MTT entries are allocated). Signed-off-by: Vladimir Sokolovsky Signed-off-by: Roland Dreier --- drivers/net/mlx4/mr.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 62071d9..644adf07 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -67,7 +67,8 @@ struct mlx4_mpt_entry { #define MLX4_MPT_FLAG_PHYSICAL (1 << 9) #define MLX4_MPT_FLAG_REGION (1 << 8) -#define MLX4_MPT_PD_FLAG_FAST_REG (1 << 26) +#define MLX4_MPT_PD_FLAG_FAST_REG (1 << 27) +#define MLX4_MPT_PD_FLAG_RAE (1 << 28) #define MLX4_MPT_PD_FLAG_EN_INV (3 << 24) #define MLX4_MTT_FLAG_PRESENT 1 @@ -348,7 +349,10 @@ int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) if (mr->mtt.order >= 0 && mr->mtt.page_shift == 0) { /* fast register MR in free state */ mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_FREE); - mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG); + mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG | + MLX4_MPT_PD_FLAG_RAE); + mpt_entry->mtt_sz = cpu_to_be32((1 << mr->mtt.order) * + MLX4_MTT_ENTRY_PER_SEG); } else { mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS); } -- cgit v1.1 From 29bdc88384c2b24e37e5760df0dc898546083d6b Mon Sep 17 00:00:00 2001 From: Vladimir Sokolovsky Date: Mon, 15 Sep 2008 14:25:23 -0700 Subject: IB/mlx4: Fix up fast register page list format Byte swap the addresses in the page list for fast register work requests to big endian to match what the HCA expectx. Also, the addresses must have the "present" bit set so that the HCA knows it can access them. Otherwise the HCA will fault the first time it accesses the memory region. Signed-off-by: Vladimir Sokolovsky Signed-off-by: Roland Dreier --- drivers/net/mlx4/mr.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 644adf07..d1dd5b4 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -71,8 +71,6 @@ struct mlx4_mpt_entry { #define MLX4_MPT_PD_FLAG_RAE (1 << 28) #define MLX4_MPT_PD_FLAG_EN_INV (3 << 24) -#define MLX4_MTT_FLAG_PRESENT 1 - #define MLX4_MPT_STATUS_SW 0xF0 #define MLX4_MPT_STATUS_HW 0x00 -- cgit v1.1 From 27ed9ddfde8d2967076c51815e4ce297c4a18139 Mon Sep 17 00:00:00 2001 From: Benjamin Li Date: Thu, 18 Sep 2008 16:46:11 -0700 Subject: bnx2: Promote vector field in bnx2_irq structure from u16 to unsigned int The bnx2 driver stores/uses the irq value from the pci_dev internally. But when it stores the irq value, it has been performing an integer demotion. Because of the recent changes made to arch/x86/kernel/io_apic.c, the new method in creating the irq value (using build_irq_for_pci_dev()) has exposed this bug on x86 systems. Because of this demotion when calling request_irq() from bnx2_request_irq(), the driver would get a return code of -EINVAL. This is because the kernel could not find the requested irq descriptor. By storing the irq value properly, the kernel can find the correct irq descriptor and the bnx2 driver can operate normally. Signed-off-by: Benjamin Li Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index c3c579f..dfacd31 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6597,7 +6597,7 @@ struct flash_spec { struct bnx2_irq { irq_handler_t handler; - u16 vector; + unsigned int vector; u8 requested; char name[16]; }; -- cgit v1.1 From f55c21fd9a92a444e55ad1ca4e4732d56661bf2e Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sat, 13 Sep 2008 13:10:31 -0700 Subject: forcedeth: call restore mac addr in nv_shutdown path after | commit f735a2a1a4f2a0f5cd823ce323e82675990469e2 | Author: Tobias Diedrich | Date: Sun May 18 15:02:37 2008 +0200 | | [netdrvr] forcedeth: setup wake-on-lan before shutting down | | When hibernating in 'shutdown' mode, after saving the image the suspend hook | is not called again. | However, if the device is in promiscous mode, wake-on-lan will not work. | This adds a shutdown hook to setup wake-on-lan before the final shutdown. | | Signed-off-by: Tobias Diedrich | Signed-off-by: Jeff Garzik my servers with nvidia ck804 and mcp55 will reverse mac address with kexec. it turns out that we need to restore the mac addr in nv_shutdown(). [akpm@linux-foundation.org: fix typo in printk] Signed-off-by: Yinghai Lu Cc: Tobias Diedrich Cc: Ayaz Abdulla Cc: Jeff Garzik Cc: "Rafael J. Wysocki" Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 0b6ecef..eeb55ed 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -5643,6 +5643,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll); + printk(KERN_DEBUG "nv_probe: set workaround bit for reversed mac addr\n"); } memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); @@ -5890,14 +5891,12 @@ static void nv_restore_phy(struct net_device *dev) } } -static void __devexit nv_remove(struct pci_dev *pci_dev) +static void nv_restore_mac_addr(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - unregister_netdev(dev); - /* special op: write back the misordered MAC address - otherwise * the next nv_probe would see a wrong address. */ @@ -5905,6 +5904,15 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) writel(np->orig_mac[1], base + NvRegMacAddrB); writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll); +} + +static void __devexit nv_remove(struct pci_dev *pci_dev) +{ + struct net_device *dev = pci_get_drvdata(pci_dev); + + unregister_netdev(dev); + + nv_restore_mac_addr(pci_dev); /* restore any phy related changes */ nv_restore_phy(dev); @@ -5975,6 +5983,8 @@ static void nv_shutdown(struct pci_dev *pdev) if (netif_running(dev)) nv_close(dev); + nv_restore_mac_addr(pdev); + pci_disable_device(pdev); if (system_state == SYSTEM_POWER_OFF) { if (pci_enable_wake(pdev, PCI_D3cold, np->wolenabled)) -- cgit v1.1 From 78566fecbb12a7616ae9a88b2ffbc8062c4a89e3 Mon Sep 17 00:00:00 2001 From: Christopher Li Date: Fri, 5 Sep 2008 14:04:05 -0700 Subject: e1000: prevent corruption of EEPROM/NVM Andrey reports e1000 corruption, and that a patch in vmware's ESX fixed it. The EEPROM corruption is triggered by concurrent access of the EEPROM read/write. Putting a lock around it solve the problem. [akpm@linux-foundation.org: use DEFINE_SPINLOCK to avoid confusing lockdep] Signed-off-by: Christopher Li Reported-by: Andrey Borzenkov Cc: Zach Amsden Cc: Pratap Subrahmanyam Cc: Jeff Kirsher Cc: Jesse Brandeburg Cc: Bruce Allan Cc: PJ Waskiewicz Cc: John Ronciak Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_hw.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 9d6edf3..d04eef53 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -144,6 +144,8 @@ static s32 e1000_host_if_read_cookie(struct e1000_hw *hw, u8 *buffer); static u8 e1000_calculate_mng_checksum(char *buffer, u32 length); static s32 e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, u16 duplex); static s32 e1000_configure_kmrn_for_1000(struct e1000_hw *hw); +static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); /* IGP cable length table */ static const @@ -168,6 +170,8 @@ u16 e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] = 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121, 124}; +static DEFINE_SPINLOCK(e1000_eeprom_lock); + /****************************************************************************** * Set the phy type member in the hw struct. * @@ -4904,6 +4908,15 @@ static s32 e1000_spi_eeprom_ready(struct e1000_hw *hw) *****************************************************************************/ s32 e1000_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) { + s32 ret; + spin_lock(&e1000_eeprom_lock); + ret = e1000_do_read_eeprom(hw, offset, words, data); + spin_unlock(&e1000_eeprom_lock); + return ret; +} + +static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ struct e1000_eeprom_info *eeprom = &hw->eeprom; u32 i = 0; @@ -5236,6 +5249,16 @@ s32 e1000_update_eeprom_checksum(struct e1000_hw *hw) *****************************************************************************/ s32 e1000_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) { + s32 ret; + spin_lock(&e1000_eeprom_lock); + ret = e1000_do_write_eeprom(hw, offset, words, data); + spin_unlock(&e1000_eeprom_lock); + return ret; +} + + +static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ struct e1000_eeprom_info *eeprom = &hw->eeprom; s32 status = 0; -- cgit v1.1 From e7272403d2f9be3dbb7cc185fcc390e781b1af6b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 8 Aug 2008 00:18:04 +0200 Subject: e100: Use pci_pme_active to clear PME_Status and disable PME# Currently e100 uses pci_enable_wake() to clear pending wake-up events and disable PME# during intitialization, but that function is not suitable for this purpose, because it immediately returns error code if device_may_wakeup() returns false for given device. Make e100 use pci_pme_active(), which carries out exactly the required operations, instead. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jeff Garzik --- drivers/net/e100.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 453115a..5cf78d6 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2738,9 +2738,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, nic->flags |= wol_magic; /* ack any pending wake events, disable PME */ - err = pci_enable_wake(pdev, 0, 0); - if (err) - DPRINTK(PROBE, ERR, "Error clearing wake event\n"); + pci_pme_active(pdev, false); strcpy(netdev->name, "eth%d"); if((err = register_netdev(netdev))) { -- cgit v1.1 From d0be7cc7688d0cc2e4daf952c43b5ce86e5c8a1d Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 17 Sep 2008 12:39:49 +0530 Subject: ath9k: connectivity is lost after Group rekeying is done Connectivtiy is lost after Group rekeying is done. The keytype maintained by ath9k is reset when group key is updated. Though sc_keytype can be reset only for broadcast key the proper fix would be to use mac80211 provided key type from txinfo during xmit and get rid of sc_keytype from ath9k ath_softc. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Senthil Balasubramanian Tested-by: Steven Noonan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 1 - drivers/net/wireless/ath9k/main.c | 3 --- drivers/net/wireless/ath9k/xmit.c | 6 +++--- 3 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 4ee695b..2f84093 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -974,7 +974,6 @@ struct ath_softc { u32 sc_keymax; /* size of key cache */ DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); /* key use bit map */ u8 sc_splitmic; /* split TKIP MIC keys */ - int sc_keytype; /* RX */ struct list_head sc_rxbuf; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 99badf1..0997196 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -206,8 +206,6 @@ static int ath_key_config(struct ath_softc *sc, if (!ret) return -EIO; - if (mac) - sc->sc_keytype = hk.kv_type; return 0; } @@ -778,7 +776,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw, case DISABLE_KEY: ath_key_delete(sc, key); clear_bit(key->keyidx, sc->sc_keymap); - sc->sc_keytype = ATH9K_CIPHER_CLR; break; default: ret = -EINVAL; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 550129f..8b332e1 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -315,11 +315,11 @@ static int ath_tx_prepare(struct ath_softc *sc, txctl->keyix = tx_info->control.hw_key->hw_key_idx; txctl->frmlen += tx_info->control.icv_len; - if (sc->sc_keytype == ATH9K_CIPHER_WEP) + if (tx_info->control.hw_key->alg == ALG_WEP) txctl->keytype = ATH9K_KEY_TYPE_WEP; - else if (sc->sc_keytype == ATH9K_CIPHER_TKIP) + else if (tx_info->control.hw_key->alg == ALG_TKIP) txctl->keytype = ATH9K_KEY_TYPE_TKIP; - else if (sc->sc_keytype == ATH9K_CIPHER_AES_CCM) + else if (tx_info->control.hw_key->alg == ALG_CCMP) txctl->keytype = ATH9K_KEY_TYPE_AES; } -- cgit v1.1 From 5d89945e6ec44494285cb8de85d4f43d4647b740 Mon Sep 17 00:00:00 2001 From: "born.into.silence@gmail.com" Date: Fri, 19 Sep 2008 16:47:06 -0700 Subject: wireless: zd1211rw: add device ID fix wifi dongle "trust nw-3100" akpm: taken from http://bugzilla.kernel.org/show_bug.cgi?id=11587 I bought the wifi dongle trust nw-3100 wich is in fact a zd1211rw. Its hardware id was missing in the sources, adding it made it work flawlessly. Cc: Daniel Drake Cc: Ulrich Kunitz Cc: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index da8b743..a60ae86 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -58,6 +58,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, -- cgit v1.1 From 6115e8557a75b5f24b56ed46c60dffef7e7fa992 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Mon, 22 Sep 2008 14:22:39 +0530 Subject: ath9k: Fix IRQ nobody cared issue with ath9k IRQs should be disabled before calling free_irq. Also flush pending IRQs. Pasted the kernel log message for reference. kernel: irq 17: nobody cared (try booting with the "irqpoll" option) kernel: [] __report_bad_irq+0x2e/0x6f kernel: [] note_interrupt+0x1b5/0x207 kernel: [] ? handle_IRQ_event+0x21/0x48 kernel: [] handle_fasteoi_irq+0x8e/0xad kernel: [] do_IRQ+0x6c/0x84 kernel: [] common_interrupt+0x23/0x28 kernel: [] ? acpi_idle_enter_simple+0x198/0x205 kernel: [] ? menu_select+0x5c/0x78 kernel: [] cpuidle_idle_call+0x59/0x89 kernel: [] cpu_idle+0xae/0xcf kernel: [] rest_init+0x4e/0x50 kernel: ======================= kernel: handlers: kernel: [] (ath_isr+0x0/0x13a [ath9k]) kernel: Disabling IRQ #17 Signed-off-by: Senthil Balasubramanian Tested-by: Steven Noonan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 4 ++-- drivers/net/wireless/ath9k/main.c | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index f6c4528..c049593 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -294,8 +294,6 @@ static int ath_stop(struct ath_softc *sc) * hardware is gone (invalid). */ - if (!sc->sc_invalid) - ath9k_hw_set_interrupts(ah, 0); ath_draintxq(sc, false); if (!sc->sc_invalid) { ath_stoprecv(sc); @@ -1336,6 +1334,8 @@ void ath_deinit(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__); + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); ath_stop(sc); if (!sc->sc_invalid) ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 0997196..acebdf1 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1411,10 +1411,17 @@ static void ath_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; + enum ath9k_int status; - if (pdev->irq) + if (pdev->irq) { + ath9k_hw_set_interrupts(sc->sc_ah, 0); + /* clear the ISR */ + ath9k_hw_getisr(sc->sc_ah, &status); + sc->sc_invalid = 1; free_irq(pdev->irq, sc); + } ath_detach(sc); + pci_iounmap(pdev, sc->mem); pci_release_region(pdev, 0); pci_disable_device(pdev); -- cgit v1.1 From 92cccc2cda9a744326bbd9f16c635187af7f8a09 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 23 Sep 2008 14:28:16 -0700 Subject: ath9k: disable MIB interrupts to fix interrupt storm Enabling the MIB interrupts has proven to cause an interrupt storm after 7 hours of run. We will make use of the MIB interrupt once we have ANI supported added so for now to cure this we disable the interrupt. The interrupt storm can be seen as follows after 7 hours of run as reported by Steven Noonan : 18:28:38 sum 1106.00 18:28:39 sum 1037.62 18:28:40 sum 1069.00 18:28:41 sum 1167.00 18:28:42 sum 1155.00 18:28:43 sum 1339.00 18:28:44 sum 18355.00 18:28:45 sum 17845.45 18:28:46 sum 15285.00 18:28:47 sum 17511.00 18:28:48 sum 17568.69 18:28:49 sum 17704.04 18:28:50 sum 18566.67 18:28:51 sum 18913.13 at 18:28:44 the MIB interrupt kicked off and caused huge latency which can be seen even on a video he submitted: http://www.youtube.com/watch?v=4GeCx1gZMpA Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index c049593..87e37bc 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -795,6 +795,12 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) sc->sc_imask |= ATH9K_INT_CST; + /* Note: We disable MIB interrupts for now as we don't yet + * handle processing ANI, otherwise you will get an interrupt + * storm after about 7 hours of usage making the system unusable + * with huge latency. Once we do have ANI processing included + * we can re-enable this interrupt. */ +#if 0 /* * Enable MIB interrupts when there are hardware phy counters. * Note we only do this (at the moment) for station mode. @@ -802,6 +808,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) if (ath9k_hw_phycounters(ah) && ((sc->sc_opmode == ATH9K_M_STA) || (sc->sc_opmode == ATH9K_M_IBSS))) sc->sc_imask |= ATH9K_INT_MIB; +#endif /* * Some hardware processes the TIM IE and fires an * interrupt when the TIM bit is set. For hardware -- cgit v1.1 From 4a7703582836f55a1cbad0e2c1c6ebbee3f9b3a7 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 1 Oct 2008 17:18:35 -0700 Subject: e1000e: write protect ICHx NVM to prevent malicious write/erase Set the hardware to ignore all write/erase cycles to the GbE region in the ICHx NVM. This feature can be disabled by the WriteProtectNVM module parameter (enabled by default) only after a hardware reset, but the machine must be power cycled before trying to enable writes. Signed-off-by: Bruce Allan Signed-off-by: Jesse Brandeburg CC: arjan@linux.intel.com Signed-off-by: Linus Torvalds --- drivers/net/e1000e/e1000.h | 2 ++ drivers/net/e1000e/ethtool.c | 3 +++ drivers/net/e1000e/ich8lan.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ drivers/net/e1000e/netdev.c | 10 +++++--- drivers/net/e1000e/param.c | 30 +++++++++++++++++++++++ 5 files changed, 100 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index ac4e506..f0c48a2 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -305,6 +305,7 @@ struct e1000_info { #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) @@ -385,6 +386,7 @@ extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw); 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 --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index e21c9e0..5ed8e13 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -529,6 +529,9 @@ static int e1000_set_eeprom(struct net_device *netdev, 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; diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 9e38452..d8efba8 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -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 @@ union ich8_hws_flash_regacc { 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); @@ -1284,6 +1298,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) * 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 +1389,49 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) } /** + * 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. diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index d266510..1f767fe 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -47,7 +47,7 @@ #include "e1000.h" -#define DRV_VERSION "0.3.3.3-k2" +#define DRV_VERSION "0.3.3.3-k4" char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; @@ -4467,6 +4467,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->bd_number = cards_found++; + e1000e_check_options(adapter); + /* setup adapter struct */ err = e1000_sw_init(adapter); if (err) @@ -4482,6 +4484,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev, 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; @@ -4573,8 +4579,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev, INIT_WORK(&adapter->reset_task, e1000_reset_task); INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); - e1000e_check_options(adapter); - /* Initialize link parameters. User can change them with ethtool */ adapter->hw.mac.autoneg = 1; adapter->fc_autoneg = 1; diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c index ed912e0..d91dbf7 100644 --- a/drivers/net/e1000e/param.c +++ b/drivers/net/e1000e/param.c @@ -133,6 +133,15 @@ E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down"); */ 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; @@ -388,4 +397,25 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) 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; + } + } + } } -- cgit v1.1 From 37f40239f49fbc0b489d0327a700fee5b3898ac2 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 2 Oct 2008 16:33:20 -0700 Subject: e1000e: reset swflag after resetting hardware in the process of debugging things, noticed that the swflag is not reset by the driver after reset, and the swflag is probably not reset unless management firmware clears it after 100ms. Signed-off-by: Jesse Brandeburg Signed-off-by: Linus Torvalds --- drivers/net/e1000e/ich8lan.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index d8efba8..f4b6744 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -1778,6 +1778,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) 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) { /* -- cgit v1.1 From a8f88ff5a5abc2ce9f7d7d2694178b2c617d713a Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 2 Oct 2008 16:33:25 -0700 Subject: e1000e: do not ever sleep in interrupt context e1000e was apparently calling two functions that attempted to reserve the SWFLAG bit for exclusive (to hardware and firmware) access to the PHY and NVM (aka eeprom). These accesses could possibly call msleep to wait for the resource which is not allowed from interrupt context. Signed-off-by: Jesse Brandeburg Acked-by: Thomas Gleixner Tested-by: Thomas Gleixner Signed-off-by: Linus Torvalds --- drivers/net/e1000e/e1000.h | 2 ++ drivers/net/e1000e/netdev.c | 31 ++++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index f0c48a2..8087bda 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -284,6 +284,8 @@ struct e1000_adapter { unsigned long led_status; unsigned int flags; + struct work_struct downshift_task; + struct work_struct update_phy_task; }; struct e1000_info { diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 1f767fe..803545b 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -1115,6 +1115,14 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter) 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 @@ static irqreturn_t e1000_intr_msi(int irq, void *data) */ 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 @@ static irqreturn_t e1000_intr(int irq, void *data) */ 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-- @@ -2912,6 +2920,21 @@ static int e1000_set_mac(struct net_device *netdev, void *p) 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 @@ -2919,7 +2942,7 @@ static int e1000_set_mac(struct net_device *netdev, void *p) 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); } /** @@ -4578,6 +4601,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, INIT_WORK(&adapter->reset_task, e1000_reset_task); INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); + 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; -- cgit v1.1 From 23033fad5be0a2c7838cb9e1579919b64af713f6 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 2 Oct 2008 16:33:30 -0700 Subject: e1000e: remove phy read from inside spinlock thanks to tglx, we're finding some interesting reentrancy issues. this patch removes the phy read from inside a spinlock, paving the way for removing the spinlock completely. The phy read was only feeding a statistic that wasn't used. Signed-off-by: Jesse Brandeburg Acked-by: Thomas Gleixner Signed-off-by: Linus Torvalds --- drivers/net/e1000e/ethtool.c | 6 +++++- drivers/net/e1000e/netdev.c | 13 ------------- 2 files changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 5ed8e13..33a3ff1 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -432,6 +432,10 @@ static void e1000_get_regs(struct net_device *netdev, 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 */ @@ -447,7 +451,7 @@ static void e1000_get_regs(struct net_device *netdev, 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 */ diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 803545b..835b692 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2954,9 +2954,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter) 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 @@ -3045,15 +3042,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter) /* 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); @@ -3073,7 +3061,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter) int ret_val; unsigned long irq_flags; - spin_lock_irqsave(&adapter->stats_lock, irq_flags); if ((er32(STATUS) & E1000_STATUS_LU) && -- cgit v1.1 From 4fa7553a075918e1e02a6039f9e826c8872b7049 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 2 Oct 2008 16:33:35 -0700 Subject: e1000e: drop stats lock the stats lock is left over from e1000, e1000e no longer has the adjust tbi stats function that required the addition of the stats lock to begin with. adding a mutex to acquire_swflag helped catch this one too. Signed-off-by: Jesse Brandeburg Acked-by: Thomas Gleixner Signed-off-by: Linus Torvalds --- drivers/net/e1000e/e1000.h | 1 - drivers/net/e1000e/netdev.c | 18 ------------------ 2 files changed, 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 8087bda..5ea6b60 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -257,7 +257,6 @@ struct e1000_adapter { 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; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 835b692..01e9558 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2600,8 +2600,6 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) /* 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; @@ -2953,7 +2951,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; - unsigned long irq_flags; /* * Prevent stats update while adapter is being reset, or if the pci @@ -2964,14 +2961,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter) 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); @@ -3046,8 +3035,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter) adapter->stats.mgptc += er32(MGTPTC); adapter->stats.mgprc += er32(MGTPRC); adapter->stats.mgpdc += er32(MGTPDC); - - spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); } /** @@ -3059,9 +3046,6 @@ 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)) { @@ -3092,8 +3076,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter) 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) -- cgit v1.1 From 717d438d1fde94decef874b9808379d1f4523453 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 2 Oct 2008 16:33:40 -0700 Subject: e1000e: debug contention on NVM SWFLAG This patch adds a mutex to the e1000e driver that would help catch any collisions of two e1000e threads accessing hardware at the same time. description and patch updated by Jesse Signed-off-by: Thomas Gleixner Signed-off-by: Jesse Brandeburg Signed-off-by: Linus Torvalds --- drivers/net/e1000e/ich8lan.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index f4b6744..0b6095b 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -380,6 +380,9 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) return 0; } +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 @@ -393,6 +396,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) u32 extcnf_ctrl; u32 timeout = PHY_CFG_TIMEOUT; + WARN_ON(preempt_count()); + + 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; @@ -407,6 +419,8 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) 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; } @@ -428,6 +442,9 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) extcnf_ctrl = er32(EXTCNF_CTRL); extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; ew32(EXTCNF_CTRL, extcnf_ctrl); + + nvm_owner = -1; + mutex_unlock(&nvm_mutex); } /** -- cgit v1.1 From 6f92a6a7ddba5ae7ca0f0255d46410465dcf2ba6 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 2 Oct 2008 16:33:45 -0700 Subject: e1000e: update version from k4 to k6 Signed-off-by: Jesse Brandeburg Signed-off-by: Linus Torvalds --- drivers/net/e1000e/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 01e9558..b81c423 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -47,7 +47,7 @@ #include "e1000.h" -#define DRV_VERSION "0.3.3.3-k4" +#define DRV_VERSION "0.3.3.3-k6" char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; -- cgit v1.1 From 95b866d5afcafee00fc9ad70665e48c86d8c4e0f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 3 Oct 2008 09:18:17 -0700 Subject: e1000e: Fix incorrect debug warning Doing 'WARN_ON(preempt_count())' was horribly horribly wrong, and would cause tons of warnings at bootup if PREEMPT was enabled because the initcalls currently run with the kernel lock, which increments the preempt count. At the same time, the warning was also insufficient, since it didn't check that interrupts were enabled. The proper debug function to use for something that can sleep and wants a warning if it's called in the wrong context is 'might_sleep()'. Reported-by: Christian Borntraeger Signed-off-by: Linus Torvalds --- drivers/net/e1000e/ich8lan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 0b6095b..bcd2bc4 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -396,7 +396,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) u32 extcnf_ctrl; u32 timeout = PHY_CFG_TIMEOUT; - WARN_ON(preempt_count()); + might_sleep(); if (!mutex_trylock(&nvm_mutex)) { WARN(1, KERN_ERR "e1000e mutex contention. Owned by pid %d\n", -- cgit v1.1