]> Git Repo - J-linux.git/commitdiff
Merge drm/drm-next into drm-intel-next-queued
authorJani Nikula <[email protected]>
Tue, 20 Nov 2018 11:14:08 +0000 (13:14 +0200)
committerJani Nikula <[email protected]>
Tue, 20 Nov 2018 11:14:08 +0000 (13:14 +0200)
Pull in v4.20-rc3 via drm-next.

Signed-off-by: Jani Nikula <[email protected]>
14 files changed:
1  2 
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/intel_hdmi.c
include/drm/drm_connector.h
include/drm/drm_dp_helper.h
include/linux/swap.h
mm/shmem.c
mm/vmscan.c
sound/x86/intel_hdmi_audio.c

index cd8362dc4f7429e46764ba23883e1fd59cb0d227,3dbfbddae7e6f2f887b30773e9b06a98774d640c..1706ed1100d5cd9bdf4aaa8a735eaf45bc76f353
@@@ -175,6 -175,11 +175,11 @@@ void drm_atomic_state_default_clear(str
                state->crtcs[i].state = NULL;
                state->crtcs[i].old_state = NULL;
                state->crtcs[i].new_state = NULL;
+               if (state->crtcs[i].commit) {
+                       drm_crtc_commit_put(state->crtcs[i].commit);
+                       state->crtcs[i].commit = NULL;
+               }
        }
  
        for (i = 0; i < config->num_total_plane; i++) {
@@@ -390,11 -395,6 +395,11 @@@ static int drm_atomic_connector_check(s
  {
        struct drm_crtc_state *crtc_state;
        struct drm_writeback_job *writeback_job = state->writeback_job;
 +      const struct drm_display_info *info = &connector->display_info;
 +
 +      state->max_bpc = info->bpc ? info->bpc : 8;
 +      if (connector->max_bpc_property)
 +              state->max_bpc = min(state->max_bpc, state->max_requested_bpc);
  
        if ((connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) || !writeback_job)
                return 0;
index 86ac6b5b36eafc6509980426c64c4258c34289d6,474b503a73a1694b9b909d976389caf135fd6b12..fa95f9974f6d071a8c1929b38be6ba70d8f7cd14
@@@ -92,6 -92,17 +92,17 @@@ drm_atomic_helper_plane_changed(struct 
        }
  }
  
+ /*
+  * For connectors that support multiple encoders, either the
+  * .atomic_best_encoder() or .best_encoder() operation must be implemented.
+  */
+ static struct drm_encoder *
+ pick_single_encoder_for_connector(struct drm_connector *connector)
+ {
+       WARN_ON(connector->encoder_ids[1]);
+       return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
+ }
  static int handle_conflicting_encoders(struct drm_atomic_state *state,
                                       bool disable_conflicting_encoders)
  {
                else if (funcs->best_encoder)
                        new_encoder = funcs->best_encoder(connector);
                else
-                       new_encoder = drm_atomic_helper_best_encoder(connector);
+                       new_encoder = pick_single_encoder_for_connector(connector);
  
                if (new_encoder) {
                        if (encoder_mask & drm_encoder_mask(new_encoder)) {
@@@ -336,7 -347,7 +347,7 @@@ update_connector_routing(struct drm_ato
        else if (funcs->best_encoder)
                new_encoder = funcs->best_encoder(connector);
        else
-               new_encoder = drm_atomic_helper_best_encoder(connector);
+               new_encoder = pick_single_encoder_for_connector(connector);
  
        if (!new_encoder) {
                DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
@@@ -658,10 -669,6 +669,10 @@@ drm_atomic_helper_check_modeset(struct 
                        if (old_connector_state->link_status !=
                            new_connector_state->link_status)
                                new_crtc_state->connectors_changed = true;
 +
 +                      if (old_connector_state->max_requested_bpc !=
 +                          new_connector_state->max_requested_bpc)
 +                              new_crtc_state->connectors_changed = true;
                }
  
                if (funcs->atomic_check)
@@@ -1432,15 -1439,16 +1443,16 @@@ EXPORT_SYMBOL(drm_atomic_helper_wait_fo
  void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,
                                          struct drm_atomic_state *old_state)
  {
-       struct drm_crtc_state *new_crtc_state;
        struct drm_crtc *crtc;
        int i;
  
-       for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
-               struct drm_crtc_commit *commit = new_crtc_state->commit;
+       for (i = 0; i < dev->mode_config.num_crtc; i++) {
+               struct drm_crtc_commit *commit = old_state->crtcs[i].commit;
                int ret;
  
-               if (!commit)
+               crtc = old_state->crtcs[i].ptr;
+               if (!crtc || !commit)
                        continue;
  
                ret = wait_for_completion_timeout(&commit->flip_done, 10 * HZ);
@@@ -1958,6 -1966,9 +1970,9 @@@ int drm_atomic_helper_setup_commit(stru
                drm_crtc_commit_get(commit);
  
                commit->abort_completion = true;
+               state->crtcs[i].commit = commit;
+               drm_crtc_commit_get(commit);
        }
  
        for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
@@@ -3411,586 -3422,3 +3426,3 @@@ fail
        return ret;
  }
  EXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
- /**
-  * drm_atomic_helper_best_encoder - Helper for
-  *    &drm_connector_helper_funcs.best_encoder callback
-  * @connector: Connector control structure
-  *
-  * This is a &drm_connector_helper_funcs.best_encoder callback helper for
-  * connectors that support exactly 1 encoder, statically determined at driver
-  * init time.
-  */
- struct drm_encoder *
- drm_atomic_helper_best_encoder(struct drm_connector *connector)
- {
-       WARN_ON(connector->encoder_ids[1]);
-       return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
- }
- EXPORT_SYMBOL(drm_atomic_helper_best_encoder);
- /**
-  * DOC: atomic state reset and initialization
-  *
-  * Both the drm core and the atomic helpers assume that there is always the full
-  * and correct atomic software state for all connectors, CRTCs and planes
-  * available. Which is a bit a problem on driver load and also after system
-  * suspend. One way to solve this is to have a hardware state read-out
-  * infrastructure which reconstructs the full software state (e.g. the i915
-  * driver).
-  *
-  * The simpler solution is to just reset the software state to everything off,
-  * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
-  * the atomic helpers provide default reset implementations for all hooks.
-  *
-  * On the upside the precise state tracking of atomic simplifies system suspend
-  * and resume a lot. For drivers using drm_mode_config_reset() a complete recipe
-  * is implemented in drm_atomic_helper_suspend() and drm_atomic_helper_resume().
-  * For other drivers the building blocks are split out, see the documentation
-  * for these functions.
-  */
- /**
-  * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs
-  * @crtc: drm CRTC
-  *
-  * Resets the atomic state for @crtc by freeing the state pointer (which might
-  * be NULL, e.g. at driver load time) and allocating a new empty state object.
-  */
- void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
- {
-       if (crtc->state)
-               __drm_atomic_helper_crtc_destroy_state(crtc->state);
-       kfree(crtc->state);
-       crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
-       if (crtc->state)
-               crtc->state->crtc = crtc;
- }
- EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
- /**
-  * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
-  * @crtc: CRTC object
-  * @state: atomic CRTC state
-  *
-  * Copies atomic state from a CRTC's current state and resets inferred values.
-  * This is useful for drivers that subclass the CRTC state.
-  */
- void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
-                                             struct drm_crtc_state *state)
- {
-       memcpy(state, crtc->state, sizeof(*state));
-       if (state->mode_blob)
-               drm_property_blob_get(state->mode_blob);
-       if (state->degamma_lut)
-               drm_property_blob_get(state->degamma_lut);
-       if (state->ctm)
-               drm_property_blob_get(state->ctm);
-       if (state->gamma_lut)
-               drm_property_blob_get(state->gamma_lut);
-       state->mode_changed = false;
-       state->active_changed = false;
-       state->planes_changed = false;
-       state->connectors_changed = false;
-       state->color_mgmt_changed = false;
-       state->zpos_changed = false;
-       state->commit = NULL;
-       state->event = NULL;
-       state->pageflip_flags = 0;
- }
- EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
- /**
-  * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
-  * @crtc: drm CRTC
-  *
-  * Default CRTC state duplicate hook for drivers which don't have their own
-  * subclassed CRTC state structure.
-  */
- struct drm_crtc_state *
- drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
- {
-       struct drm_crtc_state *state;
-       if (WARN_ON(!crtc->state))
-               return NULL;
-       state = kmalloc(sizeof(*state), GFP_KERNEL);
-       if (state)
-               __drm_atomic_helper_crtc_duplicate_state(crtc, state);
-       return state;
- }
- EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
- /**
-  * __drm_atomic_helper_crtc_destroy_state - release CRTC state
-  * @state: CRTC state object to release
-  *
-  * Releases all resources stored in the CRTC state without actually freeing
-  * the memory of the CRTC state. This is useful for drivers that subclass the
-  * CRTC state.
-  */
- 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);
-       }
-       drm_property_blob_put(state->mode_blob);
-       drm_property_blob_put(state->degamma_lut);
-       drm_property_blob_put(state->ctm);
-       drm_property_blob_put(state->gamma_lut);
- }
- EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
- /**
-  * drm_atomic_helper_crtc_destroy_state - default state destroy hook
-  * @crtc: drm CRTC
-  * @state: CRTC state object to release
-  *
-  * Default CRTC state destroy hook for drivers which don't have their own
-  * subclassed CRTC state structure.
-  */
- void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
-                                         struct drm_crtc_state *state)
- {
-       __drm_atomic_helper_crtc_destroy_state(state);
-       kfree(state);
- }
- EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
- /**
-  * __drm_atomic_helper_plane_reset - resets planes state to default values
-  * @plane: plane object, must not be NULL
-  * @state: atomic plane state, must not be NULL
-  *
-  * Initializes plane state to default. This is useful for drivers that subclass
-  * the plane state.
-  */
- void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
-                                    struct drm_plane_state *state)
- {
-       state->plane = plane;
-       state->rotation = DRM_MODE_ROTATE_0;
-       state->alpha = DRM_BLEND_ALPHA_OPAQUE;
-       state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
-       plane->state = state;
- }
- EXPORT_SYMBOL(__drm_atomic_helper_plane_reset);
- /**
-  * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes
-  * @plane: drm plane
-  *
-  * Resets the atomic state for @plane by freeing the state pointer (which might
-  * be NULL, e.g. at driver load time) and allocating a new empty state object.
-  */
- void drm_atomic_helper_plane_reset(struct drm_plane *plane)
- {
-       if (plane->state)
-               __drm_atomic_helper_plane_destroy_state(plane->state);
-       kfree(plane->state);
-       plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
-       if (plane->state)
-               __drm_atomic_helper_plane_reset(plane, plane->state);
- }
- EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
- /**
-  * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
-  * @plane: plane object
-  * @state: atomic plane state
-  *
-  * Copies atomic state from a plane's current state. This is useful for
-  * drivers that subclass the plane state.
-  */
- void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
-                                              struct drm_plane_state *state)
- {
-       memcpy(state, plane->state, sizeof(*state));
-       if (state->fb)
-               drm_framebuffer_get(state->fb);
-       state->fence = NULL;
-       state->commit = NULL;
- }
- EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
- /**
-  * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
-  * @plane: drm plane
-  *
-  * Default plane state duplicate hook for drivers which don't have their own
-  * subclassed plane state structure.
-  */
- struct drm_plane_state *
- drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
- {
-       struct drm_plane_state *state;
-       if (WARN_ON(!plane->state))
-               return NULL;
-       state = kmalloc(sizeof(*state), GFP_KERNEL);
-       if (state)
-               __drm_atomic_helper_plane_duplicate_state(plane, state);
-       return state;
- }
- EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
- /**
-  * __drm_atomic_helper_plane_destroy_state - release plane state
-  * @state: plane state object to release
-  *
-  * Releases all resources stored in the plane state without actually freeing
-  * the memory of the plane state. This is useful for drivers that subclass the
-  * plane state.
-  */
- void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)
- {
-       if (state->fb)
-               drm_framebuffer_put(state->fb);
-       if (state->fence)
-               dma_fence_put(state->fence);
-       if (state->commit)
-               drm_crtc_commit_put(state->commit);
- }
- EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
- /**
-  * drm_atomic_helper_plane_destroy_state - default state destroy hook
-  * @plane: drm plane
-  * @state: plane state object to release
-  *
-  * Default plane state destroy hook for drivers which don't have their own
-  * subclassed plane state structure.
-  */
- void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
-                                          struct drm_plane_state *state)
- {
-       __drm_atomic_helper_plane_destroy_state(state);
-       kfree(state);
- }
- EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
- /**
-  * __drm_atomic_helper_connector_reset - reset state on connector
-  * @connector: drm connector
-  * @conn_state: connector state to assign
-  *
-  * Initializes the newly allocated @conn_state and assigns it to
-  * the &drm_conector->state pointer of @connector, usually required when
-  * initializing the drivers or when called from the &drm_connector_funcs.reset
-  * hook.
-  *
-  * This is useful for drivers that subclass the connector state.
-  */
- void
- __drm_atomic_helper_connector_reset(struct drm_connector *connector,
-                                   struct drm_connector_state *conn_state)
- {
-       if (conn_state)
-               conn_state->connector = connector;
-       connector->state = conn_state;
- }
- EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
- /**
-  * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors
-  * @connector: drm connector
-  *
-  * Resets the atomic state for @connector by freeing the state pointer (which
-  * might be NULL, e.g. at driver load time) and allocating a new empty state
-  * object.
-  */
- void drm_atomic_helper_connector_reset(struct drm_connector *connector)
- {
-       struct drm_connector_state *conn_state =
-               kzalloc(sizeof(*conn_state), GFP_KERNEL);
-       if (connector->state)
-               __drm_atomic_helper_connector_destroy_state(connector->state);
-       kfree(connector->state);
-       __drm_atomic_helper_connector_reset(connector, conn_state);
- }
- EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
- /**
-  * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
-  * @connector: connector object
-  * @state: atomic connector state
-  *
-  * Copies atomic state from a connector's current state. This is useful for
-  * drivers that subclass the connector state.
-  */
- void
- __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
-                                           struct drm_connector_state *state)
- {
-       memcpy(state, connector->state, sizeof(*state));
-       if (state->crtc)
-               drm_connector_get(connector);
-       state->commit = NULL;
-       /* Don't copy over a writeback job, they are used only once */
-       state->writeback_job = NULL;
- }
- EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
- /**
-  * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
-  * @connector: drm connector
-  *
-  * Default connector state duplicate hook for drivers which don't have their own
-  * subclassed connector state structure.
-  */
- struct drm_connector_state *
- drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
- {
-       struct drm_connector_state *state;
-       if (WARN_ON(!connector->state))
-               return NULL;
-       state = kmalloc(sizeof(*state), GFP_KERNEL);
-       if (state)
-               __drm_atomic_helper_connector_duplicate_state(connector, state);
-       return state;
- }
- EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
- /**
-  * drm_atomic_helper_duplicate_state - duplicate an atomic state object
-  * @dev: DRM device
-  * @ctx: lock acquisition context
-  *
-  * Makes a copy of the current atomic state by looping over all objects and
-  * duplicating their respective states. This is used for example by suspend/
-  * resume support code to save the state prior to suspend such that it can
-  * be restored upon resume.
-  *
-  * Note that this treats atomic state as persistent between save and restore.
-  * Drivers must make sure that this is possible and won't result in confusion
-  * or erroneous behaviour.
-  *
-  * Note that if callers haven't already acquired all modeset locks this might
-  * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
-  *
-  * Returns:
-  * A pointer to the copy of the atomic state object on success or an
-  * ERR_PTR()-encoded error code on failure.
-  *
-  * See also:
-  * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
-  */
- struct drm_atomic_state *
- drm_atomic_helper_duplicate_state(struct drm_device *dev,
-                                 struct drm_modeset_acquire_ctx *ctx)
- {
-       struct drm_atomic_state *state;
-       struct drm_connector *conn;
-       struct drm_connector_list_iter conn_iter;
-       struct drm_plane *plane;
-       struct drm_crtc *crtc;
-       int err = 0;
-       state = drm_atomic_state_alloc(dev);
-       if (!state)
-               return ERR_PTR(-ENOMEM);
-       state->acquire_ctx = ctx;
-       drm_for_each_crtc(crtc, dev) {
-               struct drm_crtc_state *crtc_state;
-               crtc_state = drm_atomic_get_crtc_state(state, crtc);
-               if (IS_ERR(crtc_state)) {
-                       err = PTR_ERR(crtc_state);
-                       goto free;
-               }
-       }
-       drm_for_each_plane(plane, dev) {
-               struct drm_plane_state *plane_state;
-               plane_state = drm_atomic_get_plane_state(state, plane);
-               if (IS_ERR(plane_state)) {
-                       err = PTR_ERR(plane_state);
-                       goto free;
-               }
-       }
-       drm_connector_list_iter_begin(dev, &conn_iter);
-       drm_for_each_connector_iter(conn, &conn_iter) {
-               struct drm_connector_state *conn_state;
-               conn_state = drm_atomic_get_connector_state(state, conn);
-               if (IS_ERR(conn_state)) {
-                       err = PTR_ERR(conn_state);
-                       drm_connector_list_iter_end(&conn_iter);
-                       goto free;
-               }
-       }
-       drm_connector_list_iter_end(&conn_iter);
-       /* clear the acquire context so that it isn't accidentally reused */
-       state->acquire_ctx = NULL;
- free:
-       if (err < 0) {
-               drm_atomic_state_put(state);
-               state = ERR_PTR(err);
-       }
-       return state;
- }
- EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
- /**
-  * __drm_atomic_helper_connector_destroy_state - release connector state
-  * @state: connector state object to release
-  *
-  * Releases all resources stored in the connector state without actually
-  * freeing the memory of the connector state. This is useful for drivers that
-  * subclass the connector state.
-  */
- void
- __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state)
- {
-       if (state->crtc)
-               drm_connector_put(state->connector);
-       if (state->commit)
-               drm_crtc_commit_put(state->commit);
- }
- EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
- /**
-  * drm_atomic_helper_connector_destroy_state - default state destroy hook
-  * @connector: drm connector
-  * @state: connector state object to release
-  *
-  * Default connector state destroy hook for drivers which don't have their own
-  * subclassed connector state structure.
-  */
- void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
-                                         struct drm_connector_state *state)
- {
-       __drm_atomic_helper_connector_destroy_state(state);
-       kfree(state);
- }
- EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
- /**
-  * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
-  * @crtc: CRTC object
-  * @red: red correction table
-  * @green: green correction table
-  * @blue: green correction table
-  * @size: size of the tables
-  * @ctx: lock acquire context
-  *
-  * Implements support for legacy gamma correction table for drivers
-  * that support color management through the DEGAMMA_LUT/GAMMA_LUT
-  * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for
-  * how the atomic color management and gamma tables work.
-  */
- int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
-                                      u16 *red, u16 *green, u16 *blue,
-                                      uint32_t size,
-                                      struct drm_modeset_acquire_ctx *ctx)
- {
-       struct drm_device *dev = crtc->dev;
-       struct drm_atomic_state *state;
-       struct drm_crtc_state *crtc_state;
-       struct drm_property_blob *blob = NULL;
-       struct drm_color_lut *blob_data;
-       int i, ret = 0;
-       bool replaced;
-       state = drm_atomic_state_alloc(crtc->dev);
-       if (!state)
-               return -ENOMEM;
-       blob = drm_property_create_blob(dev,
-                                       sizeof(struct drm_color_lut) * size,
-                                       NULL);
-       if (IS_ERR(blob)) {
-               ret = PTR_ERR(blob);
-               blob = NULL;
-               goto fail;
-       }
-       /* Prepare GAMMA_LUT with the legacy values. */
-       blob_data = blob->data;
-       for (i = 0; i < size; i++) {
-               blob_data[i].red = red[i];
-               blob_data[i].green = green[i];
-               blob_data[i].blue = blue[i];
-       }
-       state->acquire_ctx = ctx;
-       crtc_state = drm_atomic_get_crtc_state(state, crtc);
-       if (IS_ERR(crtc_state)) {
-               ret = PTR_ERR(crtc_state);
-               goto fail;
-       }
-       /* Reset DEGAMMA_LUT and CTM properties. */
-       replaced  = drm_property_replace_blob(&crtc_state->degamma_lut, NULL);
-       replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
-       replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob);
-       crtc_state->color_mgmt_changed |= replaced;
-       ret = drm_atomic_commit(state);
- fail:
-       drm_atomic_state_put(state);
-       drm_property_blob_put(blob);
-       return ret;
- }
- EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
- /**
-  * __drm_atomic_helper_private_duplicate_state - copy atomic private state
-  * @obj: CRTC object
-  * @state: new private object state
-  *
-  * Copies atomic state from a private objects's current state and resets inferred values.
-  * This is useful for drivers that subclass the private state.
-  */
- void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
-                                                    struct drm_private_state *state)
- {
-       memcpy(state, obj->state, sizeof(*state));
- }
- EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
index 375cdce7df9425c87749bdbdfeaa3283aacc2239,aa18b1d7d3e4df837de8561ae10322d31ff5159c..fa9baacc863bda92bc070b7f815909ad1d3c6be1
@@@ -260,9 -260,7 +260,7 @@@ int drm_connector_init(struct drm_devic
  
        if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL &&
            connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
-               drm_object_attach_property(&connector->base,
-                                             config->edid_property,
-                                             0);
+               drm_connector_attach_edid_property(connector);
  
        drm_object_attach_property(&connector->base,
                                      config->dpms_property, 0);
@@@ -294,6 -292,24 +292,24 @@@ out_put
  }
  EXPORT_SYMBOL(drm_connector_init);
  
