From 63f4e1903ae41b4e457dd4490afe0f59e7641ad6 Mon Sep 17 00:00:00 2001 From: Guillaume Chazarain Date: Sat, 6 Nov 2010 06:39:31 +0000 Subject: skge: Remove tx queue stopping in skge_devinit() After e6484930d7c73d324bccda7d43d131088da697b9: net: allocate tx queues in register_netdevice It causes an Oops at skge_probe() time. Signed-off-by: Guillaume Chazarain Signed-off-by: David S. Miller --- drivers/net/skge.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index bfec2e0f5275..220e0398f1d5 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3858,7 +3858,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, /* device is off until link detection */ netif_carrier_off(dev); - netif_stop_queue(dev); return dev; } -- cgit v1.2.3 From 269e2d77b82d92d8dad543a2375e74372e9d773e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 8 Nov 2010 16:27:12 -0500 Subject: libipw: fix proc entry removal This bug seems to be due to commit 27ae60f8f7aac ("ipw2x00: replace "ieee80211" with "libipw" where appropriate"), where Pavel did this: - libipw_proc = proc_mkdir(DRV_NAME, init_net.proc_net); + libipw_proc = proc_mkdir("ieee80211", init_net.proc_net); but then the cleanup was kept as remove_proc_entry(DRV_NAME, init_net.proc_net); in both places (both in the failure case and in the unload case). The error string is also total crap, and says "Unable to create " DRV_NAME " proc directory\n"); Even though it doesn't actually create a proc directory named DRV_NAME at all. So that patch looks like total and utter crap to me. The commit message says "Keep /proc/net/ieee80211 under the original name to avoid breaking user interface." but the thing is, it really didn't fix anything but that one create thing. It needs to fix all the other cases too. Signed-off-by: Linus Torvalds Tested-by: Randy Dunlap Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/libipw_module.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index 32dee2ce5d31..d5ef696298ee 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -54,6 +54,7 @@ #define DRV_DESCRIPTION "802.11 data/management/control stack" #define DRV_NAME "libipw" +#define DRV_PROCNAME "ieee80211" #define DRV_VERSION LIBIPW_VERSION #define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation " @@ -293,16 +294,16 @@ static int __init libipw_init(void) struct proc_dir_entry *e; libipw_debug_level = debug; - libipw_proc = proc_mkdir("ieee80211", init_net.proc_net); + libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net); if (libipw_proc == NULL) { - LIBIPW_ERROR("Unable to create " DRV_NAME + LIBIPW_ERROR("Unable to create " DRV_PROCNAME " proc directory\n"); return -EIO; } e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc, &debug_level_proc_fops); if (!e) { - remove_proc_entry(DRV_NAME, init_net.proc_net); + remove_proc_entry(DRV_PROCNAME, init_net.proc_net); libipw_proc = NULL; return -EIO; } @@ -319,7 +320,7 @@ static void __exit libipw_exit(void) #ifdef CONFIG_LIBIPW_DEBUG if (libipw_proc) { remove_proc_entry("debug_level", libipw_proc); - remove_proc_entry(DRV_NAME, init_net.proc_net); + remove_proc_entry(DRV_PROCNAME, init_net.proc_net); libipw_proc = NULL; } #endif /* CONFIG_LIBIPW_DEBUG */ -- cgit v1.2.3 From 5f841b4130a639e5f0fbcf4a9b26045d734e4ee6 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 27 Oct 2010 18:31:15 +0530 Subject: ath9k: Avoid HW opmode overridden on monitor mode changes The HW opmode is blindly set to monitor type on monitor mode change notification. This overrides the opmode when one of the interfaces is still running as non-monitor iftype. So the monitoring information needs to be maintained seperately. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 14 ++++++++++++-- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 12 ++++++++---- drivers/net/wireless/ath/ath9k/recv.c | 4 ++-- 4 files changed, 23 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index cc13ee117823..c3a49045986d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -952,9 +952,12 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_MONITOR: REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); break; + default: + if (ah->is_monitoring) + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); + break; } } @@ -1634,7 +1637,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) switch (ah->opmode) { case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_MONITOR: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff); REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff); @@ -1663,6 +1665,14 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; break; default: + if (ah->is_monitoring) { + REG_WRITE(ah, AR_NEXT_TBTT_TIMER, + TU_TO_USEC(next_beacon)); + REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff); + REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff); + flags |= AR_TBTT_TIMER_EN; + break; + } ath_print(ath9k_hw_common(ah), ATH_DBG_BEACON, "%s: unsupported opmode: %d\n", __func__, ah->opmode); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index d032939768b0..d47d1b4b6002 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -622,6 +622,7 @@ struct ath_hw { bool sw_mgmt_crypto; bool is_pciexpress; + bool is_monitoring; bool need_an_top2_fixup; u16 tx_trig_level; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b52f1cf8a603..cf6fa54a2fa3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1217,6 +1217,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ah->imask |= ATH9K_INT_CST; sc->sc_flags &= ~SC_OP_INVALID; + sc->sc_ah->is_monitoring = false; /* Disable BMISS interrupt when we're not associated */ ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); @@ -1493,8 +1494,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath9k_hw_set_interrupts(ah, ah->imask); if (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MONITOR) { + vif->type == NL80211_IFTYPE_ADHOC) { sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); } @@ -1644,8 +1644,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if (conf->flags & IEEE80211_CONF_MONITOR) { ath_print(common, ATH_DBG_CONFIG, - "HW opmode set to Monitor mode\n"); - sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; + "Monitor mode is enabled\n"); + sc->sc_ah->is_monitoring = true; + } else { + ath_print(common, ATH_DBG_CONFIG, + "Monitor mode is disabled\n"); + sc->sc_ah->is_monitoring = false; } } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index fddb0129bb57..c76ea53c20ce 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -441,7 +441,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) */ if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) && (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) || - (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR)) + (sc->sc_ah->is_monitoring)) rfilt |= ATH9K_RX_FILTER_PROM; if (sc->rx.rxfilter & FIF_CONTROL) @@ -897,7 +897,7 @@ static bool ath9k_rx_accept(struct ath_common *common, * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ - if (ah->opmode == NL80211_IFTYPE_MONITOR) { + if (ah->is_monitoring) { if (rx_stats->rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) -- cgit v1.2.3 From 10598c124ecabbbfd7522f74de19b8f7d52a1bee Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Sat, 30 Oct 2010 22:05:13 +0530 Subject: ath9k: Fix a DMA latency issue for Intel Pinetrail platforms. Throughput was severely affected in Intel Pinetrail platforms because of a DMA problem in C3 state. This patch fixes this issue. Signed-off-by: Vivek Natarajan CC: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 8 ++++++++ drivers/net/wireless/ath/ath9k/main.c | 5 +++++ 3 files changed, 14 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9b8e7e3fcebd..170d44a35ccb 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -675,6 +675,7 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz) } extern struct ieee80211_ops ath9k_ops; +extern struct pm_qos_request_list ath9k_pm_qos_req; extern int modparam_nohwcrypt; extern int led_blink; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 95b41db0d86b..6a0d99eff404 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -15,6 +15,7 @@ */ #include +#include #include "ath9k.h" @@ -179,6 +180,8 @@ static const struct ath_ops ath9k_common_ops = { .write = ath9k_iowrite32, }; +struct pm_qos_request_list ath9k_pm_qos_req; + /**************************/ /* Initialization */ /**************************/ @@ -756,6 +759,9 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, ath_init_leds(sc); ath_start_rfkill_poll(sc); + pm_qos_add_request(&ath9k_pm_qos_req, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + return 0; error_world: @@ -811,6 +817,8 @@ void ath9k_deinit_device(struct ath_softc *sc) ath9k_ps_wakeup(sc); + pm_qos_remove_request(&ath9k_pm_qos_req); + wiphy_rfkill_stop_polling(sc->hw->wiphy); ath_deinit_leds(sc); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cf6fa54a2fa3..09dcdd7882e6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -15,6 +15,7 @@ */ #include +#include #include "ath9k.h" #include "btcoex.h" @@ -1239,6 +1240,8 @@ static int ath9k_start(struct ieee80211_hw *hw) ath9k_btcoex_timer_resume(sc); } + pm_qos_update_request(&ath9k_pm_qos_req, 55); + mutex_unlock: mutex_unlock(&sc->mutex); @@ -1416,6 +1419,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) sc->sc_flags |= SC_OP_INVALID; + pm_qos_update_request(&ath9k_pm_qos_req, PM_QOS_DEFAULT_VALUE); + mutex_unlock(&sc->mutex); ath_print(common, ATH_DBG_CONFIG, "Driver halt\n"); -- cgit v1.2.3 From 8df86db9060ddd123d172c7adb6b2b71f31e77cd Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 30 Oct 2010 19:46:37 +0200 Subject: carl9170: usbid table updates This patch includes the following updates: * add D-Link DWA-130 Rev D * Netgear has three WNDA3100 versions. the original WNDA3100 is now called WNDA3100v1. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index d8607f4c144d..3317039cd28f 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -82,9 +82,11 @@ static struct usb_device_id carl9170_usb_ids[] = { { USB_DEVICE(0x07d1, 0x3c10) }, /* D-Link DWA 160 A2 */ { USB_DEVICE(0x07d1, 0x3a09) }, + /* D-Link DWA 130 D */ + { USB_DEVICE(0x07d1, 0x3a0f) }, /* Netgear WNA1000 */ { USB_DEVICE(0x0846, 0x9040) }, - /* Netgear WNDA3100 */ + /* Netgear WNDA3100 (v1) */ { USB_DEVICE(0x0846, 0x9010) }, /* Netgear WN111 v2 */ { USB_DEVICE(0x0846, 0x9001), .driver_info = CARL9170_ONE_LED }, -- cgit v1.2.3 From fbb078fcd2fa83646ad9504d8e4c54a67b8729ae Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 3 Nov 2010 01:36:51 +0100 Subject: ath9k: check old power mode before clearing cycle counters ath9k_ps_wakeup() clears the cycle counters after waking up the hardware using ath9k_hw_setpower, however if power save is disabled, then the counters will contain useful data, which then gets discarded. Fix this by checking the old power mode before discarding any data. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 09dcdd7882e6..25d3ef4c338e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -94,11 +94,13 @@ void ath9k_ps_wakeup(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); unsigned long flags; + enum ath9k_power_mode power_mode; spin_lock_irqsave(&sc->sc_pm_lock, flags); if (++sc->ps_usecount != 1) goto unlock; + power_mode = sc->sc_ah->power_mode; ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); /* @@ -106,10 +108,12 @@ void ath9k_ps_wakeup(struct ath_softc *sc) * useful data. Better clear them now so that they don't mess up * survey data results. */ - spin_lock(&common->cc_lock); - ath_hw_cycle_counters_update(common); - memset(&common->cc_survey, 0, sizeof(common->cc_survey)); - spin_unlock(&common->cc_lock); + if (power_mode != ATH9K_PM_AWAKE) { + spin_lock(&common->cc_lock); + ath_hw_cycle_counters_update(common); + memset(&common->cc_survey, 0, sizeof(common->cc_survey)); + spin_unlock(&common->cc_lock); + } unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); -- cgit v1.2.3 From 2e30168ba7dba95710aaadf12b2a97163df067b1 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 4 Nov 2010 21:21:52 +0000 Subject: libertas: terminate scan when stopping interface There are currently no provisions in place to ensure that the scanning task has been stopped when the interface is stopped or removed. This can result in a WARNING at net/wireless/core.c:643 and other badness when you remove the module while a scan is happening. Terminate the scanning task during interface stop. Signed-off-by: Daniel Drake Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cfg.c | 5 +++-- drivers/net/wireless/libertas/dev.h | 1 + drivers/net/wireless/libertas/main.c | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 5046a0005034..373930afc26b 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -700,8 +700,9 @@ static void lbs_scan_worker(struct work_struct *work) if (priv->scan_channel < priv->scan_req->n_channels) { cancel_delayed_work(&priv->scan_work); - queue_delayed_work(priv->work_thread, &priv->scan_work, - msecs_to_jiffies(300)); + if (!priv->stopping) + queue_delayed_work(priv->work_thread, &priv->scan_work, + msecs_to_jiffies(300)); } /* This is the final data we are about to send */ diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f062ed583901..cb14c38caf3a 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -36,6 +36,7 @@ struct lbs_private { /* CFG80211 */ struct wireless_dev *wdev; bool wiphy_registered; + bool stopping; struct cfg80211_scan_request *scan_req; u8 assoc_bss[ETH_ALEN]; u8 disassoc_reason; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 47ce5a6ba120..46b88b118c99 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -104,6 +104,7 @@ static int lbs_dev_open(struct net_device *dev) lbs_deb_enter(LBS_DEB_NET); spin_lock_irq(&priv->driver_lock); + priv->stopping = false; if (priv->connect_status == LBS_CONNECTED) netif_carrier_on(dev); @@ -131,10 +132,16 @@ static int lbs_eth_stop(struct net_device *dev) lbs_deb_enter(LBS_DEB_NET); spin_lock_irq(&priv->driver_lock); + priv->stopping = true; netif_stop_queue(dev); spin_unlock_irq(&priv->driver_lock); schedule_work(&priv->mcast_work); + cancel_delayed_work_sync(&priv->scan_work); + if (priv->scan_req) { + cfg80211_scan_done(priv->scan_req, false); + priv->scan_req = NULL; + } lbs_deb_leave(LBS_DEB_NET); return 0; -- cgit v1.2.3 From f119da3015712dc32bdf1c311652479e02dcb49a Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 4 Nov 2010 17:41:25 -0700 Subject: ath9k_hw: Fix AR9280 surprise removal during frequent idle on/off Bit 22 of AR_WA should be set to fix the situation where chip reset is asynchronous to clock of analog shift registers, such that when reset is released, it could mess up the values of analog shift registers and cause some hw issue on AR9280. This bit is write only, but the driver does a read-modify-write on AR_WA without setting bit 22 in ar9002_hw_configpcipowersave() during radio disable. This causes surprise removal of hw. It can never recover from this state and the hw will become usable only after a power on/off cycle, and sometimes only during a cold reboot. This issue can be triggered by doing frequent roaming with the simple/test-roam script available from the wifi-test project [1] when roaming between APs quickly. When roaming there is a is a high possibility that the device being put into idle (radio disable) state by mac80211 during AUTH->ASSOC. A device hardware reset would fail and the kernel would output: [40251.363799] ath: AWAKE -> FULL-SLEEP [40251.363815] ieee80211 phy17: device no longer idle - working [40251.363817] ath: Marking phy17 as not-idle [40251.363819] ath: FULL-SLEEP -> AWAKE [40251.415978] pciehp 0000:00:1c.3:pcie04: Card not present on Slot(3) [40251.419896] ath: ah->misc_mode 0x4 [40251.428138] pciehp 0000:00:1c.3:pcie04: Card present on Slot(3) [40251.532247] ath: timeout (100000 us) on reg 0x9860: 0xffffffff & 0x00000001 != 0x00000000 [40251.532250] ath: Unable to reset channel (2462 MHz), reset status -5 [40251.532422] ath: Set channel: 5745 MHz [40251.540639] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.548826] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.557023] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.565211] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.573415] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.581603] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.581606] ath: Failed to stop TX DMA. Resetting hardware! [40251.592679] ath: DMA failed to stop in 10 ms AR_CR=0xffffffff AR_DIAG_SW=0xffffffff [40251.703330] ath: timeout (100000 us) on reg 0x7000: 0xffffffff & 0x00000003 != 0x00000000 [40251.703333] ath: RTC stuck in MAC reset [40251.703334] ath: Chip reset failed [40251.703335] ath: Unable to reset hardware; reset status -22 This is currently only reproducible with some HB92 (Half Mini-PCIE) cards but the fix applies to all AR9280 cards. This patch fixes this issue by setting bit 22 during radio disable. This patch has fixes for all kernels that has ath9k. [1] http://wireless.kernel.org/en/developers/Testing/wifi-test Cc: kyungwan.nam@atheros.com Cc: amod.bodas@atheros.com Cc: david.quan@atheros.com Cc: stable@kernel.org Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_hw.c | 3 +++ drivers/net/wireless/ath/ath9k/reg.h | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index a0471f2e1c7a..48261b7252d0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -410,6 +410,9 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, val &= ~(AR_WA_BIT6 | AR_WA_BIT7); } + if (AR_SREV_9280(ah)) + val |= AR_WA_BIT22; + if (AR_SREV_9285E_20(ah)) val |= AR_WA_BIT23; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 42976b0a01c1..fa05b711e5cd 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -703,6 +703,7 @@ #define AR_WA_RESET_EN (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */ #define AR_WA_ANALOG_SHIFT (1 << 20) #define AR_WA_POR_SHORT (1 << 21) /* PCI-E Phy reset control */ +#define AR_WA_BIT22 (1 << 22) #define AR9285_WA_DEFAULT 0x004a050b #define AR9280_WA_DEFAULT 0x0040073b #define AR_WA_DEFAULT 0x0000073f -- cgit v1.2.3 From ac618d70aeb681df7b77c1107fdf26f3249f855f Mon Sep 17 00:00:00 2001 From: Haitao Zhang Date: Sun, 7 Nov 2010 12:50:24 +0800 Subject: ath9k_htc: Add support for device ID 3346 This patch adds support for USB dongle with device ID 3346 from IMC Networks. Signed-off-by: Haitao Zhang Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hif_usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 6576f683dba0..2f6b1e9f0aee 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -35,6 +35,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */ { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */ + { USB_DEVICE(0x13D3, 0x3346) }, /* IMC Networks */ { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */ { }, -- cgit v1.2.3 From 490b3f4eacab3220383d2db49255a73995ecdf25 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 8 Nov 2010 12:49:12 +0530 Subject: ath9k_htc: Fix probe failure if CONFIG_USB_DEBUG enabled Since the endpoint descriptors (EP3 & EP4) were changed from Interrupt to Bulk type by firmware, the urb submission done on Bulk pipes. And the recent commit "check the endpoint type against the pipe type" added aditional error checking against pipe types under CONFIG_USB_DEBUG. So bmAttribute has to be updated for both EP3 & EP4 before submitting urbs on that pipe. This patch resolves the following failure. [ 2215.710936] usb 1-1: usb_probe_device [ 2215.710945] usb 1-1: configuration #1 chosen from 1 choice [ 2215.711152] usb 1-1: adding 1-1:1.0 (config #1, interface 0) [ 2215.711252] ath9k_hif_usb 1-1:1.0: usb_probe_interface [ 2215.711255] ath9k_hif_usb 1-1:1.0: usb_probe_interface - got id [ 2215.712780] usb 1-1: BOGUS urb xfer, pipe 3 != type 1 [ 2215.713782] usb 1-1: ath9k_htc: Unable to allocate URBs [ 2215.713801] ath9k_hif_usb: probe of 1-1:1.0 failed with error -22 Reported-by: Ming Lei Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hif_usb.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 2f6b1e9f0aee..f7ec31b4ddd3 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -541,11 +541,11 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) return; } - usb_fill_int_urb(urb, hif_dev->udev, + usb_fill_bulk_urb(urb, hif_dev->udev, usb_rcvbulkpipe(hif_dev->udev, USB_REG_IN_PIPE), nskb->data, MAX_REG_IN_BUF_SIZE, - ath9k_hif_usb_reg_in_cb, nskb, 1); + ath9k_hif_usb_reg_in_cb, nskb); ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) { @@ -721,11 +721,11 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev) if (!skb) goto err; - usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev, + usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev, usb_rcvbulkpipe(hif_dev->udev, USB_REG_IN_PIPE), skb->data, MAX_REG_IN_BUF_SIZE, - ath9k_hif_usb_reg_in_cb, skb, 1); + ath9k_hif_usb_reg_in_cb, skb); if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0) goto err; @@ -844,14 +844,6 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) goto err_fw_req; } - /* Alloc URBs */ - ret = ath9k_hif_usb_alloc_urbs(hif_dev); - if (ret) { - dev_err(&hif_dev->udev->dev, - "ath9k_htc: Unable to allocate URBs\n"); - goto err_urb; - } - /* Download firmware */ ret = ath9k_hif_usb_download_fw(hif_dev); if (ret) { @@ -867,16 +859,22 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) */ for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) { endp = &alt->endpoint[idx].desc; - if (((endp->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - == 0x04) && - ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_INT)) { + if ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT) { endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK; endp->bmAttributes |= USB_ENDPOINT_XFER_BULK; endp->bInterval = 0; } } + /* Alloc URBs */ + ret = ath9k_hif_usb_alloc_urbs(hif_dev); + if (ret) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Unable to allocate URBs\n"); + goto err_urb; + } + return 0; err_fw_download: -- cgit v1.2.3 From 48a7c3df14d0cda850337a9b3f9e667a0b12a996 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 8 Nov 2010 20:40:53 +0530 Subject: ath9k_hw: Fix memory leak on ath9k_hw_rf_alloc_ext_banks failure The allocated externel radio banks have to be freed in case of ath9k_hw_rf_alloc_ext_banks failure. Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c3a49045986d..6ebc68bca91f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -484,6 +484,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah) ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, "Failed allocating banks for " "external radio\n"); + ath9k_hw_rf_free_ext_banks(ah); return ecode; } -- cgit v1.2.3 From 53f57357ff0afc37804f4e82ee3123e0c0a2cad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Mon, 8 Nov 2010 13:23:05 +0000 Subject: r8169: revert "Handle rxfifo errors on 8168 chips" The original patch helps under obscure conditions (no pun) but some 8168 do not like it. The change needs to be tightened with a specific 8168 version. This reverts commit 801e147cde02f04b5c2f42764cd43a89fc7400a2 ("r8169: Handle rxfifo errors on 8168 chips"). Regression at https://bugzilla.kernel.org/show_bug.cgi?id=20882 Signed-off-by: Francois Romieu Tested-by: Andreas Radke Cc: Matthew Garrett Cc: Daniel J Blueman Signed-off-by: David S. Miller --- drivers/net/r8169.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index d88ce9fb1cbd..3a0877e0f97c 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2931,7 +2931,7 @@ static const struct rtl_cfg_info { .hw_start = rtl_hw_start_8168, .region = 2, .align = 8, - .intr_event = SYSErr | RxFIFOOver | LinkChg | RxOverflow | + .intr_event = SYSErr | LinkChg | RxOverflow | TxErr | TxOK | RxOK | RxErr, .napi_event = TxErr | TxOK | RxOK | RxOverflow, .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI, @@ -4588,7 +4588,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) } /* Work around for rx fifo overflow */ - if (unlikely(status & RxFIFOOver)) { + if (unlikely(status & RxFIFOOver) && + (tp->mac_version == RTL_GIGA_MAC_VER_11)) { netif_stop_queue(dev); rtl8169_tx_timeout(dev); break; -- cgit v1.2.3 From ea80907ff066edd1dd43c5fe90ae6677d15e6384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Mon, 8 Nov 2010 13:23:58 +0000 Subject: r8169: fix sleeping while holding spinlock. As device_set_wakeup_enable can now sleep, move the call to outside the critical section. Signed-off-by: Daniel J Blueman Acked-by: Rafael J. Wysocki Acked-by: Andrew Hendry Signed-off-by: David S. Miller --- drivers/net/r8169.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 3a0877e0f97c..4c4d16905efb 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -846,10 +846,10 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) else tp->features &= ~RTL_FEATURE_WOL; __rtl8169_set_wol(tp, wol->wolopts); - device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts); - spin_unlock_irq(&tp->lock); + device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts); + return 0; } -- cgit v1.2.3 From 7379efeacb707f49729080791a7a562d8996aec4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 8 Nov 2010 18:45:21 -0800 Subject: iwlwifi: dont use pci_dev before it being assign In order to use build-in debugging macro, pci_dev in priv need to be assigned first. This fix iwl3945 driver oopsed at boot with 2.6.37-rc1 Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8f8c4b73f8b9..7edf8c2fb8c7 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4000,7 +4000,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e * "the hard way", rather than using device's scan. */ if (iwl3945_mod_params.disable_hw_scan) { - IWL_ERR(priv, "sw scan support is deprecated\n"); + dev_printk(KERN_DEBUG, &(pdev->dev), + "sw scan support is deprecated\n"); iwl3945_hw_ops.hw_scan = NULL; } -- cgit v1.2.3 From 2040bd57b5f0c52dc4503e0e960b1dcafaf30a8b Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Fri, 12 Nov 2010 03:55:08 +0000 Subject: ucc_geth: Do not bring the whole IF down when TX failure. ucc_geth_close lacks a cancel_work_sync(&ugeth->timeout_work) to stop any outstanding processing of TX fail. However, one can not call cancel_work_sync without fixing the timeout function otherwise it will deadlock. This patch brings ucc_geth in line with gianfar: Don't bring the interface down and up, just reinit controller HW and PHY. Signed-off-by: Joakim Tjernlund Reviewed-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/ucc_geth.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index a4c3f5708246..cf6653f71d23 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -2065,9 +2065,6 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) /* Disable Rx and Tx */ clrbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); - phy_disconnect(ugeth->phydev); - ugeth->phydev = NULL; - ucc_geth_memclean(ugeth); } @@ -3550,7 +3547,10 @@ static int ucc_geth_close(struct net_device *dev) napi_disable(&ugeth->napi); + cancel_work_sync(&ugeth->timeout_work); ucc_geth_stop(ugeth); + phy_disconnect(ugeth->phydev); + ugeth->phydev = NULL; free_irq(ugeth->ug_info->uf_info.irq, ugeth->ndev); @@ -3579,8 +3579,12 @@ static void ucc_geth_timeout_work(struct work_struct *work) * Must reset MAC *and* PHY. This is done by reopening * the device. */ - ucc_geth_close(dev); - ucc_geth_open(dev); + netif_tx_stop_all_queues(dev); + ucc_geth_stop(ugeth); + ucc_geth_init_mac(ugeth); + /* Must start PHY here */ + phy_start(ugeth->phydev); + netif_tx_start_all_queues(dev); } netif_tx_schedule_all(dev); @@ -3594,7 +3598,6 @@ static void ucc_geth_timeout(struct net_device *dev) { struct ucc_geth_private *ugeth = netdev_priv(dev); - netif_carrier_off(dev); schedule_work(&ugeth->timeout_work); } -- cgit v1.2.3 From 75e6047431872dadd0b13503b374e48ccd71a507 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Fri, 12 Nov 2010 03:55:09 +0000 Subject: ucc_geth: Fix deadlock This script: while [ 1==1 ] ; do ifconfig eth0 up; usleep 1950000 ;ifconfig eth0 down; dmesg -c ;done causes in just a second or two: INFO: task ifconfig:572 blocked for more than 120 seconds. "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. ifconfig D 0ff65760 0 572 369 0x00000000 Call Trace: [c6157be0] [c6008460] 0xc6008460 (unreliable) [c6157ca0] [c0008608] __switch_to+0x4c/0x6c [c6157cb0] [c028fecc] schedule+0x184/0x310 [c6157ce0] [c0290e54] __mutex_lock_slowpath+0xa4/0x150 [c6157d20] [c0290c48] mutex_lock+0x44/0x48 [c6157d30] [c01aba74] phy_stop+0x20/0x70 [c6157d40] [c01aef40] ucc_geth_stop+0x30/0x98 [c6157d60] [c01b18fc] ucc_geth_close+0x9c/0xdc [c6157d80] [c01db0cc] __dev_close+0xa0/0xd0 [c6157d90] [c01deddc] __dev_change_flags+0x8c/0x148 [c6157db0] [c01def54] dev_change_flags+0x1c/0x64 [c6157dd0] [c0237ac8] devinet_ioctl+0x678/0x784 [c6157e50] [c0239a58] inet_ioctl+0xb0/0xbc [c6157e60] [c01cafa8] sock_ioctl+0x174/0x2a0 [c6157e80] [c009a16c] vfs_ioctl+0xcc/0xe0 [c6157ea0] [c009a998] do_vfs_ioctl+0xc4/0x79c [c6157f10] [c009b0b0] sys_ioctl+0x40/0x74 [c6157f40] [c00117c4] ret_from_syscall+0x0/0x38 The reason appears to be ucc_geth_stop meets adjust_link as the PHY reports PHY changes. I belive adjust_link hangs somewhere, holding the PHY lock, because ucc_geth_stop disabled the controller HW. Fix is to stop the PHY before disabling the controller. Signed-off-by: Joakim Tjernlund Reviewed-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/ucc_geth.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index cf6653f71d23..acbdab3d66ca 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -2050,12 +2050,16 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) ugeth_vdbg("%s: IN", __func__); + /* + * Tell the kernel the link is down. + * Must be done before disabling the controller + * or deadlock may happen. + */ + phy_stop(phydev); + /* Disable the controller */ ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); - /* Tell the kernel the link is down */ - phy_stop(phydev); - /* Mask all interrupts */ out_be32(ugeth->uccf->p_uccm, 0x00000000); -- cgit v1.2.3 From 167c25e4c5501f8b7e37f949d23652975c5a769c Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 10 Nov 2010 14:45:41 +0000 Subject: virtio-net: init link state correctly For device that supports VIRTIO_NET_F_STATUS, there's no need to assume the link is up and we need to call nerif_carrier_off() before querying device status, otherwise we may get wrong operstate after diver was loaded because the link watch event was not fired as expected. For device that does not support VIRITO_NET_F_STATUS, we could not get its status through virtnet_update_status() and what we can only do is always assuming the link is up. Acked-by: Michael S. Tsirkin Signed-off-by: Jason Wang Signed-off-by: Rusty Russell Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index bb6b67f6b0cc..b6d402806ae6 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -986,9 +986,15 @@ static int virtnet_probe(struct virtio_device *vdev) goto unregister; } - vi->status = VIRTIO_NET_S_LINK_UP; - virtnet_update_status(vi); - netif_carrier_on(dev); + /* Assume link up if device can't report link status, + otherwise get link status from config. */ + if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) { + netif_carrier_off(dev); + virtnet_update_status(vi); + } else { + vi->status = VIRTIO_NET_S_LINK_UP; + netif_carrier_on(dev); + } pr_debug("virtnet: registered device %s\n", dev->name); return 0; -- cgit v1.2.3 From d0d9d8ef5949551276f635cb04969184ba1a9553 Mon Sep 17 00:00:00 2001 From: Hao Zheng Date: Thu, 11 Nov 2010 13:47:58 +0000 Subject: bnx2x: Look inside vlan when determining checksum proto. Currently the skb->protocol field is used to setup checksum offloading on transmit for the correct protocol. However, if vlan offloading is disabled or otherwise not used, the protocol field will be ETH_P_8021Q, not the actual protocol. This will cause the checksum to be not computed correctly, even though the hardware is capable of looking inside vlan tags. Instead, look inside the header if necessary to determine the correct protocol type. To some extent this fixes a regression from 2.6.36 because it was previously not possible to disable vlan offloading and this error case was not exposed. Signed-off-by: Hao Zheng CC: Eilon Greenstein Signed-off-by: Jesse Gross Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_cmn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 459614d2d7bc..94d5f59d5a6f 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -1680,7 +1680,7 @@ static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb) rc = XMIT_PLAIN; else { - if (skb->protocol == htons(ETH_P_IPV6)) { + if (vlan_get_protocol(skb) == htons(ETH_P_IPV6)) { rc = XMIT_CSUM_V6; if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) rc |= XMIT_CSUM_TCP; -- cgit v1.2.3 From 5e09a10521681fe7808b1c4911a6d9c7fee55f82 Mon Sep 17 00:00:00 2001 From: Hao Zheng Date: Thu, 11 Nov 2010 13:47:59 +0000 Subject: ixgbe: Look inside vlan when determining offload protocol. Currently the skb->protocol field is used to setup various offloading parameters on transmit for the correct protocol. However, if vlan offloading is disabled or otherwise not used, the protocol field will be ETH_P_8021Q, not the actual protocol. This will cause the offloading to be not performed correctly, even though the hardware is capable of looking inside vlan tags. Instead, look inside the header if necessary to determine the correct protocol type. To some extent this fixes a regression from 2.6.36 because it was previously not possible to disable vlan offloading and this error case was not exposed. Signed-off-by: Hao Zheng CC: Jeff Kirsher CC: Alex Duyck CC: Jesse Brandeburg Signed-off-by: Jesse Gross Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 60 ++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 2bd3eb4ee5a1..fbad4d819608 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -764,8 +764,9 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, #ifdef IXGBE_FCOE /* adjust for FCoE Sequence Offload */ if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) - && (skb->protocol == htons(ETH_P_FCOE)) && - skb_is_gso(skb)) { + && skb_is_gso(skb) + && vlan_get_protocol(skb) == + htons(ETH_P_FCOE)) { hlen = skb_transport_offset(skb) + sizeof(struct fc_frame_header) + sizeof(struct fcoe_crc_eof); @@ -5823,7 +5824,7 @@ static void ixgbe_watchdog_task(struct work_struct *work) static int ixgbe_tso(struct ixgbe_adapter *adapter, struct ixgbe_ring *tx_ring, struct sk_buff *skb, - u32 tx_flags, u8 *hdr_len) + u32 tx_flags, u8 *hdr_len, __be16 protocol) { struct ixgbe_adv_tx_context_desc *context_desc; unsigned int i; @@ -5841,7 +5842,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, l4len = tcp_hdrlen(skb); *hdr_len += l4len; - if (skb->protocol == htons(ETH_P_IP)) { + if (protocol == htons(ETH_P_IP)) { struct iphdr *iph = ip_hdr(skb); iph->tot_len = 0; iph->check = 0; @@ -5880,7 +5881,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT); - if (skb->protocol == htons(ETH_P_IP)) + if (protocol == htons(ETH_P_IP)) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); @@ -5906,16 +5907,10 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, return false; } -static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb) +static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb, + __be16 protocol) { u32 rtn = 0; - __be16 protocol; - - if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) - protocol = ((const struct vlan_ethhdr *)skb->data)-> - h_vlan_encapsulated_proto; - else - protocol = skb->protocol; switch (protocol) { case cpu_to_be16(ETH_P_IP): @@ -5943,7 +5938,7 @@ static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb) default: if (unlikely(net_ratelimit())) e_warn(probe, "partial checksum but proto=%x!\n", - skb->protocol); + protocol); break; } @@ -5952,7 +5947,8 @@ static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb) static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, struct ixgbe_ring *tx_ring, - struct sk_buff *skb, u32 tx_flags) + struct sk_buff *skb, u32 tx_flags, + __be16 protocol) { struct ixgbe_adv_tx_context_desc *context_desc; unsigned int i; @@ -5981,7 +5977,7 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, IXGBE_ADVTXD_DTYP_CTXT); if (skb->ip_summed == CHECKSUM_PARTIAL) - type_tucmd_mlhl |= ixgbe_psum(adapter, skb); + type_tucmd_mlhl |= ixgbe_psum(adapter, skb, protocol); context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); /* use index zero for tx checksum offload */ @@ -6179,7 +6175,7 @@ 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) + int queue, u32 tx_flags, __be16 protocol) { struct ixgbe_atr_input atr_input; struct tcphdr *th; @@ -6190,7 +6186,7 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, u8 l4type = 0; /* Right now, we support IPv4 only */ - if (skb->protocol != htons(ETH_P_IP)) + if (protocol != htons(ETH_P_IP)) return; /* check if we're UDP or TCP */ if (iph->protocol == IPPROTO_TCP) { @@ -6257,10 +6253,13 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) { struct ixgbe_adapter *adapter = netdev_priv(dev); int txq = smp_processor_id(); - #ifdef IXGBE_FCOE - if ((skb->protocol == htons(ETH_P_FCOE)) || - (skb->protocol == htons(ETH_P_FIP))) { + __be16 protocol; + + protocol = vlan_get_protocol(skb); + + if ((protocol == htons(ETH_P_FCOE)) || + (protocol == htons(ETH_P_FIP))) { if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1); txq += adapter->ring_feature[RING_F_FCOE].mask; @@ -6303,6 +6302,9 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev int tso; int count = 0; unsigned int f; + __be16 protocol; + + protocol = vlan_get_protocol(skb); if (vlan_tx_tag_present(skb)) { tx_flags |= vlan_tx_tag_get(skb); @@ -6323,8 +6325,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev /* for FCoE with DCB, we force the priority to what * was specified by the switch */ if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED && - (skb->protocol == htons(ETH_P_FCOE) || - skb->protocol == htons(ETH_P_FIP))) { + (protocol == htons(ETH_P_FCOE) || + protocol == htons(ETH_P_FIP))) { #ifdef CONFIG_IXGBE_DCB if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK @@ -6334,7 +6336,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev } #endif /* flag for FCoE offloads */ - if (skb->protocol == htons(ETH_P_FCOE)) + if (protocol == htons(ETH_P_FCOE)) tx_flags |= IXGBE_TX_FLAGS_FCOE; } #endif @@ -6368,9 +6370,10 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev tx_flags |= IXGBE_TX_FLAGS_FSO; #endif /* IXGBE_FCOE */ } else { - if (skb->protocol == htons(ETH_P_IP)) + if (protocol == htons(ETH_P_IP)) tx_flags |= IXGBE_TX_FLAGS_IPV4; - tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len); + tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len, + protocol); if (tso < 0) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; @@ -6378,7 +6381,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev if (tso) tx_flags |= IXGBE_TX_FLAGS_TSO; - else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) && + else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags, + protocol) && (skb->ip_summed == CHECKSUM_PARTIAL)) tx_flags |= IXGBE_TX_FLAGS_CSUM; } @@ -6392,7 +6396,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev test_bit(__IXGBE_FDIR_INIT_DONE, &tx_ring->reinit_state)) { ixgbe_atr(adapter, skb, tx_ring->queue_index, - tx_flags); + tx_flags, protocol); tx_ring->atr_count = 0; } } -- cgit v1.2.3 From 53c7886c189597ff3af3413ed4e87632853b6d51 Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 11 Nov 2010 09:06:48 +0000 Subject: cxgb4vf: don't implement trivial (and incorrect) ndo_select_queue() Don't implement (struct net_device_ops *)->ndo_select_queue() with simple call to skb_tx_hash(). This leads to non-persistent TX queue selection in the Linux dev_pick_tx() routine for TCP connections. Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/cxgb4vf/cxgb4vf_main.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 6de5e2e448a5..24808ac9976e 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -1103,18 +1103,6 @@ static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr) return 0; } -/* - * Return a TX Queue on which to send the specified skb. - */ -static u16 cxgb4vf_select_queue(struct net_device *dev, struct sk_buff *skb) -{ - /* - * XXX For now just use the default hash but we probably want to - * XXX look at other possibilities ... - */ - return skb_tx_hash(dev, skb); -} - #ifdef CONFIG_NET_POLL_CONTROLLER /* * Poll all of our receive queues. This is called outside of normal interrupt @@ -2417,7 +2405,6 @@ static const struct net_device_ops cxgb4vf_netdev_ops = { .ndo_get_stats = cxgb4vf_get_stats, .ndo_set_rx_mode = cxgb4vf_set_rxmode, .ndo_set_mac_address = cxgb4vf_set_mac_addr, - .ndo_select_queue = cxgb4vf_select_queue, .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = cxgb4vf_do_ioctl, .ndo_change_mtu = cxgb4vf_change_mtu, @@ -2624,7 +2611,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, netdev->do_ioctl = cxgb4vf_do_ioctl; netdev->change_mtu = cxgb4vf_change_mtu; netdev->set_mac_address = cxgb4vf_set_mac_addr; - netdev->select_queue = cxgb4vf_select_queue; #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = cxgb4vf_poll_controller; #endif -- cgit v1.2.3 From b94e72e23e3ededa23cf18973ffc9a03c7ea8d04 Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 11 Nov 2010 09:06:49 +0000 Subject: cxgb4vf: fix bug in Generic Receive Offload Fix botch in Generic Receive Offload (the Packet Gather List Total length field wasn't being initialized). Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/cxgb4vf/sge.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c index f10864ddafbe..6a6e18b07248 100644 --- a/drivers/net/cxgb4vf/sge.c +++ b/drivers/net/cxgb4vf/sge.c @@ -1679,6 +1679,7 @@ int process_responses(struct sge_rspq *rspq, int budget) } len = RSPD_LEN(len); } + gl.tot_len = len; /* * Gather packet fragments. -- cgit v1.2.3 From eb6c503db3619c43b5aad0ced82e9d91c034ced5 Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 11 Nov 2010 09:06:50 +0000 Subject: cxgb4vf: fix some errors in Gather List to skb conversion There were some errors in the way that internal Gather Lists were being translated into skb's. This also makes the VF Driver look more like the PF Driver to facilitate easier comarison. Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/cxgb4vf/sge.c | 121 ++++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 47 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c index 6a6e18b07248..ecf0770bf0ff 100644 --- a/drivers/net/cxgb4vf/sge.c +++ b/drivers/net/cxgb4vf/sge.c @@ -154,13 +154,14 @@ enum { */ RX_COPY_THRES = 256, RX_PULL_LEN = 128, -}; -/* - * Can't define this in the above enum because PKTSHIFT isn't a constant in - * the VF Driver ... - */ -#define RX_PKT_PULL_LEN (RX_PULL_LEN + PKTSHIFT) + /* + * Main body length for sk_buffs used for RX Ethernet packets with + * fragments. Should be >= RX_PULL_LEN but possibly bigger to give + * pskb_may_pull() some room. + */ + RX_SKB_LEN = 512, +}; /* * Software state per TX descriptor. @@ -1354,6 +1355,67 @@ out_free: return NETDEV_TX_OK; } +/** + * t4vf_pktgl_to_skb - build an sk_buff from a packet gather list + * @gl: the gather list + * @skb_len: size of sk_buff main body if it carries fragments + * @pull_len: amount of data to move to the sk_buff's main body + * + * Builds an sk_buff from the given packet gather list. Returns the + * sk_buff or %NULL if sk_buff allocation failed. + */ +struct sk_buff *t4vf_pktgl_to_skb(const struct pkt_gl *gl, + unsigned int skb_len, unsigned int pull_len) +{ + struct sk_buff *skb; + struct skb_shared_info *ssi; + + /* + * If the ingress packet is small enough, allocate an skb large enough + * for all of the data and copy it inline. Otherwise, allocate an skb + * with enough room to pull in the header and reference the rest of + * the data via the skb fragment list. + * + * Below we rely on RX_COPY_THRES being less than the smallest Rx + * buff! size, which is expected since buffers are at least + * PAGE_SIZEd. In this case packets up to RX_COPY_THRES have only one + * fragment. + */ + if (gl->tot_len <= RX_COPY_THRES) { + /* small packets have only one fragment */ + skb = alloc_skb(gl->tot_len, GFP_ATOMIC); + if (unlikely(!skb)) + goto out; + __skb_put(skb, gl->tot_len); + skb_copy_to_linear_data(skb, gl->va, gl->tot_len); + } else { + skb = alloc_skb(skb_len, GFP_ATOMIC); + if (unlikely(!skb)) + goto out; + __skb_put(skb, pull_len); + skb_copy_to_linear_data(skb, gl->va, pull_len); + + ssi = skb_shinfo(skb); + ssi->frags[0].page = gl->frags[0].page; + ssi->frags[0].page_offset = gl->frags[0].page_offset + pull_len; + ssi->frags[0].size = gl->frags[0].size - pull_len; + if (gl->nfrags > 1) + memcpy(&ssi->frags[1], &gl->frags[1], + (gl->nfrags-1) * sizeof(skb_frag_t)); + ssi->nr_frags = gl->nfrags; + + skb->len = gl->tot_len; + skb->data_len = skb->len - pull_len; + skb->truesize += skb->data_len; + + /* Get a reference for the last page, we don't own it */ + get_page(gl->frags[gl->nfrags - 1].page); + } + +out: + return skb; +} + /** * t4vf_pktgl_free - free a packet gather list * @gl: the gather list @@ -1463,10 +1525,8 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, { struct sk_buff *skb; struct port_info *pi; - struct skb_shared_info *ssi; const struct cpl_rx_pkt *pkt = (void *)&rsp[1]; bool csum_ok = pkt->csum_calc && !pkt->err_vec; - unsigned int len = be16_to_cpu(pkt->len); struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq); /* @@ -1481,42 +1541,14 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, } /* - * If the ingress packet is small enough, allocate an skb large enough - * for all of the data and copy it inline. Otherwise, allocate an skb - * with enough room to pull in the header and reference the rest of - * the data via the skb fragment list. + * Convert the Packet Gather List into an skb. */ - if (len <= RX_COPY_THRES) { - /* small packets have only one fragment */ - skb = alloc_skb(gl->frags[0].size, GFP_ATOMIC); - if (!skb) - goto nomem; - __skb_put(skb, gl->frags[0].size); - skb_copy_to_linear_data(skb, gl->va, gl->frags[0].size); - } else { - skb = alloc_skb(RX_PKT_PULL_LEN, GFP_ATOMIC); - if (!skb) - goto nomem; - __skb_put(skb, RX_PKT_PULL_LEN); - skb_copy_to_linear_data(skb, gl->va, RX_PKT_PULL_LEN); - - ssi = skb_shinfo(skb); - ssi->frags[0].page = gl->frags[0].page; - ssi->frags[0].page_offset = (gl->frags[0].page_offset + - RX_PKT_PULL_LEN); - ssi->frags[0].size = gl->frags[0].size - RX_PKT_PULL_LEN; - if (gl->nfrags > 1) - memcpy(&ssi->frags[1], &gl->frags[1], - (gl->nfrags-1) * sizeof(skb_frag_t)); - ssi->nr_frags = gl->nfrags; - skb->len = len + PKTSHIFT; - skb->data_len = skb->len - RX_PKT_PULL_LEN; - skb->truesize += skb->data_len; - - /* Get a reference for the last page, we don't own it */ - get_page(gl->frags[gl->nfrags - 1].page); + skb = t4vf_pktgl_to_skb(gl, RX_SKB_LEN, RX_PULL_LEN); + if (unlikely(!skb)) { + t4vf_pktgl_free(gl); + rxq->stats.rx_drops++; + return 0; } - __skb_pull(skb, PKTSHIFT); skb->protocol = eth_type_trans(skb, rspq->netdev); skb_record_rx_queue(skb, rspq->idx); @@ -1549,11 +1581,6 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, netif_receive_skb(skb); return 0; - -nomem: - t4vf_pktgl_free(gl); - rxq->stats.rx_drops++; - return 0; } /** -- cgit v1.2.3 From 8b6edf878a28979df6057cf414c51ab39bc3cc6f Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 11 Nov 2010 09:06:51 +0000 Subject: cxgb4vf: flesh out PCI Device ID Table ... Add a bunch of T4 Device IDs for the VF Driver. Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/cxgb4vf/cxgb4vf_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 24808ac9976e..4487b1ace660 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -2829,6 +2829,14 @@ static struct pci_device_id cxgb4vf_pci_tbl[] = { CH_DEVICE(0x4800, 0), /* T440-dbg */ CH_DEVICE(0x4801, 0), /* T420-cr */ CH_DEVICE(0x4802, 0), /* T422-cr */ + CH_DEVICE(0x4803, 0), /* T440-cr */ + CH_DEVICE(0x4804, 0), /* T420-bch */ + CH_DEVICE(0x4805, 0), /* T440-bch */ + CH_DEVICE(0x4806, 0), /* T460-ch */ + CH_DEVICE(0x4807, 0), /* T420-so */ + CH_DEVICE(0x4808, 0), /* T420-cx */ + CH_DEVICE(0x4809, 0), /* T420-bt */ + CH_DEVICE(0x480a, 0), /* T404-bt */ { 0, } }; -- cgit v1.2.3 From e7a3795f56122cc92530c3f9412b8ff19b70184c Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 11 Nov 2010 09:06:52 +0000 Subject: cxgb4vf: Fail open if link_start() fails. Fail open if link_start() fails. Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/cxgb4vf/cxgb4vf_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 4487b1ace660..8da3bda13f33 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -753,7 +753,9 @@ static int cxgb4vf_open(struct net_device *dev) if (err) return err; set_bit(pi->port_id, &adapter->open_device_map); - link_start(dev); + err = link_start(dev); + if (err) + return err; netif_tx_start_all_queues(dev); return 0; } -- cgit v1.2.3 From e68e6133e2daef6fc40e91621a1e26938e428e9e Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 11 Nov 2010 09:06:53 +0000 Subject: cxgb4vf: add call to Firmware to reset VF State. Add call to Firmware to reset its VF State when we first attach to the VF. Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/cxgb4vf/cxgb4vf_main.c | 16 ++++++++++++++++ drivers/net/cxgb4vf/t4vf_common.h | 1 + drivers/net/cxgb4vf/t4vf_hw.c | 19 +++++++++++++++++++ 3 files changed, 36 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 8da3bda13f33..c3449bbc585a 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -2064,6 +2064,22 @@ static int adap_init0(struct adapter *adapter) return err; } + /* + * Some environments do not properly handle PCIE FLRs -- e.g. in Linux + * 2.6.31 and later we can't call pci_reset_function() in order to + * issue an FLR because of a self- deadlock on the device semaphore. + * Meanwhile, the OS infrastructure doesn't issue FLRs in all the + * cases where they're needed -- for instance, some versions of KVM + * fail to reset "Assigned Devices" when the VM reboots. Therefore we + * use the firmware based reset in order to reset any per function + * state. + */ + err = t4vf_fw_reset(adapter); + if (err < 0) { + dev_err(adapter->pdev_dev, "FW reset failed: err=%d\n", err); + return err; + } + /* * Grab basic operational parameters. These will predominantly have * been set up by the Physical Function Driver or will be hard coded diff --git a/drivers/net/cxgb4vf/t4vf_common.h b/drivers/net/cxgb4vf/t4vf_common.h index 873cb7d86c57..a65c80aed1f2 100644 --- a/drivers/net/cxgb4vf/t4vf_common.h +++ b/drivers/net/cxgb4vf/t4vf_common.h @@ -235,6 +235,7 @@ static inline int t4vf_wr_mbox_ns(struct adapter *adapter, const void *cmd, int __devinit t4vf_wait_dev_ready(struct adapter *); int __devinit t4vf_port_init(struct adapter *, int); +int t4vf_fw_reset(struct adapter *); int t4vf_query_params(struct adapter *, unsigned int, const u32 *, u32 *); int t4vf_set_params(struct adapter *, unsigned int, const u32 *, const u32 *); diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c index ea1c123f0cb4..e306c20dfaee 100644 --- a/drivers/net/cxgb4vf/t4vf_hw.c +++ b/drivers/net/cxgb4vf/t4vf_hw.c @@ -325,6 +325,25 @@ int __devinit t4vf_port_init(struct adapter *adapter, int pidx) return 0; } +/** + * t4vf_fw_reset - issue a reset to FW + * @adapter: the adapter + * + * Issues a reset command to FW. For a Physical Function this would + * result in the Firmware reseting all of its state. For a Virtual + * Function this just resets the state associated with the VF. + */ +int t4vf_fw_reset(struct adapter *adapter) +{ + struct fw_reset_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RESET_CMD) | + FW_CMD_WRITE); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); +} + /** * t4vf_query_params - query FW or device parameters * @adapter: the adapter -- cgit v1.2.3 From 19c0ef6b36a67fc579c77bb9b4da00e084fdb667 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Sat, 6 Nov 2010 05:11:24 +0000 Subject: axnet_cs: fix resume problem for some Ax88790 chip axnet_cs: Some Ax88790 chip need to reinitialize the CISREG_CCSR register after resume. Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller --- drivers/net/pcmcia/axnet_cs.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index d2e166e29dda..8a4d19e5de06 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -111,13 +111,14 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id); typedef struct axnet_dev_t { struct pcmcia_device *p_dev; - caddr_t base; - struct timer_list watchdog; - int stale, fast_poll; - u_short link_status; - u_char duplex_flag; - int phy_id; - int flags; + caddr_t base; + struct timer_list watchdog; + int stale, fast_poll; + u_short link_status; + u_char duplex_flag; + int phy_id; + int flags; + int active_low; } axnet_dev_t; static inline axnet_dev_t *PRIV(struct net_device *dev) @@ -322,6 +323,8 @@ static int axnet_config(struct pcmcia_device *link) if (info->flags & IS_AX88790) outb(0x10, dev->base_addr + AXNET_GPIO); /* select Internal PHY */ + info->active_low = 0; + for (i = 0; i < 32; i++) { j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2); @@ -329,15 +332,18 @@ static int axnet_config(struct pcmcia_device *link) if ((j != 0) && (j != 0xffff)) break; } - /* Maybe PHY is in power down mode. (PPD_SET = 1) - Bit 2 of CCSR is active low. */ if (i == 32) { + /* Maybe PHY is in power down mode. (PPD_SET = 1) + Bit 2 of CCSR is active low. */ pcmcia_write_config_byte(link, CISREG_CCSR, 0x04); for (i = 0; i < 32; i++) { j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2); if (j == j2) continue; - if ((j != 0) && (j != 0xffff)) break; + if ((j != 0) && (j != 0xffff)) { + info->active_low = 1; + break; + } } } @@ -383,8 +389,12 @@ static int axnet_suspend(struct pcmcia_device *link) static int axnet_resume(struct pcmcia_device *link) { struct net_device *dev = link->priv; + axnet_dev_t *info = PRIV(dev); if (link->open) { + if (info->active_low == 1) + pcmcia_write_config_byte(link, CISREG_CCSR, 0x04); + axnet_reset_8390(dev); AX88190_init(dev, 1); netif_device_attach(dev); -- cgit v1.2.3 From 6c4f199411f254bf3713b04ed8653f0955883309 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 9 Nov 2010 11:54:19 +0000 Subject: gianfar: Do not call device_set_wakeup_enable() under a spinlock The gianfar driver calls device_set_wakeup_enable() under a spinlock, which causes a problem to happen after the recent core power management changes, because this function can sleep now. Fix this by moving the device_set_wakeup_enable() call out of the spinlock-protected area. Signed-off-by: Rafael J. Wysocki Signed-off-by: David S. Miller --- drivers/net/gianfar_ethtool.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 5c566ebc54b8..3bc8e276ba4d 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -635,9 +635,10 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; + device_set_wakeup_enable(&dev->dev, wol->wolopts & WAKE_MAGIC); + spin_lock_irqsave(&priv->bflock, flags); - priv->wol_en = wol->wolopts & WAKE_MAGIC ? 1 : 0; - device_set_wakeup_enable(&dev->dev, priv->wol_en); + priv->wol_en = !!device_may_wakeup(&dev->dev); spin_unlock_irqrestore(&priv->bflock, flags); return 0; -- cgit v1.2.3