From 27caca9d2e01c92b26d0690f065aad093fea01c7 Mon Sep 17 00:00:00 2001 From: Alexander Kochetkov Date: Tue, 18 Nov 2014 21:00:58 +0400 Subject: i2c: omap: fix NACK and Arbitration Lost irq handling commit 1d7afc95946487945cc7f5019b41255b72224b70 (i2c: omap: ack IRQ in parts) changed the interrupt handler to complete transfers without clearing XRDY (AL case) and ARDY (NACK case) flags. XRDY or ARDY interrupts will be fired again. As a result, ISR keep processing transfer after it was already complete (from the driver code point of view). A didn't see real impacts of the 1d7afc9, but it is really bad idea to have ISR running on user data after transfer was complete. It looks, what 1d7afc9 violate TI specs in what how AL and NACK should be handled (see Note 1, sprugn4r, Figure 17-31 and Figure 17-32). According to specs (if I understood correctly), in case of NACK and AL driver must reset NACK, AL, ARDY, RDR, and RRDY (Master Receive Mode), and NACK, AL, ARDY, and XDR (Master Transmitter Mode). All that is done down the code under the if condition: if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) ... The patch restore pre 1d7afc9 logic of handling NACK and AL interrupts, so no interrupts is fired after ISR informs the rest of driver what transfer complete. Note: instead of removing break under NACK case, we could just replace 'break' with 'continue' and allow NACK transfer to finish using ARDY event. I found that NACK and ARDY bits usually set together. That case confirm TI wiki: http://processors.wiki.ti.com/index.php/I2C_Tips#Detecting_and_handling_NACK In order if someone interested in the event traces for NACK and AL cases, I sent them to mailing list. Tested on Beagleboard XM C. Signed-off-by: Alexander Kochetkov Fixes: 1d7afc9 i2c: omap: ack IRQ in parts Cc: # v3.7+ Acked-by: Felipe Balbi Tested-by: Aaro Koskinen Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 26942c159de1..32dc65183ea8 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -922,14 +922,12 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); - break; } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); - break; } /* -- cgit v1.2.3-59-g8ed1b From d39f77b06a712fcba6185a20bb209e357923d980 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 7 Nov 2014 12:10:44 +0000 Subject: i2c: designware: prevent early stop on TX FIFO empty If the Designware core is configured with IC_EMPTYFIFO_HOLD_MASTER_EN set to zero, allowing the TX FIFO to become empty causes a STOP condition to be generated on the I2C bus. If the transmit FIFO threshold is set too high, an erroneous STOP condition can be generated on long transfers - particularly where the interrupt latency is extended. Signed-off-by: Andrew Jackson Signed-off-by: Liviu Dudau Tested-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index edca99dbba23..23628b7bfb8d 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -359,7 +359,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev) } /* Configure Tx/Rx FIFO threshold levels */ - dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL); + dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL); dw_writel(dev, 0, DW_IC_RX_TL); /* configure the i2c master */ -- cgit v1.2.3-59-g8ed1b From ccfc866356674cb3a61829d239c685af6e85f197 Mon Sep 17 00:00:00 2001 From: Alexander Kochetkov Date: Fri, 21 Nov 2014 04:16:51 +0400 Subject: i2c: omap: fix i207 errata handling commit 6d9939f651419a63e091105663821f9c7d3fec37 (i2c: omap: split out [XR]DR and [XR]RDY) changed the way how errata i207 (I2C: RDR Flag May Be Incorrectly Set) get handled. 6d9939f6514 code doesn't correspond to workaround provided by errata. According to errata ISR must filter out spurious RDR before data read not after. ISR must read RXSTAT to get number of bytes available to read. Because RDR could be set while there could no data in the receive FIFO. Restored pre 6d9939f6514 way of handling errata. Found by code review. Real impact haven't seen. Tested on Beagleboard XM C. Signed-off-by: Alexander Kochetkov Fixes: 6d9939f651419a63e09110 i2c: omap: split out [XR]DR and [XR]RDY Tested-by: Felipe Balbi Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 32dc65183ea8..277a2288d4a8 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -952,11 +952,13 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) if (dev->fifo_size) num_bytes = dev->buf_len; - omap_i2c_receive_data(dev, num_bytes, true); - - if (dev->errata & I2C_OMAP_ERRATA_I207) + if (dev->errata & I2C_OMAP_ERRATA_I207) { i2c_omap_errata_i207(dev, stat); + num_bytes = (omap_i2c_read_reg(dev, + OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; + } + omap_i2c_receive_data(dev, num_bytes, true); omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); continue; } -- cgit v1.2.3-59-g8ed1b From bdfa7542d40e6251c232a802231b37116bd31b11 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 May 2014 21:33:09 +0300 Subject: drm/i915: Ignore SURFLIVE and flip counter when the GPU gets reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During a GPU reset we need to get pending page flip cleared out since the ring contents are gone and flip will never complete on its own. This used to work until the mmio vs. CS flip race detection came about. That piece of code is looking for a specific surface address in the SURFLIVE register, but as a flip to that address may never happen the check may never pass. So we should just skip the SURFLIVE and flip counter checks when the GPU gets reset. intel_display_handle_reset() tries to effectively complete the flip anyway by calling .update_primary_plane(). But that may not satisfy the conditions of the mmio vs. CS race detection since there's no guarantee that a modeset didn't sneak in between the GPU reset and intel_display_handle_reset(). Such a modeset will not wait for pending flips due to the ongoing GPU reset, and then the primary plane updates performed by intel_display_handle_reset() will already use the new surface address, and thus the surface address the flip is waiting for might never appear in SURFLIVE. The result is that the flip will never complete and attempts to perform further page flips will fail with -EBUSY. During the GPU reset intel_crtc_has_pending_flip() will return false regardless, so the deadlock with a modeset vs. the error work acquiring crtc->mutex was avoided. And the reset_counter check in intel_crtc_has_pending_flip() actually made this bug even less severe since it allowed normal modesets to go through even though there's a pending flip. This is a regression introduced by me here: commit 75f7f3ec600524c9544cc31695155f1a9ddbe1d9 Author: Ville Syrjälä Date: Tue Apr 15 21:41:34 2014 +0300 drm/i915: Fix mmio vs. CS flip race on ILK+ Testcase: igt/kms_flip/flip-vs-panning-vs-hang Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Reviewed-by: Daniel Vetter Cc: stable@vger.kernel.org Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f0a1a56406eb..8bcdb981d540 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9408,6 +9408,10 @@ static bool page_flip_finished(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + if (i915_reset_in_progress(&dev_priv->gpu_error) || + crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) + return true; + /* * The relevant registers doen't exist on pre-ctg. * As the flip done interrupt doesn't trigger for mmio -- cgit v1.2.3-59-g8ed1b From afa4e53a7bcd4328d88e25c7a63746b65dc6bbe2 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 25 Nov 2014 15:43:48 +0200 Subject: drm/i915: Cancel vdd off work before suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we just make sure vdd is off before suspending, but we don't cancel the vdd off work. The work wil not touch vdd if want_panel_vdd==false so in theory this is fine. In the past that was perfectly fine since the vdd off work didn't do anything when want_panel_vdd==false, so even if the work would have been run during system resume before i915 has resumed, nothing would happen. However since pps_lock() will now grab the power domain references before it can check want_panel_vdd, we may end up toggling the power wells on/off already before the driver has resumed. That is not really acceptable, so cancel the vdd off work when suspending the encoder. The problem appeared when pps_lock() was introduced in: commit 773538e86081d146e0020435d614f4b96996c1f9 Author: Ville Syrjälä Date: Thu Sep 4 14:54:56 2014 +0300 drm/i915: Reset power sequencer pipe tracking when disp2d is off Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5ad45bfff3fe..4bcd91757321 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4450,6 +4450,7 @@ static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) * vdd might still be enabled do to the delayed vdd off. * Make sure vdd is actually turned off here. */ + cancel_delayed_work_sync(&intel_dp->panel_vdd_work); pps_lock(intel_dp); edp_panel_vdd_off_sync(intel_dp); pps_unlock(intel_dp); -- cgit v1.2.3-59-g8ed1b From 094cb98179f19b75acf9ff471daabf3948ce98e6 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Tue, 25 Nov 2014 15:05:13 +0000 Subject: of/fdt: memblock_reserve /memreserve/ regions in the case of partial overlap memblock_is_region_reserved() returns true in the case of a partial overlap, meaning that the current code fails to reserve the non-overlapping portion. This call was introduced as part of d1552ce449eb "of/fdt: move memreserve and dtb memory reservations into core" which went into v3.16. I observed this causing a Midway system with a buggy fdt (the header declares itself to be larger than it really is) failing to boot because the over-inflated size of the fdt was causing it to seem to run into the swapper_pg_dir region, meaning the DT wasn't reserved. The symptoms were failing to find an disks or network and failing to boot. However given the ambiguity of whether things like the initrd are covered by /memreserve/ and similar I think it is best to also register the region rather than just ignoring it. Since memblock_reserve() handles overlaps just fine lets just warn and carry on. Signed-off-by: Ian Campbell Signed-off-by: Grant Likely Cc: Rob Herring Cc: stable@vger.kernel.org # v3.16+ --- drivers/of/fdt.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 30e97bcc4f88..d134710de96d 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -964,8 +964,6 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size, bool nomap) { - if (memblock_is_region_reserved(base, size)) - return -EBUSY; if (nomap) return memblock_remove(base, size); return memblock_reserve(base, size); -- cgit v1.2.3-59-g8ed1b From 1348579433566355e570008929daa09a0db64fd8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 14 Nov 2014 12:08:34 -0500 Subject: drm/radeon: report disconnected for LVDS/eDP with PX if ddc fails If ddc fails, presumably the i2c mux (and hopefully the signal mux) are switched to the other GPU so don't fetch the edid from the vbios so that the connector reports disconnected. bug: https://bugzilla.opensuse.org/show_bug.cgi?id=904417 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_connectors.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 300c4b3d4669..26baa9c05f6c 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -322,6 +322,12 @@ static void radeon_connector_get_edid(struct drm_connector *connector) } if (!radeon_connector->edid) { + /* don't fetch the edid from the vbios if ddc fails and runpm is + * enabled so we report disconnected. + */ + if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) + return; + if (rdev->is_atom_bios) { /* some laptops provide a hardcoded edid in rom for LCDs */ if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) || @@ -826,6 +832,8 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector, static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector, bool force) { + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = radeon_best_single_encoder(connector); enum drm_connector_status ret = connector_status_disconnected; @@ -842,7 +850,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) /* check if panel is valid */ if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) ret = connector_status_connected; - + /* don't fetch the edid from the vbios if ddc fails and runpm is + * enabled so we report disconnected. + */ + if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) + ret = connector_status_disconnected; } /* check for edid as well */ @@ -1589,6 +1601,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force) /* check if panel is valid */ if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) ret = connector_status_connected; + /* don't fetch the edid from the vbios if ddc fails and runpm is + * enabled so we report disconnected. + */ + if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) + ret = connector_status_disconnected; } /* eDP is always DP */ radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; -- cgit v1.2.3-59-g8ed1b From f6c6fda4c9e17940b0a2ba206b0408babfdc930c Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 27 Nov 2014 00:22:33 +0100 Subject: bond: Check length of IFLA_BOND_ARP_IP_TARGET attributes Fixes: 7f28fa10 ("bonding: add arp_ip_target netlink support") Reported-by: John Fastabend Cc: Scott Feldman Signed-off-by: Thomas Graf Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index c13d83e15ace..45f09a66e6c9 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -225,7 +225,12 @@ static int bond_changelink(struct net_device *bond_dev, bond_option_arp_ip_targets_clear(bond); nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) { - __be32 target = nla_get_be32(attr); + __be32 target; + + if (nla_len(attr) < sizeof(target)) + return -EINVAL; + + target = nla_get_be32(attr); bond_opt_initval(&newval, (__force u64)target); err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS, -- cgit v1.2.3-59-g8ed1b From 4d6a949c62f123569fb355b6ec7f314b76f93735 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Kimura Date: Thu, 27 Nov 2014 20:34:00 +0900 Subject: sh_eth: Fix skb alloc size and alignment adjust rule. In the current driver, allocation size of skb does not care the alignment adjust after allocation. And also, in the current implementation, buffer alignment method by sh_eth_set_receive_align function has a bug that this function displace buffer start address forcedly when the alignment is corrected. In the result, tail of the skb will exceed allocated area and kernel panic will be occurred. This patch fix this issue. Signed-off-by: Mitsuhiro Kimura Signed-off-by: Yoshihiro Kaneko Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 32 +++++++++++++------------------- drivers/net/ethernet/renesas/sh_eth.h | 4 ++-- 2 files changed, 15 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 60e9c2cd051e..f9e30b87ecd5 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -917,21 +917,13 @@ static int sh_eth_reset(struct net_device *ndev) return ret; } -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) static void sh_eth_set_receive_align(struct sk_buff *skb) { - int reserve; + uintptr_t reserve = (uintptr_t)skb->data & (SH_ETH_RX_ALIGN - 1); - reserve = SH4_SKB_RX_ALIGN - ((u32)skb->data & (SH4_SKB_RX_ALIGN - 1)); if (reserve) - skb_reserve(skb, reserve); + skb_reserve(skb, SH_ETH_RX_ALIGN - reserve); } -#else -static void sh_eth_set_receive_align(struct sk_buff *skb) -{ - skb_reserve(skb, SH2_SH3_SKB_RX_ALIGN); -} -#endif /* CPU <-> EDMAC endian convert */ @@ -1119,6 +1111,7 @@ static void sh_eth_ring_format(struct net_device *ndev) struct sh_eth_txdesc *txdesc = NULL; int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring; int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring; + int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1; mdp->cur_rx = 0; mdp->cur_tx = 0; @@ -1131,21 +1124,21 @@ static void sh_eth_ring_format(struct net_device *ndev) for (i = 0; i < mdp->num_rx_ring; i++) { /* skb */ mdp->rx_skbuff[i] = NULL; - skb = netdev_alloc_skb(ndev, mdp->rx_buf_sz); + skb = netdev_alloc_skb(ndev, skbuff_size); mdp->rx_skbuff[i] = skb; if (skb == NULL) break; - dma_map_single(&ndev->dev, skb->data, mdp->rx_buf_sz, - DMA_FROM_DEVICE); sh_eth_set_receive_align(skb); /* RX descriptor */ rxdesc = &mdp->rx_ring[i]; + /* The size of the buffer is a multiple of 16 bytes. */ + rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); + dma_map_single(&ndev->dev, skb->data, rxdesc->buffer_length, + DMA_FROM_DEVICE); rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP); - /* The size of the buffer is 16 byte boundary. */ - rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); /* Rx descriptor address set */ if (i == 0) { sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR); @@ -1397,6 +1390,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) struct sk_buff *skb; u16 pkt_len = 0; u32 desc_status; + int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1; rxdesc = &mdp->rx_ring[entry]; while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) { @@ -1448,7 +1442,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) if (mdp->cd->rpadir) skb_reserve(skb, NET_IP_ALIGN); dma_sync_single_for_cpu(&ndev->dev, rxdesc->addr, - mdp->rx_buf_sz, + ALIGN(mdp->rx_buf_sz, 16), DMA_FROM_DEVICE); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, ndev); @@ -1468,13 +1462,13 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); if (mdp->rx_skbuff[entry] == NULL) { - skb = netdev_alloc_skb(ndev, mdp->rx_buf_sz); + skb = netdev_alloc_skb(ndev, skbuff_size); mdp->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ - dma_map_single(&ndev->dev, skb->data, mdp->rx_buf_sz, - DMA_FROM_DEVICE); sh_eth_set_receive_align(skb); + dma_map_single(&ndev->dev, skb->data, + rxdesc->buffer_length, DMA_FROM_DEVICE); skb_checksum_none_assert(skb); rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index b37c427144ee..9fa93321d512 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -162,9 +162,9 @@ enum { /* Driver's parameters */ #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) -#define SH4_SKB_RX_ALIGN 32 +#define SH_ETH_RX_ALIGN 32 #else -#define SH2_SH3_SKB_RX_ALIGN 2 +#define SH_ETH_RX_ALIGN 2 #endif /* Register's bits -- cgit v1.2.3-59-g8ed1b From 28603d13997e2ef47f18589cc9a44553aad49c86 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 27 Nov 2014 21:05:34 +0800 Subject: stmmac: platform: Move plat_dat checking earlier Original code only check/alloc plat_dat for the CONFIG_OF case, this patch check/alloc it earlier and unconditionally to avoid kernel build warnings: drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c:275 stmmac_pltfr_probe() warn: variable dereferenced before check 'plat_dat' V2: Fix coding style. Signed-off-by: Huacai Chen Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 5b0da3986216..58a1a0a423d4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -265,6 +265,15 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) plat_dat = dev_get_platdata(&pdev->dev); + if (!plat_dat) + plat_dat = devm_kzalloc(&pdev->dev, + sizeof(struct plat_stmmacenet_data), + GFP_KERNEL); + if (!plat_dat) { + pr_err("%s: ERROR: no memory", __func__); + return -ENOMEM; + } + /* Set default value for multicast hash bins */ plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; @@ -272,15 +281,6 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) plat_dat->unicast_filter_entries = 1; if (pdev->dev.of_node) { - if (!plat_dat) - plat_dat = devm_kzalloc(&pdev->dev, - sizeof(struct plat_stmmacenet_data), - GFP_KERNEL); - if (!plat_dat) { - pr_err("%s: ERROR: no memory", __func__); - return -ENOMEM; - } - ret = stmmac_probe_config_dt(pdev, plat_dat, &mac); if (ret) { pr_err("%s: main dt probe failed", __func__); -- cgit v1.2.3-59-g8ed1b From 7fa2955ff70ce4532f144d26b8a087095f9c9ffc Mon Sep 17 00:00:00 2001 From: Mitsuhiro Kimura Date: Fri, 28 Nov 2014 10:04:15 +0900 Subject: sh_eth: Fix sleeping function called from invalid context This resolves the following bug which can be reproduced by building the kernel with CONFIG_DEBUG_ATOMIC_SLEEP=y and reading network statistics while the network interface is down. e.g.: ifconfig eth0 down cat /sys/class/net/eth0/statistics/tx_errors ---- [ 1238.161349] BUG: sleeping function called from invalid context at drivers/base/power/runtime.c:952 [ 1238.188279] in_atomic(): 1, irqs_disabled(): 0, pid: 1388, name: cat [ 1238.207425] CPU: 0 PID: 1388 Comm: cat Not tainted 3.10.31-ltsi-00046-gefa0b46 #1087 [ 1238.230737] Backtrace: [ 1238.238123] [] (dump_backtrace+0x0/0x10c) from [] (show_stack+0x18/0x1c) [ 1238.263499] r6:000003b8 r5:c06160c0 r4:c0669e00 r3:00404000 [ 1238.280583] [] (show_stack+0x0/0x1c) from [] (dump_stack+0x20/0x28) [ 1238.304631] [] (dump_stack+0x0/0x28) from [] (__might_sleep+0xf8/0x118) [ 1238.329734] [] (__might_sleep+0x0/0x118) from [] (__pm_runtime_resume+0x38/0x90) [ 1238.357170] r7:d616f000 r6:c049c458 r5:00000004 r4:d6a17210 [ 1238.374251] [] (__pm_runtime_resume+0x0/0x90) from [] (sh_eth_get_stats+0x44/0x280) [ 1238.402468] r7:d616f000 r6:c049c458 r5:d5c21000 r4:d5c21000 [ 1238.419552] [] (sh_eth_get_stats+0x0/0x280) from [] (dev_get_stats+0x54/0x88) [ 1238.446204] r5:d5c21000 r4:d5ed7e08 [ 1238.456980] [] (dev_get_stats+0x0/0x88) from [] (netstat_show.isra.15+0x54/0x9c) [ 1238.484413] r6:d5c21000 r5:d5c21238 r4:00000028 r3:00000001 [ 1238.501495] [] (netstat_show.isra.15+0x0/0x9c) from [] (show_tx_errors+0x18/0x1c) [ 1238.529196] r7:d5f945d8 r6:d5f945c0 r5:c049716c r4:c0650e7c [ 1238.546279] [] (show_tx_errors+0x0/0x1c) from [] (dev_attr_show+0x24/0x50) [ 1238.572157] [] (dev_attr_show+0x0/0x50) from [] (sysfs_read_file+0xb0/0x140) [ 1238.598554] r5:c049716c r4:d5c21240 [ 1238.609326] [] (sysfs_read_file+0x0/0x140) from [] (vfs_read+0xb0/0x13c) [ 1238.634679] [] (vfs_read+0x0/0x13c) from [] (SyS_read+0x44/0x74) [ 1238.657944] r8:bef45bf0 r7:00000000 r6:d6ac0600 r5:00000000 r4:00000000 [ 1238.678172] [] (SyS_read+0x0/0x74) from [] (ret_fast_syscall+0x0/0x30) ---- Signed-off-by: Mitsuhiro Kimura Signed-off-by: Yoshihiro Kaneko Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 64 +++++++++++++++++++---------------- drivers/net/ethernet/renesas/sh_eth.h | 1 + 2 files changed, 36 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index f9e30b87ecd5..b5db6b3f939f 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2036,6 +2036,8 @@ static int sh_eth_open(struct net_device *ndev) if (ret) goto out_free_irq; + mdp->is_opened = 1; + return ret; out_free_irq: @@ -2125,6 +2127,36 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_OK; } +static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + + if (sh_eth_is_rz_fast_ether(mdp)) + return &ndev->stats; + + if (!mdp->is_opened) + return &ndev->stats; + + ndev->stats.tx_dropped += sh_eth_read(ndev, TROCR); + sh_eth_write(ndev, 0, TROCR); /* (write clear) */ + ndev->stats.collisions += sh_eth_read(ndev, CDCR); + sh_eth_write(ndev, 0, CDCR); /* (write clear) */ + ndev->stats.tx_carrier_errors += sh_eth_read(ndev, LCCR); + sh_eth_write(ndev, 0, LCCR); /* (write clear) */ + + if (sh_eth_is_gether(mdp)) { + ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR); + sh_eth_write(ndev, 0, CERCR); /* (write clear) */ + ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR); + sh_eth_write(ndev, 0, CEECR); /* (write clear) */ + } else { + ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR); + sh_eth_write(ndev, 0, CNDCR); /* (write clear) */ + } + + return &ndev->stats; +} + /* device close function */ static int sh_eth_close(struct net_device *ndev) { @@ -2139,6 +2171,7 @@ static int sh_eth_close(struct net_device *ndev) sh_eth_write(ndev, 0, EDTRR); sh_eth_write(ndev, 0, EDRRR); + sh_eth_get_stats(ndev); /* PHY Disconnect */ if (mdp->phydev) { phy_stop(mdp->phydev); @@ -2157,36 +2190,9 @@ static int sh_eth_close(struct net_device *ndev) pm_runtime_put_sync(&mdp->pdev->dev); - return 0; -} - -static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev) -{ - struct sh_eth_private *mdp = netdev_priv(ndev); - - if (sh_eth_is_rz_fast_ether(mdp)) - return &ndev->stats; - - pm_runtime_get_sync(&mdp->pdev->dev); - - ndev->stats.tx_dropped += sh_eth_read(ndev, TROCR); - sh_eth_write(ndev, 0, TROCR); /* (write clear) */ - ndev->stats.collisions += sh_eth_read(ndev, CDCR); - sh_eth_write(ndev, 0, CDCR); /* (write clear) */ - ndev->stats.tx_carrier_errors += sh_eth_read(ndev, LCCR); - sh_eth_write(ndev, 0, LCCR); /* (write clear) */ - if (sh_eth_is_gether(mdp)) { - ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR); - sh_eth_write(ndev, 0, CERCR); /* (write clear) */ - ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR); - sh_eth_write(ndev, 0, CEECR); /* (write clear) */ - } else { - ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR); - sh_eth_write(ndev, 0, CNDCR); /* (write clear) */ - } - pm_runtime_put_sync(&mdp->pdev->dev); + mdp->is_opened = 0; - return &ndev->stats; + return 0; } /* ioctl to device function */ diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 9fa93321d512..22301bf9c21d 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -522,6 +522,7 @@ struct sh_eth_private { unsigned no_ether_link:1; unsigned ether_link_active_low:1; + unsigned is_opened:1; }; static inline void sh_eth_soft_swap(char *src, int len) -- cgit v1.2.3-59-g8ed1b From 5106787a9e08dc2901d6b2513ed8f377671befa8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 27 Nov 2014 09:54:09 +0100 Subject: PCI: tegra: Use physical range for I/O mapping Commit 0b0b0893d49b ("of/pci: Fix the conversion of IO ranges into IO resources") changed how I/O resources are parsed from DT. Rather than containing the physical address of the I/O region, the addresses will now be in I/O address space. On Tegra the union of all ranges is used to expose a top-level memory- mapped resource for the PCI host bridge. This helps to make /proc/iomem more readable. Combining both of the above, the union would now include the I/O space region. This causes a regression on Tegra20, where the physical base address of the PCIe controller (and therefore of the union) is located at physical address 0x80000000. Since I/O space starts at 0, the union will now include all of system RAM which starts at 0x00000000. This commit fixes this by keeping two copies of the I/O range: one that represents the range in the CPU's physical address space, the other for the range in the I/O address space. This allows the translation setup within the driver to reuse the physical addresses. The code registering the I/O region with the PCI core uses both ranges to establish the mapping. Fixes: 0b0b0893d49b ("of/pci: Fix the conversion of IO ranges into IO resources") Reported-by: Marc Zyngier Tested-by: Marc Zyngier Suggested-by: Arnd Bergmann Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas Reviewed-by: Arnd Bergmann --- drivers/pci/host/pci-tegra.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 3d43874319be..19bb19c7db4a 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -276,6 +276,7 @@ struct tegra_pcie { struct resource all; struct resource io; + struct resource pio; struct resource mem; struct resource prefetch; struct resource busn; @@ -658,7 +659,6 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) { struct tegra_pcie *pcie = sys_to_pcie(sys); int err; - phys_addr_t io_start; err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem); if (err < 0) @@ -668,14 +668,12 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) if (err) return err; - io_start = pci_pio_to_address(pcie->io.start); - pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); pci_add_resource_offset(&sys->resources, &pcie->prefetch, sys->mem_offset); pci_add_resource(&sys->resources, &pcie->busn); - pci_ioremap_io(nr * SZ_64K, io_start); + pci_ioremap_io(pcie->pio.start, pcie->io.start); return 1; } @@ -786,7 +784,6 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg) static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) { u32 fpci_bar, size, axi_address; - phys_addr_t io_start = pci_pio_to_address(pcie->io.start); /* Bar 0: type 1 extended configuration space */ fpci_bar = 0xfe100000; @@ -799,7 +796,7 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) /* Bar 1: downstream IO bar */ fpci_bar = 0xfdfc0000; size = resource_size(&pcie->io); - axi_address = io_start; + axi_address = pcie->io.start; afi_writel(pcie, axi_address, AFI_AXI_BAR1_START); afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ); afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1); @@ -1690,8 +1687,23 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) switch (res.flags & IORESOURCE_TYPE_BITS) { case IORESOURCE_IO: - memcpy(&pcie->io, &res, sizeof(res)); - pcie->io.name = np->full_name; + memcpy(&pcie->pio, &res, sizeof(res)); + pcie->pio.name = np->full_name; + + /* + * The Tegra PCIe host bridge uses this to program the + * mapping of the I/O space to the physical address, + * so we override the .start and .end fields here that + * of_pci_range_to_resource() converted to I/O space. + * We also set the IORESOURCE_MEM type to clarify that + * the resource is in the physical memory space. + */ + pcie->io.start = range.cpu_addr; + pcie->io.end = range.cpu_addr + range.size - 1; + pcie->io.flags = IORESOURCE_MEM; + pcie->io.name = "I/O"; + + memcpy(&res, &pcie->io, sizeof(res)); break; case IORESOURCE_MEM: -- cgit v1.2.3-59-g8ed1b From 19a10828814aa3ba483301b416b27f94330e0c80 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 1 Dec 2014 11:44:27 +1000 Subject: drm/nouveau/fifo/g84-: ack non-stall interrupt before handling it Closes a very unlikely race that can occur if another NonStallInterrupt method passes between checking fences and acking the previous interrupt. With this change, the interrupt will re-fire under such conditions. Tested-by: Tobias Klausmann Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c | 2 +- drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c | 4 ++-- drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c index 5ae6a43893b5..1931057f9962 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c @@ -551,8 +551,8 @@ nv04_fifo_intr(struct nouveau_subdev *subdev) } if (status & 0x40000000) { - nouveau_fifo_uevent(&priv->base); nv_wr32(priv, 0x002100, 0x40000000); + nouveau_fifo_uevent(&priv->base); status &= ~0x40000000; } } diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index 1fe1f8fbda0c..074d434c3077 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c @@ -740,6 +740,8 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) u32 inte = nv_rd32(priv, 0x002628); u32 unkn; + nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr); + for (unkn = 0; unkn < 8; unkn++) { u32 ints = (intr >> (unkn * 0x04)) & inte; if (ints & 0x1) { @@ -751,8 +753,6 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) nv_mask(priv, 0x002628, ints, 0); } } - - nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr); } static void diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index d2f0fd39c145..f8734eb74eaa 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c @@ -952,8 +952,8 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) } if (stat & 0x80000000) { - nve0_fifo_intr_engine(priv); nv_wr32(priv, 0x002100, 0x80000000); + nve0_fifo_intr_engine(priv); stat &= ~0x80000000; } -- cgit v1.2.3-59-g8ed1b From 0ec5f02f0e2c6fe88ba5817790e11fe33ee298a7 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Dec 2014 19:11:06 +1000 Subject: drm/nouveau: prevent stale fence->channel pointers, and protect with rcu Tested-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 92 +++++++++++++++++++++++---------- drivers/gpu/drm/nouveau/nouveau_fence.h | 4 +- 2 files changed, 67 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 515cd9aebb99..f32a434724e3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -52,20 +52,24 @@ nouveau_fctx(struct nouveau_fence *fence) return container_of(fence->base.lock, struct nouveau_fence_chan, lock); } -static void +static int nouveau_fence_signal(struct nouveau_fence *fence) { + int drop = 0; + fence_signal_locked(&fence->base); list_del(&fence->head); + rcu_assign_pointer(fence->channel, NULL); if (test_bit(FENCE_FLAG_USER_BITS, &fence->base.flags)) { struct nouveau_fence_chan *fctx = nouveau_fctx(fence); if (!--fctx->notify_ref) - nvif_notify_put(&fctx->notify); + drop = 1; } fence_put(&fence->base); + return drop; } static struct nouveau_fence * @@ -88,16 +92,23 @@ nouveau_fence_context_del(struct nouveau_fence_chan *fctx) { struct nouveau_fence *fence; - nvif_notify_fini(&fctx->notify); - spin_lock_irq(&fctx->lock); while (!list_empty(&fctx->pending)) { fence = list_entry(fctx->pending.next, typeof(*fence), head); - nouveau_fence_signal(fence); - fence->channel = NULL; + if (nouveau_fence_signal(fence)) + nvif_notify_put(&fctx->notify); } spin_unlock_irq(&fctx->lock); + + nvif_notify_fini(&fctx->notify); + fctx->dead = 1; + + /* + * Ensure that all accesses to fence->channel complete before freeing + * the channel. + */ + synchronize_rcu(); } static void @@ -112,21 +123,23 @@ nouveau_fence_context_free(struct nouveau_fence_chan *fctx) kref_put(&fctx->fence_ref, nouveau_fence_context_put); } -static void +static int nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx) { struct nouveau_fence *fence; - + int drop = 0; u32 seq = fctx->read(chan); while (!list_empty(&fctx->pending)) { fence = list_entry(fctx->pending.next, typeof(*fence), head); if ((int)(seq - fence->base.seqno) < 0) - return; + break; - nouveau_fence_signal(fence); + drop |= nouveau_fence_signal(fence); } + + return drop; } static int @@ -135,18 +148,21 @@ nouveau_fence_wait_uevent_handler(struct nvif_notify *notify) struct nouveau_fence_chan *fctx = container_of(notify, typeof(*fctx), notify); unsigned long flags; + int ret = NVIF_NOTIFY_KEEP; spin_lock_irqsave(&fctx->lock, flags); if (!list_empty(&fctx->pending)) { struct nouveau_fence *fence; + struct nouveau_channel *chan; fence = list_entry(fctx->pending.next, typeof(*fence), head); - nouveau_fence_update(fence->channel, fctx); + chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); + if (nouveau_fence_update(fence->channel, fctx)) + ret = NVIF_NOTIFY_DROP; } spin_unlock_irqrestore(&fctx->lock, flags); - /* Always return keep here. NVIF refcount is handled with nouveau_fence_update */ - return NVIF_NOTIFY_KEEP; + return ret; } void @@ -262,7 +278,10 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) if (!ret) { fence_get(&fence->base); spin_lock_irq(&fctx->lock); - nouveau_fence_update(chan, fctx); + + if (nouveau_fence_update(chan, fctx)) + nvif_notify_put(&fctx->notify); + list_add_tail(&fence->head, &fctx->pending); spin_unlock_irq(&fctx->lock); } @@ -276,13 +295,16 @@ nouveau_fence_done(struct nouveau_fence *fence) if (fence->base.ops == &nouveau_fence_ops_legacy || fence->base.ops == &nouveau_fence_ops_uevent) { struct nouveau_fence_chan *fctx = nouveau_fctx(fence); + struct nouveau_channel *chan; unsigned long flags; if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) return true; spin_lock_irqsave(&fctx->lock, flags); - nouveau_fence_update(fence->channel, fctx); + chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); + if (chan && nouveau_fence_update(chan, fctx)) + nvif_notify_put(&fctx->notify); spin_unlock_irqrestore(&fctx->lock, flags); } return fence_is_signaled(&fence->base); @@ -387,12 +409,18 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e if (fence && (!exclusive || !fobj || !fobj->shared_count)) { struct nouveau_channel *prev = NULL; + bool must_wait = true; f = nouveau_local_fence(fence, chan->drm); - if (f) - prev = f->channel; + if (f) { + rcu_read_lock(); + prev = rcu_dereference(f->channel); + if (prev && (prev == chan || fctx->sync(f, prev, chan) == 0)) + must_wait = false; + rcu_read_unlock(); + } - if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan)))) + if (must_wait) ret = fence_wait(fence, intr); return ret; @@ -403,19 +431,22 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e for (i = 0; i < fobj->shared_count && !ret; ++i) { struct nouveau_channel *prev = NULL; + bool must_wait = true; fence = rcu_dereference_protected(fobj->shared[i], reservation_object_held(resv)); f = nouveau_local_fence(fence, chan->drm); - if (f) - prev = f->channel; + if (f) { + rcu_read_lock(); + prev = rcu_dereference(f->channel); + if (prev && (prev == chan || fctx->sync(f, prev, chan) == 0)) + must_wait = false; + rcu_read_unlock(); + } - if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan)))) + if (must_wait) ret = fence_wait(fence, intr); - - if (ret) - break; } return ret; @@ -463,7 +494,7 @@ static const char *nouveau_fence_get_timeline_name(struct fence *f) struct nouveau_fence *fence = from_fence(f); struct nouveau_fence_chan *fctx = nouveau_fctx(fence); - return fence->channel ? fctx->name : "dead channel"; + return !fctx->dead ? fctx->name : "dead channel"; } /* @@ -476,9 +507,16 @@ static bool nouveau_fence_is_signaled(struct fence *f) { struct nouveau_fence *fence = from_fence(f); struct nouveau_fence_chan *fctx = nouveau_fctx(fence); - struct nouveau_channel *chan = fence->channel; + struct nouveau_channel *chan; + bool ret = false; + + rcu_read_lock(); + chan = rcu_dereference(fence->channel); + if (chan) + ret = (int)(fctx->read(chan) - fence->base.seqno) >= 0; + rcu_read_unlock(); - return (int)(fctx->read(chan) - fence->base.seqno) >= 0; + return ret; } static bool nouveau_fence_no_signaling(struct fence *f) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index 943b0b17b1fc..96e461c6f68f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -14,7 +14,7 @@ struct nouveau_fence { bool sysmem; - struct nouveau_channel *channel; + struct nouveau_channel __rcu *channel; unsigned long timeout; }; @@ -47,7 +47,7 @@ struct nouveau_fence_chan { char name[32]; struct nvif_notify notify; - int notify_ref; + int notify_ref, dead; }; struct nouveau_fence_priv { -- cgit v1.2.3-59-g8ed1b From 226d63a1addea8cbe8fc671978e62dc84927b046 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sun, 30 Nov 2014 12:56:18 -0500 Subject: drm/nouveau/gf116: remove copy1 engine Indications are that no GF116's actually have a copy engine there, but actually have the decompression engine. This engine can be made to do copies, but that should be done separately. Unclear why this didn't turn up on all GF116's, but perhaps the non-mobile ones came with enough VRAM to not trigger ttm migrations in test scenarios. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=85465 Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=59168 Cc: stable@vger.kernel.org Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/device/nvc0.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c index cd05677ad4b7..72a40f95d048 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c @@ -218,7 +218,6 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; -- cgit v1.2.3-59-g8ed1b From 8b62c8c6df08ca567c78afa51aa7bbc554cede06 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 2 Dec 2014 16:27:25 +1000 Subject: nouveau: move the hotplug ignore to correct place. Introduced in b440bde74f, however it was added to the wrong function in nouveau. https://bugzilla.kernel.org/show_bug.cgi?id=86011 Cc: Bjorn Helgaas CC: stable@vger.kernel.org # v3.15+ Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_drm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 57238076049f..62b97c4eef8d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -629,7 +629,6 @@ int nouveau_pmops_suspend(struct device *dev) pci_save_state(pdev); pci_disable_device(pdev); - pci_ignore_hotplug(pdev); pci_set_power_state(pdev, PCI_D3hot); return 0; } @@ -933,6 +932,7 @@ static int nouveau_pmops_runtime_suspend(struct device *dev) ret = nouveau_do_suspend(drm_dev, true); pci_save_state(pdev); pci_disable_device(pdev); + pci_ignore_hotplug(pdev); pci_set_power_state(pdev, PCI_D3cold); drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; return ret; -- cgit v1.2.3-59-g8ed1b From 86b276385c6a986872e4cd144f5940b156053c3f Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 27 Nov 2014 13:12:58 +0100 Subject: drm/radeon: sync all BOs involved in a CS v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not just the userspace relocs, otherwise we won't wait for a swapped out page tables to be swapped in again. v2: rebased on Alex current drm-fixes-3.18 Signed-off-by: Christian König Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_cs.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index a3e7aed7e680..6f377de099f9 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -251,22 +251,19 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority static int radeon_cs_sync_rings(struct radeon_cs_parser *p) { - int i, r = 0; + struct radeon_cs_reloc *reloc; + int r; - for (i = 0; i < p->nrelocs; i++) { + list_for_each_entry(reloc, &p->validated, tv.head) { struct reservation_object *resv; - if (!p->relocs[i].robj) - continue; - - resv = p->relocs[i].robj->tbo.resv; + resv = reloc->robj->tbo.resv; r = radeon_semaphore_sync_resv(p->rdev, p->ib.semaphore, resv, - p->relocs[i].tv.shared); - + reloc->tv.shared); if (r) - break; + return r; } - return r; + return 0; } /* XXX: note that this is called from the legacy UMS CS ioctl as well */ -- cgit v1.2.3-59-g8ed1b From a08b588e4199e4200d26027ffcdf3ab2fa906412 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Thu, 27 Nov 2014 18:00:54 +0900 Subject: drm/radeon: Ignore RADEON_GEM_GTT_WC on 32-bit x86 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=84627 Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_object.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 99a960a4f302..4c0d786d5c7a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -213,6 +213,13 @@ int radeon_bo_create(struct radeon_device *rdev, if (!(rdev->flags & RADEON_IS_PCIE)) bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); +#ifdef CONFIG_X86_32 + /* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit + * See https://bugs.freedesktop.org/show_bug.cgi?id=84627 + */ + bo->flags &= ~RADEON_GEM_GTT_WC; +#endif + radeon_ttm_placement_from_domain(bo, domain); /* Kernel allocation are uninterruptible */ down_read(&rdev->pm.mclk_lock); -- cgit v1.2.3-59-g8ed1b From f5475cc43c899e33098d4db44b7c5e710f16589d Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Thu, 27 Nov 2014 16:57:21 +0100 Subject: drm/radeon: kernel panic in drm_calc_vbltimestamp_from_scanoutpos with 3.18.0-rc6 I was unable too boot 3.18.0-rc6 because of the following kernel panic in drm_calc_vbltimestamp_from_scanoutpos(): [drm] Initialized drm 1.1.0 20060810 [drm] radeon kernel modesetting enabled. [drm] initializing kernel modesetting (RV100 0x1002:0x515E 0x15D9:0x8080). [drm] register mmio base: 0xC8400000 [drm] register mmio size: 65536 radeon 0000:0b:01.0: VRAM: 128M 0x00000000D0000000 - 0x00000000D7FFFFFF (16M used) radeon 0000:0b:01.0: GTT: 512M 0x00000000B0000000 - 0x00000000CFFFFFFF [drm] Detected VRAM RAM=128M, BAR=128M [drm] RAM width 16bits DDR [TTM] Zone kernel: Available graphics memory: 3829346 kiB [TTM] Zone dma32: Available graphics memory: 2097152 kiB [TTM] Initializing pool allocator [TTM] Initializing DMA pool allocator [drm] radeon: 16M of VRAM memory ready [drm] radeon: 512M of GTT memory ready. [drm] GART: num cpu pages 131072, num gpu pages 131072 [drm] PCI GART of 512M enabled (table at 0x0000000037880000). radeon 0000:0b:01.0: WB disabled radeon 0000:0b:01.0: fence driver on ring 0 use gpu addr 0x00000000b0000000 and cpu addr 0xffff8800bbbfa000 [drm] Supports vblank timestamp caching Rev 2 (21.10.2013). [drm] Driver supports precise vblank timestamp query. [drm] radeon: irq initialized. [drm] Loading R100 Microcode radeon 0000:0b:01.0: Direct firmware load for radeon/R100_cp.bin failed with error -2 radeon_cp: Failed to load firmware "radeon/R100_cp.bin" [drm:r100_cp_init] *ERROR* Failed to load firmware! radeon 0000:0b:01.0: failed initializing CP (-2). radeon 0000:0b:01.0: Disabling GPU acceleration [drm] radeon: cp finalized BUG: unable to handle kernel NULL pointer dereference at 000000000000025c IP: [] drm_calc_vbltimestamp_from_scanoutpos+0x4b/0x320 PGD 0 Oops: 0000 [#1] SMP Modules linked in: CPU: 1 PID: 1 Comm: swapper/0 Not tainted 3.18.0-rc6-4-default #2649 Hardware name: Supermicro X7DB8/X7DB8, BIOS 6.00 07/26/2006 task: ffff880234da2010 ti: ffff880234da4000 task.ti: ffff880234da4000 RIP: 0010:[] [] drm_calc_vbltimestamp_from_scanoutpos+0x4b/0x320 RSP: 0000:ffff880234da7918 EFLAGS: 00010086 RAX: ffffffff81557890 RBX: 0000000000000000 RCX: ffff880234da7a48 RDX: ffff880234da79f4 RSI: 0000000000000000 RDI: ffff880232e15000 RBP: ffff880234da79b8 R08: 0000000000000000 R09: 0000000000000000 R10: 000000000000000a R11: 0000000000000001 R12: ffff880232dda1c0 R13: ffff880232e1518c R14: 0000000000000292 R15: ffff880232e15000 FS: 0000000000000000(0000) GS:ffff88023fc40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 000000000000025c CR3: 0000000002014000 CR4: 00000000000007e0 Stack: ffff880234da79d8 0000000000000286 ffff880232dcbc00 0000000000002480 ffff880234da7958 0000000000000296 ffff880234da7998 ffffffff8151b51d ffff880234da7a48 0000000032dcbeb0 ffff880232dcbc00 ffff880232dcbc58 Call Trace: [] ? drm_vma_offset_remove+0x1d/0x110 [] radeon_get_vblank_timestamp_kms+0x38/0x60 [] ? ttm_bo_release_list+0xba/0x180 [] drm_get_last_vbltimestamp+0x41/0x70 [] vblank_disable_and_save+0x73/0x1d0 [] ? try_to_del_timer_sync+0x4f/0x70 [] drm_vblank_cleanup+0x65/0xa0 [] radeon_irq_kms_fini+0x1a/0x70 [] r100_init+0x26e/0x410 [] radeon_device_init+0x7ae/0xb50 [] radeon_driver_load_kms+0x8f/0x210 [] drm_dev_register+0xb5/0x110 [] drm_get_pci_dev+0x8f/0x200 [] radeon_pci_probe+0xad/0xe0 [] local_pci_probe+0x45/0xa0 [] pci_device_probe+0xd1/0x130 [] driver_probe_device+0x12d/0x3e0 [] __driver_attach+0x9b/0xa0 [] ? __device_attach+0x40/0x40 [] bus_for_each_dev+0x63/0xa0 [] driver_attach+0x1e/0x20 [] bus_add_driver+0x180/0x240 [] driver_register+0x64/0xf0 [] __pci_register_driver+0x4c/0x50 [] drm_pci_init+0xf5/0x120 [] ? ttm_init+0x6a/0x6a [] radeon_init+0x97/0xb5 [] do_one_initcall+0xbc/0x1f0 [] ? __wake_up+0x48/0x60 [] kernel_init_freeable+0x18a/0x215 [] ? initcall_blacklist+0xc0/0xc0 [] ? rest_init+0x80/0x80 [] kernel_init+0xe/0xf0 [] ret_from_fork+0x7c/0xb0 [] ? rest_init+0x80/0x80 Code: 45 ac 0f 88 a8 01 00 00 3b b7 d0 01 00 00 49 89 ff 0f 83 99 01 00 00 48 8b 47 20 48 8b 80 88 00 00 00 48 85 c0 0f 84 cd 01 00 00 <41> 8b b1 5c 02 00 00 41 8b 89 58 02 00 00 89 75 98 41 8b b1 60 RIP [] drm_calc_vbltimestamp_from_scanoutpos+0x4b/0x320 RSP CR2: 000000000000025c ---[ end trace ad2c0aadf48e2032 ]--- Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000009 It has helped me to add a NULL pointer check that was suggested at http://lists.freedesktop.org/archives/dri-devel/2014-October/070663.html I am not familiar with the code. But the change looks sane and we need something fast at this stage of 3.18 development. Suggested-by: Helge Deller Signed-off-by: Petr Mladek Tested-by: Petr Mladek Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_kms.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 8309b11e674d..03586763ee86 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -795,6 +795,8 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, /* Get associated drm_crtc: */ drmcrtc = &rdev->mode_info.crtcs[crtc]->base; + if (!drmcrtc) + return -EINVAL; /* Helper routine in DRM core does all the work: */ return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, -- cgit v1.2.3-59-g8ed1b From 8d609725d4357f499e2103e46011308b32f53513 Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Tue, 25 Nov 2014 20:28:24 -0600 Subject: xen-netfront: Remove BUGs on paged skb data which crosses a page boundary These BUGs can be erroneously triggered by frags which refer to tail pages within a compound page. The data in these pages may overrun the hardware page while still being contained within the compound page, but since compound_order() evaluates to 0 for tail pages the assertion fails. The code already iterates through subsequent pages correctly in this scenario, so the BUGs are unnecessary and can be removed. Fixes: f36c374782e4 ("xen/netfront: handle compound page fragments on transmit") Cc: # 3.7+ Signed-off-by: Seth Forshee Reviewed-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index cca871346a0f..ece8d1804d13 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -496,9 +496,6 @@ static void xennet_make_frags(struct sk_buff *skb, struct netfront_queue *queue, len = skb_frag_size(frag); offset = frag->page_offset; - /* Data must not cross a page boundary. */ - BUG_ON(len + offset > PAGE_SIZE<> PAGE_SHIFT; offset &= ~PAGE_MASK; @@ -506,8 +503,6 @@ static void xennet_make_frags(struct sk_buff *skb, struct netfront_queue *queue, while (len > 0) { unsigned long bytes; - BUG_ON(offset >= PAGE_SIZE); - bytes = PAGE_SIZE - offset; if (bytes > len) bytes = len; -- cgit v1.2.3-59-g8ed1b From 4c2d518695338801110bc166eece6aa02822b0b4 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 28 Nov 2014 18:35:14 +0530 Subject: cxgb4: Fill in supported link mode for SFP modules Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 8520d5529df8..279873cb6e3a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2442,9 +2442,13 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps) SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | SUPPORTED_10000baseKX4_Full; else if (type == FW_PORT_TYPE_FIBER_XFI || - type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP) + type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP) { v |= SUPPORTED_FIBRE; - else if (type == FW_PORT_TYPE_BP40_BA) + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + } else if (type == FW_PORT_TYPE_BP40_BA) v |= SUPPORTED_40000baseSR4_Full; if (caps & FW_PORT_CAP_ANEG) -- cgit v1.2.3-59-g8ed1b From 92788ac1eb06e69a822de45e2a8a63fa45eb5be2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 2 Dec 2014 15:59:31 -0800 Subject: drivers/input/evdev.c: don't kfree() a vmalloc address If kzalloc() failed and then evdev_open_device() fails, evdev_open() will pass a vmalloc'ed pointer to kfree. This might fix https://bugzilla.kernel.org/show_bug.cgi?id=88401, where there was a crash in kfree(). Reported-by: Christian Casteyde Belatedly-Acked-by: Dmitry Torokhov Cc: Henrik Rydberg Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/input/evdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index bc203485716d..8afa28e4570e 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -421,7 +421,7 @@ static int evdev_open(struct inode *inode, struct file *file) err_free_client: evdev_detach_client(evdev, client); - kfree(client); + kvfree(client); return error; } -- cgit v1.2.3-59-g8ed1b From 8961b1940200ac5e91bee1c1bc69086365e1b7c9 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 30 Nov 2014 11:49:36 +0100 Subject: pxa168: close race between napi and irq activation In pxa168_eth_open() the irqs are enabled before napi. This opens a tiny time window in which the irq handler is processed, disables irqs but then is not able to schedule the not yet activated napi, leaving irqs disabled forever (since irqs are reenabled in napi poll function). Fix this race by activating napi before irqs are activated. Signed-off-by: Lino Sanfilippo Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/pxa168_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index c3b209cd0660..a3e394c47819 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -1153,8 +1153,8 @@ static int pxa168_eth_open(struct net_device *dev) pep->rx_used_desc_q = 0; pep->rx_curr_desc_q = 0; netif_carrier_off(dev); - eth_port_start(dev); napi_enable(&pep->napi); + eth_port_start(dev); return 0; out_free_rx_skb: rxq_deinit(dev); -- cgit v1.2.3-59-g8ed1b From 6276288a4c1f755e6b65b0f2e1177855b0340e31 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 30 Nov 2014 12:51:31 +0100 Subject: skge: Unmask interrupts in case of spurious interrupts In case of a spurious interrupt dont forget to reenable the interrupts that have been masked by reading the interrupt source register. Signed-off-by: Lino Sanfilippo Acked-by: Mirko Lindner Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/skge.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c index 264eab7d3b26..7173836fe361 100644 --- a/drivers/net/ethernet/marvell/skge.c +++ b/drivers/net/ethernet/marvell/skge.c @@ -3433,10 +3433,9 @@ static irqreturn_t skge_intr(int irq, void *dev_id) if (status & IS_HW_ERR) skge_error_irq(hw); - +out: skge_write32(hw, B0_IMSK, hw->intr_mask); skge_read32(hw, B0_IMSK); -out: spin_unlock(&hw->hw_lock); return IRQ_RETVAL(handled); -- cgit v1.2.3-59-g8ed1b From ea589e9b7838f5d1c3d4998f9fe08854872187fc Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 30 Nov 2014 12:56:51 +0100 Subject: sky2: avoid pci write posting after disabling irqs In sky2_change_mtu setting B0_IMSK to 0 may be delayed due to PCI write posting which could result in irqs being still active when synchronize_irq is called. Since we are not prepared to handle any further irqs after synchronize_irq (our resources are freed after that) force the write by a consecutive read from the same register. Similar situation in sky2_all_down: Here we disabled irqs by a write to B0_IMSK but did not ensure that this write took place before synchronize_irq. Fix that too. Signed-off-by: Lino Sanfilippo Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/sky2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index bd3366267039..f14544c8d73f 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -2419,6 +2419,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) imask = sky2_read32(hw, B0_IMSK); sky2_write32(hw, B0_IMSK, 0); + sky2_read32(hw, B0_IMSK); dev->trans_start = jiffies; /* prevent tx timeout */ napi_disable(&hw->napi); @@ -3487,8 +3488,8 @@ static void sky2_all_down(struct sky2_hw *hw) int i; if (hw->flags & SKY2_HW_IRQ_SETUP) { - sky2_read32(hw, B0_IMSK); sky2_write32(hw, B0_IMSK, 0); + sky2_read32(hw, B0_IMSK); synchronize_irq(hw->pdev->irq); napi_disable(&hw->napi); -- cgit v1.2.3-59-g8ed1b From dc50ddcd4c58a5a0226038307d6ef884bec9f8c2 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 28 Nov 2014 14:08:48 +0100 Subject: can: peak_usb: fix memset() usage This patchs fixes a misplaced call to memset() that fills the request buffer with 0. The problem was with sending PCAN_USBPRO_REQ_FCT requests, the content set by the caller was thus lost. With this patch, the memory area is zeroed only when requesting info from the device. Signed-off-by: Stephane Grosjean Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 263dd921edc4..f7f796a2c50b 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -333,8 +333,6 @@ static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, if (!(dev->state & PCAN_USB_STATE_CONNECTED)) return 0; - memset(req_addr, '\0', req_size); - req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER; switch (req_id) { @@ -345,6 +343,7 @@ static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, default: p = usb_rcvctrlpipe(dev->udev, 0); req_type |= USB_DIR_IN; + memset(req_addr, '\0', req_size); break; } -- cgit v1.2.3-59-g8ed1b From af35d0f1cce7a990286e2b94c260a2c2d2a0e4b0 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 28 Nov 2014 13:49:10 +0100 Subject: can: peak_usb: fix cleanup sequence order in case of error during init This patch sets the correct reverse sequence order to the instructions set to run, when any failure occurs during the initialization steps. It also adds the missing unregistration call of the can device if the failure appears after having been registered. Signed-off-by: Stephane Grosjean Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 644e6ab8a489..dc807e10f802 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -735,7 +735,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); if (!dev->cmd_buf) { err = -ENOMEM; - goto lbl_set_intf_data; + goto lbl_free_candev; } dev->udev = usb_dev; @@ -775,7 +775,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, err = register_candev(netdev); if (err) { dev_err(&intf->dev, "couldn't register CAN device: %d\n", err); - goto lbl_free_cmd_buf; + goto lbl_restore_intf_data; } if (dev->prev_siblings) @@ -788,14 +788,14 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, if (dev->adapter->dev_init) { err = dev->adapter->dev_init(dev); if (err) - goto lbl_free_cmd_buf; + goto lbl_unregister_candev; } /* set bus off */ if (dev->adapter->dev_set_bus) { err = dev->adapter->dev_set_bus(dev, 0); if (err) - goto lbl_free_cmd_buf; + goto lbl_unregister_candev; } /* get device number early */ @@ -807,11 +807,14 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, return 0; -lbl_free_cmd_buf: - kfree(dev->cmd_buf); +lbl_unregister_candev: + unregister_candev(netdev); -lbl_set_intf_data: +lbl_restore_intf_data: usb_set_intfdata(intf, dev->prev_siblings); + kfree(dev->cmd_buf); + +lbl_free_candev: free_candev(netdev); return err; -- cgit v1.2.3-59-g8ed1b From 62bc24f67abda56e486735706be6a4dea60fdb4c Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 5 Dec 2014 14:11:09 +0100 Subject: can: peak_usb: fix multi-byte values endianess This patch fixes the endianess definition as well as the usage of the multi-byte fields in the data structures exchanged with the PEAK-System USB adapters. By fixing the endianess, this patch also fixes the wrong usage of a 32-bits local variable for handling the error status 16-bits field, in function pcan_usb_pro_handle_error(). Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb.c | 14 ++++---- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 3 +- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 20 ++++++------ drivers/net/can/usb/peak_usb/pcan_usb_pro.h | 48 ++++++++++++++-------------- 4 files changed, 43 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 925ab8ec9329..4e1659d07979 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -316,7 +316,7 @@ static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number) if (err) { netdev_err(dev->netdev, "getting serial failure: %d\n", err); } else if (serial_number) { - u32 tmp32; + __le32 tmp32; memcpy(&tmp32, args, 4); *serial_number = le32_to_cpu(tmp32); @@ -347,7 +347,7 @@ static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id) */ static int pcan_usb_update_ts(struct pcan_usb_msg_context *mc) { - u16 tmp16; + __le16 tmp16; if ((mc->ptr+2) > mc->end) return -EINVAL; @@ -371,7 +371,7 @@ static int pcan_usb_decode_ts(struct pcan_usb_msg_context *mc, u8 first_packet) { /* only 1st packet supplies a word timestamp */ if (first_packet) { - u16 tmp16; + __le16 tmp16; if ((mc->ptr + 2) > mc->end) return -EINVAL; @@ -614,7 +614,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) return -ENOMEM; if (status_len & PCAN_USB_STATUSLEN_EXT_ID) { - u32 tmp32; + __le32 tmp32; if ((mc->ptr + 4) > mc->end) goto decode_failed; @@ -622,9 +622,9 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) memcpy(&tmp32, mc->ptr, 4); mc->ptr += 4; - cf->can_id = le32_to_cpu(tmp32 >> 3) | CAN_EFF_FLAG; + cf->can_id = (le32_to_cpu(tmp32) >> 3) | CAN_EFF_FLAG; } else { - u16 tmp16; + __le16 tmp16; if ((mc->ptr + 2) > mc->end) goto decode_failed; @@ -632,7 +632,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) memcpy(&tmp16, mc->ptr, 2); mc->ptr += 2; - cf->can_id = le16_to_cpu(tmp16 >> 5); + cf->can_id = le16_to_cpu(tmp16) >> 5; } cf->can_dlc = get_can_dlc(rec_len); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index dc807e10f802..c62f48a1161d 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -856,6 +856,7 @@ static int peak_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *usb_dev = interface_to_usbdev(intf); + const u16 usb_id_product = le16_to_cpu(usb_dev->descriptor.idProduct); struct peak_usb_adapter *peak_usb_adapter, **pp; int i, err = -ENOMEM; @@ -863,7 +864,7 @@ static int peak_usb_probe(struct usb_interface *intf, /* get corresponding PCAN-USB adapter */ for (pp = peak_usb_adapters_list; *pp; pp++) - if ((*pp)->device_id == usb_dev->descriptor.idProduct) + if ((*pp)->device_id == usb_id_product) break; peak_usb_adapter = *pp; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index f7f796a2c50b..4cfa3b8605b1 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -78,8 +78,8 @@ struct pcan_usb_pro_msg { int rec_buffer_size; int rec_buffer_len; union { - u16 *rec_cnt_rd; - u32 *rec_cnt; + __le16 *rec_cnt_rd; + __le32 *rec_cnt; u8 *rec_buffer; } u; }; @@ -155,7 +155,7 @@ static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, u8 id, ...) *pc++ = va_arg(ap, int); *pc++ = va_arg(ap, int); *pc++ = va_arg(ap, int); - *(u32 *)pc = cpu_to_le32(va_arg(ap, u32)); + *(__le32 *)pc = cpu_to_le32(va_arg(ap, u32)); pc += 4; memcpy(pc, va_arg(ap, int *), i); pc += i; @@ -165,7 +165,7 @@ static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, u8 id, ...) case PCAN_USBPRO_GETDEVID: *pc++ = va_arg(ap, int); pc += 2; - *(u32 *)pc = cpu_to_le32(va_arg(ap, u32)); + *(__le32 *)pc = cpu_to_le32(va_arg(ap, u32)); pc += 4; break; @@ -173,21 +173,21 @@ static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, u8 id, ...) case PCAN_USBPRO_SETBUSACT: case PCAN_USBPRO_SETSILENT: *pc++ = va_arg(ap, int); - *(u16 *)pc = cpu_to_le16(va_arg(ap, int)); + *(__le16 *)pc = cpu_to_le16(va_arg(ap, int)); pc += 2; break; case PCAN_USBPRO_SETLED: *pc++ = va_arg(ap, int); - *(u16 *)pc = cpu_to_le16(va_arg(ap, int)); + *(__le16 *)pc = cpu_to_le16(va_arg(ap, int)); pc += 2; - *(u32 *)pc = cpu_to_le32(va_arg(ap, u32)); + *(__le32 *)pc = cpu_to_le32(va_arg(ap, u32)); pc += 4; break; case PCAN_USBPRO_SETTS: pc++; - *(u16 *)pc = cpu_to_le16(va_arg(ap, int)); + *(__le16 *)pc = cpu_to_le16(va_arg(ap, int)); pc += 2; break; @@ -200,7 +200,7 @@ static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, u8 id, ...) len = pc - pm->rec_ptr; if (len > 0) { - *pm->u.rec_cnt = cpu_to_le32(*pm->u.rec_cnt+1); + *pm->u.rec_cnt = cpu_to_le32(le32_to_cpu(*pm->u.rec_cnt) + 1); *pm->rec_ptr = id; pm->rec_ptr = pc; @@ -571,7 +571,7 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, struct pcan_usb_pro_rxstatus *er) { - const u32 raw_status = le32_to_cpu(er->status); + const u16 raw_status = le16_to_cpu(er->status); const unsigned int ctrl_idx = (er->channel >> 4) & 0x0f; struct peak_usb_device *dev = usb_if->dev[ctrl_idx]; struct net_device *netdev = dev->netdev; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h index 32275af547e0..837cee267132 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h @@ -33,27 +33,27 @@ /* PCAN_USBPRO_INFO_BL vendor request record type */ struct __packed pcan_usb_pro_blinfo { - u32 ctrl_type; + __le32 ctrl_type; u8 version[4]; u8 day; u8 month; u8 year; u8 dummy; - u32 serial_num_hi; - u32 serial_num_lo; - u32 hw_type; - u32 hw_rev; + __le32 serial_num_hi; + __le32 serial_num_lo; + __le32 hw_type; + __le32 hw_rev; }; /* PCAN_USBPRO_INFO_FW vendor request record type */ struct __packed pcan_usb_pro_fwinfo { - u32 ctrl_type; + __le32 ctrl_type; u8 version[4]; u8 day; u8 month; u8 year; u8 dummy; - u32 fw_type; + __le32 fw_type; }; /* @@ -80,46 +80,46 @@ struct __packed pcan_usb_pro_fwinfo { struct __packed pcan_usb_pro_btr { u8 data_type; u8 channel; - u16 dummy; - u32 CCBT; + __le16 dummy; + __le32 CCBT; }; struct __packed pcan_usb_pro_busact { u8 data_type; u8 channel; - u16 onoff; + __le16 onoff; }; struct __packed pcan_usb_pro_silent { u8 data_type; u8 channel; - u16 onoff; + __le16 onoff; }; struct __packed pcan_usb_pro_filter { u8 data_type; u8 dummy; - u16 filter_mode; + __le16 filter_mode; }; struct __packed pcan_usb_pro_setts { u8 data_type; u8 dummy; - u16 mode; + __le16 mode; }; struct __packed pcan_usb_pro_devid { u8 data_type; u8 channel; - u16 dummy; - u32 serial_num; + __le16 dummy; + __le32 serial_num; }; struct __packed pcan_usb_pro_setled { u8 data_type; u8 channel; - u16 mode; - u32 timeout; + __le16 mode; + __le32 timeout; }; struct __packed pcan_usb_pro_rxmsg { @@ -127,8 +127,8 @@ struct __packed pcan_usb_pro_rxmsg { u8 client; u8 flags; u8 len; - u32 ts32; - u32 id; + __le32 ts32; + __le32 id; u8 data[8]; }; @@ -141,15 +141,15 @@ struct __packed pcan_usb_pro_rxmsg { struct __packed pcan_usb_pro_rxstatus { u8 data_type; u8 channel; - u16 status; - u32 ts32; - u32 err_frm; + __le16 status; + __le32 ts32; + __le32 err_frm; }; struct __packed pcan_usb_pro_rxts { u8 data_type; u8 dummy[3]; - u32 ts64[2]; + __le32 ts64[2]; }; struct __packed pcan_usb_pro_txmsg { @@ -157,7 +157,7 @@ struct __packed pcan_usb_pro_txmsg { u8 client; u8 flags; u8 len; - u32 id; + __le32 id; u8 data[8]; }; -- cgit v1.2.3-59-g8ed1b From aebea2ba0f7495e1a1c9ea5e753d146cb2f6b845 Mon Sep 17 00:00:00 2001 From: willy tarreau Date: Tue, 2 Dec 2014 08:13:04 +0100 Subject: net: mvneta: fix Tx interrupt delay The mvneta driver sets the amount of Tx coalesce packets to 16 by default. Normally that does not cause any trouble since the driver uses a much larger Tx ring size (532 packets). But some sockets might run with very small buffers, much smaller than the equivalent of 16 packets. This is what ping is doing for example, by setting SNDBUF to 324 bytes rounded up to 2kB by the kernel. The problem is that there is no documented method to force a specific packet to emit an interrupt (eg: the last of the ring) nor is it possible to make the NIC emit an interrupt after a given delay. In this case, it causes trouble, because when ping sends packets over its raw socket, the few first packets leave the system, and the first 15 packets will be emitted without an IRQ being generated, so without the skbs being freed. And since the socket's buffer is small, there's no way to reach that amount of packets, and the ping ends up with "send: no buffer available" after sending 6 packets. Running with 3 instances of ping in parallel is enough to hide the problem, because with 6 packets per instance, that's 18 packets total, which is enough to grant a Tx interrupt before all are sent. The original driver in the LSP kernel worked around this design flaw by using a software timer to clean up the Tx descriptors. This timer was slow and caused terrible network performance on some Tx-bound workloads (such as routing) but was enough to make tools like ping work correctly. Instead here, we simply set the packet counts before interrupt to 1. This ensures that each packet sent will produce an interrupt. NAPI takes care of coalescing interrupts since the interrupt is disabled once generated. No measurable performance impact nor CPU usage were observed on small nor large packets, including when saturating the link on Tx, and this fixes tools like ping which rely on too small a send buffer. If one wants to increase this value for certain workloads where it is safe to do so, "ethtool -C $dev tx-frames" will override this default setting. This fix needs to be applied to stable kernels starting with 3.10. Tested-By: Maggie Mae Roxas Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index ade067de1689..bb4afe6ccc85 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -216,7 +216,7 @@ /* Various constants */ /* Coalescing */ -#define MVNETA_TXDONE_COAL_PKTS 16 +#define MVNETA_TXDONE_COAL_PKTS 1 #define MVNETA_RX_COAL_PKTS 32 #define MVNETA_RX_COAL_USEC 100 -- cgit v1.2.3-59-g8ed1b From 5f478b41033606d325e420df693162e2524c2b94 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 2 Dec 2014 04:30:59 -0800 Subject: net: mvneta: fix race condition in mvneta_tx() mvneta_tx() dereferences skb to get skb->len too late, as hardware might have completed the transmit and TX completion could have freed the skb from another cpu. Fixes: 71f6d1b31fb1 ("net: mvneta: replace Tx timer with a real interrupt") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index bb4afe6ccc85..67a84cfaefa1 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1721,6 +1721,7 @@ static int mvneta_tx(struct sk_buff *skb, struct net_device *dev) u16 txq_id = skb_get_queue_mapping(skb); struct mvneta_tx_queue *txq = &pp->txqs[txq_id]; struct mvneta_tx_desc *tx_desc; + int len = skb->len; int frags = 0; u32 tx_cmd; @@ -1788,7 +1789,7 @@ out: u64_stats_update_begin(&stats->syncp); stats->tx_packets++; - stats->tx_bytes += skb->len; + stats->tx_bytes += len; u64_stats_update_end(&stats->syncp); } else { dev->stats.tx_dropped++; -- cgit v1.2.3-59-g8ed1b From 03ccc4c0a9dac4b94f4e07cd0b7a9a1cb142ed36 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 2 Dec 2014 18:16:48 -0600 Subject: amd-xgbe: Do not clear interrupt indicator The interrupt value within the xgbe_ring_data structure is used as an indicator of which Rx descriptor should have the INTE bit set to generate an interrupt when that Rx descriptor is used. This bit was mistakenly cleared in the xgbe_unmap_rdata function, effectively nullifying the ethtool rx-frames support. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c index 6fc5da01437d..43b7d2e948f7 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -356,7 +356,6 @@ static void xgbe_unmap_skb(struct xgbe_prv_data *pdata, rdata->tso_header = 0; rdata->len = 0; - rdata->interrupt = 0; rdata->mapped_as_page = 0; if (rdata->state_saved) { -- cgit v1.2.3-59-g8ed1b From c153031773887fca473d25a2854cc37bd946c010 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 2 Dec 2014 18:16:54 -0600 Subject: amd-xgbe: Associate Tx SKB with proper ring descriptor The SKB for a Tx packet is associated with an xgbe_ring_data structure in the xgbe_map_tx_skb function. However, it is being saved in the structure after the last structure used when the SKB is mapped. Use the last used structure to save the SKB value. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c index 43b7d2e948f7..b15551bad7fa 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -480,7 +480,11 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb) } } - /* Save the skb address in the last entry */ + /* Save the skb address in the last entry. We always have some data + * that has been mapped so rdata is always advanced past the last + * piece of mapped data - use the entry pointed to by cur_index - 1. + */ + rdata = XGBE_GET_DESC_DATA(ring, cur_index - 1); rdata->skb = skb; /* Save the number of descriptor entries used */ -- cgit v1.2.3-59-g8ed1b From 79af221d67e7e7502d740d57eebd93ddd66cffc4 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 3 Dec 2014 11:49:50 +0530 Subject: cxgb4: Add a check for flashing FW using ethtool Don't let T4 firmware flash on a T5 adapter and vice-versa using ethtool Based on original work by Casey Leedom Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 163a2a14948c..c623f1fc2e3d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -1131,6 +1131,27 @@ unsigned int t4_flash_cfg_addr(struct adapter *adapter) return FLASH_CFG_START; } +/* Return TRUE if the specified firmware matches the adapter. I.e. T4 + * firmware for T4 adapters, T5 firmware for T5 adapters, etc. We go ahead + * and emit an error message for mismatched firmware to save our caller the + * effort ... + */ +static bool t4_fw_matches_chip(const struct adapter *adap, + const struct fw_hdr *hdr) +{ + /* The expression below will return FALSE for any unsupported adapter + * which will keep us "honest" in the future ... + */ + if ((is_t4(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T4) || + (is_t5(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T5)) + return true; + + dev_err(adap->pdev_dev, + "FW image (%d) is not suitable for this adapter (%d)\n", + hdr->chip, CHELSIO_CHIP_VERSION(adap->params.chip)); + return false; +} + /** * t4_load_fw - download firmware * @adap: the adapter @@ -1170,6 +1191,8 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) FW_MAX_SIZE); return -EFBIG; } + if (!t4_fw_matches_chip(adap, hdr)) + return -EINVAL; for (csum = 0, i = 0; i < size / sizeof(csum); i++) csum += ntohl(p[i]); @@ -3080,6 +3103,9 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data; int reset, ret; + if (!t4_fw_matches_chip(adap, fw_hdr)) + return -EINVAL; + ret = t4_fw_halt(adap, mbox, force); if (ret < 0 && !force) return ret; -- cgit v1.2.3-59-g8ed1b From c5ac97042aea4c358c5124119fdb98cc79bb9144 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 3 Dec 2014 12:29:31 +0530 Subject: cxgb4: Update FW version string to match FW binary version 1.12.25.0 Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 3c481b260745..0514b7431746 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -50,13 +50,13 @@ #include "cxgb4_uld.h" #define T4FW_VERSION_MAJOR 0x01 -#define T4FW_VERSION_MINOR 0x0B -#define T4FW_VERSION_MICRO 0x1B +#define T4FW_VERSION_MINOR 0x0C +#define T4FW_VERSION_MICRO 0x19 #define T4FW_VERSION_BUILD 0x00 #define T5FW_VERSION_MAJOR 0x01 -#define T5FW_VERSION_MINOR 0x0B -#define T5FW_VERSION_MICRO 0x1B +#define T5FW_VERSION_MINOR 0x0C +#define T5FW_VERSION_MICRO 0x19 #define T5FW_VERSION_BUILD 0x00 #define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__) -- cgit v1.2.3-59-g8ed1b From 9b8d16cf81f9d5f7284aee55050fa6753535101b Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 3 Dec 2014 12:32:58 +0100 Subject: stmmac: fix max coal timer parameter This patch is to fix the max coalesce timer setting that can be provided by ethtool. The default value (STMMAC_COAL_TX_TIMER) was used in the set_coalesce helper instead of the max one (STMMAC_MAX_COAL_TX_TICK, so defined but not used). Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 3a08a1f78c73..771cda2a48b2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -696,7 +696,7 @@ static int stmmac_set_coalesce(struct net_device *dev, (ec->tx_max_coalesced_frames == 0)) return -EINVAL; - if ((ec->tx_coalesce_usecs > STMMAC_COAL_TX_TIMER) || + if ((ec->tx_coalesce_usecs > STMMAC_MAX_COAL_TX_TICK) || (ec->tx_max_coalesced_frames > STMMAC_TX_MAX_FRAMES)) return -EINVAL; -- cgit v1.2.3-59-g8ed1b From c9cdc74dfab260ebc37190bc359f99d83fc7104f Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 3 Dec 2014 14:15:20 +0200 Subject: bnx2x: Limit 1G link enforcement Change 1G-SFP module detection by verifying not only that it's not compliant with 10G-Ethernet, but also that it's 1G-ethernet compliant. Signed-off-by: Yaniv Rosner Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 549549eaf580..778e4cd32571 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -8119,10 +8119,11 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy, case SFP_EEPROM_CON_TYPE_VAL_LC: case SFP_EEPROM_CON_TYPE_VAL_RJ45: check_limiting_mode = 1; - if ((val[SFP_EEPROM_10G_COMP_CODE_ADDR] & + if (((val[SFP_EEPROM_10G_COMP_CODE_ADDR] & (SFP_EEPROM_10G_COMP_CODE_SR_MASK | SFP_EEPROM_10G_COMP_CODE_LR_MASK | - SFP_EEPROM_10G_COMP_CODE_LRM_MASK)) == 0) { + SFP_EEPROM_10G_COMP_CODE_LRM_MASK)) == 0) && + (val[SFP_EEPROM_1G_COMP_CODE_ADDR] != 0)) { DP(NETIF_MSG_LINK, "1G SFP module detected\n"); phy->media_type = ETH_PHY_SFP_1G_FIBER; if (phy->req_line_speed != SPEED_1000) { -- cgit v1.2.3-59-g8ed1b From 244d62be91ddcea55ec6d456dbb7f71d411d21f0 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Thu, 4 Dec 2014 11:52:35 -0600 Subject: amd-xgbe: Prevent Tx cleanup stall When performing Tx cleanup, the dirty index counter is compared to the current index counter as one of the tests used to determine when to stop cleanup. The "less than" test will fail when the current index counter rolls over to zero causing cleanup to never occur again. Update the test to a "not equal" to avoid this situation. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 2349ea970255..d0e35302410f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1554,7 +1554,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) spin_lock_irqsave(&ring->lock, flags); while ((processed < XGBE_TX_DESC_MAX_PROC) && - (ring->dirty < ring->cur)) { + (ring->dirty != ring->cur)) { rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); rdesc = rdata->rdesc; -- cgit v1.2.3-59-g8ed1b From 51de7bb9ab430f1db4d07e2b5e0711c48cb5a7e6 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Fri, 5 Dec 2014 11:35:46 -0800 Subject: bnx2x: Implement ndo_gso_check() Use vxlan_gso_check() to advertise offload support for this NIC. Signed-off-by: Joe Stringer Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 74fbf9ea7bd8..893cdb6a423e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -12550,6 +12551,11 @@ static int bnx2x_get_phys_port_id(struct net_device *netdev, return 0; } +static bool bnx2x_gso_check(struct sk_buff *skb, struct net_device *dev) +{ + return vxlan_gso_check(skb); +} + static const struct net_device_ops bnx2x_netdev_ops = { .ndo_open = bnx2x_open, .ndo_stop = bnx2x_close, @@ -12581,6 +12587,7 @@ static const struct net_device_ops bnx2x_netdev_ops = { #endif .ndo_get_phys_port_id = bnx2x_get_phys_port_id, .ndo_set_vf_link_state = bnx2x_set_vf_link_state, + .ndo_gso_check = bnx2x_gso_check, }; static int bnx2x_set_coherency_mask(struct bnx2x *bp) -- cgit v1.2.3-59-g8ed1b From f15650b7f94879667f253bc32de7431c1baf2d6e Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 9 Dec 2014 11:47:04 +0000 Subject: netback: don't store invalid vif pointer When xenvif_alloc() fails, it returns a non-NULL error indicator. To avoid eventual races, we shouldn't store that into struct backend_info as readers of it only check for NULL. Signed-off-by: Jan Beulich Acked-by: Ian Campbell Signed-off-by: David S. Miller --- drivers/net/xen-netback/xenbus.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index fab0d4b42f58..d44cd19169bd 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -404,6 +404,7 @@ static int backend_create_xenvif(struct backend_info *be) int err; long handle; struct xenbus_device *dev = be->dev; + struct xenvif *vif; if (be->vif != NULL) return 0; @@ -414,13 +415,13 @@ static int backend_create_xenvif(struct backend_info *be) return (err < 0) ? err : -EINVAL; } - be->vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle); - if (IS_ERR(be->vif)) { - err = PTR_ERR(be->vif); - be->vif = NULL; + vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle); + if (IS_ERR(vif)) { + err = PTR_ERR(vif); xenbus_dev_fatal(dev, err, "creating interface"); return err; } + be->vif = vif; kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE); return 0; -- cgit v1.2.3-59-g8ed1b From 11d3d2a16cc1f05c6ece69a4392e99efb85666a6 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Tue, 9 Dec 2014 18:43:28 +0000 Subject: xen-netfront: use correct linear area after linearizing an skb Commit 97a6d1bb2b658ac85ed88205ccd1ab809899884d (xen-netfront: Fix handling packets on compound pages with skb_linearize) attempted to fix a problem where an skb that would have required too many slots would be dropped causing TCP connections to stall. However, it filled in the first slot using the original buffer and not the new one and would use the wrong offset and grant access to the wrong page. Netback would notice the malformed request and stop all traffic on the VIF, reporting: vif vif-3-0 vif3.0: txreq.offset: 85e, size: 4002, end: 6144 vif vif-3-0 vif3.0: fatal error; disabling device Reported-by: Anthony Wright Tested-by: Anthony Wright Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index ece8d1804d13..eeed0ce620f3 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -627,6 +627,9 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) slots, skb->len); if (skb_linearize(skb)) goto drop; + data = skb->data; + offset = offset_in_page(data); + len = skb_headlen(skb); } spin_lock_irqsave(&queue->tx_lock, flags); -- cgit v1.2.3-59-g8ed1b