+ /**
+  * drm_connector_attach_edid_property - attach edid property.
+  * @connector: the connector
+  *
+  * Some connector types like DRM_MODE_CONNECTOR_VIRTUAL do not get a
+  * edid property attached by default.  This function can be used to
+  * explicitly enable the edid property in these cases.
+  */
+ void drm_connector_attach_edid_property(struct drm_connector *connector)
+ {
+       struct drm_mode_config *config = &connector->dev->mode_config;
+       drm_object_attach_property(&connector->base,
+                                  config->edid_property,
+                                  0);
+ }
+ EXPORT_SYMBOL(drm_connector_attach_edid_property);
  /**
   * drm_connector_attach_encoder - attach a connector to an encoder
   * @connector: connector to attach
@@@ -916,13 -932,6 +932,13 @@@ DRM_ENUM_NAME_FN(drm_get_content_protec
   *      is no longer protected and userspace should take appropriate action
   *      (whatever that might be).
   *
 + * max bpc:
 + *    This range property is used by userspace to limit the bit depth. When
 + *    used the driver would limit the bpc in accordance with the valid range
 + *    supported by the hardware and sink. Drivers to use the function
 + *    drm_connector_attach_max_bpc_property() to create and attach the
 + *    property to the connector during initialization.
 + *
   * Connectors also have one standardized atomic property:
   *
   * CRTC_ID:
@@@ -1590,40 -1599,6 +1606,40 @@@ void drm_connector_set_link_status_prop
  }
  EXPORT_SYMBOL(drm_connector_set_link_status_property);
  
 +/**
 + * drm_connector_attach_max_bpc_property - attach "max bpc" property
 + * @connector: connector to attach max bpc property on.
 + * @min: The minimum bit depth supported by the connector.
 + * @max: The maximum bit depth supported by the connector.
 + *
 + * This is used to add support for limiting the bit depth on a connector.
 + *
 + * Returns:
 + * Zero on success, negative errno on failure.
 + */
 +int drm_connector_attach_max_bpc_property(struct drm_connector *connector,
 +                                        int min, int max)
 +{
 +      struct drm_device *dev = connector->dev;
 +      struct drm_property *prop;
 +
 +      prop = connector->max_bpc_property;
 +      if (!prop) {
 +              prop = drm_property_create_range(dev, 0, "max bpc", min, max);
 +              if (!prop)
 +                      return -ENOMEM;
 +
 +              connector->max_bpc_property = prop;
 +      }
 +
 +      drm_object_attach_property(&connector->base, prop, max);
 +      connector->state->max_requested_bpc = max;
 +      connector->state->max_bpc = max;
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL(drm_connector_attach_max_bpc_property);
 +
  /**
   * drm_connector_init_panel_orientation_property -
   *    initialize the connecters panel_orientation property
index 1e7e9513bb1007e58d30c417776f6cd6575c5a3b,1c2857f13ad438f2433ae0a90a41227bd4e8f683..0ff878c994e2eef3f21638181d9615fb546c4783
@@@ -12,7 -12,7 +12,7 @@@
  # Note the danger in using -Wall -Wextra is that when CI updates gcc we
  # will most likely get a sudden build breakage... Hopefully we will fix
  # new warnings before CI updates!
- subdir-ccflags-y := -Wall -Wextra -Wvla
+ subdir-ccflags-y := -Wall -Wextra
  subdir-ccflags-y += $(call cc-disable-warning, unused-parameter)
  subdir-ccflags-y += $(call cc-disable-warning, type-limits)
  subdir-ccflags-y += $(call cc-disable-warning, missing-field-initializers)
@@@ -75,7 -75,6 +75,7 @@@ i915-y += i915_cmd_parser.o 
          i915_gemfs.o \
          i915_query.o \
          i915_request.o \
 +        i915_scheduler.o \
          i915_timeline.o \
          i915_trace_points.o \
          i915_vma.o \
@@@ -113,8 -112,6 +113,8 @@@ i915-y += intel_audio.o 
          intel_bios.o \
          intel_cdclk.o \
          intel_color.o \
 +        intel_combo_phy.o \
 +        intel_connector.o \
          intel_display.o \
          intel_dpio_phy.o \
          intel_dpll_mgr.o \
          intel_frontbuffer.o \
          intel_hdcp.o \
          intel_hotplug.o \
 -        intel_modes.o \
          intel_overlay.o \
          intel_psr.o \
 +        intel_quirks.o \
          intel_sideband.o \
          intel_sprite.o
  i915-$(CONFIG_ACPI)           += intel_acpi.o intel_opregion.o
@@@ -145,7 -142,6 +145,7 @@@ i915-y += dvo_ch7017.o 
          intel_dp_link_training.o \
          intel_dp_mst.o \
          intel_dp.o \
 +        intel_dsi.o \
          intel_dsi_dcs_backlight.o \
          intel_dsi_vbt.o \
          intel_dvo.o \
index 7d9457915704d76dae3b8055b185d0c3321dbc00,0c8aa57ce83b4033723ded1540986b628d92d772..c55b1f75c9803e72fe339020bec14d1718385ab2
@@@ -1740,7 -1740,6 +1740,7 @@@ i915_gem_set_domain_ioctl(struct drm_de
         */
        err = i915_gem_object_wait(obj,
                                   I915_WAIT_INTERRUPTIBLE |
 +                                 I915_WAIT_PRIORITY |
                                   (write_domain ? I915_WAIT_ALL : 0),
                                   MAX_SCHEDULE_TIMEOUT,
                                   to_rps_client(file));
@@@ -2382,23 -2381,11 +2382,23 @@@ void __i915_gem_object_invalidate(struc
        invalidate_mapping_pages(mapping, 0, (loff_t)-1);
  }
  
 +/*
 + * Move pages to appropriate lru and release the pagevec, decrementing the
 + * ref count of those pages.
 + */
 +static void check_release_pagevec(struct pagevec *pvec)
 +{
 +      check_move_unevictable_pages(pvec);
 +      __pagevec_release(pvec);
 +      cond_resched();
 +}
 +
  static void
  i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj,
                              struct sg_table *pages)
  {
        struct sgt_iter sgt_iter;
 +      struct pagevec pvec;
        struct page *page;
  
        __i915_gem_object_release_shmem(obj, pages, true);
        if (i915_gem_object_needs_bit17_swizzle(obj))
                i915_gem_object_save_bit_17_swizzle(obj, pages);
  
 +      mapping_clear_unevictable(file_inode(obj->base.filp)->i_mapping);
 +
 +      pagevec_init(&pvec);
        for_each_sgt_page(page, sgt_iter, pages) {
                if (obj->mm.dirty)
                        set_page_dirty(page);
                if (obj->mm.madv == I915_MADV_WILLNEED)
                        mark_page_accessed(page);
  
 -              put_page(page);
 +              if (!pagevec_add(&pvec, page))
 +                      check_release_pagevec(&pvec);
        }
 +      if (pagevec_count(&pvec))
 +              check_release_pagevec(&pvec);
        obj->mm.dirty = false;
  
        sg_free_table(pages);
@@@ -2502,7 -2483,7 +2502,7 @@@ unlock
        mutex_unlock(&obj->mm.lock);
  }
  
 -static bool i915_sg_trim(struct sg_table *orig_st)
 +bool i915_sg_trim(struct sg_table *orig_st)
  {
        struct sg_table new_st;
        struct scatterlist *sg, *new_sg;
@@@ -2543,7 -2524,6 +2543,7 @@@ static int i915_gem_object_get_pages_gt
        unsigned long last_pfn = 0;     /* suppress gcc warning */
        unsigned int max_segment = i915_sg_segment_size();
        unsigned int sg_page_sizes;
 +      struct pagevec pvec;
        gfp_t noreclaim;
        int ret;
  
@@@ -2579,7 -2559,6 +2579,7 @@@ rebuild_st
         * Fail silently without starting the shrinker
         */
        mapping = obj->base.filp->f_mapping;
 +      mapping_set_unevictable(mapping);
        noreclaim = mapping_gfp_constraint(mapping, ~__GFP_RECLAIM);
        noreclaim |= __GFP_NORETRY | __GFP_NOWARN;
  
                gfp_t gfp = noreclaim;
  
                do {
 +                      cond_resched();
                        page = shmem_read_mapping_page_gfp(mapping, i, gfp);
                        if (likely(!IS_ERR(page)))
                                break;
                        }
  
                        i915_gem_shrink(dev_priv, 2 * page_count, NULL, *s++);
 -                      cond_resched();
  
                        /*
                         * We've tried hard to allocate the memory by reaping
  err_sg:
        sg_mark_end(sg);
  err_pages:
 -      for_each_sgt_page(page, sgt_iter, st)
 -              put_page(page);
 +      mapping_clear_unevictable(mapping);
 +      pagevec_init(&pvec);
 +      for_each_sgt_page(page, sgt_iter, st) {
 +              if (!pagevec_add(&pvec, page))
 +                      check_release_pagevec(&pvec);
 +      }
 +      if (pagevec_count(&pvec))
 +              check_release_pagevec(&pvec);
        sg_free_table(st);
        kfree(st);
  
@@@ -3557,8 -3530,6 +3557,8 @@@ static void __sleep_rcu(struct rcu_hea
        struct sleep_rcu_work *s = container_of(rcu, typeof(*s), rcu);
        struct drm_i915_private *i915 = s->i915;
  
 +      destroy_rcu_head(&s->rcu);
 +
        if (same_epoch(i915, s->epoch)) {
                INIT_WORK(&s->work, __sleep_work);
                queue_work(i915->wq, &s->work);
@@@ -3675,7 -3646,6 +3675,7 @@@ out_rearm
        if (same_epoch(dev_priv, epoch)) {
                struct sleep_rcu_work *s = kmalloc(sizeof(*s), GFP_KERNEL);
                if (s) {
 +                      init_rcu_head(&s->rcu);
                        s->i915 = dev_priv;
                        s->epoch = epoch;
                        call_rcu(&s->rcu, __sleep_rcu);
@@@ -3773,9 -3743,7 +3773,9 @@@ i915_gem_wait_ioctl(struct drm_device *
        start = ktime_get();
  
        ret = i915_gem_object_wait(obj,
 -                                 I915_WAIT_INTERRUPTIBLE | I915_WAIT_ALL,
 +                                 I915_WAIT_INTERRUPTIBLE |
 +                                 I915_WAIT_PRIORITY |
 +                                 I915_WAIT_ALL,
                                   to_wait_timeout(args->timeout_ns),
                                   to_rps_client(file));
  
@@@ -4742,8 -4710,6 +4742,8 @@@ void i915_gem_object_init(struct drm_i9
        INIT_LIST_HEAD(&obj->lut_list);
        INIT_LIST_HEAD(&obj->batch_pool_link);
  
 +      init_rcu_head(&obj->rcu);
 +
        obj->ops = ops;
  
        reservation_object_init(&obj->__builtin_resv);
@@@ -5010,13 -4976,6 +5010,13 @@@ static void __i915_gem_free_object_rcu(
                container_of(head, typeof(*obj), rcu);
        struct drm_i915_private *i915 = to_i915(obj->base.dev);
  
 +      /*
 +       * We reuse obj->rcu for the freed list, so we had better not treat
 +       * it like a rcu_head from this point forwards. And we expect all
 +       * objects to be freed via this path.
 +       */
 +      destroy_rcu_head(&obj->rcu);
 +
        /*
         * Since we require blocking on struct_mutex to unbind the freed
         * object from the GPU before releasing resources back to the
@@@ -5334,6 -5293,18 +5334,6 @@@ int i915_gem_init_hw(struct drm_i915_pr
                I915_WRITE(MI_PREDICATE_RESULT_2, IS_HSW_GT3(dev_priv) ?
                           LOWER_SLICE_ENABLED : LOWER_SLICE_DISABLED);
  
 -      if (HAS_PCH_NOP(dev_priv)) {
 -              if (IS_IVYBRIDGE(dev_priv)) {
 -                      u32 temp = I915_READ(GEN7_MSG_CTL);
 -                      temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK);
 -                      I915_WRITE(GEN7_MSG_CTL, temp);
 -              } else if (INTEL_GEN(dev_priv) >= 7) {
 -                      u32 temp = I915_READ(HSW_NDE_RSTWRN_OPT);
 -                      temp &= ~RESET_PCH_HANDSHAKE_ENABLE;
 -                      I915_WRITE(HSW_NDE_RSTWRN_OPT, temp);
 -              }
 -      }
 -
        intel_gt_workarounds_apply(dev_priv);
  
        i915_gem_init_swizzling(dev_priv);
@@@ -5980,7 -5951,7 +5980,7 @@@ void i915_gem_track_fb(struct drm_i915_
         * the bits.
         */
        BUILD_BUG_ON(INTEL_FRONTBUFFER_BITS_PER_PIPE * I915_MAX_PIPES >
 -                   sizeof(atomic_t) * BITS_PER_BYTE);
 +                   BITS_PER_TYPE(atomic_t));
  
        if (old) {
                WARN_ON(!(atomic_read(&old->frontbuffer_bits) & frontbuffer_bits));
@@@ -6081,7 -6052,8 +6081,8 @@@ i915_gem_object_get_sg(struct drm_i915_
        count = __sg_page_count(sg);
  
        while (idx + count <= n) {
-               unsigned long exception, i;
+               void *entry;
+               unsigned long i;
                int ret;
  
                /* If we cannot allocate and insert this entry, or the
                if (ret && ret != -EEXIST)
                        goto scan;
  
-               exception =
-                       RADIX_TREE_EXCEPTIONAL_ENTRY |
-                       idx << RADIX_TREE_EXCEPTIONAL_SHIFT;
+               entry = xa_mk_value(idx);
                for (i = 1; i < count; i++) {
-                       ret = radix_tree_insert(&iter->radix, idx + i,
-                                               (void *)exception);
+                       ret = radix_tree_insert(&iter->radix, idx + i, entry);
                        if (ret && ret != -EEXIST)
                                goto scan;
                }
@@@ -6139,15 -6108,14 +6137,14 @@@ lookup
        GEM_BUG_ON(!sg);
  
        /* If this index is in the middle of multi-page sg entry,
-        * the radixtree will contain an exceptional entry that points
+        * the radix tree will contain a value entry that points
         * to the start of that range. We will return the pointer to
         * the base page and the offset of this page within the
         * sg entry's range.
         */
        *offset = 0;
-       if (unlikely(radix_tree_exception(sg))) {
-               unsigned long base =
-                       (unsigned long)sg >> RADIX_TREE_EXCEPTIONAL_SHIFT;
+       if (unlikely(xa_is_value(sg))) {
+               unsigned long base = xa_to_value(sg);
  
                sg = radix_tree_lookup(&iter->radix, base);
                GEM_BUG_ON(!sg);
index d4fac09095f862aed3131243957059de2df4f6b0,1a1c04db6c80651e4bf3a88eb3000bf084caca47..7b3ae2333dbf4cea0cb95c3ead0d9d3e53b4dfa3
@@@ -1268,7 -1268,7 +1268,7 @@@ relocate_entry(struct i915_vma *vma
                else if (gen >= 4)
                        len = 4;
                else
 -                      len = 3;
 +                      len = 6;
  
                batch = reloc_gpu(eb, vma, len);
                if (IS_ERR(batch))
                        *batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
                        *batch++ = addr;
                        *batch++ = target_offset;
 +
 +                      /* And again for good measure (blb/pnv) */
 +                      *batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
 +                      *batch++ = addr;
 +                      *batch++ = target_offset;
                }
  
                goto out;
@@@ -2162,7 -2157,7 +2162,7 @@@ await_fence_array(struct i915_execbuffe
                if (!(flags & I915_EXEC_FENCE_WAIT))
                        continue;
  
-               fence = drm_syncobj_fence_get(syncobj);
+               drm_syncobj_search_fence(syncobj, 0, 0, &fence);
                if (!fence)
                        return -EINVAL;
  
index 82652c3d1bed65145b465a9a6e5e244500dcc803,35fce4c88629ea4b61187819194f08767e1bb71e..5b4d78cdb4ca32c4162322b4750e2dec80fe99d1
@@@ -305,12 -305,12 +305,12 @@@ int i915_vma_bind(struct i915_vma *vma
        GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
        GEM_BUG_ON(vma->size > vma->node.size);
  
 -      if (GEM_WARN_ON(range_overflows(vma->node.start,
 -                                      vma->node.size,
 -                                      vma->vm->total)))
 +      if (GEM_DEBUG_WARN_ON(range_overflows(vma->node.start,
 +                                            vma->node.size,
 +                                            vma->vm->total)))
                return -ENODEV;
  
 -      if (GEM_WARN_ON(!flags))
 +      if (GEM_DEBUG_WARN_ON(!flags))
                return -EINVAL;
  
        bind_flags = 0;
@@@ -892,7 -892,7 +892,7 @@@ static void export_fence(struct i915_vm
        reservation_object_lock(resv, NULL);
        if (flags & EXEC_OBJECT_WRITE)
                reservation_object_add_excl_fence(resv, &rq->fence);
-       else if (reservation_object_reserve_shared(resv) == 0)
+       else if (reservation_object_reserve_shared(resv, 1) == 0)
                reservation_object_add_shared_fence(resv, &rq->fence);
        reservation_object_unlock(resv);
  }
index 314ec14fc952406217628ad3f29af1812f80add6,d7234e03fdb0cc385db1482993cddcdbc62126c2..e2c6a2b3e8f2591da7a2652c26955421f702e816
@@@ -148,13 -148,14 +148,13 @@@ hsw_dip_data_reg(struct drm_i915_privat
        }
  }
  
 -static void g4x_write_infoframe(struct drm_encoder *encoder,
 +static void g4x_write_infoframe(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len)
  {
        const u32 *data = frame;
 -      struct drm_device *dev = encoder->dev;
 -      struct drm_i915_private *dev_priv = to_i915(dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        u32 val = I915_READ(VIDEO_DIP_CTL);
        int i;
  
        POSTING_READ(VIDEO_DIP_CTL);
  }
  
 -static bool g4x_infoframe_enabled(struct drm_encoder *encoder,
 +static bool g4x_infoframe_enabled(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 -      struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        u32 val = I915_READ(VIDEO_DIP_CTL);
  
        if ((val & VIDEO_DIP_ENABLE) == 0)
                return false;
  
 -      if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
 +      if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
                return false;
  
        return val & (VIDEO_DIP_ENABLE_AVI |
                      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
  }
  
 -static void ibx_write_infoframe(struct drm_encoder *encoder,
 +static void ibx_write_infoframe(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len)
  {
        const u32 *data = frame;
 -      struct drm_device *dev = encoder->dev;
 -      struct drm_i915_private *dev_priv = to_i915(dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
        POSTING_READ(reg);
  }
  
 -static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
 +static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 -      struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
        i915_reg_t reg = TVIDEO_DIP_CTL(pipe);
        u32 val = I915_READ(reg);
        if ((val & VIDEO_DIP_ENABLE) == 0)
                return false;
  
 -      if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
 +      if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
                return false;
  
        return val & (VIDEO_DIP_ENABLE_AVI |
                      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
  }
  
 -static void cpt_write_infoframe(struct drm_encoder *encoder,
 +static void cpt_write_infoframe(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len)
  {
        const u32 *data = frame;
 -      struct drm_device *dev = encoder->dev;
 -      struct drm_i915_private *dev_priv = to_i915(dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
        POSTING_READ(reg);
  }
  
 -static bool cpt_infoframe_enabled(struct drm_encoder *encoder,
 +static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
        u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
  
                      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
  }
  
 -static void vlv_write_infoframe(struct drm_encoder *encoder,
 +static void vlv_write_infoframe(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len)
  {
        const u32 *data = frame;
 -      struct drm_device *dev = encoder->dev;
 -      struct drm_i915_private *dev_priv = to_i915(dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
        POSTING_READ(reg);
  }
  
 -static bool vlv_infoframe_enabled(struct drm_encoder *encoder,
 +static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 -      struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
        u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
  
        if ((val & VIDEO_DIP_ENABLE) == 0)
                return false;
  
 -      if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
 +      if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
                return false;
  
        return val & (VIDEO_DIP_ENABLE_AVI |
                      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
  }
  
 -static void hsw_write_infoframe(struct drm_encoder *encoder,
 +static void hsw_write_infoframe(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len)
  {
        const u32 *data = frame;
 -      struct drm_device *dev = encoder->dev;
 -      struct drm_i915_private *dev_priv = to_i915(dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
        i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
        int data_size = type == DP_SDP_VSC ?
        POSTING_READ(ctl_reg);
  }
  
 -static bool hsw_infoframe_enabled(struct drm_encoder *encoder,
 +static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        u32 val = I915_READ(HSW_TVIDEO_DIP_CTL(pipe_config->cpu_transcoder));
  
        return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
   * trick them by giving an offset into the buffer and moving back the header
   * bytes by one.
   */
 -static void intel_write_infoframe(struct drm_encoder *encoder,
 +static void intel_write_infoframe(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *crtc_state,
                                  union hdmi_infoframe *frame)
  {
 -      struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 +      struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
        u8 buffer[VIDEO_DIP_DATA_SIZE];
        ssize_t len;
  
                return;
  
        /* Insert the 'hole' (see big comment above) at position 3 */
 -      buffer[0] = buffer[1];
 -      buffer[1] = buffer[2];
 -      buffer[2] = buffer[3];
 +      memmove(&buffer[0], &buffer[1], 3);
        buffer[3] = 0;
        len++;
  
 -      intel_dig_port->write_infoframe(encoder, crtc_state, frame->any.type, buffer, len);
 +      intel_dig_port->write_infoframe(encoder,
 +                                      crtc_state,
 +                                      frame->any.type, buffer, len);
  }
  
 -static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
 +static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder,
                                         const struct intel_crtc_state *crtc_state,
                                         const struct drm_connector_state *conn_state)
  {
 -      struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 +      struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        const struct drm_display_mode *adjusted_mode =
                &crtc_state->base.adjusted_mode;
        struct drm_connector *connector = &intel_hdmi->attached_connector->base;
-       bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
+       bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported ||
+          connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420;
        union hdmi_infoframe frame;
        int ret;
  
                return;
        }
  
 -      if (crtc_state->ycbcr420)
 +      if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
                frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
 +      else if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
 +              frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
        else
                frame.avi.colorspace = HDMI_COLORSPACE_RGB;
  
                                            conn_state);
  
        /* TODO: handle pixel repetition for YCBCR420 outputs */
 -      intel_write_infoframe(encoder, crtc_state, &frame);
 +      intel_write_infoframe(encoder, crtc_state,
 +                            &frame);
  }
  
 -static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder,
 +static void intel_hdmi_set_spd_infoframe(struct intel_encoder *encoder,
                                         const struct intel_crtc_state *crtc_state)
  {
        union hdmi_infoframe frame;
  
        frame.spd.sdi = HDMI_SPD_SDI_PC;
  
 -      intel_write_infoframe(encoder, crtc_state, &frame);
 +      intel_write_infoframe(encoder, crtc_state,
 +                            &frame);
  }
  
  static void
 -intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
 +intel_hdmi_set_hdmi_infoframe(struct intel_encoder *encoder,
                              const struct intel_crtc_state *crtc_state,
                              const struct drm_connector_state *conn_state)
  {
        if (ret < 0)
                return;
  
 -      intel_write_infoframe(encoder, crtc_state, &frame);
 +      intel_write_infoframe(encoder, crtc_state,
 +                            &frame);
  }
  
 -static void g4x_set_infoframes(struct drm_encoder *encoder,
 +static void g4x_set_infoframes(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 -      struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 +      struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
        struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
        i915_reg_t reg = VIDEO_DIP_CTL;
        u32 val = I915_READ(reg);
 -      u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
 +      u32 port = VIDEO_DIP_PORT(encoder->port);
  
        assert_hdmi_port_disabled(intel_hdmi);
  
@@@ -654,11 -658,11 +655,11 @@@ static bool gcp_default_phase_possible(
                 mode->crtc_htotal/2 % pixels_per_group == 0);
  }
  
 -static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder,
 +static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
                                         const struct intel_crtc_state *crtc_state,
                                         const struct drm_connector_state *conn_state)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        i915_reg_t reg;
        u32 val = 0;
        return val != 0;
  }
  
 -static void ibx_set_infoframes(struct drm_encoder *encoder,
 +static void ibx_set_infoframes(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
 -      struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 +      struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
        struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
        i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
 -      u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
 +      u32 port = VIDEO_DIP_PORT(encoder->port);
  
        assert_hdmi_port_disabled(intel_hdmi);
  
        intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
  }
  
 -static void cpt_set_infoframes(struct drm_encoder *encoder,
 +static void cpt_set_infoframes(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
 -      struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 +      struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
  
        intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
  }
  
 -static void vlv_set_infoframes(struct drm_encoder *encoder,
 +static void vlv_set_infoframes(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 -      struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
 -      struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 +      struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
 -      u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
 +      u32 port = VIDEO_DIP_PORT(encoder->port);
  
        assert_hdmi_port_disabled(intel_hdmi);
  
        intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
  }
  
 -static void hsw_set_infoframes(struct drm_encoder *encoder,
 +static void hsw_set_infoframes(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state)
  {
 -      struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder);
        u32 val = I915_READ(reg);
  
@@@ -961,13 -966,13 +962,13 @@@ int intel_hdmi_hdcp_write_an_aksv(struc
        ret = intel_hdmi_hdcp_write(intel_dig_port, DRM_HDCP_DDC_AN, an,
                                    DRM_HDCP_AN_LEN);
        if (ret) {
 -              DRM_ERROR("Write An over DDC failed (%d)\n", ret);
 +              DRM_DEBUG_KMS("Write An over DDC failed (%d)\n", ret);
                return ret;
        }
  
        ret = intel_gmbus_output_aksv(adapter);
        if (ret < 0) {
 -              DRM_ERROR("Failed to output aksv (%d)\n", ret);
 +              DRM_DEBUG_KMS("Failed to output aksv (%d)\n", ret);
                return ret;
        }
        return 0;
@@@ -980,7 -985,7 +981,7 @@@ static int intel_hdmi_hdcp_read_bksv(st
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BKSV, bksv,
                                   DRM_HDCP_KSV_LEN);
        if (ret)
 -              DRM_ERROR("Read Bksv over DDC failed (%d)\n", ret);
 +              DRM_DEBUG_KMS("Read Bksv over DDC failed (%d)\n", ret);
        return ret;
  }
  
@@@ -992,7 -997,7 +993,7 @@@ int intel_hdmi_hdcp_read_bstatus(struc
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BSTATUS,
                                   bstatus, DRM_HDCP_BSTATUS_LEN);
        if (ret)
 -              DRM_ERROR("Read bstatus over DDC failed (%d)\n", ret);
 +              DRM_DEBUG_KMS("Read bstatus over DDC failed (%d)\n", ret);
        return ret;
  }
  
@@@ -1005,7 -1010,7 +1006,7 @@@ int intel_hdmi_hdcp_repeater_present(st
  
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
        if (ret) {
 -              DRM_ERROR("Read bcaps over DDC failed (%d)\n", ret);
 +              DRM_DEBUG_KMS("Read bcaps over DDC failed (%d)\n", ret);
                return ret;
        }
        *repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
@@@ -1020,7 -1025,7 +1021,7 @@@ int intel_hdmi_hdcp_read_ri_prime(struc
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_RI_PRIME,
                                   ri_prime, DRM_HDCP_RI_LEN);
        if (ret)
 -              DRM_ERROR("Read Ri' over DDC failed (%d)\n", ret);
 +              DRM_DEBUG_KMS("Read Ri' over DDC failed (%d)\n", ret);
        return ret;
  }
  
@@@ -1033,7 -1038,7 +1034,7 @@@ int intel_hdmi_hdcp_read_ksv_ready(stru
  
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
        if (ret) {
 -              DRM_ERROR("Read bcaps over DDC failed (%d)\n", ret);
 +              DRM_DEBUG_KMS("Read bcaps over DDC failed (%d)\n", ret);
                return ret;
        }
        *ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
@@@ -1048,7 -1053,7 +1049,7 @@@ int intel_hdmi_hdcp_read_ksv_fifo(struc
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_KSV_FIFO,
                                   ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN);
        if (ret) {
 -              DRM_ERROR("Read ksv fifo over DDC failed (%d)\n", ret);
 +              DRM_DEBUG_KMS("Read ksv fifo over DDC failed (%d)\n", ret);
                return ret;
        }
        return 0;
@@@ -1066,7 -1071,7 +1067,7 @@@ int intel_hdmi_hdcp_read_v_prime_part(s
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_V_PRIME(i),
                                   part, DRM_HDCP_V_PRIME_PART_LEN);
        if (ret)
 -              DRM_ERROR("Read V'[%d] over DDC failed (%d)\n", i, ret);
 +              DRM_DEBUG_KMS("Read V'[%d] over DDC failed (%d)\n", i, ret);
        return ret;
  }
  
@@@ -1213,7 -1218,7 +1214,7 @@@ static void intel_hdmi_get_config(struc
        if (tmp & HDMI_MODE_SELECT_HDMI)
                pipe_config->has_hdmi_sink = true;
  
 -      if (intel_dig_port->infoframe_enabled(&encoder->base, pipe_config))
 +      if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
                pipe_config->has_infoframe = true;
  
        if (tmp & SDVO_AUDIO_ENABLE)
@@@ -1434,8 -1439,7 +1435,8 @@@ static void intel_disable_hdmi(struct i
                intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
        }
  
 -      intel_dig_port->set_infoframes(&encoder->base, false,
 +      intel_dig_port->set_infoframes(encoder,
 +                                     false,
                                       old_crtc_state, old_conn_state);
  
        intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
@@@ -1594,8 -1598,6 +1595,8 @@@ static bool hdmi_deep_color_possible(co
        struct drm_atomic_state *state = crtc_state->base.state;
        struct drm_connector_state *connector_state;
        struct drm_connector *connector;
 +      const struct drm_display_mode *adjusted_mode =
 +              &crtc_state->base.adjusted_mode;
        int i;
  
        if (HAS_GMCH_DISPLAY(dev_priv))
                if (connector_state->crtc != crtc_state->base.crtc)
                        continue;
  
 -              if (crtc_state->ycbcr420) {
 +              if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
                        const struct drm_hdmi_info *hdmi = &info->hdmi;
  
                        if (bpc == 12 && !(hdmi->y420_dc_modes &
  
        /* Display WA #1139: glk */
        if (bpc == 12 && IS_GLK_REVID(dev_priv, 0, GLK_REVID_A1) &&
 -          crtc_state->base.adjusted_mode.htotal > 5460)
 +          adjusted_mode->htotal > 5460)
 +              return false;
 +
 +      /* Display Wa_1405510057:icl */
 +      if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
 +          bpc == 10 && IS_ICELAKE(dev_priv) &&
 +          (adjusted_mode->crtc_hblank_end -
 +           adjusted_mode->crtc_hblank_start) % 8 == 2)
                return false;
  
        return true;
@@@ -1675,7 -1670,7 +1676,7 @@@ intel_hdmi_ycbcr420_config(struct drm_c
        *clock_12bpc /= 2;
        *clock_10bpc /= 2;
        *clock_8bpc /= 2;
 -      config->ycbcr420 = true;
 +      config->output_format = INTEL_OUTPUT_FORMAT_YCBCR420;
  
        /* YCBCR 420 output conversion needs a scaler */
        if (skl_update_scaler_crtc(config)) {
@@@ -1709,7 -1704,6 +1710,7 @@@ bool intel_hdmi_compute_config(struct i
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return false;
  
 +      pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink;
  
        if (pipe_config->has_hdmi_sink)
@@@ -1980,7 -1974,7 +1981,7 @@@ static void intel_hdmi_pre_enable(struc
  
        intel_hdmi_prepare(encoder, pipe_config);
  
 -      intel_dig_port->set_infoframes(&encoder->base,
 +      intel_dig_port->set_infoframes(encoder,
                                       pipe_config->has_infoframe,
                                       pipe_config, conn_state);
  }
@@@ -1998,7 -1992,7 +1999,7 @@@ static void vlv_hdmi_pre_enable(struct 
        vlv_set_phy_signal_level(encoder, 0x2b245f5f, 0x00002000, 0x5578b83a,
                                 0x2b247878);
  
 -      dport->set_infoframes(&encoder->base,
 +      dport->set_infoframes(encoder,
                              pipe_config->has_infoframe,
                              pipe_config, conn_state);
  
@@@ -2069,7 -2063,7 +2070,7 @@@ static void chv_hdmi_pre_enable(struct 
        /* Use 800mV-0dB */
        chv_set_phy_signal_level(encoder, 128, 102, false);
  
 -      dport->set_infoframes(&encoder->base,
 +      dport->set_infoframes(encoder,
                              pipe_config->has_infoframe,
                              pipe_config, conn_state);
  
        chv_phy_release_cl2_override(encoder);
  }
  
 +static int
 +intel_hdmi_connector_register(struct drm_connector *connector)
 +{
 +      int ret;
 +
 +      ret = intel_connector_register(connector);
 +      if (ret)
 +              return ret;
 +
 +      i915_debugfs_connector_add(connector);
 +
 +      return ret;
 +}
 +
  static void intel_hdmi_destroy(struct drm_connector *connector)
  {
        if (intel_attached_hdmi(connector)->cec_notifier)
                cec_notifier_put(intel_attached_hdmi(connector)->cec_notifier);
 -      kfree(to_intel_connector(connector)->detect_edid);
 -      drm_connector_cleanup(connector);
 -      kfree(connector);
 +
 +      intel_connector_destroy(connector);
  }
  
  static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_get_property = intel_digital_connector_atomic_get_property,
        .atomic_set_property = intel_digital_connector_atomic_set_property,
 -      .late_register = intel_connector_register,
 +      .late_register = intel_hdmi_connector_register,
        .early_unregister = intel_connector_unregister,
        .destroy = intel_hdmi_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
@@@ -2129,16 -2110,11 +2130,16 @@@ static const struct drm_encoder_funcs i
  static void
  intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
  {
 +      struct drm_i915_private *dev_priv = to_i915(connector->dev);
 +
        intel_attach_force_audio_property(connector);
        intel_attach_broadcast_rgb_property(connector);
        intel_attach_aspect_ratio_property(connector);
        drm_connector_attach_content_type_property(connector);
        connector->state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
 +
 +      if (!HAS_GMCH_DISPLAY(dev_priv))
 +              drm_connector_attach_max_bpc_property(connector, 8, 12);
  }
  
  /*
@@@ -2349,18 -2325,9 +2350,18 @@@ void intel_infoframe_init(struct intel_
                intel_dig_port->set_infoframes = g4x_set_infoframes;
                intel_dig_port->infoframe_enabled = g4x_infoframe_enabled;
        } else if (HAS_DDI(dev_priv)) {
 -              intel_dig_port->write_infoframe = hsw_write_infoframe;
 -              intel_dig_port->set_infoframes = hsw_set_infoframes;
 -              intel_dig_port->infoframe_enabled = hsw_infoframe_enabled;
 +              if (intel_dig_port->lspcon.active) {
 +                      intel_dig_port->write_infoframe =
 +                                      lspcon_write_infoframe;
 +                      intel_dig_port->set_infoframes = lspcon_set_infoframes;
 +                      intel_dig_port->infoframe_enabled =
 +                                              lspcon_infoframe_enabled;
 +              } else {
 +                      intel_dig_port->set_infoframes = hsw_set_infoframes;
 +                      intel_dig_port->infoframe_enabled =
 +                                              hsw_infoframe_enabled;
 +                      intel_dig_port->write_infoframe = hsw_write_infoframe;
 +              }
        } else if (HAS_PCH_IBX(dev_priv)) {
                intel_dig_port->write_infoframe = ibx_write_infoframe;
                intel_dig_port->set_infoframes = ibx_set_infoframes;
@@@ -2519,6 -2486,5 +2520,6 @@@ void intel_hdmi_init(struct drm_i915_pr
  
        intel_infoframe_init(intel_dig_port);
  
 +      intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
        intel_hdmi_init_connector(intel_dig_port, intel_connector);
  }
index 6cf19984facbc6608a418fa0fd2ce69251de11c8,dd0552cb747232cc7ac89003c6af846d6b90a0e5..af0a761f52f0ef7d2ff055431c4f990a95de627b
@@@ -508,18 -508,6 +508,18 @@@ struct drm_connector_state 
         * drm_writeback_signal_completion()
         */
        struct drm_writeback_job *writeback_job;
 +
 +      /**
 +       * @max_requested_bpc: Connector property to limit the maximum bit
 +       * depth of the pixels.
 +       */
 +      u8 max_requested_bpc;
 +
 +      /**
 +       * @max_bpc: Connector max_bpc based on the requested max_bpc property
 +       * and the connector bpc limitations obtained from edid.
 +       */
 +      u8 max_bpc;
  };
  
  /**
@@@ -985,12 -973,6 +985,12 @@@ struct drm_connector 
         */
        struct drm_property_blob *path_blob_ptr;
  
 +      /**
 +       * @max_bpc_property: Default connector property for the max bpc to be
 +       * driven out of the connector.
 +       */
 +      struct drm_property *max_bpc_property;
 +
  #define DRM_CONNECTOR_POLL_HPD (1 << 0)
  #define DRM_CONNECTOR_POLL_CONNECT (1 << 1)
  #define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2)
@@@ -1151,6 -1133,7 +1151,7 @@@ int drm_connector_init(struct drm_devic
                       struct drm_connector *connector,
                       const struct drm_connector_funcs *funcs,
                       int connector_type);
+ void drm_connector_attach_edid_property(struct drm_connector *connector);
  int drm_connector_register(struct drm_connector *connector);
  void drm_connector_unregister(struct drm_connector *connector);
  int drm_connector_attach_encoder(struct drm_connector *connector,
@@@ -1286,8 -1269,6 +1287,8 @@@ void drm_connector_set_link_status_prop
                                            uint64_t link_status);
  int drm_connector_init_panel_orientation_property(
        struct drm_connector *connector, int width, int height);
 +int drm_connector_attach_max_bpc_property(struct drm_connector *connector,
 +                                        int min, int max);
  
  /**
   * struct drm_tile_group - Tile group metadata
index 3e781dfb6fc1b9a7822a13e8310a754052132226,9ad98e8d9ede0745a67737f19aaaa11c4774fee1..3314e91f6eb318b32f2dc7981b95bd1b4f4c17e4
  #define DP_DSC_MAX_BITS_PER_PIXEL_LOW       0x067   /* eDP 1.4 */
  
  #define DP_DSC_MAX_BITS_PER_PIXEL_HI        0x068   /* eDP 1.4 */
 +# define DP_DSC_MAX_BITS_PER_PIXEL_HI_MASK  (0x3 << 0)
 +# define DP_DSC_MAX_BITS_PER_PIXEL_HI_SHIFT 8
  
  #define DP_DSC_DEC_COLOR_FORMAT_CAP         0x069
  # define DP_DSC_RGB                         (1 << 0)
  # define DP_DSC_THROUGHPUT_MODE_1_1000      (14 << 4)
  
  #define DP_DSC_MAX_SLICE_WIDTH              0x06C
 +#define DP_DSC_MIN_SLICE_WIDTH_VALUE        2560
 +#define DP_DSC_SLICE_WIDTH_MULTIPLIER       320
  
  #define DP_DSC_SLICE_CAP_2                  0x06D
  # define DP_DSC_16_PER_DP_DSC_SINK          (1 << 0)
  # define DP_AUX_FRAME_SYNC_VALID          (1 << 0)
  
  #define DP_DSC_ENABLE                       0x160   /* DP 1.4 */
 +# define DP_DECOMPRESSION_EN                (1 << 0)
  
  #define DP_PSR_EN_CFG                     0x170   /* XXX 1.2? */
  # define DP_PSR_ENABLE                            (1 << 0)
  # define DP_EDP_12                        0x01
  # define DP_EDP_13                        0x02
  # define DP_EDP_14                        0x03
+ # define DP_EDP_14a                         0x04    /* eDP 1.4a */
+ # define DP_EDP_14b                         0x05    /* eDP 1.4b */
  
  #define DP_EDP_GENERAL_CAP_1              0x701
  # define DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP         (1 << 0)
  #define DP_AUX_HDCP_KSV_FIFO          0x6802C
  #define DP_AUX_HDCP_AINFO             0x6803B
  
 +/* DP HDCP2.2 parameter offsets in DPCD address space */
 +#define DP_HDCP_2_2_REG_RTX_OFFSET            0x69000
 +#define DP_HDCP_2_2_REG_TXCAPS_OFFSET         0x69008
 +#define DP_HDCP_2_2_REG_CERT_RX_OFFSET                0x6900B
 +#define DP_HDCP_2_2_REG_RRX_OFFSET            0x69215
 +#define DP_HDCP_2_2_REG_RX_CAPS_OFFSET                0x6921D
 +#define DP_HDCP_2_2_REG_EKPUB_KM_OFFSET               0x69220
 +#define DP_HDCP_2_2_REG_EKH_KM_WR_OFFSET      0x692A0
 +#define DP_HDCP_2_2_REG_M_OFFSET              0x692B0
 +#define DP_HDCP_2_2_REG_HPRIME_OFFSET         0x692C0
 +#define DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET      0x692E0
 +#define DP_HDCP_2_2_REG_RN_OFFSET             0x692F0
 +#define DP_HDCP_2_2_REG_LPRIME_OFFSET         0x692F8
 +#define DP_HDCP_2_2_REG_EDKEY_KS_OFFSET               0x69318
 +#define       DP_HDCP_2_2_REG_RIV_OFFSET              0x69328
 +#define DP_HDCP_2_2_REG_RXINFO_OFFSET         0x69330
 +#define DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET      0x69332
 +#define DP_HDCP_2_2_REG_VPRIME_OFFSET         0x69335
 +#define DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET   0x69345
 +#define DP_HDCP_2_2_REG_V_OFFSET              0x693E0
 +#define DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET      0x693F0
 +#define DP_HDCP_2_2_REG_K_OFFSET              0x693F3
 +#define DP_HDCP_2_2_REG_STREAM_ID_TYPE_OFFSET 0x693F5
 +#define DP_HDCP_2_2_REG_MPRIME_OFFSET         0x69473
 +#define DP_HDCP_2_2_REG_RXSTATUS_OFFSET               0x69493
 +#define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET    0x69494
 +#define DP_HDCP_2_2_REG_DBG_OFFSET            0x69518
 +
 +/* DP HDCP message start offsets in DPCD address space */
 +#define DP_HDCP_2_2_AKE_INIT_OFFSET           DP_HDCP_2_2_REG_RTX_OFFSET
 +#define DP_HDCP_2_2_AKE_SEND_CERT_OFFSET      DP_HDCP_2_2_REG_CERT_RX_OFFSET
 +#define DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET   DP_HDCP_2_2_REG_EKPUB_KM_OFFSET
 +#define DP_HDCP_2_2_AKE_STORED_KM_OFFSET      DP_HDCP_2_2_REG_EKH_KM_WR_OFFSET
 +#define DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET    DP_HDCP_2_2_REG_HPRIME_OFFSET
 +#define DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET \
 +                                              DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET
 +#define DP_HDCP_2_2_LC_INIT_OFFSET            DP_HDCP_2_2_REG_RN_OFFSET
 +#define DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET     DP_HDCP_2_2_REG_LPRIME_OFFSET
 +#define DP_HDCP_2_2_SKE_SEND_EKS_OFFSET               DP_HDCP_2_2_REG_EDKEY_KS_OFFSET
 +#define DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET       DP_HDCP_2_2_REG_RXINFO_OFFSET
 +#define DP_HDCP_2_2_REP_SEND_ACK_OFFSET               DP_HDCP_2_2_REG_V_OFFSET
 +#define DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET  DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET
 +#define DP_HDCP_2_2_REP_STREAM_READY_OFFSET   DP_HDCP_2_2_REG_MPRIME_OFFSET
 +
 +#define HDCP_2_2_DP_RXSTATUS_LEN              1
 +#define HDCP_2_2_DP_RXSTATUS_READY(x)         ((x) & BIT(0))
 +#define HDCP_2_2_DP_RXSTATUS_H_PRIME(x)               ((x) & BIT(1))
 +#define HDCP_2_2_DP_RXSTATUS_PAIRING(x)               ((x) & BIT(2))
 +#define HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(x)    ((x) & BIT(3))
 +#define HDCP_2_2_DP_RXSTATUS_LINK_FAILED(x)   ((x) & BIT(4))
 +
  /* DP 1.2 Sideband message defines */
  /* peer device type - DP 1.2a Table 2-92 */
  #define DP_PEER_DEVICE_NONE           0x0
@@@ -1019,7 -965,6 +1021,7 @@@ u8 drm_dp_get_adjust_request_pre_emphas
  
  #define DP_BRANCH_OUI_HEADER_SIZE     0xc
  #define DP_RECEIVER_CAP_SIZE          0xf
 +#define DP_DSC_RECEIVER_CAP_SIZE        0xf
  #define EDP_PSR_RECEIVER_CAP_SIZE     2
  #define EDP_DISPLAY_CTL_CAP_SIZE      3
  
@@@ -1050,7 -995,6 +1052,7 @@@ struct dp_sdp_header 
  
  #define EDP_SDP_HEADER_REVISION_MASK          0x1F
  #define EDP_SDP_HEADER_VALID_PAYLOAD_BYTES    0x1F
 +#define DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 0x7F
  
  struct edp_vsc_psr {
        struct dp_sdp_header sdp_header;
@@@ -1117,43 -1061,6 +1119,43 @@@ drm_dp_is_branch(const u8 dpcd[DP_RECEI
        return dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT;
  }
  
 +/* DP/eDP DSC support */
 +u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE],
 +                                 bool is_edp);
 +u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]);
 +u8 drm_dp_dsc_sink_max_color_depth(const u8 dsc_dpc[DP_DSC_RECEIVER_CAP_SIZE]);
 +
 +static inline bool
 +drm_dp_sink_supports_dsc(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
 +{
 +      return dsc_dpcd[DP_DSC_SUPPORT - DP_DSC_SUPPORT] &
 +              DP_DSC_DECOMPRESSION_IS_SUPPORTED;
 +}
 +
 +static inline u16
 +drm_edp_dsc_sink_output_bpp(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
 +{
 +      return dsc_dpcd[DP_DSC_MAX_BITS_PER_PIXEL_LOW - DP_DSC_SUPPORT] |
 +              (dsc_dpcd[DP_DSC_MAX_BITS_PER_PIXEL_HI - DP_DSC_SUPPORT] &
 +               DP_DSC_MAX_BITS_PER_PIXEL_HI_MASK <<
 +               DP_DSC_MAX_BITS_PER_PIXEL_HI_SHIFT);
 +}
 +
 +static inline u32
 +drm_dp_dsc_sink_max_slice_width(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
 +{
 +      /* Max Slicewidth = Number of Pixels * 320 */
 +      return dsc_dpcd[DP_DSC_MAX_SLICE_WIDTH - DP_DSC_SUPPORT] *
 +              DP_DSC_SLICE_WIDTH_MULTIPLIER;
 +}
 +
 +/* Forward Error Correction Support on DP 1.4 */
 +static inline bool
 +drm_dp_sink_supports_fec(const u8 fec_capable)
 +{
 +      return fec_capable & DP_FEC_CAPABLE;
 +}
 +
  /*
   * DisplayPort AUX channel
   */
diff --combined include/linux/swap.h
index 6c95df96c9aa288902fe57545d58ecd4ccb79cb1,d8a07a4f171dbfe21ee0e288d98658f304308735..a8f6d5d89524d3163a0c8f1dc835259f8d1dea51
@@@ -18,8 -18,6 +18,8 @@@ struct notifier_block
  
  struct bio;
  
 +struct pagevec;
 +
  #define SWAP_FLAG_PREFER      0x8000  /* set if swap priority specified */
  #define SWAP_FLAG_PRIO_MASK   0x7fff
  #define SWAP_FLAG_PRIO_SHIFT  0
@@@ -169,13 -167,14 +169,14 @@@ enum 
        SWP_SOLIDSTATE  = (1 << 4),     /* blkdev seeks are cheap */
        SWP_CONTINUED   = (1 << 5),     /* swap_map has count continuation */
        SWP_BLKDEV      = (1 << 6),     /* its a block device */
-       SWP_FILE        = (1 << 7),     /* set after swap_activate success */
-       SWP_AREA_DISCARD = (1 << 8),    /* single-time swap area discards */
-       SWP_PAGE_DISCARD = (1 << 9),    /* freed swap page-cluster discards */
-       SWP_STABLE_WRITES = (1 << 10),  /* no overwrite PG_writeback pages */
-       SWP_SYNCHRONOUS_IO = (1 << 11), /* synchronous IO is efficient */
+       SWP_ACTIVATED   = (1 << 7),     /* set after swap_activate success */
+       SWP_FS          = (1 << 8),     /* swap file goes through fs */
+       SWP_AREA_DISCARD = (1 << 9),    /* single-time swap area discards */
+       SWP_PAGE_DISCARD = (1 << 10),   /* freed swap page-cluster discards */
+       SWP_STABLE_WRITES = (1 << 11),  /* no overwrite PG_writeback pages */
+       SWP_SYNCHRONOUS_IO = (1 << 12), /* synchronous IO is efficient */
                                        /* add others here before... */
-       SWP_SCANNING    = (1 << 12),    /* refcount in scan_swap_map */
+       SWP_SCANNING    = (1 << 13),    /* refcount in scan_swap_map */
  };
  
  #define SWAP_CLUSTER_MAX 32UL
@@@ -298,20 -297,15 +299,15 @@@ struct vma_swap_readahead 
  
  /* linux/mm/workingset.c */
  void *workingset_eviction(struct address_space *mapping, struct page *page);
bool workingset_refault(void *shadow);
void workingset_refault(struct page *page, void *shadow);
  void workingset_activation(struct page *page);
  
- /* Do not use directly, use workingset_lookup_update */
- void workingset_update_node(struct radix_tree_node *node);
- /* Returns workingset_update_node() if the mapping has shadow entries. */
- #define workingset_lookup_update(mapping)                             \
- ({                                                                    \
-       radix_tree_update_node_t __helper = workingset_update_node;     \
-       if (dax_mapping(mapping) || shmem_mapping(mapping))             \
-               __helper = NULL;                                        \
-       __helper;                                                       \
- })
+ /* Only track the nodes of mappings with shadow entries */
+ void workingset_update_node(struct xa_node *node);
+ #define mapping_set_update(xas, mapping) do {                         \
+       if (!dax_mapping(mapping) && !shmem_mapping(mapping))           \
+               xas_set_update(xas, workingset_update_node);            \
+ } while (0)
  
  /* linux/mm/page_alloc.c */
  extern unsigned long totalram_pages;
@@@ -375,7 -369,7 +371,7 @@@ static inline int node_reclaim(struct p
  #endif
  
  extern int page_evictable(struct page *page);
 -extern void check_move_unevictable_pages(struct page **, int nr_pages);
 +extern void check_move_unevictable_pages(struct pagevec *pvec);
  
  extern int kswapd_run(int nid);
  extern void kswapd_stop(int nid);
@@@ -410,7 -404,7 +406,7 @@@ extern void show_swap_cache_info(void)
  extern int add_to_swap(struct page *page);
  extern int add_to_swap_cache(struct page *, swp_entry_t, gfp_t);
  extern int __add_to_swap_cache(struct page *page, swp_entry_t entry);
- extern void __delete_from_swap_cache(struct page *);
+ extern void __delete_from_swap_cache(struct page *, swp_entry_t entry);
  extern void delete_from_swap_cache(struct page *);
  extern void free_page_and_swap_cache(struct page *);
  extern void free_pages_and_swap_cache(struct page **, int);
@@@ -564,7 -558,8 +560,8 @@@ static inline int add_to_swap_cache(str
        return -1;
  }
  
- static inline void __delete_from_swap_cache(struct page *page)
+ static inline void __delete_from_swap_cache(struct page *page,
+                                                       swp_entry_t entry)
  {
  }
  
diff --combined mm/shmem.c
index 0c3b005a59eb4b28dce083bd88eb503d13b9216a,d44991ea5ed4b7612482525ebaa502457cbf1ead..0e10b06fc7d62eacf4263918850c2a8ade99cd2a
@@@ -322,24 -322,20 +322,20 @@@ void shmem_uncharge(struct inode *inode
  }
  
  /*
-  * Replace item expected in radix tree by a new item, while holding tree lock.
+  * Replace item expected in xarray by a new item, while holding xa_lock.
   */
- static int shmem_radix_tree_replace(struct address_space *mapping,
+ static int shmem_replace_entry(struct address_space *mapping,
                        pgoff_t index, void *expected, void *replacement)
  {
-       struct radix_tree_node *node;
-       void __rcu **pslot;
+       XA_STATE(xas, &mapping->i_pages, index);
        void *item;
  
        VM_BUG_ON(!expected);
        VM_BUG_ON(!replacement);
-       item = __radix_tree_lookup(&mapping->i_pages, index, &node, &pslot);
-       if (!item)
-               return -ENOENT;
+       item = xas_load(&xas);
        if (item != expected)
                return -ENOENT;
-       __radix_tree_replace(&mapping->i_pages, node, pslot,
-                            replacement, NULL);
+       xas_store(&xas, replacement);
        return 0;
  }
  
  static bool shmem_confirm_swap(struct address_space *mapping,
                               pgoff_t index, swp_entry_t swap)
  {
-       void *item;
-       rcu_read_lock();
-       item = radix_tree_lookup(&mapping->i_pages, index);
-       rcu_read_unlock();
-       return item == swp_to_radix_entry(swap);
+       return xa_load(&mapping->i_pages, index) == swp_to_radix_entry(swap);
  }
  
  /*
@@@ -586,9 -577,11 +577,11 @@@ static inline bool is_huge_enabled(stru
   */
  static int shmem_add_to_page_cache(struct page *page,
                                   struct address_space *mapping,
-                                  pgoff_t index, void *expected)
+                                  pgoff_t index, void *expected, gfp_t gfp)
  {
-       int error, nr = hpage_nr_pages(page);
+       XA_STATE_ORDER(xas, &mapping->i_pages, index, compound_order(page));
+       unsigned long i = 0;
+       unsigned long nr = 1UL << compound_order(page);
  
        VM_BUG_ON_PAGE(PageTail(page), page);
        VM_BUG_ON_PAGE(index != round_down(index, nr), page);
        page->mapping = mapping;
        page->index = index;
  
-       xa_lock_irq(&mapping->i_pages);
-       if (PageTransHuge(page)) {
-               void __rcu **results;
-               pgoff_t idx;
-               int i;
-               error = 0;
-               if (radix_tree_gang_lookup_slot(&mapping->i_pages,
-                                       &results, &idx, index, 1) &&
-                               idx < index + HPAGE_PMD_NR) {
-                       error = -EEXIST;
+       do {
+               void *entry;
+               xas_lock_irq(&xas);
+               entry = xas_find_conflict(&xas);
+               if (entry != expected)
+                       xas_set_err(&xas, -EEXIST);
+               xas_create_range(&xas);
+               if (xas_error(&xas))
+                       goto unlock;
+ next:
+               xas_store(&xas, page + i);
+               if (++i < nr) {
+                       xas_next(&xas);
+                       goto next;
                }
-               if (!error) {
-                       for (i = 0; i < HPAGE_PMD_NR; i++) {
-                               error = radix_tree_insert(&mapping->i_pages,
-                                               index + i, page + i);
-                               VM_BUG_ON(error);
-                       }
+               if (PageTransHuge(page)) {
                        count_vm_event(THP_FILE_ALLOC);
+                       __inc_node_page_state(page, NR_SHMEM_THPS);
                }
-       } else if (!expected) {
-               error = radix_tree_insert(&mapping->i_pages, index, page);
-       } else {
-               error = shmem_radix_tree_replace(mapping, index, expected,
-                                                                page);
-       }
-       if (!error) {
                mapping->nrpages += nr;
-               if (PageTransHuge(page))
-                       __inc_node_page_state(page, NR_SHMEM_THPS);
                __mod_node_page_state(page_pgdat(page), NR_FILE_PAGES, nr);
                __mod_node_page_state(page_pgdat(page), NR_SHMEM, nr);
-               xa_unlock_irq(&mapping->i_pages);
-       } else {
+ unlock:
+               xas_unlock_irq(&xas);
+       } while (xas_nomem(&xas, gfp));
+       if (xas_error(&xas)) {
                page->mapping = NULL;
-               xa_unlock_irq(&mapping->i_pages);
                page_ref_sub(page, nr);
+               return xas_error(&xas);
        }
-       return error;
+       return 0;
  }
  
  /*
@@@ -654,7 -639,7 +639,7 @@@ static void shmem_delete_from_page_cach
        VM_BUG_ON_PAGE(PageCompound(page), page);
  
        xa_lock_irq(&mapping->i_pages);
-       error = shmem_radix_tree_replace(mapping, page->index, page, radswap);
+       error = shmem_replace_entry(mapping, page->index, page, radswap);
        page->mapping = NULL;
        mapping->nrpages--;
        __dec_node_page_state(page, NR_FILE_PAGES);
  }
  
  /*
-  * Remove swap entry from radix tree, free the swap and its page cache.
+  * Remove swap entry from page cache, free the swap and its page cache.
   */
  static int shmem_free_swap(struct address_space *mapping,
                           pgoff_t index, void *radswap)
        void *old;
  
        xa_lock_irq(&mapping->i_pages);
-       old = radix_tree_delete_item(&mapping->i_pages, index, radswap);
+       old = __xa_cmpxchg(&mapping->i_pages, index, radswap, NULL, 0);
        xa_unlock_irq(&mapping->i_pages);
        if (old != radswap)
                return -ENOENT;
  unsigned long shmem_partial_swap_usage(struct address_space *mapping,
                                                pgoff_t start, pgoff_t end)
  {
-       struct radix_tree_iter iter;
-       void __rcu **slot;
+       XA_STATE(xas, &mapping->i_pages, start);
        struct page *page;
        unsigned long swapped = 0;
  
        rcu_read_lock();
-       radix_tree_for_each_slot(slot, &mapping->i_pages, &iter, start) {
-               if (iter.index >= end)
-                       break;
-               page = radix_tree_deref_slot(slot);
-               if (radix_tree_deref_retry(page)) {
-                       slot = radix_tree_iter_retry(&iter);
+       xas_for_each(&xas, page, end - 1) {
+               if (xas_retry(&xas, page))
                        continue;
-               }
-               if (radix_tree_exceptional_entry(page))
+               if (xa_is_value(page))
                        swapped++;
  
                if (need_resched()) {
-                       slot = radix_tree_iter_resume(slot, &iter);
+                       xas_pause(&xas);
                        cond_resched_rcu();
                }
        }
@@@ -781,14 -756,14 +756,14 @@@ void shmem_unlock_mapping(struct addres
                        break;
                index = indices[pvec.nr - 1] + 1;
                pagevec_remove_exceptionals(&pvec);
 -              check_move_unevictable_pages(pvec.pages, pvec.nr);
 +              check_move_unevictable_pages(&pvec);
                pagevec_release(&pvec);
                cond_resched();
        }
  }
  
  /*
-  * Remove range of pages and swap entries from radix tree, and free them.
+  * Remove range of pages and swap entries from page cache, and free them.
   * If !unfalloc, truncate or punch hole; if unfalloc, undo failed fallocate.
   */
  static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
                        if (index >= end)
                                break;
  
-                       if (radix_tree_exceptional_entry(page)) {
+                       if (xa_is_value(page)) {
                                if (unfalloc)
                                        continue;
                                nr_swaps_freed += !shmem_free_swap(mapping,
                        if (index >= end)
                                break;
  
-                       if (radix_tree_exceptional_entry(page)) {
+                       if (xa_is_value(page)) {
                                if (unfalloc)
                                        continue;
                                if (shmem_free_swap(mapping, index, page)) {
@@@ -1110,34 -1085,27 +1085,27 @@@ static void shmem_evict_inode(struct in
        clear_inode(inode);
  }
  
- static unsigned long find_swap_entry(struct radix_tree_root *root, void *item)
+ static unsigned long find_swap_entry(struct xarray *xa, void *item)
  {
-       struct radix_tree_iter iter;
-       void __rcu **slot;
-       unsigned long found = -1;
+       XA_STATE(xas, xa, 0);
        unsigned int checked = 0;
+       void *entry;
  
        rcu_read_lock();
-       radix_tree_for_each_slot(slot, root, &iter, 0) {
-               void *entry = radix_tree_deref_slot(slot);
-               if (radix_tree_deref_retry(entry)) {
-                       slot = radix_tree_iter_retry(&iter);
+       xas_for_each(&xas, entry, ULONG_MAX) {
+               if (xas_retry(&xas, entry))
                        continue;
-               }
-               if (entry == item) {
-                       found = iter.index;
+               if (entry == item)
                        break;
-               }
                checked++;
-               if ((checked % 4096) != 0)
+               if ((checked % XA_CHECK_SCHED) != 0)
                        continue;
-               slot = radix_tree_iter_resume(slot, &iter);
+               xas_pause(&xas);
                cond_resched_rcu();
        }
        rcu_read_unlock();
-       return found;
+       return entry ? xas.xa_index : -1;
  }
  
  /*
@@@ -1175,10 -1143,10 +1143,10 @@@ static int shmem_unuse_inode(struct shm
                 * We needed to drop mutex to make that restrictive page
                 * allocation, but the inode might have been freed while we
                 * dropped it: although a racing shmem_evict_inode() cannot
-                * complete without emptying the radix_tree, our page lock
+                * complete without emptying the page cache, our page lock
                 * on this swapcache page is not enough to prevent that -
                 * free_swap_and_cache() of our swap entry will only
-                * trylock_page(), removing swap from radix_tree whatever.
+                * trylock_page(), removing swap from page cache whatever.
                 *
                 * We must not proceed to shmem_add_to_page_cache() if the
                 * inode has been freed, but of course we cannot rely on
         */
        if (!error)
                error = shmem_add_to_page_cache(*pagep, mapping, index,
-                                               radswap);
+                                               radswap, gfp);
        if (error != -ENOMEM) {
                /*
                 * Truncation and eviction use free_swap_and_cache(), which
@@@ -1244,7 -1212,7 +1212,7 @@@ int shmem_unuse(swp_entry_t swap, struc
                                            &memcg, false);
        if (error)
                goto out;
-       /* No radix_tree_preload: swap entry keeps a place for page in tree */
+       /* No memory allocation: swap entry occupies the slot for the page */
        error = -EAGAIN;
  
        mutex_lock(&shmem_swaplist_mutex);
@@@ -1453,27 -1421,21 +1421,21 @@@ static struct page *shmem_alloc_hugepag
                struct shmem_inode_info *info, pgoff_t index)
  {
        struct vm_area_struct pvma;
-       struct inode *inode = &info->vfs_inode;
-       struct address_space *mapping = inode->i_mapping;
-       pgoff_t idx, hindex;
-       void __rcu **results;
+       struct address_space *mapping = info->vfs_inode.i_mapping;
+       pgoff_t hindex;
        struct page *page;
  
        if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE))
                return NULL;
  
        hindex = round_down(index, HPAGE_PMD_NR);
-       rcu_read_lock();
-       if (radix_tree_gang_lookup_slot(&mapping->i_pages, &results, &idx,
-                               hindex, 1) && idx < hindex + HPAGE_PMD_NR) {
-               rcu_read_unlock();
+       if (xa_find(&mapping->i_pages, &hindex, hindex + HPAGE_PMD_NR - 1,
+                                                               XA_PRESENT))
                return NULL;
-       }
-       rcu_read_unlock();
  
        shmem_pseudo_vma_init(&pvma, info, hindex);
        page = alloc_pages_vma(gfp | __GFP_COMP | __GFP_NORETRY | __GFP_NOWARN,
-                       HPAGE_PMD_ORDER, &pvma, 0, numa_node_id(), true);
+                       HPAGE_PMD_ORDER, &pvma, 0, numa_node_id());
        shmem_pseudo_vma_destroy(&pvma);
        if (page)
                prep_transhuge_page(page);
@@@ -1578,8 -1540,7 +1540,7 @@@ static int shmem_replace_page(struct pa
         * a nice clean interface for us to replace oldpage by newpage there.
         */
        xa_lock_irq(&swap_mapping->i_pages);
-       error = shmem_radix_tree_replace(swap_mapping, swap_index, oldpage,
-                                                                  newpage);
+       error = shmem_replace_entry(swap_mapping, swap_index, oldpage, newpage);
        if (!error) {
                __inc_node_page_state(newpage, NR_FILE_PAGES);
                __dec_node_page_state(oldpage, NR_FILE_PAGES);
@@@ -1643,7 -1604,7 +1604,7 @@@ static int shmem_getpage_gfp(struct ino
  repeat:
        swap.val = 0;
        page = find_lock_entry(mapping, index);
-       if (radix_tree_exceptional_entry(page)) {
+       if (xa_is_value(page)) {
                swap = radix_to_swp_entry(page);
                page = NULL;
        }
                                false);
                if (!error) {
                        error = shmem_add_to_page_cache(page, mapping, index,
-                                               swp_to_radix_entry(swap));
+                                               swp_to_radix_entry(swap), gfp);
                        /*
                         * We already confirmed swap under page lock, and make
                         * no memory allocation here, so usually no possibility
@@@ -1824,13 -1785,8 +1785,8 @@@ alloc_nohuge:          page = shmem_alloc_and_a
                                PageTransHuge(page));
                if (error)
                        goto unacct;
-               error = radix_tree_maybe_preload_order(gfp & GFP_RECLAIM_MASK,
-                               compound_order(page));
-               if (!error) {
-                       error = shmem_add_to_page_cache(page, mapping, hindex,
-                                                       NULL);
-                       radix_tree_preload_end();
-               }
+               error = shmem_add_to_page_cache(page, mapping, hindex,
+                                               NULL, gfp & GFP_RECLAIM_MASK);
                if (error) {
                        mem_cgroup_cancel_charge(page, memcg,
                                        PageTransHuge(page));
@@@ -1931,7 -1887,7 +1887,7 @@@ unlock
                spin_unlock_irq(&info->lock);
                goto repeat;
        }
-       if (error == -EEXIST)   /* from above or from radix_tree_insert */
+       if (error == -EEXIST)
                goto repeat;
        return error;
  }
@@@ -2299,11 -2255,8 +2255,8 @@@ static int shmem_mfill_atomic_pte(struc
        if (ret)
                goto out_release;
  
-       ret = radix_tree_maybe_preload(gfp & GFP_RECLAIM_MASK);
-       if (!ret) {
-               ret = shmem_add_to_page_cache(page, mapping, pgoff, NULL);
-               radix_tree_preload_end();
-       }
+       ret = shmem_add_to_page_cache(page, mapping, pgoff, NULL,
+                                               gfp & GFP_RECLAIM_MASK);
        if (ret)
                goto out_release_uncharge;
  
@@@ -2548,7 -2501,7 +2501,7 @@@ static ssize_t shmem_file_read_iter(str
  }
  
  /*
-  * llseek SEEK_DATA or SEEK_HOLE through the radix_tree.
+  * llseek SEEK_DATA or SEEK_HOLE through the page cache.
   */
  static pgoff_t shmem_seek_hole_data(struct address_space *mapping,
                                    pgoff_t index, pgoff_t end, int whence)
                                index = indices[i];
                        }
                        page = pvec.pages[i];
-                       if (page && !radix_tree_exceptional_entry(page)) {
+                       if (page && !xa_is_value(page)) {
                                if (!PageUptodate(page))
                                        page = NULL;
                        }
@@@ -2610,9 -2563,7 +2563,7 @@@ static loff_t shmem_file_llseek(struct 
        inode_lock(inode);
        /* We're holding i_mutex so we can access i_size directly */
  
-       if (offset < 0)
-               offset = -EINVAL;
-       else if (offset >= inode->i_size)
+       if (offset < 0 || offset >= inode->i_size)
                offset = -ENXIO;
        else {
                start = offset >> PAGE_SHIFT;
diff --combined mm/vmscan.c
index 0dbc493026a27d4f59b7ca6d83a4c864340f99a1,62ac0c488624fd8fd3d2306b04951466cca1a0df..24ab1f7394abaafa9e0dccac37597ae65ef77e0f
  #include <linux/delayacct.h>
  #include <linux/sysctl.h>
  #include <linux/oom.h>
 +#include <linux/pagevec.h>
  #include <linux/prefetch.h>
  #include <linux/printk.h>
  #include <linux/dax.h>
+ #include <linux/psi.h>
  
  #include <asm/tlbflush.h>
  #include <asm/div64.h>
@@@ -474,9 -474,18 +475,18 @@@ static unsigned long do_shrink_slab(str
        nr = atomic_long_xchg(&shrinker->nr_deferred[nid], 0);
  
        total_scan = nr;
-       delta = freeable >> priority;
-       delta *= 4;
-       do_div(delta, shrinker->seeks);
+       if (shrinker->seeks) {
+               delta = freeable >> priority;
+               delta *= 4;
+               do_div(delta, shrinker->seeks);
+       } else {
+               /*
+                * These objects don't require any IO to create. Trim
+                * them aggressively under memory pressure to keep
+                * them from causing refetches in the IO caches.
+                */
+               delta = freeable / 2;
+       }
  
        /*
         * Make sure we apply some minimal pressure on default priority
@@@ -581,8 -590,8 +591,8 @@@ static unsigned long shrink_slab_memcg(
                        struct mem_cgroup *memcg, int priority)
  {
        struct memcg_shrinker_map *map;
-       unsigned long freed = 0;
-       int ret, i;
+       unsigned long ret, freed = 0;
+       int i;
  
        if (!memcg_kmem_enabled() || !mem_cgroup_online(memcg))
                return 0;
@@@ -678,9 -687,8 +688,8 @@@ static unsigned long shrink_slab(gfp_t 
                                 struct mem_cgroup *memcg,
                                 int priority)
  {
+       unsigned long ret, freed = 0;
        struct shrinker *shrinker;
-       unsigned long freed = 0;
-       int ret;
  
        if (!mem_cgroup_is_root(memcg))
                return shrink_slab_memcg(gfp_mask, nid, memcg, priority);
@@@ -743,12 -751,12 +752,12 @@@ static inline int is_page_cache_freeabl
  {
        /*
         * A freeable page cache page is referenced only by the caller
-        * that isolated the page, the page cache radix tree and
-        * optional buffer heads at page->private.
+        * that isolated the page, the page cache and optional buffer
+        * heads at page->private.
         */
-       int radix_pins = PageTransHuge(page) && PageSwapCache(page) ?
+       int page_cache_pins = PageTransHuge(page) && PageSwapCache(page) ?
                HPAGE_PMD_NR : 1;
-       return page_count(page) - page_has_private(page) == 1 + radix_pins;
+       return page_count(page) - page_has_private(page) == 1 + page_cache_pins;
  }
  
  static int may_write_to_inode(struct inode *inode, struct scan_control *sc)
@@@ -924,7 -932,7 +933,7 @@@ static int __remove_mapping(struct addr
        if (PageSwapCache(page)) {
                swp_entry_t swap = { .val = page_private(page) };
                mem_cgroup_swapout(page, swap);
-               __delete_from_swap_cache(page);
+               __delete_from_swap_cache(page, swap);
                xa_unlock_irqrestore(&mapping->i_pages, flags);
                put_swap_page(page, swap);
        } else {
@@@ -2147,6 -2155,7 +2156,7 @@@ static void shrink_active_list(unsigne
                }
  
                ClearPageActive(page);  /* we are de-activating */
+               SetPageWorkingset(page);
                list_add(&page->lru, &l_inactive);
        }
  
                        /*
                         * Scan types proportional to swappiness and
                         * their relative recent reclaim efficiency.
+                        * Make sure we don't miss the last page
+                        * because of a round-off error.
                         */
-                       scan = div64_u64(scan * fraction[file],
-                                        denominator);
+                       scan = DIV64_U64_ROUND_UP(scan * fraction[file],
+                                                 denominator);
                        break;
                case SCAN_FILE:
                case SCAN_ANON:
@@@ -3304,6 -3315,7 +3316,7 @@@ unsigned long try_to_free_mem_cgroup_pa
  {
        struct zonelist *zonelist;
        unsigned long nr_reclaimed;
+       unsigned long pflags;
        int nid;
        unsigned int noreclaim_flag;
        struct scan_control sc = {
                                            sc.gfp_mask,
                                            sc.reclaim_idx);
  
+       psi_memstall_enter(&pflags);
        noreclaim_flag = memalloc_noreclaim_save();
        nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
        memalloc_noreclaim_restore(noreclaim_flag);
+       psi_memstall_leave(&pflags);
  
        trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
  
@@@ -3499,6 -3515,7 +3516,7 @@@ static int balance_pgdat(pg_data_t *pgd
        int i;
        unsigned long nr_soft_reclaimed;
        unsigned long nr_soft_scanned;
+       unsigned long pflags;
        struct zone *zone;
        struct scan_control sc = {
                .gfp_mask = GFP_KERNEL,
                .may_swap = 1,
        };
  
+       psi_memstall_enter(&pflags);
        __fs_reclaim_acquire();
  
        count_vm_event(PAGEOUTRUN);
  out:
        snapshot_refaults(NULL, pgdat);
        __fs_reclaim_release();
+       psi_memstall_leave(&pflags);
        /*
         * Return the order kswapd stopped reclaiming at as
         * prepare_kswapd_sleep() takes it into account. If another caller
@@@ -4163,16 -4182,17 +4183,16 @@@ int page_evictable(struct page *page
        return ret;
  }
  
 -#ifdef CONFIG_SHMEM
  /**
 - * check_move_unevictable_pages - check pages for evictability and move to appropriate zone lru list
 - * @pages:    array of pages to check
 - * @nr_pages: number of pages to check
 + * check_move_unevictable_pages - check pages for evictability and move to
 + * appropriate zone lru list
 + * @pvec: pagevec with lru pages to check
   *
 - * Checks pages for evictability and moves them to the appropriate lru list.
 - *
 - * This function is only used for SysV IPC SHM_UNLOCK.
 + * Checks pages for evictability, if an evictable page is in the unevictable
 + * lru list, moves it to the appropriate evictable lru list. This function
 + * should be only used for lru pages.
   */
 -void check_move_unevictable_pages(struct page **pages, int nr_pages)
 +void check_move_unevictable_pages(struct pagevec *pvec)
  {
        struct lruvec *lruvec;
        struct pglist_data *pgdat = NULL;
        int pgrescued = 0;
        int i;
  
 -      for (i = 0; i < nr_pages; i++) {
 -              struct page *page = pages[i];
 +      for (i = 0; i < pvec->nr; i++) {
 +              struct page *page = pvec->pages[i];
                struct pglist_data *pagepgdat = page_pgdat(page);
  
                pgscanned++;
                spin_unlock_irq(&pgdat->lru_lock);
        }
  }
 -#endif /* CONFIG_SHMEM */
 +EXPORT_SYMBOL_GPL(check_move_unevictable_pages);
index 202bf16f85fd4dd63a210dbe67d69d5a0cecfae9,83d76c345940557f25a6e2b08150bacbd3dc404f..00c92eb854ce7b65daedc7c3fa98f69f9b891d86
@@@ -30,7 -30,6 +30,6 @@@
  #include <linux/pm_runtime.h>
  #include <linux/dma-mapping.h>
  #include <linux/delay.h>
- #include <asm/set_memory.h>
  #include <sound/core.h>
  #include <sound/asoundef.h>
  #include <sound/pcm.h>
@@@ -1141,8 -1140,7 +1140,7 @@@ static int had_pcm_hw_params(struct snd
                             struct snd_pcm_hw_params *hw_params)
  {
        struct snd_intelhad *intelhaddata;
-       unsigned long addr;
-       int pages, buf_size, retval;
+       int buf_size, retval;
  
        intelhaddata = snd_pcm_substream_chip(substream);
        buf_size = params_buffer_bytes(hw_params);
                return retval;
        dev_dbg(intelhaddata->dev, "%s:allocated memory = %d\n",
                __func__, buf_size);
-       /* mark the pages as uncached region */
-       addr = (unsigned long) substream->runtime->dma_area;
-       pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
-       retval = set_memory_uc(addr, pages);
-       if (retval) {
-               dev_err(intelhaddata->dev, "set_memory_uc failed.Error:%d\n",
-                       retval);
-               return retval;
-       }
-       memset(substream->runtime->dma_area, 0, buf_size);
        return retval;
  }
  
  static int had_pcm_hw_free(struct snd_pcm_substream *substream)
  {
        struct snd_intelhad *intelhaddata;
-       unsigned long addr;
-       u32 pages;
  
        intelhaddata = snd_pcm_substream_chip(substream);
        had_do_reset(intelhaddata);
  
-       /* mark back the pages as cached/writeback region before the free */
-       if (substream->runtime->dma_area != NULL) {
-               addr = (unsigned long) substream->runtime->dma_area;
-               pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) /
-                                                               PAGE_SIZE;
-               set_memory_wb(addr, pages);
-               return snd_pcm_lib_free_pages(substream);
-       }
-       return 0;
+       return snd_pcm_lib_free_pages(substream);
  }
  
  /*
@@@ -1671,7 -1648,7 +1648,7 @@@ static int had_create_jack(struct snd_i
   * PM callbacks
   */
  
 -static int hdmi_lpe_audio_runtime_suspend(struct device *dev)
 +static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev)
  {
        struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev);
        int port;
                }
        }
  
 -      return 0;
 -}
 -
 -static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev)
 -{
 -      struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev);
 -      int err;
 +      snd_power_change_state(card_ctx->card, SNDRV_CTL_POWER_D3hot);
  
 -      err = hdmi_lpe_audio_runtime_suspend(dev);
 -      if (!err)
 -              snd_power_change_state(card_ctx->card, SNDRV_CTL_POWER_D3hot);
 -      return err;
 -}
 -
 -static int hdmi_lpe_audio_runtime_resume(struct device *dev)
 -{
 -      pm_runtime_mark_last_busy(dev);
        return 0;
  }
  
@@@ -1696,10 -1688,8 +1673,10 @@@ static int __maybe_unused hdmi_lpe_audi
  {
        struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev);
  
 -      hdmi_lpe_audio_runtime_resume(dev);
 +      pm_runtime_mark_last_busy(dev);
 +
        snd_power_change_state(card_ctx->card, SNDRV_CTL_POWER_D0);
 +
        return 0;
  }
  
@@@ -1847,7 -1837,7 +1824,7 @@@ static int hdmi_lpe_audio_probe(struct 
                 * try to allocate 600k buffer as default which is large enough
                 */
                snd_pcm_lib_preallocate_pages_for_all(pcm,
-                                                     SNDRV_DMA_TYPE_DEV, NULL,
+                                                     SNDRV_DMA_TYPE_DEV_UC, NULL,
                                                      HAD_DEFAULT_BUFFER, HAD_MAX_BUFFER);
  
                /* create controls */
  
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_mark_last_busy(&pdev->dev);
 -      pm_runtime_set_active(&pdev->dev);
  
        dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__);
        for_each_port(card_ctx, port) {
@@@ -1917,6 -1908,8 +1894,6 @@@ static int hdmi_lpe_audio_remove(struc
  
  static const struct dev_pm_ops hdmi_lpe_audio_pm = {
        SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume)
 -      SET_RUNTIME_PM_OPS(hdmi_lpe_audio_runtime_suspend,
 -                         hdmi_lpe_audio_runtime_resume, NULL)
  };
  
  static struct platform_driver hdmi_lpe_audio_driver = {
This page took 0.234805 seconds and 4 git commands to generate.