Merge tag 'drm-misc-fixes-2018-02-21' of git://anongit.freedesktop.org/drm/drm-misc...
authorDave Airlie <airlied@redhat.com>
Wed, 21 Feb 2018 22:39:26 +0000 (08:39 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 21 Feb 2018 22:39:26 +0000 (08:39 +1000)
Fixes for 4.16. I contains fixes for deadlock on runtime suspend on few
drivers, a memory leak on non-blocking commits, a crash on color-eviction.
The is also meson and edid fixes, plus a fix for a doc warning.

* tag 'drm-misc-fixes-2018-02-21' of git://anongit.freedesktop.org/drm/drm-misc:
  drm/tve200: fix kernel-doc documentation comment include
  drm/meson: fix vsync buffer update
  drm: Handle unexpected holes in color-eviction
  drm/edid: Add 6 bpc quirk for CPT panel in Asus UX303LA
  drm/amdgpu: Fix deadlock on runtime suspend
  drm/radeon: Fix deadlock on runtime suspend
  drm/nouveau: Fix deadlock on runtime suspend
  drm: Allow determining if current task is output poll worker
  workqueue: Allow retrieval of current task's work struct
  drm/atomic: Fix memleak on ERESTARTSYS during non-blocking commits

1  2 
drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/meson/meson_plane.c
drivers/gpu/drm/radeon/radeon_connectors.c
include/drm/drm_atomic.h
kernel/workqueue.c

index 8ca3783f2debefbc32f1ad3d6bc475cfbc16b986,21e7ae159dffcb140e20f90ad160111c01c0ffff..74d2efaec52f86a5dac357d2c52f775db67bdb83
@@@ -358,6 -358,7 +358,6 @@@ static int amdgpu_connector_ddc_get_mod
        if (amdgpu_connector->edid) {
                drm_mode_connector_update_edid_property(connector, amdgpu_connector->edid);
                ret = drm_add_edid_modes(connector, amdgpu_connector->edid);
 -              drm_edid_to_eld(connector, amdgpu_connector->edid);
                return ret;
        }
        drm_mode_connector_update_edid_property(connector, NULL);
@@@ -736,9 -737,11 +736,11 @@@ amdgpu_connector_lvds_detect(struct drm
        enum drm_connector_status ret = connector_status_disconnected;
        int r;
  
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
  
        if (encoder) {
                struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
        /* check acpi lid status ??? */
  
        amdgpu_connector_update_scratch_regs(connector, ret);
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
        return ret;
  }
  
@@@ -868,9 -875,11 +874,11 @@@ amdgpu_connector_vga_detect(struct drm_
        enum drm_connector_status ret = connector_status_disconnected;
        int r;
  
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
  
        encoder = amdgpu_connector_best_single_encoder(connector);
        if (!encoder)
        amdgpu_connector_update_scratch_regs(connector, ret);
  
  out:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
  
        return ret;
  }
@@@ -988,9 -999,11 +998,11 @@@ amdgpu_connector_dvi_detect(struct drm_
        enum drm_connector_status ret = connector_status_disconnected;
        bool dret = false, broken_edid = false;
  
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
  
        if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
                ret = connector->status;
        amdgpu_connector_update_scratch_regs(connector, ret);
  
  exit:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
  
        return ret;
  }
@@@ -1359,9 -1374,11 +1373,11 @@@ amdgpu_connector_dp_detect(struct drm_c
        struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
        int r;
  
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
  
        if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
                ret = connector->status;
  
        amdgpu_connector_update_scratch_regs(connector, ret);
  out:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
  
        return ret;
  }
index ab4032167094cca0ddeb3583915af6fe07ae5301,e8c249361d7e4acebd8e6f2dcf5d50d8d94935dc..ae3cbfe9e01cd6a52cc7c6a15ec809e971139ee4
@@@ -695,100 -695,6 +695,100 @@@ drm_atomic_helper_check_modeset(struct 
  }
  EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
  
 +/**
 + * drm_atomic_helper_check_plane_state() - Check plane state for validity
 + * @plane_state: plane state to check
 + * @crtc_state: crtc state to check
 + * @clip: integer clipping coordinates
 + * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
 + * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
 + * @can_position: is it legal to position the plane such that it
 + *                doesn't cover the entire crtc?  This will generally
 + *                only be false for primary planes.
 + * @can_update_disabled: can the plane be updated while the crtc
 + *                       is disabled?
 + *
 + * Checks that a desired plane update is valid, and updates various
 + * bits of derived state (clipped coordinates etc.). Drivers that provide
 + * their own plane handling rather than helper-provided implementations may
 + * still wish to call this function to avoid duplication of error checking
 + * code.
 + *
 + * RETURNS:
 + * Zero if update appears valid, error code on failure
 + */
 +int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
 +                                      const struct drm_crtc_state *crtc_state,
 +                                      const struct drm_rect *clip,
 +                                      int min_scale,
 +                                      int max_scale,
 +                                      bool can_position,
 +                                      bool can_update_disabled)
 +{
 +      struct drm_framebuffer *fb = plane_state->fb;
 +      struct drm_rect *src = &plane_state->src;
 +      struct drm_rect *dst = &plane_state->dst;
 +      unsigned int rotation = plane_state->rotation;
 +      int hscale, vscale;
 +
 +      WARN_ON(plane_state->crtc && plane_state->crtc != crtc_state->crtc);
 +
 +      *src = drm_plane_state_src(plane_state);
 +      *dst = drm_plane_state_dest(plane_state);
 +
 +      if (!fb) {
 +              plane_state->visible = false;
 +              return 0;
 +      }
 +
 +      /* crtc should only be NULL when disabling (i.e., !fb) */
 +      if (WARN_ON(!plane_state->crtc)) {
 +              plane_state->visible = false;
 +              return 0;
 +      }
 +
 +      if (!crtc_state->enable && !can_update_disabled) {
 +              DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n");
 +              return -EINVAL;
 +      }
 +
 +      drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation);
 +
 +      /* Check scaling */
 +      hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
 +      vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
 +      if (hscale < 0 || vscale < 0) {
 +              DRM_DEBUG_KMS("Invalid scaling of plane\n");
 +              drm_rect_debug_print("src: ", &plane_state->src, true);
 +              drm_rect_debug_print("dst: ", &plane_state->dst, false);
 +              return -ERANGE;
 +      }
 +
 +      plane_state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
 +
 +      drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
 +
 +      if (!plane_state->visible)
 +              /*
 +               * Plane isn't visible; some drivers can handle this
 +               * so we just return success here.  Drivers that can't
 +               * (including those that use the primary plane helper's
 +               * update function) will return an error from their
 +               * update_plane handler.
 +               */
 +              return 0;
 +
 +      if (!can_position && !drm_rect_equals(dst, clip)) {
 +              DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
 +              drm_rect_debug_print("dst: ", dst, false);
 +              drm_rect_debug_print("clip: ", clip, false);
 +              return -EINVAL;
 +      }
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL(drm_atomic_helper_check_plane_state);
 +
  /**
   * drm_atomic_helper_check_planes - validate state object for planes changes
   * @dev: DRM device
@@@ -1001,12 -907,6 +1001,12 @@@ disable_outputs(struct drm_device *dev
   *
   * Drivers can use this for building their own atomic commit if they don't have
   * a pure helper-based modeset implementation.
 + *
 + * Since these updates are not synchronized with lockings, only code paths
 + * called from &drm_mode_config_helper_funcs.atomic_commit_tail can look at the
 + * legacy state filled out by this helper. Defacto this means this helper and
 + * the legacy state pointers are only really useful for transitioning an
 + * existing driver to the atomic world.
   */
  void
  drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
@@@ -1878,6 -1778,8 +1878,8 @@@ int drm_atomic_helper_setup_commit(stru
                new_crtc_state->event->base.completion = &commit->flip_done;
                new_crtc_state->event->base.completion_release = release_crtc_commit;
                drm_crtc_commit_get(commit);
+               commit->abort_completion = true;
        }
  
        for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
                    !try_wait_for_completion(&old_conn_state->commit->flip_done))
                        return -EBUSY;
  
 -              /* commit tracked through new_crtc_state->commit, no need to do it explicitly */
 -              if (new_conn_state->crtc)
 -                      continue;
 -
 -              commit = crtc_or_fake_commit(state, old_conn_state->crtc);
 +              /* Always track connectors explicitly for e.g. link retraining. */
 +              commit = crtc_or_fake_commit(state, new_conn_state->crtc ?: old_conn_state->crtc);
                if (!commit)
                        return -ENOMEM;
  
                    !try_wait_for_completion(&old_plane_state->commit->flip_done))
                        return -EBUSY;
  
 -              /*
 -               * Unlike connectors, always track planes explicitly for
 -               * async pageflip support.
 -               */
 +              /* Always track planes explicitly for async pageflip support. */
                commit = crtc_or_fake_commit(state, new_plane_state->crtc ?: old_plane_state->crtc);
                if (!commit)
                        return -ENOMEM;
