Merge drm/drm-fixes into drm-misc-fixes
authorThomas Zimmermann <tzimmermann@suse.de>
Mon, 13 Mar 2023 09:14:05 +0000 (10:14 +0100)
committerThomas Zimmermann <tzimmermann@suse.de>
Mon, 13 Mar 2023 09:14:05 +0000 (10:14 +0100)
Backmerging to get latest upstream.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
1  2 
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_gem_shmem_helper.c
drivers/gpu/drm/ttm/ttm_device.c
drivers/gpu/drm/virtio/virtgpu_vq.c
drivers/video/fbdev/core/fb_defio.c
include/drm/drm_gem.h
include/linux/fb.h

@@@ -96,7 -96,6 +96,6 @@@ struct detailed_mode_closure 
        struct drm_connector *connector;
        const struct drm_edid *drm_edid;
        bool preferred;
-       u32 quirks;
        int modes;
  };
  
@@@ -2797,7 -2796,7 +2796,7 @@@ u32 drm_edid_get_panel_id(struct i2c_ad
         * the EDID then we'll just return 0.
         */
  
 -      base_block = kmalloc(EDID_LENGTH, GFP_KERNEL);
 +      base_block = kzalloc(EDID_LENGTH, GFP_KERNEL);
        if (!base_block)
                return 0;
  
@@@ -2887,9 -2886,9 +2886,9 @@@ static u32 edid_get_quirks(const struc
   * Walk the mode list for connector, clearing the preferred status on existing
   * modes and setting it anew for the right mode ala quirks.
   */
- static void edid_fixup_preferred(struct drm_connector *connector,
-                                u32 quirks)
+ static void edid_fixup_preferred(struct drm_connector *connector)
  {
+       const struct drm_display_info *info = &connector->display_info;
        struct drm_display_mode *t, *cur_mode, *preferred_mode;
        int target_refresh = 0;
        int cur_vrefresh, preferred_vrefresh;
        if (list_empty(&connector->probed_modes))
                return;
  
-       if (quirks & EDID_QUIRK_PREFER_LARGE_60)
+       if (info->quirks & EDID_QUIRK_PREFER_LARGE_60)
                target_refresh = 60;
-       if (quirks & EDID_QUIRK_PREFER_LARGE_75)
+       if (info->quirks & EDID_QUIRK_PREFER_LARGE_75)
                target_refresh = 75;
  
        preferred_mode = list_first_entry(&connector->probed_modes,
@@@ -3401,9 -3400,9 +3400,9 @@@ drm_mode_do_interlace_quirk(struct drm_
   */
  static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connector,
                                                  const struct drm_edid *drm_edid,
-                                                 const struct detailed_timing *timing,
-                                                 u32 quirks)
+                                                 const struct detailed_timing *timing)
  {
+       const struct drm_display_info *info = &connector->display_info;
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *mode;
        const struct detailed_pixel_timing *pt = &timing->data.pixel_data;
                return NULL;
        }
  
-       if (quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) {
+       if (info->quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) {
                mode = drm_cvt_mode(dev, hactive, vactive, 60, true, false, false);
                if (!mode)
                        return NULL;
        if (!mode)
                return NULL;
  
-       if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH)
+       if (info->quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH)
                mode->clock = 1088 * 10;
        else
                mode->clock = le16_to_cpu(timing->pixel_clock) * 10;
  
        drm_mode_do_interlace_quirk(mode, pt);
  
-       if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
+       if (info->quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
                mode->flags |= DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC;
        } else {
                mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ?
@@@ -3485,12 -3484,12 +3484,12 @@@ set_size
        mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
        mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
  
-       if (quirks & EDID_QUIRK_DETAILED_IN_CM) {
+       if (info->quirks & EDID_QUIRK_DETAILED_IN_CM) {
                mode->width_mm *= 10;
                mode->height_mm *= 10;
        }
  
-       if (quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
+       if (info->quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
                mode->width_mm = drm_edid->edid->width_cm * 10;
                mode->height_mm = drm_edid->edid->height_cm * 10;
        }
@@@ -4003,8 -4002,7 +4002,7 @@@ do_detailed_mode(const struct detailed_
                return;
  
        newmode = drm_mode_detailed(closure->connector,
-                                   closure->drm_edid, timing,
-                                   closure->quirks);
+                                   closure->drm_edid, timing);
        if (!newmode)
                return;
  
   * add_detailed_modes - Add modes from detailed timings
   * @connector: attached connector
   * @drm_edid: EDID block to scan
-  * @quirks: quirks to apply
   */
  static int add_detailed_modes(struct drm_connector *connector,
-                             const struct drm_edid *drm_edid, u32 quirks)
+                             const struct drm_edid *drm_edid)
  {
        struct detailed_mode_closure closure = {
                .connector = connector,
                .drm_edid = drm_edid,
-               .quirks = quirks,
        };
  
        if (drm_edid->edid->revision >= 4)
@@@ -4468,28 -4464,20 +4464,20 @@@ static u8 svd_to_vic(u8 svd
        return svd;
  }
  
+ /*
+  * Return a display mode for the 0-based vic_index'th VIC across all CTA VDBs in
+  * the EDID, or NULL on errors.
+  */
  static struct drm_display_mode *
- drm_display_mode_from_vic_index(struct drm_connector *connector,
-                               const u8 *video_db, u8 video_len,
-                               u8 video_index)
+ drm_display_mode_from_vic_index(struct drm_connector *connector, int vic_index)
  {
+       const struct drm_display_info *info = &connector->display_info;
        struct drm_device *dev = connector->dev;
-       struct drm_display_mode *newmode;
-       u8 vic;
-       if (video_db == NULL || video_index >= video_len)
-               return NULL;
  
-       /* CEA modes are numbered 1..127 */
-       vic = svd_to_vic(video_db[video_index]);
-       if (!drm_valid_cea_vic(vic))
-               return NULL;
-       newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic));
-       if (!newmode)
+       if (!info->vics || vic_index >= info->vics_len || !info->vics[vic_index])
                return NULL;
  
-       return newmode;
+       return drm_display_mode_from_cea_vic(dev, info->vics[vic_index]);
  }
  
  /*
  static int do_y420vdb_modes(struct drm_connector *connector,
                            const u8 *svds, u8 svds_len)
  {
-       int modes = 0, i;
        struct drm_device *dev = connector->dev;
-       struct drm_display_info *info = &connector->display_info;
-       struct drm_hdmi_info *hdmi = &info->hdmi;
+       int modes = 0, i;
  
        for (i = 0; i < svds_len; i++) {
                u8 vic = svd_to_vic(svds[i]);
                newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic));
                if (!newmode)
                        break;
-               bitmap_set(hdmi->y420_vdb_modes, vic, 1);
                drm_mode_probed_add(connector, newmode);
                modes++;
        }
  
-       if (modes > 0)
-               info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
        return modes;
  }
  
- /*
-  * drm_add_cmdb_modes - Add a YCBCR 420 mode into bitmap
-  * @connector: connector corresponding to the HDMI sink
-  * @vic: CEA vic for the video mode to be added in the map
-  *
-  * Makes an entry for a videomode in the YCBCR 420 bitmap
-  */
- static void
- drm_add_cmdb_modes(struct drm_connector *connector, u8 svd)
- {
-       u8 vic = svd_to_vic(svd);
-       struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
-       if (!drm_valid_cea_vic(vic))
-               return;
-       bitmap_set(hdmi->y420_cmdb_modes, vic, 1);
- }
  /**
   * drm_display_mode_from_cea_vic() - return a mode for CEA VIC
   * @dev: DRM device
@@@ -4577,29 -4541,20 +4541,20 @@@ drm_display_mode_from_cea_vic(struct dr
  }
  EXPORT_SYMBOL(drm_display_mode_from_cea_vic);
  
- static int
do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
+ /* Add modes based on VICs parsed in parse_cta_vdb() */
static int add_cta_vdb_modes(struct drm_connector *connector)
  {
+       const struct drm_display_info *info = &connector->display_info;
        int i, modes = 0;
-       struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
  
-       for (i = 0; i < len; i++) {
+       if (!info->vics)
+               return 0;
+       for (i = 0; i < info->vics_len; i++) {
                struct drm_display_mode *mode;
  
-               mode = drm_display_mode_from_vic_index(connector, db, len, i);
+               mode = drm_display_mode_from_vic_index(connector, i);
                if (mode) {
-                       /*
-                        * YCBCR420 capability block contains a bitmap which
-                        * gives the index of CEA modes from CEA VDB, which
-                        * can support YCBCR 420 sampling output also (apart
-                        * from RGB/YCBCR444 etc).
-                        * For example, if the bit 0 in bitmap is set,
-                        * first mode in VDB can support YCBCR420 output too.
-                        * Add YCBCR420 modes only if sink is HDMI 2.0 capable.
-                        */
-                       if (i < 64 && hdmi->y420_cmdb_map & (1ULL << i))
-                               drm_add_cmdb_modes(connector, db[i]);
                        drm_mode_probed_add(connector, mode);
                        modes++;
                }
@@@ -4693,15 -4648,13 +4648,13 @@@ static int add_hdmi_mode(struct drm_con
  }
  
  static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
-                              const u8 *video_db, u8 video_len, u8 video_index)
+                              int vic_index)
  {
        struct drm_display_mode *newmode;
        int modes = 0;
  
        if (structure & (1 << 0)) {
-               newmode = drm_display_mode_from_vic_index(connector, video_db,
-                                                         video_len,
-                                                         video_index);
+               newmode = drm_display_mode_from_vic_index(connector, vic_index);
                if (newmode) {
                        newmode->flags |= DRM_MODE_FLAG_3D_FRAME_PACKING;
                        drm_mode_probed_add(connector, newmode);
                }
        }
        if (structure & (1 << 6)) {
-               newmode = drm_display_mode_from_vic_index(connector, video_db,
-                                                         video_len,
-                                                         video_index);
+               newmode = drm_display_mode_from_vic_index(connector, vic_index);
                if (newmode) {
                        newmode->flags |= DRM_MODE_FLAG_3D_TOP_AND_BOTTOM;
                        drm_mode_probed_add(connector, newmode);
                }
        }
        if (structure & (1 << 8)) {
-               newmode = drm_display_mode_from_vic_index(connector, video_db,
-                                                         video_len,
-                                                         video_index);
+               newmode = drm_display_mode_from_vic_index(connector, vic_index);
                if (newmode) {
                        newmode->flags |= DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF;
                        drm_mode_probed_add(connector, newmode);
        return modes;
  }
  
+ static bool hdmi_vsdb_latency_present(const u8 *db)
+ {
+       return db[8] & BIT(7);
+ }
+ static bool hdmi_vsdb_i_latency_present(const u8 *db)
+ {
+       return hdmi_vsdb_latency_present(db) && db[8] & BIT(6);
+ }
+ static int hdmi_vsdb_latency_length(const u8 *db)
+ {
+       if (hdmi_vsdb_i_latency_present(db))
+               return 4;
+       else if (hdmi_vsdb_latency_present(db))
+               return 2;
+       else
+               return 0;
+ }
  /*
   * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block
   * @connector: connector corresponding to the HDMI sink
   * also adds the stereo 3d modes when applicable.
   */
  static int
- do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
-                  const u8 *video_db, u8 video_len)
+ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 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;
        if (!(db[8] & (1 << 5)))
                goto out;
  
-       /* Latency_Fields_Present */
-       if (db[8] & (1 << 7))
-               offset += 2;
-       /* I_Latency_Fields_Present */
-       if (db[8] & (1 << 6))
-               offset += 2;
+       offset += hdmi_vsdb_latency_length(db);
  
        /* the declared length is not long enough for the 2 first bytes
         * of additional video format capabilities */
                for (i = 0; i < 16; i++) {
                        if (mask & (1 << i))
                                modes += add_3d_struct_modes(connector,
-                                               structure_all,
-                                               video_db,
-                                               video_len, i);
+                                                            structure_all, i);
                }
        }
  
  
                if (newflag != 0) {
                        newmode = drm_display_mode_from_vic_index(connector,
-                                                                 video_db,
-                                                                 video_len,
                                                                  vic_index);
  
                        if (newmode) {
        }
  
  out:
-       if (modes > 0)
-               info->has_hdmi_infoframe = true;
        return modes;
  }
  
@@@ -5204,20 -5159,26 +5159,26 @@@ static int edid_hfeeodb_extension_block
        return cta[4 + 2];
  }
  
- static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector,
-                                     const u8 *db)
+ /*
+  * CTA-861 YCbCr 4:2:0 Capability Map Data Block (CTA Y420CMDB)
+  *
+  * Y420CMDB contains a bitmap which gives the index of CTA modes from CTA VDB,
+  * which can support YCBCR 420 sampling output also (apart from RGB/YCBCR444
+  * etc). For example, if the bit 0 in bitmap is set, first mode in VDB can
+  * support YCBCR420 output too.
+  */
+ static void parse_cta_y420cmdb(struct drm_connector *connector,
+                              const struct cea_db *db, u64 *y420cmdb_map)
  {
        struct drm_display_info *info = &connector->display_info;
-       struct drm_hdmi_info *hdmi = &info->hdmi;
-       u8 map_len = cea_db_payload_len(db) - 1;
-       u8 count;
+       int i, map_len = cea_db_payload_len(db) - 1;
+       const u8 *data = cea_db_data(db) + 1;
        u64 map = 0;
  
        if (map_len == 0) {
                /* All CEA modes support ycbcr420 sampling also.*/
-               hdmi->y420_cmdb_map = U64_MAX;
-               info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
-               return;
+               map = U64_MAX;
+               goto out;
        }
  
        /*
        if (WARN_ON_ONCE(map_len > 8))
                map_len = 8;
  
-       for (count = 0; count < map_len; count++)
-               map |= (u64)db[2 + count] << (8 * count);
+       for (i = 0; i < map_len; i++)
+               map |= (u64)data[i] << (8 * i);
  
+ out:
        if (map)
                info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
  
-       hdmi->y420_cmdb_map = map;
+       *y420cmdb_map = map;
  }
  
  static int add_cea_modes(struct drm_connector *connector,
  {
        const struct cea_db *db;
        struct cea_db_iter iter;
-       int modes = 0;
+       int modes;
+       /* CTA VDB block VICs parsed earlier */
+       modes = add_cta_vdb_modes(connector);
  
        cea_db_iter_edid_begin(drm_edid, &iter);
        cea_db_iter_for_each(db, &iter) {
-               const u8 *hdmi = NULL, *video = NULL;
-               u8 hdmi_len = 0, video_len = 0;
-               if (cea_db_tag(db) == CTA_DB_VIDEO) {
-                       video = cea_db_data(db);
-                       video_len = cea_db_payload_len(db);
-                       modes += do_cea_modes(connector, video, video_len);
-               } else if (cea_db_is_hdmi_vsdb(db)) {
-                       /* FIXME: Switch to use cea_db_data() */
-                       hdmi = (const u8 *)db;
-                       hdmi_len = cea_db_payload_len(db);
+               if (cea_db_is_hdmi_vsdb(db)) {
+                       modes += do_hdmi_vsdb_modes(connector, (const u8 *)db,
+                                                   cea_db_payload_len(db));
                } else if (cea_db_is_y420vdb(db)) {
                        const u8 *vdb420 = cea_db_data(db) + 1;
  
                        modes += do_y420vdb_modes(connector, vdb420,
                                                  cea_db_payload_len(db) - 1);
                }
-               /*
-                * We parse the HDMI VSDB after having added the cea modes as we
-                * will be patching their flags when the sink supports stereo
-                * 3D.
-                */
-               if (hdmi)
-                       modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len,
-                                                   video, video_len);
        }
        cea_db_iter_end(&iter);
  
@@@ -5416,6 -5364,7 +5364,7 @@@ drm_parse_hdr_metadata_block(struct drm
        }
  }
  
+ /* HDMI Vendor-Specific Data Block (HDMI VSDB, H14b-VSDB) */
  static void
  drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
  {
  
        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;
-       }
-       if (len >= 9)
+       if (len >= 10 && hdmi_vsdb_latency_present(db)) {
+               connector->latency_present[0] = true;
                connector->video_latency[0] = db[9];
-       if (len >= 10)
                connector->audio_latency[0] = db[10];
-       if (len >= 11)
+       }
+       if (len >= 12 && hdmi_vsdb_i_latency_present(db)) {
+               connector->latency_present[1] = true;
                connector->video_latency[1] = db[11];
-       if (len >= 12)
                connector->audio_latency[1] = db[12];
+       }
  
        drm_dbg_kms(connector->dev,
                    "[CONNECTOR:%d:%s] HDMI: latency present %d %d, video latency %d %d, audio latency %d %d\n",
@@@ -5533,8 -5482,6 +5482,6 @@@ static void drm_edid_to_eld(struct drm_
        int total_sad_count = 0;
        int mnl;
  
-       clear_eld(connector);
        if (!drm_edid)
                return;
  
@@@ -5864,6 -5811,92 +5811,92 @@@ drm_default_rgb_quant_range(const struc
  }
  EXPORT_SYMBOL(drm_default_rgb_quant_range);
  
+ /* CTA-861 Video Data Block (CTA VDB) */
+ static void parse_cta_vdb(struct drm_connector *connector, const struct cea_db *db)
+ {
+       struct drm_display_info *info = &connector->display_info;
+       int i, vic_index, len = cea_db_payload_len(db);
+       const u8 *svds = cea_db_data(db);
+       u8 *vics;
+       if (!len)
+               return;
+       /* Gracefully handle multiple VDBs, however unlikely that is */
+       vics = krealloc(info->vics, info->vics_len + len, GFP_KERNEL);
+       if (!vics)
+               return;
+       vic_index = info->vics_len;
+       info->vics_len += len;
+       info->vics = vics;
+       for (i = 0; i < len; i++) {
+               u8 vic = svd_to_vic(svds[i]);
+               if (!drm_valid_cea_vic(vic))
+                       vic = 0;
+               info->vics[vic_index++] = vic;
+       }
+ }
+ /*
+  * Update y420_cmdb_modes based on previously parsed CTA VDB and Y420CMDB.
+  *
+  * Translate the y420cmdb_map based on VIC indexes to y420_cmdb_modes indexed
+  * using the VICs themselves.
+  */
+ static void update_cta_y420cmdb(struct drm_connector *connector, u64 y420cmdb_map)
+ {
+       struct drm_display_info *info = &connector->display_info;
+       struct drm_hdmi_info *hdmi = &info->hdmi;
+       int i, len = min_t(int, info->vics_len, BITS_PER_TYPE(y420cmdb_map));
+       for (i = 0; i < len; i++) {
+               u8 vic = info->vics[i];
+               if (vic && y420cmdb_map & BIT_ULL(i))
+                       bitmap_set(hdmi->y420_cmdb_modes, vic, 1);
+       }
+ }
+ static bool cta_vdb_has_vic(const struct drm_connector *connector, u8 vic)
+ {
+       const struct drm_display_info *info = &connector->display_info;
+       int i;
+       if (!vic || !info->vics)
+               return false;
+       for (i = 0; i < info->vics_len; i++) {
+               if (info->vics[i] == vic)
+                       return true;
+       }
+       return false;
+ }
+ /* CTA-861-H YCbCr 4:2:0 Video Data Block (CTA Y420VDB) */
+ static void parse_cta_y420vdb(struct drm_connector *connector,
+                             const struct cea_db *db)
+ {
+       struct drm_display_info *info = &connector->display_info;
+       struct drm_hdmi_info *hdmi = &info->hdmi;
+       const u8 *svds = cea_db_data(db) + 1;
+       int i;
+       for (i = 0; i < cea_db_payload_len(db) - 1; i++) {
+               u8 vic = svd_to_vic(svds[i]);
+               if (!drm_valid_cea_vic(vic))
+                       continue;
+               bitmap_set(hdmi->y420_vdb_modes, vic, 1);
+               info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
+       }
+ }
  static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db)
  {
        struct drm_display_info *info = &connector->display_info;
@@@ -5995,14 -6028,14 +6028,14 @@@ static void drm_parse_dsc_info(struct d
  static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
                                      const u8 *hf_scds)
  {
-       struct drm_display_info *display = &connector->display_info;
-       struct drm_hdmi_info *hdmi = &display->hdmi;
+       struct drm_display_info *info = &connector->display_info;
+       struct drm_hdmi_info *hdmi = &info->hdmi;
        struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap;
        int max_tmds_clock = 0;
        u8 max_frl_rate = 0;
        bool dsc_support = false;
  
-       display->has_hdmi_infoframe = true;
+       info->has_hdmi_infoframe = true;
  
        if (hf_scds[6] & 0x80) {
                hdmi->scdc.supported = true;
                max_tmds_clock = hf_scds[5] * 5000;
  
                if (max_tmds_clock > 340000) {
-                       display->max_tmds_clock = max_tmds_clock;
+                       info->max_tmds_clock = max_tmds_clock;
                }
  
                if (scdc->supported) {
@@@ -6117,6 -6150,7 +6150,7 @@@ static void drm_parse_hdmi_deep_color_i
        }
  }
  
+ /* HDMI Vendor-Specific Data Block (HDMI VSDB, H14b-VSDB) */
  static void
  drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
  {
        if (len >= 7)
                info->max_tmds_clock = db[7] * 5000;
  
+       /*
+        * Try to infer whether the sink supports HDMI infoframes.
+        *
+        * HDMI infoframe support was first added in HDMI 1.4. Assume the sink
+        * supports infoframes if HDMI_Video_present is set.
+        */
+       if (len >= 8 && db[8] & BIT(5))
+               info->has_hdmi_infoframe = true;
        drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI: DVI dual %d, max TMDS clock %d kHz\n",
                    connector->base.id, connector->name,
                    info->dvi_dual, info->max_tmds_clock);
@@@ -6165,6 -6208,7 +6208,7 @@@ static void drm_parse_cea_ext(struct dr
        const struct cea_db *db;
        struct cea_db_iter iter;
        const u8 *edid_ext;
+       u64 y420cmdb_map = 0;
  
        drm_edid_iter_begin(drm_edid, &edid_iter);
        drm_edid_iter_for_each(edid_ext, &edid_iter) {
                else if (cea_db_is_microsoft_vsdb(db))
                        drm_parse_microsoft_vsdb(connector, data);
                else if (cea_db_is_y420cmdb(db))
-                       drm_parse_y420cmdb_bitmap(connector, data);
+                       parse_cta_y420cmdb(connector, db, &y420cmdb_map);
+               else if (cea_db_is_y420vdb(db))
+                       parse_cta_y420vdb(connector, db);
                else if (cea_db_is_vcdb(db))
                        drm_parse_vcdb(connector, data);
                else if (cea_db_is_hdmi_hdr_metadata_block(db))
                        drm_parse_hdr_metadata_block(connector, data);
+               else if (cea_db_tag(db) == CTA_DB_VIDEO)
+                       parse_cta_vdb(connector, db);
        }
        cea_db_iter_end(&iter);
+       if (y420cmdb_map)
+               update_cta_y420cmdb(connector, y420cmdb_map);
  }
  
  static
@@@ -6374,17 -6425,29 +6425,29 @@@ static void drm_reset_display_info(stru
        info->mso_stream_count = 0;
        info->mso_pixel_overlap = 0;
        info->max_dsc_bpp = 0;
+       kfree(info->vics);
+       info->vics = NULL;
+       info->vics_len = 0;
+       info->quirks = 0;
  }
  
- static u32 update_display_info(struct drm_connector *connector,
-                              const struct drm_edid *drm_edid)
+ static void update_display_info(struct drm_connector *connector,
+                               const struct drm_edid *drm_edid)
  {
        struct drm_display_info *info = &connector->display_info;
-       const struct edid *edid = drm_edid->edid;
-       u32 quirks = edid_get_quirks(drm_edid);
+       const struct edid *edid;
  
        drm_reset_display_info(connector);
+       clear_eld(connector);
+       if (!drm_edid)
+               return;
+       edid = drm_edid->edid;
+       info->quirks = edid_get_quirks(drm_edid);
  
        info->width_mm = edid->width_cm * 10;
        info->height_mm = edid->height_cm * 10;
        drm_update_mso(connector, drm_edid);
  
  out:
-       if (quirks & EDID_QUIRK_NON_DESKTOP) {
+       if (info->quirks & EDID_QUIRK_NON_DESKTOP) {
                drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Non-desktop display%s\n",
                            connector->base.id, connector->name,
                            info->non_desktop ? " (redundant quirk)" : "");
                info->non_desktop = true;
        }
  
-       if (quirks & EDID_QUIRK_CAP_DSC_15BPP)
+       if (info->quirks & EDID_QUIRK_CAP_DSC_15BPP)
                info->max_dsc_bpp = 15;
  
-       return quirks;
+       if (info->quirks & EDID_QUIRK_FORCE_6BPC)
+               info->bpc = 6;
+       if (info->quirks & EDID_QUIRK_FORCE_8BPC)
+               info->bpc = 8;
+       if (info->quirks & EDID_QUIRK_FORCE_10BPC)
+               info->bpc = 10;
+       if (info->quirks & EDID_QUIRK_FORCE_12BPC)
+               info->bpc = 12;
+       /* Depends on info->cea_rev set by drm_parse_cea_ext() above */
+       drm_edid_to_eld(connector, drm_edid);
  }
  
  static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev,
@@@ -6561,27 -6637,14 +6637,14 @@@ static int add_displayid_detailed_modes
        return num_modes;
  }
  
- static int _drm_edid_connector_update(struct drm_connector *connector,
-                                     const struct drm_edid *drm_edid)
+ static int _drm_edid_connector_add_modes(struct drm_connector *connector,
+                                        const struct drm_edid *drm_edid)
  {
+       const struct drm_display_info *info = &connector->display_info;
        int num_modes = 0;
-       u32 quirks;
  
-       if (!drm_edid) {
-               drm_reset_display_info(connector);
-               clear_eld(connector);
+       if (!drm_edid)
                return 0;
-       }
-       /*
-        * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks.
-        * To avoid multiple parsing of same block, lets parse that map
-        * from sink info, before parsing CEA modes.
-        */
-       quirks = update_display_info(connector, drm_edid);
-       /* Depends on info->cea_rev set by update_display_info() above */
-       drm_edid_to_eld(connector, drm_edid);
  
        /*
         * EDID spec says modes should be preferred in this order:
         *
         * XXX order for additional mode types in extension blocks?
         */
-       num_modes += add_detailed_modes(connector, drm_edid, quirks);
+       num_modes += add_detailed_modes(connector, drm_edid);
        num_modes += add_cvt_modes(connector, drm_edid);
        num_modes += add_standard_modes(connector, drm_edid);
        num_modes += add_established_modes(connector, drm_edid);
        if (drm_edid->edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ)
                num_modes += add_inferred_modes(connector, drm_edid);
  
-       if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
-               edid_fixup_preferred(connector, quirks);
-       if (quirks & EDID_QUIRK_FORCE_6BPC)
-               connector->display_info.bpc = 6;
-       if (quirks & EDID_QUIRK_FORCE_8BPC)
-               connector->display_info.bpc = 8;
-       if (quirks & EDID_QUIRK_FORCE_10BPC)
-               connector->display_info.bpc = 10;
-       if (quirks & EDID_QUIRK_FORCE_12BPC)
-               connector->display_info.bpc = 12;
+       if (info->quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
+               edid_fixup_preferred(connector);
  
        return num_modes;
  }
   * @connector: Connector
   * @drm_edid: EDID
   *
-  * Update the connector mode list, display info, ELD, HDR metadata, relevant
-  * properties, etc. from the passed in EDID.
+  * Update the connector display info, ELD, HDR metadata, relevant properties,
+  * etc. from the passed in EDID.
   *
   * If EDID is NULL, reset the information.
   *
-  * Return: The number of modes added or 0 if we couldn't find any.
+  * Must be called before calling drm_edid_connector_add_modes().
+  *
+  * Return: 0 on success, negative error on errors.
   */
  int drm_edid_connector_update(struct drm_connector *connector,
                              const struct drm_edid *drm_edid)
  {
-       int count;
-       count = _drm_edid_connector_update(connector, drm_edid);
+       update_display_info(connector, drm_edid);
  
        _drm_update_tile_info(connector, drm_edid);
  
-       /* Note: Ignore errors for now. */
-       _drm_edid_connector_property_update(connector, drm_edid);
-       return count;
+       return _drm_edid_connector_property_update(connector, drm_edid);
  }
  EXPORT_SYMBOL(drm_edid_connector_update);
  
- static int _drm_connector_update_edid_property(struct drm_connector *connector,
-                                              const struct drm_edid *drm_edid)
+ /**
+  * drm_edid_connector_add_modes - Update probed modes from the EDID property
+  * @connector: Connector
+  *
+  * Add the modes from the previously updated EDID property to the connector
+  * probed modes list.
+  *
+  * drm_edid_connector_update() must have been called before this to update the
+  * EDID property.
+  *
+  * Return: The number of modes added, or 0 if we couldn't find any.
+  */
+ int drm_edid_connector_add_modes(struct drm_connector *connector)
  {
-       /*
-        * Set the display info, using edid if available, otherwise resetting
-        * the values to defaults. This duplicates the work done in
-        * drm_add_edid_modes, but that function is not consistently called
-        * before this one in all drivers and the computation is cheap enough
-        * that it seems better to duplicate it rather than attempt to ensure
-        * some arbitrary ordering of calls.
-        */
-       if (drm_edid)
-               update_display_info(connector, drm_edid);
-       else
-               drm_reset_display_info(connector);
+       const struct drm_edid *drm_edid = NULL;
+       int count;
  
-       _drm_update_tile_info(connector, drm_edid);
+       if (connector->edid_blob_ptr)
+               drm_edid = drm_edid_alloc(connector->edid_blob_ptr->data,
+                                         connector->edid_blob_ptr->length);
  
-       return _drm_edid_connector_property_update(connector, drm_edid);
+       count = _drm_edid_connector_add_modes(connector, drm_edid);
+       drm_edid_free(drm_edid);
+       return count;
  }
+ EXPORT_SYMBOL(drm_edid_connector_add_modes);
  
  /**
   * drm_connector_update_edid_property - update the edid property of a connector
@@@ -6749,8 -6805,7 +6805,7 @@@ int drm_connector_update_edid_property(
  {
        struct drm_edid drm_edid;
  
-       return _drm_connector_update_edid_property(connector,
-                                                  drm_edid_legacy_init(&drm_edid, edid));
+       return drm_edid_connector_update(connector, drm_edid_legacy_init(&drm_edid, edid));
  }
  EXPORT_SYMBOL(drm_connector_update_edid_property);
  
   * &drm_display_info structure and ELD in @connector with any information which
   * can be derived from the edid.
   *
-  * This function is deprecated. Use drm_edid_connector_update() instead.
+  * This function is deprecated. Use drm_edid_connector_add_modes() instead.
   *
   * Return: The number of modes added or 0 if we couldn't find any.
   */
  int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
  {
-       struct drm_edid drm_edid;
+       struct drm_edid _drm_edid;
+       const struct drm_edid *drm_edid;
  
        if (edid && !drm_edid_is_valid(edid)) {
                drm_warn(connector->dev, "[CONNECTOR:%d:%s] EDID invalid.\n",
                edid = NULL;
        }
  
-       return _drm_edid_connector_update(connector,
-                                         drm_edid_legacy_init(&drm_edid, edid));
+       drm_edid = drm_edid_legacy_init(&_drm_edid, edid);
+       update_display_info(connector, drm_edid);
+       return _drm_edid_connector_add_modes(connector, drm_edid);
  }
  EXPORT_SYMBOL(drm_add_edid_modes);
  
@@@ -6885,8 -6944,6 +6944,6 @@@ static u8 drm_mode_hdmi_vic(const struc
  static u8 drm_mode_cea_vic(const struct drm_connector *connector,
                           const struct drm_display_mode *mode)
  {
-       u8 vic;
        /*
         * HDMI spec says if a mode is found in HDMI 1.4b 4K modes
         * we should send its VIC in vendor infoframes, else send the
        if (drm_mode_hdmi_vic(connector, mode))
                return 0;
  
-       vic = drm_match_cea_mode(mode);
+       return drm_match_cea_mode(mode);
+ }
  
-       /*
-        * HDMI 1.4 VIC range: 1 <= VIC <= 64 (CEA-861-D) but
-        * HDMI 2.0 VIC range: 1 <= VIC <= 107 (CEA-861-F). So we
-        * have to make sure we dont break HDMI 1.4 sinks.
-        */
-       if (!is_hdmi2_sink(connector) && vic > 64)
+ /*
+  * Avoid sending VICs defined in HDMI 2.0 in AVI infoframes to sinks that
+  * conform to HDMI 1.4.
+  *
+  * HDMI 1.4 (CTA-861-D) VIC range: [1..64]
+  * HDMI 2.0 (CTA-861-F) VIC range: [1..107]
+  *
+  * If the sink lists the VIC in CTA VDB, assume it's fine, regardless of HDMI
+  * version.
+  */
+ static u8 vic_for_avi_infoframe(const struct drm_connector *connector, u8 vic)
+ {
+       if (!is_hdmi2_sink(connector) && vic > 64 &&
+           !cta_vdb_has_vic(connector, vic))
                return 0;
  
        return vic;
@@@ -6978,7 -7044,7 +7044,7 @@@ drm_hdmi_avi_infoframe_from_display_mod
                picture_aspect = HDMI_PICTURE_ASPECT_NONE;
        }
  
-       frame->video_code = vic;
+       frame->video_code = vic_for_avi_infoframe(connector, vic);
        frame->picture_aspect = picture_aspect;
        frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
        frame->scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
@@@ -170,6 -170,20 +170,20 @@@ void drm_gem_private_object_init(struc
  EXPORT_SYMBOL(drm_gem_private_object_init);
  
  /**
+  * drm_gem_private_object_fini - Finalize a failed drm_gem_object
+  * @obj: drm_gem_object
+  *
+  * Uninitialize an already allocated GEM object when it initialized failed
+  */
+ void drm_gem_private_object_fini(struct drm_gem_object *obj)
+ {
+       WARN_ON(obj->dma_buf);
+       dma_resv_fini(&obj->_resv);
+ }
+ EXPORT_SYMBOL(drm_gem_private_object_fini);
+ /**
   * drm_gem_object_handle_free - release resources bound to userspace handles
   * @obj: GEM object to clean up.
   *
@@@ -930,12 -944,11 +944,11 @@@ drm_gem_release(struct drm_device *dev
  void
  drm_gem_object_release(struct drm_gem_object *obj)
  {
-       WARN_ON(obj->dma_buf);
        if (obj->filp)
                fput(obj->filp);
  
-       dma_resv_fini(&obj->_resv);
+       drm_gem_private_object_fini(obj);
        drm_gem_free_mmap_offset(obj);
        drm_gem_lru_remove(obj);
  }
@@@ -1047,7 -1060,7 +1060,7 @@@ int drm_gem_mmap_obj(struct drm_gem_obj
                        goto err_drm_gem_object_put;
                }
  
-               vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+               vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
                vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
                vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
        }
@@@ -1375,13 -1388,10 +1388,13 @@@ EXPORT_SYMBOL(drm_gem_lru_move_tail)
   *
   * @lru: The LRU to scan
   * @nr_to_scan: The number of pages to try to reclaim
 + * @remaining: The number of pages left to reclaim, should be initialized by caller
   * @shrink: Callback to try to shrink/reclaim the object.
   */
  unsigned long
 -drm_gem_lru_scan(struct drm_gem_lru *lru, unsigned nr_to_scan,
 +drm_gem_lru_scan(struct drm_gem_lru *lru,
 +               unsigned int nr_to_scan,
 +               unsigned long *remaining,
                 bool (*shrink)(struct drm_gem_object *obj))
  {
        struct drm_gem_lru still_in_lru;
                 * hit shrinker in response to trying to get backing pages
                 * for this obj (ie. while it's lock is already held)
                 */
 -              if (!dma_resv_trylock(obj->resv))
 +              if (!dma_resv_trylock(obj->resv)) {
 +                      *remaining += obj->size >> PAGE_SHIFT;
                        goto tail;
 +              }
  
                if (shrink(obj)) {
                        freed += obj->size >> PAGE_SHIFT;
@@@ -79,8 -79,10 +79,10 @@@ __drm_gem_shmem_create(struct drm_devic
        } else {
                ret = drm_gem_object_init(dev, obj, size);
        }
-       if (ret)
+       if (ret) {
+               drm_gem_private_object_fini(obj);
                goto err_free;
+       }
  
        ret = drm_gem_create_mmap_offset(obj);
        if (ret)
@@@ -413,7 -415,7 +415,7 @@@ void drm_gem_shmem_vunmap(struct drm_ge
  }
  EXPORT_SYMBOL(drm_gem_shmem_vunmap);
  
- static struct drm_gem_shmem_object *
+ static int
  drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
                                 struct drm_device *dev, size_t size,
                                 uint32_t *handle)
  
        shmem = drm_gem_shmem_create(dev, size);
        if (IS_ERR(shmem))
-               return shmem;
+               return PTR_ERR(shmem);
  
        /*
         * Allocate an id of idr table where the obj is registered
        ret = drm_gem_handle_create(file_priv, &shmem->base, handle);
        /* drop reference from allocate - handle holds it now. */
        drm_gem_object_put(&shmem->base);
-       if (ret)
-               return ERR_PTR(ret);
  
-       return shmem;
+       return ret;
  }
  
  /* Update madvise status, returns true if not purged, else
@@@ -518,7 -518,6 +518,6 @@@ int drm_gem_shmem_dumb_create(struct dr
                              struct drm_mode_create_dumb *args)
  {
        u32 min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
-       struct drm_gem_shmem_object *shmem;
  
        if (!args->pitch || !args->size) {
                args->pitch = min_pitch;
                        args->size = PAGE_ALIGN(args->pitch * args->height);
        }
  
-       shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle);
-       return PTR_ERR_OR_ZERO(shmem);
+       return drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle);
  }
  EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
  
@@@ -622,21 -619,18 +619,21 @@@ int drm_gem_shmem_mmap(struct drm_gem_s
        int ret;
  
        if (obj->import_attach) {
 -              /* Drop the reference drm_gem_mmap_obj() acquired.*/
 -              drm_gem_object_put(obj);
                vma->vm_private_data = NULL;
 +              ret = dma_buf_mmap(obj->dma_buf, vma, 0);
 +
 +              /* Drop the reference drm_gem_mmap_obj() acquired.*/
 +              if (!ret)
 +                      drm_gem_object_put(obj);
  
 -              return dma_buf_mmap(obj->dma_buf, vma, 0);
 +              return ret;
        }
  
        ret = drm_gem_shmem_get_pages(shmem);
        if (ret)
                return ret;
  
-       vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+       vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
        vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
        if (shmem->map_wc)
                vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
@@@ -684,23 -678,7 +681,7 @@@ struct sg_table *drm_gem_shmem_get_sg_t
  }
  EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table);
  
- /**
-  * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a
-  *                             scatter/gather table for a shmem GEM object.
-  * @shmem: shmem GEM object
-  *
-  * This function returns a scatter/gather table suitable for driver usage. If
-  * the sg table doesn't exist, the pages are pinned, dma-mapped, and a sg
-  * table created.
-  *
-  * This is the main function for drivers to get at backing storage, and it hides
-  * and difference between dma-buf imported and natively allocated objects.
-  * drm_gem_shmem_get_sg_table() should not be directly called by drivers.
-  *
-  * Returns:
-  * A pointer to the scatter/gather table of pinned pages or errno on failure.
-  */
- struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem)
+ static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_object *shmem)
  {
        struct drm_gem_object *obj = &shmem->base;
        int ret;
  
        WARN_ON(obj->import_attach);
  
-       ret = drm_gem_shmem_get_pages(shmem);
+       ret = drm_gem_shmem_get_pages_locked(shmem);
        if (ret)
                return ERR_PTR(ret);
  
@@@ -733,9 -711,39 +714,39 @@@ err_free_sgt
        sg_free_table(sgt);
        kfree(sgt);
  err_put_pages:
-       drm_gem_shmem_put_pages(shmem);
+       drm_gem_shmem_put_pages_locked(shmem);
        return ERR_PTR(ret);
  }
+ /**
+  * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a
+  *                             scatter/gather table for a shmem GEM object.
+  * @shmem: shmem GEM object
+  *
+  * This function returns a scatter/gather table suitable for driver usage. If
+  * the sg table doesn't exist, the pages are pinned, dma-mapped, and a sg
+  * table created.
+  *
+  * This is the main function for drivers to get at backing storage, and it hides
+  * and difference between dma-buf imported and natively allocated objects.
+  * drm_gem_shmem_get_sg_table() should not be directly called by drivers.
+  *
+  * Returns:
+  * A pointer to the scatter/gather table of pinned pages or errno on failure.
+  */
+ struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem)
+ {
+       int ret;
+       struct sg_table *sgt;
+       ret = mutex_lock_interruptible(&shmem->pages_lock);
+       if (ret)
+               return ERR_PTR(ret);
+       sgt = drm_gem_shmem_get_pages_sgt_locked(shmem);
+       mutex_unlock(&shmem->pages_lock);
+       return sgt;
+ }
  EXPORT_SYMBOL_GPL(drm_gem_shmem_get_pages_sgt);
  
  /**
@@@ -767,7 -775,7 +778,7 @@@ drm_gem_shmem_prime_import_sg_table(str
  
        shmem->sgt = sgt;
  
-       DRM_DEBUG_PRIME("size = %zu\n", size);
+       drm_dbg_prime(dev, "size = %zu\n", size);
  
        return &shmem->base;
  }
  
  #include <linux/mm.h>
  
+ #include <drm/ttm/ttm_bo.h>
  #include <drm/ttm/ttm_device.h>
  #include <drm/ttm/ttm_tt.h>
  #include <drm/ttm/ttm_placement.h>
- #include <drm/ttm/ttm_bo_api.h>
  
  #include "ttm_module.h"
  
@@@ -158,7 -158,7 +158,7 @@@ int ttm_device_swapout(struct ttm_devic
                        struct ttm_buffer_object *bo = res->bo;
                        uint32_t num_pages;
  
 -                      if (!bo)
 +                      if (!bo || bo->resource != res)
                                continue;
  
                        num_pages = PFN_UP(bo->base.size);
  }
  EXPORT_SYMBOL(ttm_device_swapout);
  
- static void ttm_device_delayed_workqueue(struct work_struct *work)
- {
-       struct ttm_device *bdev =
-               container_of(work, struct ttm_device, wq.work);
-       if (!ttm_bo_delayed_delete(bdev, false))
-               schedule_delayed_work(&bdev->wq,
-                                     ((HZ / 100) < 1) ? 1 : HZ / 100);
- }
  /**
   * ttm_device_init
   *
@@@ -215,15 -205,19 +205,19 @@@ int ttm_device_init(struct ttm_device *
        if (ret)
                return ret;
  
+       bdev->wq = alloc_workqueue("ttm", WQ_MEM_RECLAIM | WQ_HIGHPRI, 16);
+       if (!bdev->wq) {
+               ttm_global_release();
+               return -ENOMEM;
+       }
        bdev->funcs = funcs;
  
        ttm_sys_man_init(bdev);
        ttm_pool_init(&bdev->pool, dev, use_dma_alloc, use_dma32);
  
        bdev->vma_manager = vma_manager;
-       INIT_DELAYED_WORK(&bdev->wq, ttm_device_delayed_workqueue);
        spin_lock_init(&bdev->lru_lock);
-       INIT_LIST_HEAD(&bdev->ddestroy);
        INIT_LIST_HEAD(&bdev->pinned);
        bdev->dev_mapping = mapping;
        mutex_lock(&ttm_global_mutex);
@@@ -247,10 -241,8 +241,8 @@@ void ttm_device_fini(struct ttm_device 
        list_del(&bdev->device_list);
        mutex_unlock(&ttm_global_mutex);
  
-       cancel_delayed_work_sync(&bdev->wq);
-       if (ttm_bo_delayed_delete(bdev, true))
-               pr_debug("Delayed destroy list was clean\n");
+       drain_workqueue(bdev->wq);
+       destroy_workqueue(bdev->wq);
  
        spin_lock(&bdev->lru_lock);
        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
@@@ -215,7 -215,7 +215,7 @@@ void virtio_gpu_dequeue_ctrl_func(struc
        list_for_each_entry(entry, &reclaim_list, list) {
                resp = (struct virtio_gpu_ctrl_hdr *)entry->resp_buf;
  
-               trace_virtio_gpu_cmd_response(vgdev->ctrlq.vq, resp);
+               trace_virtio_gpu_cmd_response(vgdev->ctrlq.vq, resp, entry->seqno);
  
                if (resp->type != cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA)) {
                        if (le32_to_cpu(resp->type) >= VIRTIO_GPU_RESP_ERR_UNSPEC) {
@@@ -261,6 -261,10 +261,10 @@@ void virtio_gpu_dequeue_cursor_func(str
        spin_unlock(&vgdev->cursorq.qlock);
  
        list_for_each_entry_safe(entry, tmp, &reclaim_list, list) {
+               struct virtio_gpu_ctrl_hdr *resp =
+                       (struct virtio_gpu_ctrl_hdr *)entry->resp_buf;
+               trace_virtio_gpu_cmd_response(vgdev->cursorq.vq, resp, entry->seqno);
                list_del(&entry->list);
                free_vbuf(vgdev, entry);
        }
@@@ -353,7 -357,8 +357,8 @@@ again
        ret = virtqueue_add_sgs(vq, sgs, outcnt, incnt, vbuf, GFP_ATOMIC);
        WARN_ON(ret);
  
-       trace_virtio_gpu_cmd_queue(vq, virtio_gpu_vbuf_ctrl_hdr(vbuf));
+       vbuf->seqno = ++vgdev->ctrlq.seqno;
+       trace_virtio_gpu_cmd_queue(vq, virtio_gpu_vbuf_ctrl_hdr(vbuf), vbuf->seqno);
  
        atomic_inc(&vgdev->pending_commands);
  
@@@ -465,8 -470,10 +470,10 @@@ retry
                spin_lock(&vgdev->cursorq.qlock);
                goto retry;
        } else {
+               vbuf->seqno = ++vgdev->cursorq.seqno;
                trace_virtio_gpu_cmd_queue(vq,
-                       virtio_gpu_vbuf_ctrl_hdr(vbuf));
+                       virtio_gpu_vbuf_ctrl_hdr(vbuf),
+                       vbuf->seqno);
  
                notify = virtqueue_kick_prepare(vq);
        }
@@@ -597,7 -604,7 +604,7 @@@ void virtio_gpu_cmd_transfer_to_host_2d
        bool use_dma_api = !virtio_has_dma_quirk(vgdev->vdev);
  
        if (virtio_gpu_is_shmem(bo) && use_dma_api)
 -              dma_sync_sgtable_for_device(&vgdev->vdev->dev,
 +              dma_sync_sgtable_for_device(vgdev->vdev->dev.parent,
                                            bo->base.sgt, DMA_TO_DEVICE);
  
        cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p));
@@@ -1019,7 -1026,7 +1026,7 @@@ void virtio_gpu_cmd_transfer_to_host_3d
        bool use_dma_api = !virtio_has_dma_quirk(vgdev->vdev);
  
        if (virtio_gpu_is_shmem(bo) && use_dma_api)
 -              dma_sync_sgtable_for_device(&vgdev->vdev->dev,
 +              dma_sync_sgtable_for_device(vgdev->vdev->dev.parent,
                                            bo->base.sgt, DMA_TO_DEVICE);
  
        cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p));
@@@ -157,10 -157,6 +157,6 @@@ static vm_fault_t fb_deferred_io_track_
        /* protect against the workqueue changing the page list */
        mutex_lock(&fbdefio->lock);
  
-       /* first write in this cycle, notify the driver */
-       if (fbdefio->first_io && list_empty(&fbdefio->pagereflist))
-               fbdefio->first_io(info);
        pageref = fb_deferred_io_pageref_get(info, offset, page);
        if (WARN_ON_ONCE(!pageref)) {
                ret = VM_FAULT_OOM;
@@@ -232,9 -228,9 +228,9 @@@ static const struct address_space_opera
  int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
  {
        vma->vm_ops = &fb_deferred_io_vm_ops;
-       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+       vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
        if (!(info->flags & FBINFO_VIRTFB))
-               vma->vm_flags |= VM_IO;
+               vm_flags_set(vma, VM_IO);
        vma->vm_private_data = info;
        return 0;
  }
@@@ -309,18 -305,17 +305,18 @@@ void fb_deferred_io_open(struct fb_inf
                         struct inode *inode,
                         struct file *file)
  {
 +      struct fb_deferred_io *fbdefio = info->fbdefio;
 +
        file->f_mapping->a_ops = &fb_deferred_io_aops;
 +      fbdefio->open_count++;
  }
  EXPORT_SYMBOL_GPL(fb_deferred_io_open);
  
 -void fb_deferred_io_release(struct fb_info *info)
 +static void fb_deferred_io_lastclose(struct fb_info *info)
  {
 -      struct fb_deferred_io *fbdefio = info->fbdefio;
        struct page *page;
        int i;
  
 -      BUG_ON(!fbdefio);
        cancel_delayed_work_sync(&info->deferred_work);
  
        /* clear out the mapping that we setup */
                page->mapping = NULL;
        }
  }
 +
 +void fb_deferred_io_release(struct fb_info *info)
 +{
 +      struct fb_deferred_io *fbdefio = info->fbdefio;
 +
 +      if (!--fbdefio->open_count)
 +              fb_deferred_io_lastclose(info);
 +}
  EXPORT_SYMBOL_GPL(fb_deferred_io_release);
  
  void fb_deferred_io_cleanup(struct fb_info *info)
  {
        struct fb_deferred_io *fbdefio = info->fbdefio;
  
 -      fb_deferred_io_release(info);
 +      fb_deferred_io_lastclose(info);
  
        kvfree(info->pagerefs);
        mutex_destroy(&fbdefio->lock);
diff --combined include/drm/drm_gem.h
@@@ -405,6 -405,7 +405,7 @@@ int drm_gem_object_init(struct drm_devi
                        struct drm_gem_object *obj, size_t size);
  void drm_gem_private_object_init(struct drm_device *dev,
                                 struct drm_gem_object *obj, size_t size);
+ void drm_gem_private_object_fini(struct drm_gem_object *obj);
  void drm_gem_vm_open(struct vm_area_struct *vma);
  void drm_gem_vm_close(struct vm_area_struct *vma);
  int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
@@@ -475,9 -476,7 +476,9 @@@ int drm_gem_dumb_map_offset(struct drm_
  void drm_gem_lru_init(struct drm_gem_lru *lru, struct mutex *lock);
  void drm_gem_lru_remove(struct drm_gem_object *obj);
  void drm_gem_lru_move_tail(struct drm_gem_lru *lru, struct drm_gem_object *obj);
 -unsigned long drm_gem_lru_scan(struct drm_gem_lru *lru, unsigned nr_to_scan,
 +unsigned long drm_gem_lru_scan(struct drm_gem_lru *lru,
 +                             unsigned int nr_to_scan,
 +                             unsigned long *remaining,
                               bool (*shrink)(struct drm_gem_object *obj));
  
  #endif /* __DRM_GEM_H__ */
diff --combined include/linux/fb.h
@@@ -212,11 -212,9 +212,10 @@@ struct fb_deferred_io 
        /* delay between mkwrite and deferred handler */
        unsigned long delay;
        bool sort_pagereflist; /* sort pagelist by offset */
 +      int open_count; /* number of opened files; protected by fb_info lock */
        struct mutex lock; /* mutex that protects the pageref list */
        struct list_head pagereflist; /* list of pagerefs for touched pages */
        /* callback */
-       void (*first_io)(struct fb_info *info);
        void (*deferred_io)(struct fb_info *info, struct list_head *pagelist);
  };
  #endif
@@@ -424,8 -422,6 +423,6 @@@ struct fb_tile_ops 
   */
  #define FBINFO_MISC_ALWAYS_SETPAR   0x40000
  
- /* where the fb is a firmware driver, and can be replaced with a proper one */
- #define FBINFO_MISC_FIRMWARE        0x80000
  /*
   * Host and GPU endianness differ.
   */
@@@ -500,30 -496,10 +497,10 @@@ struct fb_info 
        void *fbcon_par;                /* fbcon use-only private area */
        /* From here on everything is device dependent */
        void *par;
-       /* we need the PCI or similar aperture base/size not
-          smem_start/size as smem_start may just be an object
-          allocated inside the aperture so may not actually overlap */
-       struct apertures_struct {
-               unsigned int count;
-               struct aperture {
-                       resource_size_t base;
-                       resource_size_t size;
-               } ranges[0];
-       } *apertures;
  
        bool skip_vt_switch; /* no VT switch on suspend/resume required */
  };
  
- static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
-       struct apertures_struct *a;
-       a = kzalloc(struct_size(a, ranges, max_num), GFP_KERNEL);
-       if (!a)
-               return NULL;
-       a->count = max_num;
-       return a;
- }
  #define FBINFO_FLAG_DEFAULT   FBINFO_DEFAULT
  
  /* This will go away