--- /dev/null
+From df51e7aa2cf204e3a65657a1d60b96cfda133e9b Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Sat, 4 Sep 2010 14:57:27 +0100
+Subject: agp/intel: Promote warning about failure to setup flush to error.
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit df51e7aa2cf204e3a65657a1d60b96cfda133e9b upstream.
+
+Make sure we always detect when we fail to correctly allocate the Isoch
+Flush Page and print an error to warn the user about the likely memory
+corruption that will result in invalid rendering or worse.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/agp/intel-gtt.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/char/agp/intel-gtt.c
++++ b/drivers/char/agp/intel-gtt.c
+@@ -1061,11 +1061,11 @@ static void intel_i9xx_setup_flush(void)
+ intel_i915_setup_chipset_flush();
+ }
+
+- if (intel_private.ifp_resource.start) {
++ if (intel_private.ifp_resource.start)
+ intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE);
+- if (!intel_private.i9xx_flush_page)
+- dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing");
+- }
++ if (!intel_private.i9xx_flush_page)
++ dev_err(&intel_private.pcidev->dev,
++ "can't ioremap flush page - no chipset flushing\n");
+ }
+
+ static int intel_i9xx_configure(void)
--- /dev/null
+From a25c25c2a2aa55e609099a9f74453c518aec29a6 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Fri, 20 Aug 2010 14:36:45 +0100
+Subject: drm/i915: Allocate the PCI resource for the MCHBAR
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit a25c25c2a2aa55e609099a9f74453c518aec29a6 upstream.
+
+We were failing when trying to allocate the resource for MMIO of the
+MCHBAR because we forgot to specify what type of resource we wanted.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
+Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/i915_dma.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/gpu/drm/i915/i915_dma.c
++++ b/drivers/gpu/drm/i915/i915_dma.c
+@@ -883,7 +883,7 @@ intel_alloc_mchbar_resource(struct drm_d
+ int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+ u32 temp_lo, temp_hi = 0;
+ u64 mchbar_addr;
+- int ret = 0;
++ int ret;
+
+ if (IS_I965G(dev))
+ pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
+@@ -893,22 +893,23 @@ intel_alloc_mchbar_resource(struct drm_d
+ /* If ACPI doesn't have it, assume we need to allocate it ourselves */
+ #ifdef CONFIG_PNP
+ if (mchbar_addr &&
+- pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
+- ret = 0;
+- goto out;
+- }
++ pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE))
++ return 0;
+ #endif
+
+ /* Get some space for it */
+- ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, &dev_priv->mch_res,
++ dev_priv->mch_res.name = "i915 MCHBAR";
++ dev_priv->mch_res.flags = IORESOURCE_MEM;
++ ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus,
++ &dev_priv->mch_res,
+ MCHBAR_SIZE, MCHBAR_SIZE,
+ PCIBIOS_MIN_MEM,
+- 0, pcibios_align_resource,
++ 0, pcibios_align_resource,
+ dev_priv->bridge_dev);
+ if (ret) {
+ DRM_DEBUG_DRIVER("failed bus alloc: %d\n", ret);
+ dev_priv->mch_res.start = 0;
+- goto out;
++ return ret;
+ }
+
+ if (IS_I965G(dev))
+@@ -917,8 +918,7 @@ intel_alloc_mchbar_resource(struct drm_d
+
+ pci_write_config_dword(dev_priv->bridge_dev, reg,
+ lower_32_bits(dev_priv->mch_res.start));
+-out:
+- return ret;
++ return 0;
+ }
+
+ /* Setup MCHBAR if possible, return true if we should disable it again */
--- /dev/null
+From dd8849c8f59ec1cee4809a0c5e603e045abe860e Mon Sep 17 00:00:00 2001
+From: Jesse Barnes <jbarnes@virtuousgeek.org>
+Date: Thu, 9 Sep 2010 11:58:02 -0700
+Subject: drm/i915: don't enable self-refresh on Ironlake
+
+From: Jesse Barnes <jbarnes@virtuousgeek.org>
+
+commit dd8849c8f59ec1cee4809a0c5e603e045abe860e upstream.
+
+We don't know how to enable it safely, especially as outputs turn on and
+off. When disabling LP1 we also need to make sure LP2 and 3 are already
+disabled.
+
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29173
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29082
+Reported-by: Chris Lord <chris@linux.intel.com>
+Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
+Tested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++
+ drivers/gpu/drm/i915/intel_display.c | 6 ++++--
+ 2 files changed, 12 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/i915/i915_reg.h
++++ b/drivers/gpu/drm/i915/i915_reg.h
+@@ -2200,9 +2200,17 @@
+ #define WM1_LP_SR_EN (1<<31)
+ #define WM1_LP_LATENCY_SHIFT 24
+ #define WM1_LP_LATENCY_MASK (0x7f<<24)
++#define WM1_LP_FBC_LP1_MASK (0xf<<20)
++#define WM1_LP_FBC_LP1_SHIFT 20
+ #define WM1_LP_SR_MASK (0x1ff<<8)
+ #define WM1_LP_SR_SHIFT 8
+ #define WM1_LP_CURSOR_MASK (0x3f)
++#define WM2_LP_ILK 0x4510c
++#define WM2_LP_EN (1<<31)
++#define WM3_LP_ILK 0x45110
++#define WM3_LP_EN (1<<31)
++#define WM1S_LP_ILK 0x45120
++#define WM1S_LP_EN (1<<31)
+
+ /* Memory latency timer register */
+ #define MLTR_ILK 0x11222
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -3206,8 +3206,7 @@ static void ironlake_update_wm(struct dr
+ reg_value = I915_READ(WM1_LP_ILK);
+ reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK |
+ WM1_LP_CURSOR_MASK);
+- reg_value |= WM1_LP_SR_EN |
+- (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
++ reg_value |= (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
+ (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm;
+
+ I915_WRITE(WM1_LP_ILK, reg_value);
+@@ -5425,6 +5424,9 @@ void intel_init_clock_gating(struct drm_
+ I915_WRITE(DISP_ARB_CTL,
+ (I915_READ(DISP_ARB_CTL) |
+ DISP_FBC_WM_DIS));
++ I915_WRITE(WM3_LP_ILK, 0);
++ I915_WRITE(WM2_LP_ILK, 0);
++ I915_WRITE(WM1_LP_ILK, 0);
+ }
+ return;
+ } else if (IS_G4X(dev)) {
--- /dev/null
+From 4f7f7b7eb94bd37c449f06932459bbed78826f8d Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Wed, 18 Aug 2010 18:12:56 +0100
+Subject: drm/i915/dp: Really try 5 times before giving up.
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 4f7f7b7eb94bd37c449f06932459bbed78826f8d upstream.
+
+Only stop trying if the aux channel sucessfully reports that the
+transmission was completed, otherwise try again. On the 5th failure,
+bail and report that something is amiss.
+
+This fixes a sporadic failure in reading the EDID for my external panel
+over DP.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/intel_dp.c | 58 +++++++++++++++++++---------------------
+ 1 file changed, 28 insertions(+), 30 deletions(-)
+
+--- a/drivers/gpu/drm/i915/intel_dp.c
++++ b/drivers/gpu/drm/i915/intel_dp.c
+@@ -229,7 +229,6 @@ intel_dp_aux_ch(struct intel_encoder *in
+ uint32_t ch_data = ch_ctl + 4;
+ int i;
+ int recv_bytes;
+- uint32_t ctl;
+ uint32_t status;
+ uint32_t aux_clock_divider;
+ int try, precharge;
+@@ -253,41 +252,43 @@ intel_dp_aux_ch(struct intel_encoder *in
+ else
+ precharge = 5;
+
++ if (I915_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) {
++ DRM_ERROR("dp_aux_ch not started status 0x%08x\n",
++ I915_READ(ch_ctl));
++ return -EBUSY;
++ }
++
+ /* Must try at least 3 times according to DP spec */
+ for (try = 0; try < 5; try++) {
+ /* Load the send data into the aux channel data registers */
+- for (i = 0; i < send_bytes; i += 4) {
+- uint32_t d = pack_aux(send + i, send_bytes - i);
+-
+- I915_WRITE(ch_data + i, d);
+- }
+-
+- ctl = (DP_AUX_CH_CTL_SEND_BUSY |
+- DP_AUX_CH_CTL_TIME_OUT_400us |
+- (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+- (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+- (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
+- DP_AUX_CH_CTL_DONE |
+- DP_AUX_CH_CTL_TIME_OUT_ERROR |
+- DP_AUX_CH_CTL_RECEIVE_ERROR);
++ for (i = 0; i < send_bytes; i += 4)
++ I915_WRITE(ch_data + i,
++ pack_aux(send + i, send_bytes - i));
+
+ /* Send the command and wait for it to complete */
+- I915_WRITE(ch_ctl, ctl);
+- (void) I915_READ(ch_ctl);
++ I915_WRITE(ch_ctl,
++ DP_AUX_CH_CTL_SEND_BUSY |
++ DP_AUX_CH_CTL_TIME_OUT_400us |
++ (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
++ (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
++ (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
++ DP_AUX_CH_CTL_DONE |
++ DP_AUX_CH_CTL_TIME_OUT_ERROR |
++ DP_AUX_CH_CTL_RECEIVE_ERROR);
+ for (;;) {
+- udelay(100);
+ status = I915_READ(ch_ctl);
+ if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
+ break;
++ udelay(100);
+ }
+
+ /* Clear done status and any errors */
+- I915_WRITE(ch_ctl, (status |
+- DP_AUX_CH_CTL_DONE |
+- DP_AUX_CH_CTL_TIME_OUT_ERROR |
+- DP_AUX_CH_CTL_RECEIVE_ERROR));
+- (void) I915_READ(ch_ctl);
+- if ((status & DP_AUX_CH_CTL_TIME_OUT_ERROR) == 0)
++ I915_WRITE(ch_ctl,
++ status |
++ DP_AUX_CH_CTL_DONE |
++ DP_AUX_CH_CTL_TIME_OUT_ERROR |
++ DP_AUX_CH_CTL_RECEIVE_ERROR);
++ if (status & DP_AUX_CH_CTL_DONE)
+ break;
+ }
+
+@@ -314,15 +315,12 @@ intel_dp_aux_ch(struct intel_encoder *in
+ /* Unload any bytes sent back from the other side */
+ recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
+ DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
+-
+ if (recv_bytes > recv_size)
+ recv_bytes = recv_size;
+
+- for (i = 0; i < recv_bytes; i += 4) {
+- uint32_t d = I915_READ(ch_data + i);
+-
+- unpack_aux(d, recv + i, recv_bytes - i);
+- }
++ for (i = 0; i < recv_bytes; i += 4)
++ unpack_aux(I915_READ(ch_data + i),
++ recv + i, recv_bytes - i);
+
+ return recv_bytes;
+ }
--- /dev/null
+From a69ffdbfcba8eabf2ca9d384b578e6f28b339c61 Mon Sep 17 00:00:00 2001
+From: Zhenyu Wang <zhenyuw@linux.intel.com>
+Date: Mon, 30 Aug 2010 16:12:42 +0800
+Subject: drm/i915: Enable MI_FLUSH on Sandybridge
+
+From: Zhenyu Wang <zhenyuw@linux.intel.com>
+
+commit a69ffdbfcba8eabf2ca9d384b578e6f28b339c61 upstream.
+
+MI_FLUSH is being deprecated, but still available on Sandybridge.
+Make sure it's enabled as userspace still uses MI_FLUSH.
+
+Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/i915_reg.h | 1 +
+ drivers/gpu/drm/i915/intel_ringbuffer.c | 8 ++++++--
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/i915/i915_reg.h
++++ b/drivers/gpu/drm/i915/i915_reg.h
+@@ -312,6 +312,7 @@
+
+ #define MI_MODE 0x0209c
+ # define VS_TIMER_DISPATCH (1 << 6)
++# define MI_FLUSH_ENABLE (1 << 11)
+
+ #define SCPD0 0x0209c /* 915+ only */
+ #define IER 0x020a0
+--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
++++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
+@@ -203,9 +203,13 @@ static int init_render_ring(struct drm_d
+ {
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret = init_ring_common(dev, ring);
++ int mode;
++
+ if (IS_I9XX(dev) && !IS_GEN3(dev)) {
+- I915_WRITE(MI_MODE,
+- (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH);
++ mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
++ if (IS_GEN6(dev))
++ mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
++ I915_WRITE(MI_MODE, mode);
+ }
+ return ret;
+ }
--- /dev/null
+From 9f82d23846146990d475f6753be733e55788d88d Mon Sep 17 00:00:00 2001
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+Date: Mon, 30 Aug 2010 21:25:23 +0200
+Subject: drm/i915: overlay on gen2 can't address above 1G
+
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+
+commit 9f82d23846146990d475f6753be733e55788d88d upstream.
+
+So set the coherent dma mask accordingly. This dma mask is only used
+for physical objects, so it won't really matter allocation-wise.
+
+Now this never really surfaced because sane 32bit kernels only have 1G
+of lowmem. But some eager testers (distros?) still carry around the patch
+to adjust lowmem via a kconfig option. And the kernel seems to favour
+high allocations on boot-up, hence the overlay blowing up reliably.
+
+Because the patch is tiny and nicely shows how broken gen2 is it's imho
+worth to merge despite the fact that mucking around with the lowmem/
+highmem division is (no longer) supported.
+
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=28318
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/i915_dma.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/gpu/drm/i915/i915_dma.c
++++ b/drivers/gpu/drm/i915/i915_dma.c
+@@ -2079,6 +2079,10 @@ int i915_driver_load(struct drm_device *
+ goto free_priv;
+ }
+
++ /* overlay on gen2 is broken and can't address above 1G */
++ if (IS_GEN2(dev))
++ dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
++
+ dev_priv->regs = ioremap(base, size);
+ if (!dev_priv->regs) {
+ DRM_ERROR("failed to map registers\n");
--- /dev/null
+From 032d2a0d068b0368296a56469761394ef03207c3 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Mon, 6 Sep 2010 16:17:22 +0100
+Subject: drm/i915: Prevent double dpms on
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 032d2a0d068b0368296a56469761394ef03207c3 upstream.
+
+Arguably this is a bug in drm-core in that we should not be called twice
+in succession with DPMS_ON, however this is still occuring and we see
+FDI link training failures on the second call leading to the occassional
+blank display. For the time being ignore the repeated call.
+
+Original patch by Dave Airlie <airlied@redhat.com>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/intel_display.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -2314,6 +2314,9 @@ static void intel_crtc_dpms(struct drm_c
+ int pipe = intel_crtc->pipe;
+ bool enabled;
+
++ if (intel_crtc->dpms_mode == mode)
++ return;
++
+ dev_priv->display.dpms(crtc, mode);
+
+ intel_crtc->dpms_mode = mode;
+@@ -4915,7 +4918,7 @@ static void intel_crtc_init(struct drm_d
+ dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
+
+ intel_crtc->cursor_addr = 0;
+- intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
++ intel_crtc->dpms_mode = -1;
+ drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
+
+ intel_crtc->busy = false;
--- /dev/null
+From b741be82cf2079f71553af595610f17a3a3a752a Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Thu, 9 Sep 2010 19:15:23 -0400
+Subject: drm/radeon/kms/evergreen: fix backend setup
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit b741be82cf2079f71553af595610f17a3a3a752a upstream.
+
+This patch fixes rendering errors on some evergreen boards.
+Hardcoding the backend map is not an optimal solution, but
+a better fix is being worked on.
+
+Similar to the fix for rv740
+(6271901d828b34b27607314026deaf417f9f9b75).
+
+Fixes:
+https://bugs.freedesktop.org/show_bug.cgi?id=29986
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/evergreen.c | 27 +++++++++++++++++++--------
+ 1 file changed, 19 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/radeon/evergreen.c
++++ b/drivers/gpu/drm/radeon/evergreen.c
+@@ -1143,14 +1143,25 @@ static void evergreen_gpu_init(struct ra
+ EVERGREEN_MAX_BACKENDS_MASK));
+ break;
+ }
+- } else
+- gb_backend_map =
+- evergreen_get_tile_pipe_to_backend_map(rdev,
+- rdev->config.evergreen.max_tile_pipes,
+- rdev->config.evergreen.max_backends,
+- ((EVERGREEN_MAX_BACKENDS_MASK <<
+- rdev->config.evergreen.max_backends) &
+- EVERGREEN_MAX_BACKENDS_MASK));
++ } else {
++ switch (rdev->family) {
++ case CHIP_CYPRESS:
++ case CHIP_HEMLOCK:
++ gb_backend_map = 0x66442200;
++ break;
++ case CHIP_JUNIPER:
++ gb_backend_map = 0x00006420;
++ break;
++ default:
++ gb_backend_map =
++ evergreen_get_tile_pipe_to_backend_map(rdev,
++ rdev->config.evergreen.max_tile_pipes,
++ rdev->config.evergreen.max_backends,
++ ((EVERGREEN_MAX_BACKENDS_MASK <<
++ rdev->config.evergreen.max_backends) &
++ EVERGREEN_MAX_BACKENDS_MASK));
++ }
++ }
+
+ WREG32(GB_BACKEND_MAP, gb_backend_map);
+ WREG32(GB_ADDR_CONFIG, gb_addr_config);
--- /dev/null
+From 7e7b41d2ff30ed7ad4bf401d18566e6f38e42e4f Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Thu, 2 Sep 2010 21:32:32 -0400
+Subject: drm/radeon/kms/evergreen: fix gpu hangs in userspace accel code
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit 7e7b41d2ff30ed7ad4bf401d18566e6f38e42e4f upstream.
+
+These VGT regs need to be programmed via the ring rather than
+MMIO as on previous asics (r6xx/r7xx).
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/evergreen.c | 39 ++++++++++++++++++++++++++++++++++++-
+ drivers/gpu/drm/radeon/r600.c | 5 ----
+ 2 files changed, 39 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/radeon/evergreen.c
++++ b/drivers/gpu/drm/radeon/evergreen.c
+@@ -658,6 +658,43 @@ static int evergreen_cp_load_microcode(s
+ return 0;
+ }
+
++static int evergreen_cp_start(struct radeon_device *rdev)
++{
++ int r;
++ uint32_t cp_me;
++
++ r = radeon_ring_lock(rdev, 7);
++ if (r) {
++ DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
++ return r;
++ }
++ radeon_ring_write(rdev, PACKET3(PACKET3_ME_INITIALIZE, 5));
++ radeon_ring_write(rdev, 0x1);
++ radeon_ring_write(rdev, 0x0);
++ radeon_ring_write(rdev, rdev->config.evergreen.max_hw_contexts - 1);
++ radeon_ring_write(rdev, PACKET3_ME_INITIALIZE_DEVICE_ID(1));
++ radeon_ring_write(rdev, 0);
++ radeon_ring_write(rdev, 0);
++ radeon_ring_unlock_commit(rdev);
++
++ cp_me = 0xff;
++ WREG32(CP_ME_CNTL, cp_me);
++
++ r = radeon_ring_lock(rdev, 4);
++ if (r) {
++ DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
++ return r;
++ }
++ /* init some VGT regs */
++ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
++ radeon_ring_write(rdev, (VGT_VERTEX_REUSE_BLOCK_CNTL - PACKET3_SET_CONTEXT_REG_START) >> 2);
++ radeon_ring_write(rdev, 0xe);
++ radeon_ring_write(rdev, 0x10);
++ radeon_ring_unlock_commit(rdev);
++
++ return 0;
++}
++
+ int evergreen_cp_resume(struct radeon_device *rdev)
+ {
+ u32 tmp;
+@@ -702,7 +739,7 @@ int evergreen_cp_resume(struct radeon_de
+ rdev->cp.rptr = RREG32(CP_RB_RPTR);
+ rdev->cp.wptr = RREG32(CP_RB_WPTR);
+
+- r600_cp_start(rdev);
++ evergreen_cp_start(rdev);
+ rdev->cp.ready = true;
+ r = radeon_ring_test(rdev);
+ if (r) {
+--- a/drivers/gpu/drm/radeon/r600.c
++++ b/drivers/gpu/drm/radeon/r600.c
+@@ -2104,10 +2104,7 @@ int r600_cp_start(struct radeon_device *
+ }
+ radeon_ring_write(rdev, PACKET3(PACKET3_ME_INITIALIZE, 5));
+ radeon_ring_write(rdev, 0x1);
+- if (rdev->family >= CHIP_CEDAR) {
+- radeon_ring_write(rdev, 0x0);
+- radeon_ring_write(rdev, rdev->config.evergreen.max_hw_contexts - 1);
+- } else if (rdev->family >= CHIP_RV770) {
++ if (rdev->family >= CHIP_RV770) {
+ radeon_ring_write(rdev, 0x0);
+ radeon_ring_write(rdev, rdev->config.rv770.max_hw_contexts - 1);
+ } else {
--- /dev/null
+From 87cbf8f2c5d1b1fc4642c3dc0bb6efc587479603 Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Fri, 27 Aug 2010 13:59:54 -0400
+Subject: drm/radeon/kms: fix a regression on r7xx AGP due to the HDP flush fix
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit 87cbf8f2c5d1b1fc4642c3dc0bb6efc587479603 upstream.
+
+commit: 812d046915f48236657f02c06d7dc47140e9ceda
+drm/radeon/kms/r7xx: add workaround for hw issue with HDP flush
+breaks on AGP boards since there is no VRAM gart table.
+
+This patch fixes the issue by creating a VRAM scratch page so that
+can be used on both AGP and PCIE.
+
+Fixes:
+https://bugs.freedesktop.org/show_bug.cgi?id=29834
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/r600.c | 2 -
+ drivers/gpu/drm/radeon/radeon.h | 6 ++++
+ drivers/gpu/drm/radeon/rv770.c | 52 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 59 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/radeon/r600.c
++++ b/drivers/gpu/drm/radeon/r600.c
+@@ -3526,7 +3526,7 @@ void r600_ioctl_wait_idle(struct radeon_
+ * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
+ */
+ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) {
+- void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
++ void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
+ u32 tmp;
+
+ WREG32(HDP_DEBUG1, 0);
+--- a/drivers/gpu/drm/radeon/radeon.h
++++ b/drivers/gpu/drm/radeon/radeon.h
+@@ -997,6 +997,11 @@ int radeon_gem_set_tiling_ioctl(struct d
+ int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+
++/* VRAM scratch page for HDP bug */
++struct r700_vram_scratch {
++ struct radeon_bo *robj;
++ volatile uint32_t *ptr;
++};
+
+ /*
+ * Core structure, functions and helpers.
+@@ -1060,6 +1065,7 @@ struct radeon_device {
+ const struct firmware *pfp_fw; /* r6/700 PFP firmware */
+ const struct firmware *rlc_fw; /* r6/700 RLC firmware */
+ struct r600_blit r600_blit;
++ struct r700_vram_scratch vram_scratch;
+ int msi_enabled; /* msi enabled */
+ struct r600_ih ih; /* r6/700 interrupt ring */
+ struct workqueue_struct *wq;
+--- a/drivers/gpu/drm/radeon/rv770.c
++++ b/drivers/gpu/drm/radeon/rv770.c
+@@ -889,6 +889,54 @@ static void rv770_gpu_init(struct radeon
+
+ }
+
++static int rv770_vram_scratch_init(struct radeon_device *rdev)
++{
++ int r;
++ u64 gpu_addr;
++
++ if (rdev->vram_scratch.robj == NULL) {
++ r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE,
++ true, RADEON_GEM_DOMAIN_VRAM,
++ &rdev->vram_scratch.robj);
++ if (r) {
++ return r;
++ }
++ }
++
++ r = radeon_bo_reserve(rdev->vram_scratch.robj, false);
++ if (unlikely(r != 0))
++ return r;
++ r = radeon_bo_pin(rdev->vram_scratch.robj,
++ RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
++ if (r) {
++ radeon_bo_unreserve(rdev->vram_scratch.robj);
++ return r;
++ }
++ r = radeon_bo_kmap(rdev->vram_scratch.robj,
++ (void **)&rdev->vram_scratch.ptr);
++ if (r)
++ radeon_bo_unpin(rdev->vram_scratch.robj);
++ radeon_bo_unreserve(rdev->vram_scratch.robj);
++
++ return r;
++}
++
++static void rv770_vram_scratch_fini(struct radeon_device *rdev)
++{
++ int r;
++
++ if (rdev->vram_scratch.robj == NULL) {
++ return;
++ }
++ r = radeon_bo_reserve(rdev->vram_scratch.robj, false);
++ if (likely(r == 0)) {
++ radeon_bo_kunmap(rdev->vram_scratch.robj);
++ radeon_bo_unpin(rdev->vram_scratch.robj);
++ radeon_bo_unreserve(rdev->vram_scratch.robj);
++ }
++ radeon_bo_unref(&rdev->vram_scratch.robj);
++}
++
+ int rv770_mc_init(struct radeon_device *rdev)
+ {
+ u32 tmp;
+@@ -954,6 +1002,9 @@ static int rv770_startup(struct radeon_d
+ if (r)
+ return r;
+ }
++ r = rv770_vram_scratch_init(rdev);
++ if (r)
++ return r;
+ rv770_gpu_init(rdev);
+ r = r600_blit_init(rdev);
+ if (r) {
+@@ -1179,6 +1230,7 @@ void rv770_fini(struct radeon_device *rd
+ r600_irq_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ rv770_pcie_gart_fini(rdev);
++ rv770_vram_scratch_fini(rdev);
+ radeon_gem_fini(rdev);
+ radeon_fence_driver_fini(rdev);
+ radeon_clocks_fini(rdev);
--- /dev/null
+From 0d9958b18e10d7426d94cc3dd024920a40db3ee2 Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Wed, 1 Sep 2010 12:03:37 -0400
+Subject: drm/radeon/kms: force legacy pll algo for RV515 LVDS
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit 0d9958b18e10d7426d94cc3dd024920a40db3ee2 upstream.
+
+There has been periodic evidence that LVDS, on at least some
+panels, prefers the dividers selected by the legacy pll algo.
+This patch forces the use of the legacy pll algo on RV515
+LVDS panels. The old behavior (new pll algo) can be selected
+by setting the new_pll module parameter to 1.
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/atombios_crtc.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/drivers/gpu/drm/radeon/atombios_crtc.c
++++ b/drivers/gpu/drm/radeon/atombios_crtc.c
+@@ -527,6 +527,20 @@ static u32 atombios_adjust_pll(struct dr
+ pll->algo = PLL_ALGO_LEGACY;
+ pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
+ }
++ /* There is some evidence (often anecdotal) that RV515 LVDS
++ * (on some boards at least) prefers the legacy algo. I'm not
++ * sure whether this should handled generically or on a
++ * case-by-case quirk basis. Both algos should work fine in the
++ * majority of cases.
++ */
++ if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) &&
++ (rdev->family == CHIP_RV515)) {
++ /* allow the user to overrride just in case */
++ if (radeon_new_pll == 1)
++ pll->algo = PLL_ALGO_NEW;
++ else
++ pll->algo = PLL_ALGO_LEGACY;
++ }
+ } else {
+ if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
+ pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
--- /dev/null
+From f90087eea44ce5fad139f086bc9d89ca37b0edc2 Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Tue, 7 Sep 2010 11:42:45 -0400
+Subject: drm/radeon/kms: force legacy pll algo for RV620 LVDS
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit f90087eea44ce5fad139f086bc9d89ca37b0edc2 upstream.
+
+There has been periodic evidence that LVDS, on at least some
+panels, prefers the dividers selected by the legacy pll algo.
+This patch forces the use of the legacy pll algo on RV620
+LVDS panels. The old behavior (new pll algo) can be selected
+by setting the new_pll module parameter to 1.
+
+Fixes:
+https://bugs.freedesktop.org/show_bug.cgi?id=30029
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/atombios_crtc.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/radeon/atombios_crtc.c
++++ b/drivers/gpu/drm/radeon/atombios_crtc.c
+@@ -527,14 +527,15 @@ static u32 atombios_adjust_pll(struct dr
+ pll->algo = PLL_ALGO_LEGACY;
+ pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
+ }
+- /* There is some evidence (often anecdotal) that RV515 LVDS
++ /* There is some evidence (often anecdotal) that RV515/RV620 LVDS
+ * (on some boards at least) prefers the legacy algo. I'm not
+ * sure whether this should handled generically or on a
+ * case-by-case quirk basis. Both algos should work fine in the
+ * majority of cases.
+ */
+ if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) &&
+- (rdev->family == CHIP_RV515)) {
++ ((rdev->family == CHIP_RV515) ||
++ (rdev->family == CHIP_RV620))) {
+ /* allow the user to overrride just in case */
+ if (radeon_new_pll == 1)
+ pll->algo = PLL_ALGO_NEW;
--- /dev/null
+From 95347871865ca5093c7e87a223274f7c3b5eccda Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Wed, 1 Sep 2010 17:20:42 -0400
+Subject: drm/radeon/kms: properly set crtc high base on r7xx
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit 95347871865ca5093c7e87a223274f7c3b5eccda upstream.
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/atombios_crtc.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/radeon/atombios_crtc.c
++++ b/drivers/gpu/drm/radeon/atombios_crtc.c
+@@ -1007,11 +1007,11 @@ static int avivo_crtc_set_base(struct dr
+
+ if (rdev->family >= CHIP_RV770) {
+ if (radeon_crtc->crtc_id) {
+- WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0);
+- WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0);
++ WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
++ WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
+ } else {
+- WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0);
+- WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0);
++ WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
++ WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
+ }
+ }
+ WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
--- /dev/null
+From c877cdce93a44eea96f6cf7fc04be7d0372db2be Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <error27@gmail.com>
+Date: Wed, 23 Jun 2010 19:03:01 +0200
+Subject: i915: return -EFAULT if copy_to_user fails
+
+From: Dan Carpenter <error27@gmail.com>
+
+commit c877cdce93a44eea96f6cf7fc04be7d0372db2be upstream.
+
+copy_to_user() returns the number of bytes remaining to be copied and
+I'm pretty sure we want to return a negative error code here.
+
+Signed-off-by: Dan Carpenter <error27@gmail.com>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/i915_gem.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/i915/i915_gem.c
++++ b/drivers/gpu/drm/i915/i915_gem.c
+@@ -3709,6 +3709,7 @@ i915_gem_do_execbuffer(struct drm_device
+ if (ret != 0) {
+ DRM_ERROR("copy %d cliprects failed: %d\n",
+ args->num_cliprects, ret);
++ ret = -EFAULT;
+ goto pre_mutex_err;
+ }
+ }
--- /dev/null
+From 9927a403ca8c97798129953fa9cbb5dc259c7cb9 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <error27@gmail.com>
+Date: Sat, 19 Jun 2010 15:12:51 +0200
+Subject: i915: return -EFAULT if copy_to_user fails
+
+From: Dan Carpenter <error27@gmail.com>
+
+commit 9927a403ca8c97798129953fa9cbb5dc259c7cb9 upstream.
+
+copy_to_user returns the number of bytes remaining to be copied, but we
+want to return a negative error code here. These are returned to
+userspace.
+
+Signed-off-by: Dan Carpenter <error27@gmail.com>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/i915_dma.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/i915/i915_dma.c
++++ b/drivers/gpu/drm/i915/i915_dma.c
+@@ -612,8 +612,10 @@ static int i915_batchbuffer(struct drm_d
+ ret = copy_from_user(cliprects, batch->cliprects,
+ batch->num_cliprects *
+ sizeof(struct drm_clip_rect));
+- if (ret != 0)
++ if (ret != 0) {
++ ret = -EFAULT;
+ goto fail_free;
++ }
+ }
+
+ mutex_lock(&dev->struct_mutex);
+@@ -654,8 +656,10 @@ static int i915_cmdbuffer(struct drm_dev
+ return -ENOMEM;
+
+ ret = copy_from_user(batch_data, cmdbuf->buf, cmdbuf->sz);
+- if (ret != 0)
++ if (ret != 0) {
++ ret = -EFAULT;
+ goto fail_batch_free;
++ }
+
+ if (cmdbuf->num_cliprects) {
+ cliprects = kcalloc(cmdbuf->num_cliprects,
+@@ -668,8 +672,10 @@ static int i915_cmdbuffer(struct drm_dev
+ ret = copy_from_user(cliprects, cmdbuf->cliprects,
+ cmdbuf->num_cliprects *
+ sizeof(struct drm_clip_rect));
+- if (ret != 0)
++ if (ret != 0) {
++ ret = -EFAULT;
+ goto fail_clip_free;
++ }
+ }
+
+ mutex_lock(&dev->struct_mutex);
--- /dev/null
+From 12e8ba25ef52f19e7a42e61aecb3c1fef83b2a82 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Tue, 7 Sep 2010 23:39:28 +0100
+Subject: Revert "drm/i915: Allow LVDS on pipe A on gen4+"
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 12e8ba25ef52f19e7a42e61aecb3c1fef83b2a82 upstream.
+
+This reverts commit 0f3ee801b332d6ff22285386675fe5aaedf035c3.
+
+Enabling LVDS on pipe A was causing excessive wakeups on otherwise idle
+systems due to i915 interrupts. So restrict the LVDS to pipe B once more,
+whilst the issue is properly diagnosed.
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=16307
+Reported-and-tested-by: Enrico Bandiello <enban@postal.uv.es>
+Poked-by: Florian Mickler <florian@mickler.org>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Adam Jackson <ajax@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/intel_lvds.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/gpu/drm/i915/intel_lvds.c
++++ b/drivers/gpu/drm/i915/intel_lvds.c
+@@ -988,8 +988,6 @@ void intel_lvds_init(struct drm_device *
+
+ intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
+ intel_encoder->crtc_mask = (1 << 1);
+- if (IS_I965G(dev))
+- intel_encoder->crtc_mask |= (1 << 0);
+ drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
+ drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
+ connector->display_info.subpixel_order = SubPixelHorizontalRGB;
cifs-fix-potential-double-put-of-tcp-session-reference.patch
nfs-fix-a-typo-in-nfs_sockaddr_match_ipaddr6.patch
sunrpc-fix-race-corrupting-rpc-upcall.patch
-sunrpc-fix-a-race-in-rpc_info_open.patch
+agp-intel-promote-warning-about-failure-to-setup-flush-to-error.patch
+drm-radeon-kms-fix-a-regression-on-r7xx-agp-due-to-the-hdp-flush-fix.patch
+drm-i915-enable-mi_flush-on-sandybridge.patch
+drm-radeon-kms-force-legacy-pll-algo-for-rv515-lvds.patch
+drm-radeon-kms-force-legacy-pll-algo-for-rv620-lvds.patch
+drm-radeon-kms-properly-set-crtc-high-base-on-r7xx.patch
+drm-radeon-kms-evergreen-fix-gpu-hangs-in-userspace-accel-code.patch
+drm-radeon-kms-evergreen-fix-backend-setup.patch
+i915-return-efault-if-copy_to_user-fails.patch
+i915-return-efault-if-copy_to_user-fails-2.patch
+drm-i915-dp-really-try-5-times-before-giving-up.patch
+drm-i915-allocate-the-pci-resource-for-the-mchbar.patch
+drm-i915-overlay-on-gen2-can-t-address-above-1g.patch
+drm-i915-prevent-double-dpms-on.patch
+drm-i915-don-t-enable-self-refresh-on-ironlake.patch
+revert-drm-i915-allow-lvds-on-pipe-a-on-gen4.patch
+++ /dev/null
-From 006abe887c5e637d059c44310de6c92f36aded3b Mon Sep 17 00:00:00 2001
-From: Trond Myklebust <Trond.Myklebust@netapp.com>
-Date: Sun, 12 Sep 2010 19:55:25 -0400
-Subject: SUNRPC: Fix a race in rpc_info_open
-
-From: Trond Myklebust <Trond.Myklebust@netapp.com>
-
-commit 006abe887c5e637d059c44310de6c92f36aded3b upstream.
-
-There is a race between rpc_info_open and rpc_release_client()
-in that nothing stops a process from opening the file after
-the clnt->cl_kref goes to zero.
-
-Fix this by using atomic_inc_unless_zero()...
-
-Reported-by: J. Bruce Fields <bfields@redhat.com>
-Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-
----
- include/linux/sunrpc/clnt.h | 2 +-
- net/sunrpc/clnt.c | 24 +++++++++++-------------
- net/sunrpc/rpc_pipe.c | 14 ++++++++------
- 3 files changed, 20 insertions(+), 20 deletions(-)
-
---- a/include/linux/sunrpc/clnt.h
-+++ b/include/linux/sunrpc/clnt.h
-@@ -30,7 +30,7 @@ struct rpc_inode;
- * The high-level client handle
- */
- struct rpc_clnt {
-- struct kref cl_kref; /* Number of references */
-+ atomic_t cl_count; /* Number of references */
- struct list_head cl_clients; /* Global list of clients */
- struct list_head cl_tasks; /* List of tasks */
- spinlock_t cl_lock; /* spinlock */
---- a/net/sunrpc/clnt.c
-+++ b/net/sunrpc/clnt.c
-@@ -226,7 +226,7 @@ static struct rpc_clnt * rpc_new_client(
- goto out_no_principal;
- }
-
-- kref_init(&clnt->cl_kref);
-+ atomic_set(&clnt->cl_count, 1);
-
- err = rpc_setup_pipedir(clnt, program->pipe_dir_name);
- if (err < 0)
-@@ -390,14 +390,14 @@ rpc_clone_client(struct rpc_clnt *clnt)
- if (new->cl_principal == NULL)
- goto out_no_principal;
- }
-- kref_init(&new->cl_kref);
-+ atomic_set(&new->cl_count, 1);
- err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
- if (err != 0)
- goto out_no_path;
- if (new->cl_auth)
- atomic_inc(&new->cl_auth->au_count);
- xprt_get(clnt->cl_xprt);
-- kref_get(&clnt->cl_kref);
-+ atomic_inc(&clnt->cl_count);
- rpc_register_client(new);
- rpciod_up();
- return new;
-@@ -436,10 +436,8 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client);
- * Free an RPC client
- */
- static void
--rpc_free_client(struct kref *kref)
-+rpc_free_client(struct rpc_clnt *clnt)
- {
-- struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
--
- dprintk("RPC: destroying %s client for %s\n",
- clnt->cl_protname, clnt->cl_server);
- if (!IS_ERR(clnt->cl_path.dentry)) {
-@@ -466,12 +464,10 @@ out_free:
- * Free an RPC client
- */
- static void
--rpc_free_auth(struct kref *kref)
-+rpc_free_auth(struct rpc_clnt *clnt)
- {
-- struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
--
- if (clnt->cl_auth == NULL) {
-- rpc_free_client(kref);
-+ rpc_free_client(clnt);
- return;
- }
-
-@@ -480,10 +476,11 @@ rpc_free_auth(struct kref *kref)
- * release remaining GSS contexts. This mechanism ensures
- * that it can do so safely.
- */
-- kref_init(kref);
-+ atomic_inc(&clnt->cl_count);
- rpcauth_release(clnt->cl_auth);
- clnt->cl_auth = NULL;
-- kref_put(kref, rpc_free_client);
-+ if (atomic_dec_and_test(&clnt->cl_count))
-+ rpc_free_client(clnt);
- }
-
- /*
-@@ -496,7 +493,8 @@ rpc_release_client(struct rpc_clnt *clnt
-
- if (list_empty(&clnt->cl_tasks))
- wake_up(&destroy_wait);
-- kref_put(&clnt->cl_kref, rpc_free_auth);
-+ if (atomic_dec_and_test(&clnt->cl_count))
-+ rpc_free_auth(clnt);
- }
-
- /**
---- a/net/sunrpc/rpc_pipe.c
-+++ b/net/sunrpc/rpc_pipe.c
-@@ -371,21 +371,23 @@ rpc_show_info(struct seq_file *m, void *
- static int
- rpc_info_open(struct inode *inode, struct file *file)
- {
-- struct rpc_clnt *clnt;
-+ struct rpc_clnt *clnt = NULL;
- int ret = single_open(file, rpc_show_info, NULL);
-
- if (!ret) {
- struct seq_file *m = file->private_data;
-- mutex_lock(&inode->i_mutex);
-- clnt = RPC_I(inode)->private;
-- if (clnt) {
-- kref_get(&clnt->cl_kref);
-+
-+ spin_lock(&file->f_path.dentry->d_lock);
-+ if (!d_unhashed(file->f_path.dentry))
-+ clnt = RPC_I(inode)->private;
-+ if (clnt != NULL && atomic_inc_not_zero(&clnt->cl_count)) {
-+ spin_unlock(&file->f_path.dentry->d_lock);
- m->private = clnt;
- } else {
-+ spin_unlock(&file->f_path.dentry->d_lock);
- single_release(inode, file);
- ret = -EINVAL;
- }
-- mutex_unlock(&inode->i_mutex);
- }
- return ret;
- }