From b2ec153a637409bd87952d44409905b7d98418b8 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 14 Dec 2009 14:09:49 -0500 Subject: rt2x00: Fix rt2800usb detection in rt2800lib. rt2800lib incorrectly detected whether RT2800USB was enabled because it didn't account for a modularized RT2800USB driver. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index eb1e1d0..6e13650 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -37,7 +37,7 @@ #include #include "rt2x00.h" -#ifdef CONFIG_RT2800USB +#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE) #include "rt2x00usb.h" #endif #include "rt2800lib.h" @@ -1121,7 +1121,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00_intf_is_usb(rt2x00dev)) { rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); -#ifdef CONFIG_RT2800USB +#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE) rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, USB_MODE_RESET, REGISTER_TIMEOUT); #endif -- cgit v0.10.2 From d24deb2580823ab0b8425790c6f5d18e2ff749d8 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Fri, 4 Dec 2009 23:46:54 +0100 Subject: mac80211: Add define for TX headroom reserved by mac80211 itself. Add a definition of the amount of TX headroom reserved by mac80211 itself for its own purposes. Also add BUILD_BUG_ON to validate the value. This define can then be used by drivers to request additional TX headroom in the most efficient manner. Signed-off-by: Gertjan van Wingerde Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2aff490..538d6b7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1737,6 +1737,12 @@ static inline void ieee80211_rx_ni(struct ieee80211_hw *hw, local_bh_enable(); } +/* + * The TX headroom reserved by mac80211 for its own tx_status functions. + * This is enough for the radiotap header. + */ +#define IEEE80211_TX_STATUS_HEADROOM 13 + /** * ieee80211_tx_status - transmit status callback * diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 8116d1a..0d2d948 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -515,6 +515,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) * and we need some headroom for passing the frame to monitor * interfaces, but never both at the same time. */ + BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != + sizeof(struct ieee80211_tx_status_rtap_hdr)); local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, sizeof(struct ieee80211_tx_status_rtap_hdr)); -- cgit v0.10.2 From 64a76b504b04b5da16d1e7658a95dd126594e02f Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 10 Dec 2009 14:37:21 -0800 Subject: iwlwifi: allocated rx page accounting cleanup In iwlwifi, priv->alloc_rxb_page is used to keep track of the Rx pages allocated by the driver. This cleans up the page free routines by introducing __iwl_free_pages/iwl_free_pages so that the accounting is more accurate and less error prone. This also fixes two instances where the counter was not updated. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7da1dab..4609323 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1835,8 +1835,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) rc = -EIO; } - priv->alloc_rxb_page--; - free_pages(cmd.reply_page, priv->hw_params.rx_page_order); + iwl_free_pages(priv, cmd.reply_page); return rc; } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2673e9a..e1032f2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1353,4 +1353,15 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; } +static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page) +{ + __free_pages(page, priv->hw_params.rx_page_order); + priv->alloc_rxb_page--; +} + +static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page) +{ + free_pages(page, priv->hw_params.rx_page_order); + priv->alloc_rxb_page--; +} #endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index a231659..30e9ea6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -234,7 +234,7 @@ cancel: } fail: if (cmd->reply_page) { - free_pages(cmd->reply_page, priv->hw_params.rx_page_order); + iwl_free_pages(priv, cmd->reply_page); cmd->reply_page = 0; } out: diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 6090bc1..f5c87e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -345,10 +345,8 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, PAGE_SIZE << priv->hw_params.rx_page_order, PCI_DMA_FROMDEVICE); - __free_pages(rxq->pool[i].page, - priv->hw_params.rx_page_order); + __iwl_free_pages(priv, rxq->pool[i].page); rxq->pool[i].page = NULL; - priv->alloc_rxb_page--; } } @@ -416,9 +414,7 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, PAGE_SIZE << priv->hw_params.rx_page_order, PCI_DMA_FROMDEVICE); - priv->alloc_rxb_page--; - __free_pages(rxq->pool[i].page, - priv->hw_params.rx_page_order); + __iwl_free_pages(priv, rxq->pool[i].page); rxq->pool[i].page = NULL; } list_add_tail(&rxq->pool[i].list, &rxq->rx_used); diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index a2b2b83..fa1c89b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -144,8 +144,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) clear_bit(STATUS_SCAN_HW, &priv->status); } - priv->alloc_rxb_page--; - free_pages(cmd.reply_page, priv->hw_params.rx_page_order); + iwl_free_pages(priv, cmd.reply_page); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index cd6a690..cde09a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -164,9 +164,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, break; } } - - priv->alloc_rxb_page--; - free_pages(cmd.reply_page, priv->hw_params.rx_page_order); + iwl_free_pages(priv, cmd.reply_page); return ret; } @@ -391,9 +389,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, break; } } - - priv->alloc_rxb_page--; - free_pages(cmd.reply_page, priv->hw_params.rx_page_order); + iwl_free_pages(priv, cmd.reply_page); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2a28a1f..994db4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -812,7 +812,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, break; } - free_pages(cmd.reply_page, priv->hw_params.rx_page_order); + iwl_free_pages(priv, cmd.reply_page); return rc; } @@ -1198,9 +1198,7 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, PAGE_SIZE << priv->hw_params.rx_page_order, PCI_DMA_FROMDEVICE); - priv->alloc_rxb_page--; - __free_pages(rxq->pool[i].page, - priv->hw_params.rx_page_order); + __iwl_free_pages(priv, rxq->pool[i].page); rxq->pool[i].page = NULL; } list_add_tail(&rxq->pool[i].list, &rxq->rx_used); @@ -1247,10 +1245,8 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, PAGE_SIZE << priv->hw_params.rx_page_order, PCI_DMA_FROMDEVICE); - __free_pages(rxq->pool[i].page, - priv->hw_params.rx_page_order); + __iwl_free_pages(priv, rxq->pool[i].page); rxq->pool[i].page = NULL; - priv->alloc_rxb_page--; } } -- cgit v0.10.2 From f8701fe3aec24fcfb0dfa19aab47904611f96daf Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 10 Dec 2009 14:37:22 -0800 Subject: iwlwifi: power up all devices for EEPROM read Recent commits "iwlwifi: remove power-wasting calls to apm_ops.init()" and "iwlagn: power up device before initializing EEPROM" had the goal of reducing device power consumption from the time the module is loaded until the interface is brought up and the device's power saving mechanisms kick in. The idea is that once the module is loaded there is no need for the device to consume power until the interface is brought up. With the current solution the device is only powered up during EEPROM read, and then so also only if the EEPROM type is OTP. We have found that on certain platforms even non-OTP devices require power to be up during EEPROM read. On these platforms the driver never loads and the system log contains the following: iwlagn 0000:03:00.0: MAC is in deep sleep!. CSR_GP_CNTRL = 0x080403D8 We thus now power up all devices during EEPROM read. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index a7bfae0..1ec8cb4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -77,8 +77,7 @@ * The MAC (uCode processor, etc.) does not need to be powered up for accessing * the CSR registers. * - * NOTE: Newer devices using one-time-programmable (OTP) memory - * require device to be awake in order to read this memory + * NOTE: Device does need to be awake in order to read this memory * via CSR_EEPROM and CSR_OTP registers */ #define CSR_BASE (0x000) @@ -111,9 +110,8 @@ /* * EEPROM and OTP (one-time-programmable) memory reads * - * NOTE: For (newer) devices using OTP, device must be awake, initialized via - * apm_ops.init() in order to read. Older devices (3945/4965/5000) - * use EEPROM and do not require this. + * NOTE: Device must be awake, initialized via apm_ops.init(), + * in order to read. */ #define CSR_EEPROM_REG (CSR_BASE+0x02c) #define CSR_EEPROM_GP (CSR_BASE+0x030) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 3946e5c..72f0d77 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -518,10 +518,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) } e = (u16 *)priv->eeprom; - if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { - /* OTP reads require powered-up chip */ - priv->cfg->ops->lib->apm_ops.init(priv); - } + priv->cfg->ops->lib->apm_ops.init(priv); ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); if (ret < 0) { @@ -570,13 +567,6 @@ int iwl_eeprom_init(struct iwl_priv *priv) e[cache_addr / 2] = eeprom_data; cache_addr += sizeof(u16); } - - /* - * Now that OTP reads are complete, reset chip to save - * power until we load uCode during "up". - */ - priv->cfg->ops->lib->apm_ops.stop(priv); - } else { /* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) { @@ -603,6 +593,8 @@ done: err: if (ret) iwl_eeprom_free(priv); + /* Reset chip to save power until we load uCode during "up". */ + priv->cfg->ops->lib->apm_ops.stop(priv); alloc_err: return ret; } -- cgit v0.10.2 From 521d9bce86331d8261213b807a9127f7e2ec046b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 10 Dec 2009 14:37:23 -0800 Subject: iwlwifi: fix syslog message for event log dump size When trigger event log dumping from debugfs, the entire event log should be dumped and the size should match the number of events being dump. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b8377ef..715db219 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1842,7 +1842,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) } #ifdef CONFIG_IWLWIFI_DEBUG - if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)) + if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) && !full_log) size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; #else diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 994db4a..4c0e475 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1684,7 +1684,7 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) } #ifdef CONFIG_IWLWIFI_DEBUG - if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)) + if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) && !full_log) size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES) ? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size; #else -- cgit v0.10.2 From 4d91f9f3730d6d82a3ba67cae215a1823ba6a191 Mon Sep 17 00:00:00 2001 From: Benoit Papillault Date: Sat, 12 Dec 2009 00:22:35 +0100 Subject: ath9k: Last fix for TX software padding. First, we copy/paste the padding stuff from ath9k_tx to ath_tx_cabq since it needs to same kind of padding, but for internally generated beacons. Next, software padding done on TX needs to be removed before calling ieee80211_tx_status. The code was already there in ath_tx_complete but it was wrong. Fix it by using ath9k_cmn_padpos. This later code has been tested by sending packets to a monitor interface and reading packets from the same interface. Signed-off-by: Benoit PAPILLAULT Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2a11cc5..6770620 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1780,7 +1780,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - int hdrlen, padsize; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + int padpos, padsize; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_tx_control txctl; @@ -1792,7 +1793,6 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) * BSSes. */ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); @@ -1800,9 +1800,9 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) } /* Add the padding after the header if this is not already done */ - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - padsize = hdrlen % 4; + padpos = ath9k_cmn_padpos(hdr->frame_control); + padsize = padpos & 3; + if (padsize && skb->len>padpos) { if (skb_headroom(skb) < padsize) { ath_print(common, ATH_DBG_XMIT, "TX CABQ padding failed\n"); @@ -1810,7 +1810,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) return; } skb_push(skb, padsize); - memmove(skb->data, skb->data + padsize, hdrlen); + memmove(skb->data, skb->data + padsize, padpos); } txctl.txq = sc->beacon.cabq; @@ -1838,7 +1838,8 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_common *common = ath9k_hw_common(sc->sc_ah); - int hdrlen, padsize; + struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; + int padpos, padsize; ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); @@ -1853,14 +1854,14 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, tx_info->flags |= IEEE80211_TX_STAT_ACK; } - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - padsize = hdrlen & 3; - if (padsize && hdrlen >= 24) { + padpos = ath9k_cmn_padpos(hdr->frame_control); + padsize = padpos & 3; + if (padsize && skb->len>padpos+padsize) { /* * Remove MAC header padding before giving the frame back to * mac80211. */ - memmove(skb->data + padsize, skb->data, hdrlen); + memmove(skb->data + padsize, skb->data, padpos); skb_pull(skb, padsize); } -- cgit v0.10.2 From 855da5e07ef4dba5f23d8f6f31004116ba16c52a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Dec 2009 17:07:45 +0100 Subject: drivers/net/wireless: Correct code taking the size of a pointer sizeof(iv16) and sizeof(iv32) are the sizes of pointers. Change them to the size of the copied data. Furthermore, iveiv_entry is a local structure that has just been initialized and is not visible outside this function. Thus, there would seem to be no point to copy data into it. The order of the arguments is thus changed to copy the data into the parameters, which are provided as pointers, suggesting in this case that they should be used to return values. A simplified version of the semantic patch that finds the first problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression *x; expression f; type T; @@ *f(...,(T)x,...) // Signed-off-by: Julia Lawall Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 6e13650..a199f85 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2140,8 +2140,8 @@ static void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, rt2800_register_multiread(rt2x00dev, offset, &iveiv_entry, sizeof(iveiv_entry)); - memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16)); - memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32)); + memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16)); + memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32)); } static int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -- cgit v0.10.2 From 93b6bd26b74efe46b4579592560f9f1cb7b61994 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 14 Dec 2009 20:33:55 +0100 Subject: rt2x00: Disable powersaving for rt61pci and rt2800pci. We've had many reports of rt61pci failures with powersaving enabled. Therefore, as a stop-gap measure, disable powersaving of the rt61pci until we have found a proper solution. Also disable powersaving on rt2800pci as it most probably will show the same problem. Cc: stable@kernel.org Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index a199f85..6bf6c0f 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2022,6 +2022,12 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) u16 eeprom; /* + * Disable powersaving as default on PCI devices. + */ + if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + /* * Initialize all hw fields. */ rt2x00dev->hw->flags = diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 687e17d..0ca5893 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2539,6 +2539,11 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) unsigned int i; /* + * Disable powersaving as default. + */ + rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + /* * Initialize all hw fields. */ rt2x00dev->hw->flags = -- cgit v0.10.2 From af6b8ee38833b39f70946f767740565ceb126961 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 14 Dec 2009 14:12:08 -0800 Subject: iwlwifi: fix EEPROM/OTP reading endian annotations and a bug The construct "le16_to_cpu((__force __le16)(r >> 16))" has always bothered me when looking through the iwlwifi code, it shouldn't be necessary to __force anything, and before this code, "r" was obtained with an ioread32, which swaps each of the two u16 values in it properly when swapping the entire u32 value. I've had arguments about this code with people before, but always conceded they were right because removing it only made things not work at all on big endian platforms. However, analysing a failure of the OTP reading code, I now finally figured out what is going on, and why my intuition about that code being wrong was right all along. It turns out that the 'priv->eeprom' u8 array really wants to have the data in it in little endian. So the force code above and all really converts *to* little endian, not from it. Cf., for instance, the function iwl_eeprom_query16() -- it reads two u8 values and combines them into a u16, in a little-endian way. And considering it more, it makes sense to have the eeprom array as on the device, after all not all values really are 16-bit values, the MAC address for instance is not. Now, what this really means is that all the annotations are completely wrong. The eeprom reading code should fill the priv->eeprom array as a __le16 array, with __le16 values. This also means that iwl_read_otp_word() should really have a __le16 pointer as the data argument, since it should be filling that in a format suitable for priv->eeprom. Propagating these changes throughout, iwl_find_otp_image() is found to be, now obviously visible, defective -- it uses the data returned by iwl_read_otp_word() directly as if it was CPU endianness. Fixing that, which is this hunk of the patch: - next_link_addr = link_value * sizeof(u16); + next_link_addr = le16_to_cpu(link_value) * sizeof(u16); is the only real change of this patch. Everything else is just fixing the sparse annotations. Also, the bug only shows up on big endian platforms with a 1000 series card. 5000 and previous series do not use OTP, and 6000 series has shadow RAM support which means we don't ever use the defective code on any cards but 1000. Signed-off-by: Johannes Berg Cc: stable@kernel.org Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e1032f2..165d1f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1168,7 +1168,7 @@ struct iwl_priv { u32 last_beacon_time; u64 last_tsf; - /* eeprom */ + /* eeprom -- this is in the card's little endian byte order */ u8 *eeprom; int nvm_device_type; struct iwl_eeprom_calib_info *calib_info; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 72f0d77..08ad6e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -370,7 +370,7 @@ static int iwl_init_otp_access(struct iwl_priv *priv) return ret; } -static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) +static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_data) { int ret = 0; u32 r; @@ -404,7 +404,7 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); } - *eeprom_data = le16_to_cpu((__force __le16)(r >> 16)); + *eeprom_data = cpu_to_le16(r >> 16); return 0; } @@ -413,7 +413,8 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) */ static bool iwl_is_otp_empty(struct iwl_priv *priv) { - u16 next_link_addr = 0, link_value; + u16 next_link_addr = 0; + __le16 link_value; bool is_empty = false; /* locate the beginning of OTP link list */ @@ -443,7 +444,8 @@ static bool iwl_is_otp_empty(struct iwl_priv *priv) static int iwl_find_otp_image(struct iwl_priv *priv, u16 *validblockaddr) { - u16 next_link_addr = 0, link_value = 0, valid_addr; + u16 next_link_addr = 0, valid_addr; + __le16 link_value = 0; int usedblocks = 0; /* set addressing mode to absolute to traverse the link list */ @@ -463,7 +465,7 @@ static int iwl_find_otp_image(struct iwl_priv *priv, * check for more block on the link list */ valid_addr = next_link_addr; - next_link_addr = link_value * sizeof(u16); + next_link_addr = le16_to_cpu(link_value) * sizeof(u16); IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n", usedblocks, next_link_addr); if (iwl_read_otp_word(priv, next_link_addr, &link_value)) @@ -497,7 +499,7 @@ static int iwl_find_otp_image(struct iwl_priv *priv, */ int iwl_eeprom_init(struct iwl_priv *priv) { - u16 *e; + __le16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); int sz; int ret; @@ -516,7 +518,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) ret = -ENOMEM; goto alloc_err; } - e = (u16 *)priv->eeprom; + e = (__le16 *)priv->eeprom; priv->cfg->ops->lib->apm_ops.init(priv); @@ -559,7 +561,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) } for (addr = validblockaddr; addr < validblockaddr + sz; addr += sizeof(u16)) { - u16 eeprom_data; + __le16 eeprom_data; ret = iwl_read_otp_word(priv, addr, &eeprom_data); if (ret) @@ -584,7 +586,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) goto done; } r = _iwl_read_direct32(priv, CSR_EEPROM_REG); - e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); + e[addr / 2] = cpu_to_le16(r >> 16); } } ret = 0; -- cgit v0.10.2 From b7bb1756cb6a610cdbac8cfdad9e79bb5670b63b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 14 Dec 2009 14:12:09 -0800 Subject: iwlwifi: fix more eeprom endian bugs I've also for a long time had a problem with the temperature calculation code, which I had fixed by byte-swapping the values, and now it turns out that was the correct fix after all. Also, any use of iwl_eeprom_query_addr() that is for more than a u8 must be cast to little endian, and some structs as well. Fix all this. Again, no real impact on platforms that already are little endian. Signed-off-by: Johannes Berg Cc: stable@kernel.org Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 386513b..484c5fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1204,7 +1204,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info); /* calculate tx gain adjustment based on power supply voltage */ - voltage = priv->calib_info->voltage; + voltage = le16_to_cpu(priv->calib_info->voltage); init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage); voltage_compensation = iwl4965_get_voltage_compensation(voltage, init_voltage); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 4ef6804..bc056e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -92,11 +92,15 @@ static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) { - u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, - EEPROM_5000_TEMPERATURE); - /* offset = temperature - voltage / coef */ - s32 offset = (s32)(temp_calib[0] - temp_calib[1] / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); - return offset; + u16 temperature, voltage; + __le16 *temp_calib = + (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_TEMPERATURE); + + temperature = le16_to_cpu(temp_calib[0]); + voltage = le16_to_cpu(temp_calib[1]); + + /* offset = temp - volt / coeff */ + return (s32)(temperature - voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); } /* Fixed (non-configurable) rx data from phy */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e2f8615..33a5866 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -333,14 +333,15 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv) static int iwl5000_set_Xtal_calib(struct iwl_priv *priv) { struct iwl_calib_xtal_freq_cmd cmd; - u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); + __le16 *xtal_calib = + (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD; cmd.hdr.first_group = 0; cmd.hdr.groups_num = 1; cmd.hdr.data_valid = 1; - cmd.cap_pin1 = (u8)xtal_calib[0]; - cmd.cap_pin2 = (u8)xtal_calib[1]; + cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]); + cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]); return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL], (u8 *)&cmd, sizeof(cmd)); } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 5cd2b66..0cd9c02 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -137,7 +137,7 @@ struct iwl_eeprom_channel { * */ struct iwl_eeprom_enhanced_txpwr { - u16 common; + __le16 common; s8 chain_a_max; s8 chain_b_max; s8 chain_c_max; @@ -360,7 +360,7 @@ struct iwl_eeprom_calib_subband_info { struct iwl_eeprom_calib_info { u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ u8 saturation_power52; /* half-dBm */ - s16 voltage; /* signed */ + __le16 voltage; /* signed */ struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS]; } __attribute__ ((packed)); -- cgit v0.10.2 From bc45a67079c916a9bd0a95b0b879cc0f259bac6e Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Mon, 14 Dec 2009 14:12:10 -0800 Subject: iwl3945: disable power save we see from http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2125 that power saving does not work well on 3945. Since then power saving has also been connected with association problems where an AP deathenticates a 3945 after it is unable to transmit data to it - this happens when 3945 enters power savings mode. Disable power save support until issues are resolved. Signed-off-by: Reinette Chatre CC: stable@kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 4609323..e413bd3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2835,6 +2835,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { .use_isr_legacy = true, .ht_greenfield_support = false, .led_compensation = 64, + .broken_powersave = true, }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2851,6 +2852,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .use_isr_legacy = true, .ht_greenfield_support = false, .led_compensation = 64, + .broken_powersave = true, }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4c0e475..c322d6c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3932,9 +3932,11 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | - IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + IEEE80211_HW_SPECTRUM_MGMT; + + if (!priv->cfg->broken_powersave) + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | -- cgit v0.10.2 From 731a29b74aa823e09a6547befce3f721bef32f86 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Mon, 14 Dec 2009 14:12:11 -0800 Subject: iwlwifi: initialize spinlock before use Recent powersaving work resulted in power management ops being called during EEPROM initialization. The lock used by these functions is not initialized at this time. Ensure lock is initialized before it is used. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 715db219..1c9866d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3173,7 +3173,6 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->ibss_beacon = NULL; - spin_lock_init(&priv->lock); spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); @@ -3361,10 +3360,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) (unsigned long long) pci_resource_len(pdev, 0)); IWL_DEBUG_INFO(priv, "pci_resource_base = %p\n", priv->hw_base); - /* this spin lock will be used in apm_ops.init and EEPROM access + /* these spin locks will be used in apm_ops.init and EEPROM access * we should init now */ spin_lock_init(&priv->reg_lock); + spin_lock_init(&priv->lock); iwl_hw_detect(priv); IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n", priv->cfg->name, priv->hw_rev); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c322d6c..96b23f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3863,7 +3863,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->retry_rate = 1; priv->ibss_beacon = NULL; - spin_lock_init(&priv->lock); spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); @@ -4055,10 +4054,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, 0x41, 0x00); - /* this spin lock will be used in apm_ops.init and EEPROM access + /* these spin locks will be used in apm_ops.init and EEPROM access * we should init now */ spin_lock_init(&priv->reg_lock); + spin_lock_init(&priv->lock); /*********************** * 4. Read EEPROM -- cgit v0.10.2 From dc57a303faab8562b92e85df0d79c4a05d7e2a61 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 14 Dec 2009 14:12:12 -0800 Subject: iwl3945: fix panic in iwl3945 driver 3945 updated write_ptr without regard to read_ptr on the Tx path. This messes up our TFD on high load and result in the following: <1>[ 7290.414172] IP: [] iwl3945_rx_reply_tx+0xc1/0x450 [iwl3945] <4>[ 7290.414205] PGD 0 <1>[ 7290.414214] Thread overran stack, or stack corrupted <0>[ 7290.414229] Oops: 0002 [#1] PREEMPT SMP <0>[ 7290.414246] last sysfs file: /sys/devices/platform/coretemp.1/temp1_input <4>[ 7290.414265] CPU 0 <4>[ 7290.414274] Modules linked in: af_packet nfsd usb_storage usb_libusual cpufreq_powersave exportfs cpufreq_conservative iwl3945 nfs cpufreq_userspace snd_hda_codec_realtek acpi_cpufreq uvcvideo lockd iwlcore snd_hda_intel joydev coretemp nfs_acl videodev snd_hda_codec mac80211 v4l1_compat snd_hwdep sbp2 v4l2_compat_ioctl32 uhci_hcd psmouse auth_rpcgss ohci1394 cfg80211 ehci_hcd video ieee1394 snd_pcm serio_raw battery ac nvidia(P) usbcore output sunrpc evdev lirc_ene0100 snd_page_alloc rfkill tg3 libphy fuse lzo lzo_decompress lzo_compress <6>[ 7290.414486] Pid: 0, comm: swapper Tainted: P 2.6.32-rc8-wl #213 Aspire 5720 <6>[ 7290.414507] RIP: 0010:[] [] iwl3945_rx_reply_tx+0xc1/0x450 [iwl3945] <6>[ 7290.414541] RSP: 0018:ffff880002203d60 EFLAGS: 00010246 <6>[ 7290.414557] RAX: 000000000000004f RBX: ffff880064c11600 RCX: 0000000000000013 <6>[ 7290.414576] RDX: ffffffffa0ddcf20 RSI: ffff8800512b7008 RDI: 0000000000000038 <6>[ 7290.414596] RBP: ffff880002203dd0 R08: 0000000000000000 R09: 0000000000000100 <6>[ 7290.414616] R10: 0000000000000001 R11: 0000000000000000 R12: 00000000000000a0 <6>[ 7290.414635] R13: 0000000000000002 R14: 0000000000000013 R15: 0000000000020201 <6>[ 7290.414655] FS: 0000000000000000(0000) GS:ffff880002200000(0000) knlGS:0000000000000000 <6>[ 7290.414677] CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b <6>[ 7290.414693] CR2: 0000000000000041 CR3: 0000000001001000 CR4: 00000000000006f0 <6>[ 7290.414712] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 <6>[ 7290.414732] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 <4>[ 7290.414752] Process swapper (pid: 0, threadinfo ffffffff81524000, task ffffffff81528b60) <0>[ 7290.414772] Stack: <4>[ 7290.414780] ffff880002203da0 0000000000000046 0000000000000000 0000000000000046 <4>[ 7290.414804] <0> 0000000000000282 0000000000000282 0000000000000282 ffff880064c12010 <4>[ 7290.414830] <0> ffff880002203db0 ffff880064c11600 ffff880064c12e50 ffff8800512b7000 <0>[ 7290.414858] Call Trace: <0>[ 7290.414867] <4>[ 7290.414884] [] iwl3945_irq_tasklet+0x657/0x1740 [iwl3945] <4>[ 7290.414910] [] ? _spin_unlock+0x30/0x60 <4>[ 7290.414931] [] tasklet_action+0x101/0x110 <4>[ 7290.414950] [] __do_softirq+0xc0/0x160 <4>[ 7290.414968] [] call_softirq+0x1c/0x30 <4>[ 7290.414986] [] do_softirq+0x75/0xb0 <4>[ 7290.415003] [] irq_exit+0x95/0xa0 <4>[ 7290.415020] [] do_IRQ+0x77/0xf0 <4>[ 7290.415038] [] ret_from_intr+0x0/0xf <0>[ 7290.415052] <4>[ 7290.415067] [] ? acpi_idle_enter_bm+0x270/0x2a5 <4>[ 7290.415087] [] ? acpi_idle_enter_bm+0x27a/0x2a5 <4>[ 7290.415107] [] ? acpi_idle_enter_bm+0x270/0x2a5 <4>[ 7290.415130] [] ? cpuidle_idle_call+0x93/0xf0 <4>[ 7290.415149] [] ? cpu_idle+0xa7/0x110 <4>[ 7290.415168] [] ? rest_init+0x75/0x80 <4>[ 7290.415187] [] ? start_kernel+0x3a7/0x3b3 <4>[ 7290.415206] [] ? x86_64_start_reservations+0x125/0x129 <4>[ 7290.415227] [] ? x86_64_start_kernel+0xe4/0xeb <0>[ 7290.415243] Code: 00 41 39 ce 0f 8d e8 01 00 00 48 8b 47 40 48 63 d2 48 69 d2 98 00 00 00 4c 8b 04 02 48 c7 c2 20 cf dd a0 49 8d 78 38 49 8d 40 4f 47 09 00 c6 47 0c 00 c6 47 0f 00 c6 47 12 00 c6 47 15 00 49 <1>[ 7290.415382] RIP [] iwl3945_rx_reply_tx+0xc1/0x450 [iwl3945] <4>[ 7290.415410] RSP <0>[ 7290.415421] CR2: 0000000000000041 <4>[ 7290.415436] ---[ end trace ec46807277caa515 ]--- <0>[ 7290.415450] Kernel panic - not syncing: Fatal exception in interrupt <4>[ 7290.415468] Pid: 0, comm: swapper Tainted: P D 2.6.32-rc8-wl #213 <4>[ 7290.415486] Call Trace: <4>[ 7290.415495] [] panic+0x7d/0x13a <4>[ 7290.415519] [] oops_end+0xda/0xe0 <4>[ 7290.415538] [] no_context+0xea/0x250 <4>[ 7290.415557] [] ? select_task_rq_fair+0x511/0x780 <4>[ 7290.415578] [] __bad_area_nosemaphore+0x125/0x1e0 <4>[ 7290.415597] [] ? __enqueue_entity+0x7c/0x80 <4>[ 7290.415616] [] ? enqueue_task_fair+0x111/0x150 <4>[ 7290.415636] [] bad_area_nosemaphore+0xe/0x10 <4>[ 7290.415656] [] do_page_fault+0x26a/0x320 <4>[ 7290.415674] [] page_fault+0x1f/0x30 <4>[ 7290.415697] [] ? iwl3945_rx_reply_tx+0xc1/0x450 [iwl3945] <4>[ 7290.415723] [] iwl3945_irq_tasklet+0x657/0x1740 [iwl3945] <4>[ 7290.415746] [] ? _spin_unlock+0x30/0x60 <4>[ 7290.415764] [] tasklet_action+0x101/0x110 <4>[ 7290.415783] [] __do_softirq+0xc0/0x160 <4>[ 7290.415801] [] call_softirq+0x1c/0x30 <4>[ 7290.415818] [] do_softirq+0x75/0xb0 <4>[ 7290.415835] [] irq_exit+0x95/0xa0 <4>[ 7290.415852] [] do_IRQ+0x77/0xf0 <4>[ 7290.415869] [] ret_from_intr+0x0/0xf <4>[ 7290.415883] [] ? acpi_idle_enter_bm+0x270/0x2a5 <4>[ 7290.415911] [] ? acpi_idle_enter_bm+0x27a/0x2a5 <4>[ 7290.415931] [] ? acpi_idle_enter_bm+0x270/0x2a5 <4>[ 7290.415952] [] ? cpuidle_idle_call+0x93/0xf0 <4>[ 7290.415971] [] ? cpu_idle+0xa7/0x110 <4>[ 7290.415989] [] ? rest_init+0x75/0x80 <4>[ 7290.416007] [] ? start_kernel+0x3a7/0x3b3 <4>[ 7290.416026] [] ? x86_64_start_reservations+0x125/0x129 <4>[ 7290.416047] [] ? x86_64_start_kernel+0xe4/0xeb Reported-by: Maxim Levitsky Tested-by: Maxim Levitsky Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre CC: stable@kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 96b23f4..e5d8fa3 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -548,6 +548,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txq = &priv->txq[txq_id]; q = &txq->q; + if ((iwl_queue_space(q) < q->high_mark)) + goto drop; + spin_lock_irqsave(&priv->lock, flags); idx = get_cmd_index(q, q->write_ptr, 0); -- cgit v0.10.2 From 6c3069b1e7e983e176a5f826e2edffefdd404a08 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Mon, 14 Dec 2009 14:12:13 -0800 Subject: iwlwifi: fix 40MHz operation setting on cards that do not allow it Some devices have 40MHz operation disabled entirely. Ensure that driver do not enable 40MHz operation if a channel does not allow this. This fixes http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2135 Signed-off-by: Reinette Chatre CC: stable@kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 08ad6e4..4a30969 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -749,7 +749,8 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, ch_info->ht40_eeprom = *eeprom_ch; ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; ch_info->ht40_flags = eeprom_ch->flags; - ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; + if (eeprom_ch->flags & EEPROM_CHANNEL_VALID) + ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; return 0; } -- cgit v0.10.2 From 7988436c6330eab98f64b6e799ce2d30fe5ffd55 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 14 Dec 2009 23:32:31 +0100 Subject: rt2x00: Fix calculation of rt2800 iveiv entry offset. Fix typo. The index should be multiplied by the entry size, not 'and'-ed. Found via code-inspection. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index c5fe867..1a7eae3 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1323,7 +1323,7 @@ #define PAIRWISE_KEY_ENTRY(__idx) \ ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) #define MAC_IVEIV_ENTRY(__idx) \ - ( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) ) + ( MAC_IVEIV_TABLE_BASE + ((__idx) * sizeof(struct mac_iveiv_entry)) ) #define MAC_WCID_ATTR_ENTRY(__idx) \ ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) ) #define SHARED_KEY_ENTRY(__idx) \ -- cgit v0.10.2 From 17b182e3db255ab068c2ebb85f34840607a53cc4 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 14 Dec 2009 14:56:56 +0530 Subject: ath9k: Fix bug in assigning sequence number The internal, driver-specific maintenance of sequence numbers is applicable only for HT frames. Also, remove comments that are not relevant anymore. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 6770620..fd0cf4d8 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1414,17 +1414,9 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb, * For HT capable stations, we save tidno for later use. * We also override seqno set by upper layer with the one * in tx aggregation state. - * - * If fragmentation is on, the sequence number is - * not overridden, since it has been - * incremented by the fragmentation routine. - * - * FIXME: check if the fragmentation threshold exceeds - * IEEE80211 max. */ tid = ATH_AN_2_TID(an, bf->bf_tidno); - hdr->seq_ctrl = cpu_to_le16(tid->seq_next << - IEEE80211_SEQ_SEQ_SHIFT); + hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); bf->bf_seqno = tid->seq_next; INCR(tid->seq_next, IEEE80211_SEQ_MAX); } @@ -1636,7 +1628,8 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_keyix = ATH9K_TXKEYIX_INVALID; } - if (ieee80211_is_data_qos(fc) && (sc->sc_flags & SC_OP_TXAGGR)) + if (ieee80211_is_data_qos(fc) && bf_isht(bf) && + (sc->sc_flags & SC_OP_TXAGGR)) assign_aggr_tid_seqno(skb, bf); bf->bf_mpdu = skb; -- cgit v0.10.2 From e8009e9850d59000d518296af372888911a129bd Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 14 Dec 2009 14:57:08 +0530 Subject: ath9k: Fix TX queue draining When TX DMA termination has failed, the HW has to be reset completely. Doing a fast channel change in this case is insufficient. Also, change the debug level of a couple of messages to FATAL. Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 71b84d9..efc420c 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -186,7 +186,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) wait = wait_time; while (ath9k_hw_numtxpending(ah, q)) { if ((--wait) == 0) { - ath_print(common, ATH_DBG_QUEUE, + ath_print(common, ATH_DBG_FATAL, "Failed to stop TX DMA in 100 " "msec after killing last frame\n"); break; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index fd0cf4d8..1e813bb 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1108,11 +1108,11 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) if (npend) { int r; - ath_print(common, ATH_DBG_XMIT, + ath_print(common, ATH_DBG_FATAL, "Unable to stop TxDMA. Reset HAL!\n"); spin_lock_bh(&sc->sc_resetlock); - r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); + r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); if (r) ath_print(common, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d\n", -- cgit v0.10.2 From 2ab81d4a9a5ecb13d343269b3cdf5d975c81c570 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 14 Dec 2009 16:34:56 +0530 Subject: ath9k: Stop ANI when doing a reset The MIB counters are disabled when doing a chip reset. Since ANI depends on the MIB registers for its operation, relying on the contents of said registers during HW reset results in sub-optimal performance. Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c487434..9e68c1a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1973,6 +1973,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) struct ieee80211_hw *hw = sc->hw; int r; + /* Stop ANI */ + del_timer_sync(&common->ani.timer); + ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, retry_tx); ath_stoprecv(sc); @@ -2014,6 +2017,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) } } + /* Start ANI */ + ath_start_ani(common); + return r; } -- cgit v0.10.2 From 77ca7d9e2c099b4484bb10075948b4267f37d9fa Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Mon, 14 Dec 2009 15:56:54 -0800 Subject: drivers/net/wireless/iwlwifi/iwl-tx.c: fix gcc-3.4.5 warning drivers/net/wireless/iwlwifi/iwl-tx.c: In function `iwl_hw_txq_ctx_free': drivers/net/wireless/iwlwifi/iwl-tx.c:410: warning: suggest explicit braces to avoid ambiguous `else' Cc: Zhu Yi Cc: Reinette Chatre Signed-off-by: Andrew Morton Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 00da5e1..87ce2bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -407,13 +407,14 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) int txq_id; /* Tx queues */ - if (priv->txq) + if (priv->txq) { for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) if (txq_id == IWL_CMD_QUEUE_NUM) iwl_cmd_queue_free(priv); else iwl_tx_queue_free(priv, txq_id); + } iwl_free_dma_ptr(priv, &priv->kw); iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); -- cgit v0.10.2 From 45b241689179a6065384260242637cf21dabfb2d Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 16 Dec 2009 05:12:58 +0100 Subject: Libertas: fix buffer overflow in lbs_get_essid() The libertas driver copies the SSID buffer back to the wireless core and appends a trailing NULL character for termination. This is a) unnecessary because the buffer is allocated with kzalloc and is hence already NULLed when this function is called, and b) for priv->curbssparams.ssid_len == 32, it writes back one byte too much which causes memory corruptions. Fix this by removing the extra write. Signed-off-by: Daniel Mack Cc: Stephen Hemminger Cc: Maithili Hinge Cc: Kiran Divekar Cc: Michael Hirsch Cc: netdev@vger.kernel.org Cc: libertas-dev@lists.infradead.org Cc: linux-wireless@lists.infradead.org Cc: stable@kernel.org Acked-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index a8eb9e1..4b1aab5 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -2025,10 +2025,8 @@ static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, if (priv->connect_status == LBS_CONNECTED) { memcpy(extra, priv->curbssparams.ssid, priv->curbssparams.ssid_len); - extra[priv->curbssparams.ssid_len] = '\0'; } else { memset(extra, 0, 32); - extra[priv->curbssparams.ssid_len] = '\0'; } /* * If none, we may want to get the one that was set -- cgit v0.10.2 From 8585c2b896861aacd15337c3c7e58ad114e6cf60 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Wed, 16 Dec 2009 17:01:38 +0100 Subject: iwmc3200wifi: Fix test of unsigned in iwm_ntf_stop_resume_tx() `queue' was unsigned so the test did not work. Signed-off-by: Roel Kluin Reviewed-by: Pavel Roskin Acked-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 5a26bb0..79ffa3b 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -349,7 +349,7 @@ int iwm_up(struct iwm_priv *iwm); int iwm_down(struct iwm_priv *iwm); /* TX API */ -u16 iwm_tid_to_queue(u16 tid); +int iwm_tid_to_queue(u16 tid); void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); void iwm_tx_worker(struct work_struct *work); int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index e4f0f87..c4c0d23 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -76,7 +76,7 @@ static int iwm_stop(struct net_device *ndev) */ static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; -u16 iwm_tid_to_queue(u16 tid) +int iwm_tid_to_queue(u16 tid) { if (tid > IWM_UMAC_TID_NR - 2) return -EINVAL; diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 72c27a3e..3db3d8b 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1126,7 +1126,7 @@ static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf, if (!stop) { struct iwm_tx_queue *txq; - u16 queue = iwm_tid_to_queue(bit); + int queue = iwm_tid_to_queue(bit); if (queue < 0) continue; -- cgit v0.10.2 From 9a418af5df03ad133cd8c8f6742b75e542db6392 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 Dec 2009 13:55:48 +0100 Subject: mac80211: fix peer HT capabilities I noticed yesterday, because Jeff had noticed a speed regression, cf. bug http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2138 that the SM PS settings for peers were wrong. Instead of overwriting the SM PS settings with the local bits, we need to keep the remote bits. The bug was part of the original HT code from over two years ago, but unfortunately nobody noticed that it makes no sense -- we shouldn't be overwriting the peer's setting with our own but rather keep it intact when masking the peer capabilities with our own. While fixing that, I noticed that the masking of capabilities is completely useless for most of the bits, so also fix those other bits. Finally, I also noticed that PSMP_SUPPORT no longer exists in the final 802.11n version, so also remove that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 6bf6c0f..27bf887 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2080,8 +2080,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_TX_STBC | - IEEE80211_HT_CAP_RX_STBC | - IEEE80211_HT_CAP_PSMP_SUPPORT; + IEEE80211_HT_CAP_RX_STBC; spec->ht.ampdu_factor = 3; spec->ht.ampdu_density = 4; spec->ht.mcs.tx_params = diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index d9724a2..163c840 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -832,7 +832,7 @@ struct ieee80211_ht_cap { #define IEEE80211_HT_CAP_DELAY_BA 0x0400 #define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 #define IEEE80211_HT_CAP_DSSSCCK40 0x1000 -#define IEEE80211_HT_CAP_PSMP_SUPPORT 0x2000 +#define IEEE80211_HT_CAP_RESERVED 0x2000 #define IEEE80211_HT_CAP_40MHZ_INTOLERANT 0x4000 #define IEEE80211_HT_CAP_LSIG_TXOP_PROT 0x8000 diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 3787455..d7dcee6 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -34,9 +34,28 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, ht_cap->ht_supported = true; - ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap; - ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS; - ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS; + /* + * The bits listed in this expression should be + * the same for the peer and us, if the station + * advertises more then we can't use those thus + * we mask them out. + */ + ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & + (sband->ht_cap.cap | + ~(IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40)); + /* + * The STBC bits are asymmetric -- if we don't have + * TX then mask out the peer's RX and vice versa. + */ + if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) + ht_cap->cap &= ~IEEE80211_HT_CAP_RX_STBC; + if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) + ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; ampdu_info = ht_cap_ie->ampdu_params_info; ht_cap->ampdu_factor = -- cgit v0.10.2 From 0183826b58a2712ffe608bc3302447be3e6a3ab8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 Dec 2009 16:16:53 +0100 Subject: mac80211: fix WMM AP settings application My commit 77fdaa12cea26c204cc12c312fe40bc0f3dcdfd8 Author: Johannes Berg Date: Tue Jul 7 03:45:17 2009 +0200 mac80211: rework MLME for multiple authentications inadvertedly broke WMM because it removed, along with a bunch of other now useless initialisations, the line initialising sdata->u.mgd.wmm_last_param_set to -1 which would make it adopt any WMM parameter set. If, as is usually the case, the AP uses WMM parameter set sequence number zero, we'd never update it until the AP changes the sequence number. Add the missing initialisation back to get the WMM settings from the AP applied locally. Signed-off-by: Johannes Berg Cc: stable@kernel.org [2.6.31+] Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d8d50fb..c79e59f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -915,6 +915,14 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | IEEE80211_STA_BEACON_POLL); + /* + * Always handle WMM once after association regardless + * of the first value the AP uses. Setting -1 here has + * that effect because the AP values is an unsigned + * 4-bit value. + */ + sdata->u.mgd.wmm_last_param_set = -1; + ieee80211_led_assoc(local, 1); sdata->vif.bss_conf.assoc = 1; -- cgit v0.10.2 From 92c6f8d849178582fc527aaf1e51dd37a74767d3 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 18 Dec 2009 11:19:32 -0800 Subject: ps3_gelic_wireless: Fix build failure due to missing WEXT_PRIV The option to support the old style PSK interface in the PS3 GELIC wireless drivers requires CONFIG_WEXT_PRIV to be set Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Geoff Levand Signed-off-by: John W. Linville diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 0bbd5ae..18ff622 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2344,6 +2344,7 @@ config GELIC_NET config GELIC_WIRELESS bool "PS3 Wireless support" + depends on WLAN depends on GELIC_NET select WIRELESS_EXT help @@ -2356,6 +2357,7 @@ config GELIC_WIRELESS config GELIC_WIRELESS_OLD_PSK_INTERFACE bool "PS3 Wireless private PSK interface (OBSOLETE)" depends on GELIC_WIRELESS + select WEXT_PRIV help This option retains the obsolete private interface to pass the PSK from user space programs to the driver. The PSK -- cgit v0.10.2 From ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 23 Dec 2009 13:46:36 +0000 Subject: sfc: Move PHY software state initialisation from init() into probe() This prevents efx->link_advertising from being blatted during a reset. The phy_short_reach sysfs node is now destroyed later in the port shutdown process, so check for STATE_RUNNING after acquiring the rtnl_lock (just like in set_phy_flash_cfg). Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index f983e3b..103e8b0 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -741,14 +741,14 @@ static int efx_probe_port(struct efx_nic *efx) EFX_LOG(efx, "create port\n"); + if (phy_flash_cfg) + efx->phy_mode = PHY_MODE_SPECIAL; + /* Connect up MAC/PHY operations table */ rc = efx->type->probe_port(efx); if (rc) goto err; - if (phy_flash_cfg) - efx->phy_mode = PHY_MODE_SPECIAL; - /* Sanity check MAC address */ if (is_valid_ether_addr(efx->mac_address)) { memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 17afcd2..9d009c4 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -925,6 +925,7 @@ static int falcon_probe_port(struct efx_nic *efx) static void falcon_remove_port(struct efx_nic *efx) { + efx->phy_op->remove(efx); efx_nic_free_buffer(efx, &efx->stats_buffer); } diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 0e1bcc5..eb694af 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -304,31 +304,47 @@ static u32 mcdi_to_ethtool_media(u32 media) static int efx_mcdi_phy_probe(struct efx_nic *efx) { - struct efx_mcdi_phy_cfg *phy_cfg; + struct efx_mcdi_phy_cfg *phy_data; + u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; + u32 caps; int rc; - /* TODO: Move phy_data initialisation to - * phy_op->probe/remove, rather than init/fini */ - phy_cfg = kzalloc(sizeof(*phy_cfg), GFP_KERNEL); - if (phy_cfg == NULL) { - rc = -ENOMEM; - goto fail_alloc; - } - rc = efx_mcdi_get_phy_cfg(efx, phy_cfg); + /* Initialise and populate phy_data */ + phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); + if (phy_data == NULL) + return -ENOMEM; + + rc = efx_mcdi_get_phy_cfg(efx, phy_data); if (rc != 0) goto fail; - efx->phy_type = phy_cfg->type; + /* Read initial link advertisement */ + BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); + rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, + outbuf, sizeof(outbuf), NULL); + if (rc) + goto fail; + + /* Fill out nic state */ + efx->phy_data = phy_data; + efx->phy_type = phy_data->type; - efx->mdio_bus = phy_cfg->channel; - efx->mdio.prtad = phy_cfg->port; - efx->mdio.mmds = phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); + efx->mdio_bus = phy_data->channel; + efx->mdio.prtad = phy_data->port; + efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); efx->mdio.mode_support = 0; - if (phy_cfg->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) + if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) efx->mdio.mode_support |= MDIO_SUPPORTS_C22; - if (phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) + if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); + if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) + efx->link_advertising = + mcdi_to_ethtool_cap(phy_data->media, caps); + else + phy_data->forced_cap = caps; + /* Assert that we can map efx -> mcdi loopback modes */ BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE); BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA); @@ -365,46 +381,6 @@ static int efx_mcdi_phy_probe(struct efx_nic *efx) * but by convention we don't */ efx->loopback_modes &= ~(1 << LOOPBACK_NONE); - kfree(phy_cfg); - - return 0; - -fail: - kfree(phy_cfg); -fail_alloc: - return rc; -} - -static int efx_mcdi_phy_init(struct efx_nic *efx) -{ - struct efx_mcdi_phy_cfg *phy_data; - u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; - u32 caps; - int rc; - - phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); - if (phy_data == NULL) - return -ENOMEM; - - rc = efx_mcdi_get_phy_cfg(efx, phy_data); - if (rc != 0) - goto fail; - - efx->phy_data = phy_data; - - BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); - rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, - outbuf, sizeof(outbuf), NULL); - if (rc) - goto fail; - - caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); - if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) - efx->link_advertising = - mcdi_to_ethtool_cap(phy_data->media, caps); - else - phy_data->forced_cap = caps; - return 0; fail: @@ -504,7 +480,7 @@ static bool efx_mcdi_phy_poll(struct efx_nic *efx) return !efx_link_state_equal(&efx->link_state, &old_state); } -static void efx_mcdi_phy_fini(struct efx_nic *efx) +static void efx_mcdi_phy_remove(struct efx_nic *efx) { struct efx_mcdi_phy_data *phy_data = efx->phy_data; @@ -586,10 +562,11 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec struct efx_phy_operations efx_mcdi_phy_ops = { .probe = efx_mcdi_phy_probe, - .init = efx_mcdi_phy_init, + .init = efx_port_dummy_op_int, .reconfigure = efx_mcdi_phy_reconfigure, .poll = efx_mcdi_phy_poll, - .fini = efx_mcdi_phy_fini, + .fini = efx_port_dummy_op_void, + .remove = efx_mcdi_phy_remove, .get_settings = efx_mcdi_phy_get_settings, .set_settings = efx_mcdi_phy_set_settings, .run_tests = NULL, diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 34c381f..d5aab5b 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -524,6 +524,7 @@ struct efx_phy_operations { int (*probe) (struct efx_nic *efx); int (*init) (struct efx_nic *efx); void (*fini) (struct efx_nic *efx); + void (*remove) (struct efx_nic *efx); int (*reconfigure) (struct efx_nic *efx); bool (*poll) (struct efx_nic *efx); void (*get_settings) (struct efx_nic *efx, diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 3800fc7..7450e3a 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -137,6 +137,14 @@ static int qt202x_reset_phy(struct efx_nic *efx) static int qt202x_phy_probe(struct efx_nic *efx) { + struct qt202x_phy_data *phy_data; + + phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL); + if (!phy_data) + return -ENOMEM; + efx->phy_data = phy_data; + phy_data->phy_mode = efx->phy_mode; + efx->mdio.mmds = QT202X_REQUIRED_DEVS; efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; efx->loopback_modes = QT202X_LOOPBACKS | FALCON_XMAC_LOOPBACKS; @@ -145,7 +153,6 @@ static int qt202x_phy_probe(struct efx_nic *efx) static int qt202x_phy_init(struct efx_nic *efx) { - struct qt202x_phy_data *phy_data; u32 devid; int rc; @@ -155,17 +162,11 @@ static int qt202x_phy_init(struct efx_nic *efx) return rc; } - phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL); - if (!phy_data) - return -ENOMEM; - efx->phy_data = phy_data; - devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n", devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), efx_mdio_id_rev(devid)); - phy_data->phy_mode = efx->phy_mode; return 0; } @@ -224,7 +225,7 @@ static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecm mdio45_ethtool_gset(&efx->mdio, ecmd); } -static void qt202x_phy_fini(struct efx_nic *efx) +static void qt202x_phy_remove(struct efx_nic *efx) { /* Free the context block */ kfree(efx->phy_data); @@ -236,7 +237,8 @@ struct efx_phy_operations falcon_qt202x_phy_ops = { .init = qt202x_phy_init, .reconfigure = qt202x_phy_reconfigure, .poll = qt202x_phy_poll, - .fini = qt202x_phy_fini, + .fini = efx_port_dummy_op_void, + .remove = qt202x_phy_remove, .get_settings = qt202x_phy_get_settings, .set_settings = efx_mdio_set_settings, }; diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index de07a4f..f8c6771 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -133,6 +133,7 @@ static int siena_probe_port(struct efx_nic *efx) void siena_remove_port(struct efx_nic *efx) { + efx->phy_op->remove(efx); efx_nic_free_buffer(efx, &efx->stats_buffer); } diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index ca11572..3009c29 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -202,10 +202,14 @@ static ssize_t set_phy_short_reach(struct device *dev, int rc; rtnl_lock(); - efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, - MDIO_PMA_10GBT_TXPWR_SHORT, - count != 0 && *buf != '0'); - rc = efx_reconfigure_port(efx); + if (efx->state != STATE_RUNNING) { + rc = -EBUSY; + } else { + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, + MDIO_PMA_10GBT_TXPWR_SHORT, + count != 0 && *buf != '0'); + rc = efx_reconfigure_port(efx); + } rtnl_unlock(); return rc < 0 ? rc : (ssize_t)count; @@ -298,36 +302,62 @@ static int tenxpress_init(struct efx_nic *efx) return 0; } -static int sfx7101_phy_probe(struct efx_nic *efx) +static int tenxpress_phy_probe(struct efx_nic *efx) { - efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; - efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; - efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS; - return 0; -} + struct tenxpress_phy_data *phy_data; + int rc; + + /* Allocate phy private storage */ + phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); + if (!phy_data) + return -ENOMEM; + efx->phy_data = phy_data; + phy_data->phy_mode = efx->phy_mode; + + /* Create any special files */ + if (efx->phy_type == PHY_TYPE_SFT9001B) { + rc = device_create_file(&efx->pci_dev->dev, + &dev_attr_phy_short_reach); + if (rc) + goto fail; + } + + if (efx->phy_type == PHY_TYPE_SFX7101) { + efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; + efx->mdio.mode_support = MDIO_SUPPORTS_C45; + + efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS; + + efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | + ADVERTISED_10000baseT_Full); + } else { + efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; + efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + + efx->loopback_modes = (SFT9001_LOOPBACKS | + FALCON_XMAC_LOOPBACKS | + FALCON_GMAC_LOOPBACKS); + + efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | + ADVERTISED_10000baseT_Full | + ADVERTISED_1000baseT_Full | + ADVERTISED_100baseT_Full); + } -static int sft9001_phy_probe(struct efx_nic *efx) -{ - efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; - efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; - efx->loopback_modes = (SFT9001_LOOPBACKS | FALCON_XMAC_LOOPBACKS | - FALCON_GMAC_LOOPBACKS); return 0; + +fail: + kfree(efx->phy_data); + efx->phy_data = NULL; + return rc; } static int tenxpress_phy_init(struct efx_nic *efx) { - struct tenxpress_phy_data *phy_data; - int rc = 0; + int rc; falcon_board(efx)->type->init_phy(efx); - phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); - if (!phy_data) - return -ENOMEM; - efx->phy_data = phy_data; - phy_data->phy_mode = efx->phy_mode; - if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { if (efx->phy_type == PHY_TYPE_SFT9001A) { int reg; @@ -341,44 +371,27 @@ static int tenxpress_phy_init(struct efx_nic *efx) rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) - goto fail; + return rc; rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); if (rc < 0) - goto fail; + return rc; } rc = tenxpress_init(efx); if (rc < 0) - goto fail; + return rc; - /* Initialise advertising flags */ - efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | - ADVERTISED_10000baseT_Full); - if (efx->phy_type != PHY_TYPE_SFX7101) - efx->link_advertising |= (ADVERTISED_1000baseT_Full | - ADVERTISED_100baseT_Full); + /* Reinitialise flow control settings */ efx_link_set_wanted_fc(efx, efx->wanted_fc); efx_mdio_an_reconfigure(efx); - if (efx->phy_type == PHY_TYPE_SFT9001B) { - rc = device_create_file(&efx->pci_dev->dev, - &dev_attr_phy_short_reach); - if (rc) - goto fail; - } - schedule_timeout_uninterruptible(HZ / 5); /* 200ms */ /* Let XGXS and SerDes out of reset */ falcon_reset_xaui(efx); return 0; - - fail: - kfree(efx->phy_data); - efx->phy_data = NULL; - return rc; } /* Perform a "special software reset" on the PHY. The caller is @@ -589,25 +602,26 @@ static bool tenxpress_phy_poll(struct efx_nic *efx) return !efx_link_state_equal(&efx->link_state, &old_state); } -static void tenxpress_phy_fini(struct efx_nic *efx) +static void sfx7101_phy_fini(struct efx_nic *efx) { int reg; + /* Power down the LNPGA */ + reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); + + /* Waiting here ensures that the board fini, which can turn + * off the power to the PHY, won't get run until the LNPGA + * powerdown has been given long enough to complete. */ + schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */ +} + +static void tenxpress_phy_remove(struct efx_nic *efx) +{ if (efx->phy_type == PHY_TYPE_SFT9001B) device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_short_reach); - if (efx->phy_type == PHY_TYPE_SFX7101) { - /* Power down the LNPGA */ - reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); - efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); - - /* Waiting here ensures that the board fini, which can turn - * off the power to the PHY, won't get run until the LNPGA - * powerdown has been given long enough to complete. */ - schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */ - } - kfree(efx->phy_data); efx->phy_data = NULL; } @@ -819,11 +833,12 @@ static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) } struct efx_phy_operations falcon_sfx7101_phy_ops = { - .probe = sfx7101_phy_probe, + .probe = tenxpress_phy_probe, .init = tenxpress_phy_init, .reconfigure = tenxpress_phy_reconfigure, .poll = tenxpress_phy_poll, - .fini = tenxpress_phy_fini, + .fini = sfx7101_phy_fini, + .remove = tenxpress_phy_remove, .get_settings = tenxpress_get_settings, .set_settings = tenxpress_set_settings, .set_npage_adv = sfx7101_set_npage_adv, @@ -832,11 +847,12 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = { }; struct efx_phy_operations falcon_sft9001_phy_ops = { - .probe = sft9001_phy_probe, + .probe = tenxpress_phy_probe, .init = tenxpress_phy_init, .reconfigure = tenxpress_phy_reconfigure, .poll = tenxpress_phy_poll, - .fini = tenxpress_phy_fini, + .fini = efx_port_dummy_op_void, + .remove = tenxpress_phy_remove, .get_settings = tenxpress_get_settings, .set_settings = tenxpress_set_settings, .set_npage_adv = sft9001_set_npage_adv, -- cgit v0.10.2 From a355020af415947c7dee7e00a91360d11b6a9b47 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 23 Dec 2009 13:46:47 +0000 Subject: sfc: Include XGXS in XMAC link status check except in XGMII loopback The XGXS block may not get a link immediately in XGXS or XAUI loopback modes, so we still need to check it. Split falcon_xaui_link_ok() into falcon_xgxs_link_ok(), which checks only the Falcon XGXS block, and falcon_xmac_link_ok(), which checks one or both sides of the link as appropriate. Also rename falcon_check_xaui_link() to falcon_xmac_link_ok_retry(). Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 3da933f..8ccab2c 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -111,16 +111,12 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) efx_writeo(efx, ®, FR_AB_XM_MGT_INT_MASK); } -/* Get status of XAUI link */ -static bool falcon_xaui_link_ok(struct efx_nic *efx) +static bool falcon_xgxs_link_ok(struct efx_nic *efx) { efx_oword_t reg; bool align_done, link_ok = false; int sync_status; - if (LOOPBACK_INTERNAL(efx)) - return true; - /* Read link status */ efx_reado(efx, ®, FR_AB_XX_CORE_STAT); @@ -135,14 +131,24 @@ static bool falcon_xaui_link_ok(struct efx_nic *efx) EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES); efx_writeo(efx, ®, FR_AB_XX_CORE_STAT); - /* If the link is up, then check the phy side of the xaui link */ - if (efx->link_state.up && link_ok) - if (efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) - link_ok = efx_mdio_phyxgxs_lane_sync(efx); - return link_ok; } +static bool falcon_xmac_link_ok(struct efx_nic *efx) +{ + /* + * Check MAC's XGXS link status except when using XGMII loopback + * which bypasses the XGXS block. + * If possible, check PHY's XGXS link status except when using + * MAC loopback. + */ + return (efx->loopback_mode == LOOPBACK_XGMII || + falcon_xgxs_link_ok(efx)) && + (!(efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) || + LOOPBACK_INTERNAL(efx) || + efx_mdio_phyxgxs_lane_sync(efx)); +} + void falcon_reconfigure_xmac_core(struct efx_nic *efx) { unsigned int max_frame_len; @@ -245,9 +251,9 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) /* Try to bring up the Falcon side of the Falcon-Phy XAUI link */ -static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) +static bool falcon_xmac_link_ok_retry(struct efx_nic *efx, int tries) { - bool mac_up = falcon_xaui_link_ok(efx); + bool mac_up = falcon_xmac_link_ok(efx); if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS || efx_phy_mode_disabled(efx->phy_mode)) @@ -261,7 +267,7 @@ static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) falcon_reset_xaui(efx); udelay(200); - mac_up = falcon_xaui_link_ok(efx); + mac_up = falcon_xmac_link_ok(efx); --tries; } @@ -272,7 +278,7 @@ static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) static bool falcon_xmac_check_fault(struct efx_nic *efx) { - return !falcon_check_xaui_link_up(efx, 5); + return !falcon_xmac_link_ok_retry(efx, 5); } static int falcon_reconfigure_xmac(struct efx_nic *efx) @@ -284,7 +290,7 @@ static int falcon_reconfigure_xmac(struct efx_nic *efx) falcon_reconfigure_mac_wrapper(efx); - efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5); + efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5); falcon_mask_status_intr(efx, true); return 0; @@ -357,7 +363,7 @@ void falcon_poll_xmac(struct efx_nic *efx) return; falcon_mask_status_intr(efx, false); - efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 1); + efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1); falcon_mask_status_intr(efx, true); } -- cgit v0.10.2 From a7ebd27a13757248863cd61e541af7fa9e7727ee Mon Sep 17 00:00:00 2001 From: Neil Turton Date: Wed, 23 Dec 2009 13:47:13 +0000 Subject: sfc: Fix DMA mapping cleanup in case of an error in TSO We need buffer->len to remain valid to work out the correct address to be unmapped. We therefore need to clear buffer->len after the unmap operation. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index e669f94..a8b70ef 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -821,8 +821,6 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) EFX_TXQ_MASK]; efx_tsoh_free(tx_queue, buffer); EFX_BUG_ON_PARANOID(buffer->skb); - buffer->len = 0; - buffer->continuation = true; if (buffer->unmap_len) { unmap_addr = (buffer->dma_addr + buffer->len - buffer->unmap_len); @@ -836,6 +834,8 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) PCI_DMA_TODEVICE); buffer->unmap_len = 0; } + buffer->len = 0; + buffer->continuation = true; } } -- cgit v0.10.2 From 17d6aeafe9d8268612d91edc0102659edb382282 Mon Sep 17 00:00:00 2001 From: Matthew Slattery Date: Wed, 23 Dec 2009 13:47:37 +0000 Subject: sfc: QT2025C: Work around PHY bug If we see the PHY remaining stuck in a link-down state due to PCS being down while PMA/PMD is up, we briefly switch to PMA/PMD loopback and back, which usually unsticks it. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 7450e3a..e4590fb 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -52,11 +52,15 @@ void falcon_qt202x_set_led(struct efx_nic *p, int led, int mode) struct qt202x_phy_data { enum efx_phy_mode phy_mode; + bool bug17190_in_bad_state; + unsigned long bug17190_timer; }; #define QT2022C2_MAX_RESET_TIME 500 #define QT2022C2_RESET_WAIT 10 +#define BUG17190_INTERVAL (2 * HZ) + static int qt2025c_wait_reset(struct efx_nic *efx) { unsigned long timeout = jiffies + 10 * HZ; @@ -96,6 +100,39 @@ static int qt2025c_wait_reset(struct efx_nic *efx) return 0; } +static void qt2025c_bug17190_workaround(struct efx_nic *efx) +{ + struct qt202x_phy_data *phy_data = efx->phy_data; + + /* The PHY can get stuck in a state where it reports PHY_XS and PMA/PMD + * layers up, but PCS down (no block_lock). If we notice this state + * persisting for a couple of seconds, we switch PMA/PMD loopback + * briefly on and then off again, which is normally sufficient to + * recover it. + */ + if (efx->link_state.up || + !efx_mdio_links_ok(efx, MDIO_DEVS_PMAPMD | MDIO_DEVS_PHYXS)) { + phy_data->bug17190_in_bad_state = false; + return; + } + + if (!phy_data->bug17190_in_bad_state) { + phy_data->bug17190_in_bad_state = true; + phy_data->bug17190_timer = jiffies + BUG17190_INTERVAL; + return; + } + + if (time_after_eq(jiffies, phy_data->bug17190_timer)) { + EFX_LOG(efx, "bashing QT2025C PMA/PMD\n"); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_PMA_CTRL1_LOOPBACK, true); + msleep(100); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_PMA_CTRL1_LOOPBACK, false); + phy_data->bug17190_timer = jiffies + BUG17190_INTERVAL; + } +} + static int qt202x_reset_phy(struct efx_nic *efx) { int rc; @@ -144,6 +181,8 @@ static int qt202x_phy_probe(struct efx_nic *efx) return -ENOMEM; efx->phy_data = phy_data; phy_data->phy_mode = efx->phy_mode; + phy_data->bug17190_in_bad_state = false; + phy_data->bug17190_timer = 0; efx->mdio.mmds = QT202X_REQUIRED_DEVS; efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; @@ -184,6 +223,9 @@ static bool qt202x_phy_poll(struct efx_nic *efx) efx->link_state.fd = true; efx->link_state.fc = efx->wanted_fc; + if (efx->phy_type == PHY_TYPE_QT2025C) + qt2025c_bug17190_workaround(efx); + return efx->link_state.up != was_up; } -- cgit v0.10.2 From 0d83b2f64c330ee3892cb3117ac5d56e97185ecf Mon Sep 17 00:00:00 2001 From: Matthew Slattery Date: Wed, 23 Dec 2009 13:48:04 +0000 Subject: sfc: QT2025C: Switch into self-configure mode when not in loopback The PHY boots in a mode which is not necessarily optimal. This change switches it to self-configure mode (except when in loopback, which won't work in that mode if an SFP+ module is not present) by rebooting the PHY's microcontroller, and replicating the sequence of configuration writes from the boot EEPROM with the appropriate changes. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index e4590fb..0cd6eed0 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -33,6 +33,9 @@ #define PCS_FW_HEARTBEAT_REG 0xd7ee #define PCS_FW_HEARTB_LBN 0 #define PCS_FW_HEARTB_WIDTH 8 +#define PCS_FW_PRODUCT_CODE_1 0xd7f0 +#define PCS_FW_VERSION_1 0xd7f3 +#define PCS_FW_BUILD_1 0xd7f6 #define PCS_UC8051_STATUS_REG 0xd7fd #define PCS_UC_STATUS_LBN 0 #define PCS_UC_STATUS_WIDTH 8 @@ -54,6 +57,7 @@ struct qt202x_phy_data { enum efx_phy_mode phy_mode; bool bug17190_in_bad_state; unsigned long bug17190_timer; + u32 firmware_ver; }; #define QT2022C2_MAX_RESET_TIME 500 @@ -100,6 +104,25 @@ static int qt2025c_wait_reset(struct efx_nic *efx) return 0; } +static void qt2025c_firmware_id(struct efx_nic *efx) +{ + struct qt202x_phy_data *phy_data = efx->phy_data; + u8 firmware_id[9]; + size_t i; + + for (i = 0; i < sizeof(firmware_id); i++) + firmware_id[i] = efx_mdio_read(efx, MDIO_MMD_PCS, + PCS_FW_PRODUCT_CODE_1 + i); + EFX_INFO(efx, "QT2025C firmware %xr%d v%d.%d.%d.%d [20%02d-%02d-%02d]\n", + (firmware_id[0] << 8) | firmware_id[1], firmware_id[2], + firmware_id[3] >> 4, firmware_id[3] & 0xf, + firmware_id[4], firmware_id[5], + firmware_id[6], firmware_id[7], firmware_id[8]); + phy_data->firmware_ver = ((firmware_id[3] & 0xf0) << 20) | + ((firmware_id[3] & 0x0f) << 16) | + (firmware_id[4] << 8) | firmware_id[5]; +} + static void qt2025c_bug17190_workaround(struct efx_nic *efx) { struct qt202x_phy_data *phy_data = efx->phy_data; @@ -133,6 +156,95 @@ static void qt2025c_bug17190_workaround(struct efx_nic *efx) } } +static int qt2025c_select_phy_mode(struct efx_nic *efx) +{ + struct qt202x_phy_data *phy_data = efx->phy_data; + struct falcon_board *board = falcon_board(efx); + int reg, rc, i; + uint16_t phy_op_mode; + + /* Only 2.0.1.0+ PHY firmware supports the more optimal SFP+ + * Self-Configure mode. Don't attempt any switching if we encounter + * older firmware. */ + if (phy_data->firmware_ver < 0x02000100) + return 0; + + /* In general we will get optimal behaviour in "SFP+ Self-Configure" + * mode; however, that powers down most of the PHY when no module is + * present, so we must use a different mode (any fixed mode will do) + * to be sure that loopbacks will work. */ + phy_op_mode = (efx->loopback_mode == LOOPBACK_NONE) ? 0x0038 : 0x0020; + + /* Only change mode if really necessary */ + reg = efx_mdio_read(efx, 1, 0xc319); + if ((reg & 0x0038) == phy_op_mode) + return 0; + EFX_LOG(efx, "Switching PHY to mode 0x%04x\n", phy_op_mode); + + /* This sequence replicates the register writes configured in the boot + * EEPROM (including the differences between board revisions), except + * that the operating mode is changed, and the PHY is prevented from + * unnecessarily reloading the main firmware image again. */ + efx_mdio_write(efx, 1, 0xc300, 0x0000); + /* (Note: this portion of the boot EEPROM sequence, which bit-bashes 9 + * STOPs onto the firmware/module I2C bus to reset it, varies across + * board revisions, as the bus is connected to different GPIO/LED + * outputs on the PHY.) */ + if (board->major == 0 && board->minor < 2) { + efx_mdio_write(efx, 1, 0xc303, 0x4498); + for (i = 0; i < 9; i++) { + efx_mdio_write(efx, 1, 0xc303, 0x4488); + efx_mdio_write(efx, 1, 0xc303, 0x4480); + efx_mdio_write(efx, 1, 0xc303, 0x4490); + efx_mdio_write(efx, 1, 0xc303, 0x4498); + } + } else { + efx_mdio_write(efx, 1, 0xc303, 0x0920); + efx_mdio_write(efx, 1, 0xd008, 0x0004); + for (i = 0; i < 9; i++) { + efx_mdio_write(efx, 1, 0xc303, 0x0900); + efx_mdio_write(efx, 1, 0xd008, 0x0005); + efx_mdio_write(efx, 1, 0xc303, 0x0920); + efx_mdio_write(efx, 1, 0xd008, 0x0004); + } + efx_mdio_write(efx, 1, 0xc303, 0x4900); + } + efx_mdio_write(efx, 1, 0xc303, 0x4900); + efx_mdio_write(efx, 1, 0xc302, 0x0004); + efx_mdio_write(efx, 1, 0xc316, 0x0013); + efx_mdio_write(efx, 1, 0xc318, 0x0054); + efx_mdio_write(efx, 1, 0xc319, phy_op_mode); + efx_mdio_write(efx, 1, 0xc31a, 0x0098); + efx_mdio_write(efx, 3, 0x0026, 0x0e00); + efx_mdio_write(efx, 3, 0x0027, 0x0013); + efx_mdio_write(efx, 3, 0x0028, 0xa528); + efx_mdio_write(efx, 1, 0xd006, 0x000a); + efx_mdio_write(efx, 1, 0xd007, 0x0009); + efx_mdio_write(efx, 1, 0xd008, 0x0004); + /* This additional write is not present in the boot EEPROM. It + * prevents the PHY's internal boot ROM doing another pointless (and + * slow) reload of the firmware image (the microcontroller's code + * memory is not affected by the microcontroller reset). */ + efx_mdio_write(efx, 1, 0xc317, 0x00ff); + efx_mdio_write(efx, 1, 0xc300, 0x0002); + msleep(20); + + /* Restart microcontroller execution from RAM */ + efx_mdio_write(efx, 3, 0xe854, 0x00c0); + efx_mdio_write(efx, 3, 0xe854, 0x0040); + msleep(50); + + /* Wait for the microcontroller to be ready again */ + rc = qt2025c_wait_reset(efx); + if (rc < 0) { + EFX_ERR(efx, "PHY microcontroller reset during mode switch " + "timed out\n"); + return rc; + } + + return 0; +} + static int qt202x_reset_phy(struct efx_nic *efx) { int rc; @@ -206,6 +318,9 @@ static int qt202x_phy_init(struct efx_nic *efx) devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), efx_mdio_id_rev(devid)); + if (efx->phy_type == PHY_TYPE_QT2025C) + qt2025c_firmware_id(efx); + return 0; } @@ -234,6 +349,10 @@ static int qt202x_phy_reconfigure(struct efx_nic *efx) struct qt202x_phy_data *phy_data = efx->phy_data; if (efx->phy_type == PHY_TYPE_QT2025C) { + int rc = qt2025c_select_phy_mode(efx); + if (rc) + return rc; + /* There are several different register bits which can * disable TX (and save power) on direct-attach cables * or optical transceivers, varying somewhat between -- cgit v0.10.2 From 1a1284ef97ca79ba747d211b697e996a248a8555 Mon Sep 17 00:00:00 2001 From: Matthew Slattery Date: Wed, 23 Dec 2009 13:48:32 +0000 Subject: sfc: QT2025C: Work around PHY firmware initialisation bug The PHY's firmware very occasionally appears to lock up very early, but with the heartbeat update still running. Rebooting the microcontroller core seems to be sufficient to recover. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 0cd6eed0..326ffa4 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -63,11 +63,16 @@ struct qt202x_phy_data { #define QT2022C2_MAX_RESET_TIME 500 #define QT2022C2_RESET_WAIT 10 +#define QT2025C_MAX_HEARTB_TIME (5 * HZ) +#define QT2025C_HEARTB_WAIT 100 +#define QT2025C_MAX_FWSTART_TIME (25 * HZ / 10) +#define QT2025C_FWSTART_WAIT 100 + #define BUG17190_INTERVAL (2 * HZ) -static int qt2025c_wait_reset(struct efx_nic *efx) +static int qt2025c_wait_heartbeat(struct efx_nic *efx) { - unsigned long timeout = jiffies + 10 * HZ; + unsigned long timeout = jiffies + QT2025C_MAX_HEARTB_TIME; int reg, old_counter = 0; /* Wait for firmware heartbeat to start */ @@ -84,9 +89,17 @@ static int qt2025c_wait_reset(struct efx_nic *efx) break; if (time_after(jiffies, timeout)) return -ETIMEDOUT; - msleep(10); + msleep(QT2025C_HEARTB_WAIT); } + return 0; +} + +static int qt2025c_wait_fw_status_good(struct efx_nic *efx) +{ + unsigned long timeout = jiffies + QT2025C_MAX_FWSTART_TIME; + int reg; + /* Wait for firmware status to look good */ for (;;) { reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG); @@ -98,12 +111,44 @@ static int qt2025c_wait_reset(struct efx_nic *efx) break; if (time_after(jiffies, timeout)) return -ETIMEDOUT; - msleep(100); + msleep(QT2025C_FWSTART_WAIT); } return 0; } +static void qt2025c_restart_firmware(struct efx_nic *efx) +{ + /* Restart microcontroller execution of firmware from RAM */ + efx_mdio_write(efx, 3, 0xe854, 0x00c0); + efx_mdio_write(efx, 3, 0xe854, 0x0040); + msleep(50); +} + +static int qt2025c_wait_reset(struct efx_nic *efx) +{ + int rc; + + rc = qt2025c_wait_heartbeat(efx); + if (rc != 0) + return rc; + + rc = qt2025c_wait_fw_status_good(efx); + if (rc == -ETIMEDOUT) { + /* Bug 17689: occasionally heartbeat starts but firmware status + * code never progresses beyond 0x00. Try again, once, after + * restarting execution of the firmware image. */ + EFX_LOG(efx, "bashing QT2025C microcontroller\n"); + qt2025c_restart_firmware(efx); + rc = qt2025c_wait_heartbeat(efx); + if (rc != 0) + return rc; + rc = qt2025c_wait_fw_status_good(efx); + } + + return rc; +} + static void qt2025c_firmware_id(struct efx_nic *efx) { struct qt202x_phy_data *phy_data = efx->phy_data; @@ -229,10 +274,8 @@ static int qt2025c_select_phy_mode(struct efx_nic *efx) efx_mdio_write(efx, 1, 0xc300, 0x0002); msleep(20); - /* Restart microcontroller execution from RAM */ - efx_mdio_write(efx, 3, 0xe854, 0x00c0); - efx_mdio_write(efx, 3, 0xe854, 0x0040); - msleep(50); + /* Restart microcontroller execution of firmware from RAM */ + qt2025c_restart_firmware(efx); /* Wait for the microcontroller to be ready again */ rc = qt2025c_wait_reset(efx); -- cgit v0.10.2 From 50d6ec552bdd4d9227fe9ed2bac819eced3170ac Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 23 Dec 2009 13:48:42 +0000 Subject: sfc: QT2025C: Add error message for suspected bad SFP+ cables Some cables have EEPROMs that conflict with the PHY's on-board EEPROM so it cannot load firmware. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 326ffa4..ff8f0a4 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -87,8 +87,14 @@ static int qt2025c_wait_heartbeat(struct efx_nic *efx) old_counter = counter; else if (counter != old_counter) break; - if (time_after(jiffies, timeout)) + if (time_after(jiffies, timeout)) { + /* Some cables have EEPROMs that conflict with the + * PHY's on-board EEPROM so it cannot load firmware */ + EFX_ERR(efx, "If an SFP+ direct attach cable is" + " connected, please check that it complies" + " with the SFP+ specification\n"); return -ETIMEDOUT; + } msleep(QT2025C_HEARTB_WAIT); } -- cgit v0.10.2 From 286d47ba90315a871f77351f7f61b7e4a96476a9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 23 Dec 2009 13:49:13 +0000 Subject: sfc: Disable TX descriptor prefetch watchdog This hardware watchdog can misfire, so it does more harm than good. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index a577be2..db44224 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1576,6 +1576,8 @@ void efx_nic_init_common(struct efx_nic *efx) EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1); /* Prefetch threshold 2 => fetch when descriptor cache half empty */ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2); + /* Disable hardware watchdog which can misfire */ + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff); /* Squash TX of packets of 16 bytes or less */ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); -- cgit v0.10.2 From d68caec645b4b92f6a81985265b024bc94bce41f Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 23 Dec 2009 13:20:47 +0000 Subject: igb: do not force pcs link when in KX mode We were forcing the PCS link up in error when we are in KX mode. We should only be disabling autoneg, not forcing the link up. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index e8e9e91..c505b50 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -1096,9 +1096,7 @@ static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw) hw_dbg("Configuring Autoneg:PCS_LCTL=0x%08X\n", reg); } else { /* Set PCS register for forced link */ - reg |= E1000_PCS_LCTL_FSD | /* Force Speed */ - E1000_PCS_LCTL_FORCE_LINK | /* Force Link */ - E1000_PCS_LCTL_FLV_LINK_UP; /* Force link value up */ + reg |= E1000_PCS_LCTL_FSD; /* Force Speed */ hw_dbg("Configuring Forced Link:PCS_LCTL=0x%08X\n", reg); } -- cgit v0.10.2 From 8c6af2995c14e71558c312b86955ae32272a03d8 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 23 Dec 2009 13:21:07 +0000 Subject: igb: do not force retry count to 1 on 82580 phy This change resolves an issue seen in some configurations where the link may drop to 100Mb/s even though the link itself supports 1000Mb/s. The issue was root caused to the fact that we were only trying the link once. Now instead we will try up to 5 attempts on a faulty cable before downshifting to 100Mb/s. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c index 5c9d73e..3670a66 100644 --- a/drivers/net/igb/e1000_phy.c +++ b/drivers/net/igb/e1000_phy.c @@ -457,15 +457,6 @@ s32 igb_copper_link_setup_82580(struct e1000_hw *hw) phy_data |= I82580_CFG_ENABLE_DOWNSHIFT; ret_val = phy->ops.write_reg(hw, I82580_CFG_REG, phy_data); - if (ret_val) - goto out; - - /* Set number of link attempts before downshift */ - ret_val = phy->ops.read_reg(hw, I82580_CTRL_REG, &phy_data); - if (ret_val) - goto out; - phy_data &= ~I82580_CTRL_DOWNSHIFT_MASK; - ret_val = phy->ops.write_reg(hw, I82580_CTRL_REG, phy_data); out: return ret_val; -- cgit v0.10.2 From d405ea3ef2499eb46834418a643973c884ff7f30 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 23 Dec 2009 13:21:27 +0000 Subject: igb: correctly offset 82575 flow control watermarks by 16 bytes The watermark values for the 82575 were not being set correctly. As a result the high and low watermark values were set to the same value which can lead to excess xon/xoff packets being generated. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 78963a0..933c64f 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1306,13 +1306,8 @@ void igb_reset(struct igb_adapter *adapter) hwm = min(((pba << 10) * 9 / 10), ((pba << 10) - 2 * adapter->max_frame_size)); - if (mac->type < e1000_82576) { - fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */ - fc->low_water = fc->high_water - 8; - } else { - fc->high_water = hwm & 0xFFF0; /* 16-byte granularity */ - fc->low_water = fc->high_water - 16; - } + fc->high_water = hwm & 0xFFF0; /* 16-byte granularity */ + fc->low_water = fc->high_water - 16; fc->pause_time = 0xFFFF; fc->send_xon = 1; fc->current_mode = fc->requested_mode; -- cgit v0.10.2 From 58b8b042509f53955ba660a4245e221c5405f124 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 23 Dec 2009 13:21:46 +0000 Subject: igb: check both function bits in status register in wol exception The ethtool code for enabling Wake on Lan was not correctly checking the status register bits so as a result ports 0 and 2 were both being allowed to set WOL to enabled even though it is only supported on the first port for our adapters. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index ac9d527..f771a6c 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -1795,7 +1795,7 @@ static int igb_wol_exclusion(struct igb_adapter *adapter, /* dual port cards only support WoL on port A from now on * unless it was enabled in the eeprom for port B * so exclude FUNC_1 ports from having WoL enabled */ - if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1 && + if ((rd32(E1000_STATUS) & E1000_STATUS_FUNC_MASK) && !adapter->eeprom_wol) { wol->supported = 0; break; -- cgit v0.10.2 From 1242b6f31e1d0688f1eb1dc78036dbd975bd6140 Mon Sep 17 00:00:00 2001 From: "Williams, Mitch A" Date: Wed, 23 Dec 2009 13:22:43 +0000 Subject: igbvf: Make igbvf error message more informative Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index e9dd95f..0dbd032 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2763,7 +2763,8 @@ static int __devinit igbvf_probe(struct pci_dev *pdev, err = hw->mac.ops.reset_hw(hw); if (err) { dev_info(&pdev->dev, - "PF still in reset state, assigning new address\n"); + "PF still in reset state, assigning new address." + " Is the PF interface up?\n"); random_ether_addr(hw->mac.addr); } else { err = hw->mac.ops.read_mac_addr(hw); -- cgit v0.10.2 From d7b901418250f00eaaa18f9135d09ba61b72a5bc Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Wed, 23 Dec 2009 04:40:36 +0000 Subject: be2net: Bug fix to avoid soft lockup in loopback test. This change ensures that loopback test command gives up after 4 seconds when the hardware is not responsive. This could happen if the ports are connected properly in loopback mode. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 1b68bd9..a27fdb3 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1501,6 +1501,7 @@ int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req)); + req->hdr.timeout = 4; req->pattern = cpu_to_le64(pattern); req->src_port = cpu_to_le32(port_num); -- cgit v0.10.2 From fced9999ed7f6975fbb2350a73048918ba60a773 Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Wed, 23 Dec 2009 04:41:44 +0000 Subject: be2net: Bug fix to config NIC appropriately before loopback test NIC controller has to be set to an appropriate mode before doing a loopback test. Test will fail otherwise. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index a27fdb3..102ade1 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1479,6 +1479,41 @@ err: return status; } +int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, + u8 loopback_type, u8 enable) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_set_lmode *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_LOWLEVEL_SET_LOOPBACK_MODE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, + OPCODE_LOWLEVEL_SET_LOOPBACK_MODE, + sizeof(*req)); + + req->src_port = port_num; + req->dest_port = port_num; + req->loopback_type = loopback_type; + req->loopback_state = enable; + + status = be_mcc_notify_wait(adapter); +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, u32 loopback_type, u32 pkt_size, u32 num_pkts, u64 pattern) { diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 92b87ef..c002b83 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -155,6 +155,7 @@ struct be_mcc_mailbox { #define OPCODE_LOWLEVEL_HOST_DDR_DMA 17 #define OPCODE_LOWLEVEL_LOOPBACK_TEST 18 +#define OPCODE_LOWLEVEL_SET_LOOPBACK_MODE 19 struct be_cmd_req_hdr { u8 opcode; /* dword 0 */ @@ -821,6 +822,19 @@ struct be_cmd_resp_loopback_test { u32 ticks_compl; }; +struct be_cmd_req_set_lmode { + struct be_cmd_req_hdr hdr; + u8 src_port; + u8 dest_port; + u8 loopback_type; + u8 loopback_state; +}; + +struct be_cmd_resp_set_lmode { + struct be_cmd_resp_hdr resp_hdr; + u8 rsvd0[4]; +}; + /********************** DDR DMA test *********************/ struct be_cmd_req_ddrdma_test { struct be_cmd_req_hdr hdr; @@ -912,3 +926,5 @@ extern int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, u32 num_pkts, u64 pattern); extern int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, u32 byte_cnt, struct be_dma_mem *cmd); +extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, + u8 loopback_type, u8 enable); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 298b92c..da66d15 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -118,6 +118,7 @@ static const char et_self_tests[][ETH_GSTRING_LEN] = { #define BE_MAC_LOOPBACK 0x0 #define BE_PHY_LOOPBACK 0x1 #define BE_ONE_PORT_EXT_LOOPBACK 0x2 +#define BE_NO_LOOPBACK 0xff static void be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) @@ -489,6 +490,19 @@ err: return ret; } +static u64 be_loopback_test(struct be_adapter *adapter, u8 loopback_type, + u64 *status) +{ + be_cmd_set_loopback(adapter, adapter->port_num, + loopback_type, 1); + *status = be_cmd_loopback_test(adapter, adapter->port_num, + loopback_type, 1500, + 2, 0xabc); + be_cmd_set_loopback(adapter, adapter->port_num, + BE_NO_LOOPBACK, 1); + return *status; +} + static void be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) { @@ -497,23 +511,18 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM); if (test->flags & ETH_TEST_FL_OFFLINE) { - data[0] = be_cmd_loopback_test(adapter, adapter->port_num, - BE_MAC_LOOPBACK, 1500, - 2, 0xabc); - if (data[0] != 0) + if (be_loopback_test(adapter, BE_MAC_LOOPBACK, + &data[0]) != 0) { test->flags |= ETH_TEST_FL_FAILED; - - data[1] = be_cmd_loopback_test(adapter, adapter->port_num, - BE_PHY_LOOPBACK, 1500, - 2, 0xabc); - if (data[1] != 0) + } + if (be_loopback_test(adapter, BE_PHY_LOOPBACK, + &data[1]) != 0) { test->flags |= ETH_TEST_FL_FAILED; - - data[2] = be_cmd_loopback_test(adapter, adapter->port_num, - BE_ONE_PORT_EXT_LOOPBACK, - 1500, 2, 0xabc); - if (data[2] != 0) + } + if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK, + &data[2]) != 0) { test->flags |= ETH_TEST_FL_FAILED; + } data[3] = be_test_ddr_dma(adapter); if (data[3] != 0) -- cgit v0.10.2 From 16c02145902d8597841a25e8443cfb082898a2d7 Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Wed, 23 Dec 2009 04:42:51 +0000 Subject: be2net: Bug fix to return correct values in ethtool get_settings. Changes to return correct values for transceiver and supported in ethtool get_settings function. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 9e56014..9fd8e5e 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -275,6 +275,7 @@ struct be_adapter { u32 tx_fc; /* Tx flow control */ int link_speed; u8 port_type; + u8 transceiver; }; extern const struct ethtool_ops be_ethtool_ops; diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index da66d15..5d001c4 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -340,28 +340,50 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) status = be_cmd_read_port_type(adapter, adapter->port_num, &connector); - switch (connector) { - case 7: - ecmd->port = PORT_FIBRE; - break; - default: - ecmd->port = PORT_TP; - break; + if (!status) { + switch (connector) { + case 7: + ecmd->port = PORT_FIBRE; + ecmd->transceiver = XCVR_EXTERNAL; + break; + case 0: + ecmd->port = PORT_TP; + ecmd->transceiver = XCVR_EXTERNAL; + break; + default: + ecmd->port = PORT_TP; + ecmd->transceiver = XCVR_INTERNAL; + break; + } + } else { + ecmd->port = PORT_AUI; + ecmd->transceiver = XCVR_INTERNAL; } /* Save for future use */ adapter->link_speed = ecmd->speed; adapter->port_type = ecmd->port; + adapter->transceiver = ecmd->transceiver; } else { ecmd->speed = adapter->link_speed; ecmd->port = adapter->port_type; + ecmd->transceiver = adapter->transceiver; } ecmd->duplex = DUPLEX_FULL; ecmd->autoneg = AUTONEG_DISABLE; - ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_TP); ecmd->phy_address = adapter->port_num; - ecmd->transceiver = XCVR_INTERNAL; + switch (ecmd->port) { + case PORT_FIBRE: + ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + break; + case PORT_TP: + ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_TP); + break; + case PORT_AUI: + ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_AUI); + break; + } return 0; } -- cgit v0.10.2 From 656ab8172a49d3931e64f866c080260be638c8a9 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 23 Dec 2009 21:19:19 -0800 Subject: ixgbe: fix Need to call pci_save_state after pci_restore_state This patch adds a pci_save_state() call in ixgbe_resume() after pci_restore_state(). A similar change was made in ixgbe_io_slot_reset() that accommodates pci_restore_state() new behavior. This change makes pci_restore_state() clear the saved_state flag This is necessary due to a resent kernel change to pci_restore_state() so that it now clears the saved_state flag of the device right after the device.s standard configuration registers have been poplulated with the previously saved values. Signed-off-by: Don Skidmore Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index bd64387..1a2ea62 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4373,6 +4373,11 @@ static int ixgbe_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); + /* + * pci_restore_state clears dev->state_saved so call + * pci_save_state to restore it. + */ + pci_save_state(pdev); err = pci_enable_device_mem(pdev); if (err) { -- cgit v0.10.2 From c0d7a0212becebe11ffe6979ee3d6f1c4104568d Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Wed, 23 Dec 2009 21:54:29 -0800 Subject: net/via-rhine: Fix scheduling while atomic bugs There are BUGs "scheduling while atomic" triggered by the timer rhine_tx_timeout(). They are caused by calling napi_disable() (with msleep()). This patch fixes it by moving most of the timer content to the workqueue function (similarly to other drivers, like tg3), with spin_lock() changed to BH version. Additionally, there is spin_lock_irq() moved in rhine_close() to exclude napi_disable() etc., also tg3's way. Reported-by: Andrey Rahmatullin Tested-by: Andrey Rahmatullin Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 593e01f..611b804 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -102,6 +102,7 @@ static const int multicast_filter_limit = 32; #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -389,6 +390,7 @@ struct rhine_private { struct net_device *dev; struct napi_struct napi; spinlock_t lock; + struct work_struct reset_task; /* Frequently used values: keep some adjacent for cache effect. */ u32 quirks; @@ -407,6 +409,7 @@ struct rhine_private { static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int rhine_open(struct net_device *dev); +static void rhine_reset_task(struct work_struct *work); static void rhine_tx_timeout(struct net_device *dev); static netdev_tx_t rhine_start_tx(struct sk_buff *skb, struct net_device *dev); @@ -775,6 +778,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, dev->irq = pdev->irq; spin_lock_init(&rp->lock); + INIT_WORK(&rp->reset_task, rhine_reset_task); + rp->mii_if.dev = dev; rp->mii_if.mdio_read = mdio_read; rp->mii_if.mdio_write = mdio_write; @@ -1179,22 +1184,18 @@ static int rhine_open(struct net_device *dev) return 0; } -static void rhine_tx_timeout(struct net_device *dev) +static void rhine_reset_task(struct work_struct *work) { - struct rhine_private *rp = netdev_priv(dev); - void __iomem *ioaddr = rp->base; - - printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " - "%4.4x, resetting...\n", - dev->name, ioread16(ioaddr + IntrStatus), - mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); + struct rhine_private *rp = container_of(work, struct rhine_private, + reset_task); + struct net_device *dev = rp->dev; /* protect against concurrent rx interrupts */ disable_irq(rp->pdev->irq); napi_disable(&rp->napi); - spin_lock(&rp->lock); + spin_lock_bh(&rp->lock); /* clear all descriptors */ free_tbufs(dev); @@ -1206,7 +1207,7 @@ static void rhine_tx_timeout(struct net_device *dev) rhine_chip_reset(dev); init_registers(dev); - spin_unlock(&rp->lock); + spin_unlock_bh(&rp->lock); enable_irq(rp->pdev->irq); dev->trans_start = jiffies; @@ -1214,6 +1215,19 @@ static void rhine_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } +static void rhine_tx_timeout(struct net_device *dev) +{ + struct rhine_private *rp = netdev_priv(dev); + void __iomem *ioaddr = rp->base; + + printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " + "%4.4x, resetting...\n", + dev->name, ioread16(ioaddr + IntrStatus), + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); + + schedule_work(&rp->reset_task); +} + static netdev_tx_t rhine_start_tx(struct sk_buff *skb, struct net_device *dev) { @@ -1830,10 +1844,11 @@ static int rhine_close(struct net_device *dev) struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; - spin_lock_irq(&rp->lock); - - netif_stop_queue(dev); napi_disable(&rp->napi); + cancel_work_sync(&rp->reset_task); + netif_stop_queue(dev); + + spin_lock_irq(&rp->lock); if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, " -- cgit v0.10.2 From f466dba1832f05006cf6caa9be41fb98d11cb848 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Wed, 23 Dec 2009 22:02:57 -0800 Subject: pktgen: ndo_start_xmit can return NET_XMIT_xxx values This updates pktgen so that it does not decrement skb->users when it receives valid NET_XMIT_xxx values. These are now valid return values from ndo_start_xmit in net-next-2.6. They also indicate the skb has been consumed. This fixes pktgen to work correctly with vlan devices. Signed-off-by: John Fastabend Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index a23b45f..de0c2c7 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -250,8 +250,7 @@ struct pktgen_dev { __u64 count; /* Default No packets to send */ __u64 sofar; /* How many pkts we've sent so far */ __u64 tx_bytes; /* How many bytes we've transmitted */ - __u64 errors; /* Errors when trying to transmit, - pkts will be re-sent */ + __u64 errors; /* Errors when trying to transmit, */ /* runtime counters relating to clone_skb */ @@ -3465,6 +3464,12 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->seq_num++; pkt_dev->tx_bytes += pkt_dev->last_pkt_size; break; + case NET_XMIT_DROP: + case NET_XMIT_CN: + case NET_XMIT_POLICED: + /* skb has been consumed */ + pkt_dev->errors++; + break; default: /* Drivers are not supposed to return other values! */ if (net_ratelimit()) pr_info("pktgen: %s xmit error: %d\n", -- cgit v0.10.2 From 4a6e47a460ce55e283063fc3f7391c8ea46bea27 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 25 Dec 2009 17:13:07 -0800 Subject: bnx2x: Initialize cnic status block during chip reset When the device is reset during MTU change, ring size change, or self test, etc, the cnic status block needs to be properly initialized if cnic is registered. Signed-off-by: Michael Chan Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 77ba135..306c2b8 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -7593,6 +7593,8 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD) { bnx2x_set_iscsi_eth_mac_addr(bp, 1); bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET; + bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping, + CNIC_SB_ID(bp)); } mutex_unlock(&bp->cnic_mutex); #endif -- cgit v0.10.2 From 28f6aeea3f12d37bd258b2c0d5ba891bff4ec479 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Fri, 25 Dec 2009 17:30:22 -0800 Subject: net: restore ip source validation when using policy routing and the skb mark: there are cases where a back path validation requires us to use a different routing table for src ip validation than the one used for mapping ingress dst ip. One such a case is transparent proxying where we pretend to be the destination system and therefore the local table is used for incoming packets but possibly a main table would be used on outbound. Make the default behavior to allow the above and if users need to turn on the symmetry via sysctl src_valid_mark Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 699e85c..b230492 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -81,6 +81,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) #define IN_DEV_FORWARD(in_dev) IN_DEV_CONF_GET((in_dev), FORWARDING) #define IN_DEV_MFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), MC_FORWARDING) #define IN_DEV_RPFILTER(in_dev) IN_DEV_MAXCONF((in_dev), RP_FILTER) +#define IN_DEV_SRC_VMARK(in_dev) IN_DEV_ORCONF((in_dev), SRC_VMARK) #define IN_DEV_SOURCE_ROUTE(in_dev) IN_DEV_ANDCONF((in_dev), \ ACCEPT_SOURCE_ROUTE) #define IN_DEV_ACCEPT_LOCAL(in_dev) IN_DEV_ORCONF((in_dev), ACCEPT_LOCAL) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 877ba03..bd27fbc 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -482,6 +482,7 @@ enum NET_IPV4_CONF_ARP_ACCEPT=21, NET_IPV4_CONF_ARP_NOTIFY=22, NET_IPV4_CONF_ACCEPT_LOCAL=23, + NET_IPV4_CONF_SRC_VMARK=24, __NET_IPV4_CONF_MAX }; diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5cdbc10..040c4f0 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1397,6 +1397,7 @@ static struct devinet_sysctl_table { DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE, "accept_source_route"), DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"), + DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"), DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"), DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"), DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"), diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 3323168..82dbf71 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -252,6 +252,8 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, no_addr = in_dev->ifa_list == NULL; rpf = IN_DEV_RPFILTER(in_dev); accept_local = IN_DEV_ACCEPT_LOCAL(in_dev); + if (mark && !IN_DEV_SRC_VMARK(in_dev)) + fl.mark = 0; } rcu_read_unlock(); -- cgit v0.10.2 From b3837ceca005890f1a328eb1a4204a9dc92b1b9f Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Fri, 25 Dec 2009 18:48:33 -0800 Subject: vxge: use DMA_BIT_MASK instead of plain values. Use DMA_BIT_MASK instead of plain values. Signed-off-by: Denis Kirjanov Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index f1c4b2a..0fdfd58 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -4087,21 +4087,21 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) goto _exit0; } - if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) { + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { vxge_debug_ll_config(VXGE_TRACE, "%s : using 64bit DMA", __func__); high_dma = 1; if (pci_set_consistent_dma_mask(pdev, - 0xffffffffffffffffULL)) { + DMA_BIT_MASK(64))) { vxge_debug_init(VXGE_ERR, "%s : unable to obtain 64bit DMA for " "consistent allocations", __func__); ret = -ENOMEM; goto _exit1; } - } else if (!pci_set_dma_mask(pdev, 0xffffffffUL)) { + } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { vxge_debug_ll_config(VXGE_TRACE, "%s : using 32bit DMA", __func__); } else { -- cgit v0.10.2 From 7583605b6d29f1f7f6fc505b883328089f3485ad Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 24 Dec 2009 05:31:03 +0000 Subject: ucc_geth: Fix empty TX queue processing Following oops was seen with the ucc_geth driver: Unable to handle kernel paging request for data at address 0x00000058 Faulting instruction address: 0xc024f2fc Oops: Kernel access of bad area, sig: 11 [#1] [...] NIP [c024f2fc] skb_recycle_check+0x14/0x100 LR [e30aa0a4] ucc_geth_poll+0xd8/0x4e0 [ucc_geth_driver] Call Trace: [df857d50] [c000b03c] __ipipe_grab_irq+0x3c/0xa4 (unreliable) [df857d60] [e30aa0a4] ucc_geth_poll+0xd8/0x4e0 [ucc_geth_driver] [df857dd0] [c0258cf8] net_rx_action+0xf8/0x1b8 [df857e10] [c0032a38] __do_softirq+0xb8/0x13c [df857e60] [c00065cc] do_softirq+0xa0/0xac [...] This is because ucc_geth_tx() tries to process an empty queue when queues are logically stopped. Stopping the queues doesn't disable polling, and since nowadays ucc_geth_tx() is actually called from the polling routine, the oops above might pop up. Fix this by removing 'netif_queue_stopped() == 0' check. Reported-by: Lennart Sorensen Signed-off-by: Anton Vorontsov Tested-by: Lennart Sorensen Cc: Stable [2.6.32] Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index afaf088..0f8c99e 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3273,7 +3273,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) /* Handle the transmitted buffer and release */ /* the BD to be used with the current frame */ - if ((bd == ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0)) + if (bd == ugeth->txBd[txQ]) /* queue empty? */ break; dev->stats.tx_packets++; -- cgit v0.10.2 From 08b5e1c91ce95793c59a59529a362a1bcc81faae Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 24 Dec 2009 05:31:05 +0000 Subject: ucc_geth: Fix netdev watchdog triggering on link changes Since commit 864fdf884e82bacbe8ca5e93bd43393a61d2e2b4 ("ucc_geth: Fix hangs after switching from full to half duplex") ucc_geth driver disables the controller during MAC configuration changes. Though, disabling the controller might take quite awhile, and so the netdev watchdog might get upset: NETDEV WATCHDOG: eth2 (ucc_geth): transmit queue 0 timed out ------------[ cut here ]------------ Badness at c02729a8 [verbose debug info unavailable] NIP: c02729a8 LR: c02729a8 CTR: c01b6088 REGS: c0451c40 TRAP: 0700 Not tainted (2.6.32-trunk-8360e) [...] NIP [c02729a8] dev_watchdog+0x280/0x290 LR [c02729a8] dev_watchdog+0x280/0x290 Call Trace: [c0451cf0] [c02729a8] dev_watchdog+0x280/0x290 (unreliable) [c0451d50] [c00377c4] run_timer_softirq+0x164/0x224 [c0451da0] [c0032a38] __do_softirq+0xb8/0x13c [c0451df0] [c00065cc] do_softirq+0xa0/0xac [c0451e00] [c003280c] irq_exit+0x7c/0x9c [c0451e10] [c00640c4] __ipipe_sync_stage+0x248/0x24c [...] This patch fixes the issue by detaching the netdev during the time we change the configuration. Reported-by: Lennart Sorensen Signed-off-by: Anton Vorontsov Tested-by: Lennart Sorensen Cc: Stable [2.6.32] Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 0f8c99e..7fff4c5 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1563,7 +1563,10 @@ static int ugeth_disable(struct ucc_geth_private *ugeth, enum comm_dir mode) static void ugeth_quiesce(struct ucc_geth_private *ugeth) { - /* Wait for and prevent any further xmits. */ + /* Prevent any further xmits, plus detach the device. */ + netif_device_detach(ugeth->ndev); + + /* Wait for any current xmits to finish. */ netif_tx_disable(ugeth->ndev); /* Disable the interrupt to avoid NAPI rescheduling. */ @@ -1577,7 +1580,7 @@ static void ugeth_activate(struct ucc_geth_private *ugeth) { napi_enable(&ugeth->napi); enable_irq(ugeth->ug_info->uf_info.irq); - netif_tx_wake_all_queues(ugeth->ndev); + netif_device_attach(ugeth->ndev); } /* Called every time the controller might need to be made -- cgit v0.10.2 From 08fafd8461c0ca8d1b389b7dc11d17e7b2331282 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 24 Dec 2009 05:31:20 +0000 Subject: ucc_geth: Don't needlessly change MAC settings in adjust_link() If PHY doesn't have an IRQ, phylib would poll for link changes, and would call adjust_link() every second. In that case we disable and enable the controller every second. Let's better check if there is actually anything changed, and, if so, change the MAC settings. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 7fff4c5..41ad2f3 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1651,25 +1651,28 @@ static void adjust_link(struct net_device *dev) ugeth->oldspeed = phydev->speed; } - /* - * To change the MAC configuration we need to disable the - * controller. To do so, we have to either grab ugeth->lock, - * which is a bad idea since 'graceful stop' commands might - * take quite a while, or we can quiesce driver's activity. - */ - ugeth_quiesce(ugeth); - ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); - - out_be32(&ug_regs->maccfg2, tempval); - out_be32(&uf_regs->upsmr, upsmr); - - ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); - ugeth_activate(ugeth); - if (!ugeth->oldlink) { new_state = 1; ugeth->oldlink = 1; } + + if (new_state) { + /* + * To change the MAC configuration we need to disable + * the controller. To do so, we have to either grab + * ugeth->lock, which is a bad idea since 'graceful + * stop' commands might take quite a while, or we can + * quiesce driver's activity. + */ + ugeth_quiesce(ugeth); + ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); + + out_be32(&ug_regs->maccfg2, tempval); + out_be32(&uf_regs->upsmr, upsmr); + + ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); + ugeth_activate(ugeth); + } } else if (ugeth->oldlink) { new_state = 1; ugeth->oldlink = 0; -- cgit v0.10.2 From 80924e5f7dbe00d964b7249160c7ca25fa3cd889 Mon Sep 17 00:00:00 2001 From: Vitaliy Gusev Date: Fri, 25 Dec 2009 07:17:43 +0000 Subject: tun: use tun_sk instead container_of Using macro tun_sk is more clear and shorter. However tun.c has tun_sk, but doesn't use it. Signed-off-by: Vitaliy Gusev Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 01e99f2..2834a01 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -849,13 +849,13 @@ static void tun_sock_write_space(struct sock *sk) if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible_sync(sk->sk_sleep); - tun = container_of(sk, struct tun_sock, sk)->tun; + tun = tun_sk(sk)->tun; kill_fasync(&tun->fasync, SIGIO, POLL_OUT); } static void tun_sock_destruct(struct sock *sk) { - free_netdev(container_of(sk, struct tun_sock, sk)->tun->dev); + free_netdev(tun_sk(sk)->tun->dev); } static struct proto tun_proto = { @@ -990,7 +990,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) sk->sk_write_space = tun_sock_write_space; sk->sk_sndbuf = INT_MAX; - container_of(sk, struct tun_sock, sk)->tun = tun; + tun_sk(sk)->tun = tun; security_tun_dev_post_create(sk); -- cgit v0.10.2 From f74dac0859bd9678b289ad9dc215026fd7ce033e Mon Sep 17 00:00:00 2001 From: Sandeep Gopalpet Date: Thu, 24 Dec 2009 03:13:06 +0000 Subject: gianfar: Fix gianfar select_queue bogosity The gfar_select_queue() function was used to set queue mapping only for forwarding/bridging applications and the condition for locally generated packets was completely ignored. The solution is to remove the gfar_select_queue() function and use skb_record_rx_queue to set queue mapping for forwarding/bridging applications. This will ensure that in case of forwarding/bridging applications txq = rxq will be selected and skb_tx_hash will be used to pick up a txq for locally generated packets. Signed-off-by: Sandeep Gopalpet Signed-off-by: David S. Miller diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index e0620d0..8bd3c9f 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -143,7 +143,6 @@ void gfar_start(struct net_device *dev); static void gfar_clear_exact_match(struct net_device *dev); static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr); static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -u16 gfar_select_queue(struct net_device *dev, struct sk_buff *skb); MODULE_AUTHOR("Freescale Semiconductor, Inc"); MODULE_DESCRIPTION("Gianfar Ethernet Driver"); @@ -455,7 +454,6 @@ static const struct net_device_ops gfar_netdev_ops = { .ndo_set_multicast_list = gfar_set_multi, .ndo_tx_timeout = gfar_timeout, .ndo_do_ioctl = gfar_ioctl, - .ndo_select_queue = gfar_select_queue, .ndo_get_stats = gfar_get_stats, .ndo_vlan_rx_register = gfar_vlan_rx_register, .ndo_set_mac_address = eth_mac_addr, @@ -506,10 +504,6 @@ static inline int gfar_uses_fcb(struct gfar_private *priv) return priv->vlgrp || priv->rx_csum_enable; } -u16 gfar_select_queue(struct net_device *dev, struct sk_buff *skb) -{ - return skb_get_queue_mapping(skb); -} static void free_tx_pointers(struct gfar_private *priv) { int i = 0; @@ -2470,10 +2464,11 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, fcb = (struct rxfcb *)skb->data; /* Remove the FCB from the skb */ - skb_set_queue_mapping(skb, fcb->rq); /* Remove the padded bytes, if there are any */ - if (amount_pull) + if (amount_pull) { + skb_record_rx_queue(skb, fcb->rq); skb_pull(skb, amount_pull); + } if (priv->rx_csum_enable) gfar_rx_checksum(skb, fcb); @@ -2554,7 +2549,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) /* Remove the FCS from the packet length */ skb_put(skb, pkt_len); rx_queue->stats.rx_bytes += pkt_len; - + skb_record_rx_queue(skb, rx_queue->qindex); gfar_process_frame(dev, skb, amount_pull); } else { -- cgit v0.10.2 From 1f04493123763f5b8bc6d5de9aed0222345c052c Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 24 Dec 2009 08:11:24 +0000 Subject: Fix MAC address access in 3c507, ibmlana, pcnet32 and libertas Commit f001fde5eadd915f4858d22ed70d7040f48767cf changed net_device.dev_addr from a 32-byte array to a pointer. I found 4 ethernet drivers which rely on sizeof(dev_addr), which are now only copying 4 bytes of the address information on 32bit systems. Fix them to use ETH_ALEN. Signed-off-by: Daniel Drake Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index fbc2311..77cf090 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -56,6 +56,7 @@ static const char version[] = #include #include #include +#include #include #include #include @@ -734,8 +735,7 @@ static void init_82586_mem(struct net_device *dev) memcpy_toio(lp->base, init_words + 5, sizeof(init_words) - 10); /* Fill in the station address. */ - memcpy_toio(lp->base+SA_OFFSET, dev->dev_addr, - sizeof(dev->dev_addr)); + memcpy_toio(lp->base+SA_OFFSET, dev->dev_addr, ETH_ALEN); /* The Tx-block list is written as needed. We just set up the values. */ lp->tx_cmd_link = IDLELOOP + 4; diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 090a6d3..052c740 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -87,6 +87,7 @@ History: #include #include #include +#include #include #include @@ -988,7 +989,7 @@ static int __devinit ibmlana_init_one(struct device *kdev) /* copy out MAC address */ - for (z = 0; z < sizeof(dev->dev_addr); z++) + for (z = 0; z < ETH_ALEN; z++) dev->dev_addr[z] = inb(dev->base_addr + MACADDRPROM + z); /* print config */ diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index dcc67a3..e154677 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -45,6 +45,7 @@ static const char *const version = #include #include #include +#include #include #include #include @@ -1765,7 +1766,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ if (!is_valid_ether_addr(dev->perm_addr)) - memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); + memset(dev->dev_addr, 0, ETH_ALEN); if (pcnet32_debug & NETIF_MSG_PROBE) { printk(" %pM", dev->dev_addr); diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 2f91c9b..92b7a35 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -351,8 +352,7 @@ int lbs_add_mesh(struct lbs_private *priv) mesh_dev->netdev_ops = &mesh_netdev_ops; mesh_dev->ethtool_ops = &lbs_ethtool_ops; - memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, - sizeof(priv->dev->dev_addr)); + memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN); SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent); -- cgit v0.10.2 From c99a3d2e04c63a795e13c26d6f2982731e1f1ae0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 23 Dec 2009 03:27:10 +0000 Subject: bond_3ad.c avoid possible null deref A few lines earlier we assume that best->slave could be either null or non-null so we should check it here as well. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 0fb7a49..822f586 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1580,7 +1580,7 @@ static void ad_agg_selection_logic(struct aggregator *agg) // check if any partner replys if (best->is_individual) { pr_warning("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n", - best->slave->dev->master->name); + best->slave ? best->slave->dev->master->name : "NULL"); } best->is_active = 1; -- cgit v0.10.2 From 96c5340147584481ef0c0afbb5423f7563c1d24a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 25 Dec 2009 23:30:02 +0000 Subject: NET: XFRM: Fix spelling of neighbour. Signed-off-by: Ralf Baechle net/xfrm/xfrm_policy.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) Signed-off-by: David S. Miller diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index cb81ca3..4725a54 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1445,7 +1445,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, if (!dev) goto free_dst; - /* Copy neighbout for reachability confirmation */ + /* Copy neighbour for reachability confirmation */ dst0->neighbour = neigh_clone(dst->neighbour); xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len); -- cgit v0.10.2 From 5b0691508aa99d309101a49b4b084dc16b3d7019 Mon Sep 17 00:00:00 2001 From: Andrey Borzenkov Date: Tue, 22 Dec 2009 21:38:44 +0300 Subject: orinoco: fix GFP_KERNEL in orinoco_set_key with interrupts disabled orinoco_set_key is called from two places both with interrupts disabled (under orinoco_lock). Use GFP_ATOMIC instead of GFP_KERNEL. Fixes following warning: [ 77.254109] WARNING: at /home/bor/src/linux-git/kernel/lockdep.c:2465 lockdep_trace_alloc+0x9a/0xa0() [ 77.254109] Hardware name: PORTEGE 4000 [ 77.254109] Modules linked in: af_packet irnet ppp_generic slhc ircomm_tty ircomm binfmt_misc dm_mirror dm_region_hash dm_log dm_round_robin dm_multipath dm_mod loop nvram toshiba cryptomgr aead pcompress crypto_blkcipher michael_mic crypto_hash crypto_algapi orinoco_cs orinoco cfg80211 smsc_ircc2 pcmcia irda toshiba_acpi yenta_socket video i2c_ali1535 backlight rsrc_nonstatic ali_agp pcmcia_core psmouse output crc_ccitt i2c_core alim1535_wdt rfkill sg evdev ohci_hcd agpgart usbcore pata_ali libata reiserfs [last unloaded: scsi_wait_scan] [ 77.254109] Pid: 2296, comm: wpa_supplicant Not tainted 2.6.32-1avb #1 [ 77.254109] Call Trace: [ 77.254109] [] warn_slowpath_common+0x6d/0xa0 [ 77.254109] [] ? lockdep_trace_alloc+0x9a/0xa0 [ 77.254109] [] ? lockdep_trace_alloc+0x9a/0xa0 [ 77.254109] [] warn_slowpath_null+0x15/0x20 [ 77.254109] [] lockdep_trace_alloc+0x9a/0xa0 [ 77.254109] [] __kmalloc+0x36/0x130 [ 77.254109] [] ? orinoco_set_key+0x48/0x1c0 [orinoco] [ 77.254109] [] orinoco_set_key+0x48/0x1c0 [orinoco] [ 77.254109] [] orinoco_ioctl_set_encodeext+0x1dc/0x2d0 [orinoco] [ 77.254109] [] ioctl_standard_call+0x207/0x3b0 [ 77.254109] [] ? orinoco_ioctl_set_encodeext+0x0/0x2d0 [orinoco] [ 77.254109] [] ? rtnl_lock+0xf/0x20 [ 77.254109] [] ? rtnl_lock+0xf/0x20 [ 77.254109] [] ? __dev_get_by_name+0x85/0xb0 [ 77.254109] [] wext_handle_ioctl+0x176/0x200 [ 77.254109] [] ? orinoco_ioctl_set_encodeext+0x0/0x2d0 [orinoco] [ 77.254109] [] dev_ioctl+0x6af/0x730 [ 77.254109] [] ? move_addr_to_kernel+0x55/0x60 [ 77.254109] [] ? sys_sendto+0xe9/0x130 [ 77.254109] [] sock_ioctl+0x7e/0x250 [ 77.254109] [] ? sock_ioctl+0x0/0x250 [ 77.254109] [] vfs_ioctl+0x1c/0x70 [ 77.254109] [] do_vfs_ioctl+0x6a/0x590 [ 77.254109] [] ? might_fault+0x90/0xa0 [ 77.254109] [] ? might_fault+0x4a/0xa0 [ 77.254109] [] ? sys_socketcall+0x17e/0x280 [ 77.254109] [] sys_ioctl+0x39/0x60 [ 77.254109] [] sysenter_do_call+0x12/0x32 [ 77.254109] ---[ end trace 95ef563548d21efd ]--- Signed-off-by: Andrey Borzenkov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 7698fdd..31ca241 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -23,7 +23,7 @@ #define MAX_RID_LEN 1024 /* Helper routine to record keys - * Do not call from interrupt context */ + * It is called under orinoco_lock so it may not sleep */ static int orinoco_set_key(struct orinoco_private *priv, int index, enum orinoco_alg alg, const u8 *key, int key_len, const u8 *seq, int seq_len) @@ -32,14 +32,14 @@ static int orinoco_set_key(struct orinoco_private *priv, int index, kzfree(priv->keys[index].seq); if (key_len) { - priv->keys[index].key = kzalloc(key_len, GFP_KERNEL); + priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC); if (!priv->keys[index].key) goto nomem; } else priv->keys[index].key = NULL; if (seq_len) { - priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL); + priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC); if (!priv->keys[index].seq) goto free_key; } else -- cgit v0.10.2 From 659c8e5243caf14564155ad8421404f044dd8031 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 18 Dec 2009 11:36:49 +0100 Subject: libertas: Remove carrier signaling from the scan code There is no reason to signal a carrier off when doing a 802.11 scan. Cc: Holger Schurig Signed-off-by: Samuel Ortiz Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index c6a6c04..b0b1c78 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -567,11 +567,8 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) chan_count = lbs_scan_create_channel_list(priv, chan_list); netif_stop_queue(priv->dev); - netif_carrier_off(priv->dev); - if (priv->mesh_dev) { + if (priv->mesh_dev) netif_stop_queue(priv->mesh_dev); - netif_carrier_off(priv->mesh_dev); - } /* Prepare to continue an interrupted scan */ lbs_deb_scan("chan_count %d, scan_channel %d\n", @@ -635,16 +632,13 @@ out2: priv->scan_channel = 0; out: - if (priv->connect_status == LBS_CONNECTED) { - netif_carrier_on(priv->dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->dev); - } - if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) { - netif_carrier_on(priv->mesh_dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->mesh_dev); - } + if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len) + netif_wake_queue(priv->dev); + + if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED) && + !priv->tx_pending_len) + netif_wake_queue(priv->mesh_dev); + kfree(chan_list); lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); -- cgit v0.10.2 From 2e10d330f8d5f039fa1e00baf59435ab0f11c722 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 20 Dec 2009 19:07:09 +0100 Subject: mac80211: fix ibss join with fixed-bssid When fixed bssid is requested when joining an ibss network, incoming beacons that match the configured bssid cause mac80211 to create new sta entries, even before the ibss interface is in joined state. When that happens, it fails to bring up the interface entirely, because it checks for existing sta entries before joining. This patch fixes this bug by refusing to create sta info entries before the interface is fully operational. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 10d1385..1f2db64 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -382,6 +382,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, u8 *bssid,u8 *addr, u32 supp_rates) { + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; struct sta_info *sta; int band = local->hw.conf.channel->band; @@ -397,6 +398,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, return NULL; } + if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH) + return NULL; + if (compare_ether_addr(bssid, sdata->u.ibss.bssid)) return NULL; -- cgit v0.10.2 From 242ab7ad689accafd5e87ffd22b85cf1bf7fbbef Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 21 Dec 2009 22:26:48 -0500 Subject: ath5k: fix SWI calibration interrupt storm The calibration period is now invoked by triggering a software interrupt from within the ISR by ath5k_hw_calibration_poll() instead of via a timer. However, the calibration interval isn't initialized before interrupts are enabled, so we can have a situation where an interrupt occurs before the interval is assigned, so the interval is actually negative. As a result, the ISR will arm a software interrupt to schedule the tasklet, and then rearm it when the SWI is processed, and so on, leading to a softlockup at modprobe time. Move the initialization order around so the calibration interval is set before interrupts are active. Another possible fix is to schedule the tasklet directly from the poll routine, but I think there are additional plans for the SWI. Signed-off-by: Bob Copeland Cc: stable@kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index a4c086f..2a446a9 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2381,6 +2381,9 @@ ath5k_init(struct ath5k_softc *sc) */ ath5k_stop_locked(sc); + /* Set PHY calibration interval */ + ah->ah_cal_intval = ath5k_calinterval; + /* * The basic interface to setting the hardware in a good * state is ``reset''. On return the hardware is known to @@ -2408,10 +2411,6 @@ ath5k_init(struct ath5k_softc *sc) /* Set ack to be sent at low bit-rates */ ath5k_hw_set_ack_bitrate_high(ah, false); - - /* Set PHY calibration inteval */ - ah->ah_cal_intval = ath5k_calinterval; - ret = 0; done: mmiowb(); -- cgit v0.10.2 From 5e31258945f60dff65952575625cac214a75893e Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Wed, 23 Dec 2009 00:03:21 +0100 Subject: rt2x00: Add USB ID for Linksys WUSB 600N rev 2. This is a rt2870 based device. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index af85d18..ab95346 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -922,6 +922,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Logitec */ { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, -- cgit v0.10.2 From 671adc93b6472eaa0142a88d096c945f7b07893a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:12:04 +0100 Subject: wireless: remove remaining qual code This removes the remaining users of the rx status 'qual' field and the field itself. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 2a446a9..e63b7c4 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1903,17 +1903,6 @@ accept: rxs->noise = sc->ah->ah_noise_floor; rxs->signal = rxs->noise + rs.rs_rssi; - /* An rssi of 35 indicates you should be able use - * 54 Mbps reliably. A more elaborate scheme can be used - * here but it requires a map of SNR/throughput for each - * possible mode used */ - rxs->qual = rs.rs_rssi * 100 / 35; - - /* rssi can be more than 35 though, anything above that - * should be considered at 100% */ - if (rxs->qual > 100) - rxs->qual = 100; - rxs->antenna = rs.rs_antenna; rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e413bd3..234891d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -681,19 +681,13 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, snr = rx_stats_sig_avg / rx_stats_noise_diff; rx_status.noise = rx_status.signal - iwl3945_calc_db_from_ratio(snr); - rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, - rx_status.noise); - - /* If noise info not available, calculate signal quality indicator (%) - * using just the dBm signal level. */ } else { rx_status.noise = priv->last_rx_noise; - rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0); } - IWL_DEBUG_STATS(priv, "Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", - rx_status.signal, rx_status.noise, rx_status.qual, + IWL_DEBUG_STATS(priv, "Rssi %d noise %d sig_avg %d noise_diff %d\n", + rx_status.signal, rx_status.noise, rx_stats_sig_avg, rx_stats_noise_diff); header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index ecc23ec..531fa12 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -222,7 +222,6 @@ struct iwl3945_ibss_seq { * *****************************************************************************/ extern int iwl3945_calc_db_from_ratio(int sig_ratio); -extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm); extern void iwl3945_rx_replenish(void *data); extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index f5c87e7..6f36b6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -650,47 +650,6 @@ void iwl_reply_statistics(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_reply_statistics); -#define PERFECT_RSSI (-20) /* dBm */ -#define WORST_RSSI (-95) /* dBm */ -#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) - -/* Calculate an indication of rx signal quality (a percentage, not dBm!). - * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info - * about formulas used below. */ -static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) -{ - int sig_qual; - int degradation = PERFECT_RSSI - rssi_dbm; - - /* If we get a noise measurement, use signal-to-noise ratio (SNR) - * as indicator; formula is (signal dbm - noise dbm). - * SNR at or above 40 is a great signal (100%). - * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. - * Weakest usable signal is usually 10 - 15 dB SNR. */ - if (noise_dbm) { - if (rssi_dbm - noise_dbm >= 40) - return 100; - else if (rssi_dbm < noise_dbm) - return 0; - sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; - - /* Else use just the signal level. - * This formula is a least squares fit of data points collected and - * compared with a reference system that had a percentage (%) display - * for signal quality. */ - } else - sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * - (15 * RSSI_RANGE + 62 * degradation)) / - (RSSI_RANGE * RSSI_RANGE); - - if (sig_qual > 100) - sig_qual = 100; - else if (sig_qual < 1) - sig_qual = 0; - - return sig_qual; -} - /* Calc max signal level (dBm) among 3 possible receivers */ static inline int iwl_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp) @@ -1101,11 +1060,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (iwl_is_associated(priv) && !test_bit(STATUS_SCANNING, &priv->status)) { rx_status.noise = priv->last_rx_noise; - rx_status.qual = iwl_calc_sig_qual(rx_status.signal, - rx_status.noise); } else { rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - rx_status.qual = iwl_calc_sig_qual(rx_status.signal, 0); } /* Reset beacon noise level if not associated. */ @@ -1118,8 +1074,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, iwl_dbg_report_frame(priv, phy_res, len, header, 1); #endif iwl_dbg_log_rx_data_frame(priv, len, header); - IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", - rx_status.signal, rx_status.noise, rx_status.qual, + IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, TSF %llu\n", + rx_status.signal, rx_status.noise, (unsigned long long)rx_status.mactime); /* diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e5d8fa3..f8e4e4b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1299,47 +1299,6 @@ int iwl3945_calc_db_from_ratio(int sig_ratio) return (int)ratio2dB[sig_ratio]; } -#define PERFECT_RSSI (-20) /* dBm */ -#define WORST_RSSI (-95) /* dBm */ -#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) - -/* Calculate an indication of rx signal quality (a percentage, not dBm!). - * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info - * about formulas used below. */ -int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm) -{ - int sig_qual; - int degradation = PERFECT_RSSI - rssi_dbm; - - /* If we get a noise measurement, use signal-to-noise ratio (SNR) - * as indicator; formula is (signal dbm - noise dbm). - * SNR at or above 40 is a great signal (100%). - * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. - * Weakest usable signal is usually 10 - 15 dB SNR. */ - if (noise_dbm) { - if (rssi_dbm - noise_dbm >= 40) - return 100; - else if (rssi_dbm < noise_dbm) - return 0; - sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; - - /* Else use just the signal level. - * This formula is a least squares fit of data points collected and - * compared with a reference system that had a percentage (%) display - * for signal quality. */ - } else - sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * - (15 * RSSI_RANGE + 62 * degradation)) / - (RSSI_RANGE * RSSI_RANGE); - - if (sig_qual > 100) - sig_qual = 100; - else if (sig_qual < 1) - sig_qual = 0; - - return sig_qual; -} - /** * iwl3945_rx_handle - Main entry function for receiving responses from uCode * diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 019431d..26a1abd 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -495,7 +495,6 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) stats.band = IEEE80211_BAND_2GHZ; stats.signal = prxpd->snr; stats.noise = prxpd->nf; - stats.qual = prxpd->snr - prxpd->nf; /* Marvell rate index has a hole at value 4 */ if (prxpd->rx_rate > 4) --prxpd->rx_rate; diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index a1a3dd1..8a40a14 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -132,7 +132,6 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.antenna = (flags2 >> 15) & 1; /* TODO: improve signal/rssi reporting */ - rx_status.qual = flags2 & 0xFF; rx_status.signal = (flags2 >> 8) & 0x7F; /* XXX: is this correct? */ rx_status.rate_idx = (flags >> 20) & 0xF; diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index dfa1b9bc..7ca95c4 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -1325,151 +1325,11 @@ int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) return r; } -static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size) -{ - static const u16 constants[] = { - 715, 655, 585, 540, 470, 410, 360, 315, - 270, 235, 205, 175, 150, 125, 105, 85, - 65, 50, 40, 25, 15 - }; - - int i; - u32 x; - - /* It seems that their quality parameter is somehow per signal - * and is now transferred per bit. - */ - switch (zd_rate) { - case ZD_OFDM_RATE_6M: - case ZD_OFDM_RATE_12M: - case ZD_OFDM_RATE_24M: - size *= 2; - break; - case ZD_OFDM_RATE_9M: - case ZD_OFDM_RATE_18M: - case ZD_OFDM_RATE_36M: - case ZD_OFDM_RATE_54M: - size *= 4; - size /= 3; - break; - case ZD_OFDM_RATE_48M: - size *= 3; - size /= 2; - break; - default: - return -EINVAL; - } - - x = (10000 * status_quality)/size; - for (i = 0; i < ARRAY_SIZE(constants); i++) { - if (x > constants[i]) - break; - } - - switch (zd_rate) { - case ZD_OFDM_RATE_6M: - case ZD_OFDM_RATE_9M: - i += 3; - break; - case ZD_OFDM_RATE_12M: - case ZD_OFDM_RATE_18M: - i += 5; - break; - case ZD_OFDM_RATE_24M: - case ZD_OFDM_RATE_36M: - i += 9; - break; - case ZD_OFDM_RATE_48M: - case ZD_OFDM_RATE_54M: - i += 15; - break; - default: - return -EINVAL; - } - - return i; -} - -static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size) -{ - int r; - - r = ofdm_qual_db(status_quality, zd_rate, size); - ZD_ASSERT(r >= 0); - if (r < 0) - r = 0; - - r = (r * 100)/29; - return r <= 100 ? r : 100; -} - -static unsigned int log10times100(unsigned int x) -{ - static const u8 log10[] = { - 0, - 0, 30, 47, 60, 69, 77, 84, 90, 95, 100, - 104, 107, 111, 114, 117, 120, 123, 125, 127, 130, - 132, 134, 136, 138, 139, 141, 143, 144, 146, 147, - 149, 150, 151, 153, 154, 155, 156, 157, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, 169, 169, - 170, 171, 172, 173, 174, 174, 175, 176, 177, 177, - 178, 179, 179, 180, 181, 181, 182, 183, 183, 184, - 185, 185, 186, 186, 187, 188, 188, 189, 189, 190, - 190, 191, 191, 192, 192, 193, 193, 194, 194, 195, - 195, 196, 196, 197, 197, 198, 198, 199, 199, 200, - 200, 200, 201, 201, 202, 202, 202, 203, 203, 204, - 204, 204, 205, 205, 206, 206, 206, 207, 207, 207, - 208, 208, 208, 209, 209, 210, 210, 210, 211, 211, - 211, 212, 212, 212, 213, 213, 213, 213, 214, 214, - 214, 215, 215, 215, 216, 216, 216, 217, 217, 217, - 217, 218, 218, 218, 219, 219, 219, 219, 220, 220, - 220, 220, 221, 221, 221, 222, 222, 222, 222, 223, - 223, 223, 223, 224, 224, 224, 224, - }; - - return x < ARRAY_SIZE(log10) ? log10[x] : 225; -} - -enum { - MAX_CCK_EVM_DB = 45, -}; - -static int cck_evm_db(u8 status_quality) -{ - return (20 * log10times100(status_quality)) / 100; -} - -static int cck_snr_db(u8 status_quality) -{ - int r = MAX_CCK_EVM_DB - cck_evm_db(status_quality); - ZD_ASSERT(r >= 0); - return r; -} - -static int cck_qual_percent(u8 status_quality) -{ - int r; - - r = cck_snr_db(status_quality); - r = (100*r)/17; - return r <= 100 ? r : 100; -} - static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame) { return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame); } -u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, - const struct rx_status *status) -{ - return (status->frame_status&ZD_RX_OFDM) ? - ofdm_qual_percent(status->signal_quality_ofdm, - zd_rate_from_ofdm_plcp_header(rx_frame), - size) : - cck_qual_percent(status->signal_quality_cck); -} - /** * zd_rx_rate - report zd-rate * @rx_frame - received frame diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 9fd8f35..f8bbf7d 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -929,9 +929,6 @@ static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval) struct rx_status; -u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, - const struct rx_status *status); - u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status); struct zd_mc_hash { diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 8a24373..cc648ef 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -828,9 +828,6 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; stats.band = IEEE80211_BAND_2GHZ; stats.signal = status->signal_strength; - stats.qual = zd_rx_qual_percent(buffer, - length - sizeof(struct rx_status), - status); rate = zd_rx_rate(buffer, status); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 538d6b7..0bf3697 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -547,7 +547,6 @@ enum mac80211_rx_flags { * unspecified depending on the hardware capabilities flags * @IEEE80211_HW_SIGNAL_* * @noise: noise when receiving this frame, in dBm. - * @qual: overall signal quality indication, in percent (0-100). * @antenna: antenna used * @rate_idx: index of data rate into band's supported rates or MCS index if * HT rates are use (RX_FLAG_HT) @@ -559,7 +558,6 @@ struct ieee80211_rx_status { int freq; int signal; int noise; - int __deprecated qual; int antenna; int rate_idx; int flag; -- cgit v0.10.2 From 3bdb2d48c5f58c781a4099c99044384a23620884 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:12:05 +0100 Subject: cfg80211: fix race between deauth and assoc response Joseph Nahmias reported, in http://bugs.debian.org/562016, that he was getting the following warning (with some log around the issue): ath0: direct probe to AP 00:11:95:77:e0:b0 (try 1) ath0: direct probe responded ath0: authenticate with AP 00:11:95:77:e0:b0 (try 1) ath0: authenticated ath0: associate with AP 00:11:95:77:e0:b0 (try 1) ath0: deauthenticating from 00:11:95:77:e0:b0 by local choice (reason=3) ath0: direct probe to AP 00:11:95:77:e0:b0 (try 1) ath0: RX AssocResp from 00:11:95:77:e0:b0 (capab=0x421 status=0 aid=2) ath0: associated ------------[ cut here ]------------ WARNING: at net/wireless/mlme.c:97 cfg80211_send_rx_assoc+0x14d/0x152 [cfg80211]() Hardware name: 7658CTO ... Pid: 761, comm: phy0 Not tainted 2.6.32-trunk-686 #1 Call Trace: [] ? warn_slowpath_common+0x5e/0x8a [] ? warn_slowpath_null+0xa/0xc [] ? cfg80211_send_rx_assoc+0x14d/0x152 ... ath0: link becomes ready ath0: deauthenticating from 00:11:95:77:e0:b0 by local choice (reason=3) ath0: no IPv6 routers present ath0: link is not ready ath0: direct probe to AP 00:11:95:77:e0:b0 (try 1) ath0: direct probe responded ath0: authenticate with AP 00:11:95:77:e0:b0 (try 1) ath0: authenticated ath0: associate with AP 00:11:95:77:e0:b0 (try 1) ath0: RX ReassocResp from 00:11:95:77:e0:b0 (capab=0x421 status=0 aid=2) ath0: associated It is not clear to me how the first "direct probe" here happens, but this seems to be a race condition, if the user requests to deauth after requesting assoc, but before the assoc response is received. In that case, it may happen that mac80211 tries to report the assoc success to cfg80211, but gets blocked on the wdev lock that is held because the user is requesting the deauth. The result is that we run into a warning. This is mostly harmless, but maybe cause an unexpected event to be sent to userspace; we'd send an assoc success event although userspace was no longer expecting that. To fix this, remove the warning and check whether the race happened and in that case abort processing. Reported-by: Joseph Nahmias Cc: stable@kernel.org Cc: 562016-quiet@bugs.debian.org Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 1001db4..82e6002 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -93,7 +93,18 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) } } - WARN_ON(!bss); + /* + * We might be coming here because the driver reported + * a successful association at the same time as the + * user requested a deauth. In that case, we will have + * removed the BSS from the auth_bsses list due to the + * deauth request when the assoc response makes it. If + * the two code paths acquire the lock the other way + * around, that's just the standard situation of a + * deauth being requested while connected. + */ + if (!bss) + goto out; } else if (wdev->conn) { cfg80211_sme_failed_assoc(wdev); /* -- cgit v0.10.2 From 83bd11a06da8bd119cc517de84b3214df3a7a6d4 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 23 Dec 2009 14:04:43 +0100 Subject: ath9k: Storage class should be before const qualifier The C99 specification states in section 6.11.5: The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature. Signed-off-by: Tobias Klauser Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 5321f73..f7af5ea 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -96,7 +96,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common) pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); } -const static struct ath_bus_ops ath_pci_bus_ops = { +static const struct ath_bus_ops ath_pci_bus_ops = { .read_cachesize = ath_pci_read_cachesize, .cleanup = ath_pci_cleanup, .eeprom_read = ath_pci_eeprom_read, -- cgit v0.10.2 From 79496738eb896d1658d9f3cca98e474c5f31eea3 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 23 Dec 2009 14:18:11 +0100 Subject: iwlwifi: Storage class should be before const qualifier The C99 specification states in section 6.11.5: The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature. Signed-off-by: Tobias Klauser Acked-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index fe511cb..b93e491 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -150,7 +150,7 @@ static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { }; /* mbps, mcs */ -const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { +static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { { "1", "BPSK DSSS"}, { "2", "QPSK DSSS"}, {"5.5", "BPSK CCK"}, -- cgit v0.10.2 From befabac2d8e4925b97c5eebc78ecc4b2079fd9dd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 23 Dec 2009 15:23:19 +0200 Subject: wl1271_cmd.c: cleanup char => u8 This is just a clean up and doesn't make a functional difference. It keeps the lint checkers happy. Signed-off-by: Dan Carpenter Reviewed-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 886a9bc..c3385b3 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -777,7 +777,7 @@ out: return ret; } -static int wl1271_build_basic_rates(char *rates, u8 band) +static int wl1271_build_basic_rates(u8 *rates, u8 band) { u8 index = 0; @@ -804,7 +804,7 @@ static int wl1271_build_basic_rates(char *rates, u8 band) return index; } -static int wl1271_build_extended_rates(char *rates, u8 band) +static int wl1271_build_extended_rates(u8 *rates, u8 band) { u8 index = 0; -- cgit v0.10.2 From 65486c8b30498dd274eea2c542696f22b63fe5b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 15:33:35 +0100 Subject: cfg80211: fix error path in cfg80211_wext_siwscan If there's an invalid channel or SSID, the code leaks the scan request. Always free the scan request, unless it was successfully given to the driver. Reported-by: Dan Carpenter Signed-off-by: Johannes Berg Acked-by: Dan Carpenter Signed-off-by: John W. Linville diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 12dfa62..0c2cbbe 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -601,7 +601,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, struct cfg80211_registered_device *rdev; struct wiphy *wiphy; struct iw_scan_req *wreq = NULL; - struct cfg80211_scan_request *creq; + struct cfg80211_scan_request *creq = NULL; int i, err, n_channels = 0; enum ieee80211_band band; @@ -694,8 +694,10 @@ int cfg80211_wext_siwscan(struct net_device *dev, /* translate "Scan for SSID" request */ if (wreq) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { - if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; + if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) { + err = -EINVAL; + goto out; + } memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len); creq->ssids[0].ssid_len = wreq->essid_len; } @@ -707,12 +709,15 @@ int cfg80211_wext_siwscan(struct net_device *dev, err = rdev->ops->scan(wiphy, dev, creq); if (err) { rdev->scan_req = NULL; - kfree(creq); + /* creq will be freed below */ } else { nl80211_send_scan_start(rdev, dev); + /* creq now owned by driver */ + creq = NULL; dev_hold(dev); } out: + kfree(creq); cfg80211_unlock_rdev(rdev); return err; } -- cgit v0.10.2 From 3867cf6a8c699846e928e8f5a9f31013708df192 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 23 Dec 2009 20:03:27 -0500 Subject: ath9k: fix suspend by waking device prior to stop Ensure the device is awake prior to trying to tell hardware to stop it. Impact of not doing this is we can likely leave the device in an undefined state likely causing issues with suspend and resume. This patch ensures harware is where it should be prior to suspend. Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9e68c1a..2ec7451 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2514,6 +2514,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) return; /* another wiphy still in use */ } + /* Ensure HW is awake when we try to shut it down. */ + ath9k_ps_wakeup(sc); + if (ah->btcoex_hw.enabled) { ath9k_hw_btcoex_disable(ah); if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) @@ -2534,6 +2537,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* disable HAL and put h/w to sleep */ ath9k_hw_disable(ah); ath9k_hw_configpcipowersave(ah, 1, 1); + ath9k_ps_restore(sc); + + /* Finally, put the chip in FULL SLEEP mode */ ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); sc->sc_flags |= SC_OP_INVALID; -- cgit v0.10.2 From 5f70a88f631c3480107853cae12925185eb4c598 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 23 Dec 2009 20:03:28 -0500 Subject: ath9k: wake hardware for interface IBSS/AP/Mesh removal When we remove a IBSS/AP/Mesh interface we stop DMA but to do this we should ensure hardware is on. Awaken the device prior to these calls. This should ensure DMA is stopped upon suspend and plain device removal. Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2ec7451..623ade8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2653,8 +2653,10 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { + ath9k_ps_wakeup(sc); ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); ath_beacon_return(sc, avp); + ath9k_ps_restore(sc); } sc->sc_flags &= ~SC_OP_BEACONS; -- cgit v0.10.2 From 8b685ba9de803f210936400612a32a2003f47cd3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 23 Dec 2009 20:03:29 -0500 Subject: ath9k: wake hardware during AMPDU TX actions AMDPDU actions poke hardware for TX operation, as such we want to turn hardware on for these actions. AMDPU RX operations do not require hardware on as nothing is done in hardware for those actions. Without this we cannot guarantee hardware has been programmed correctly for each AMPDU TX action. Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 623ade8..996eb90 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -3105,15 +3105,21 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: + ath9k_ps_wakeup(sc); ath_tx_aggr_start(sc, sta, tid, ssn); ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_STOP: + ath9k_ps_wakeup(sc); ath_tx_aggr_stop(sc, sta, tid); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_OPERATIONAL: + ath9k_ps_wakeup(sc); ath_tx_aggr_resume(sc, sta, tid); + ath9k_ps_restore(sc); break; default: ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, -- cgit v0.10.2 From 5b479a076de091590423a9e6dfc2584126b28761 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 24 Dec 2009 14:04:32 +0100 Subject: ath9k: fix missed error codes in the tx status check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My previous change added in: commit 815833e7ecf0b9a017315cae6aef4d7cd9517681 ath9k: fix tx status reporting was not checking all possible tx error conditions. This could possibly lead to throughput issues due to slow rate control adaption or missed retransmissions of failed A-MPDU frames. This patch adds a mask for all possible error conditions and uses it in the xmit ok check. Cc: stable@kernel.org Reported-by: Björn Smedman Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 0c87771..e185479 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -77,6 +77,9 @@ #define ATH9K_TXERR_XTXOP 0x08 #define ATH9K_TXERR_TIMER_EXPIRED 0x10 #define ATH9K_TX_ACKED 0x20 +#define ATH9K_TXERR_MASK \ + (ATH9K_TXERR_XRETRY | ATH9K_TXERR_FILT | ATH9K_TXERR_FIFO | \ + ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED) #define ATH9K_TX_BA 0x01 #define ATH9K_TX_PWRMGMT 0x02 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 1e813bb..fa12b90 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2072,7 +2072,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) &txq->axq_q, lastbf->list.prev); txq->axq_depth--; - txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_FILT); + txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_MASK); txq->axq_tx_inprogress = false; spin_unlock_bh(&txq->axq_lock); -- cgit v0.10.2 From b98c06b6debfe84c90200143bb1102f312f50a33 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 24 Dec 2009 15:26:09 -0500 Subject: mac80211: fix race with suspend and dynamic_ps_disable_work When mac80211 suspends it calls a driver's suspend callback as a last step and after that the driver assumes no calls will be made to it until we resume and its start callback is kicked. If such calls are made, however, suspend can end up throwing hardware in an unexpected state and making the device unusable upon resume. Fix this by preventing mac80211 to schedule dynamic_ps_disable_work by checking for when mac80211 starts to suspend and starts quiescing. Frames should be allowed to go through though as that is part of the quiescing steps and we do not flush the mac80211 workqueue since it was already done towards the beginning of suspend cycle. The other mac80211 issue will be hanled in the next patch. For further details see refer to the thread: http://marc.info/?t=126144866100001&r=1&w=2 Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8834cc9..27ceaef 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1419,6 +1419,10 @@ static bool need_dynamic_ps(struct ieee80211_local *local) if (!local->ps_sdata) return false; + /* No point if we're going to suspend */ + if (local->quiescing) + return false; + return true; } -- cgit v0.10.2 From 24feda0084722189468a65e20019cdd8ef99702b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 24 Dec 2009 15:38:22 -0500 Subject: mac80211: fix propagation of failed hardware reconfigurations mac80211 does not propagate failed hardware reconfiguration requests. For suspend and resume this is important due to all the possible issues that can come out of the suspend <-> resume cycle. Not propagating the error means cfg80211 will assume the resume for the device went through fine and mac80211 will continue on trying to poke at the hardware, enable timers, queue work, and so on for a device which is completley unfunctional. The least we can do is to propagate device start issues and warn when this occurs upon resume. A side effect of this patch is we also now propagate the start errors upon harware reconfigurations (non-suspend), but this should also be desirable anyway, there is not point in continuing to reconfigure a device if mac80211 was unable to start the device. For further details refer to the thread: http://marc.info/?t=126151038700001&r=1&w=2 Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 78a6e92..dc76267 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1039,7 +1039,19 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* restart hardware */ if (local->open_count) { + /* + * Upon resume hardware can sometimes be goofy due to + * various platform / driver / bus issues, so restarting + * the device may at times not work immediately. Propagate + * the error. + */ res = drv_start(local); + if (res) { + WARN(local->suspended, "Harware became unavailable " + "upon resume. This is could be a software issue" + "prior to suspend or a harware issue\n"); + return res; + } ieee80211_led_radio(local, true); } -- cgit v0.10.2 From e8a4a6df7397eb3b43ad3139d3fe9b41df70d6b0 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sat, 26 Dec 2009 20:31:59 +0100 Subject: wl1251: timeout one too soon in wl1251_boot_run_firmware() `loop' reaches INIT_LOOP + 1 after the loop. so if ACX_INTR_INIT_COMPLETE occurs in the last iteration the write occurs but also the error out as if a timeout occurred. This is probably very unlikely to ever occur. Signed-off-by: Roel Kluin Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 2e733e7..28a8086 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -256,7 +256,7 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) } } - if (loop >= INIT_LOOP) { + if (loop > INIT_LOOP) { wl1251_error("timeout waiting for the hardware to " "complete initialization"); return -EIO; -- cgit v0.10.2 From 6c853da3f30c93eae847ecbcd9fdf10ba0da04c2 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 28 Dec 2009 14:23:11 +0800 Subject: iwmc3200wifi: fix array out-of-boundary access Allocate priv->rx_packets[IWM_RX_ID_HASH + 1] because the max array index is IWM_RX_ID_HASH according to IWM_RX_ID_GET_HASH(). Cc: stable@kernel.org Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 79ffa3b..8428111 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -268,7 +268,7 @@ struct iwm_priv { struct sk_buff_head rx_list; struct list_head rx_tickets; - struct list_head rx_packets[IWM_RX_ID_HASH]; + struct list_head rx_packets[IWM_RX_ID_HASH + 1]; struct workqueue_struct *rx_wq; struct work_struct rx_worker; -- cgit v0.10.2 From 55afc80b2ab100618c17af77915f75307b6bd5d1 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 29 Dec 2009 14:07:42 -0500 Subject: Revert "b43: Enforce DMA descriptor memory constraints" This reverts commit 9bd568a50c446433038dec2a5186c5c57c3dbd23. That commit is shown to cause allocation failures during initialization on some machines. http://bugzilla.kernel.org/show_bug.cgi?id=14844 Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 027be27..88d1fd0 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -383,160 +383,44 @@ static inline } } -/* Check if a DMA region fits the device constraints. - * Returns true, if the region is OK for usage with this device. */ -static inline bool b43_dma_address_ok(struct b43_dmaring *ring, - dma_addr_t addr, size_t size) -{ - switch (ring->type) { - case B43_DMA_30BIT: - if ((u64)addr + size > (1ULL << 30)) - return 0; - break; - case B43_DMA_32BIT: - if ((u64)addr + size > (1ULL << 32)) - return 0; - break; - case B43_DMA_64BIT: - /* Currently we can't have addresses beyond - * 64bit in the kernel. */ - break; - } - return 1; -} - -#define is_4k_aligned(addr) (((u64)(addr) & 0x0FFFull) == 0) -#define is_8k_aligned(addr) (((u64)(addr) & 0x1FFFull) == 0) - -static void b43_unmap_and_free_ringmem(struct b43_dmaring *ring, void *base, - dma_addr_t dmaaddr, size_t size) -{ - ssb_dma_unmap_single(ring->dev->dev, dmaaddr, size, DMA_TO_DEVICE); - free_pages((unsigned long)base, get_order(size)); -} - -static void * __b43_get_and_map_ringmem(struct b43_dmaring *ring, - dma_addr_t *dmaaddr, size_t size, - gfp_t gfp_flags) -{ - void *base; - - base = (void *)__get_free_pages(gfp_flags, get_order(size)); - if (!base) - return NULL; - memset(base, 0, size); - *dmaaddr = ssb_dma_map_single(ring->dev->dev, base, size, - DMA_TO_DEVICE); - if (ssb_dma_mapping_error(ring->dev->dev, *dmaaddr)) { - free_pages((unsigned long)base, get_order(size)); - return NULL; - } - - return base; -} - -static void * b43_get_and_map_ringmem(struct b43_dmaring *ring, - dma_addr_t *dmaaddr, size_t size) -{ - void *base; - - base = __b43_get_and_map_ringmem(ring, dmaaddr, size, - GFP_KERNEL); - if (!base) { - b43err(ring->dev->wl, "Failed to allocate or map pages " - "for DMA ringmemory\n"); - return NULL; - } - if (!b43_dma_address_ok(ring, *dmaaddr, size)) { - /* The memory does not fit our device constraints. - * Retry with GFP_DMA set to get lower memory. */ - b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size); - base = __b43_get_and_map_ringmem(ring, dmaaddr, size, - GFP_KERNEL | GFP_DMA); - if (!base) { - b43err(ring->dev->wl, "Failed to allocate or map pages " - "in the GFP_DMA region for DMA ringmemory\n"); - return NULL; - } - if (!b43_dma_address_ok(ring, *dmaaddr, size)) { - b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size); - b43err(ring->dev->wl, "Failed to allocate DMA " - "ringmemory that fits device constraints\n"); - return NULL; - } - } - /* We expect the memory to be 4k aligned, at least. */ - if (B43_WARN_ON(!is_4k_aligned(*dmaaddr))) { - b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size); - return NULL; - } - - return base; -} - static int alloc_ringmemory(struct b43_dmaring *ring) { - unsigned int required; - void *base; - dma_addr_t dmaaddr; - - /* There are several requirements to the descriptor ring memory: - * - The memory region needs to fit the address constraints for the - * device (same as for frame buffers). - * - For 30/32bit DMA devices, the descriptor ring must be 4k aligned. - * - For 64bit DMA devices, the descriptor ring must be 8k aligned. + gfp_t flags = GFP_KERNEL; + + /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K + * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing + * has shown that 4K is sufficient for the latter as long as the buffer + * does not cross an 8K boundary. + * + * For unknown reasons - possibly a hardware error - the BCM4311 rev + * 02, which uses 64-bit DMA, needs the ring buffer in very low memory, + * which accounts for the GFP_DMA flag below. + * + * The flags here must match the flags in free_ringmemory below! */ - if (ring->type == B43_DMA_64BIT) - required = ring->nr_slots * sizeof(struct b43_dmadesc64); - else - required = ring->nr_slots * sizeof(struct b43_dmadesc32); - if (B43_WARN_ON(required > 0x1000)) + flags |= GFP_DMA; + ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev, + B43_DMA_RINGMEMSIZE, + &(ring->dmabase), flags); + if (!ring->descbase) { + b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); return -ENOMEM; - - ring->alloc_descsize = 0x1000; - base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize); - if (!base) - return -ENOMEM; - ring->alloc_descbase = base; - ring->alloc_dmabase = dmaaddr; - - if ((ring->type != B43_DMA_64BIT) || is_8k_aligned(dmaaddr)) { - /* We're on <=32bit DMA, or we already got 8k aligned memory. - * That's all we need, so we're fine. */ - ring->descbase = base; - ring->dmabase = dmaaddr; - return 0; - } - b43_unmap_and_free_ringmem(ring, base, dmaaddr, ring->alloc_descsize); - - /* Ok, we failed at the 8k alignment requirement. - * Try to force-align the memory region now. */ - ring->alloc_descsize = 0x2000; - base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize); - if (!base) - return -ENOMEM; - ring->alloc_descbase = base; - ring->alloc_dmabase = dmaaddr; - - if (is_8k_aligned(dmaaddr)) { - /* We're already 8k aligned. That Ok, too. */ - ring->descbase = base; - ring->dmabase = dmaaddr; - return 0; } - /* Force-align it to 8k */ - ring->descbase = (void *)((u8 *)base + 0x1000); - ring->dmabase = dmaaddr + 0x1000; - B43_WARN_ON(!is_8k_aligned(ring->dmabase)); + memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE); return 0; } static void free_ringmemory(struct b43_dmaring *ring) { - b43_unmap_and_free_ringmem(ring, ring->alloc_descbase, - ring->alloc_dmabase, ring->alloc_descsize); + gfp_t flags = GFP_KERNEL; + + if (ring->type == B43_DMA_64BIT) + flags |= GFP_DMA; + + ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE, + ring->descbase, ring->dmabase, flags); } /* Reset the RX DMA channel */ @@ -646,14 +530,29 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr))) return 1; - if (!b43_dma_address_ok(ring, addr, buffersize)) { - /* We can't support this address. Unmap it again. */ - unmap_descbuffer(ring, addr, buffersize, dma_to_device); - return 1; + switch (ring->type) { + case B43_DMA_30BIT: + if ((u64)addr + buffersize > (1ULL << 30)) + goto address_error; + break; + case B43_DMA_32BIT: + if ((u64)addr + buffersize > (1ULL << 32)) + goto address_error; + break; + case B43_DMA_64BIT: + /* Currently we can't have addresses beyond + * 64bit in the kernel. */ + break; } /* The address is OK. */ return 0; + +address_error: + /* We can't support this address. Unmap it again. */ + unmap_descbuffer(ring, addr, buffersize, dma_to_device); + + return 1; } static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb) @@ -715,9 +614,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, meta->dmaaddr = dmaaddr; ring->ops->fill_descriptor(ring, desc, dmaaddr, ring->rx_buffersize, 0, 0, 0); - ssb_dma_sync_single_for_device(ring->dev->dev, - ring->alloc_dmabase, - ring->alloc_descsize, DMA_TO_DEVICE); return 0; } @@ -1354,9 +1250,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring, } /* Now transfer the whole frame. */ wmb(); - ssb_dma_sync_single_for_device(ring->dev->dev, - ring->alloc_dmabase, - ring->alloc_descsize, DMA_TO_DEVICE); ops->poke_tx(ring, next_slot(ring, slot)); return 0; diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index e607b39..f7ab37c 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -157,6 +157,7 @@ struct b43_dmadesc_generic { } __attribute__ ((__packed__)); /* Misc DMA constants */ +#define B43_DMA_RINGMEMSIZE PAGE_SIZE #define B43_DMA0_RX_FRAMEOFFSET 30 /* DMA engine tuning knobs */ @@ -246,12 +247,6 @@ struct b43_dmaring { /* The QOS priority assigned to this ring. Only used for TX rings. * This is the mac80211 "queue" value. */ u8 queue_prio; - /* Pointers and size of the originally allocated and mapped memory - * region for the descriptor ring. */ - void *alloc_descbase; - dma_addr_t alloc_dmabase; - unsigned int alloc_descsize; - /* Pointer to our wireless device. */ struct b43_wldev *dev; #ifdef CONFIG_B43_DEBUG /* Maximum number of used slots. */ -- cgit v0.10.2