diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-07-17 10:40:39 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-07-17 10:41:02 +1000 |
| commit | 2e33bfe53cba8558eb83f3fd327d0a5e21172baa (patch) | |
| tree | 3db3d70d73a6f39d4fbef9482989954a8e4bd696 | |
| parent | 295a8c0b0e44760ef7e06c55beacbe0caafe1ce7 (diff) | |
| parent | ec6444a00c49e6c2b5e9a507272a28126677f9ee (diff) | |
Merge tag 'drm-misc-next-2026-07-16' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for 7.3:
UAPI Changes:
Cross-subsystem Changes:
Core Changes:
- blend: allow blend mode property without PREMULTI
- bridges:
- Rename drm_for_each_bridge_in_chain_scoped to
drm_for_each_bridge_in_chain
- Drop legacy bridges support
- gpusvm: Code reorganization to give drivers more flexibility
Driver Changes:
- etnaviv: Check if a reset has been successful
- nouveau: Create instmem iomapping at first use
- panthor: Remove redundant cleanup
- qxl: Convert to a simple encoder to a regular one
- bridges:
- Convert all remaining legacy bridges to atomic
- tc358767: clamp the reported AUX read size to the request
- panels:
- novatek-nt37801: Use mipi_dsi_*_multi() functions
- samsung-s6d16d0: Fix prepare error handling
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maxime Ripard <mripard@redhat.com>
Link: https://patch.msgid.link/20260716-famous-pastel-ostrich-a1aaef@houat
63 files changed, 728 insertions, 618 deletions
diff --git a/.clang-format b/.clang-format index 6a3de86ab27a..5ef5743b77c9 100644 --- a/.clang-format +++ b/.clang-format @@ -167,7 +167,7 @@ ForEachMacros: - 'drm_connector_for_each_possible_encoder' - 'drm_exec_for_each_locked_object' - 'drm_exec_for_each_locked_object_reverse' - - 'drm_for_each_bridge_in_chain_scoped' + - 'drm_for_each_bridge_in_chain' - 'drm_for_each_connector_iter' - 'drm_for_each_crtc' - 'drm_for_each_crtc_reverse' diff --git a/drivers/gpu/drm/adp/adp-mipi.c b/drivers/gpu/drm/adp/adp-mipi.c index cba7d32150a9..232bb9539423 100644 --- a/drivers/gpu/drm/adp/adp-mipi.c +++ b/drivers/gpu/drm/adp/adp-mipi.c @@ -5,6 +5,7 @@ #include <linux/of.h> #include <linux/platform_device.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_mipi_dsi.h> @@ -222,6 +223,9 @@ static int adp_dsi_bridge_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs adp_dsi_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = adp_dsi_bridge_attach, }; diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index f3fe47b12edc..eba5c6dcb5ad 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -566,7 +566,8 @@ anx6345_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void anx6345_bridge_disable(struct drm_bridge *bridge) +static void anx6345_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct anx6345 *anx6345 = bridge_to_anx6345(bridge); @@ -580,7 +581,8 @@ static void anx6345_bridge_disable(struct drm_bridge *bridge) anx6345_poweroff(anx6345); } -static void anx6345_bridge_enable(struct drm_bridge *bridge) +static void anx6345_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct anx6345 *anx6345 = bridge_to_anx6345(bridge); int err; @@ -600,11 +602,14 @@ static void anx6345_bridge_enable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs anx6345_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = anx6345_bridge_attach, .detach = anx6345_bridge_detach, .mode_valid = anx6345_bridge_mode_valid, - .disable = anx6345_bridge_disable, - .enable = anx6345_bridge_enable, + .atomic_disable = anx6345_bridge_disable, + .atomic_enable = anx6345_bridge_enable, }; static void unregister_i2c_dummy_clients(struct anx6345 *anx6345) diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index ba0fc149a9e7..32186efa6f50 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -937,7 +937,8 @@ anx78xx_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void anx78xx_bridge_disable(struct drm_bridge *bridge) +static void anx78xx_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct anx78xx *anx78xx = bridge_to_anx78xx(bridge); @@ -975,7 +976,8 @@ unlock: mutex_unlock(&anx78xx->lock); } -static void anx78xx_bridge_enable(struct drm_bridge *bridge) +static void anx78xx_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct anx78xx *anx78xx = bridge_to_anx78xx(bridge); int err; @@ -992,12 +994,15 @@ static void anx78xx_bridge_enable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs anx78xx_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = anx78xx_bridge_attach, .detach = anx78xx_bridge_detach, .mode_valid = anx78xx_bridge_mode_valid, - .disable = anx78xx_bridge_disable, + .atomic_disable = anx78xx_bridge_disable, .mode_set = anx78xx_bridge_mode_set, - .enable = anx78xx_bridge_enable, + .atomic_enable = anx78xx_bridge_enable, }; static irqreturn_t anx78xx_hpd_threaded_handler(int irq, void *data) diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c index 1ed21a8713bf..169939d23310 100644 --- a/drivers/gpu/drm/bridge/aux-bridge.c +++ b/drivers/gpu/drm/bridge/aux-bridge.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/of.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/bridge/aux-bridge.h> @@ -104,6 +105,9 @@ static int drm_aux_bridge_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs drm_aux_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = drm_aux_bridge_attach, }; diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c index f02a38a2638a..a2e525aa5788 100644 --- a/drivers/gpu/drm/bridge/aux-hpd-bridge.c +++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/of.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/bridge/aux-bridge.h> @@ -165,6 +166,9 @@ static int drm_aux_hpd_bridge_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs drm_aux_hpd_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = drm_aux_hpd_bridge_attach, }; diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c index a237c65ebd69..92d464727e41 100644 --- a/drivers/gpu/drm/bridge/chrontel-ch7033.c +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -330,7 +330,8 @@ static enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void ch7033_bridge_disable(struct drm_bridge *bridge) +static void ch7033_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge); @@ -338,7 +339,8 @@ static void ch7033_bridge_disable(struct drm_bridge *bridge) regmap_update_bits(priv->regmap, 0x52, RESETDB, 0x00); } -static void ch7033_bridge_enable(struct drm_bridge *bridge) +static void ch7033_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge); @@ -514,11 +516,14 @@ static void ch7033_bridge_mode_set(struct drm_bridge *bridge, } static const struct drm_bridge_funcs ch7033_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = ch7033_bridge_attach, .detach = ch7033_bridge_detach, .mode_valid = ch7033_bridge_mode_valid, - .disable = ch7033_bridge_disable, - .enable = ch7033_bridge_enable, + .atomic_disable = ch7033_bridge_disable, + .atomic_enable = ch7033_bridge_enable, .mode_set = ch7033_bridge_mode_set, }; diff --git a/drivers/gpu/drm/bridge/cros-ec-anx7688.c b/drivers/gpu/drm/bridge/cros-ec-anx7688.c index a35dae9b56e2..da16c793e3ba 100644 --- a/drivers/gpu/drm/bridge/cros-ec-anx7688.c +++ b/drivers/gpu/drm/bridge/cros-ec-anx7688.c @@ -5,6 +5,7 @@ * Copyright 2020 Google LLC */ +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_print.h> #include <linux/i2c.h> @@ -92,6 +93,9 @@ static bool cros_ec_anx7688_bridge_mode_fixup(struct drm_bridge *bridge, } static const struct drm_bridge_funcs cros_ec_anx7688_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .mode_fixup = cros_ec_anx7688_bridge_mode_fixup, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt8713sx.c b/drivers/gpu/drm/bridge/lontium-lt8713sx.c index cee485adf5e5..4a6420b876da 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8713sx.c +++ b/drivers/gpu/drm/bridge/lontium-lt8713sx.c @@ -18,6 +18,7 @@ #include <linux/wait.h> #include <linux/workqueue.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_of.h> @@ -508,6 +509,9 @@ static const struct attribute_group *lt8713sx_attr_groups[] = { }; static const struct drm_bridge_funcs lt8713sx_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = lt8713sx_bridge_attach, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 729b12b67470..df5d07e7644c 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -457,7 +457,8 @@ static void lt8912_bridge_mode_set(struct drm_bridge *bridge, drm_display_mode_to_videomode(adj, <->mode); } -static void lt8912_bridge_enable(struct drm_bridge *bridge) +static void lt8912_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct lt8912 *lt = bridge_to_lt8912(bridge); @@ -634,11 +635,14 @@ static const struct drm_edid *lt8912_bridge_edid_read(struct drm_bridge *bridge, } static const struct drm_bridge_funcs lt8912_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = lt8912_bridge_attach, .detach = lt8912_bridge_detach, .mode_valid = lt8912_bridge_mode_valid, .mode_set = lt8912_bridge_mode_set, - .enable = lt8912_bridge_enable, + .atomic_enable = lt8912_bridge_enable, .detect = lt8912_bridge_detect, .edid_read = lt8912_bridge_edid_read, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 9427cc2358ae..6625ba23761c 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -465,6 +465,9 @@ static void lt9611uxc_hdmi_audio_shutdown(struct drm_bridge *bridge, } static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = lt9611uxc_bridge_attach, .mode_valid = lt9611uxc_bridge_mode_valid, .mode_set = lt9611uxc_bridge_mode_set, diff --git a/drivers/gpu/drm/bridge/lvds-codec.c b/drivers/gpu/drm/bridge/lvds-codec.c index d1135dc3b99f..a82ea0c944eb 100644 --- a/drivers/gpu/drm/bridge/lvds-codec.c +++ b/drivers/gpu/drm/bridge/lvds-codec.c @@ -43,7 +43,8 @@ static int lvds_codec_attach(struct drm_bridge *bridge, bridge, flags); } -static void lvds_codec_enable(struct drm_bridge *bridge) +static void lvds_codec_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct lvds_codec *lvds_codec = to_lvds_codec(bridge); int ret; @@ -59,7 +60,8 @@ static void lvds_codec_enable(struct drm_bridge *bridge) gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 0); } -static void lvds_codec_disable(struct drm_bridge *bridge) +static void lvds_codec_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct lvds_codec *lvds_codec = to_lvds_codec(bridge); int ret; @@ -100,8 +102,8 @@ lvds_codec_atomic_get_input_bus_fmts(struct drm_bridge *bridge, static const struct drm_bridge_funcs funcs = { .attach = lvds_codec_attach, - .enable = lvds_codec_enable, - .disable = lvds_codec_disable, + .atomic_enable = lvds_codec_enable, + .atomic_disable = lvds_codec_disable, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_create_state = drm_atomic_helper_bridge_create_state, diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index 2d02cc69f237..25ff0a0acc93 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -214,6 +214,9 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = ge_b850v3_lvds_attach, .detect = ge_b850v3_lvds_bridge_detect, .edid_read = ge_b850v3_lvds_edid_read, diff --git a/drivers/gpu/drm/bridge/microchip-lvds.c b/drivers/gpu/drm/bridge/microchip-lvds.c index 5fb8633f43c5..dd4ffc9f4df3 100644 --- a/drivers/gpu/drm/bridge/microchip-lvds.c +++ b/drivers/gpu/drm/bridge/microchip-lvds.c @@ -167,6 +167,9 @@ static void mchp_lvds_atomic_disable(struct drm_bridge *bridge, } static const struct drm_bridge_funcs mchp_lvds_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = mchp_lvds_attach, .atomic_enable = mchp_lvds_atomic_enable, .atomic_disable = mchp_lvds_atomic_disable, diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 7acb11f16dc1..a9b4ac2defc9 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -111,7 +111,8 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) return 0; } -static void ptn3460_pre_enable(struct drm_bridge *bridge) +static void ptn3460_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); int ret; @@ -139,7 +140,8 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge) ptn_bridge->enabled = true; } -static void ptn3460_disable(struct drm_bridge *bridge) +static void ptn3460_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); @@ -163,7 +165,7 @@ static const struct drm_edid *ptn3460_edid_read(struct drm_bridge *bridge, int ret; power_off = !ptn_bridge->enabled; - ptn3460_pre_enable(&ptn_bridge->bridge); + ptn3460_pre_enable(&ptn_bridge->bridge, NULL); edid = kmalloc(EDID_LENGTH, GFP_KERNEL); if (!edid) { @@ -182,7 +184,7 @@ static const struct drm_edid *ptn3460_edid_read(struct drm_bridge *bridge, out: if (power_off) - ptn3460_disable(&ptn_bridge->bridge); + ptn3460_disable(&ptn_bridge->bridge, NULL); return drm_edid; } @@ -248,8 +250,11 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs ptn3460_bridge_funcs = { - .pre_enable = ptn3460_pre_enable, - .disable = ptn3460_disable, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_pre_enable = ptn3460_pre_enable, + .atomic_disable = ptn3460_disable, .attach = ptn3460_bridge_attach, .edid_read = ptn3460_edid_read, }; diff --git a/drivers/gpu/drm/bridge/of-display-mode-bridge.c b/drivers/gpu/drm/bridge/of-display-mode-bridge.c index e66dae168fd0..af3e727e91c9 100644 --- a/drivers/gpu/drm/bridge/of-display-mode-bridge.c +++ b/drivers/gpu/drm/bridge/of-display-mode-bridge.c @@ -9,6 +9,7 @@ #include <linux/export.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_modes.h> #include <drm/drm_probe_helper.h> @@ -52,6 +53,9 @@ static int of_display_mode_bridge_get_modes(struct drm_bridge *bridge, } static const struct drm_bridge_funcs of_display_mode_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = of_display_mode_bridge_attach, .get_modes = of_display_mode_bridge_get_modes, }; diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index f879a1df077d..33844db753aa 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -336,7 +336,8 @@ static const struct backlight_ops ps8622_backlight_ops = { .update_status = ps8622_backlight_update, }; -static void ps8622_pre_enable(struct drm_bridge *bridge) +static void ps8622_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); int ret; @@ -381,13 +382,15 @@ static void ps8622_pre_enable(struct drm_bridge *bridge) ps8622->enabled = true; } -static void ps8622_disable(struct drm_bridge *bridge) +static void ps8622_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { /* Delay after panel is disabled */ msleep(PS8622_PWMO_END_T12_MS); } -static void ps8622_post_disable(struct drm_bridge *bridge) +static void ps8622_post_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); @@ -428,9 +431,12 @@ static int ps8622_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs ps8622_bridge_funcs = { - .pre_enable = ps8622_pre_enable, - .disable = ps8622_disable, - .post_disable = ps8622_post_disable, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_pre_enable = ps8622_pre_enable, + .atomic_disable = ps8622_disable, + .atomic_post_disable = ps8622_post_disable, .attach = ps8622_attach, }; diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 5788066d479e..25ab475309e8 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -1919,7 +1919,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host, /* * of_graph_get_remote_node() produces a noisy error message if port * node isn't found and the absence of the port is a legit case here, - * so at first we silently check whether graph presents in the + * so at first we silently check whether a graph is present in the * device-tree node. */ if (!of_graph_is_present(np)) diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c index bb1bed03eb5b..be67642ab7d3 100644 --- a/drivers/gpu/drm/bridge/sii9234.c +++ b/drivers/gpu/drm/bridge/sii9234.c @@ -13,6 +13,7 @@ * Dharam Kumar <dharam.kr@samsung.com> */ #include <drm/bridge/mhl.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> @@ -339,7 +340,7 @@ static int sii9234_cbus_reset(struct sii9234 *ctx) return sii9234_clear_error(ctx); } -/* Require to chek mhl imformation of samsung in cbus_init_register */ +/* Require to check mhl information of samsung in cbus_init_register */ static int sii9234_cbus_init(struct sii9234 *ctx) { cbus_writeb(ctx, 0x07, 0xF2); @@ -614,7 +615,7 @@ static void sii9234_cable_out(struct sii9234 *ctx) disable_irq(to_i2c_client(ctx->dev)->irq); tpi_writeb(ctx, TPI_DPD_REG, 0); - /* Turn on&off hpd festure for only QCT HDMI */ + /* Turn on&off hpd feature for only QCT HDMI */ sii9234_hw_off(ctx); ctx->state = ST_OFF; @@ -708,7 +709,7 @@ static enum sii9234_state sii9234_rsen_change(struct sii9234 *ctx) { int value; - /* Work_around code to handle wrong interrupt */ + /* Workaround code to handle wrong interrupt */ if (ctx->state != ST_RGND_1K) { dev_err(ctx->dev, "RSEN_HIGH without RGND_1K\n"); return ST_FAILURE; @@ -723,9 +724,9 @@ static enum sii9234_state sii9234_rsen_change(struct sii9234 *ctx) } dev_dbg(ctx->dev, "RSEN lost\n"); /* - * Once RSEN loss is confirmed,we need to check - * based on cable status and chip power status,whether - * it is SINK Loss(HDMI cable not connected, TV Off) + * Once RSEN loss is confirmed, we need to check + * based on cable status and chip power status, whether + * it is SINK Loss (HDMI cable not connected, TV Off) * or MHL cable disconnection * TODO: Define the below mhl_disconnection() */ @@ -820,26 +821,22 @@ static int sii9234_init_resources(struct sii9234 *ctx, int ret; if (!ctx->dev->of_node) { - dev_err(ctx->dev, "not DT device\n"); + dev_err(ctx->dev, "no DT device\n"); return -ENODEV; } ctx->gpio_reset = devm_gpiod_get(ctx->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->gpio_reset)) { - dev_err(ctx->dev, "failed to get reset gpio from DT\n"); - return PTR_ERR(ctx->gpio_reset); - } + if (IS_ERR(ctx->gpio_reset)) + return dev_err_probe(ctx->dev, PTR_ERR(ctx->gpio_reset), + "failed to get reset gpio from DT\n"); ctx->supplies[0].supply = "avcc12"; ctx->supplies[1].supply = "avcc33"; ctx->supplies[2].supply = "iovcc18"; ctx->supplies[3].supply = "cvcc12"; ret = devm_regulator_bulk_get(ctx->dev, 4, ctx->supplies); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(ctx->dev, "regulator_bulk failed\n"); - return ret; - } + if (ret) + return dev_err_probe(ctx->dev, ret, "regulator_bulk failed\n"); ctx->client[I2C_MHL] = client; @@ -878,6 +875,9 @@ static enum drm_mode_status sii9234_mode_valid(struct drm_bridge *bridge, } static const struct drm_bridge_funcs sii9234_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .mode_valid = sii9234_mode_valid, }; @@ -911,10 +911,9 @@ static int sii9234_probe(struct i2c_client *client) sii9234_irq_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "sii9234", ctx); - if (ret < 0) { - dev_err(dev, "failed to install IRQ handler\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to install IRQ handler\n"); ret = sii9234_init_resources(ctx, client); if (ret < 0) diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 982306eb4f0a..22c81b38b41e 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -9,6 +9,7 @@ #include <linux/unaligned.h> #include <drm/bridge/mhl.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> @@ -2280,6 +2281,9 @@ static bool sii8620_mode_fixup(struct drm_bridge *bridge, } static const struct drm_bridge_funcs sii8620_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = sii8620_attach, .detach = sii8620_detach, .mode_fixup = sii8620_mode_fixup, diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index cc13c98f9be6..3fba7002322e 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -132,7 +132,8 @@ static int simple_bridge_attach(struct drm_bridge *bridge, return 0; } -static void simple_bridge_enable(struct drm_bridge *bridge) +static void simple_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge); int ret; @@ -146,7 +147,8 @@ static void simple_bridge_enable(struct drm_bridge *bridge) gpiod_set_value_cansleep(sbridge->enable, 1); } -static void simple_bridge_disable(struct drm_bridge *bridge) +static void simple_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge); @@ -157,9 +159,12 @@ static void simple_bridge_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs simple_bridge_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = simple_bridge_attach, - .enable = simple_bridge_enable, - .disable = simple_bridge_disable, + .atomic_enable = simple_bridge_enable, + .atomic_disable = simple_bridge_disable, }; static int simple_bridge_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index 12b43245bb8f..f55a56cbd88f 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -266,7 +266,8 @@ static void tc358764_reset(struct tc358764 *ctx) usleep_range(1000, 2000); } -static void tc358764_post_disable(struct drm_bridge *bridge) +static void tc358764_post_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tc358764 *ctx = bridge_to_tc358764(bridge); int ret; @@ -278,7 +279,8 @@ static void tc358764_post_disable(struct drm_bridge *bridge) dev_err(ctx->dev, "error disabling regulators (%d)\n", ret); } -static void tc358764_pre_enable(struct drm_bridge *bridge) +static void tc358764_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tc358764 *ctx = bridge_to_tc358764(bridge); int ret; @@ -303,8 +305,11 @@ static int tc358764_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs tc358764_bridge_funcs = { - .post_disable = tc358764_post_disable, - .pre_enable = tc358764_pre_enable, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_post_disable = tc358764_post_disable, + .atomic_pre_enable = tc358764_pre_enable, .attach = tc358764_attach, }; diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 966c3eae437e..ce1b73214f26 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -527,7 +527,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux, * address-only transfer */ if (size) - size = FIELD_GET(AUX_BYTES, auxstatus); + size = min_t(size_t, size, FIELD_GET(AUX_BYTES, auxstatus)); msg->reply = FIELD_GET(AUX_STATUS, auxstatus); switch (request) { diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c index 6c427bc75896..16c745591175 100644 --- a/drivers/gpu/drm/bridge/tda998x_drv.c +++ b/drivers/gpu/drm/bridge/tda998x_drv.c @@ -1410,7 +1410,8 @@ static enum drm_mode_status tda998x_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void tda998x_bridge_enable(struct drm_bridge *bridge) +static void tda998x_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); @@ -1428,7 +1429,8 @@ static void tda998x_bridge_enable(struct drm_bridge *bridge) } } -static void tda998x_bridge_disable(struct drm_bridge *bridge) +static void tda998x_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); @@ -1745,12 +1747,15 @@ static void tda998x_bridge_hpd_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs tda998x_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = tda998x_bridge_attach, .detach = tda998x_bridge_detach, .mode_valid = tda998x_bridge_mode_valid, - .disable = tda998x_bridge_disable, + .atomic_disable = tda998x_bridge_disable, .mode_set = tda998x_bridge_mode_set, - .enable = tda998x_bridge_enable, + .atomic_enable = tda998x_bridge_enable, .edid_read = tda998x_bridge_edid_read, .detect = tda998x_bridge_detect, .hpd_enable = tda998x_bridge_hpd_enable, diff --git a/drivers/gpu/drm/bridge/thc63lvd1024.c b/drivers/gpu/drm/bridge/thc63lvd1024.c index c804222846c3..679b424ba0c3 100644 --- a/drivers/gpu/drm/bridge/thc63lvd1024.c +++ b/drivers/gpu/drm/bridge/thc63lvd1024.c @@ -13,6 +13,7 @@ #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_panel.h> @@ -81,7 +82,8 @@ static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void thc63_enable(struct drm_bridge *bridge) +static void thc63_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct thc63_dev *thc63 = to_thc63(bridge); int ret; @@ -97,7 +99,8 @@ static void thc63_enable(struct drm_bridge *bridge) gpiod_set_value(thc63->oe, 1); } -static void thc63_disable(struct drm_bridge *bridge) +static void thc63_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct thc63_dev *thc63 = to_thc63(bridge); int ret; @@ -112,10 +115,13 @@ static void thc63_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs thc63_bridge_func = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = thc63_attach, .mode_valid = thc63_mode_valid, - .enable = thc63_enable, - .disable = thc63_disable, + .atomic_enable = thc63_enable, + .atomic_disable = thc63_disable, }; static int thc63_parse_dt(struct thc63_dev *thc63) diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 6f06f7b4e992..f0a14f52aaac 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -174,14 +174,16 @@ static void tfp410_detach(struct drm_bridge *bridge) } } -static void tfp410_enable(struct drm_bridge *bridge) +static void tfp410_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tfp410 *dvi = drm_bridge_to_tfp410(bridge); gpiod_set_value_cansleep(dvi->powerdown, 0); } -static void tfp410_disable(struct drm_bridge *bridge) +static void tfp410_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tfp410 *dvi = drm_bridge_to_tfp410(bridge); @@ -242,8 +244,8 @@ static int tfp410_atomic_check(struct drm_bridge *bridge, static const struct drm_bridge_funcs tfp410_bridge_funcs = { .attach = tfp410_attach, .detach = tfp410_detach, - .enable = tfp410_enable, - .disable = tfp410_disable, + .atomic_enable = tfp410_enable, + .atomic_disable = tfp410_disable, .mode_valid = tfp410_mode_valid, .atomic_create_state = drm_atomic_helper_bridge_create_state, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, diff --git a/drivers/gpu/drm/bridge/ti-tpd12s015.c b/drivers/gpu/drm/bridge/ti-tpd12s015.c index 136e47ad1a10..e7b172ab7f55 100644 --- a/drivers/gpu/drm/bridge/ti-tpd12s015.c +++ b/drivers/gpu/drm/bridge/ti-tpd12s015.c @@ -19,6 +19,7 @@ #include <linux/of_graph.h> #include <linux/platform_device.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> struct tpd12s015_device { @@ -96,6 +97,9 @@ static void tpd12s015_hpd_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs tpd12s015_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = tpd12s015_attach, .detach = tpd12s015_detach, .detect = tpd12s015_bridge_detect, diff --git a/drivers/gpu/drm/bridge/waveshare-dsi.c b/drivers/gpu/drm/bridge/waveshare-dsi.c index ded57f298d64..9c9825c9b7c5 100644 --- a/drivers/gpu/drm/bridge/waveshare-dsi.c +++ b/drivers/gpu/drm/bridge/waveshare-dsi.c @@ -12,6 +12,7 @@ #include <linux/of_graph.h> #include <linux/regmap.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_of.h> @@ -92,7 +93,8 @@ static int ws_bridge_bridge_attach(struct drm_bridge *bridge, &ws->bridge, flags); } -static void ws_bridge_bridge_enable(struct drm_bridge *bridge) +static void ws_bridge_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ws_bridge *ws = bridge_to_ws_bridge(bridge); @@ -100,7 +102,8 @@ static void ws_bridge_bridge_enable(struct drm_bridge *bridge) backlight_enable(ws->backlight); } -static void ws_bridge_bridge_disable(struct drm_bridge *bridge) +static void ws_bridge_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ws_bridge *ws = bridge_to_ws_bridge(bridge); @@ -109,8 +112,11 @@ static void ws_bridge_bridge_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs ws_bridge_bridge_funcs = { - .enable = ws_bridge_bridge_enable, - .disable = ws_bridge_bridge_disable, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_enable = ws_bridge_bridge_enable, + .atomic_disable = ws_bridge_bridge_disable, .attach = ws_bridge_bridge_attach, }; diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c index 92f8a2d7aab4..8b54069fa53a 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -147,7 +147,7 @@ static void drm_bridge_connector_hpd_notify(struct drm_connector *connector, to_drm_bridge_connector(connector); /* Notify all bridges in the pipeline of hotplug events. */ - drm_for_each_bridge_in_chain_scoped(bridge_connector->encoder, bridge) { + drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge) { if (bridge->funcs->hpd_notify) bridge->funcs->hpd_notify(bridge, connector, status); } @@ -854,7 +854,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, * detection are available, we don't support hotplug detection at all. */ connector_type = DRM_MODE_CONNECTOR_Unknown; - drm_for_each_bridge_in_chain_scoped(encoder, bridge) { + drm_for_each_bridge_in_chain(encoder, bridge) { if (!bridge->interlace_allowed) connector->interlace_allowed = false; if (!bridge->ycbcr_420_allowed) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 735ab7badc2e..e5c8ef06caed 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1554,7 +1554,7 @@ drm_atomic_add_encoder_bridges(struct drm_atomic_commit *state, "Adding all bridges for [encoder:%d:%s] to %p\n", encoder->base.id, encoder->name, state); - drm_for_each_bridge_in_chain_scoped(encoder, bridge) { + drm_for_each_bridge_in_chain(encoder, bridge) { /* Skip bridges that don't implement the atomic state hooks. */ if (!bridge->funcs->atomic_duplicate_state) continue; diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 2f0d1ba285be..d17ae964fb21 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -563,10 +563,10 @@ EXPORT_SYMBOL(drm_atomic_normalize_zpos); /** * drm_plane_create_blend_mode_property - create a new blend mode property * @plane: drm plane - * @supported_modes: bitmask of supported modes, must include - * BIT(DRM_MODE_BLEND_PREMULTI). Current DRM assumption is - * that alpha is premultiplied, and old userspace can break if - * the property defaults to anything else. + * @supported_modes: bitmask of supported modes. When + * BIT(DRM_MODE_BLEND_PREMULTI) is included, it will be used + * as the default. Otherwise, the default will fallback to one + * of the supported modes. * * This creates a new property describing the blend mode. * @@ -599,13 +599,14 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, { DRM_MODE_BLEND_PREMULTI, "Pre-multiplied" }, { DRM_MODE_BLEND_COVERAGE, "Coverage" }, }; + unsigned int default_mode; unsigned int valid_mode_mask = BIT(DRM_MODE_BLEND_PIXEL_NONE) | BIT(DRM_MODE_BLEND_PREMULTI) | BIT(DRM_MODE_BLEND_COVERAGE); int i; if (WARN_ON((supported_modes & ~valid_mode_mask) || - ((supported_modes & BIT(DRM_MODE_BLEND_PREMULTI)) == 0))) + (supported_modes == 0))) return -EINVAL; prop = drm_property_create(dev, DRM_MODE_PROP_ENUM, @@ -630,7 +631,14 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, } } - drm_object_attach_property(&plane->base, prop, DRM_MODE_BLEND_PREMULTI); + if (supported_modes & BIT(DRM_MODE_BLEND_PREMULTI)) + default_mode = DRM_MODE_BLEND_PREMULTI; + else if (supported_modes & BIT(DRM_MODE_BLEND_COVERAGE)) + default_mode = DRM_MODE_BLEND_COVERAGE; + else + default_mode = DRM_MODE_BLEND_PIXEL_NONE; + + drm_object_attach_property(&plane->base, prop, default_mode); plane->blend_mode_property = prop; return 0; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 6ead9b75ae3d..83f1809a5d37 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -555,11 +555,6 @@ static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = { .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state, }; -static bool drm_bridge_is_atomic(struct drm_bridge *bridge) -{ - return bridge->funcs->atomic_create_state != NULL; -} - /** * drm_bridge_attach - attach the bridge to an encoder's chain * @@ -629,9 +624,8 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, goto err_reset_bridge; } - if (drm_bridge_is_atomic(bridge)) - drm_atomic_private_obj_init(bridge->dev, &bridge->base, - &drm_bridge_priv_state_funcs); + drm_atomic_private_obj_init(bridge->dev, &bridge->base, + &drm_bridge_priv_state_funcs); return 0; @@ -664,8 +658,7 @@ void drm_bridge_detach(struct drm_bridge *bridge) if (WARN_ON(!bridge->dev)) return; - if (drm_bridge_is_atomic(bridge)) - drm_atomic_private_obj_fini(&bridge->base); + drm_atomic_private_obj_fini(&bridge->base); if (bridge->funcs->detach) bridge->funcs->detach(bridge); @@ -690,9 +683,9 @@ void drm_bridge_detach(struct drm_bridge *bridge) * disable the bridge automatically. * * The enable and disable operations are split in - * &drm_bridge_funcs.pre_enable, &drm_bridge_funcs.enable, - * &drm_bridge_funcs.disable and &drm_bridge_funcs.post_disable to provide - * finer-grained control. + * &drm_bridge_funcs.atomic_pre_enable, &drm_bridge_funcs.atomic_enable, + * &drm_bridge_funcs.atomic_disable and &drm_bridge_funcs.atomic_post_disable + * to provide finer-grained control. * * Bridge drivers may implement the legacy version of those operations, or * the atomic version (prefixed with atomic\_), in which case they shall also @@ -833,10 +826,9 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_set); * @bridge: bridge control structure * @state: atomic state being committed * - * Calls &drm_bridge_funcs.atomic_disable (falls back on - * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain, - * starting from the last bridge to the first. These are called before calling - * &drm_encoder_helper_funcs.atomic_disable + * Calls &drm_bridge_funcs.atomic_disable op for all the bridges in the encoder + * chain, starting from the last bridge to the first. These are called before + * calling &drm_encoder_helper_funcs.atomic_disable * * Note: the bridge passed should be the one closest to the encoder */ @@ -852,11 +844,8 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, encoder = bridge->encoder; mutex_lock(&encoder->bridge_chain_mutex); list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - if (iter->funcs->atomic_disable) { + if (iter->funcs->atomic_disable) iter->funcs->atomic_disable(iter, state); - } else if (iter->funcs->disable) { - iter->funcs->disable(iter); - } if (iter == bridge) break; @@ -870,8 +859,6 @@ static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge, { if (state && bridge->funcs->atomic_post_disable) bridge->funcs->atomic_post_disable(bridge, state); - else if (bridge->funcs->post_disable) - bridge->funcs->post_disable(bridge); } /** @@ -880,10 +867,9 @@ static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge, * @bridge: bridge control structure * @state: atomic state being committed * - * Calls &drm_bridge_funcs.atomic_post_disable (falls back on - * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain, - * starting from the first bridge to the last. These are called after completing - * &drm_encoder_helper_funcs.atomic_disable + * Calls &drm_bridge_funcs.atomic_post_disable op for all the bridges in the + * encoder chain, starting from the first bridge to the last. These are called + * after completing &drm_encoder_helper_funcs.atomic_disable * * If a bridge sets @pre_enable_prev_first, then the @post_disable for that * bridge will be called before the previous one to reverse the @pre_enable @@ -967,8 +953,6 @@ static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge, { if (state && bridge->funcs->atomic_pre_enable) bridge->funcs->atomic_pre_enable(bridge, state); - else if (bridge->funcs->pre_enable) - bridge->funcs->pre_enable(bridge); } /** @@ -977,10 +961,9 @@ static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge, * @bridge: bridge control structure * @state: atomic state being committed * - * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on - * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain, - * starting from the last bridge to the first. These are called before calling - * &drm_encoder_helper_funcs.atomic_enable + * Calls &drm_bridge_funcs.atomic_pre_enable op for all the bridges in the + * encoder chain, starting from the last bridge to the first. These are called + * before calling &drm_encoder_helper_funcs.atomic_enable * * If a bridge sets @pre_enable_prev_first, then the pre_enable for the * prev bridge will be called before pre_enable of this bridge. @@ -1057,10 +1040,9 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); * @first_bridge: bridge control structure * @state: atomic state being committed * - * Calls &drm_bridge_funcs.atomic_enable (falls back on - * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain, - * starting from the first bridge to the last. These are called after completing - * &drm_encoder_helper_funcs.atomic_enable + * Calls &drm_bridge_funcs.atomic_enable op for all the bridges in the encoder + * chain, starting from the first bridge to the last. These are called after + * completing &drm_encoder_helper_funcs.atomic_enable * * Note: the bridge passed should be the one closest to the encoder */ @@ -1071,11 +1053,8 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *first_bridge, return; drm_for_each_bridge_in_chain_from(first_bridge, bridge) - if (bridge->funcs->atomic_enable) { + if (bridge->funcs->atomic_enable) bridge->funcs->atomic_enable(bridge, state); - } else if (bridge->funcs->enable) { - bridge->funcs->enable(bridge); - } } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); @@ -1717,7 +1696,7 @@ struct drm_bridge *of_drm_get_bridge_by_endpoint(const struct device_node *np, /* * of_graph_get_remote_node() produces a noisy error message if port * node isn't found and the absence of the port is a legit case here, - * so at first we silently check whether graph is present in the + * so at first we silently check whether a graph is present in the * device-tree node. */ if (!of_graph_is_present(np)) @@ -1817,7 +1796,7 @@ static int encoder_bridges_show(struct seq_file *m, void *data) struct drm_printer p = drm_seq_file_printer(m); unsigned int idx = 0; - drm_for_each_bridge_in_chain_scoped(encoder, bridge) + drm_for_each_bridge_in_chain(encoder, bridge) drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, true); return 0; diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index 958cb605aedd..fcfe635bc195 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -48,6 +48,47 @@ * event. As mentioned above, ranges are tracked in a notifier's Red-Black * tree. * + * - Pages: + * struct drm_gpusvm_pages holds the DMA mapping state for a range of + * CPU virtual addresses: the DMA mapped device addresses, + * the device private pagemap, the IOVA state, the per mapping + * notifier sequence number, and the drm_device that owns the DMA + * mappings. + * A driver embeds one or more struct drm_gpusvm_pages alongside its + * struct drm_gpusvm_range, choosing one of two layouts: + * + * 1:1 - one drm_gpusvm_pages per range (one drm_device). Simplest + * layout; to mirror a VA range on several devices a driver uses a + * separate range (and notifier) per device, so the HMM fault is taken + * once per device. + * + * N:1 - one drm_gpusvm_pages per drm_device, all sharing one range and + * notifier; only the per-device DMA mapping differs. The instances must + * sit in contiguous memory so a single drm_gpusvm_range_set_unmapped() + * can mark them all. A driver can keep one instance inline for the single + * device case and switch to a heap array only when more devices join, + * e.g.: + * + * .. code-block:: c + * + * struct driver_range { + * struct drm_gpusvm_range base; + * unsigned int num_pages; // 1: inline_pages, >1: pages[] + * union { + * struct drm_gpusvm_pages inline_pages; + * struct drm_gpusvm_pages *pages; + * }; + * }; + * + * In the N:1 case the driver allocates the pages array with a zeroing + * allocator (e.g. kcalloc(num_pages, ...)), initialises each entry with + * drm_gpusvm_init_pages(), and frees each entry with + * drm_gpusvm_free_pages() plus the array itself, from its range free + * callback. Each drm_gpusvm_pages is mapped independently by their own + * drm_device. + * Each drm_gpusvm_pages must be zero-initialised and initialised with + * drm_gpusvm_init_pages(), called once per entry. + * * - Operations: * Define the interface for driver-specific GPU SVM operations such as * range allocation, notifier allocation, and invalidations. @@ -92,7 +133,7 @@ * range RB tree and list, as well as the range's DMA mappings and sequence * number. GPU SVM manages all necessary locking and unlocking operations, * except for the recheck range's pages being valid - * (drm_gpusvm_range_pages_valid) when the driver is committing GPU bindings. + * (drm_gpusvm_pages_valid) when the driver is committing GPU bindings. * This lock corresponds to the ``driver->update`` lock mentioned in * Documentation/mm/hmm.rst. Future revisions may transition from a GPU SVM * global lock to a per-notifier lock if finer-grained locking is deemed @@ -140,15 +181,20 @@ * * .. code-block:: c * - * int driver_bind_range(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range) + * struct driver_range { + * struct drm_gpusvm_range base; + * struct drm_gpusvm_pages pages; + * }; + * + * int driver_bind_range(struct drm_gpusvm *gpusvm, struct driver_range *drange) * { * int err = 0; * - * driver_alloc_and_setup_memory_for_bind(gpusvm, range); + * driver_alloc_and_setup_memory_for_bind(gpusvm, drange); * * drm_gpusvm_notifier_lock(gpusvm); - * if (drm_gpusvm_range_pages_valid(range)) - * driver_commit_bind(gpusvm, range); + * if (drm_gpusvm_pages_valid(gpusvm, &drange->pages)) + * driver_commit_bind(gpusvm, drange); * else * err = -EAGAIN; * drm_gpusvm_notifier_unlock(gpusvm); @@ -160,6 +206,8 @@ * unsigned long gpuva_start, unsigned long gpuva_end) * { * struct drm_gpusvm_ctx ctx = {}; + * struct driver_range *drange; + * struct drm_gpusvm_range *range; * int err; * * driver_svm_lock(); @@ -174,6 +222,7 @@ * err = PTR_ERR(range); * goto unlock; * } + * drange = container_of(range, struct driver_range, base); * * if (driver_migration_policy(range)) { * err = drm_pagemap_populate_mm(driver_choose_drm_pagemap(), @@ -183,7 +232,10 @@ * goto retry; * } * - * err = drm_gpusvm_range_get_pages(gpusvm, range, &ctx); + * err = drm_gpusvm_get_pages(gpusvm, &drange->pages, + * gpusvm->mm, &range->notifier->notifier, + * drm_gpusvm_range_start(range), + * drm_gpusvm_range_end(range), &ctx); * if (err == -EOPNOTSUPP || err == -EFAULT || err == -EPERM) { // CPU mappings changed * if (err == -EOPNOTSUPP) * drm_gpusvm_range_evict(gpusvm, range); @@ -192,7 +244,7 @@ * goto unlock; * } * - * err = driver_bind_range(gpusvm, range); + * err = driver_bind_range(gpusvm, drange); * if (err == -EAGAIN) // CPU mappings changed * goto retry * @@ -205,6 +257,21 @@ * * .. code-block:: c * + * // The driver owns the drm_gpusvm_pages lifecycle. ops->range_free is + * // the final fallback: drm_gpusvm_free_pages() unmaps any + * // lingering DMA mapping and a no-op if already unmapped and frees the + * // dma_addr array. The normal flow is to DMA unmap before + * // drm_gpusvm_range_remove() (before the range leaves the tree). + * void driver_range_free(struct drm_gpusvm_range *range) + * { + * struct driver_range *drange = + * container_of(range, struct driver_range, base); + * + * drm_gpusvm_free_pages(range->gpusvm, &drange->pages, + * drm_gpusvm_range_size(range) >> PAGE_SHIFT); + * kfree(drange); + * } + * * void __driver_garbage_collector(struct drm_gpusvm *gpusvm, * struct drm_gpusvm_range *range) * { @@ -215,6 +282,14 @@ * drm_gpusvm_range_evict(gpusvm, range); * * driver_unbind_range(range); + * // The pages must be DMA unmapped before drm_gpusvm_range_remove() + * // , so a range is never off the MMU interval tree while still DMA + * // mapped as the original drmsvm design flow. Otherwise a concurrent CPU + * // munmap's notifier could miss this range and free pages still mapped + * // for device DMA. This is the normal unmap point. + * drm_gpusvm_unmap_pages(gpusvm, &drange->pages, + * drm_gpusvm_range_size(range) >> PAGE_SHIFT, + * &(struct drm_gpusvm_ctx){ .in_notifier = false }); * drm_gpusvm_range_remove(gpusvm, range); * } * @@ -236,17 +311,22 @@ * { * struct drm_gpusvm_ctx ctx = { .in_notifier = true, }; * struct drm_gpusvm_range *range = NULL; + * struct driver_range *drange; * * driver_invalidate_device_pages(gpusvm, mmu_range->start, mmu_range->end); * * drm_gpusvm_for_each_range(range, notifier, mmu_range->start, * mmu_range->end) { - * drm_gpusvm_range_unmap_pages(gpusvm, range, &ctx); + * drange = container_of(range, struct driver_range, base); + * + * drm_gpusvm_unmap_pages(gpusvm, &drange->pages, + * drm_gpusvm_range_size(range) >> PAGE_SHIFT, + * &ctx); * * if (mmu_range->event != MMU_NOTIFY_UNMAP) * continue; * - * drm_gpusvm_range_set_unmapped(range, mmu_range); + * drm_gpusvm_range_set_unmapped(range, &drange->pages, 1, mmu_range); * driver_garbage_collector_add(gpusvm, range); * } * } @@ -359,7 +439,6 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = { * drm_gpusvm_init() - Initialize the GPU SVM. * @gpusvm: Pointer to the GPU SVM structure. * @name: Name of the GPU SVM. - * @drm: Pointer to the DRM device structure. * @mm: Pointer to the mm_struct for the address space. * @mm_start: Start address of GPU SVM. * @mm_range: Range of the GPU SVM. @@ -373,7 +452,9 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = { * This function initializes the GPU SVM. * * Note: If only using the simple drm_gpusvm_pages API (get/unmap/free), - * then only @gpusvm, @name, and @drm are expected. However, the same base + * then only @gpusvm and @name are expected. The @drm drm_device for dma + * mappings is bound per-pages via drm_gpusvm_init_pages() before the first + * drm_gpusvm_get_pages() call. However, the same base * @gpusvm can also be used with both modes together in which case the full * setup is needed, where the core drm_gpusvm_pages API will simply never use * the other fields. @@ -381,7 +462,7 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = { * Return: 0 on success, a negative error code on failure. */ int drm_gpusvm_init(struct drm_gpusvm *gpusvm, - const char *name, struct drm_device *drm, + const char *name, struct mm_struct *mm, unsigned long mm_start, unsigned long mm_range, unsigned long notifier_size, @@ -399,7 +480,6 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm, } gpusvm->name = name; - gpusvm->drm = drm; gpusvm->mm = mm; gpusvm->mm_start = mm_start; gpusvm->mm_range = mm_range; @@ -640,8 +720,7 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm, range->itree.start = ALIGN_DOWN(fault_addr, chunk_size); range->itree.last = ALIGN(fault_addr + 1, chunk_size) - 1; INIT_LIST_HEAD(&range->entry); - range->pages.notifier_seq = LONG_MAX; - range->pages.flags.migrate_devmem = migrate_devmem ? 1 : 0; + range->flags.migrate_devmem = migrate_devmem ? 1 : 0; return range; } @@ -929,7 +1008,7 @@ retry: * mallocs 16k but the CPU VMA is ~128k which results in 64k SVM * ranges. When migrating the SVM ranges, some processes fail in * drm_pagemap_migrate_to_devmem with 'migrate.cpages != npages' - * and then upon drm_gpusvm_range_get_pages device pages from + * and then upon drm_gpusvm_get_pages device pages from * other processes are collected + faulted in which creates all * sorts of problems. Unsure exactly how this happening, also * problem goes away if 'xe_exec_system_allocator --r @@ -1135,11 +1214,16 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm, unsigned long npages) { struct drm_pagemap *dpagemap = svm_pages->dpagemap; - struct device *dev = gpusvm->drm->dev; + struct device *dev; unsigned long i, j; lockdep_assert_held(&gpusvm->notifier_lock); + if (!svm_pages->drm) + return; + + dev = svm_pages->drm->dev; + if (svm_pages->flags.has_dma_mapping) { struct drm_gpusvm_pages_flags flags = { .__flags = svm_pages->flags.__flags, @@ -1222,12 +1306,17 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_free_pages); * This function removes the specified GPU SVM range and also removes the parent * GPU SVM notifier if no more ranges remain in the notifier. The caller must * hold a lock to protect range and notifier removal. + * + * This function does not unmap or free the drm_gpusvm_pages, the driver owns + * that lifecycle. The caller must DMA unmap the range's pages before calling + * this function, so a range is never removed from the MMU interval tree while + * still DMA mapped. Typically the driver calls drm_gpusvm_unmap_pages() first. + * And the range_free callback's drm_gpusvm_free_pages() is a final fallback safe + * net. */ void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range) { - unsigned long npages = npages_in_range(drm_gpusvm_range_start(range), - drm_gpusvm_range_end(range)); struct drm_gpusvm_notifier *notifier; drm_gpusvm_driver_lock_held(gpusvm); @@ -1239,8 +1328,6 @@ void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm, return; drm_gpusvm_notifier_lock(gpusvm); - __drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages); - __drm_gpusvm_free_pages(gpusvm, &range->pages); __drm_gpusvm_range_remove(notifier, range); drm_gpusvm_notifier_unlock(gpusvm); @@ -1319,34 +1406,14 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_put); * * Return: True if GPU SVM range has valid pages, False otherwise */ -static bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_pages *svm_pages) +bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm, + struct drm_gpusvm_pages *svm_pages) { lockdep_assert_held(&gpusvm->notifier_lock); return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping; } - -/** - * drm_gpusvm_range_pages_valid() - GPU SVM range pages valid - * @gpusvm: Pointer to the GPU SVM structure - * @range: Pointer to the GPU SVM range structure - * - * This function determines if a GPU SVM range pages are valid. Expected be - * called holding gpusvm->notifier_lock and as the last step before committing a - * GPU binding. This is akin to a notifier seqno check in the HMM documentation - * but due to wider notifiers (i.e., notifiers which span multiple ranges) this - * function is required for finer grained checking (i.e., per range) if pages - * are valid. - * - * Return: True if GPU SVM range has valid pages, False otherwise - */ -bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range) -{ - return drm_gpusvm_pages_valid(gpusvm, &range->pages); -} -EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid); +EXPORT_SYMBOL_GPL(drm_gpusvm_pages_valid); /** * drm_gpusvm_pages_valid_unlocked() - GPU SVM pages valid unlocked @@ -1421,6 +1488,9 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, DMA_BIDIRECTIONAL; struct dma_iova_state *state = &svm_pages->state; + if (!svm_pages->drm) + return -EINVAL; + retry: if (time_after(jiffies, timeout)) return -EBUSY; @@ -1520,7 +1590,7 @@ map_pages: pagemap = page_pgmap(page); dpagemap = drm_pagemap_page_to_dpagemap(page); - if (drm_WARN_ON(gpusvm->drm, !dpagemap)) { + if (drm_WARN_ON(svm_pages->drm, !dpagemap)) { /* * Raced. This is not supposed to happen * since hmm_range_fault() should've migrated @@ -1532,10 +1602,10 @@ map_pages: } svm_pages->dma_addr[j] = dpagemap->ops->device_map(dpagemap, - gpusvm->drm->dev, + svm_pages->drm->dev, page, order, dma_dir); - if (dma_mapping_error(gpusvm->drm->dev, + if (dma_mapping_error(svm_pages->drm->dev, svm_pages->dma_addr[j].addr)) { err = -EFAULT; goto err_unmap; @@ -1555,11 +1625,11 @@ map_pages: } if (!i) - dma_iova_try_alloc(gpusvm->drm->dev, state, + dma_iova_try_alloc(svm_pages->drm->dev, state, 0, npages * PAGE_SIZE); if (dma_use_iova(state)) { - err = dma_iova_link(gpusvm->drm->dev, state, + err = dma_iova_link(svm_pages->drm->dev, state, hmm_pfn_to_phys(pfns[i]), svm_pages->state_offset, PAGE_SIZE << order, @@ -1570,11 +1640,11 @@ map_pages: addr = state->addr + svm_pages->state_offset; svm_pages->state_offset += PAGE_SIZE << order; } else { - addr = dma_map_page(gpusvm->drm->dev, + addr = dma_map_page(svm_pages->drm->dev, page, 0, PAGE_SIZE << order, dma_dir); - if (dma_mapping_error(gpusvm->drm->dev, addr)) { + if (dma_mapping_error(svm_pages->drm->dev, addr)) { err = -EFAULT; goto err_unmap; } @@ -1590,7 +1660,7 @@ map_pages: } if (dma_use_iova(state)) { - err = dma_iova_sync(gpusvm->drm->dev, state, 0, + err = dma_iova_sync(svm_pages->drm->dev, state, 0, svm_pages->state_offset); if (err) goto err_unmap; @@ -1626,28 +1696,6 @@ err_free: EXPORT_SYMBOL_GPL(drm_gpusvm_get_pages); /** - * drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range - * @gpusvm: Pointer to the GPU SVM structure - * @range: Pointer to the GPU SVM range structure - * @ctx: GPU SVM context - * - * This function gets pages for a GPU SVM range and ensures they are mapped for - * DMA access. - * - * Return: 0 on success, negative error code on failure. - */ -int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range, - const struct drm_gpusvm_ctx *ctx) -{ - return drm_gpusvm_get_pages(gpusvm, &range->pages, gpusvm->mm, - &range->notifier->notifier, - drm_gpusvm_range_start(range), - drm_gpusvm_range_end(range), ctx); -} -EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages); - -/** * drm_gpusvm_unmap_pages() - Unmap GPU svm pages * @gpusvm: Pointer to the GPU SVM structure * @svm_pages: Pointer to the GPU SVM pages structure @@ -1678,29 +1726,6 @@ void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm, EXPORT_SYMBOL_GPL(drm_gpusvm_unmap_pages); /** - * drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range - * @gpusvm: Pointer to the GPU SVM structure - * @range: Pointer to the GPU SVM range structure - * @ctx: GPU SVM context - * - * This function unmaps pages associated with a GPU SVM range. If @in_notifier - * is set, it is assumed that gpusvm->notifier_lock is held in write mode; if it - * is clear, it acquires gpusvm->notifier_lock in read mode. Must be called on - * each GPU SVM range attached to notifier in gpusvm->ops->invalidate for IOMMU - * security model. - */ -void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range, - const struct drm_gpusvm_ctx *ctx) -{ - unsigned long npages = npages_in_range(drm_gpusvm_range_start(range), - drm_gpusvm_range_end(range)); - - return drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages, ctx); -} -EXPORT_SYMBOL_GPL(drm_gpusvm_range_unmap_pages); - -/** * drm_gpusvm_range_evict() - Evict GPU SVM range * @gpusvm: Pointer to the GPU SVM structure * @range: Pointer to the GPU SVM range to be removed @@ -1784,20 +1809,40 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_has_mapping); /** * drm_gpusvm_range_set_unmapped() - Mark a GPU SVM range as unmapped * @range: Pointer to the GPU SVM range structure. + * @pages: Pointer to the GPU SVM pages structure(s). + * @pages_count: Number of GPU SVM pages structure(s) passed in. * @mmu_range: Pointer to the MMU notifier range structure. * * This function marks a GPU SVM range as unmapped and sets the partial_unmap flag * if the range partially falls within the provided MMU notifier range. */ void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range, + struct drm_gpusvm_pages *pages, + unsigned int pages_count, const struct mmu_notifier_range *mmu_range) { + struct drm_gpusvm_range_flags range_flags = { + .__flags = range->flags.__flags, + }; + unsigned int i; + lockdep_assert_held_write(&range->gpusvm->notifier_lock); - range->pages.flags.unmapped = true; + range_flags.unmapped = true; + for (i = 0; i < pages_count; ++i) { + struct drm_gpusvm_pages_flags flags = { + .__flags = pages[i].flags.__flags, + }; + + flags.unmapped = true; + /* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */ + WRITE_ONCE(pages[i].flags.__flags, flags.__flags); + } if (drm_gpusvm_range_start(range) < mmu_range->start || drm_gpusvm_range_end(range) > mmu_range->end) - range->pages.flags.partial_unmap = true; + range_flags.partial_unmap = true; + /* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */ + WRITE_ONCE(range->flags.__flags, range_flags.__flags); } EXPORT_SYMBOL_GPL(drm_gpusvm_range_set_unmapped); diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index f432f485a914..3bcc7bf0900c 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -857,6 +857,25 @@ static void validate_encoder_possible_crtcs(struct drm_encoder *encoder) encoder->possible_crtcs, crtc_mask); } +static void validate_blend_mode_for_alpha_formats(struct drm_plane *plane) +{ + const struct drm_format_info *fmt; + u32 i; + + /* blend mode property supported, no need to check anything */ + if (plane->blend_mode_property) + return; + + for (i = 0; i < plane->format_count; i++) { + fmt = drm_format_info(plane->format_types[i]); + if (fmt->has_alpha) { + WARN(1, "[PLANE:%d:%s] pixel format with alpha exposed but blend mode not setup", + plane->base.id, plane->name); + break; + } + } +} + void drm_mode_config_validate(struct drm_device *dev) { struct drm_encoder *encoder; @@ -915,6 +934,8 @@ void drm_mode_config_validate(struct drm_device *dev) drm_for_each_plane(plane, dev) { if (plane->type == DRM_PLANE_TYPE_PRIMARY) num_primary++; + + validate_blend_mode_for_alpha_formats(plane); } WARN(num_primary != dev->mode_config.num_crtc, diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 96eef327bf7e..1f4cff6bb4a7 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -297,7 +297,7 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, /* * of_graph_get_remote_node() produces a noisy error message if port * node isn't found and the absence of the port is a legit case here, - * so at first we silently check whether graph presents in the + * so at first we silently check whether a graph is present in the * device-tree node. */ if (!of_graph_is_present(np)) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index c314b3cb5e70..4dbc8a7ea6af 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -584,9 +584,9 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) /* read idle register. */ idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); - /* try resetting again if FE is not idle */ - if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) { - dev_dbg(gpu->dev, "FE is not idle\n"); + /* try resetting again if any module is not idle */ + if ((idle & gpu->idle_mask) != gpu->idle_mask) { + dev_dbg(gpu->dev, "GPU modules not idle\n"); continue; } @@ -600,6 +600,23 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) continue; } + /* try resetting again if MMUv2 is not disabled */ + if (gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION) { + if (gpu->sec_mode == ETNA_SEC_KERNEL) { + if (gpu_read(gpu, VIVS_MMUv2_SEC_CONTROL) & + VIVS_MMUv2_SEC_CONTROL_ENABLE) { + dev_dbg(gpu->dev, "MMU is not disabled\n"); + continue; + } + } else { + if (gpu_read(gpu, VIVS_MMUv2_CONTROL) & + VIVS_MMUv2_CONTROL_ENABLE) { + dev_dbg(gpu->dev, "MMU is not disabled\n"); + continue; + } + } + } + /* enable debug register access */ control &= ~VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS; gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index e68c954ec3e6..3069f958137f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c @@ -21,6 +21,7 @@ #include <video/of_videomode.h> #include <video/videomode.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_encoder.h> #include <drm/drm_print.h> @@ -228,7 +229,8 @@ static void mic_set_reg_on(struct exynos_mic *mic, bool enable) writel(reg, mic->reg + MIC_OP); } -static void mic_post_disable(struct drm_bridge *bridge) +static void mic_post_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct exynos_mic *mic = bridge->driver_private; @@ -257,7 +259,8 @@ static void mic_mode_set(struct drm_bridge *bridge, mutex_unlock(&mic_mutex); } -static void mic_pre_enable(struct drm_bridge *bridge) +static void mic_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct exynos_mic *mic = bridge->driver_private; int ret; @@ -295,9 +298,12 @@ unlock: } static const struct drm_bridge_funcs mic_bridge_funcs = { - .post_disable = mic_post_disable, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_post_disable = mic_post_disable, .mode_set = mic_mode_set, - .pre_enable = mic_pre_enable, + .atomic_pre_enable = mic_pre_enable, }; static int exynos_mic_bind(struct device *dev, struct device *master, diff --git a/drivers/gpu/drm/imx/dc/dc-ic.c b/drivers/gpu/drm/imx/dc/dc-ic.c index a270ae4030cd..fa87bf1f4508 100644 --- a/drivers/gpu/drm/imx/dc/dc-ic.c +++ b/drivers/gpu/drm/imx/dc/dc-ic.c @@ -14,6 +14,8 @@ #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include "dc-drv.h" + #define USERINTERRUPTMASK(n) (0x8 + 4 * (n)) #define INTERRUPTENABLE(n) (0x10 + 4 * (n)) #define INTERRUPTPRESET(n) (0x18 + 4 * (n)) @@ -174,8 +176,8 @@ static int dc_ic_probe(struct platform_device *pdev) regmap_write(data->regs, USERINTERRUPTMASK(i), 0xffffffff); } - data->domain = irq_domain_add_linear(dev->of_node, IRQ_COUNT, - &irq_generic_chip_ops, data); + data->domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node), IRQ_COUNT, + &irq_generic_chip_ops, data); if (!data->domain) { dev_err(dev, "failed to create IRQ domain\n"); pm_runtime_put(dev); diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c index 47d45897ed06..5cf44ccb02cf 100644 --- a/drivers/gpu/drm/mcde/mcde_dsi.c +++ b/drivers/gpu/drm/mcde/mcde_dsi.c @@ -1063,6 +1063,9 @@ static int mcde_dsi_bridge_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = mcde_dsi_bridge_attach, .mode_set = mcde_dsi_bridge_mode_set, }; diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 959c994eef24..0e4f430de983 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -850,7 +850,8 @@ static void mtk_dpi_bridge_mode_set(struct drm_bridge *bridge, drm_mode_copy(&dpi->mode, adjusted_mode); } -static void mtk_dpi_bridge_disable(struct drm_bridge *bridge) +static void mtk_dpi_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct mtk_dpi *dpi = bridge_to_dpi(bridge); @@ -860,7 +861,8 @@ static void mtk_dpi_bridge_disable(struct drm_bridge *bridge) pinctrl_select_state(dpi->pinctrl, dpi->pins_gpio); } -static void mtk_dpi_bridge_enable(struct drm_bridge *bridge) +static void mtk_dpi_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct mtk_dpi *dpi = bridge_to_dpi(bridge); @@ -982,8 +984,8 @@ static const struct drm_bridge_funcs mtk_dpi_bridge_funcs = { .attach = mtk_dpi_bridge_attach, .mode_set = mtk_dpi_bridge_mode_set, .mode_valid = mtk_dpi_bridge_mode_valid, - .disable = mtk_dpi_bridge_disable, - .enable = mtk_dpi_bridge_enable, + .atomic_disable = mtk_dpi_bridge_disable, + .atomic_enable = mtk_dpi_bridge_enable, .atomic_check = mtk_dpi_bridge_atomic_check, .atomic_get_output_bus_fmts = mtk_dpi_bridge_atomic_get_output_bus_fmts, .atomic_get_input_bus_fmts = mtk_dpi_bridge_atomic_get_input_bus_fmts, diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 46faeaae9d94..959daa88b1d0 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -275,7 +275,8 @@ static void dsi_mgr_bridge_power_off(struct drm_bridge *bridge) dsi_mgr_phy_disable(id); } -static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge) +static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { int id = dsi_mgr_bridge_get_id(bridge); struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); @@ -331,7 +332,8 @@ void msm_dsi_manager_tpg_enable(void) } } -static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge) +static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { int id = dsi_mgr_bridge_get_id(bridge); struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); @@ -445,9 +447,12 @@ static int dsi_mgr_bridge_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = dsi_mgr_bridge_attach, - .pre_enable = dsi_mgr_bridge_pre_enable, - .post_disable = dsi_mgr_bridge_post_disable, + .atomic_pre_enable = dsi_mgr_bridge_pre_enable, + .atomic_post_disable = dsi_mgr_bridge_post_disable, .mode_set = dsi_mgr_bridge_mode_set, .mode_valid = dsi_mgr_bridge_mode_valid, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c index 700cea5def35..f128330f30d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c @@ -297,6 +297,7 @@ r535_fbsr = { static void * r535_instmem_dtor(struct nvkm_instmem *imem) { + nv50_instmem_dtor(imem); kfree(imem->func); return imem; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index 6fbaa1e5876d..f4489efc94a7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -30,10 +30,14 @@ #include <subdev/gsp.h> #include <subdev/mmu.h> +#include <linux/io-mapping.h> + struct nv50_instmem { struct nvkm_instmem base; u64 addr; + struct io_mapping iomap; + /* Mappings that can be evicted when BAR2 space has been exhausted. */ struct list_head lru; }; @@ -124,7 +128,6 @@ nv50_instobj_kmap(struct nv50_instobj *iobj, struct nvkm_vmm *vmm) struct nv50_instobj *eobj; struct nvkm_memory *memory = &iobj->base.memory; struct nvkm_subdev *subdev = &imem->base.subdev; - struct nvkm_device *device = subdev->device; struct nvkm_vma *bar = NULL, *ebar; u64 size = nvkm_memory_size(memory); void *emap; @@ -155,7 +158,7 @@ nv50_instobj_kmap(struct nv50_instobj *iobj, struct nvkm_vmm *vmm) mutex_unlock(&imem->base.mutex); if (!eobj) break; - iounmap(emap); + io_mapping_unmap(emap); nvkm_vmm_put(vmm, &ebar); } @@ -172,8 +175,7 @@ nv50_instobj_kmap(struct nv50_instobj *iobj, struct nvkm_vmm *vmm) /* Make the mapping visible to the host. */ iobj->bar = bar; - iobj->map = ioremap_wc(device->func->resource_addr(device, NVKM_BAR2_INST) + - (u32)iobj->bar->addr, size); + iobj->map = io_mapping_map_wc(&imem->iomap, (u32)iobj->bar->addr, size); if (!iobj->map) { nvkm_warn(subdev, "PRAMIN ioremap failed\n"); nvkm_vmm_put(vmm, &iobj->bar); @@ -188,6 +190,16 @@ nv50_instobj_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm, return nvkm_memory_map(memory, offset, vmm, vma, argv, argc); } +static bool +check_io_mapping(struct nv50_instmem *imem) +{ + struct nvkm_device *device = imem->base.subdev.device; + + return io_mapping_init_wc(&imem->iomap, + device->func->resource_addr(device, NVKM_BAR2_INST), + device->func->resource_size(device, NVKM_BAR2_INST)) != NULL; +} + static void nv50_instobj_release(struct nvkm_memory *memory) { @@ -239,7 +251,7 @@ nv50_instobj_acquire(struct nvkm_memory *memory) /* Attempt to get a direct CPU mapping of the object. */ if ((vmm = nvkm_bar_bar2_vmm(imem->subdev.device))) { - if (!iobj->map) + if (!iobj->map && iobj->imem->iomap.size) nv50_instobj_kmap(iobj, vmm); map = iobj->map; } @@ -277,7 +289,12 @@ nv50_instobj_boot(struct nvkm_memory *memory, struct nvkm_vmm *vmm) iobj->lru.next = NULL; } - nv50_instobj_kmap(iobj, vmm); + /* + * boot is only called on BAR2, if we can't remap the complete + * BAR it's unlikely things are functioning well. + */ + if (check_io_mapping(iobj->imem)) + nv50_instobj_kmap(iobj, vmm); nvkm_instmem_boot(imem); mutex_unlock(&imem->mutex); } @@ -330,7 +347,7 @@ nv50_instobj_dtor(struct nvkm_memory *memory) if (map) { struct nvkm_vmm *vmm = nvkm_bar_bar2_vmm(imem->subdev.device); - iounmap(map); + io_mapping_unmap(map); if (likely(vmm)) /* Can be NULL during BAR destructor. */ nvkm_vmm_put(vmm, &bar); } @@ -406,10 +423,14 @@ nv50_instmem_fini(struct nvkm_instmem *base) nv50_instmem(base)->addr = ~0ULL; } -static void * +void * nv50_instmem_dtor(struct nvkm_instmem *base) { - return nv50_instmem(base); + struct nv50_instmem *imem = nv50_instmem(base); + + if (imem->iomap.size) + io_mapping_fini(&imem->iomap); + return imem; } static const struct nvkm_instmem_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h index 87bbdd786eaa..b423f01f5fcd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -26,6 +26,7 @@ int nv50_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero, struct nvkm_memory **); int nv50_instobj_wrap(struct nvkm_instmem *, struct nvkm_memory *vram, struct nvkm_memory **bar2); +void *nv50_instmem_dtor(struct nvkm_instmem *base); void nvkm_instmem_ctor(const struct nvkm_instmem_func *, struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_instmem *); diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 9f86db774c39..419915e33816 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -22,6 +22,7 @@ #include <linux/string.h> #include <linux/sys_soc.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include "dss.h" @@ -482,7 +483,8 @@ static void dpi_bridge_mode_set(struct drm_bridge *bridge, dpi->pixelclock = adjusted_mode->clock * 1000; } -static void dpi_bridge_enable(struct drm_bridge *bridge) +static void dpi_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct dpi_data *dpi = drm_bridge_to_dpi(bridge); int r; @@ -533,7 +535,8 @@ err_get_dispc: regulator_disable(dpi->vdds_dsi_reg); } -static void dpi_bridge_disable(struct drm_bridge *bridge) +static void dpi_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct dpi_data *dpi = drm_bridge_to_dpi(bridge); @@ -552,12 +555,15 @@ static void dpi_bridge_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs dpi_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = dpi_bridge_attach, .mode_valid = dpi_bridge_mode_valid, .mode_fixup = dpi_bridge_mode_fixup, .mode_set = dpi_bridge_mode_set, - .enable = dpi_bridge_enable, - .disable = dpi_bridge_disable, + .atomic_enable = dpi_bridge_enable, + .atomic_disable = dpi_bridge_disable, }; static void dpi_bridge_init(struct dpi_data *dpi) diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 27fe7bca9e2c..7aaee94f86e4 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -35,6 +35,7 @@ #include <linux/component.h> #include <linux/sys_soc.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> @@ -4654,7 +4655,8 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge, dsi_set_config(&dsi->output, adjusted_mode); } -static void dsi_bridge_enable(struct drm_bridge *bridge) +static void dsi_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct dsi_data *dsi = drm_bridge_to_dsi(bridge); struct omap_dss_device *dssdev = &dsi->output; @@ -4673,7 +4675,8 @@ static void dsi_bridge_enable(struct drm_bridge *bridge) dsi_bus_unlock(dsi); } -static void dsi_bridge_disable(struct drm_bridge *bridge) +static void dsi_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct dsi_data *dsi = drm_bridge_to_dsi(bridge); struct omap_dss_device *dssdev = &dsi->output; @@ -4692,11 +4695,14 @@ static void dsi_bridge_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs dsi_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = dsi_bridge_attach, .mode_valid = dsi_bridge_mode_valid, .mode_set = dsi_bridge_mode_set, - .enable = dsi_bridge_enable, - .disable = dsi_bridge_disable, + .atomic_enable = dsi_bridge_enable, + .atomic_disable = dsi_bridge_disable, }; static void dsi_bridge_init(struct dsi_data *dsi) diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index df4cbc683e2c..d4a3c0ecaaf2 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -16,6 +16,7 @@ #include <linux/regulator/consumer.h> #include <linux/string.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include "dss.h" @@ -197,7 +198,8 @@ static void sdi_bridge_mode_set(struct drm_bridge *bridge, sdi->pixelclock = adjusted_mode->clock * 1000; } -static void sdi_bridge_enable(struct drm_bridge *bridge) +static void sdi_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct sdi_device *sdi = drm_bridge_to_sdi(bridge); struct dispc_clock_info dispc_cinfo; @@ -260,7 +262,8 @@ err_get_dispc: regulator_disable(sdi->vdds_sdi_reg); } -static void sdi_bridge_disable(struct drm_bridge *bridge) +static void sdi_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct sdi_device *sdi = drm_bridge_to_sdi(bridge); @@ -274,12 +277,15 @@ static void sdi_bridge_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs sdi_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = sdi_bridge_attach, .mode_valid = sdi_bridge_mode_valid, .mode_fixup = sdi_bridge_mode_fixup, .mode_set = sdi_bridge_mode_set, - .enable = sdi_bridge_enable, - .disable = sdi_bridge_disable, + .atomic_enable = sdi_bridge_enable, + .atomic_disable = sdi_bridge_disable, }; static void sdi_bridge_init(struct sdi_device *sdi) diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 9b5d53dc361e..5416c668a205 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -25,6 +25,7 @@ #include <linux/component.h> #include <linux/sys_soc.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include "omapdss.h" @@ -614,14 +615,16 @@ static void venc_bridge_mode_set(struct drm_bridge *bridge, dispc_set_tv_pclk(venc->dss->dispc, 13500000); } -static void venc_bridge_enable(struct drm_bridge *bridge) +static void venc_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct venc_device *venc = drm_bridge_to_venc(bridge); venc_power_on(venc); } -static void venc_bridge_disable(struct drm_bridge *bridge) +static void venc_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct venc_device *venc = drm_bridge_to_venc(bridge); @@ -653,12 +656,15 @@ static int venc_bridge_get_modes(struct drm_bridge *bridge, } static const struct drm_bridge_funcs venc_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = venc_bridge_attach, .mode_valid = venc_bridge_mode_valid, .mode_fixup = venc_bridge_mode_fixup, .mode_set = venc_bridge_mode_set, - .enable = venc_bridge_enable, - .disable = venc_bridge_disable, + .atomic_enable = venc_bridge_enable, + .atomic_disable = venc_bridge_disable, .get_modes = venc_bridge_get_modes, }; diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37801.c b/drivers/gpu/drm/panel/panel-novatek-nt37801.c index 861e999250f9..5e46c4c6d771 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt37801.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt37801.c @@ -51,61 +51,56 @@ static void novatek_nt37801_reset(struct novatek_nt37801 *ctx) mipi_dsi_dcs_write_seq_multi((dsi_ctx), NT37801_DCS_SWITCH_PAGE, \ 0x55, 0xaa, 0x52, 0x08, (page)) -static int novatek_nt37801_on(struct novatek_nt37801 *ctx) +static void novatek_nt37801_on(struct mipi_dsi_multi_context *dsi_ctx) { - struct mipi_dsi_device *dsi = ctx->dsi; - struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; - - dsi->mode_flags |= MIPI_DSI_MODE_LPM; - - novatek_nt37801_switch_page(&dsi_ctx, 0x01); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x01); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x0b, 0x0b, 0x0b); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x80); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x10); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x1b); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x55); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x18); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x19); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x0f); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfc, 0x00); - mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0x0000, 0x059f); - mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0x0000, 0x0c7f); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x03, 0x03); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, + dsi_ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + novatek_nt37801_switch_page(dsi_ctx, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc5, 0x0b, 0x0b, 0x0b); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x80); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf5, 0x10); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x1b); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf4, 0x55); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x18); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf8, 0x19); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x0f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfc, 0x00); + mipi_dsi_dcs_set_column_address_multi(dsi_ctx, 0x0000, 0x059f); + mipi_dsi_dcs_set_page_address_multi(dsi_ctx, 0x0000, 0x0c7f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x90, 0x03, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x91, 0x89, 0x28, 0x00, 0x28, 0xc2, 0x00, 0x02, 0x68, 0x04, 0x6c, 0x00, 0x0a, 0x02, 0x77, 0x01, 0xe9, 0x10, 0xf0); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x23); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x23); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfb, 0x00, 0x01, 0x00, 0x11, 0x33, 0x33, 0x33, 0x55, 0x57, 0xd0, 0x00, 0x00, 0x44, 0x56, 0x77, 0x78, 0x9a, 0xbc, 0xdd, 0xf0); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x06); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0xdc); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x00); - mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x00, 0x18, 0x00, 0x10); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x06); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf3, 0xdc); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x00); + mipi_dsi_dcs_set_tear_on_multi(dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x3b, 0x00, 0x18, 0x00, 0x10); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x51, 0x07, 0xff, 0x07, 0xff, 0x0f, 0xff); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x01); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9c, 0x01); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_MEMORY_START); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x00); - - novatek_nt37801_switch_page(&dsi_ctx, 0x01); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x55, 0x01, 0xff, 0x03); - mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); - mipi_dsi_msleep(&dsi_ctx, 120); - mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); - mipi_dsi_msleep(&dsi_ctx, 20); - - return dsi_ctx.accum_err; + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x5a, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x5f, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x9c, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_MEMORY_START); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x2f, 0x00); + + novatek_nt37801_switch_page(dsi_ctx, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x55, 0x01, 0xff, 0x03); + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); + mipi_dsi_msleep(dsi_ctx, 120); + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); + mipi_dsi_msleep(dsi_ctx, 20); } static int novatek_nt37801_off(struct novatek_nt37801 *ctx) @@ -127,7 +122,8 @@ static int novatek_nt37801_off(struct novatek_nt37801 *ctx) static int novatek_nt37801_prepare(struct drm_panel *panel) { struct novatek_nt37801 *ctx = to_novatek_nt37801(panel); - struct device *dev = &ctx->dsi->dev; + struct mipi_dsi_device *dsi = ctx->dsi; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; struct drm_dsc_picture_parameter_set pps; int ret; @@ -137,22 +133,12 @@ static int novatek_nt37801_prepare(struct drm_panel *panel) return ret; novatek_nt37801_reset(ctx); - - ret = novatek_nt37801_on(ctx); - if (ret < 0) - goto err; - + novatek_nt37801_on(&dsi_ctx); drm_dsc_pps_payload_pack(&pps, &ctx->dsc); - - ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps); - if (ret < 0) { - dev_err(panel->dev, "failed to transmit PPS: %d\n", ret); - goto err; - } - - ret = mipi_dsi_compression_mode(ctx->dsi, true); - if (ret < 0) { - dev_err(dev, "failed to enable compression mode: %d\n", ret); + mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps); + mipi_dsi_compression_mode_multi(&dsi_ctx, true); + if (dsi_ctx.accum_err) { + ret = dsi_ctx.accum_err; goto err; } diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c index 1b14aa4efe35..54a65abf7e89 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c @@ -88,16 +88,22 @@ static int s6d16d0_prepare(struct drm_panel *panel) MIPI_DSI_DCS_TEAR_MODE_VBLANK); if (ret) { dev_err(s6->dev, "failed to enable vblank TE (%d)\n", ret); - return ret; + goto err_power_off; } /* Exit sleep mode and power on */ ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret) { dev_err(s6->dev, "failed to exit sleep mode (%d)\n", ret); - return ret; + goto err_power_off; } return 0; + +err_power_off: + gpiod_set_value_cansleep(s6->reset_gpio, 1); + regulator_disable(s6->supply); + + return ret; } static int s6d16d0_enable(struct drm_panel *panel) diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index 784e36d72c2b..36cc2e67a308 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -21,6 +21,7 @@ #include <drm/drm_utils.h> #include "panfrost_device.h" +#include "panfrost_drv.h" #include "panfrost_gem.h" #include "panfrost_mmu.h" #include "panfrost_job.h" diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 298b046c95ed..5832dccfc093 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -3446,7 +3446,6 @@ queue_timedout_job(struct drm_sched_job *sched_job) static void queue_free_job(struct drm_sched_job *sched_job) { - drm_sched_job_cleanup(sched_job); panthor_job_put(sched_job); } diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index a026bd35ef48..7f4178800afd 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -31,12 +31,12 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_edid.h> +#include <drm/drm_encoder.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_vblank.h> #include <drm/drm_vblank_helper.h> @@ -1095,6 +1095,10 @@ static const struct drm_connector_helper_funcs qxl_connector_helper_funcs = { .best_encoder = qxl_best_encoder, }; +static const struct drm_encoder_funcs qxl_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + static enum drm_connector_status qxl_conn_detect( struct drm_connector *connector, bool force) @@ -1169,10 +1173,10 @@ static int qdev_output_init(struct drm_device *dev, int num_output) drm_connector_init(dev, &qxl_output->base, &qxl_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); - ret = drm_simple_encoder_init(dev, &qxl_output->enc, - DRM_MODE_ENCODER_VIRTUAL); + ret = drm_encoder_init(dev, &qxl_output->enc, &qxl_encoder_funcs, + DRM_MODE_ENCODER_VIRTUAL, NULL); if (ret) { - drm_err(dev, "drm_simple_encoder_init() failed, error %d\n", + drm_err(dev, "drm_encoder_init() failed, error %d\n", ret); goto err_drm_connector_cleanup; } diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 7484d3c3f4ed..b48099468eb9 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -209,7 +209,8 @@ static void dvo_debugfs_init(struct sti_dvo *dvo, struct drm_minor *minor) minor->debugfs_root, minor); } -static void sti_dvo_disable(struct drm_bridge *bridge) +static void sti_dvo_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct sti_dvo *dvo = bridge->driver_private; @@ -232,7 +233,8 @@ static void sti_dvo_disable(struct drm_bridge *bridge) dvo->enabled = false; } -static void sti_dvo_pre_enable(struct drm_bridge *bridge) +static void sti_dvo_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct sti_dvo *dvo = bridge->driver_private; struct dvo_config *config = dvo->config; @@ -320,16 +322,20 @@ static void sti_dvo_set_mode(struct drm_bridge *bridge, dvo->config = &rgb_24bit_de_cfg; } -static void sti_dvo_bridge_nope(struct drm_bridge *bridge) +static void sti_dvo_bridge_nope(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { /* do nothing */ } static const struct drm_bridge_funcs sti_dvo_bridge_funcs = { - .pre_enable = sti_dvo_pre_enable, - .enable = sti_dvo_bridge_nope, - .disable = sti_dvo_disable, - .post_disable = sti_dvo_bridge_nope, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_pre_enable = sti_dvo_pre_enable, + .atomic_enable = sti_dvo_bridge_nope, + .atomic_disable = sti_dvo_disable, + .atomic_post_disable = sti_dvo_bridge_nope, .mode_set = sti_dvo_set_mode, }; diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index b9f8f68f01f9..b4def2b25cec 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -404,7 +404,8 @@ static void sti_hda_configure_awg(struct sti_hda *hda, u32 *awg_instr, int nb) hda_write(hda, 0, HDA_SYNC_AWGI + i * 4); } -static void sti_hda_disable(struct drm_bridge *bridge) +static void sti_hda_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct sti_hda *hda = drm_bridge_to_sti_hda(bridge); u32 val; @@ -429,7 +430,8 @@ static void sti_hda_disable(struct drm_bridge *bridge) hda->enabled = false; } -static void sti_hda_pre_enable(struct drm_bridge *bridge) +static void sti_hda_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct sti_hda *hda = drm_bridge_to_sti_hda(bridge); u32 val, i, mode_idx; @@ -563,16 +565,20 @@ static void sti_hda_set_mode(struct drm_bridge *bridge, mode->clock * 1000); } -static void sti_hda_bridge_nope(struct drm_bridge *bridge) +static void sti_hda_bridge_nope(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { /* do nothing */ } static const struct drm_bridge_funcs sti_hda_bridge_funcs = { - .pre_enable = sti_hda_pre_enable, - .enable = sti_hda_bridge_nope, - .disable = sti_hda_disable, - .post_disable = sti_hda_bridge_nope, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_pre_enable = sti_hda_pre_enable, + .atomic_enable = sti_hda_bridge_nope, + .atomic_disable = sti_hda_disable, + .atomic_post_disable = sti_hda_bridge_nope, .mode_set = sti_hda_set_mode, }; diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index f8222e60b1e0..7ba9e0b7ba6c 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -752,7 +752,8 @@ static void hdmi_debugfs_init(struct sti_hdmi *hdmi, struct drm_minor *minor) minor->debugfs_root, minor); } -static void sti_hdmi_disable(struct drm_bridge *bridge) +static void sti_hdmi_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct sti_hdmi *hdmi = drm_bridge_to_sti_hdmi(bridge); @@ -884,7 +885,8 @@ static int hdmi_audio_configure(struct sti_hdmi *hdmi) return hdmi_audio_infoframe_config(hdmi); } -static void sti_hdmi_pre_enable(struct drm_bridge *bridge) +static void sti_hdmi_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct sti_hdmi *hdmi = drm_bridge_to_sti_hdmi(bridge); @@ -964,16 +966,20 @@ static void sti_hdmi_set_mode(struct drm_bridge *bridge, } } -static void sti_hdmi_bridge_nope(struct drm_bridge *bridge) +static void sti_hdmi_bridge_nope(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { /* do nothing */ } static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = { - .pre_enable = sti_hdmi_pre_enable, - .enable = sti_hdmi_bridge_nope, - .disable = sti_hdmi_disable, - .post_disable = sti_hdmi_bridge_nope, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_pre_enable = sti_hdmi_pre_enable, + .atomic_enable = sti_hdmi_bridge_nope, + .atomic_disable = sti_hdmi_disable, + .atomic_post_disable = sti_hdmi_bridge_nope, .mode_set = sti_hdmi_set_mode, }; diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c index 10a32620e962..15583ade8494 100644 --- a/drivers/gpu/drm/tests/drm_bridge_test.c +++ b/drivers/gpu/drm/tests/drm_bridge_test.c @@ -74,26 +74,6 @@ static void drm_test_bridge_priv_destroy(struct drm_bridge *bridge) priv->destroyed = true; } -static void drm_test_bridge_enable(struct drm_bridge *bridge) -{ - struct drm_bridge_priv *priv = bridge_to_priv(bridge); - - priv->enable_count++; -} - -static void drm_test_bridge_disable(struct drm_bridge *bridge) -{ - struct drm_bridge_priv *priv = bridge_to_priv(bridge); - - priv->disable_count++; -} - -static const struct drm_bridge_funcs drm_test_bridge_legacy_funcs = { - .destroy = drm_test_bridge_priv_destroy, - .enable = drm_test_bridge_enable, - .disable = drm_test_bridge_disable, -}; - static void drm_test_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_atomic_commit *state) { @@ -695,35 +675,8 @@ retry_state: drm_modeset_acquire_fini(&ctx); } -/* - * Test that drm_bridge_get_current_state() returns NULL for a - * non-atomic bridge. - */ -static void drm_test_drm_bridge_get_current_state_legacy(struct kunit *test) -{ - struct drm_bridge_init_priv *priv; - struct drm_bridge *bridge; - - priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv); - - /* - * NOTE: Strictly speaking, we should take the bridge->base.lock - * before calling that function. However, bridge->base is only - * initialized if the bridge is atomic, while we explicitly - * initialize one that isn't there. - * - * In order to avoid unnecessary warnings, let's skip the - * locking. The function would return NULL in all cases anyway, - * so we don't really have any concurrency to worry about. - */ - bridge = &priv->test_bridge->bridge; - KUNIT_EXPECT_NULL(test, drm_bridge_get_current_state(bridge)); -} - static struct kunit_case drm_bridge_get_current_state_tests[] = { KUNIT_CASE(drm_test_drm_bridge_get_current_state_atomic), - KUNIT_CASE(drm_test_drm_bridge_get_current_state_legacy), { } }; @@ -829,62 +782,6 @@ retry_reset: } /* - * Test that a non-atomic bridge is properly power-cycled when calling - * drm_bridge_helper_reset_crtc(). - */ -static void drm_test_drm_bridge_helper_reset_crtc_legacy(struct kunit *test) -{ - struct drm_modeset_acquire_ctx ctx; - struct drm_bridge_init_priv *priv; - struct drm_display_mode *mode; - struct drm_bridge_priv *bridge_priv; - int ret; - - priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv); - - mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode); - - drm_modeset_acquire_init(&ctx, 0); - -retry_commit: - ret = drm_kunit_helper_enable_crtc_connector(test, - &priv->drm, priv->crtc, - priv->connector, - mode, - &ctx); - if (ret == -EDEADLK) { - drm_modeset_backoff(&ctx); - goto retry_commit; - } - KUNIT_ASSERT_EQ(test, ret, 0); - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - - bridge_priv = priv->test_bridge; - KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 1); - KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0); - - drm_modeset_acquire_init(&ctx, 0); - -retry_reset: - ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx); - if (ret == -EDEADLK) { - drm_modeset_backoff(&ctx); - goto retry_reset; - } - KUNIT_ASSERT_EQ(test, ret, 0); - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - - KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 2); - KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1); -} - -/* * Test that a bridge using the drm_atomic_helper_bridge_get_hdmi_output_bus_fmts() * function for &drm_bridge_funcs.atomic_get_output_bus_fmts behaves as expected * for an HDMI connector bridge. Does so by creating an HDMI bridge connector @@ -970,7 +867,6 @@ retry_commit: static struct kunit_case drm_bridge_helper_reset_crtc_tests[] = { KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic), KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic_disabled), - KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_legacy), KUNIT_CASE(drm_test_drm_bridge_helper_hdmi_output_bus_fmts), { } }; @@ -1071,7 +967,7 @@ static void drm_test_bridge_chain_verify_fmt(struct kunit *test, struct drm_bridge_state *bstate; unsigned int i = 0; - drm_for_each_bridge_in_chain_scoped(&priv->encoder, bridge) { + drm_for_each_bridge_in_chain(&priv->encoder, bridge) { KUNIT_ASSERT_LT(test, i, num_expected); bstate = drm_bridge_get_current_state(bridge); diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 5fdad444009f..c48ddc888cb0 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -760,7 +760,7 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma, return -EAGAIN; } if (xe_svm_range_has_dma_mapping(range)) { - xe_res_first_dma(range->base.pages.dma_addr, 0, + xe_res_first_dma(range->pages.dma_addr, 0, xe_svm_range_size(range), &curs); xe_svm_range_debug(range, "BIND PREPARE - MIXED"); diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index e0f0c23d172d..b228a737cfd6 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -66,7 +66,7 @@ static bool xe_svm_range_in_vram(struct xe_svm_range *range) struct drm_gpusvm_pages_flags flags = { /* Pairs with WRITE_ONCE in drm_gpusvm.c */ - .__flags = READ_ONCE(range->base.pages.flags.__flags), + .__flags = READ_ONCE(range->pages.flags.__flags), }; return flags.has_devmem_pages; @@ -96,7 +96,7 @@ static struct xe_vm *range_to_vm(struct drm_gpusvm_range *r) (r__)->base.gpusvm, \ xe_svm_range_in_vram((r__)) ? 1 : 0, \ xe_svm_range_has_vram_binding((r__)) ? 1 : 0, \ - (r__)->base.pages.notifier_seq, \ + (r__)->pages.notifier_seq, \ xe_svm_range_start((r__)), xe_svm_range_end((r__)), \ xe_svm_range_size((r__))) @@ -115,6 +115,7 @@ xe_svm_range_alloc(struct drm_gpusvm *gpusvm) return NULL; INIT_LIST_HEAD(&range->garbage_collector_link); + drm_gpusvm_init_pages(&range->pages, &gpusvm_to_vm(gpusvm)->xe->drm); xe_vm_get(gpusvm_to_vm(gpusvm)); return &range->base; @@ -122,8 +123,10 @@ xe_svm_range_alloc(struct drm_gpusvm *gpusvm) static void xe_svm_range_free(struct drm_gpusvm_range *range) { + drm_gpusvm_free_pages(range->gpusvm, &(to_xe_range(range)->pages), + drm_gpusvm_range_size(range) >> PAGE_SHIFT); xe_vm_put(range_to_vm(range)); - kfree(range); + kfree(to_xe_range(range)); } static void @@ -134,7 +137,8 @@ xe_svm_garbage_collector_add_range(struct xe_vm *vm, struct xe_svm_range *range, range_debug(range, "GARBAGE COLLECTOR ADD"); - drm_gpusvm_range_set_unmapped(&range->base, mmu_range); + drm_gpusvm_range_set_unmapped(&range->base, &range->pages, 1, + mmu_range); spin_lock(&vm->svm.garbage_collector.lock); if (list_empty(&range->garbage_collector_link)) @@ -166,7 +170,7 @@ xe_svm_range_notifier_event_begin(struct xe_vm *vm, struct drm_gpusvm_range *r, range_debug(range, "NOTIFIER"); /* Skip if already unmapped or if no binding exist */ - if (range->base.pages.flags.unmapped || !range->tile_present) + if (range->base.flags.unmapped || !range->tile_present) return 0; range_debug(range, "NOTIFIER - EXECUTE"); @@ -208,7 +212,8 @@ xe_svm_range_notifier_event_end(struct xe_vm *vm, struct drm_gpusvm_range *r, xe_svm_assert_in_notifier(vm); - drm_gpusvm_range_unmap_pages(&vm->svm.gpusvm, r, &ctx); + drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &(to_xe_range(r)->pages), + drm_gpusvm_range_size(r) >> PAGE_SHIFT, &ctx); if (!xe_vm_is_closed(vm) && mmu_range->event == MMU_NOTIFY_UNMAP) xe_svm_garbage_collector_add_range(vm, to_xe_range(r), mmu_range); @@ -299,6 +304,7 @@ range_notifier_event_end: static int __xe_svm_garbage_collector(struct xe_vm *vm, struct xe_svm_range *range) { + struct drm_gpusvm_ctx ctx = { .in_notifier = false, }; struct dma_fence *fence; range_debug(range, "GARBAGE COLLECTOR"); @@ -310,6 +316,10 @@ static int __xe_svm_garbage_collector(struct xe_vm *vm, return PTR_ERR(fence); dma_fence_put(fence); + drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &range->pages, + drm_gpusvm_range_size(&range->base) >> PAGE_SHIFT, + &ctx); + drm_gpusvm_range_remove(&vm->svm.gpusvm, &range->base); return 0; @@ -901,7 +911,7 @@ int xe_svm_init(struct xe_vm *vm) return err; } - err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", &vm->xe->drm, + err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", current->mm, 0, vm->size, xe_modparam.svm_notifier_size * SZ_1M, &gpusvm_ops, fault_chunk_sizes, @@ -915,7 +925,7 @@ int xe_svm_init(struct xe_vm *vm) } } else { err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", - &vm->xe->drm, NULL, 0, 0, 0, NULL, + NULL, 0, 0, 0, NULL, NULL, 0); } @@ -944,15 +954,28 @@ void xe_svm_close(struct xe_vm *vm) */ void xe_svm_fini(struct xe_vm *vm) { + struct drm_gpusvm_notifier *notifier, *next; + struct drm_gpusvm_ctx ctx = { .in_notifier = false, }; + xe_assert(vm->xe, xe_vm_is_closed(vm)); + drm_gpusvm_for_each_notifier_safe(notifier, next, &vm->svm.gpusvm, 0, LONG_MAX) { + struct drm_gpusvm_range *range, *__next; + + drm_gpusvm_for_each_range_safe(range, __next, notifier, 0, LONG_MAX) + drm_gpusvm_unmap_pages(&vm->svm.gpusvm, + &(to_xe_range(range)->pages), + drm_gpusvm_range_size(range) >> PAGE_SHIFT, + &ctx); + } + drm_gpusvm_fini(&vm->svm.gpusvm); } static bool xe_svm_range_has_pagemap_locked(const struct xe_svm_range *range, const struct drm_pagemap *dpagemap) { - return range->base.pages.dpagemap == dpagemap; + return range->pages.dpagemap == dpagemap; } static bool xe_svm_range_has_pagemap(struct xe_svm_range *range, @@ -1017,7 +1040,7 @@ bool xe_svm_range_validate(struct xe_vm *vm, if (dpagemap) ret = ret && xe_svm_range_has_pagemap_locked(range, dpagemap); else - ret = ret && !range->base.pages.dpagemap; + ret = ret && !range->pages.dpagemap; xe_svm_notifier_unlock(vm); @@ -1135,8 +1158,12 @@ bool xe_svm_range_needs_migrate_to_vram(struct xe_svm_range *range, struct xe_vm { struct xe_vm *vm = range_to_vm(&range->base); u64 range_size = xe_svm_range_size(range); + struct drm_gpusvm_range_flags flags = { + /* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */ + .__flags = READ_ONCE(range->base.flags.__flags), + }; - if (!range->base.pages.flags.migrate_devmem || !dpagemap) + if (!flags.migrate_devmem || !dpagemap) return false; xe_assert(vm->xe, IS_DGFX(vm->xe)); @@ -1220,6 +1247,7 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma, struct xe_validation_ctx vctx; struct drm_exec exec; struct xe_svm_range *range; + struct drm_gpusvm_range_flags range_flags; struct dma_fence *fence; struct drm_pagemap *dpagemap; struct xe_tile *tile = gt_to_tile(gt); @@ -1248,7 +1276,9 @@ retry: xe_svm_range_fault_count_stats_incr(gt, range); - if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) + /* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */ + range_flags.__flags = READ_ONCE(range->base.flags.__flags); + if (ctx.devmem_only && !range_flags.migrate_devmem) return -EACCES; if (xe_svm_range_is_valid(range, tile, ctx.devmem_only, dpagemap)) { @@ -1505,7 +1535,11 @@ int xe_svm_range_get_pages(struct xe_vm *vm, struct xe_svm_range *range, { int err = 0; - err = drm_gpusvm_range_get_pages(&vm->svm.gpusvm, &range->base, ctx); + err = drm_gpusvm_get_pages(&vm->svm.gpusvm, &range->pages, + vm->svm.gpusvm.mm, + &range->base.notifier->notifier, + drm_gpusvm_range_start(&range->base), + drm_gpusvm_range_end(&range->base), ctx); if (err == -EOPNOTSUPP) { range_debug(range, "PAGE FAULT - EVICT PAGES"); drm_gpusvm_range_evict(&vm->svm.gpusvm, &range->base); @@ -1620,8 +1654,12 @@ int xe_svm_alloc_vram(struct xe_svm_range *range, const struct drm_gpusvm_ctx *c struct xe_device *xe = vm->xe; int err, retries = 1; bool write_locked = false; + struct drm_gpusvm_range_flags flags = { + /* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */ + .__flags = READ_ONCE(range->base.flags.__flags), + }; - xe_assert(range_to_vm(&range->base)->xe, range->base.pages.flags.migrate_devmem); + xe_assert(range_to_vm(&range->base)->xe, flags.migrate_devmem); range_debug(range, "ALLOCATE VRAM"); migration_state = drm_gpusvm_scan_mm(&range->base, diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h index 3ca46a6f98c7..a921556d3466 100644 --- a/drivers/gpu/drm/xe/xe_svm.h +++ b/drivers/gpu/drm/xe/xe_svm.h @@ -31,6 +31,8 @@ struct xe_vram_region; struct xe_svm_range { /** @base: base drm_gpusvm_range */ struct drm_gpusvm_range base; + /** @pages: Page/DMA mapping state for this range (single drm_device). */ + struct drm_gpusvm_pages pages; /** * @garbage_collector_link: Link into VM's garbage collect SVM range * list. Protected by VM's garbage collect lock. @@ -74,7 +76,7 @@ struct xe_pagemap { */ static inline bool xe_svm_range_pages_valid(struct xe_svm_range *range) { - return drm_gpusvm_range_pages_valid(range->base.gpusvm, &range->base); + return drm_gpusvm_pages_valid(range->base.gpusvm, &range->pages); } int xe_devm_add(struct xe_tile *tile, struct xe_vram_region *vr); @@ -132,7 +134,7 @@ void *xe_svm_private_page_owner(struct xe_vm *vm, bool force_smem); static inline bool xe_svm_range_has_dma_mapping(struct xe_svm_range *range) { lockdep_assert_held(&range->base.gpusvm->notifier_lock); - return range->base.pages.flags.has_dma_mapping; + return range->pages.flags.has_dma_mapping; } /** @@ -210,10 +212,10 @@ struct xe_vram_region; struct xe_svm_range { struct { struct interval_tree_node itree; - struct { - const struct drm_pagemap_addr *dma_addr; - } pages; } base; + struct { + const struct drm_pagemap_addr *dma_addr; + } pages; u32 tile_present; u32 tile_invalidated; }; @@ -233,7 +235,7 @@ static inline int xe_svm_init(struct xe_vm *vm) { #if IS_ENABLED(CONFIG_DRM_GPUSVM) - return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm, + return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", NULL, 0, 0, 0, NULL, NULL, 0); #else return 0; diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c index 1d2ab678faf5..8b2d461ea0b2 100644 --- a/drivers/gpu/drm/xe/xe_userptr.c +++ b/drivers/gpu/drm/xe/xe_userptr.c @@ -390,19 +390,20 @@ int xe_userptr_setup(struct xe_userptr_vma *uvma, unsigned long start, unsigned long range) { struct xe_userptr *userptr = &uvma->userptr; + struct xe_vm *vm = xe_vma_vm(&uvma->vma); int err; INIT_LIST_HEAD(&userptr->invalidate_link); INIT_LIST_HEAD(&userptr->repin_link); + drm_gpusvm_init_pages(&userptr->pages, &vm->xe->drm); + err = mmu_interval_notifier_insert(&userptr->notifier, current->mm, start, range, &vma_userptr_notifier_ops); if (err) return err; - userptr->pages.notifier_seq = LONG_MAX; - return 0; } diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 18f3db367dc1..3ac84ed57ab2 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -173,52 +173,6 @@ struct drm_bridge_funcs { bool (*mode_fixup)(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); - /** - * @disable: - * - * This callback should disable the bridge. It is called right before - * the preceding element in the display pipe is disabled. If the - * preceding element is a bridge this means it's called before that - * bridge's @disable vfunc. If the preceding element is a &drm_encoder - * it's called right before the &drm_encoder_helper_funcs.disable, - * &drm_encoder_helper_funcs.prepare or &drm_encoder_helper_funcs.dpms - * hook. - * - * The bridge can assume that the display pipe (i.e. clocks and timing - * signals) feeding it is still running when this callback is called. - * - * The @disable callback is optional. - * - * NOTE: - * - * This is deprecated, do not use! - * New drivers shall use &drm_bridge_funcs.atomic_disable. - */ - void (*disable)(struct drm_bridge *bridge); - - /** - * @post_disable: - * - * This callback should disable the bridge. It is called right after the - * preceding element in the display pipe is disabled. If the preceding - * element is a bridge this means it's called after that bridge's - * @post_disable function. If the preceding element is a &drm_encoder - * it's called right after the encoder's - * &drm_encoder_helper_funcs.disable, &drm_encoder_helper_funcs.prepare - * or &drm_encoder_helper_funcs.dpms hook. - * - * The bridge must assume that the display pipe (i.e. clocks and timing - * signals) feeding it is no longer running when this callback is - * called. - * - * The @post_disable callback is optional. - * - * NOTE: - * - * This is deprecated, do not use! - * New drivers shall use &drm_bridge_funcs.atomic_post_disable. - */ - void (*post_disable)(struct drm_bridge *bridge); /** * @mode_set: @@ -249,55 +203,6 @@ struct drm_bridge_funcs { void (*mode_set)(struct drm_bridge *bridge, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode); - /** - * @pre_enable: - * - * This callback should enable the bridge. It is called right before - * the preceding element in the display pipe is enabled. If the - * preceding element is a bridge this means it's called before that - * bridge's @pre_enable function. If the preceding element is a - * &drm_encoder it's called right before the encoder's - * &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or - * &drm_encoder_helper_funcs.dpms hook. - * - * The display pipe (i.e. clocks and timing signals) feeding this bridge - * will not yet be running when this callback is called. The bridge must - * not enable the display link feeding the next bridge in the chain (if - * there is one) when this callback is called. - * - * The @pre_enable callback is optional. - * - * NOTE: - * - * This is deprecated, do not use! - * New drivers shall use &drm_bridge_funcs.atomic_pre_enable. - */ - void (*pre_enable)(struct drm_bridge *bridge); - - /** - * @enable: - * - * This callback should enable the bridge. It is called right after - * the preceding element in the display pipe is enabled. If the - * preceding element is a bridge this means it's called after that - * bridge's @enable function. If the preceding element is a - * &drm_encoder it's called right after the encoder's - * &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or - * &drm_encoder_helper_funcs.dpms hook. - * - * The bridge can assume that the display pipe (i.e. clocks and timing - * signals) feeding it is running when this callback is called. This - * callback must enable the display link feeding the next bridge in the - * chain if there is one. - * - * The @enable callback is optional. - * - * NOTE: - * - * This is deprecated, do not use! - * New drivers shall use &drm_bridge_funcs.atomic_enable. - */ - void (*enable)(struct drm_bridge *bridge); /** * @atomic_pre_enable: @@ -1359,14 +1264,6 @@ drm_bridge_get_current_state(struct drm_bridge *bridge) if (!bridge) return NULL; - /* - * Only atomic bridges will have bridge->base initialized by - * drm_atomic_private_obj_init(), so we need to make sure we're - * working with one before we try to use the lock. - */ - if (!bridge->funcs || !bridge->funcs->atomic_create_state) - return NULL; - drm_modeset_lock_assert_held(&bridge->base.lock); if (!bridge->base.state) @@ -1474,9 +1371,9 @@ static inline struct drm_bridge *__drm_for_each_bridge_in_chain_next(struct drm_ DEFINE_FREE(__drm_for_each_bridge_in_chain_cleanup, struct drm_bridge *, if (_T) { mutex_unlock(&_T->encoder->bridge_chain_mutex); drm_bridge_put(_T); }) -/* Internal to drm_for_each_bridge_in_chain_scoped() */ +/* Internal to drm_for_each_bridge_in_chain() */ static inline struct drm_bridge * -__drm_for_each_bridge_in_chain_scoped_start(struct drm_encoder *encoder) +__drm_for_each_bridge_in_chain_start(struct drm_encoder *encoder) { mutex_lock(&encoder->bridge_chain_mutex); @@ -1489,8 +1386,7 @@ __drm_for_each_bridge_in_chain_scoped_start(struct drm_encoder *encoder) } /** - * drm_for_each_bridge_in_chain_scoped - iterate over all bridges attached - * to an encoder + * drm_for_each_bridge_in_chain - iterate over all bridges attached to an encoder * @encoder: the encoder to iterate bridges on * @bridge: a bridge pointer updated to point to the current bridge at each * iteration @@ -1500,9 +1396,9 @@ __drm_for_each_bridge_in_chain_scoped_start(struct drm_encoder *encoder) * Automatically gets/puts the bridge reference while iterating and locks * the encoder chain mutex to prevent chain modifications while iterating. */ -#define drm_for_each_bridge_in_chain_scoped(encoder, bridge) \ +#define drm_for_each_bridge_in_chain(encoder, bridge) \ for (struct drm_bridge *bridge __free(__drm_for_each_bridge_in_chain_cleanup) = \ - __drm_for_each_bridge_in_chain_scoped_start((encoder)); \ + __drm_for_each_bridge_in_chain_start((encoder)); \ bridge; \ bridge = __drm_for_each_bridge_in_chain_next(bridge)) \ diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h index 8a4d7134a9a7..b7d987bf76aa 100644 --- a/include/drm/drm_gpusvm.h +++ b/include/drm/drm_gpusvm.h @@ -109,9 +109,7 @@ struct drm_gpusvm_notifier { /** * struct drm_gpusvm_pages_flags - Structure representing a GPU SVM pages flags * - * @migrate_devmem: Flag indicating whether the pages can be migrated to device memory * @unmapped: Flag indicating if the pages has been unmapped - * @partial_unmap: Flag indicating if the pages has been partially unmapped * @has_devmem_pages: Flag indicating if the pages has devmem pages * @has_dma_mapping: Flag indicating if the pages has a DMA mapping * @__flags: Flags for pages in u16 form (used for READ_ONCE) @@ -119,11 +117,8 @@ struct drm_gpusvm_notifier { struct drm_gpusvm_pages_flags { union { struct { - /* All flags below must be set upon creation */ - u16 migrate_devmem : 1; /* All flags below must be set / cleared under notifier lock */ u16 unmapped : 1; - u16 partial_unmap : 1; u16 has_devmem_pages : 1; u16 has_dma_mapping : 1; }; @@ -134,6 +129,7 @@ struct drm_gpusvm_pages_flags { /** * struct drm_gpusvm_pages - Structure representing a GPU SVM mapped pages * + * @drm: The DRM device that owns the dma mappings * @dma_addr: Device address array * @dpagemap: The struct drm_pagemap of the device pages we're dma-mapping. * Note this is assuming only one drm_pagemap per range is allowed. @@ -143,6 +139,7 @@ struct drm_gpusvm_pages_flags { * @flags: Flags for the range; see &struct drm_gpusvm_pages_flags */ struct drm_gpusvm_pages { + struct drm_device *drm; struct drm_pagemap_addr *dma_addr; struct drm_pagemap *dpagemap; struct dma_iova_state state; @@ -152,6 +149,27 @@ struct drm_gpusvm_pages { }; /** + * struct drm_gpusvm_range_flags - Range-level GPU SVM flags + * + * @migrate_devmem: Flag indicating whether the range can be migrated to device memory + * @unmapped: Flag indicating if the range has been unmapped + * @partial_unmap: Flag indicating if the range has been partially unmapped + * @__flags: All flags in u16 form (used for READ_ONCE) + */ +struct drm_gpusvm_range_flags { + union { + struct { + /* All flags below must be set upon creation */ + u16 migrate_devmem : 1; + /* All flags below must be set / cleared under notifier lock */ + u16 unmapped : 1; + u16 partial_unmap : 1; + }; + u16 __flags; + }; +}; + +/** * struct drm_gpusvm_range - Structure representing a GPU SVM range * * @gpusvm: Pointer to the GPU SVM structure @@ -159,7 +177,7 @@ struct drm_gpusvm_pages { * @refcount: Reference count for the range * @itree: Interval tree node for the range (inserted in GPU SVM notifier) * @entry: List entry to fast interval tree traversal - * @pages: The pages for this range. + * @flags: Flags for range see &struct drm_gpusvm_range_flags * * This structure represents a GPU SVM range used for tracking memory ranges * mapped in a DRM device. @@ -170,14 +188,13 @@ struct drm_gpusvm_range { struct kref refcount; struct interval_tree_node itree; struct list_head entry; - struct drm_gpusvm_pages pages; + struct drm_gpusvm_range_flags flags; }; /** * struct drm_gpusvm - GPU SVM structure * * @name: Name of the GPU SVM - * @drm: Pointer to the DRM device structure * @mm: Pointer to the mm_struct for the address space * @mm_start: Start address of GPU SVM * @mm_range: Range of the GPU SVM @@ -201,7 +218,6 @@ struct drm_gpusvm_range { */ struct drm_gpusvm { const char *name; - struct drm_device *drm; struct mm_struct *mm; unsigned long mm_start; unsigned long mm_range; @@ -253,7 +269,7 @@ struct drm_gpusvm_ctx { }; int drm_gpusvm_init(struct drm_gpusvm *gpusvm, - const char *name, struct drm_device *drm, + const char *name, struct mm_struct *mm, unsigned long mm_start, unsigned long mm_range, unsigned long notifier_size, @@ -287,16 +303,8 @@ drm_gpusvm_range_get(struct drm_gpusvm_range *range); void drm_gpusvm_range_put(struct drm_gpusvm_range *range); -bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range); - -int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range, - const struct drm_gpusvm_ctx *ctx); - -void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range, - const struct drm_gpusvm_ctx *ctx); +bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm, + struct drm_gpusvm_pages *svm_pages); bool drm_gpusvm_has_mapping(struct drm_gpusvm *gpusvm, unsigned long start, unsigned long end); @@ -310,6 +318,8 @@ drm_gpusvm_range_find(struct drm_gpusvm_notifier *notifier, unsigned long start, unsigned long end); void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range, + struct drm_gpusvm_pages *pages, + unsigned int pages_count, const struct mmu_notifier_range *mmu_range); int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, @@ -329,6 +339,23 @@ void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm, unsigned long npages); /** + * drm_gpusvm_init_pages() - Initialize a freshly allocated drm_gpusvm_pages + * @svm_pages: Pointer to the drm_gpusvm_pages to initialize. + * @drm: The DRM device that will own DMA mappings for this pages object. + * + * Drivers that embed one or more drm_gpusvm_pages in their own range + * structure must call this once on each pages instance after allocation, + * before the first drm_gpusvm_get_pages() / unmap / free. + */ +static inline void drm_gpusvm_init_pages(struct drm_gpusvm_pages *svm_pages, + struct drm_device *drm) +{ + memset(svm_pages, 0, sizeof(*svm_pages)); + svm_pages->drm = drm; + svm_pages->notifier_seq = LONG_MAX; +} + +/** * enum drm_gpusvm_scan_result - Scan result from the drm_gpusvm_scan_mm() function. * @DRM_GPUSVM_SCAN_UNPOPULATED: At least one page was not present or inaccessible. * @DRM_GPUSVM_SCAN_EQUAL: All pages belong to the struct dev_pagemap indicated as |
