From cf04317227d0c53d931a0b963e7ac6f7f0125e8a Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Mon, 30 Apr 2012 11:43:07 -0700 Subject: brcmfmac: fix a double spin_unlock_irqrestore issue in dpc dpc_tl_lock is not acquired in the error handle code for bus down. But it's unlocked using spin_unlock_irqrestore after finishing task list walk down. Grab the lock before breaking the loop to avoid a double unlock. Reported-by: Dan Carpenter Signed-off-by: Franky Lin Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index eb3829b03cd3..e2b34e1563f4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2637,6 +2637,7 @@ static int brcmf_sdbrcm_dpc_thread(void *data) /* after stopping the bus, exit thread */ brcmf_sdbrcm_bus_stop(bus->sdiodev->dev); bus->dpc_tsk = NULL; + spin_lock_irqsave(&bus->dpc_tl_lock, flags); break; } -- cgit v1.2.3 From 9d1ceac5c6f7e77ea914de376ec17ced3eb22e5f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 1 May 2012 09:12:24 +0530 Subject: Revert "ath9k_hw: Fix incorrect spur_freq_sd for AR9003" This reverts commit a844adfd7bee4edc66d337de6c33b348e83552a8. The commit a844adfd is degrading rx sensitivity of lower rate in HT40 mode and it is confirmed that reverting the change is improving rx sensitivity. spur_freq_sd (for self-corr in AGC) is defined with respect to the center of each 20MHz channel while spur_phase_delta (for self-corr in Rx and spur data filter) is defined with respect to the center of current RF channel. So in short, we need to subtract spur_freq_sd (for self-corr in AGC) by the offset between the center of primary20 and the center of RF channel in SW. This offset could be +/10 MHz for dynamic 40. Cc: Madhan Jaganathan Signed-off-by: Kai Shi Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index deb6cfb2959a..600aca9fe6b1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -373,7 +373,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah, else spur_subchannel_sd = 0; - spur_freq_sd = (freq_offset << 9) / 11; + spur_freq_sd = ((freq_offset + 10) << 9) / 11; } else { if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, @@ -382,7 +382,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah, else spur_subchannel_sd = 1; - spur_freq_sd = (freq_offset << 9) / 11; + spur_freq_sd = ((freq_offset - 10) << 9) / 11; } -- cgit v1.2.3 From ab6039a70bb559b2fb5f363934da67d864ccda2a Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Sat, 17 Mar 2012 05:51:52 +0000 Subject: ixgbe: fix race condition with shutdown It was possible for shutdown to pull the rug out from other driver entry points. Now we just grab the rtnl lock before taking everything apart. Thanks to Hariharan for noticing this tight race condition. Signed-off-by: Don Skidmore Cc: Hariharan Nagarajan Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 88f6b2e9b72d..d9dbf871abb8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -4866,10 +4866,12 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) netif_device_detach(netdev); if (netif_running(netdev)) { + rtnl_lock(); ixgbe_down(adapter); ixgbe_free_irq(adapter); ixgbe_free_all_tx_resources(adapter); ixgbe_free_all_rx_resources(adapter); + rtnl_unlock(); } ixgbe_clear_interrupt_scheme(adapter); -- cgit v1.2.3 From f525c6d29501eb483f2d6f742d2f1dc0452b924d Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Wed, 18 Apr 2012 22:42:27 +0000 Subject: ixgbe: dcb: BIT_APP_UPCHG not set by ixgbe_copy_dcb_cfg() After this commit: commit aacc1bea190d731755a65cb8ec31dd756f4e263e Author: Multanen, Eric W Date: Wed Mar 28 07:49:09 2012 +0000 ixgbe: driver fix for link flap The BIT_APP_UPCHG bit is no longer set when ixgbe_dcbnl_set_all() is called. This results in the FCoE app user priority never getting set and the driver will not configure the tx_rings correctly for FCoE packets which use the SAN MTU and FCoE offloads. We resolve this regression by fixing ixgbe_copy_dcb_cfg() to also check for FCoE application changes. Additionally, we can drop the IEEE variants of get_dcb_app() because this path is never called with the IEEE mode enabled. Signed-off-by: John Fastabend Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 3 -- drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c | 43 ++++++++++++------------- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 +-- 3 files changed, 22 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 74e192107f9a..81b155589532 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -574,9 +574,6 @@ extern struct ixgbe_info ixgbe_82599_info; extern struct ixgbe_info ixgbe_X540_info; #ifdef CONFIG_IXGBE_DCB extern const struct dcbnl_rtnl_ops dcbnl_ops; -extern int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, - struct ixgbe_dcb_config *dst_dcb_cfg, - int tc_max); #endif extern char ixgbe_driver_name[]; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c index 652e4b09546d..32e5c02ff6d0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c @@ -44,18 +44,26 @@ #define DCB_NO_HW_CHG 1 /* DCB configuration did not change */ #define DCB_HW_CHG 2 /* DCB configuration changed, no reset */ -int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *scfg, - struct ixgbe_dcb_config *dcfg, int tc_max) +static int ixgbe_copy_dcb_cfg(struct ixgbe_adapter *adapter, int tc_max) { + struct ixgbe_dcb_config *scfg = &adapter->temp_dcb_cfg; + struct ixgbe_dcb_config *dcfg = &adapter->dcb_cfg; struct tc_configuration *src = NULL; struct tc_configuration *dst = NULL; int i, j; int tx = DCB_TX_CONFIG; int rx = DCB_RX_CONFIG; int changes = 0; +#ifdef IXGBE_FCOE + struct dcb_app app = { + .selector = DCB_APP_IDTYPE_ETHTYPE, + .protocol = ETH_P_FCOE, + }; + u8 up = dcb_getapp(adapter->netdev, &app); - if (!scfg || !dcfg) - return changes; + if (up && !(up & (1 << adapter->fcoe.up))) + changes |= BIT_APP_UPCHG; +#endif for (i = DCB_PG_ATTR_TC_0; i < tc_max + DCB_PG_ATTR_TC_0; i++) { src = &scfg->tc_config[i - DCB_PG_ATTR_TC_0]; @@ -332,28 +340,12 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) struct ixgbe_adapter *adapter = netdev_priv(netdev); int ret = DCB_NO_HW_CHG; int i; -#ifdef IXGBE_FCOE - struct dcb_app app = { - .selector = DCB_APP_IDTYPE_ETHTYPE, - .protocol = ETH_P_FCOE, - }; - u8 up; - - /* In IEEE mode, use the IEEE Ethertype selector value */ - if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) { - app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE; - up = dcb_ieee_getapp_mask(netdev, &app); - } else { - up = dcb_getapp(netdev, &app); - } -#endif /* Fail command if not in CEE mode */ if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) return ret; - adapter->dcb_set_bitmap |= ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, - &adapter->dcb_cfg, + adapter->dcb_set_bitmap |= ixgbe_copy_dcb_cfg(adapter, MAX_TRAFFIC_CLASS); if (!adapter->dcb_set_bitmap) return ret; @@ -440,8 +432,13 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) * FCoE is using changes. This happens if the APP info * changes or the up2tc mapping is updated. */ - if ((up && !(up & (1 << adapter->fcoe.up))) || - (adapter->dcb_set_bitmap & BIT_APP_UPCHG)) { + if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { + struct dcb_app app = { + .selector = DCB_APP_IDTYPE_ETHTYPE, + .protocol = ETH_P_FCOE, + }; + u8 up = dcb_getapp(netdev, &app); + adapter->fcoe.up = ffs(up) - 1; ixgbe_dcbnl_devreset(netdev); ret = DCB_HW_CHG_RST; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index d9dbf871abb8..50f0700d250d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -4418,8 +4418,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->dcb_cfg.pfc_mode_enable = false; adapter->dcb_set_bitmap = 0x00; adapter->dcbx_cap = DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_CEE; - ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg, - MAX_TRAFFIC_CLASS); + memcpy(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, + sizeof(adapter->temp_dcb_cfg)); #endif -- cgit v1.2.3 From ed90542b0ce5415050c6fbfca324bccaafa69f2f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 24 Mar 2012 00:29:46 -0400 Subject: iwlwifi: fix skb truesize underestimation By default, iwlwifi uses order-1 pages (8 KB) to store incoming frames, but doesnt say so in skb->truesize. This makes very possible to exhaust kernel memory since these skb evade normal socket memory accounting. As struct ieee80211_hdr is going to be pulled before calling IP stack, there is no need to use dev_alloc_skb() to reserve NET_SKB_PAD bytes. alloc_skb() is ok in this driver, allowing more tailroom. Pull beginning of frame in skb header, in the hope we can reuse order-1 pages in the driver immediately for small frames and reduce their truesize to the minimum (linear skbs) Signed-off-by: Eric Dumazet Cc: Wey-Yi Guy Cc: "John W. Linville" Cc: Neal Cardwell Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rx.c | 21 ++++++++++++++------- drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-trans.h | 1 + 3 files changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index f4b84d1596e3..22474608a70b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -773,8 +773,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, struct sk_buff *skb; __le16 fc = hdr->frame_control; struct iwl_rxon_context *ctx; - struct page *p; - int offset; + unsigned int hdrlen, fraglen; /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { @@ -788,16 +787,24 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; - skb = dev_alloc_skb(128); + /* Dont use dev_alloc_skb(), we'll have enough headroom once + * ieee80211_hdr pulled. + */ + skb = alloc_skb(128, GFP_ATOMIC); if (!skb) { - IWL_ERR(priv, "dev_alloc_skb failed\n"); + IWL_ERR(priv, "alloc_skb failed\n"); return; } + hdrlen = min_t(unsigned int, len, skb_tailroom(skb)); + memcpy(skb_put(skb, hdrlen), hdr, hdrlen); + fraglen = len - hdrlen; - offset = (void *)hdr - rxb_addr(rxb); - p = rxb_steal_page(rxb); - skb_add_rx_frag(skb, 0, p, offset, len, len); + if (fraglen) { + int offset = (void *)hdr + hdrlen - rxb_addr(rxb); + skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, + fraglen, rxb->truesize); + } iwl_update_stats(priv, false, fc, len); /* diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index 8b1a7988e176..aa7aea168138 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -374,8 +374,9 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, if (WARN_ON(!rxb)) return; + rxcb.truesize = PAGE_SIZE << hw_params(trans).rx_page_order; dma_unmap_page(trans->dev, rxb->page_dma, - PAGE_SIZE << hw_params(trans).rx_page_order, + rxcb.truesize, DMA_FROM_DEVICE); rxcb._page = rxb->page; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 0c81cbaa8088..fdf97886a5e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -260,6 +260,7 @@ static inline void iwl_free_resp(struct iwl_host_cmd *cmd) struct iwl_rx_cmd_buffer { struct page *_page; + unsigned int truesize; }; static inline void *rxb_addr(struct iwl_rx_cmd_buffer *r) -- cgit v1.2.3 From dad8a3b3eaa0c2ca25368a0b9f65edca84e27a40 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Mon, 23 Apr 2012 12:22:39 +0000 Subject: igb, ixgbe: netdev_tx_reset_queue incorrectly called from tx init path igb and ixgbe incorrectly call netdev_tx_reset_queue() from i{gb|xgbe}_clean_tx_ring() this sort of works in most cases except when the number of real tx queues changes. When the number of real tx queues changes netdev_tx_reset_queue() only gets called on the new number of queues so when we reduce the number of queues we risk triggering the watchdog timer and repeated device resets. So this is not only a cosmetic issue but causes real bugs. For example enabling/disabling DCB or FCoE in ixgbe will trigger this. CC: Alexander Duyck Signed-off-by: John Fastabend Tested-by: John Bishop Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 4 ++-- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 2 ++ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 5ec31598ee47..d22350055285 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2771,8 +2771,6 @@ void igb_configure_tx_ring(struct igb_adapter *adapter, txdctl |= E1000_TXDCTL_QUEUE_ENABLE; wr32(E1000_TXDCTL(reg_idx), txdctl); - - netdev_tx_reset_queue(txring_txq(ring)); } /** @@ -3282,6 +3280,8 @@ static void igb_clean_tx_ring(struct igb_ring *tx_ring) igb_unmap_and_free_tx_resource(tx_ring, buffer_info); } + netdev_tx_reset_queue(txring_txq(tx_ring)); + size = sizeof(struct igb_tx_buffer) * tx_ring->count; memset(tx_ring->tx_buffer_info, 0, size); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 31a2bf76a346..cfe7d269590c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -1780,6 +1780,8 @@ static u16 ixgbe_clean_test_rings(struct ixgbe_ring *rx_ring, rx_desc = IXGBE_RX_DESC(rx_ring, rx_ntc); } + netdev_tx_reset_queue(txring_txq(tx_ring)); + /* re-map buffers to ring, store next to clean values */ ixgbe_alloc_rx_buffers(rx_ring, count); rx_ring->next_to_clean = rx_ntc; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 50f0700d250d..467948e9ecd9 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -2671,8 +2671,6 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, /* enable queue */ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl); - netdev_tx_reset_queue(txring_txq(ring)); - /* TXDCTL.EN will return 0 on 82598 if link is down, so skip it */ if (hw->mac.type == ixgbe_mac_82598EB && !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP)) @@ -4167,6 +4165,8 @@ static void ixgbe_clean_tx_ring(struct ixgbe_ring *tx_ring) ixgbe_unmap_and_free_tx_resource(tx_ring, tx_buffer_info); } + netdev_tx_reset_queue(txring_txq(tx_ring)); + size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count; memset(tx_ring->tx_buffer_info, 0, size); -- cgit v1.2.3 From dd7f5c9e5cb24f72140206d3e5961b4cc5a84034 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Sun, 25 Mar 2012 17:49:25 +0000 Subject: e1000: Silence sparse warnings by correcting type Silence sparse warnings shown below: ... drivers/net/ethernet/intel/e1000/e1000_main.c:3435:17: warning: cast to restricted __le64 drivers/net/ethernet/intel/e1000/e1000_main.c:3435:17: warning: cast to restricted __le64 ... Signed-off-by: Andrei Emeltchenko Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000/e1000_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 4348b6fd44fa..37caa8885c2a 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -3380,7 +3380,7 @@ static void e1000_dump(struct e1000_adapter *adapter) for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) { struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i); struct e1000_buffer *buffer_info = &tx_ring->buffer_info[i]; - struct my_u { u64 a; u64 b; }; + struct my_u { __le64 a; __le64 b; }; struct my_u *u = (struct my_u *)tx_desc; const char *type; @@ -3424,7 +3424,7 @@ rx_ring_summary: for (i = 0; rx_ring->desc && (i < rx_ring->count); i++) { struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i); struct e1000_buffer *buffer_info = &rx_ring->buffer_info[i]; - struct my_u { u64 a; u64 b; }; + struct my_u { __le64 a; __le64 b; }; struct my_u *u = (struct my_u *)rx_desc; const char *type; -- cgit v1.2.3 From 24f06716cd5dbfc3d737ec2a24ac58ef76f68dc7 Mon Sep 17 00:00:00 2001 From: Ariel Elior Date: Sun, 6 May 2012 07:05:57 +0000 Subject: bnx2x: bug fix when loading after SAN boot This is a bug fix for an "interface fails to load" issue. The issue occurs when bnx2x driver loads after UNDI driver was previously loaded over the chip. In such a scenario the UNDI driver is loaded and operates in the pre-boot kernel, within its own specific host memory address range. When the pre-boot stage is complete, the real kernel is loaded, in a new and distinct host memory address range. The transition from pre-boot stage to boot is asynchronous from UNDI point of view. A race condition occurs when UNDI driver triggers a DMAE transaction to valid host addresses in the pre-boot stage, when control is diverted to the real kernel. This results in access to illegal addresses by our HW as the addresses which were valid in the preboot stage are no longer considered valid. Specifically, the 'was_error' bit in the pci glue of our device is set. This causes all following pci transactions from chip to host to timeout (in accordance to the pci spec). Signed-off-by: Ariel Elior Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index e077d2508727..6af310195bae 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9122,13 +9122,34 @@ static int __devinit bnx2x_prev_unload_common(struct bnx2x *bp) return bnx2x_prev_mcp_done(bp); } +/* previous driver DMAE transaction may have occurred when pre-boot stage ended + * and boot began, or when kdump kernel was loaded. Either case would invalidate + * the addresses of the transaction, resulting in was-error bit set in the pci + * causing all hw-to-host pcie transactions to timeout. If this happened we want + * to clear the interrupt which detected this from the pglueb and the was done + * bit + */ +static void __devinit bnx2x_prev_interrupted_dmae(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) { + BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing"); + REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, 1 << BP_FUNC(bp)); + } +} + static int __devinit bnx2x_prev_unload(struct bnx2x *bp) { int time_counter = 10; u32 rc, fw, hw_lock_reg, hw_lock_val; BNX2X_DEV_INFO("Entering Previous Unload Flow\n"); - /* Release previously held locks */ + /* clear hw from errors which may have resulted from an interrupted + * dmae transaction. + */ + bnx2x_prev_interrupted_dmae(bp); + + /* Release previously held locks */ hw_lock_reg = (BP_FUNC(bp) <= 5) ? (MISC_REG_DRIVER_CONTROL_1 + BP_FUNC(bp) * 8) : (MISC_REG_DRIVER_CONTROL_7 + (BP_FUNC(bp) - 6) * 8); -- cgit v1.2.3 From 6eddcb4c82883451aec3be1240f17793370fa62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 26 Apr 2012 02:35:10 +0000 Subject: cdc_ether: Ignore bogus union descriptor for RNDIS devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some RNDIS devices include a bogus CDC Union descriptor pointing to non-existing interfaces. The RNDIS code is already prepared to handle devices without a CDC Union descriptor by hardwiring the driver to use interfaces 0 and 1, which is correct for the devices with the bogus descriptor as well. So we can reuse the existing workaround. Cc: Markus Kolb Cc: Iker Salmón San Millán Cc: Jonathan Nieder Cc: Oliver Neukum Cc: 655387@bugs.debian.org Cc: stable@vger.kernel.org Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ether.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 90a30026a931..00880edba048 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -83,6 +83,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) struct cdc_state *info = (void *) &dev->data; int status; int rndis; + bool android_rndis_quirk = false; struct usb_driver *driver = driver_of(intf); struct usb_cdc_mdlm_desc *desc = NULL; struct usb_cdc_mdlm_detail_desc *detail = NULL; @@ -195,6 +196,11 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) info->control, info->u->bSlaveInterface0, info->data); + /* fall back to hard-wiring for RNDIS */ + if (rndis) { + android_rndis_quirk = true; + goto next_desc; + } goto bad_desc; } if (info->control != intf) { @@ -271,11 +277,15 @@ next_desc: /* Microsoft ActiveSync based and some regular RNDIS devices lack the * CDC descriptors, so we'll hard-wire the interfaces and not check * for descriptors. + * + * Some Android RNDIS devices have a CDC Union descriptor pointing + * to non-existing interfaces. Ignore that and attempt the same + * hard-wired 0 and 1 interfaces. */ - if (rndis && !info->u) { + if (rndis && (!info->u || android_rndis_quirk)) { info->control = usb_ifnum_to_if(dev->udev, 0); info->data = usb_ifnum_to_if(dev->udev, 1); - if (!info->control || !info->data) { + if (!info->control || !info->data || info->control != intf) { dev_dbg(&intf->dev, "rndis: master #0/%p slave #1/%p\n", info->control, -- cgit v1.2.3 From 3132d2827d92c2ee47fdf4dbec75bba0a2f291cb Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 5 May 2012 02:31:23 +0100 Subject: sfc: Fix division by zero when using one RX channel and no SR-IOV If RSS is disabled on the PF (efx->n_rx_channels == 1) we try to set up the indirection table so that VFs can use it, setting efx->rss_spread = efx_vf_size(efx). But if SR-IOV was disabled at compile time, this evaluates to 0 and we end up dividing by zero when initialising the table. I considered changing the fallback definition of efx_vf_size() to return 1, but its value is really meaningless if we are not going to enable VFs. Therefore add a condition of efx_sriov_wanted(efx) in efx_probe_interrupts(). Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/efx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 3cbfbffe3f00..4a0005342e65 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1349,7 +1349,7 @@ static int efx_probe_interrupts(struct efx_nic *efx) } /* RSS might be usable on VFs even if it is disabled on the PF */ - efx->rss_spread = (efx->n_rx_channels > 1 ? + efx->rss_spread = ((efx->n_rx_channels > 1 || !efx_sriov_wanted(efx)) ? efx->n_rx_channels : efx_vf_size(efx)); return 0; -- cgit v1.2.3 From 477206a018f902895bfcd069dd820bfe94c187b1 Mon Sep 17 00:00:00 2001 From: Julien Ducourthial Date: Wed, 9 May 2012 00:00:06 +0200 Subject: r8169: fix unsigned int wraparound with TSO The r8169 may get stuck or show bad behaviour after activating TSO : the net_device is not stopped when it has no more TX descriptors. This problem comes from TX_BUFS_AVAIL which may reach -1 when all transmit descriptors are in use. The patch simply tries to keep positive values. Tested with 8111d(onboard) on a D510MO, and with 8111e(onboard) on a Zotac 890GXITX. Signed-off-by: Julien Ducourthial Acked-by: Francois Romieu Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index f54509377efa..ce6b44d1f252 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -61,8 +61,12 @@ #define R8169_MSG_DEFAULT \ (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN) -#define TX_BUFFS_AVAIL(tp) \ - (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1) +#define TX_SLOTS_AVAIL(tp) \ + (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx) + +/* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */ +#define TX_FRAGS_READY_FOR(tp,nr_frags) \ + (TX_SLOTS_AVAIL(tp) >= (nr_frags + 1)) /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ @@ -5115,7 +5119,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, u32 opts[2]; int frags; - if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) { + if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) { netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n"); goto err_stop_0; } @@ -5169,7 +5173,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, mmiowb(); - if (TX_BUFFS_AVAIL(tp) < MAX_SKB_FRAGS) { + if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) { /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must * not miss a ring update when it notices a stopped queue. */ @@ -5183,7 +5187,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, * can't. */ smp_mb(); - if (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS) + if (TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) netif_wake_queue(dev); } @@ -5306,7 +5310,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) */ smp_mb(); if (netif_queue_stopped(dev) && - (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)) { + TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) { netif_wake_queue(dev); } /* -- cgit v1.2.3 From cfb8c3aa59302636c69890be10b2ef23a7ca83b2 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Thu, 10 May 2012 15:38:37 +0000 Subject: igb: fix rtnl race in PM resume path Since the caller (PM resume code) is not the one holding rtnl, when taking the 'else' branch rtnl may be released at any moment, thereby defeating the whole purpose of this code block. Signed-off-by: Benjamin Poirier Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igb/igb_main.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index d22350055285..8683ca4748c8 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1111,9 +1111,12 @@ msi_only: adapter->flags |= IGB_FLAG_HAS_MSI; out: /* Notify the stack of the (possibly) reduced queue counts. */ + rtnl_lock(); netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues); - return netif_set_real_num_rx_queues(adapter->netdev, - adapter->num_rx_queues); + err = netif_set_real_num_rx_queues(adapter->netdev, + adapter->num_rx_queues); + rtnl_unlock(); + return err; } /** @@ -6796,18 +6799,7 @@ static int igb_resume(struct device *dev) pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); - if (!rtnl_is_locked()) { - /* - * shut up ASSERT_RTNL() warning in - * netif_set_real_num_tx/rx_queues. - */ - rtnl_lock(); - err = igb_init_interrupt_scheme(adapter); - rtnl_unlock(); - } else { - err = igb_init_interrupt_scheme(adapter); - } - if (err) { + if (igb_init_interrupt_scheme(adapter)) { dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); return -ENOMEM; } -- cgit v1.2.3 From 380ec964bc19f865af70c0339dff1cb75dc4f8f2 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Thu, 10 May 2012 04:00:53 +0000 Subject: ehea: fix losing of NEQ events when one event occurred early The NEQ interrupt is only triggered when there was no previous pending interrupt. If we request irq handling after an interrupt has occurred, we will never get an interrupt until we call H_RESET_EVENTS. Events seem to be cleared when we first register the NEQ. So, when we requested irq handling right after registering it, a possible race with an interrupt was much less likely. Now, there is a chance we may lose this race and never get any events. The fix here is to poll and acknowledge any events that might have happened right after registering the irq handler. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ehea/ehea_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index c9069a28832b..f4d2da0db1b1 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -3335,6 +3335,8 @@ static int __devinit ehea_probe_adapter(struct platform_device *dev, goto out_shutdown_ports; } + /* Handle any events that might be pending. */ + tasklet_hi_schedule(&adapter->neq_tasklet); ret = 0; goto out; -- cgit v1.2.3 From 59b9997baba5242997ddc7bd96b1391f5275a5a4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 10 May 2012 23:03:34 -0400 Subject: Revert "net: maintain namespace isolation between vlan and real device" This reverts commit 8a83a00b0735190384a348156837918271034144. It causes regressions for S390 devices, because it does an unconditional DST drop on SKBs for vlans and the QETH device needs the neighbour entry hung off the DST for certain things on transmit. Arnd can't remember exactly why he even needed this change. Conflicts: drivers/net/macvlan.c net/8021q/vlan_dev.c net/core/dev.c Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index f975afdc315c..025367a94add 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -259,7 +259,7 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) xmit_world: skb->ip_summed = ip_summed; - skb_set_dev(skb, vlan->lowerdev); + skb->dev = vlan->lowerdev; return dev_queue_xmit(skb); } -- cgit v1.2.3 From 13a8e0c8cdb43982372bd6c65fb26839c8fd8ce9 Mon Sep 17 00:00:00 2001 From: Jiri Bohac Date: Wed, 9 May 2012 01:01:40 +0000 Subject: bonding: don't increase rx_dropped after processing LACPDUs Since commit 3aba891d, bonding processes LACP frames (802.3ad mode) with bond_handle_frame(). Currently a copy of the skb is made and the original is left to be processed by other rx_handlers and the rest of the network stack by returning RX_HANDLER_ANOTHER. As there is no protocol handler for PKT_TYPE_LACPDU, the frame is dropped and dev->rx_dropped increased. Fix this by making bond_handle_frame() return RX_HANDLER_CONSUMED if bonding has processed the LACP frame. Signed-off-by: Jiri Bohac Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 18 ++++++++++++------ drivers/net/bonding/bond_3ad.h | 2 +- drivers/net/bonding/bond_main.c | 16 +++++++++++----- 3 files changed, 24 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 793b00138275..3463b469e657 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2173,9 +2173,10 @@ re_arm: * received frames (loopback). Since only the payload is given to this * function, it check for loopback. */ -static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 length) +static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 length) { struct port *port; + int ret = RX_HANDLER_ANOTHER; if (length >= sizeof(struct lacpdu)) { @@ -2184,11 +2185,12 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u if (!port->slave) { pr_warning("%s: Warning: port of slave %s is uninitialized\n", slave->dev->name, slave->dev->master->name); - return; + return ret; } switch (lacpdu->subtype) { case AD_TYPE_LACPDU: + ret = RX_HANDLER_CONSUMED; pr_debug("Received LACPDU on port %d\n", port->actor_port_number); /* Protect against concurrent state machines */ @@ -2198,6 +2200,7 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u break; case AD_TYPE_MARKER: + ret = RX_HANDLER_CONSUMED; // No need to convert fields to Little Endian since we don't use the marker's fields. switch (((struct bond_marker *)lacpdu)->tlv_type) { @@ -2219,6 +2222,7 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u } } } + return ret; } /** @@ -2456,18 +2460,20 @@ out: return NETDEV_TX_OK; } -void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, +int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, struct slave *slave) { + int ret = RX_HANDLER_ANOTHER; if (skb->protocol != PKT_TYPE_LACPDU) - return; + return ret; if (!pskb_may_pull(skb, sizeof(struct lacpdu))) - return; + return ret; read_lock(&bond->lock); - bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len); + ret = bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len); read_unlock(&bond->lock); + return ret; } /* diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index 235b2cc58b28..5ee7e3c45db7 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -274,7 +274,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave); void bond_3ad_handle_link_change(struct slave *slave, char link); int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); -void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, +int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, struct slave *slave); int bond_3ad_set_carrier(struct bonding *bond); void bond_3ad_update_lacp_rate(struct bonding *bond); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 62d2409bb293..bc13b3d77432 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1444,8 +1444,9 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) struct sk_buff *skb = *pskb; struct slave *slave; struct bonding *bond; - void (*recv_probe)(struct sk_buff *, struct bonding *, + int (*recv_probe)(struct sk_buff *, struct bonding *, struct slave *); + int ret = RX_HANDLER_ANOTHER; skb = skb_share_check(skb, GFP_ATOMIC); if (unlikely(!skb)) @@ -1464,8 +1465,12 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); if (likely(nskb)) { - recv_probe(nskb, bond, slave); + ret = recv_probe(nskb, bond, slave); dev_kfree_skb(nskb); + if (ret == RX_HANDLER_CONSUMED) { + consume_skb(skb); + return ret; + } } } @@ -1487,7 +1492,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) memcpy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, ETH_ALEN); } - return RX_HANDLER_ANOTHER; + return ret; } /* enslave device to bond device */ @@ -2723,7 +2728,7 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 } } -static void bond_arp_rcv(struct sk_buff *skb, struct bonding *bond, +static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond, struct slave *slave) { struct arphdr *arp; @@ -2731,7 +2736,7 @@ static void bond_arp_rcv(struct sk_buff *skb, struct bonding *bond, __be32 sip, tip; if (skb->protocol != __cpu_to_be16(ETH_P_ARP)) - return; + return RX_HANDLER_ANOTHER; read_lock(&bond->lock); @@ -2776,6 +2781,7 @@ static void bond_arp_rcv(struct sk_buff *skb, struct bonding *bond, out_unlock: read_unlock(&bond->lock); + return RX_HANDLER_ANOTHER; } /* -- cgit v1.2.3 From f09e2249c4f5c7c13261ec73f5a7807076af0c8e Mon Sep 17 00:00:00 2001 From: Basil Gor Date: Thu, 3 May 2012 22:55:24 +0000 Subject: macvtap: restore vlan header on user read Ethernet vlan header is not on the packet and kept in the skb->vlan_tci when it comes from lower dev. This patch inserts vlan header in user buffer during skb copy on user read. Signed-off-by: Basil Gor Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/macvtap.c | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 0427c6561c84..cb8fd5069dbe 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -759,6 +760,8 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, struct macvlan_dev *vlan; int ret; int vnet_hdr_len = 0; + int vlan_offset = 0; + int copied; if (q->flags & IFF_VNET_HDR) { struct virtio_net_hdr vnet_hdr; @@ -773,18 +776,48 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr))) return -EFAULT; } + copied = vnet_hdr_len; + + if (!vlan_tx_tag_present(skb)) + len = min_t(int, skb->len, len); + else { + int copy; + struct { + __be16 h_vlan_proto; + __be16 h_vlan_TCI; + } veth; + veth.h_vlan_proto = htons(ETH_P_8021Q); + veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); + + vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); + len = min_t(int, skb->len + VLAN_HLEN, len); + + copy = min_t(int, vlan_offset, len); + ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy); + len -= copy; + copied += copy; + if (ret || !len) + goto done; + + copy = min_t(int, sizeof(veth), len); + ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy); + len -= copy; + copied += copy; + if (ret || !len) + goto done; + } - len = min_t(int, skb->len, len); - - ret = skb_copy_datagram_const_iovec(skb, 0, iv, vnet_hdr_len, len); + ret = skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len); + copied += len; +done: rcu_read_lock_bh(); vlan = rcu_dereference_bh(q->vlan); if (vlan) - macvlan_count_rx(vlan, len, ret == 0, 0); + macvlan_count_rx(vlan, copied - vnet_hdr_len, ret == 0, 0); rcu_read_unlock_bh(); - return ret ? ret : (len + vnet_hdr_len); + return ret ? ret : copied; } static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb, -- cgit v1.2.3 From 062e55e3960062fc2fb62a7274b4c253003eba73 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 10 May 2012 12:51:30 +0000 Subject: ks8851: Update link status during link change interrupt If a link change interrupt comes in we just clear the interrupt and continue along without notifying the upper networking layers that the link has changed. Use the mii_check_link() function to update the link status whenever a link change interrupt occurs. Cc: Ben Dooks Signed-off-by: Stephen Boyd Signed-off-by: David S. Miller --- drivers/net/ethernet/micrel/ks8851.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c index f8dda009d3c0..5e313e9a252f 100644 --- a/drivers/net/ethernet/micrel/ks8851.c +++ b/drivers/net/ethernet/micrel/ks8851.c @@ -618,10 +618,8 @@ static void ks8851_irq_work(struct work_struct *work) netif_dbg(ks, intr, ks->netdev, "%s: status 0x%04x\n", __func__, status); - if (status & IRQ_LCI) { - /* should do something about checking link status */ + if (status & IRQ_LCI) handled |= IRQ_LCI; - } if (status & IRQ_LDI) { u16 pmecr = ks8851_rdreg16(ks, KS_PMECR); @@ -684,6 +682,9 @@ static void ks8851_irq_work(struct work_struct *work) mutex_unlock(&ks->lock); + if (status & IRQ_LCI) + mii_check_link(&ks->mii); + if (status & IRQ_TXI) netif_wake_queue(ks->netdev); -- cgit v1.2.3