Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: try harder to avoid regression when merging mode bits

For QXL hw we really want the bits to be replaced as we change
the preferred mode on the fly, and the same goes for virgl when
I get to it, however the original fix for this seems to have caused
a wierd regression on Intel G33 that in a stunning display of failure
at opposition to his normal self, Daniel failed to diagnose.

So we are left doing this, ugly ugly ugly ugly, Daniel you fixed
that G33 yet?, ugly, ugly.

Tested-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>

+57 -26
+7 -2
drivers/gpu/drm/drm_modes.c
··· 1013 1013 /** 1014 1014 * drm_mode_connector_list_update - update the mode list for the connector 1015 1015 * @connector: the connector to update 1016 + * @merge_type_bits: whether to merge or overright type bits. 1016 1017 * 1017 1018 * This moves the modes from the @connector probed_modes list 1018 1019 * to the actual mode list. It compares the probed mode against the current ··· 1022 1021 * This is just a helper functions doesn't validate any modes itself and also 1023 1022 * doesn't prune any invalid modes. Callers need to do that themselves. 1024 1023 */ 1025 - void drm_mode_connector_list_update(struct drm_connector *connector) 1024 + void drm_mode_connector_list_update(struct drm_connector *connector, 1025 + bool merge_type_bits) 1026 1026 { 1027 1027 struct drm_display_mode *mode; 1028 1028 struct drm_display_mode *pmode, *pt; ··· 1041 1039 /* if equal delete the probed mode */ 1042 1040 mode->status = pmode->status; 1043 1041 /* Merge type bits together */ 1044 - mode->type |= pmode->type; 1042 + if (merge_type_bits) 1043 + mode->type |= pmode->type; 1044 + else 1045 + mode->type = pmode->type; 1045 1046 list_del(&pmode->head); 1046 1047 drm_mode_destroy(connector->dev, pmode); 1047 1048 break;
+43 -21
drivers/gpu/drm/drm_probe_helper.c
··· 82 82 return; 83 83 } 84 84 85 - /** 86 - * drm_helper_probe_single_connector_modes - get complete set of display modes 87 - * @connector: connector to probe 88 - * @maxX: max width for modes 89 - * @maxY: max height for modes 90 - * 91 - * Based on the helper callbacks implemented by @connector try to detect all 92 - * valid modes. Modes will first be added to the connector's probed_modes list, 93 - * then culled (based on validity and the @maxX, @maxY parameters) and put into 94 - * the normal modes list. 95 - * 96 - * Intended to be use as a generic implementation of the ->fill_modes() 97 - * @connector vfunc for drivers that use the crtc helpers for output mode 98 - * filtering and detection. 99 - * 100 - * Returns: 101 - * The number of modes found on @connector. 102 - */ 103 - int drm_helper_probe_single_connector_modes(struct drm_connector *connector, 104 - uint32_t maxX, uint32_t maxY) 85 + static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, 86 + uint32_t maxX, uint32_t maxY, bool merge_type_bits) 105 87 { 106 88 struct drm_device *dev = connector->dev; 107 89 struct drm_display_mode *mode; ··· 137 155 if (count == 0) 138 156 goto prune; 139 157 140 - drm_mode_connector_list_update(connector); 158 + drm_mode_connector_list_update(connector, merge_type_bits); 141 159 142 160 if (maxX && maxY) 143 161 drm_mode_validate_size(dev, &connector->modes, maxX, maxY); ··· 176 194 177 195 return count; 178 196 } 197 + 198 + /** 199 + * drm_helper_probe_single_connector_modes - get complete set of display modes 200 + * @connector: connector to probe 201 + * @maxX: max width for modes 202 + * @maxY: max height for modes 203 + * 204 + * Based on the helper callbacks implemented by @connector try to detect all 205 + * valid modes. Modes will first be added to the connector's probed_modes list, 206 + * then culled (based on validity and the @maxX, @maxY parameters) and put into 207 + * the normal modes list. 208 + * 209 + * Intended to be use as a generic implementation of the ->fill_modes() 210 + * @connector vfunc for drivers that use the crtc helpers for output mode 211 + * filtering and detection. 212 + * 213 + * Returns: 214 + * The number of modes found on @connector. 215 + */ 216 + int drm_helper_probe_single_connector_modes(struct drm_connector *connector, 217 + uint32_t maxX, uint32_t maxY) 218 + { 219 + return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, true); 220 + } 179 221 EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); 222 + 223 + /** 224 + * drm_helper_probe_single_connector_modes_nomerge - get complete set of display modes 225 + * @connector: connector to probe 226 + * @maxX: max width for modes 227 + * @maxY: max height for modes 228 + * 229 + * This operates like drm_hehlper_probe_single_connector_modes except it 230 + * replaces the mode bits instead of merging them for preferred modes. 231 + */ 232 + int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector *connector, 233 + uint32_t maxX, uint32_t maxY) 234 + { 235 + return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, false); 236 + } 237 + EXPORT_SYMBOL(drm_helper_probe_single_connector_modes_nomerge); 180 238 181 239 /** 182 240 * drm_kms_helper_hotplug_event - fire off KMS hotplug events
+1 -1
drivers/gpu/drm/qxl/qxl_display.c
··· 841 841 .save = qxl_conn_save, 842 842 .restore = qxl_conn_restore, 843 843 .detect = qxl_conn_detect, 844 - .fill_modes = drm_helper_probe_single_connector_modes, 844 + .fill_modes = drm_helper_probe_single_connector_modes_nomerge, 845 845 .set_property = qxl_conn_set_property, 846 846 .destroy = qxl_conn_destroy, 847 847 };
+1 -1
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
··· 2001 2001 if (du->pref_mode) 2002 2002 list_move(&du->pref_mode->head, &connector->probed_modes); 2003 2003 2004 - drm_mode_connector_list_update(connector); 2004 + drm_mode_connector_list_update(connector, true); 2005 2005 2006 2006 return 1; 2007 2007 }
+4
include/drm/drm_crtc_helper.h
··· 165 165 extern int drm_helper_probe_single_connector_modes(struct drm_connector 166 166 *connector, uint32_t maxX, 167 167 uint32_t maxY); 168 + extern int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector 169 + *connector, 170 + uint32_t maxX, 171 + uint32_t maxY); 168 172 extern void drm_kms_helper_poll_init(struct drm_device *dev); 169 173 extern void drm_kms_helper_poll_fini(struct drm_device *dev); 170 174 extern bool drm_helper_hpd_irq_event(struct drm_device *dev);
+1 -1
include/drm/drm_modes.h
··· 223 223 void drm_mode_prune_invalid(struct drm_device *dev, 224 224 struct list_head *mode_list, bool verbose); 225 225 void drm_mode_sort(struct list_head *mode_list); 226 - void drm_mode_connector_list_update(struct drm_connector *connector); 226 + void drm_mode_connector_list_update(struct drm_connector *connector, bool merge_type_bits); 227 227 228 228 /* parsing cmdline modes */ 229 229 bool