@@@ -3421,8 -3329,21 +3423,21 @@@ EXPORT_SYMBOL(drm_atomic_helper_crtc_du
  void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
  {
        if (state->commit) {
+               /*
+                * In the event that a non-blocking commit returns
+                * -ERESTARTSYS before the commit_tail work is queued, we will
+                * have an extra reference to the commit object. Release it, if
+                * the event has not been consumed by the worker.
+                *
+                * state->event may be freed, so we can't directly look at
+                * state->event->base.completion.
+                */
+               if (state->event && state->commit->abort_completion)
+                       drm_crtc_commit_put(state->commit);
                kfree(state->commit->event);
                state->commit->event = NULL;
                drm_crtc_commit_put(state->commit);
        }
  
index 9796c29dc004ce961ac65c1576ca34b1c1155cd9,16fb76ba6509d981bf194792f433161c6b890168..4f751a9d71a34b858950ddae058bb50eaa281afa
@@@ -113,6 -113,9 +113,9 @@@ static const struct edid_quirk 
        /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
        { "AEO", 0, EDID_QUIRK_FORCE_6BPC },
  
+       /* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */
+       { "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC },
        /* Belinea 10 15 55 */
        { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 },
        { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 },
  
        /* HTC Vive VR Headset */
        { "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP },
 +
 +      /* Oculus Rift DK1, DK2, and CV1 VR Headsets */
 +      { "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP },
 +      { "OVR", 0x0003, EDID_QUIRK_NON_DESKTOP },
 +      { "OVR", 0x0004, EDID_QUIRK_NON_DESKTOP },
 +
 +      /* Windows Mixed Reality Headsets */
 +      { "ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP },
 +      { "HPN", 0x3515, EDID_QUIRK_NON_DESKTOP },
 +      { "LEN", 0x0408, EDID_QUIRK_NON_DESKTOP },
 +      { "LEN", 0xb800, EDID_QUIRK_NON_DESKTOP },
 +      { "FUJ", 0x1970, EDID_QUIRK_NON_DESKTOP },
 +      { "DEL", 0x7fce, EDID_QUIRK_NON_DESKTOP },
 +      { "SEC", 0x144a, EDID_QUIRK_NON_DESKTOP },
 +      { "AUS", 0xc102, EDID_QUIRK_NON_DESKTOP },
 +
 +      /* Sony PlayStation VR Headset */
 +      { "SNY", 0x0704, EDID_QUIRK_NON_DESKTOP },
  };
  
  /*
@@@ -3416,7 -3401,6 +3419,7 @@@ static in
  do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
                   const u8 *video_db, u8 video_len)
  {
 +      struct drm_display_info *info = &connector->display_info;
        int modes = 0, offset = 0, i, multi_present = 0, multi_len;
        u8 vic_len, hdmi_3d_len = 0;
        u16 mask;
        }
  
  out:
 +      if (modes > 0)
 +              info->has_hdmi_infoframe = true;
        return modes;
  }
  
@@@ -3782,8 -3764,8 +3785,8 @@@ drm_parse_hdmi_vsdb_audio(struct drm_co
  {
        u8 len = cea_db_payload_len(db);
  
 -      if (len >= 6)
 -              connector->eld[5] |= (db[6] >> 7) << 1;  /* Supports_AI */
 +      if (len >= 6 && (db[6] & (1 << 7)))
 +              connector->eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_SUPPORTS_AI;
        if (len >= 8) {
                connector->latency_present[0] = db[8] >> 7;
                connector->latency_present[1] = (db[8] >> 6) & 1;
@@@ -3855,27 -3837,16 +3858,27 @@@ void drm_edid_get_monitor_name(struct e
  }
  EXPORT_SYMBOL(drm_edid_get_monitor_name);
  
 -/**
 +static void clear_eld(struct drm_connector *connector)
 +{
 +      memset(connector->eld, 0, sizeof(connector->eld));
 +
 +      connector->latency_present[0] = false;
 +      connector->latency_present[1] = false;
 +      connector->video_latency[0] = 0;
 +      connector->audio_latency[0] = 0;
 +      connector->video_latency[1] = 0;
 +      connector->audio_latency[1] = 0;
 +}
 +
 +/*
   * drm_edid_to_eld - build ELD from EDID
   * @connector: connector corresponding to the HDMI/DP sink
   * @edid: EDID to parse
   *
   * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The
 - * Conn_Type, HDCP and Port_ID ELD fields are left for the graphics driver to
 - * fill in.
 + * HDCP and Port_ID ELD fields are left for the graphics driver to fill in.
   */
 -void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
 +static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
  {
        uint8_t *eld = connector->eld;
        u8 *cea;
        int mnl;
        int dbl;
  
 -      memset(eld, 0, sizeof(connector->eld));
 -
 -      connector->latency_present[0] = false;
 -      connector->latency_present[1] = false;
 -      connector->video_latency[0] = 0;
 -      connector->audio_latency[0] = 0;
 -      connector->video_latency[1] = 0;
 -      connector->audio_latency[1] = 0;
 +      clear_eld(connector);
  
        if (!edid)
                return;
                return;
        }
  
 -      mnl = get_monitor_name(edid, eld + 20);
 +      mnl = get_monitor_name(edid, &eld[DRM_ELD_MONITOR_NAME_STRING]);
 +      DRM_DEBUG_KMS("ELD monitor %s\n", &eld[DRM_ELD_MONITOR_NAME_STRING]);
  
 -      eld[4] = (cea[1] << 5) | mnl;
 -      DRM_DEBUG_KMS("ELD monitor %s\n", eld + 20);
 +      eld[DRM_ELD_CEA_EDID_VER_MNL] = cea[1] << DRM_ELD_CEA_EDID_VER_SHIFT;
 +      eld[DRM_ELD_CEA_EDID_VER_MNL] |= mnl;
  
 -      eld[0] = 2 << 3;                /* ELD version: 2 */
 +      eld[DRM_ELD_VER] = DRM_ELD_VER_CEA861D;
  
 -      eld[16] = edid->mfg_id[0];
 -      eld[17] = edid->mfg_id[1];
 -      eld[18] = edid->prod_code[0];
 -      eld[19] = edid->prod_code[1];
 +      eld[DRM_ELD_MANUFACTURER_NAME0] = edid->mfg_id[0];
 +      eld[DRM_ELD_MANUFACTURER_NAME1] = edid->mfg_id[1];
 +      eld[DRM_ELD_PRODUCT_CODE0] = edid->prod_code[0];
 +      eld[DRM_ELD_PRODUCT_CODE1] = edid->prod_code[1];
  
        if (cea_revision(cea) >= 3) {
                int i, start, end;
                                /* Audio Data Block, contains SADs */
                                sad_count = min(dbl / 3, 15 - total_sad_count);
                                if (sad_count >= 1)
 -                                      memcpy(eld + 20 + mnl + total_sad_count * 3,
 +                                      memcpy(&eld[DRM_ELD_CEA_SAD(mnl, total_sad_count)],
                                               &db[1], sad_count * 3);
                                total_sad_count += sad_count;
                                break;
                        case SPEAKER_BLOCK:
                                /* Speaker Allocation Data Block */
                                if (dbl >= 1)
 -                                      eld[7] = db[1];
 +                                      eld[DRM_ELD_SPEAKER] = db[1];
                                break;
                        case VENDOR_BLOCK:
                                /* HDMI Vendor-Specific Data Block */
                        }
                }
        }
 -      eld[5] |= total_sad_count << 4;
 +      eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= total_sad_count << DRM_ELD_SAD_COUNT_SHIFT;
 +
 +      if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
 +          connector->connector_type == DRM_MODE_CONNECTOR_eDP)
 +              eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_DP;
 +      else
 +              eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_HDMI;
  
        eld[DRM_ELD_BASELINE_ELD_LEN] =
                DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4);
        DRM_DEBUG_KMS("ELD size %d, SAD count %d\n",
                      drm_eld_size(eld), total_sad_count);
  }
 -EXPORT_SYMBOL(drm_edid_to_eld);
  
  /**
   * drm_edid_to_sad - extracts SADs from EDID
@@@ -4269,8 -4241,6 +4272,8 @@@ static void drm_parse_hdmi_forum_vsdb(s
        struct drm_display_info *display = &connector->display_info;
        struct drm_hdmi_info *hdmi = &display->hdmi;
  
 +      display->has_hdmi_infoframe = true;
 +
        if (hf_vsdb[6] & 0x80) {
                hdmi->scdc.supported = true;
                if (hf_vsdb[6] & 0x40)
@@@ -4446,7 -4416,6 +4449,7 @@@ drm_reset_display_info(struct drm_conne
        info->cea_rev = 0;
        info->max_tmds_clock = 0;
        info->dvi_dual = false;
 +      info->has_hdmi_infoframe = false;
  
        info->non_desktop = 0;
  }
@@@ -4467,7 -4436,6 +4470,7 @@@ u32 drm_add_display_info(struct drm_con
        info->cea_rev = 0;
        info->max_tmds_clock = 0;
        info->dvi_dual = false;
 +      info->has_hdmi_infoframe = false;
  
        info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
  
@@@ -4669,8 -4637,8 +4672,8 @@@ static int add_displayid_detailed_modes
   * @edid: EDID data
   *
   * Add the specified modes to the connector's mode list. Also fills out the
 - * &drm_display_info structure in @connector with any information which can be
 - * derived from the edid.
 + * &drm_display_info structure and ELD in @connector with any information which
 + * can be derived from the edid.
   *
   * Return: The number of modes added or 0 if we couldn't find any.
   */
@@@ -4680,18 -4648,14 +4683,18 @@@ int drm_add_edid_modes(struct drm_conne
        u32 quirks;
  
        if (edid == NULL) {
 +              clear_eld(connector);
                return 0;
        }
        if (!drm_edid_is_valid(edid)) {
 +              clear_eld(connector);
                dev_warn(connector->dev->dev, "%s: EDID invalid.\n",
                         connector->name);
                return 0;
        }
  
 +      drm_edid_to_eld(connector, edid);
 +
        /*
         * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks.
         * To avoid multiple parsing of same block, lets parse that map
@@@ -4889,11 -4853,6 +4892,11 @@@ EXPORT_SYMBOL(drm_hdmi_avi_infoframe_fr
   * @mode: DRM display mode
   * @rgb_quant_range: RGB quantization range (Q)
   * @rgb_quant_range_selectable: Sink support selectable RGB quantization range (QS)
 + * @is_hdmi2_sink: HDMI 2.0 sink, which has different default recommendations
 + *
 + * Note that @is_hdmi2_sink can be derived by looking at the
 + * &drm_scdc.supported flag stored in &drm_hdmi_info.scdc,
 + * &drm_display_info.hdmi, which can be found in &drm_connector.display_info.
   */
  void
  drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,
@@@ -4972,7 -4931,6 +4975,7 @@@ s3d_structure_from_display_mode(const s
   * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with
   * data from a DRM display mode
   * @frame: HDMI vendor infoframe
 + * @connector: the connector
   * @mode: DRM display mode
   *
   * Note that there's is a need to send HDMI vendor infoframes only when using a
   */
  int
  drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
 +                                          struct drm_connector *connector,
                                            const struct drm_display_mode *mode)
  {
 +      /*
 +       * FIXME: sil-sii8620 doesn't have a connector around when
 +       * we need one, so we have to be prepared for a NULL connector.
 +       */
 +      bool has_hdmi_infoframe = connector ?
 +              connector->display_info.has_hdmi_infoframe : false;
        int err;
        u32 s3d_flags;
        u8 vic;
        if (!frame || !mode)
                return -EINVAL;
  
 +      if (!has_hdmi_infoframe)
 +              return -EINVAL;
 +
        vic = drm_match_hdmi_mode(mode);
        s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK;
  
 -      if (!vic && !s3d_flags)
 -              return -EINVAL;
 +      /*
 +       * Even if it's not absolutely necessary to send the infoframe
 +       * (ie.vic==0 and s3d_struct==0) we will still send it if we
 +       * know that the sink can handle it. This is based on a
 +       * suggestion in HDMI 2.0 Appendix F. Apparently some sinks
 +       * have trouble realizing that they shuld switch from 3D to 2D
 +       * mode if the source simply stops sending the infoframe when
 +       * it wants to switch from 3D to 2D.
 +       */
  
        if (vic && s3d_flags)
                return -EINVAL;
        if (err < 0)
                return err;
  
 -      if (vic)
 -              frame->vic = vic;
 -      else
 -              frame->s3d_struct = s3d_structure_from_display_mode(mode);
 +      frame->vic = vic;
 +      frame->s3d_struct = s3d_structure_from_display_mode(mode);
  
        return 0;
  }
diff --combined drivers/gpu/drm/drm_mm.c
index 186c4e90cc1cd25e06a19a89da1bf88a7d9e0cf7,edab571dbc90546627ef48b2f22574cdfa29fa61..89eef1bb4ddc3f606dea32ac24a3702c7293152c
@@@ -92,7 -92,7 +92,7 @@@
   * some basic allocator dumpers for debugging.
   *
   * Note that this range allocator is not thread-safe, drivers need to protect
 - * modifications with their on locking. The idea behind this is that for a full
 + * modifications with their own locking. The idea behind this is that for a full
   * memory manager additional data needs to be protected anyway, hence internal
   * locking would be fully redundant.
   */
@@@ -836,9 -836,24 +836,24 @@@ struct drm_mm_node *drm_mm_scan_color_e
        if (!mm->color_adjust)
                return NULL;
  
-       hole = list_first_entry(&mm->hole_stack, typeof(*hole), hole_stack);
-       hole_start = __drm_mm_hole_node_start(hole);
-       hole_end = hole_start + hole->hole_size;
+       /*
+        * The hole found during scanning should ideally be the first element
+        * in the hole_stack list, but due to side-effects in the driver it
+        * may not be.
+        */
+       list_for_each_entry(hole, &mm->hole_stack, hole_stack) {
+               hole_start = __drm_mm_hole_node_start(hole);
+               hole_end = hole_start + hole->hole_size;
+               if (hole_start <= scan->hit_start &&
+                   hole_end >= scan->hit_end)
+                       break;
+       }
+       /* We should only be called after we found the hole previously */
+       DRM_MM_BUG_ON(&hole->hole_stack == &mm->hole_stack);
+       if (unlikely(&hole->hole_stack == &mm->hole_stack))
+               return NULL;
  
        DRM_MM_BUG_ON(hole_start > scan->hit_start);
        DRM_MM_BUG_ON(hole_end < scan->hit_end);
index 555fbe54d6e224e2b58a7d263353efac2d7e0104,7a6b2dc08913ecffd856432e10542b1bf4614902..00b8445ba8192b63bf6015eb1442342c39b47378
@@@ -216,7 -216,8 +216,7 @@@ enum drm_mode_status drm_connector_mode
   * suspend/resume.
   *
   * Drivers can call this helper from their device resume implementation. It is
 - * an error to call this when the output polling support has not yet been set
 - * up.
 + * not an error to call this even when output polling isn't enabled.
   *
   * Note that calls to enable and disable polling must be strictly ordered, which
   * is automatically the case when they're only call from suspend/resume
@@@ -653,6 -654,26 +653,26 @@@ out
                schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
  }
  
+ /**
+  * drm_kms_helper_is_poll_worker - is %current task an output poll worker?
+  *
+  * Determine if %current task is an output poll worker.  This can be used
+  * to select distinct code paths for output polling versus other contexts.
+  *
+  * One use case is to avoid a deadlock between the output poll worker and
+  * the autosuspend worker wherein the latter waits for polling to finish
+  * upon calling drm_kms_helper_poll_disable(), while the former waits for
+  * runtime suspend to finish upon calling pm_runtime_get_sync() in a
+  * connector ->detect hook.
+  */
+ bool drm_kms_helper_is_poll_worker(void)
+ {
+       struct work_struct *work = current_work();
+       return work && work->func == output_poll_execute;
+ }
+ EXPORT_SYMBOL(drm_kms_helper_is_poll_worker);
  /**
   * drm_kms_helper_poll_disable - disable output polling
   * @dev: drm_device
index d0a6ac8390f39fd64dd194b76c3078e374ef51f2,0b6011b8d6321a2e32e7aaaace5d85828e725d8b..27bd3503e1e49eb82b51a9b2cf11bfd7593da20a
@@@ -61,10 -61,10 +61,10 @@@ static int meson_plane_atomic_check(str
        clip.x2 = crtc_state->mode.hdisplay;
        clip.y2 = crtc_state->mode.vdisplay;
  
 -      return drm_plane_helper_check_state(state, &clip,
 -                                          DRM_PLANE_HELPER_NO_SCALING,
 -                                          DRM_PLANE_HELPER_NO_SCALING,
 -                                          true, true);
 +      return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
 +                                                 DRM_PLANE_HELPER_NO_SCALING,
 +                                                 DRM_PLANE_HELPER_NO_SCALING,
 +                                                 true, true);
  }
  
  /* Takes a fixed 16.16 number and converts it to integer. */
@@@ -164,10 -164,9 +164,9 @@@ static void meson_plane_atomic_update(s
        /* Update Canvas with buffer address */
        gem = drm_fb_cma_get_gem_obj(fb, 0);
  
-       meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
-                          gem->paddr, fb->pitches[0],
-                          fb->height, MESON_CANVAS_WRAP_NONE,
-                          MESON_CANVAS_BLKMODE_LINEAR);
+       priv->viu.osd1_addr = gem->paddr;
+       priv->viu.osd1_stride = fb->pitches[0];
+       priv->viu.osd1_height = fb->height;
  
        spin_unlock_irqrestore(&priv->drm->event_lock, flags);
  }
index 5012f5e47a1e599d1758b91957d79925487de260,30e129684c7cf828982a3d1dfdf4e8ba8030038b..2e2ca3c6b47d374fc6650d15bfab5d7934740a2f
@@@ -392,6 -392,7 +392,6 @@@ static int radeon_ddc_get_modes(struct 
        if (radeon_connector->edid) {
                drm_mode_connector_update_edid_property(connector, radeon_connector->edid);
                ret = drm_add_edid_modes(connector, radeon_connector->edid);
 -              drm_edid_to_eld(connector, radeon_connector->edid);
                return ret;
        }
        drm_mode_connector_update_edid_property(connector, NULL);
@@@ -899,9 -900,11 +899,11 @@@ radeon_lvds_detect(struct drm_connecto
        enum drm_connector_status ret = connector_status_disconnected;
        int r;
  
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
  
        if (encoder) {
                struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        /* check acpi lid status ??? */
  
        radeon_connector_update_scratch_regs(connector, ret);
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
        return ret;
  }
  
@@@ -1039,9 -1046,11 +1045,11 @@@ radeon_vga_detect(struct drm_connector 
        enum drm_connector_status ret = connector_status_disconnected;
        int r;
  
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
  
        encoder = radeon_best_single_encoder(connector);
        if (!encoder)
        radeon_connector_update_scratch_regs(connector, ret);
  
  out:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
  
        return ret;
  }
@@@ -1173,9 -1184,11 +1183,11 @@@ radeon_tv_detect(struct drm_connector *
        if (!radeon_connector->dac_load_detect)
                return ret;
  
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
  
        encoder = radeon_best_single_encoder(connector);
        if (!encoder)
        if (ret == connector_status_connected)
                ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
        radeon_connector_update_scratch_regs(connector, ret);
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
        return ret;
  }
  
@@@ -1251,9 -1268,11 +1267,11 @@@ radeon_dvi_detect(struct drm_connector 
        enum drm_connector_status ret = connector_status_disconnected;
        bool dret = false, broken_edid = false;
  
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
  
        if (radeon_connector->detected_hpd_without_ddc) {
                force = true;
        }
  
  exit:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
  
        return ret;
  }
@@@ -1688,9 -1709,11 +1708,11 @@@ radeon_dp_detect(struct drm_connector *
        if (radeon_dig_connector->is_mst)
                return connector_status_disconnected;
  
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
  
        if (!force && radeon_check_hpd_status_unchanged(connector)) {
                ret = connector->status;
        }
  
  out:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
  
        return ret;
  }
diff --combined include/drm/drm_atomic.h
index 1c27526c499eed6f50b46771aaea27282567deb9,c63b0b48e884cc9dbc38ef0428b2d0ad761a2775..cf13842a6dbd1fa8808f4e9c0d49a5f9b012c931
@@@ -134,6 -134,15 +134,15 @@@ struct drm_crtc_commit 
         * &drm_pending_vblank_event pointer to clean up private events.
         */
        struct drm_pending_vblank_event *event;
+       /**
+        * @abort_completion:
+        *
+        * A flag that's set after drm_atomic_helper_setup_commit takes a second
+        * reference for the completion of $drm_crtc_state.event. It's used by
+        * the free code to remove the second reference if commit fails.
+        */
+       bool abort_completion;
  };
  
  struct __drm_planes_state {
@@@ -189,40 -198,12 +198,40 @@@ struct drm_private_state_funcs 
                                     struct drm_private_state *state);
  };
  
 +/**
 + * struct drm_private_obj - base struct for driver private atomic object
 + *
 + * A driver private object is initialized by calling
 + * drm_atomic_private_obj_init() and cleaned up by calling
 + * drm_atomic_private_obj_fini().
 + *
 + * Currently only tracks the state update functions and the opaque driver
 + * private state itself, but in the future might also track which
 + * &drm_modeset_lock is required to duplicate and update this object's state.
 + */
  struct drm_private_obj {
 +      /**
 +       * @state: Current atomic state for this driver private object.
 +       */
        struct drm_private_state *state;
  
 +      /**
 +       * @funcs:
 +       *
 +       * Functions to manipulate the state of this driver private object, see
 +       * &drm_private_state_funcs.
 +       */
        const struct drm_private_state_funcs *funcs;
  };
  
 +/**
 + * struct drm_private_state - base struct for driver private object state
 + * @state: backpointer to global drm_atomic_state
 + *
 + * Currently only contains a backpointer to the overall atomic update, but in
 + * the future also might hold synchronization information similar to e.g.
 + * &drm_crtc.commit.
 + */
  struct drm_private_state {
        struct drm_atomic_state *state;
  };
@@@ -246,10 -227,6 +255,10 @@@ struct __drm_private_objs_state 
   * @num_private_objs: size of the @private_objs array
   * @private_objs: pointer to array of private object pointers
   * @acquire_ctx: acquire context for this atomic modeset state update
 + *
 + * States are added to an atomic update by calling drm_atomic_get_crtc_state(),
 + * drm_atomic_get_plane_state(), drm_atomic_get_connector_state(), or for
 + * private state structures, drm_atomic_get_private_obj_state().
   */
  struct drm_atomic_state {
        struct kref ref;
diff --combined kernel/workqueue.c
index 017044c2623373455274a1d642cecc7e3c4811aa,255c20efdf7bd468a5ffd9dd7d317c2582c9790c..bb9a519cbf5093ece372daa532121f1511957999
@@@ -48,7 -48,6 +48,7 @@@
  #include <linux/moduleparam.h>
  #include <linux/uaccess.h>
  #include <linux/sched/isolation.h>
 +#include <linux/nmi.h>
  
  #include "workqueue_internal.h"
  
@@@ -2136,7 -2135,7 +2136,7 @@@ __acquires(&pool->lock
         * stop_machine. At the same time, report a quiescent RCU state so
         * the same condition doesn't freeze RCU.
         */
 -      cond_resched_rcu_qs();
 +      cond_resched();
  
        spin_lock_irq(&pool->lock);
  
@@@ -3807,7 -3806,6 +3807,7 @@@ int apply_workqueue_attrs(struct workqu
  
        return ret;
  }
 +EXPORT_SYMBOL_GPL(apply_workqueue_attrs);
  
  /**
   * wq_update_unbound_numa - update NUMA affinity of a wq for CPU hot[un]plug
@@@ -3941,37 -3939,6 +3941,37 @@@ static int wq_clamp_max_active(int max_
        return clamp_val(max_active, 1, lim);
  }
  
 +/*
 + * Workqueues which may be used during memory reclaim should have a rescuer
 + * to guarantee forward progress.
 + */
 +static int init_rescuer(struct workqueue_struct *wq)
 +{
 +      struct worker *rescuer;
 +      int ret;
 +
 +      if (!(wq->flags & WQ_MEM_RECLAIM))
 +              return 0;
 +
 +      rescuer = alloc_worker(NUMA_NO_NODE);
 +      if (!rescuer)
 +              return -ENOMEM;
 +
 +      rescuer->rescue_wq = wq;
 +      rescuer->task = kthread_create(rescuer_thread, rescuer, "%s", wq->name);
 +      ret = PTR_ERR_OR_ZERO(rescuer->task);
 +      if (ret) {
 +              kfree(rescuer);
 +              return ret;
 +      }
 +
 +      wq->rescuer = rescuer;
 +      kthread_bind_mask(rescuer->task, cpu_possible_mask);
 +      wake_up_process(rescuer->task);
 +
 +      return 0;
 +}
 +
  struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
                                               unsigned int flags,
                                               int max_active,
        if (alloc_and_link_pwqs(wq) < 0)
                goto err_free_wq;
  
 -      /*
 -       * Workqueues which may be used during memory reclaim should
 -       * have a rescuer to guarantee forward progress.
 -       */
 -      if (flags & WQ_MEM_RECLAIM) {
 -              struct worker *rescuer;
 -
 -              rescuer = alloc_worker(NUMA_NO_NODE);
 -              if (!rescuer)
 -                      goto err_destroy;
 -
 -              rescuer->rescue_wq = wq;
 -              rescuer->task = kthread_create(rescuer_thread, rescuer, "%s",
 -                                             wq->name);
 -              if (IS_ERR(rescuer->task)) {
 -                      kfree(rescuer);
 -                      goto err_destroy;
 -              }
 -
 -              wq->rescuer = rescuer;
 -              kthread_bind_mask(rescuer->task, cpu_possible_mask);
 -              wake_up_process(rescuer->task);
 -      }
 +      if (wq_online && init_rescuer(wq) < 0)
 +              goto err_destroy;
  
        if ((wq->flags & WQ_SYSFS) && workqueue_sysfs_register(wq))
                goto err_destroy;
@@@ -4179,6 -4167,22 +4179,22 @@@ void workqueue_set_max_active(struct wo
  }
  EXPORT_SYMBOL_GPL(workqueue_set_max_active);
  
+ /**
+  * current_work - retrieve %current task's work struct
+  *
+  * Determine if %current task is a workqueue worker and what it's working on.
+  * Useful to find out the context that the %current task is running in.
+  *
+  * Return: work struct if %current task is a workqueue worker, %NULL otherwise.
+  */
+ struct work_struct *current_work(void)
+ {
+       struct worker *worker = current_wq_worker();
+       return worker ? worker->current_work : NULL;
+ }
+ EXPORT_SYMBOL(current_work);
  /**
   * current_is_workqueue_rescuer - is %current workqueue rescuer?
   *
@@@ -4475,12 -4479,6 +4491,12 @@@ void show_workqueue_state(void
                        if (pwq->nr_active || !list_empty(&pwq->delayed_works))
                                show_pwq(pwq);
                        spin_unlock_irqrestore(&pwq->pool->lock, flags);
 +                      /*
 +                       * We could be printing a lot from atomic context, e.g.
 +                       * sysrq-t -> show_workqueue_state(). Avoid triggering
 +                       * hard lockup.
 +                       */
 +                      touch_nmi_watchdog();
                }
        }
  
                pr_cont("\n");
        next_pool:
                spin_unlock_irqrestore(&pool->lock, flags);
 +              /*
 +               * We could be printing a lot from atomic context, e.g.
 +               * sysrq-t -> show_workqueue_state(). Avoid triggering
 +               * hard lockup.
 +               */
 +              touch_nmi_watchdog();
        }
  
        rcu_read_unlock_sched();
@@@ -5653,8 -5645,6 +5669,8 @@@ int __init workqueue_init(void
         * archs such as power and arm64.  As per-cpu pools created
         * previously could be missing node hint and unbound pools NUMA
         * affinity, fix them up.
 +       *
 +       * Also, while iterating workqueues, create rescuers if requested.
         */
        wq_numa_init();
  
                }
        }
  
 -      list_for_each_entry(wq, &workqueues, list)
 +      list_for_each_entry(wq, &workqueues, list) {
                wq_update_unbound_numa(wq, smp_processor_id(), true);
 +              WARN(init_rescuer(wq),
 +                   "workqueue: failed to create early rescuer for %s",
 +                   wq->name);
 +      }
  
        mutex_unlock(&wq_pool_mutex);