]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'drm-intel-next-fixes-2016-12-22' of git://anongit.freedesktop.org/git...
authorDave Airlie <airlied@redhat.com>
Thu, 22 Dec 2016 19:28:02 +0000 (05:28 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 22 Dec 2016 19:28:02 +0000 (05:28 +1000)
First set of i915 fixes for code in next.

* tag 'drm-intel-next-fixes-2016-12-22' of git://anongit.freedesktop.org/git/drm-intel:
  drm/i915: skip the first 4k of stolen memory on everything >= gen8
  drm/i915: Fallback to single PAGE_SIZE segments for DMA remapping
  drm/i915: Fix use after free in logical_render_ring_init
  drm/i915: disable PSR by default on HSW/BDW
  drm/i915: Fix setting of boost freq tunable
  drm/i915: tune down the fast link training vs boot fail
  drm/i915: Reorder phys backing storage release
  drm/i915/gen9: Fix PCODE polling during SAGV disabling
  drm/i915/gen9: Fix PCODE polling during CDCLK change notification
  drm/i915/dsi: Fix chv_exec_gpio disabling the GPIOs it is setting
  drm/i915/dsi: Fix swapping of MIPI_SEQ_DEASSERT_RESET / MIPI_SEQ_ASSERT_RESET
  drm/i915/dsi: Do not clear DPOUNIT_CLOCK_GATE_DISABLE from vlv_init_display_clock_gating
  drm/i915: drop the struct_mutex when wedged or trying to reset

1  2 
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_pm.c

index 412f3513f269b4a96217f814aa0d882a27a3e1e5,c6f80bc3b7bc696e2f535026cf34cb456fd21ca3..4a31b7a891ecaf3e2732c9f2d6ce62fa633419f6
@@@ -174,21 -174,35 +174,35 @@@ static struct sg_table 
  i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
  {
        struct address_space *mapping = obj->base.filp->f_mapping;
-       char *vaddr = obj->phys_handle->vaddr;
+       drm_dma_handle_t *phys;
        struct sg_table *st;
        struct scatterlist *sg;
+       char *vaddr;
        int i;
  
        if (WARN_ON(i915_gem_object_needs_bit17_swizzle(obj)))
                return ERR_PTR(-EINVAL);
  
+       /* Always aligning to the object size, allows a single allocation
+        * to handle all possible callers, and given typical object sizes,
+        * the alignment of the buddy allocation will naturally match.
+        */
+       phys = drm_pci_alloc(obj->base.dev,
+                            obj->base.size,
+                            roundup_pow_of_two(obj->base.size));
+       if (!phys)
+               return ERR_PTR(-ENOMEM);
+       vaddr = phys->vaddr;
        for (i = 0; i < obj->base.size / PAGE_SIZE; i++) {
                struct page *page;
                char *src;
  
                page = shmem_read_mapping_page(mapping, i);
-               if (IS_ERR(page))
-                       return ERR_CAST(page);
+               if (IS_ERR(page)) {
+                       st = ERR_CAST(page);
+                       goto err_phys;
+               }
  
                src = kmap_atomic(page);
                memcpy(vaddr, src, PAGE_SIZE);
        i915_gem_chipset_flush(to_i915(obj->base.dev));
  
        st = kmalloc(sizeof(*st), GFP_KERNEL);
-       if (st == NULL)
-               return ERR_PTR(-ENOMEM);
+       if (!st) {
+               st = ERR_PTR(-ENOMEM);
+               goto err_phys;
+       }
  
        if (sg_alloc_table(st, 1, GFP_KERNEL)) {
                kfree(st);
-               return ERR_PTR(-ENOMEM);
+               st = ERR_PTR(-ENOMEM);
+               goto err_phys;
        }
  
        sg = st->sgl;
        sg->offset = 0;
        sg->length = obj->base.size;
  
-       sg_dma_address(sg) = obj->phys_handle->busaddr;
+       sg_dma_address(sg) = phys->busaddr;
        sg_dma_len(sg) = obj->base.size;
  
+       obj->phys_handle = phys;
+       return st;
+ err_phys:
+       drm_pci_free(obj->base.dev, phys);
        return st;
  }
  
@@@ -272,12 -294,13 +294,13 @@@ i915_gem_object_put_pages_phys(struct d
  
        sg_free_table(pages);
        kfree(pages);
+       drm_pci_free(obj->base.dev, obj->phys_handle);
  }
  
  static void
  i915_gem_object_release_phys(struct drm_i915_gem_object *obj)
  {
-       drm_pci_free(obj->base.dev, obj->phys_handle);
        i915_gem_object_unpin_pages(obj);
  }
  
@@@ -538,15 -561,13 +561,13 @@@ in
  i915_gem_object_attach_phys(struct drm_i915_gem_object *obj,
                            int align)
  {
-       drm_dma_handle_t *phys;
        int ret;
  
-       if (obj->phys_handle) {
-               if ((unsigned long)obj->phys_handle->vaddr & (align -1))
-                       return -EBUSY;
+       if (align > obj->base.size)
+               return -EINVAL;
  
+       if (obj->ops == &i915_gem_phys_ops)
                return 0;
-       }
  
        if (obj->mm.madv != I915_MADV_WILLNEED)
                return -EFAULT;
        if (obj->mm.pages)
                return -EBUSY;
  
-       /* create a new object */
-       phys = drm_pci_alloc(obj->base.dev, obj->base.size, align);
-       if (!phys)
-               return -ENOMEM;
-       obj->phys_handle = phys;
        obj->ops = &i915_gem_phys_ops;
  
        return i915_gem_object_pin_pages(obj);
@@@ -1796,7 -1811,8 +1811,7 @@@ int i915_gem_fault(struct vm_area_struc
        int ret;
  
        /* We don't use vmf->pgoff since that has the fake offset */
 -      page_offset = ((unsigned long)vmf->virtual_address - area->vm_start) >>
 -              PAGE_SHIFT;
 +      page_offset = (vmf->address - area->vm_start) >> PAGE_SHIFT;
  
        trace_i915_gem_object_fault(obj, page_offset, true, write);
  
@@@ -2326,7 -2342,8 +2341,8 @@@ static struct sg_table 
  i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
  {
        struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
-       int page_count, i;
+       const unsigned long page_count = obj->base.size / PAGE_SIZE;
+       unsigned long i;
        struct address_space *mapping;
        struct sg_table *st;
        struct scatterlist *sg;
        if (st == NULL)
                return ERR_PTR(-ENOMEM);
  
-       page_count = obj->base.size / PAGE_SIZE;
+ rebuild_st:
        if (sg_alloc_table(st, page_count, GFP_KERNEL)) {
                kfree(st);
                return ERR_PTR(-ENOMEM);
        i915_sg_trim(st);
  
        ret = i915_gem_gtt_prepare_pages(obj, st);
-       if (ret)
-               goto err_pages;
+       if (ret) {
+               /* DMA remapping failed? One possible cause is that
+                * it could not reserve enough large entries, asking
+                * for PAGE_SIZE chunks instead may be helpful.
+                */
+               if (max_segment > PAGE_SIZE) {
+                       for_each_sgt_page(page, sgt_iter, st)
+                               put_page(page);
+                       sg_free_table(st);
+                       max_segment = PAGE_SIZE;
+                       goto rebuild_st;
+               } else {
+                       dev_warn(&dev_priv->drm.pdev->dev,
+                                "Failed to DMA remap %lu pages\n",
+                                page_count);
+                       goto err_pages;
+               }
+       }
  
        if (i915_gem_object_needs_bit17_swizzle(obj))
                i915_gem_object_do_bit_17_swizzle(obj, st);
index cf5cff7b03b8528ce10590a1dd973bbfa2b87776,7d234043822d1786bd01367affff41b5904fe458..6daad86137606d700b6101ee0ffde7a7ee35a1cd
@@@ -2189,7 -2189,7 +2189,7 @@@ intel_pin_and_fence_fb_obj(struct drm_f
  
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
  
 -      alignment = intel_surf_alignment(dev_priv, fb->modifier[0]);
 +      alignment = intel_surf_alignment(dev_priv, fb->modifier);
  
        intel_fill_fb_ggtt_view(&view, fb, rotation);
  
@@@ -2350,13 -2350,13 +2350,13 @@@ static u32 intel_adjust_tile_offset(in
  
        WARN_ON(new_offset > old_offset);
  
 -      if (fb->modifier[plane] != DRM_FORMAT_MOD_NONE) {
 +      if (fb->modifier != DRM_FORMAT_MOD_NONE) {
                unsigned int tile_size, tile_width, tile_height;
                unsigned int pitch_tiles;
  
                tile_size = intel_tile_size(dev_priv);
                intel_tile_dims(dev_priv, &tile_width, &tile_height,
 -                              fb->modifier[plane], cpp);
 +                              fb->modifier, cpp);
  
                if (drm_rotation_90_or_270(rotation)) {
                        pitch_tiles = pitch / tile_height;
@@@ -2399,7 -2399,7 +2399,7 @@@ static u32 _intel_compute_tile_offset(c
                                      unsigned int rotation,
                                      u32 alignment)
  {
 -      uint64_t fb_modifier = fb->modifier[plane];
 +      uint64_t fb_modifier = fb->modifier;
        unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
        u32 offset, offset_aligned;
  
@@@ -2458,7 -2458,7 +2458,7 @@@ u32 intel_compute_tile_offset(int *x, i
        if (fb->pixel_format == DRM_FORMAT_NV12 && plane == 1)
                alignment = 4096;
        else
 -              alignment = intel_surf_alignment(dev_priv, fb->modifier[plane]);
 +              alignment = intel_surf_alignment(dev_priv, fb->modifier);
  
        return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch,
                                          rotation, alignment);
@@@ -2540,13 -2540,13 +2540,13 @@@ intel_fill_fb_info(struct drm_i915_priv
                                                    DRM_ROTATE_0, tile_size);
                offset /= tile_size;
  
 -              if (fb->modifier[i] != DRM_FORMAT_MOD_NONE) {
 +              if (fb->modifier != DRM_FORMAT_MOD_NONE) {
                        unsigned int tile_width, tile_height;
                        unsigned int pitch_tiles;
                        struct drm_rect r;
  
                        intel_tile_dims(dev_priv, &tile_width, &tile_height,
 -                                      fb->modifier[i], cpp);
 +                                      fb->modifier, cpp);
  
                        rot_info->plane[i].offset = offset;
                        rot_info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i], tile_width * cpp);
@@@ -2705,7 -2705,7 +2705,7 @@@ intel_alloc_initial_plane_obj(struct in
        mode_cmd.width = fb->width;
        mode_cmd.height = fb->height;
        mode_cmd.pitches[0] = fb->pitches[0];
 -      mode_cmd.modifier[0] = fb->modifier[0];
 +      mode_cmd.modifier[0] = fb->modifier;
        mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
  
        if (intel_framebuffer_init(dev, to_intel_framebuffer(fb),
@@@ -2835,7 -2835,7 +2835,7 @@@ static int skl_max_plane_width(const st
  {
        int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
  
 -      switch (fb->modifier[plane]) {
 +      switch (fb->modifier) {
        case DRM_FORMAT_MOD_NONE:
        case I915_FORMAT_MOD_X_TILED:
                switch (cpp) {
                }
                break;
        default:
 -              MISSING_CASE(fb->modifier[plane]);
 +              MISSING_CASE(fb->modifier);
        }
  
        return 2048;
@@@ -2894,7 -2894,7 +2894,7 @@@ static int skl_check_main_surface(struc
        intel_add_fb_offsets(&x, &y, plane_state, 0);
        offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
  
 -      alignment = intel_surf_alignment(dev_priv, fb->modifier[0]);
 +      alignment = intel_surf_alignment(dev_priv, fb->modifier);
  
        /*
         * AUX surface offset is specified as the distance from the
         *
         * TODO: linear and Y-tiled seem fine, Yf untested,
         */
 -      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) {
 +      if (fb->modifier == I915_FORMAT_MOD_X_TILED) {
                int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
  
                while ((x + w) * cpp > fb->pitches[0]) {
@@@ -3059,7 -3059,7 +3059,7 @@@ static void i9xx_update_primary_plane(s
        }
  
        if (INTEL_GEN(dev_priv) >= 4 &&
 -          fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
 +          fb->modifier == I915_FORMAT_MOD_X_TILED)
                dspcntr |= DISPPLANE_TILED;
  
        if (rotation & DRM_ROTATE_180)
@@@ -3170,7 -3170,7 +3170,7 @@@ static void ironlake_update_primary_pla
                BUG();
        }
  
 -      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
 +      if (fb->modifier == I915_FORMAT_MOD_X_TILED)
                dspcntr |= DISPPLANE_TILED;
  
        if (rotation & DRM_ROTATE_180)
@@@ -3280,9 -3280,9 +3280,9 @@@ u32 skl_plane_stride(const struct drm_f
        if (drm_rotation_90_or_270(rotation)) {
                int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
  
 -              stride /= intel_tile_height(dev_priv, fb->modifier[0], cpp);
 +              stride /= intel_tile_height(dev_priv, fb->modifier, cpp);
        } else {
 -              stride /= intel_fb_stride_alignment(dev_priv, fb->modifier[0],
 +              stride /= intel_fb_stride_alignment(dev_priv, fb->modifier,
                                                    fb->pixel_format);
        }
  
@@@ -3398,7 -3398,7 +3398,7 @@@ static void skylake_update_primary_plan
                    PLANE_CTL_PIPE_CSC_ENABLE;
  
        plane_ctl |= skl_plane_ctl_format(fb->pixel_format);
 -      plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]);
 +      plane_ctl |= skl_plane_ctl_tiling(fb->modifier);
        plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
        plane_ctl |= skl_plane_ctl_rotation(rotation);
  
@@@ -6244,35 -6244,24 +6244,24 @@@ skl_dpll0_disable(struct drm_i915_priva
        dev_priv->cdclk_pll.vco = 0;
  }
  
- static bool skl_cdclk_pcu_ready(struct drm_i915_private *dev_priv)
- {
-       int ret;
-       u32 val;
-       /* inform PCU we want to change CDCLK */
-       val = SKL_CDCLK_PREPARE_FOR_CHANGE;
-       mutex_lock(&dev_priv->rps.hw_lock);
-       ret = sandybridge_pcode_read(dev_priv, SKL_PCODE_CDCLK_CONTROL, &val);
-       mutex_unlock(&dev_priv->rps.hw_lock);
-       return ret == 0 && (val & SKL_CDCLK_READY_FOR_CHANGE);
- }
- static bool skl_cdclk_wait_for_pcu_ready(struct drm_i915_private *dev_priv)
- {
-       return _wait_for(skl_cdclk_pcu_ready(dev_priv), 3000, 10) == 0;
- }
  static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk, int vco)
  {
        u32 freq_select, pcu_ack;
+       int ret;
  
        WARN_ON((cdclk == 24000) != (vco == 0));
  
        DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d kHz)\n", cdclk, vco);
  
-       if (!skl_cdclk_wait_for_pcu_ready(dev_priv)) {
-               DRM_ERROR("failed to inform PCU about cdclk change\n");
+       mutex_lock(&dev_priv->rps.hw_lock);
+       ret = skl_pcode_request(dev_priv, SKL_PCODE_CDCLK_CONTROL,
+                               SKL_CDCLK_PREPARE_FOR_CHANGE,
+                               SKL_CDCLK_READY_FOR_CHANGE,
+                               SKL_CDCLK_READY_FOR_CHANGE, 3);
+       mutex_unlock(&dev_priv->rps.hw_lock);
+       if (ret) {
+               DRM_ERROR("Failed to inform PCU about cdclk change (%d)\n",
+                         ret);
                return;
        }
  
@@@ -8707,7 -8696,7 +8696,7 @@@ i9xx_get_initial_plane_config(struct in
        if (INTEL_GEN(dev_priv) >= 4) {
                if (val & DISPPLANE_TILED) {
                        plane_config->tiling = I915_TILING_X;
 -                      fb->modifier[0] = I915_FORMAT_MOD_X_TILED;
 +                      fb->modifier = I915_FORMAT_MOD_X_TILED;
                }
        }
  
  
        aligned_height = intel_fb_align_height(dev, fb->height,
                                               fb->pixel_format,
 -                                             fb->modifier[0]);
 +                                             fb->modifier);
  
        plane_config->size = fb->pitches[0] * aligned_height;
  
@@@ -9748,17 -9737,17 +9737,17 @@@ skylake_get_initial_plane_config(struc
        tiling = val & PLANE_CTL_TILED_MASK;
        switch (tiling) {
        case PLANE_CTL_TILED_LINEAR:
 -              fb->modifier[0] = DRM_FORMAT_MOD_NONE;
 +              fb->modifier = DRM_FORMAT_MOD_NONE;
                break;
        case PLANE_CTL_TILED_X:
                plane_config->tiling = I915_TILING_X;
 -              fb->modifier[0] = I915_FORMAT_MOD_X_TILED;
 +              fb->modifier = I915_FORMAT_MOD_X_TILED;
                break;
        case PLANE_CTL_TILED_Y:
 -              fb->modifier[0] = I915_FORMAT_MOD_Y_TILED;
 +              fb->modifier = I915_FORMAT_MOD_Y_TILED;
                break;
        case PLANE_CTL_TILED_YF:
 -              fb->modifier[0] = I915_FORMAT_MOD_Yf_TILED;
 +              fb->modifier = I915_FORMAT_MOD_Yf_TILED;
                break;
        default:
                MISSING_CASE(tiling);
        fb->width = ((val >> 0) & 0x1fff) + 1;
  
        val = I915_READ(PLANE_STRIDE(pipe, 0));
 -      stride_mult = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
 +      stride_mult = intel_fb_stride_alignment(dev_priv, fb->modifier,
                                                fb->pixel_format);
        fb->pitches[0] = (val & 0x3ff) * stride_mult;
  
        aligned_height = intel_fb_align_height(dev, fb->height,
                                               fb->pixel_format,
 -                                             fb->modifier[0]);
 +                                             fb->modifier);
  
        plane_config->size = fb->pitches[0] * aligned_height;
  
@@@ -9849,7 -9838,7 +9838,7 @@@ ironlake_get_initial_plane_config(struc
        if (INTEL_GEN(dev_priv) >= 4) {
                if (val & DISPPLANE_TILED) {
                        plane_config->tiling = I915_TILING_X;
 -                      fb->modifier[0] = I915_FORMAT_MOD_X_TILED;
 +                      fb->modifier = I915_FORMAT_MOD_X_TILED;
                }
        }
  
  
        aligned_height = intel_fb_align_height(dev, fb->height,
                                               fb->pixel_format,
 -                                             fb->modifier[0]);
 +                                             fb->modifier);
  
        plane_config->size = fb->pitches[0] * aligned_height;
  
@@@ -11784,7 -11773,7 +11773,7 @@@ static int intel_gen4_queue_flip(struc
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0]);
        intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset |
 -                      intel_fb_modifier_to_tiling(fb->modifier[0]));
 +                      intel_fb_modifier_to_tiling(fb->modifier));
  
        /* XXX Enabling the panel-fitter across page-flip is so far
         * untested on non-native modes, so ignore it for now.
@@@ -11817,7 -11806,7 +11806,7 @@@ static int intel_gen6_queue_flip(struc
        intel_ring_emit(ring, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0] |
 -                      intel_fb_modifier_to_tiling(fb->modifier[0]));
 +                      intel_fb_modifier_to_tiling(fb->modifier));
        intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset);
  
        /* Contrary to the suggestions in the documentation,
@@@ -11923,7 -11912,7 +11912,7 @@@ static int intel_gen7_queue_flip(struc
  
        intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);
        intel_ring_emit(ring, fb->pitches[0] |
 -                      intel_fb_modifier_to_tiling(fb->modifier[0]));
 +                      intel_fb_modifier_to_tiling(fb->modifier));
        intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset);
        intel_ring_emit(ring, (MI_NOOP));
  
@@@ -11969,7 -11958,7 +11958,7 @@@ static void skl_do_mmio_flip(struct int
  
        ctl = I915_READ(PLANE_CTL(pipe, 0));
        ctl &= ~PLANE_CTL_TILED_MASK;
 -      switch (fb->modifier[0]) {
 +      switch (fb->modifier) {
        case DRM_FORMAT_MOD_NONE:
                break;
        case I915_FORMAT_MOD_X_TILED:
                ctl |= PLANE_CTL_TILED_YF;
                break;
        default:
 -              MISSING_CASE(fb->modifier[0]);
 +              MISSING_CASE(fb->modifier);
        }
  
        /*
@@@ -12007,7 -11996,7 +11996,7 @@@ static void ilk_do_mmio_flip(struct int
  
        dspcntr = I915_READ(reg);
  
 -      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
 +      if (fb->modifier == I915_FORMAT_MOD_X_TILED)
                dspcntr |= DISPPLANE_TILED;
        else
                dspcntr &= ~DISPPLANE_TILED;
@@@ -12222,7 -12211,7 +12211,7 @@@ static int intel_crtc_page_flip(struct 
  
        if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
                engine = dev_priv->engine[BCS];
 -              if (fb->modifier[0] != old_fb->modifier[0])
 +              if (fb->modifier != old_fb->modifier)
                        /* vlv: DISPLAY_FLIP fails to change tiling */
                        engine = NULL;
        } else if (IS_IVYBRIDGE(dev_priv) || IS_HASWELL(dev_priv)) {
@@@ -12380,7 -12369,7 +12369,7 @@@ static bool intel_wm_need_update(struc
        if (!cur->base.fb || !new->base.fb)
                return false;
  
 -      if (cur->base.fb->modifier[0] != new->base.fb->modifier[0] ||
 +      if (cur->base.fb->modifier != new->base.fb->modifier ||
            cur->base.rotation != new->base.rotation ||
            drm_rect_width(&new->base.src) != drm_rect_width(&cur->base.src) ||
            drm_rect_height(&new->base.src) != drm_rect_height(&cur->base.src) ||
@@@ -15109,7 -15098,7 +15098,7 @@@ intel_check_cursor_plane(struct drm_pla
                return -ENOMEM;
        }
  
 -      if (fb->modifier[0] != DRM_FORMAT_MOD_NONE) {
 +      if (fb->modifier != DRM_FORMAT_MOD_NONE) {
                DRM_DEBUG_KMS("cursor cannot be tiled\n");
                return -EINVAL;
        }
index d67974eb127a0f19caa005c1f5a69687ec88ae84,1377679ac10954581181ce372c65dab1242626ab..ae2c0bb4b2e8b384c6fc8858490143064ec4dec3
@@@ -2964,24 -2964,10 +2964,10 @@@ intel_enable_sagv(struct drm_i915_priva
        return 0;
  }
  
- static int
- intel_do_sagv_disable(struct drm_i915_private *dev_priv)
- {
-       int ret;
-       uint32_t temp = GEN9_SAGV_DISABLE;
-       ret = sandybridge_pcode_read(dev_priv, GEN9_PCODE_SAGV_CONTROL,
-                                    &temp);
-       if (ret)
-               return ret;
-       else
-               return temp & GEN9_SAGV_IS_DISABLED;
- }
  int
  intel_disable_sagv(struct drm_i915_private *dev_priv)
  {
-       int ret, result;
+       int ret;
  
        if (!intel_has_sagv(dev_priv))
                return 0;
        mutex_lock(&dev_priv->rps.hw_lock);
  
        /* bspec says to keep retrying for at least 1 ms */
-       ret = wait_for(result = intel_do_sagv_disable(dev_priv), 1);
+       ret = skl_pcode_request(dev_priv, GEN9_PCODE_SAGV_CONTROL,
+                               GEN9_SAGV_DISABLE,
+                               GEN9_SAGV_IS_DISABLED, GEN9_SAGV_IS_DISABLED,
+                               1);
        mutex_unlock(&dev_priv->rps.hw_lock);
  
-       if (ret == -ETIMEDOUT) {
-               DRM_ERROR("Request to disable SAGV timed out\n");
-               return -ETIMEDOUT;
-       }
        /*
         * Some skl systems, pre-release machines in particular,
         * don't actually have an SAGV.
         */
-       if (IS_SKYLAKE(dev_priv) && result == -ENXIO) {
+       if (IS_SKYLAKE(dev_priv) && ret == -ENXIO) {
                DRM_DEBUG_DRIVER("No SAGV found on system, ignoring\n");
                dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED;
                return 0;
-       } else if (result < 0) {
-               DRM_ERROR("Failed to disable the SAGV\n");
-               return result;
+       } else if (ret < 0) {
+               DRM_ERROR("Failed to disable the SAGV (%d)\n", ret);
+               return ret;
        }
  
        dev_priv->sagv_status = I915_SAGV_DISABLED;
@@@ -3067,7 -3051,7 +3051,7 @@@ bool intel_can_enable_sagv(struct drm_a
                latency = dev_priv->wm.skl_latency[level];
  
                if (skl_needs_memory_bw_wa(intel_state) &&
 -                  plane->base.state->fb->modifier[0] ==
 +                  plane->base.state->fb->modifier ==
                    I915_FORMAT_MOD_X_TILED)
                        latency += 15;
  
@@@ -3327,8 -3311,8 +3311,8 @@@ skl_ddb_min_alloc(const struct drm_plan
                return 0;
  
        /* For Non Y-tile return 8-blocks */
 -      if (fb->modifier[0] != I915_FORMAT_MOD_Y_TILED &&
 -          fb->modifier[0] != I915_FORMAT_MOD_Yf_TILED)
 +      if (fb->modifier != I915_FORMAT_MOD_Y_TILED &&
 +          fb->modifier != I915_FORMAT_MOD_Yf_TILED)
                return 8;
  
        src_w = drm_rect_width(&intel_pstate->base.src) >> 16;
@@@ -3597,7 -3581,7 +3581,7 @@@ static int skl_compute_plane_wm(const s
                return 0;
        }
  
 -      if (apply_memory_bw_wa && fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
 +      if (apply_memory_bw_wa && fb->modifier == I915_FORMAT_MOD_X_TILED)
                latency += 15;
  
        width = drm_rect_width(&intel_pstate->base.src) >> 16;
                y_min_scanlines *= 2;
  
        plane_bytes_per_line = width * cpp;
 -      if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
 -          fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
 +      if (fb->modifier == I915_FORMAT_MOD_Y_TILED ||
 +          fb->modifier == I915_FORMAT_MOD_Yf_TILED) {
                plane_blocks_per_line =
                      DIV_ROUND_UP(plane_bytes_per_line * y_min_scanlines, 512);
                plane_blocks_per_line /= y_min_scanlines;
 -      } else if (fb->modifier[0] == DRM_FORMAT_MOD_NONE) {
 +      } else if (fb->modifier == DRM_FORMAT_MOD_NONE) {
                plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512)
                                        + 1;
        } else {
  
        y_tile_minimum = plane_blocks_per_line * y_min_scanlines;
  
 -      if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
 -          fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
 +      if (fb->modifier == I915_FORMAT_MOD_Y_TILED ||
 +          fb->modifier == I915_FORMAT_MOD_Yf_TILED) {
                selected_result = max(method2, y_tile_minimum);
        } else {
                if ((cpp * cstate->base.adjusted_mode.crtc_htotal / 512 < 1) &&
        res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line);
  
        if (level >= 1 && level <= 7) {
 -              if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
 -                  fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
 +              if (fb->modifier == I915_FORMAT_MOD_Y_TILED ||
 +                  fb->modifier == I915_FORMAT_MOD_Yf_TILED) {
                        res_blocks += y_tile_minimum;
                        res_lines += y_min_scanlines;
                } else {
@@@ -7890,6 -7874,81 +7874,81 @@@ int sandybridge_pcode_write(struct drm_
        return 0;
  }
  
+ static bool skl_pcode_try_request(struct drm_i915_private *dev_priv, u32 mbox,
+                                 u32 request, u32 reply_mask, u32 reply,
+                                 u32 *status)
+ {
+       u32 val = request;
+       *status = sandybridge_pcode_read(dev_priv, mbox, &val);
+       return *status || ((val & reply_mask) == reply);
+ }
+ /**
+  * skl_pcode_request - send PCODE request until acknowledgment
+  * @dev_priv: device private
+  * @mbox: PCODE mailbox ID the request is targeted for
+  * @request: request ID
+  * @reply_mask: mask used to check for request acknowledgment
+  * @reply: value used to check for request acknowledgment
+  * @timeout_base_ms: timeout for polling with preemption enabled
+  *
+  * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE
+  * reports an error or an overall timeout of @timeout_base_ms+10 ms expires.
+  * The request is acknowledged once the PCODE reply dword equals @reply after
+  * applying @reply_mask. Polling is first attempted with preemption enabled
+  * for @timeout_base_ms and if this times out for another 10 ms with
+  * preemption disabled.
+  *
+  * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some
+  * other error as reported by PCODE.
+  */
+ int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request,
+                     u32 reply_mask, u32 reply, int timeout_base_ms)
+ {
+       u32 status;
+       int ret;
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+ #define COND skl_pcode_try_request(dev_priv, mbox, request, reply_mask, reply, \
+                                  &status)
+       /*
+        * Prime the PCODE by doing a request first. Normally it guarantees
+        * that a subsequent request, at most @timeout_base_ms later, succeeds.
+        * _wait_for() doesn't guarantee when its passed condition is evaluated
+        * first, so send the first request explicitly.
+        */
+       if (COND) {
+               ret = 0;
+               goto out;
+       }
+       ret = _wait_for(COND, timeout_base_ms * 1000, 10);
+       if (!ret)
+               goto out;
+       /*
+        * The above can time out if the number of requests was low (2 in the
+        * worst case) _and_ PCODE was busy for some reason even after a
+        * (queued) request and @timeout_base_ms delay. As a workaround retry
+        * the poll with preemption disabled to maximize the number of
+        * requests. Increase the timeout from @timeout_base_ms to 10ms to
+        * account for interrupts that could reduce the number of these
+        * requests.
+        */
+       DRM_DEBUG_KMS("PCODE timeout, retrying with preemption disabled\n");
+       WARN_ON_ONCE(timeout_base_ms > 3);
+       preempt_disable();
+       ret = wait_for_atomic(COND, 10);
+       preempt_enable();
+ out:
+       return ret ? ret : status;
+ #undef COND
+ }
  static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val)
  {
        /*