From 6c3118e2305326743acb52250bcfd0d52389d9dc Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 23 Jun 2010 06:49:21 -0700 Subject: ath9k: Fix bug in starting ani There are few places where ANI is started without checking if it is right to start. This might lead to a case where ani timer would be left undeleted and cause improper memory acccess during module unload. This bug is clearly exposed with paprd support where the driver detects tx hang and does a chip reset. During this reset ani is (re)started without checking if it needs to be started. This would leave a timer scheduled even after all the resources are freed and cause a panic. This patch introduces a bit in sc_flags to indicate if ani needs to be started in sw_scan_start() and ath_reset(). This would fix the following panic. This issue is easily seen with ar9003 + paprd. BUG: unable to handle kernel paging request at 0000000000003f38 [] ? __queue_work+0x41/0x50 [] run_timer_softirq+0x17a/0x370 [] ? tick_dev_program_event+0x48/0x110 [] __do_softirq+0xb9/0x1f0 [] ? handle_IRQ_event+0x50/0x160 [] call_softirq+0x1c/0x30 [] do_softirq+0x65/0xa0 [] irq_exit+0x85/0x90 [] do_IRQ+0x75/0xf0 [] ret_from_intr+0x0/0x11 [] ? acpi_idle_enter_simple+0xe4/0x119 [] ? acpi_idle_enter_simple+0xdd/0x119 [] cpuidle_idle_call+0xa7/0x140 [] cpu_idle+0xb3/0x110 [] start_secondary+0x1ee/0x1f5 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index fbb7dec6dde..5ea87736a6a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -445,6 +445,7 @@ void ath_deinit_leds(struct ath_softc *sc); #define SC_OP_TSF_RESET BIT(11) #define SC_OP_BT_PRIORITY_DETECTED BIT(12) #define SC_OP_BT_SCAN BIT(13) +#define SC_OP_ANI_RUN BIT(14) /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index abfa0493236..1e2a68ea935 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -336,6 +336,10 @@ set_timer: static void ath_start_ani(struct ath_common *common) { unsigned long timestamp = jiffies_to_msecs(jiffies); + struct ath_softc *sc = (struct ath_softc *) common->priv; + + if (!(sc->sc_flags & SC_OP_ANI_RUN)) + return; common->ani.longcal_timer = timestamp; common->ani.shortcal_timer = timestamp; @@ -872,11 +876,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, /* Reset rssi stats */ sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); } else { ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); common->curaid = 0; /* Stop ANI */ + sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); } } @@ -1478,8 +1484,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MONITOR) + vif->type == NL80211_IFTYPE_MONITOR) { + sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); + } out: mutex_unlock(&sc->mutex); @@ -1500,6 +1508,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); /* Stop ANI */ + sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); /* Reclaim beacon resources */ -- cgit v1.2.3 From d1e89f37de2845db364ef6d67586cd882f86b557 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 18 Jun 2010 03:41:25 -0700 Subject: iwlwifi: fix multicast commit 3474ad635db371b0d8d0ee40086f15d223d5b6a4 Author: Johannes Berg Date: Thu Apr 29 04:43:05 2010 -0700 iwlwifi: apply filter flags directly broke multicast. The reason, it turns out, is that the code previously checked if ALLMULTI _changed_, which the new code no longer did, and normally it _never_ changes. Had somebody changed it manually, the code prior to my patch there would have been broken already. The reason is that we always, unconditionally, ask the device to pass up all multicast frames, but the new code made it depend on ALLMULTI which broke it since now we'd pass up multicast frames depending on the default filter in the device, which isn't necessarily what we want (since we don't program it right now). Fix this by simply not checking allmulti as we have allmulti behaviour enabled already anyway. Reported-by: Maxim Levitsky Tested-by: Maxim Levitsky Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 426e95567de..5bbc5298ef9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1314,7 +1314,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw, changed_flags, *total_flags); CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); - CHK(FIF_ALLMULTI, RXON_FILTER_ACCEPT_GRP_MSK); CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); @@ -1329,6 +1328,12 @@ void iwl_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); + /* + * Receiving all multicast frames is always enabled by the + * default flags setup in iwl_connection_init_rx_config() + * since we currently do not support programming multicast + * filters into the device. + */ *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -- cgit v1.2.3 From 062bee448bd539580ef9f64efe50fdfe04eeb103 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 18 Jun 2010 11:33:17 -0700 Subject: iwlwifi: set TX_CMD_FLAG_PROT_REQUIRE_MSK in tx_flag When building tx command, always set TX_CMD_FLAG_PROT_REQUIRE_MSK for 5000 series and up. Without setting this bit the firmware will not examine the RTS/CTS setting and thus not send traffic with the appropriate protection. RTS/CTS is is required for HT traffic in a noisy environment where, without this setting, connections will stall on some hardware as documented in the patch that initially attempted to address this: commit 1152dcc28c66a74b5b3f1a3ede0aa6729bfd48e4 Author: Wey-Yi Guy Date: Fri Jan 15 13:42:58 2010 -0800 iwlwifi: Fix throughput stall issue in HT mode for 5000 Similar to 6000 and 1000 series, RTS/CTS is the recommended protection mechanism for 5000 series in HT mode based on the HW design. Using RTS/CTS will better protect the inner exchange from interference, especially in highly-congested environment, it also prevent uCode encounter TX FIFO underrun and other HT mode related performance issues. For 3945 and 4965, different flags are used for RTS/CTS or CTS-to-Self protection. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 44ef5d93bef..01658cf82d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -212,11 +212,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv) static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags) { - if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || - (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) - *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK; - else - *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK; + *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK; } /* Calc max signal level (dBm) among 3 possible receivers */ -- cgit v1.2.3 From d5675bd204efd87a174eeea592de23c4c4e7f908 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 24 Jun 2010 16:59:59 +0300 Subject: vhost: break out of polling loop on error When ring parsing fails, we currently handle this as ring empty condition. This means that we enable kicks and recheck ring empty: if this not empty, we re-start polling which of course will fail again. Instead, let's return a negative error code and stop polling. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 12 ++++++++++-- drivers/vhost/vhost.c | 33 +++++++++++++++++---------------- drivers/vhost/vhost.h | 8 ++++---- 3 files changed, 31 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 0f41c9195e9..54096eef484 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -98,7 +98,8 @@ static void tx_poll_start(struct vhost_net *net, struct socket *sock) static void handle_tx(struct vhost_net *net) { struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX]; - unsigned head, out, in, s; + unsigned out, in, s; + int head; struct msghdr msg = { .msg_name = NULL, .msg_namelen = 0, @@ -135,6 +136,9 @@ static void handle_tx(struct vhost_net *net) ARRAY_SIZE(vq->iov), &out, &in, NULL, NULL); + /* On error, stop handling until the next kick. */ + if (head < 0) + break; /* Nothing new? Wait for eventfd to tell us they refilled. */ if (head == vq->num) { wmem = atomic_read(&sock->sk->sk_wmem_alloc); @@ -192,7 +196,8 @@ static void handle_tx(struct vhost_net *net) static void handle_rx(struct vhost_net *net) { struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX]; - unsigned head, out, in, log, s; + unsigned out, in, log, s; + int head; struct vhost_log *vq_log; struct msghdr msg = { .msg_name = NULL, @@ -228,6 +233,9 @@ static void handle_rx(struct vhost_net *net) ARRAY_SIZE(vq->iov), &out, &in, vq_log, &log); + /* On error, stop handling until the next kick. */ + if (head < 0) + break; /* OK, now we need to know about added descriptors. */ if (head == vq->num) { if (unlikely(vhost_enable_notify(vq))) { diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 3b83382e06e..5ccd384ec0b 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -873,12 +873,13 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, * number of output then some number of input descriptors, it's actually two * iovecs, but we pack them into one and note how many of each there were. * - * This function returns the descriptor number found, or vq->num (which - * is never a valid descriptor number) if none was found. */ -unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, - struct iovec iov[], unsigned int iov_size, - unsigned int *out_num, unsigned int *in_num, - struct vhost_log *log, unsigned int *log_num) + * This function returns the descriptor number found, or vq->num (which is + * never a valid descriptor number) if none was found. A negative code is + * returned on error. */ +int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, + struct iovec iov[], unsigned int iov_size, + unsigned int *out_num, unsigned int *in_num, + struct vhost_log *log, unsigned int *log_num) { struct vring_desc desc; unsigned int i, head, found = 0; @@ -890,13 +891,13 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, if (get_user(vq->avail_idx, &vq->avail->idx)) { vq_err(vq, "Failed to access avail idx at %p\n", &vq->avail->idx); - return vq->num; + return -EFAULT; } if ((u16)(vq->avail_idx - last_avail_idx) > vq->num) { vq_err(vq, "Guest moved used index from %u to %u", last_avail_idx, vq->avail_idx); - return vq->num; + return -EFAULT; } /* If there's nothing new since last we looked, return invalid. */ @@ -912,14 +913,14 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, vq_err(vq, "Failed to read head: idx %d address %p\n", last_avail_idx, &vq->avail->ring[last_avail_idx % vq->num]); - return vq->num; + return -EFAULT; } /* If their number is silly, that's an error. */ if (head >= vq->num) { vq_err(vq, "Guest says index %u > %u is available", head, vq->num); - return vq->num; + return -EINVAL; } /* When we start there are none of either input nor output. */ @@ -933,19 +934,19 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, if (i >= vq->num) { vq_err(vq, "Desc index is %u > %u, head = %u", i, vq->num, head); - return vq->num; + return -EINVAL; } if (++found > vq->num) { vq_err(vq, "Loop detected: last one at %u " "vq size %u head %u\n", i, vq->num, head); - return vq->num; + return -EINVAL; } ret = copy_from_user(&desc, vq->desc + i, sizeof desc); if (ret) { vq_err(vq, "Failed to get descriptor: idx %d addr %p\n", i, vq->desc + i); - return vq->num; + return -EFAULT; } if (desc.flags & VRING_DESC_F_INDIRECT) { ret = get_indirect(dev, vq, iov, iov_size, @@ -954,7 +955,7 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, if (ret < 0) { vq_err(vq, "Failure detected " "in indirect descriptor at idx %d\n", i); - return vq->num; + return ret; } continue; } @@ -964,7 +965,7 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, if (ret < 0) { vq_err(vq, "Translation failure %d descriptor idx %d\n", ret, i); - return vq->num; + return ret; } if (desc.flags & VRING_DESC_F_WRITE) { /* If this is an input descriptor, @@ -981,7 +982,7 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, if (*in_num) { vq_err(vq, "Descriptor has out after in: " "idx %d\n", i); - return vq->num; + return -EINVAL; } *out_num += ret; } diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 44591ba9b07..11ee13dba0f 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -120,10 +120,10 @@ long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg); int vhost_vq_access_ok(struct vhost_virtqueue *vq); int vhost_log_access_ok(struct vhost_dev *); -unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *, - struct iovec iov[], unsigned int iov_count, - unsigned int *out_num, unsigned int *in_num, - struct vhost_log *log, unsigned int *log_num); +int vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *, + struct iovec iov[], unsigned int iov_count, + unsigned int *out_num, unsigned int *in_num, + struct vhost_log *log, unsigned int *log_num); void vhost_discard_vq_desc(struct vhost_virtqueue *); int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len); -- cgit v1.2.3 From c22d7ac844f1cb9c6a5fd20f89ebadc2feef891b Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Fri, 25 Jun 2010 09:50:44 +0000 Subject: bonding: prevent netpoll over bonded interfaces Support for netpoll over bonded interfaces was added here: commit f6dc31a85cd46a959bdd987adad14c3b645e03c1 Author: WANG Cong Date: Thu May 6 00:48:51 2010 -0700 bonding: make bonding support netpoll but it is bad enough that we should probably just disable netpoll over bonding until some of the locking logic in the bonding driver is changed or converted completely to RCU. Simple actions like changing the active slave in active-backup mode will hang the box if a high enough printk debugging level is enabled. Keeping the old code around will be good for anyone that wants to work on it (and for after the RCU conversion), so I propose this small patch rather than ripping it all out. Signed-off-by: Andy Gospodarek Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5e12462a9d5..c3d98dde2f8 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -168,7 +168,7 @@ static int arp_ip_count; static int bond_mode = BOND_MODE_ROUNDROBIN; static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2; static int lacp_fast; - +static int disable_netpoll = 1; const struct bond_parm_tbl bond_lacp_tbl[] = { { "slow", AD_LACP_SLOW}, @@ -1742,15 +1742,23 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_set_carrier(bond); #ifdef CONFIG_NET_POLL_CONTROLLER - if (slaves_support_netpoll(bond_dev)) { - bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; - if (bond_dev->npinfo) - slave_dev->npinfo = bond_dev->npinfo; - } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) { + /* + * Netpoll and bonding is broken, make sure it is not initialized + * until it is fixed. + */ + if (disable_netpoll) { bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; - pr_info("New slave device %s does not support netpoll\n", - slave_dev->name); - pr_info("Disabling netpoll support for %s\n", bond_dev->name); + } else { + if (slaves_support_netpoll(bond_dev)) { + bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; + if (bond_dev->npinfo) + slave_dev->npinfo = bond_dev->npinfo; + } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) { + bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; + pr_info("New slave device %s does not support netpoll\n", + slave_dev->name); + pr_info("Disabling netpoll support for %s\n", bond_dev->name); + } } #endif read_unlock(&bond->lock); @@ -1950,8 +1958,11 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) #ifdef CONFIG_NET_POLL_CONTROLLER read_lock_bh(&bond->lock); - if (slaves_support_netpoll(bond_dev)) - bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; + + /* Make sure netpoll over stays disabled until fixed. */ + if (!disable_netpoll) + if (slaves_support_netpoll(bond_dev)) + bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; read_unlock_bh(&bond->lock); if (slave_dev->netdev_ops->ndo_netpoll_cleanup) slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev); -- cgit v1.2.3 From fa37813401ff52d78591c262d6542e4d5d935584 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Tue, 29 Jun 2010 18:28:12 +0000 Subject: ixgbe: fix panic when shutting down system with WoL enabled This patch added to 2.6.34: commit 5f6c01819979afbfec7e0b15fe52371b8eed87e8 Author: Jesse Brandeburg Date: Wed Apr 14 16:04:23 2010 -0700 ixgbe: fix bug with vlan strip in promsic mode among other things added a function called ixgbe_vlan_filter_enable. This new function wants to access and set some rx_ring parameters, but adapter->rx_ring has already been freed. This simply moves the free until after the access and makes __ixgbe_shutdown look more like ixgbe_remove. Signed-off-by: Andy Gospodarek Acked-by: Jesse Brandeburg Tested-by: Emil Tantilov Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index ce30c62a97f..e237748995c 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5195,7 +5195,6 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) ixgbe_free_all_tx_resources(adapter); ixgbe_free_all_rx_resources(adapter); } - ixgbe_clear_interrupt_scheme(adapter); #ifdef CONFIG_PM retval = pci_save_state(pdev); @@ -5230,6 +5229,8 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) *enable_wake = !!wufc; + ixgbe_clear_interrupt_scheme(adapter); + ixgbe_release_hw_control(adapter); pci_disable_device(pdev); -- cgit v1.2.3 From 9f756f018a6d9f83556f972ce7fcd6870274efae Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 29 Jun 2010 18:28:36 +0000 Subject: ixgbe: disable tx engine before disabling tx laser Disabling the tx laser while receiving DMA requests can hang the device. After this occurs the device is in a bad state. The GPIO bit never clears when PCI master access is disabled and a reboot is required to get the device in a good state again. Signed-off-by: John Fastabend Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index e237748995c..7ddd60e7d38 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3684,10 +3684,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter) /* signal that we are down to the interrupt handler */ set_bit(__IXGBE_DOWN, &adapter->state); - /* power down the optics */ - if (hw->phy.multispeed_fiber) - hw->mac.ops.disable_tx_laser(hw); - /* disable receive for all VFs and wait one second */ if (adapter->num_vfs) { /* ping all the active vfs to let them know we are going down */ @@ -3742,6 +3738,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter) (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) & ~IXGBE_DMATXCTL_TE)); + /* power down the optics */ + if (hw->phy.multispeed_fiber) + hw->mac.ops.disable_tx_laser(hw); + /* clear n-tuple filters that are cached */ ethtool_ntuple_flush(netdev); -- cgit v1.2.3 From d3ead2413cb99d3e6265577b12537434e229d8c2 Mon Sep 17 00:00:00 2001 From: Guillaume Gaudonville Date: Tue, 29 Jun 2010 18:29:00 +0000 Subject: ixgbe: skip non IPv4 packets in ATR filter In driver ixgbe, ixgbe_atr may cause crashes for non-ipv4 packets. Just add a test to check skb->protocol. It may crash on short packets due to ip_hdr() access. Signed-off-by: Guillaume Gaudonville Acked-by: Peter P Waskiewicz Jr Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 7ddd60e7d38..a0b33165b98 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -6024,7 +6024,6 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, int queue, u32 tx_flags) { - /* Right now, we support IPv4 only */ struct ixgbe_atr_input atr_input; struct tcphdr *th; struct iphdr *iph = ip_hdr(skb); @@ -6033,6 +6032,9 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, u32 src_ipv4_addr, dst_ipv4_addr; u8 l4type = 0; + /* Right now, we support IPv4 only */ + if (skb->protocol != htons(ETH_P_IP)) + return; /* check if we're UDP or TCP */ if (iph->protocol == IPPROTO_TCP) { th = tcp_hdr(skb); -- cgit v1.2.3 From 9b2c2ff7a1c04e69842254dd4afe0f8ad4efa439 Mon Sep 17 00:00:00 2001 From: Saeed Bishara Date: Sun, 27 Jun 2010 00:26:43 +0000 Subject: mv643xx_eth: use sw csum for big packets Some controllers (KW, Dove) limits the TX IP/layer4 checksum offloading to a max size. Signed-off-by: Saeed Bishara Acked-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index e345ec8cb47..73bb8ea6f54 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -289,6 +289,7 @@ struct mv643xx_eth_shared_private { unsigned int t_clk; int extended_rx_coal_limit; int tx_bw_control; + int tx_csum_limit; }; #define TX_BW_CONTROL_ABSENT 0 @@ -776,13 +777,16 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) l4i_chk = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) { + int hdr_len; int tag_bytes; BUG_ON(skb->protocol != htons(ETH_P_IP) && skb->protocol != htons(ETH_P_8021Q)); - tag_bytes = (void *)ip_hdr(skb) - (void *)skb->data - ETH_HLEN; - if (unlikely(tag_bytes & ~12)) { + hdr_len = (void *)ip_hdr(skb) - (void *)skb->data; + tag_bytes = hdr_len - ETH_HLEN; + if (skb->len - hdr_len > mp->shared->tx_csum_limit || + unlikely(tag_bytes & ~12)) { if (skb_checksum_help(skb) == 0) goto no_csum; kfree_skb(skb); @@ -2666,6 +2670,7 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) * Detect hardware parameters. */ msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000; + msp->tx_csum_limit = pd->tx_csum_limit ? pd->tx_csum_limit : 9 * 1024; infer_hw_params(msp); platform_set_drvdata(pdev, msp); -- cgit v1.2.3 From dd1589a431e90f9ff587e640c67101a565e52bba Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 30 Jun 2010 13:10:09 -0700 Subject: Bluetooth: Fix abuse of the preincrement operator Fix abuse of the preincrement operator as detected when building with gcc 4.6.0: CC [M] drivers/bluetooth/hci_bcsp.o drivers/bluetooth/hci_bcsp.c: In function 'bcsp_prepare_pkt': drivers/bluetooth/hci_bcsp.c:247:20: warning: operation on 'bcsp->msgq_txseq' may be undefined Reported-by: Justin P. Mattock Signed-off-by: David Howells Acked-by: Gustavo F. Padovan Signed-off-by: David S. Miller --- drivers/bluetooth/hci_bcsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 40aec0fb859..42d69d4de05 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -244,7 +244,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, if (rel) { hdr[0] |= 0x80 + bcsp->msgq_txseq; BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); - bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; + bcsp->msgq_txseq = (bcsp->msgq_txseq + 1) & 0x07; } if (bcsp->use_crc) -- cgit v1.2.3 From 42d782ac1bef7cbcdf05b857731345c6e8149f90 Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Tue, 29 Jun 2010 08:24:39 +0000 Subject: bonding: check if clients MAC addr has changed When two systems using bonding devices in adaptive load balancing (ALB) communicates with each other, an endless ping-pong of ARP replies starts between these two systems. What happens? In the ALB mode, bonding driver keeps track of each client connected in a hash table, so it can do the receive load balancing (RLB). This hash table is updated when an ARP reply is received, then it scans for the client entry, updates its MAC address and flag it to be announced later. Therefore, two seconds later, the alb monitor runs and send for each updated client entry two ARP replies updating this specific client. The same process happens on the receiving system, causing the endless ping-pong of arp replies. See more information including the relevant functions below: System 1 System 2 bond0 bond0 ping ARP request ---------> <--------- ARP reply +->rlb_arp_recv <---------------------+ <--- loop begins | rlb_update_entry_from_arp | | client_info->ntt = 1; | | bond_info->rx_ntt = 1; | | | | | | | | bond_alb_monitor | | rlb_update_rx_clients | | rlb_update_client | | arp_create(ARPOP_REPLY) | | send ARP reply --------------> V | send ARP reply --------------> | rlb_arp_recv | rlb_update_entry_from_arp | client_info->ntt = 1; | bond_info->rx_ntt = 1; | < snipped, same as in system 1> +------- <-------------- send ARP reply <-------------- send ARP reply Besides the unneeded networking traffic, this loop breaks a cluster because a backup system can't take over the IP address. There is always one system sending an ARP reply poisoning the network. This patch fixes the problem adding a check for the MAC address before updating it. Thus, if the MAC address didn't change, there is no need to update neither to announce it later. Signed-off-by: Flavio Leitner Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 40fdc41446c..df483076eda 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -340,7 +340,8 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) if ((client_info->assigned) && (client_info->ip_src == arp->ip_dst) && - (client_info->ip_dst == arp->ip_src)) { + (client_info->ip_dst == arp->ip_src) && + (compare_ether_addr_64bits(client_info->mac_dst, arp->mac_src))) { /* update the clients MAC address */ memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN); client_info->ntt = 1; -- cgit v1.2.3 From 7b3384fc30633738ae4eaf8e1bc6ce70470ced80 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 1 Jul 2010 18:40:12 +0300 Subject: vhost: add unlikely annotations to error path patch 'break out of polling loop on error' caused a minor performance regression on my machine: recover that performance by adding a bunch of unlikely annotations in the error handling. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 4 ++-- drivers/vhost/vhost.c | 53 ++++++++++++++++++++++++++------------------------- 2 files changed, 29 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 54096eef484..2406377a6e5 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -137,7 +137,7 @@ static void handle_tx(struct vhost_net *net) &out, &in, NULL, NULL); /* On error, stop handling until the next kick. */ - if (head < 0) + if (unlikely(head < 0)) break; /* Nothing new? Wait for eventfd to tell us they refilled. */ if (head == vq->num) { @@ -234,7 +234,7 @@ static void handle_rx(struct vhost_net *net) &out, &in, vq_log, &log); /* On error, stop handling until the next kick. */ - if (head < 0) + if (unlikely(head < 0)) break; /* OK, now we need to know about added descriptors. */ if (head == vq->num) { diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 5ccd384ec0b..0b99783083f 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -736,12 +736,12 @@ static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len, mem = rcu_dereference(dev->memory); while ((u64)len > s) { u64 size; - if (ret >= iov_size) { + if (unlikely(ret >= iov_size)) { ret = -ENOBUFS; break; } reg = find_region(mem, addr, len); - if (!reg) { + if (unlikely(!reg)) { ret = -EFAULT; break; } @@ -780,18 +780,18 @@ static unsigned next_desc(struct vring_desc *desc) return next; } -static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, - struct iovec iov[], unsigned int iov_size, - unsigned int *out_num, unsigned int *in_num, - struct vhost_log *log, unsigned int *log_num, - struct vring_desc *indirect) +static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, + struct iovec iov[], unsigned int iov_size, + unsigned int *out_num, unsigned int *in_num, + struct vhost_log *log, unsigned int *log_num, + struct vring_desc *indirect) { struct vring_desc desc; unsigned int i = 0, count, found = 0; int ret; /* Sanity check */ - if (indirect->len % sizeof desc) { + if (unlikely(indirect->len % sizeof desc)) { vq_err(vq, "Invalid length in indirect descriptor: " "len 0x%llx not multiple of 0x%zx\n", (unsigned long long)indirect->len, @@ -801,7 +801,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, ret = translate_desc(dev, indirect->addr, indirect->len, vq->indirect, ARRAY_SIZE(vq->indirect)); - if (ret < 0) { + if (unlikely(ret < 0)) { vq_err(vq, "Translation failure %d in indirect.\n", ret); return ret; } @@ -813,7 +813,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, count = indirect->len / sizeof desc; /* Buffers are chained via a 16 bit next field, so * we can have at most 2^16 of these. */ - if (count > USHRT_MAX + 1) { + if (unlikely(count > USHRT_MAX + 1)) { vq_err(vq, "Indirect buffer length too big: %d\n", indirect->len); return -E2BIG; @@ -821,19 +821,19 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, do { unsigned iov_count = *in_num + *out_num; - if (++found > count) { + if (unlikely(++found > count)) { vq_err(vq, "Loop detected: last one at %u " "indirect size %u\n", i, count); return -EINVAL; } - if (memcpy_fromiovec((unsigned char *)&desc, vq->indirect, - sizeof desc)) { + if (unlikely(memcpy_fromiovec((unsigned char *)&desc, vq->indirect, + sizeof desc))) { vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n", i, (size_t)indirect->addr + i * sizeof desc); return -EINVAL; } - if (desc.flags & VRING_DESC_F_INDIRECT) { + if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) { vq_err(vq, "Nested indirect descriptor: idx %d, %zx\n", i, (size_t)indirect->addr + i * sizeof desc); return -EINVAL; @@ -841,7 +841,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count, iov_size - iov_count); - if (ret < 0) { + if (unlikely(ret < 0)) { vq_err(vq, "Translation failure %d indirect idx %d\n", ret, i); return ret; @@ -857,7 +857,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, } else { /* If it's an output descriptor, they're all supposed * to come before any input descriptors. */ - if (*in_num) { + if (unlikely(*in_num)) { vq_err(vq, "Indirect descriptor " "has out after in: idx %d\n", i); return -EINVAL; @@ -888,13 +888,13 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, /* Check it isn't doing very strange things with descriptor numbers. */ last_avail_idx = vq->last_avail_idx; - if (get_user(vq->avail_idx, &vq->avail->idx)) { + if (unlikely(get_user(vq->avail_idx, &vq->avail->idx))) { vq_err(vq, "Failed to access avail idx at %p\n", &vq->avail->idx); return -EFAULT; } - if ((u16)(vq->avail_idx - last_avail_idx) > vq->num) { + if (unlikely((u16)(vq->avail_idx - last_avail_idx) > vq->num)) { vq_err(vq, "Guest moved used index from %u to %u", last_avail_idx, vq->avail_idx); return -EFAULT; @@ -909,7 +909,8 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, /* Grab the next descriptor number they're advertising, and increment * the index we've seen. */ - if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) { + if (unlikely(get_user(head, + &vq->avail->ring[last_avail_idx % vq->num]))) { vq_err(vq, "Failed to read head: idx %d address %p\n", last_avail_idx, &vq->avail->ring[last_avail_idx % vq->num]); @@ -917,7 +918,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, } /* If their number is silly, that's an error. */ - if (head >= vq->num) { + if (unlikely(head >= vq->num)) { vq_err(vq, "Guest says index %u > %u is available", head, vq->num); return -EINVAL; @@ -931,19 +932,19 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, i = head; do { unsigned iov_count = *in_num + *out_num; - if (i >= vq->num) { + if (unlikely(i >= vq->num)) { vq_err(vq, "Desc index is %u > %u, head = %u", i, vq->num, head); return -EINVAL; } - if (++found > vq->num) { + if (unlikely(++found > vq->num)) { vq_err(vq, "Loop detected: last one at %u " "vq size %u head %u\n", i, vq->num, head); return -EINVAL; } ret = copy_from_user(&desc, vq->desc + i, sizeof desc); - if (ret) { + if (unlikely(ret)) { vq_err(vq, "Failed to get descriptor: idx %d addr %p\n", i, vq->desc + i); return -EFAULT; @@ -952,7 +953,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, ret = get_indirect(dev, vq, iov, iov_size, out_num, in_num, log, log_num, &desc); - if (ret < 0) { + if (unlikely(ret < 0)) { vq_err(vq, "Failure detected " "in indirect descriptor at idx %d\n", i); return ret; @@ -962,7 +963,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count, iov_size - iov_count); - if (ret < 0) { + if (unlikely(ret < 0)) { vq_err(vq, "Translation failure %d descriptor idx %d\n", ret, i); return ret; @@ -979,7 +980,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, } else { /* If it's an output descriptor, they're all supposed * to come before any input descriptors. */ - if (*in_num) { + if (unlikely(*in_num)) { vq_err(vq, "Descriptor has out after in: " "idx %d\n", i); return -EINVAL; -- cgit v1.2.3 From c89827e0e9346c039aed9b63c14096c2d36796b1 Mon Sep 17 00:00:00 2001 From: Cody Rester Date: Thu, 1 Jul 2010 21:27:44 -0700 Subject: drivers: bluetooth: bluecard_cs.c: Fixed include error, changed to linux/io.h Fixed include error, changed to linux/io.h Signed-off-by: Cody Rester Acked-by: Gustavo F. Padovan Signed-off-by: David S. Miller --- drivers/bluetooth/bluecard_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 6f907ebed2d..6d34f405a2f 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include -- cgit v1.2.3 From 7b00ac51ffcda994ef0839001257be894cc6e5a8 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 2 Jul 2010 21:47:54 -0700 Subject: net: Revert "rndis_host: Poll status channel before control channel" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit c17b274dc2aa538b68c1f02b01a3c4e124b435ba. That change was reported to break rndis_wlan support for the WUSB54GS. Reported-by: Luís Picciochi Oliveira Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/usb/rndis_host.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 28d3ee175e7..dd8a4adf48c 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -104,10 +104,8 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) { struct cdc_state *info = (void *) &dev->data; - struct usb_cdc_notification notification; int master_ifnum; int retval; - int partial; unsigned count; __le32 rsp; u32 xid = 0, msg_len, request_id; @@ -135,17 +133,13 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) if (unlikely(retval < 0 || xid == 0)) return retval; - /* Some devices don't respond on the control channel until - * polled on the status channel, so do that first. */ - retval = usb_interrupt_msg( - dev->udev, - usb_rcvintpipe(dev->udev, dev->status->desc.bEndpointAddress), - ¬ification, sizeof(notification), &partial, - RNDIS_CONTROL_TIMEOUT_MS); - if (unlikely(retval < 0)) - return retval; + // FIXME Seems like some devices discard responses when + // we time out and cancel our "get response" requests... + // so, this is fragile. Probably need to poll for status. - /* Poll the control channel; the request probably completed immediately */ + /* ignore status endpoint, just poll the control channel; + * the request probably completed immediately + */ rsp = buf->msg_type | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { memset(buf, 0, CONTROL_BUFFER_SIZE); -- cgit v1.2.3 From 0dacca73a3ddefa6cb8a7e0282f938e01faa1a64 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 2 Jul 2010 21:49:02 -0700 Subject: usbnet: Set parent device early for netdev_printk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit netdev_printk() follows the net_device's parent device pointer, so we must set that earlier than we previously did. Reported-by: Luís Picciochi Oliveira Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index a95c73de582..81c76ada8e5 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1293,6 +1293,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) goto out; } + /* netdev_printk() needs this so do it as early as possible */ + SET_NETDEV_DEV(net, &udev->dev); + dev = netdev_priv(net); dev->udev = xdev; dev->intf = udev; @@ -1377,8 +1380,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->rx_urb_size = dev->hard_mtu; dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); - SET_NETDEV_DEV(net, &udev->dev); - if ((dev->driver_info->flags & FLAG_WLAN) != 0) SET_NETDEV_DEVTYPE(net, &wlan_type); if ((dev->driver_info->flags & FLAG_WWAN) != 0) -- cgit v1.2.3 From 72046d84f0d6e3047f4d5a5173260141983b2b61 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 1 Jul 2010 03:00:17 +0000 Subject: qlge: Replacing add_timer() to mod_timer() Currently qlge driver calls add_timer() instead of mod_timer(). This patch changes add_timer() to mod_timer(), which seems a better solution. Signed-off-by: Breno Leitao Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index fa4b24c49f4..509dadcd1c5 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4611,8 +4611,7 @@ static void ql_timer(unsigned long data) return; } - qdev->timer.expires = jiffies + (5*HZ); - add_timer(&qdev->timer); + mod_timer(&qdev->timer, jiffies + (5*HZ)); } static int __devinit qlge_probe(struct pci_dev *pdev, @@ -4808,8 +4807,7 @@ static void qlge_io_resume(struct pci_dev *pdev) netif_err(qdev, ifup, qdev->ndev, "Device was not running prior to EEH.\n"); } - qdev->timer.expires = jiffies + (5*HZ); - add_timer(&qdev->timer); + mod_timer(&qdev->timer, jiffies + (5*HZ)); netif_device_attach(ndev); } @@ -4871,8 +4869,7 @@ static int qlge_resume(struct pci_dev *pdev) return err; } - qdev->timer.expires = jiffies + (5*HZ); - add_timer(&qdev->timer); + mod_timer(&qdev->timer, jiffies + (5*HZ)); netif_device_attach(ndev); return 0; -- cgit v1.2.3 From 7ae80abdba0644e12ac17da567a2db1efc1bf8a8 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 1 Jul 2010 03:00:18 +0000 Subject: qlge: fix a eeh handler to not add a pending timer On some ocasions the function qlge_io_resume() tries to add a pending timer, which causes the system to hit the BUG() on add_timer() function. This patch removes the timer during the EEH recovery. Signed-off-by: Breno Leitao Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 509dadcd1c5..d10bcefc0e4 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4712,6 +4712,8 @@ static void ql_eeh_close(struct net_device *ndev) netif_stop_queue(ndev); } + /* Disabling the timer */ + del_timer_sync(&qdev->timer); if (test_bit(QL_ADAPTER_UP, &qdev->flags)) cancel_delayed_work_sync(&qdev->asic_reset_work); cancel_delayed_work_sync(&qdev->mpi_reset_work); -- cgit v1.2.3 From f0796d5c73e59786d09a1e617689d1d415f2db44 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Thu, 1 Jul 2010 13:21:57 +0000 Subject: net: decreasing real_num_tx_queues needs to flush qdisc Reducing real_num_queues needs to flush the qdisc otherwise skbs with queue_mappings greater then real_num_tx_queues can be sent to the underlying driver. The flow for this is, dev_queue_xmit() dev_pick_tx() skb_tx_hash() => hash using real_num_tx_queues skb_set_queue_mapping() ... qdisc_enqueue_root() => enqueue skb on txq from hash ... dev->real_num_tx_queues -= n ... sch_direct_xmit() dev_hard_start_xmit() ndo_start_xmit(skb,dev) => skb queue set with old hash skbs are enqueued on the qdisc with skb->queue_mapping set 0 < queue_mappings < real_num_tx_queues. When the driver decreases real_num_tx_queues skb's may be dequeued from the qdisc with a queue_mapping greater then real_num_tx_queues. This fixes a case in ixgbe where this was occurring with DCB and FCoE. Because the driver is using queue_mapping to map skbs to tx descriptor rings we can potentially map skbs to rings that no longer exist. Signed-off-by: John Fastabend Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index a0b33165b98..7b5d9764f31 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4001,7 +4001,7 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) done: /* Notify the stack of the (possibly) reduced Tx Queue count. */ - adapter->netdev->real_num_tx_queues = adapter->num_tx_queues; + netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues); } static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, -- cgit v1.2.3 From 4a49043223e5047c8f60a09f7b2927a2e6e8dfc7 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Fri, 2 Jul 2010 09:13:49 +0000 Subject: s2io: resolve statistics issues This patch resolves a number of issues in the statistics gathering of the s2io driver. On Xframe adapters, the received multicast statistics counter includes pause frames which are not indicated to the driver. This can cause issues where the multicast packet count is higher than what has actually been received, possibly higher than the number of packets received. The driver software counters are replaced with the adapter hardware statistics for rx_packets, rx_bytes, and tx_bytes. It also uses the overflow registers to determine if the statistics wrapped the 32bit register (removing the window of having a statistic value less than the previous call). rx_length_errors statistic now includes undersized packets in addition to oversized packets in its counting. Finally, rx_crc_errors are now being counted. Signed-off-by: Jon Mason Signed-off-by: David S. Miller --- drivers/net/s2io.c | 101 +++++++++++++++++++++++++++++++++-------------------- drivers/net/s2io.h | 4 --- 2 files changed, 64 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 668327ccd8d..1d37f0c310c 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3130,7 +3130,6 @@ static void tx_intr_handler(struct fifo_info *fifo_data) pkt_cnt++; /* Updating the statistics block */ - nic->dev->stats.tx_bytes += skb->len; swstats->mem_freed += skb->truesize; dev_kfree_skb_irq(skb); @@ -4901,48 +4900,81 @@ static void s2io_updt_stats(struct s2io_nic *sp) * Return value: * pointer to the updated net_device_stats structure. */ - static struct net_device_stats *s2io_get_stats(struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); - struct config_param *config = &sp->config; struct mac_info *mac_control = &sp->mac_control; struct stat_block *stats = mac_control->stats_info; - int i; + u64 delta; /* Configure Stats for immediate updt */ s2io_updt_stats(sp); - /* Using sp->stats as a staging area, because reset (due to mtu - change, for example) will clear some hardware counters */ - dev->stats.tx_packets += le32_to_cpu(stats->tmac_frms) - - sp->stats.tx_packets; - sp->stats.tx_packets = le32_to_cpu(stats->tmac_frms); - - dev->stats.tx_errors += le32_to_cpu(stats->tmac_any_err_frms) - - sp->stats.tx_errors; - sp->stats.tx_errors = le32_to_cpu(stats->tmac_any_err_frms); - - dev->stats.rx_errors += le64_to_cpu(stats->rmac_drop_frms) - - sp->stats.rx_errors; - sp->stats.rx_errors = le64_to_cpu(stats->rmac_drop_frms); - - dev->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms) - - sp->stats.multicast; - sp->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms); - - dev->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms) - - sp->stats.rx_length_errors; - sp->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms); + /* A device reset will cause the on-adapter statistics to be zero'ed. + * This can be done while running by changing the MTU. To prevent the + * system from having the stats zero'ed, the driver keeps a copy of the + * last update to the system (which is also zero'ed on reset). This + * enables the driver to accurately know the delta between the last + * update and the current update. + */ + delta = ((u64) le32_to_cpu(stats->rmac_vld_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_vld_frms)) - sp->stats.rx_packets; + sp->stats.rx_packets += delta; + dev->stats.rx_packets += delta; + + delta = ((u64) le32_to_cpu(stats->tmac_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_frms)) - sp->stats.tx_packets; + sp->stats.tx_packets += delta; + dev->stats.tx_packets += delta; + + delta = ((u64) le32_to_cpu(stats->rmac_data_octets_oflow) << 32 | + le32_to_cpu(stats->rmac_data_octets)) - sp->stats.rx_bytes; + sp->stats.rx_bytes += delta; + dev->stats.rx_bytes += delta; + + delta = ((u64) le32_to_cpu(stats->tmac_data_octets_oflow) << 32 | + le32_to_cpu(stats->tmac_data_octets)) - sp->stats.tx_bytes; + sp->stats.tx_bytes += delta; + dev->stats.tx_bytes += delta; + + delta = le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_errors; + sp->stats.rx_errors += delta; + dev->stats.rx_errors += delta; + + delta = ((u64) le32_to_cpu(stats->tmac_any_err_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_any_err_frms)) - sp->stats.tx_errors; + sp->stats.tx_errors += delta; + dev->stats.tx_errors += delta; + + delta = le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_dropped; + sp->stats.rx_dropped += delta; + dev->stats.rx_dropped += delta; + + delta = le64_to_cpu(stats->tmac_drop_frms) - sp->stats.tx_dropped; + sp->stats.tx_dropped += delta; + dev->stats.tx_dropped += delta; + + /* The adapter MAC interprets pause frames as multicast packets, but + * does not pass them up. This erroneously increases the multicast + * packet count and needs to be deducted when the multicast frame count + * is queried. + */ + delta = (u64) le32_to_cpu(stats->rmac_vld_mcst_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_vld_mcst_frms); + delta -= le64_to_cpu(stats->rmac_pause_ctrl_frms); + delta -= sp->stats.multicast; + sp->stats.multicast += delta; + dev->stats.multicast += delta; - /* collect per-ring rx_packets and rx_bytes */ - dev->stats.rx_packets = dev->stats.rx_bytes = 0; - for (i = 0; i < config->rx_ring_num; i++) { - struct ring_info *ring = &mac_control->rings[i]; + delta = ((u64) le32_to_cpu(stats->rmac_usized_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_usized_frms)) + + le64_to_cpu(stats->rmac_long_frms) - sp->stats.rx_length_errors; + sp->stats.rx_length_errors += delta; + dev->stats.rx_length_errors += delta; - dev->stats.rx_packets += ring->rx_packets; - dev->stats.rx_bytes += ring->rx_bytes; - } + delta = le64_to_cpu(stats->rmac_fcs_err_frms) - sp->stats.rx_crc_errors; + sp->stats.rx_crc_errors += delta; + dev->stats.rx_crc_errors += delta; return &dev->stats; } @@ -7455,15 +7487,11 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) } } - /* Updating statistics */ - ring_data->rx_packets++; rxdp->Host_Control = 0; if (sp->rxd_mode == RXD_MODE_1) { int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2); - ring_data->rx_bytes += len; skb_put(skb, len); - } else if (sp->rxd_mode == RXD_MODE_3B) { int get_block = ring_data->rx_curr_get_info.block_index; int get_off = ring_data->rx_curr_get_info.offset; @@ -7472,7 +7500,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) unsigned char *buff = skb_push(skb, buf0_len); struct buffAdd *ba = &ring_data->ba[get_block][get_off]; - ring_data->rx_bytes += buf0_len + buf2_len; memcpy(buff, ba->ba_0, buf0_len); skb_put(skb, buf2_len); } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 47c36e0994f..5e52c75892d 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -745,10 +745,6 @@ struct ring_info { /* Buffer Address store. */ struct buffAdd **ba; - - /* per-Ring statistics */ - unsigned long rx_packets; - unsigned long rx_bytes; } ____cacheline_aligned; /* Fifo specific structure */ -- cgit v1.2.3 From 1788f49548860fa1c861ee3454d47b466c877e43 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 2 Jul 2010 16:32:55 +0000 Subject: virtio_net: do not reschedule rx refill forever We currently fill all of RX ring, then add_buf returns ENOSPC, which gets mis-detected as an out of memory condition and causes us to reschedule the work, and so on forever. Fix this by oom = err == -ENOMEM; Signed-off-by: Michael S. Tsirkin Signed-off-by: Rusty Russell Cc: stable@kernel.org # .34.x Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1edb7a61983..ee7571195b1 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -415,7 +415,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp) static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp) { int err; - bool oom = false; + bool oom; do { if (vi->mergeable_rx_bufs) @@ -425,10 +425,9 @@ static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp) else err = add_recvbuf_small(vi, gfp); - if (err < 0) { - oom = true; + oom = err == -ENOMEM; + if (err < 0) break; - } ++vi->num; } while (err > 0); if (unlikely(vi->num > vi->max)) -- cgit v1.2.3 From 58eba97d0774c69b1cf3e5a8ac74419409d1abbf Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 2 Jul 2010 16:34:01 +0000 Subject: virtio_net: fix oom handling on tx virtio net will never try to overflow the TX ring, so the only reason add_buf may fail is out of memory. Thus, we can not stop the device until some request completes - there's no guarantee anything at all is outstanding. Make the error message clearer as well: error here does not indicate queue full. Signed-off-by: Michael S. Tsirkin Signed-off-by: Rusty Russell (...and avoid TX_BUSY) Cc: stable@kernel.org # .34.x (s/virtqueue_/vi->svq->vq_ops->/) Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index ee7571195b1..bb6b67f6b0c 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -562,7 +562,6 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) struct virtnet_info *vi = netdev_priv(dev); int capacity; -again: /* Free up any pending old buffers before queueing new ones. */ free_old_xmit_skbs(vi); @@ -571,14 +570,20 @@ again: /* This can happen with OOM and indirect buffers. */ if (unlikely(capacity < 0)) { - netif_stop_queue(dev); - dev_warn(&dev->dev, "Unexpected full queue\n"); - if (unlikely(!virtqueue_enable_cb(vi->svq))) { - virtqueue_disable_cb(vi->svq); - netif_start_queue(dev); - goto again; + if (net_ratelimit()) { + if (likely(capacity == -ENOMEM)) { + dev_warn(&dev->dev, + "TX queue failure: out of memory\n"); + } else { + dev->stats.tx_fifo_errors++; + dev_warn(&dev->dev, + "Unexpected TX queue failure: %d\n", + capacity); + } } - return NETDEV_TX_BUSY; + dev->stats.tx_dropped++; + kfree_skb(skb); + return NETDEV_TX_OK; } virtqueue_kick(vi->svq); -- cgit v1.2.3 From 3390712a474abdcd3de10024dd1062e5928d381c Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Sat, 3 Jul 2010 05:20:42 +0000 Subject: net/ne: fix memory leak in ne_drv_probe() net_device allocated with alloc_eip_netdev() must be freed. Signed-off-by: Kulikov Vasiliy Signed-off-by: David S. Miller --- drivers/net/ne.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ne.c b/drivers/net/ne.c index b8e2923a1d6..1063093b3af 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -806,8 +806,10 @@ static int __init ne_drv_probe(struct platform_device *pdev) dev->base_addr = res->start; dev->irq = platform_get_irq(pdev, 0); } else { - if (this_dev < 0 || this_dev >= MAX_NE_CARDS) + if (this_dev < 0 || this_dev >= MAX_NE_CARDS) { + free_netdev(dev); return -EINVAL; + } dev->base_addr = io[this_dev]; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; -- cgit v1.2.3 From dfe1e8eddcd73fc58124933c14c2efe93fab0b8f Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Mon, 5 Jul 2010 21:44:20 +0000 Subject: ll_temac: Fix missing iounmaps Fix missing iounmaps. Signed-off-by: Denis Kirjanov Signed-off-by: David S. Miller --- drivers/net/ll_temac_main.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 52dcc849564..6474c4973d3 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -964,7 +964,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) np = of_parse_phandle(op->dev.of_node, "llink-connected", 0); if (!np) { dev_err(&op->dev, "could not find DMA node\n"); - goto nodev; + goto err_iounmap; } /* Setup the DMA register accesses, could be DCR or memory mapped */ @@ -978,7 +978,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs); } else { dev_err(&op->dev, "unable to map DMA registers\n"); - goto nodev; + goto err_iounmap; } } @@ -987,7 +987,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) { dev_err(&op->dev, "could not determine irqs\n"); rc = -ENOMEM; - goto nodev; + goto err_iounmap_2; } of_node_put(np); /* Finished with the DMA node; drop the reference */ @@ -997,7 +997,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) if ((!addr) || (size != 6)) { dev_err(&op->dev, "could not find MAC address\n"); rc = -ENODEV; - goto nodev; + goto err_iounmap_2; } temac_set_mac_address(ndev, (void *)addr); @@ -1013,7 +1013,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group); if (rc) { dev_err(lp->dev, "Error creating sysfs files\n"); - goto nodev; + goto err_iounmap_2; } rc = register_netdev(lp->ndev); @@ -1026,6 +1026,11 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) err_register_ndev: sysfs_remove_group(&lp->dev->kobj, &temac_attr_group); + err_iounmap_2: + if (lp->sdma_regs) + iounmap(lp->sdma_regs); + err_iounmap: + iounmap(lp->regs); nodev: free_netdev(ndev); ndev = NULL; @@ -1044,6 +1049,9 @@ static int __devexit temac_of_remove(struct of_device *op) of_node_put(lp->phy_node); lp->phy_node = NULL; dev_set_drvdata(&op->dev, NULL); + iounmap(lp->regs); + if (lp->sdma_regs) + iounmap(lp->sdma_regs); free_netdev(ndev); return 0; } -- cgit v1.2.3 From 7074b16cc6bd27b1962e8f592b3733ebe92f4897 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 6 Jul 2010 03:02:03 +0000 Subject: vxge: show startup message with KERN_INFO The original KERN_CRIT will mess up terminals. CC: Sreenivasa Honnur Signed-off-by: Wu Fengguang Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index d14e207de1d..fc8b2d7a091 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -4517,9 +4517,9 @@ vxge_starter(void) char version[32]; snprintf(version, 32, "%s", DRV_VERSION); - printk(KERN_CRIT "%s: Copyright(c) 2002-2009 Neterion Inc\n", + printk(KERN_INFO "%s: Copyright(c) 2002-2009 Neterion Inc\n", VXGE_DRIVER_NAME); - printk(KERN_CRIT "%s: Driver version: %s\n", + printk(KERN_INFO "%s: Driver version: %s\n", VXGE_DRIVER_NAME, version); verify_bandwidth(); -- cgit v1.2.3 From 33b665eeeb85956ccbdf31c4c31a4e2a31133c44 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 6 Jul 2010 05:18:11 +0000 Subject: NET: SB1250: Initialize .owner Signed-off-by: Ralf Baechle drivers/net/sb1250-mac.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) Signed-off-by: David S. Miller --- drivers/net/sb1250-mac.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 1f3acc3a5df..79eee306208 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2671,6 +2671,7 @@ static struct platform_driver sbmac_driver = { .remove = __exit_p(sbmac_remove), .driver = { .name = sbmac_string, + .owner = THIS_MODULE, }, }; -- cgit v1.2.3