| From fc43810b29bb72a90e2505448d65abde52e96714 Mon Sep 17 00:00:00 2001 |
| From: Hans de Goede <hdegoede@redhat.com> |
| Date: Thu, 24 Oct 2019 10:52:53 +0200 |
| Subject: [PATCH] drm/nouveau: Fix drm-core using atomic code-paths on pre-nv50 |
| hardware |
| |
| commit 64d17f25dcad518461ccf0c260544e1e379c5b35 upstream. |
| |
| We do not support atomic modesetting on pre-nv50 hardware, but until now |
| our connector code was setting drm_connector->state on pre-nv50 hardware. |
| |
| This causes the core to enter atomic modesetting paths in at least: |
| |
| 1. drm_connector_get_encoder(), returning connector->state->best_encoder |
| which is always 0, causing us to always report 0 as encoder_id in |
| the drmModeConnector struct returned by drmModeGetConnector(). |
| |
| 2. drm_encoder_get_crtc(), returning NULL because uses_atomic get set, |
| causing us to always report 0 as crtc_id in the drmModeEncoder struct |
| returned by drmModeGetEncoder() |
| |
| Which in turn confuses userspace, at least plymouth thinks that the pipe |
| has changed because of this and tries to reconfigure it unnecessarily. |
| |
| More in general we should not set drm_connector->state in the non-atomic |
| code as this violates the drm-core's expectations. |
| |
| This commit fixes this by using a nouveau_conn_atom struct embedded in the |
| nouveau_connector struct for property handling in the non-atomic case. |
| |
| Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1706557 |
| Signed-off-by: Hans de Goede <hdegoede@redhat.com> |
| Signed-off-by: Ben Skeggs <bskeggs@redhat.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c |
| index 3a14365e3d23..6bd9f55a3f0b 100644 |
| --- a/drivers/gpu/drm/nouveau/nouveau_connector.c |
| +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c |
| @@ -246,14 +246,22 @@ nouveau_conn_atomic_duplicate_state(struct drm_connector *connector) |
| void |
| nouveau_conn_reset(struct drm_connector *connector) |
| { |
| + struct nouveau_connector *nv_connector = nouveau_connector(connector); |
| struct nouveau_conn_atom *asyc; |
| |
| - if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL)))) |
| - return; |
| + if (drm_drv_uses_atomic_modeset(connector->dev)) { |
| + if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL)))) |
| + return; |
| + |
| + if (connector->state) |
| + nouveau_conn_atomic_destroy_state(connector, |
| + connector->state); |
| + |
| + __drm_atomic_helper_connector_reset(connector, &asyc->state); |
| + } else { |
| + asyc = &nv_connector->properties_state; |
| + } |
| |
| - if (connector->state) |
| - nouveau_conn_atomic_destroy_state(connector, connector->state); |
| - __drm_atomic_helper_connector_reset(connector, &asyc->state); |
| asyc->dither.mode = DITHERING_MODE_AUTO; |
| asyc->dither.depth = DITHERING_DEPTH_AUTO; |
| asyc->scaler.mode = DRM_MODE_SCALE_NONE; |
| @@ -277,8 +285,14 @@ void |
| nouveau_conn_attach_properties(struct drm_connector *connector) |
| { |
| struct drm_device *dev = connector->dev; |
| - struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state); |
| struct nouveau_display *disp = nouveau_display(dev); |
| + struct nouveau_connector *nv_connector = nouveau_connector(connector); |
| + struct nouveau_conn_atom *armc; |
| + |
| + if (drm_drv_uses_atomic_modeset(connector->dev)) |
| + armc = nouveau_conn_atom(connector->state); |
| + else |
| + armc = &nv_connector->properties_state; |
| |
| /* Init DVI-I specific properties. */ |
| if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) |
| @@ -750,9 +764,9 @@ static int |
| nouveau_connector_set_property(struct drm_connector *connector, |
| struct drm_property *property, uint64_t value) |
| { |
| - struct nouveau_conn_atom *asyc = nouveau_conn_atom(connector->state); |
| struct nouveau_connector *nv_connector = nouveau_connector(connector); |
| struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; |
| + struct nouveau_conn_atom *asyc = &nv_connector->properties_state; |
| struct drm_encoder *encoder = to_drm_encoder(nv_encoder); |
| int ret; |
| |
| diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h |
| index de9588420884..de84fb4708c7 100644 |
| --- a/drivers/gpu/drm/nouveau/nouveau_connector.h |
| +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h |
| @@ -118,6 +118,12 @@ struct nouveau_connector { |
| #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT |
| struct nouveau_backlight *backlight; |
| #endif |
| + /* |
| + * Our connector property code expects a nouveau_conn_atom struct |
| + * even on pre-nv50 where we do not support atomic. This embedded |
| + * version gets used in the non atomic modeset case. |
| + */ |
| + struct nouveau_conn_atom properties_state; |
| }; |
| |
| static inline struct nouveau_connector *nouveau_connector( |
| -- |
| 2.7.4 |
| |