From 1e3e4cae75cd21bdb8d67ac5a3848ea2d0f84cc6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 18 May 2020 14:22:28 +0000 Subject: drm: DPMS is no longer the only mutable connector prop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are a bunch of other writable connector properties now. Signed-off-by: Simon Ser Cc: Daniel Vetter Cc: Ville Syrjala Cc: Pekka Paalanen Cc: Michel Dänzer Reviewed-by: Daniel Vetter Reviewed-by: Pekka Paalanen Link: https://patchwork.freedesktop.org/patch/msgid/vrfq3PQ_YaPv75xE6-4QeyyLkevKNLpQo8JgnX6EnEcYaFRXxSg98QECUOmHe_eMirwPB0qNRXHE_jzEkXDb3J3YS2OuZXAZgJFnNMLm6W4=@emersion.fr --- drivers/gpu/drm/drm_connector.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu/drm/drm_connector.c') diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index b1099e1251a2..f2b20fd66319 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -948,8 +948,7 @@ static const struct drm_prop_enum_list dp_colorspaces[] = { * connector is linked to. Drivers should never set this property directly, * it is handled by the DRM core by calling the &drm_connector_funcs.dpms * callback. For atomic drivers the remapping to the "ACTIVE" property is - * implemented in the DRM core. This is the only standard connector - * property that userspace can change. + * implemented in the DRM core. * * Note that this property cannot be set through the MODE_ATOMIC ioctl, * userspace must use "ACTIVE" on the CRTC instead. -- cgit v1.2.3 From a66da873c424fd9a695ae945d6e0160bb467dcf9 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 4 Jun 2020 09:20:23 +0000 Subject: drm: document how user-space should use link-status Describe what a "BAD" link-status means for user-space and how it should handle it. The logic described has been implemented in igt [1]. v2: - Change wording to avoid "enabled" (Daniel) - Add paragraph about multiple connectors sharing the same CRTC (Pekka) - Add paragraph about performing an atomic commit on a connector without updating the link-status property (Daniel) v3: - Fix description of what happens when link-status isn't reset to "GOOD", and when link-status is reset without ALLOW_MODESET (Daniel, Ville) - Changing link-status to "BAD" is a no-op - Clearly state that "BAD" means black screen (Manasi) [1]: https://gitlab.freedesktop.org/drm/igt-gpu-tools/-/commit/fbe61f529737191d0920521946a575bd55f00fbe Signed-off-by: Simon Ser Cc: Daniel Vetter Cc: Manasi Navare Cc: Ville Syrjala Cc: Pekka Paalanen Reviewed-by: Daniel Vetter Acked-by: Pekka Paalanen Link: https://patchwork.freedesktop.org/patch/msgid/kFylMmeRMGJk-oi8f-Td8A7GNa1C-GsK23-vjKg77VhWfwpkLJg7QxFlQ_g9KdVxZiyWl9eJWpUGa5PYasR9YcyvIbuBmHVfKeHb4rH0yTM=@emersion.fr --- drivers/gpu/drm/drm_connector.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/gpu/drm/drm_connector.c') diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index f2b20fd66319..7a6779cab12f 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -994,6 +994,32 @@ static const struct drm_prop_enum_list dp_colorspaces[] = { * after modeset, the kernel driver may set this to "BAD" and issue a * hotplug uevent. Drivers should update this value using * drm_connector_set_link_status_property(). + * + * When user-space receives the hotplug uevent and detects a "BAD" + * link-status, the sink doesn't receive pixels anymore (e.g. the screen + * becomes completely black). The list of available modes may have + * changed. User-space is expected to pick a new mode if the current one + * has disappeared and perform a new modeset with link-status set to + * "GOOD" to re-enable the connector. + * + * If multiple connectors share the same CRTC and one of them gets a "BAD" + * link-status, the other are unaffected (ie. the sinks still continue to + * receive pixels). + * + * When user-space performs an atomic commit on a connector with a "BAD" + * link-status without resetting the property to "GOOD", the sink may + * still not receive pixels. When user-space performs an atomic commit + * which resets the link-status property to "GOOD" without the + * ALLOW_MODESET flag set, it might fail because a modeset is required. + * + * User-space can only change link-status to "GOOD", changing it to "BAD" + * is a no-op. + * + * For backwards compatibility with non-atomic userspace the kernel + * tries to automatically set the link-status back to "GOOD" in the + * SETCRTC IOCTL. This might fail if the mode is no longer valid, similar + * to how it might fail if a different screen has been connected in the + * interim. * non_desktop: * Indicates the output should be ignored for purposes of displaying a * standard desktop environment or console. This is most likely because -- cgit v1.2.3 From 84e543bc9d1dc550132ba25b72df28d40cc44333 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 26 Jun 2020 22:42:52 +0200 Subject: drm/connector: fix minor typos in comments Some of these comments are part of the Linux GPU Driver Developer's Guide. Fix some minor typo in the comments and remove a repeated 'the'. Signed-off-by: Antonio Borneo Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20200626204252.44565-1-antonio.borneo@st.com --- drivers/gpu/drm/drm_connector.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/drm_connector.c') diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 7a6779cab12f..a57b05561448 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -37,7 +37,7 @@ * DOC: overview * * In DRM connectors are the general abstraction for display sinks, and include - * als fixed panels or anything else that can display pixels in some form. As + * also fixed panels or anything else that can display pixels in some form. As * opposed to all other KMS objects representing hardware (like CRTC, encoder or * plane abstractions) connectors can be hotplugged and unplugged at runtime. * Hence they are reference-counted using drm_connector_get() and @@ -128,7 +128,7 @@ EXPORT_SYMBOL(drm_get_connector_type_name); /** * drm_connector_get_cmdline_mode - reads the user's cmdline mode - * @connector: connector to quwery + * @connector: connector to query * * The kernel supports per-connector configuration of its consoles through * use of the video= parameter. This function parses that option and @@ -985,7 +985,7 @@ static const struct drm_prop_enum_list dp_colorspaces[] = { * DP MST sinks), or high-res integrated panels (like dual-link DSI) which * are not gen-locked. Note that for tiled panels which are genlocked, like * dual-link LVDS or dual-link DSI, the driver should try to not expose the - * tiling and virtualize both &drm_crtc and &drm_plane if needed. Drivers + * tiling and virtualise both &drm_crtc and &drm_plane if needed. Drivers * should update this value using drm_connector_set_tile_property(). * Userspace cannot change this property. * link-status: @@ -1151,7 +1151,7 @@ static const struct drm_prop_enum_list dp_colorspaces[] = { * * It will even need to do colorspace conversion and get all layers * to one common colorspace for blending. It can use either GL, Media - * or display engine to get this done based on the capabilties of the + * or display engine to get this done based on the capabilities of the * associated hardware. * * Driver expects metadata to be put in &struct hdr_output_metadata @@ -1634,7 +1634,7 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); * variable refresh rate capability for a connector. * * Returns: - * Zero on success, negative errono on failure. + * Zero on success, negative errno on failure. */ int drm_connector_attach_vrr_capable_property( struct drm_connector *connector) @@ -1779,7 +1779,7 @@ EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); * HDMI connectors. * * Returns: - * Zero on success, negative errono on failure. + * Zero on success, negative errno on failure. */ int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector) { @@ -1808,7 +1808,7 @@ EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); * DP connectors. * * Returns: - * Zero on success, negative errono on failure. + * Zero on success, negative errno on failure. */ int drm_mode_create_dp_colorspace_property(struct drm_connector *connector) { @@ -1860,7 +1860,7 @@ EXPORT_SYMBOL(drm_mode_create_content_type_property); * drm_mode_create_suggested_offset_properties - create suggests offset properties * @dev: DRM device * - * Create the the suggested x/y offset property for connectors. + * Create the suggested x/y offset property for connectors. */ int drm_mode_create_suggested_offset_properties(struct drm_device *dev) { @@ -1983,7 +1983,7 @@ int drm_connector_update_edid_property(struct drm_connector *connector, size = EDID_LENGTH * (1 + edid->extensions); /* Set the display info, using edid if available, otherwise - * reseting the values to defaults. This duplicates the work + * resetting the values to defaults. This duplicates the work * done in drm_add_edid_modes, but that function is not * consistently called before this one in all drivers and the * computation is cheap enough that it seems better to @@ -2096,7 +2096,7 @@ void drm_connector_set_vrr_capable_property( EXPORT_SYMBOL(drm_connector_set_vrr_capable_property); /** - * drm_connector_set_panel_orientation - sets the connecter's panel_orientation + * drm_connector_set_panel_orientation - sets the connector's panel_orientation * @connector: connector for which to set the panel-orientation property. * @panel_orientation: drm_panel_orientation value to set * @@ -2151,7 +2151,7 @@ EXPORT_SYMBOL(drm_connector_set_panel_orientation); /** * drm_connector_set_panel_orientation_with_quirk - - * set the connecter's panel_orientation after checking for quirks + * set the connector's panel_orientation after checking for quirks * @connector: connector for which to init the panel-orientation property. * @panel_orientation: drm_panel_orientation value to set * @width: width in pixels of the panel, used for panel quirk detection -- cgit v1.2.3 From 5186421cbfe250002308d4d759674214b385752f Mon Sep 17 00:00:00 2001 From: Stanislav Lisovskiy Date: Tue, 30 Jun 2020 05:56:59 +0530 Subject: drm: Introduce epoch counter to drm_connector This counter will be used by drm_helper_probe_detect caller to determine if anything had changed(including edid, connection status and etc). Hardware specific driver detect hooks are responsible for updating this counter when some change is detected to notify the drm part, which can trigger for example hotplug event. Also now call drm_connector_update_edid_property right after we get edid always to make sure there is a unified way to handle edid change, without having to change tons of source code as currently drm_connector_update_edid_property is called only in certain cases like reprobing and not right after edid is actually updated. v2: Added documentation for the new counter. Rename change_counter to epoch_counter. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105540 Signed-off-by: Stanislav Lisovskiy Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20200630002700.5451-3-kunal1.joshi@intel.com --- drivers/gpu/drm/drm_connector.c | 16 ++++++++++++++++ drivers/gpu/drm/drm_edid.c | 8 +++++--- drivers/gpu/drm/drm_probe_helper.c | 38 +++++++++++++++++++++++++++++++++----- include/drm/drm_connector.h | 2 ++ 4 files changed, 56 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/drm_connector.c') diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 480b3770cddb..d6e86227542e 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -269,6 +269,7 @@ int drm_connector_init(struct drm_device *dev, INIT_LIST_HEAD(&connector->modes); mutex_init(&connector->mutex); connector->edid_blob_ptr = NULL; + connector->epoch_counter = 0; connector->tile_blob_ptr = NULL; connector->status = connector_status_unknown; connector->display_info.panel_orientation = @@ -1979,6 +1980,7 @@ int drm_connector_update_edid_property(struct drm_connector *connector, struct drm_device *dev = connector->dev; size_t size = 0; int ret; + const struct edid *old_edid; /* ignore requests to set edid when overridden */ if (connector->override_edid) @@ -2002,6 +2004,20 @@ int drm_connector_update_edid_property(struct drm_connector *connector, drm_update_tile_info(connector, edid); + if (connector->edid_blob_ptr) { + old_edid = (const struct edid *)connector->edid_blob_ptr->data; + if (old_edid) { + if (!drm_edid_are_equal(edid, old_edid)) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Edid was changed.\n", + connector->base.id, connector->name); + + connector->epoch_counter += 1; + DRM_DEBUG_KMS("Updating change counter to %llu\n", + connector->epoch_counter); + } + } + } + drm_object_property_set_value(&connector->base, dev->mode_config.non_desktop_property, connector->display_info.non_desktop); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 920ac9ef6018..8b559b82a15e 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1632,7 +1632,6 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) return false; if (edid1) { - edid1_len = EDID_LENGTH * (1 + edid1->extensions); edid2_len = EDID_LENGTH * (1 + edid2->extensions); @@ -1647,7 +1646,6 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) } EXPORT_SYMBOL(drm_edid_are_equal); - /** * drm_edid_block_valid - Sanity check the EDID block (base or extension) * @raw_edid: pointer to raw EDID block @@ -2050,13 +2048,17 @@ EXPORT_SYMBOL(drm_probe_ddc); struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { + struct edid *edid; + if (connector->force == DRM_FORCE_OFF) return NULL; if (connector->force == DRM_FORCE_UNSPECIFIED && !drm_probe_ddc(adapter)) return NULL; - return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); + edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); + drm_connector_update_edid_property(connector, edid); + return edid; } EXPORT_SYMBOL(drm_get_edid); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 09e872e61315..e0ed58d291ed 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -292,6 +292,9 @@ retry: if (WARN_ON(ret < 0)) ret = connector_status_unknown; + if (ret != connector->status) + connector->epoch_counter += 1; + drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); @@ -325,11 +328,16 @@ drm_helper_probe_detect(struct drm_connector *connector, return ret; if (funcs->detect_ctx) - return funcs->detect_ctx(connector, ctx, force); + ret = funcs->detect_ctx(connector, ctx, force); else if (connector->funcs->detect) - return connector->funcs->detect(connector, force); + ret = connector->funcs->detect(connector, force); else - return connector_status_connected; + ret = connector_status_connected; + + if (ret != connector->status) + connector->epoch_counter += 1; + + return ret; } EXPORT_SYMBOL(drm_helper_probe_detect); @@ -779,6 +787,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) struct drm_connector_list_iter conn_iter; enum drm_connector_status old_status; bool changed = false; + u64 old_epoch_counter; if (!dev->mode_config.poll_enabled) return false; @@ -792,20 +801,39 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) old_status = connector->status; + old_epoch_counter = connector->epoch_counter; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Old epoch counter %llu\n", connector->base.id, + connector->name, + old_epoch_counter); + connector->status = drm_helper_probe_detect(connector, NULL, false); DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", connector->base.id, connector->name, drm_get_connector_status_name(old_status), drm_get_connector_status_name(connector->status)); - if (old_status != connector->status) + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] New epoch counter %llu\n", + connector->base.id, + connector->name, + connector->epoch_counter); + + /* + * Check if epoch counter had changed, meaning that we need + * to send a uevent. + */ + if (old_epoch_counter != connector->epoch_counter) changed = true; + } drm_connector_list_iter_end(&conn_iter); mutex_unlock(&dev->mode_config.mutex); - if (changed) + if (changed) { drm_kms_helper_hotplug_event(dev); + DRM_DEBUG_KMS("Sent hotplug event\n"); + } return changed; } diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index fd543d1db9b2..6a451b86c454 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1329,6 +1329,8 @@ struct drm_connector { enum drm_connector_force force; /** @override_edid: has the EDID been overwritten through debugfs for testing? */ bool override_edid; + /** @epoch_counter: used to detect any other changes in connector, besides status */ + u64 epoch_counter; /** * @possible_encoders: Bit mask of encoders that can drive this -- cgit v1.2.3 From 948de84233d32be56e0b7ee5c1c4b2d960efee27 Mon Sep 17 00:00:00 2001 From: Suraj Upadhyay Date: Thu, 2 Jul 2020 18:53:32 +0530 Subject: drm : Insert blank lines after declarations. Resolve checkpatch issues for missing blank lines after declarations. Issues found in multiple files with checkpatch.pl. Signed-off-by: Suraj Upadhyay Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20200702131749.GA25710@blackclown --- drivers/gpu/drm/drm_atomic.c | 1 + drivers/gpu/drm/drm_atomic_uapi.c | 7 +++++++ drivers/gpu/drm/drm_bufs.c | 6 ++++++ drivers/gpu/drm/drm_connector.c | 2 ++ drivers/gpu/drm/drm_crtc.c | 1 + drivers/gpu/drm/drm_crtc_helper.c | 3 +++ drivers/gpu/drm/drm_dp_helper.c | 1 + drivers/gpu/drm/drm_dp_mst_topology.c | 20 ++++++++++++++++++++ drivers/gpu/drm/drm_edid.c | 17 +++++++++++++++++ drivers/gpu/drm/drm_file.c | 2 ++ drivers/gpu/drm/drm_framebuffer.c | 1 + drivers/gpu/drm/drm_ioc32.c | 2 ++ drivers/gpu/drm/drm_lease.c | 4 ++++ drivers/gpu/drm/drm_lock.c | 1 + drivers/gpu/drm/drm_mode_config.c | 1 + drivers/gpu/drm/drm_pci.c | 1 + drivers/gpu/drm/drm_plane.c | 1 + drivers/gpu/drm/drm_prime.c | 1 + drivers/gpu/drm/drm_syncobj.c | 1 + drivers/gpu/drm/drm_vblank.c | 1 + 20 files changed, 74 insertions(+) (limited to 'drivers/gpu/drm/drm_connector.c') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 965173fd0ac2..58527f151984 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -575,6 +575,7 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, fb->modifier); if (ret) { struct drm_format_name_buf format_name; + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid pixel format %s, modifier 0x%llx\n", plane->base.id, plane->name, drm_get_format_name(fb->format->format, diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index a1e5e262bae2..25c269bc4681 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -522,6 +522,7 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, if (property == config->prop_fb_id) { struct drm_framebuffer *fb; + fb = drm_framebuffer_lookup(dev, file_priv, val); drm_atomic_set_fb_for_plane(state, fb); if (fb) @@ -539,6 +540,7 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, } else if (property == config->prop_crtc_id) { struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val); + if (val && !crtc) return -EACCES; return drm_atomic_set_crtc_for_plane(state, crtc); @@ -681,6 +683,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, if (property == config->prop_crtc_id) { struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val); + if (val && !crtc) return -EACCES; return drm_atomic_set_crtc_for_connector(state, crtc); @@ -754,6 +757,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, } else if (property == config->writeback_fb_id_property) { struct drm_framebuffer *fb; int ret; + fb = drm_framebuffer_lookup(dev, file_priv, val); ret = drm_atomic_set_writeback_fb_for_connector(state, fb); if (fb) @@ -861,6 +865,7 @@ int drm_atomic_get_property(struct drm_mode_object *obj, switch (obj->type) { case DRM_MODE_OBJECT_CONNECTOR: { struct drm_connector *connector = obj_to_connector(obj); + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); ret = drm_atomic_connector_get_property(connector, connector->state, property, val); @@ -868,6 +873,7 @@ int drm_atomic_get_property(struct drm_mode_object *obj, } case DRM_MODE_OBJECT_CRTC: { struct drm_crtc *crtc = obj_to_crtc(obj); + WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); ret = drm_atomic_crtc_get_property(crtc, crtc->state, property, val); @@ -875,6 +881,7 @@ int drm_atomic_get_property(struct drm_mode_object *obj, } case DRM_MODE_OBJECT_PLANE: { struct drm_plane *plane = obj_to_plane(obj); + WARN_ON(!drm_modeset_is_locked(&plane->mutex)); ret = drm_atomic_plane_get_property(plane, plane->state, property, val); diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index ef26ac57f039..a0735fbc144b 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -53,6 +53,7 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, struct drm_local_map *map) { struct drm_map_list *entry; + list_for_each_entry(entry, &dev->maplist, head) { /* * Because the kernel-userspace ABI is fixed at a 32-bit offset @@ -102,6 +103,7 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash, if (!use_hashed_handle) { int ret; + hash->key = user_token >> PAGE_SHIFT; ret = drm_ht_insert_item(&dev->map_hash, hash); if (ret != -EINVAL) @@ -391,6 +393,7 @@ struct drm_local_map *drm_legacy_findmap(struct drm_device *dev, unsigned int token) { struct drm_map_list *_entry; + list_for_each_entry(_entry, &dev->maplist, head) if (_entry->user_token == token) return _entry->map; @@ -1323,6 +1326,7 @@ int __drm_legacy_infobufs(struct drm_device *dev, if (*p >= count) { for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { struct drm_buf_entry *from = &dma->bufs[i]; + if (from->buf_count) { if (f(data, count, from) < 0) return -EFAULT; @@ -1359,6 +1363,7 @@ int drm_legacy_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_buf_info *request = data; + return __drm_legacy_infobufs(dev, data, &request->count, copy_one_buf); } @@ -1570,6 +1575,7 @@ int drm_legacy_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_buf_map *request = data; + return __drm_legacy_mapbufs(dev, data, &request->count, &request->virtual, map_one_buf, file_priv); diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index d6e86227542e..00e40a26a800 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -2409,6 +2409,7 @@ static void drm_tile_group_free(struct kref *kref) { struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); struct drm_device *dev = tg->dev; + mutex_lock(&dev->mode_config.idr_mutex); idr_remove(&dev->mode_config.tile_idr, tg->id); mutex_unlock(&dev->mode_config.idr_mutex); @@ -2444,6 +2445,7 @@ struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, { struct drm_tile_group *tg; int id; + mutex_lock(&dev->mode_config.idr_mutex); idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { if (!memcmp(tg->group_data, topology, 8)) { diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f1216088f65f..283bcc4362ca 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -656,6 +656,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, fb->modifier); if (ret) { struct drm_format_name_buf format_name; + DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n", drm_get_format_name(fb->format->format, &format_name), diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index a4d36aca45ea..bff917531f33 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -185,6 +185,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) drm_for_each_crtc(crtc, dev) { const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc->enabled = drm_helper_crtc_in_use(crtc); if (!crtc->enabled) { if (crtc_funcs->disable) @@ -884,6 +885,7 @@ int drm_helper_connector_dpms(struct drm_connector *connector, int mode) if (mode < old_dpms) { if (crtc) { const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + if (crtc_funcs->dpms) (*crtc_funcs->dpms) (crtc, drm_helper_choose_crtc_dpms(crtc)); @@ -898,6 +900,7 @@ int drm_helper_connector_dpms(struct drm_connector *connector, int mode) drm_helper_encoder_dpms(encoder, encoder_dpms); if (crtc) { const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + if (crtc_funcs->dpms) (*crtc_funcs->dpms) (crtc, drm_helper_choose_crtc_dpms(crtc)); diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 6d716dcb432c..51ffa449bdd7 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -57,6 +57,7 @@ static u8 dp_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE], int i = DP_LANE0_1_STATUS + (lane >> 1); int s = (lane & 1) * 4; u8 l = dp_link_status(link_status, i); + return (l >> s) & 0xf; } diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index b2f5a84b4cfb..09b32289497e 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -259,6 +259,7 @@ static u8 drm_dp_msg_data_crc4(const uint8_t *data, u8 number_of_bytes) static inline u8 drm_dp_calc_sb_hdr_size(struct drm_dp_sideband_msg_hdr *hdr) { u8 size = 3; + size += (hdr->lct / 2); return size; } @@ -269,6 +270,7 @@ static void drm_dp_encode_sideband_msg_hdr(struct drm_dp_sideband_msg_hdr *hdr, int idx = 0; int i; u8 crc4; + buf[idx++] = ((hdr->lct & 0xf) << 4) | (hdr->lcr & 0xf); for (i = 0; i < (hdr->lct / 2); i++) buf[idx++] = hdr->rad[i]; @@ -289,6 +291,7 @@ static bool drm_dp_decode_sideband_msg_hdr(struct drm_dp_sideband_msg_hdr *hdr, u8 len; int i; u8 idx; + if (buf[0] == 0) return false; len = 3; @@ -326,6 +329,7 @@ drm_dp_encode_sideband_req(const struct drm_dp_sideband_msg_req_body *req, int idx = 0; int i; u8 *buf = raw->msg; + buf[idx++] = req->req_type & 0x7f; switch (req->req_type) { @@ -673,6 +677,7 @@ drm_dp_mst_dump_sideband_msg_tx(struct drm_printer *p, static void drm_dp_crc_sideband_chunk_req(u8 *msg, u8 len) { u8 crc4; + crc4 = drm_dp_msg_data_crc4(msg, len); msg[len] = crc4; } @@ -747,6 +752,7 @@ static bool drm_dp_sideband_parse_link_address(struct drm_dp_sideband_msg_rx *ra { int idx = 1; int i; + memcpy(repmsg->u.link_addr.guid, &raw->msg[idx], 16); idx += 16; repmsg->u.link_addr.nports = raw->msg[idx] & 0xf; @@ -798,6 +804,7 @@ static bool drm_dp_sideband_parse_remote_dpcd_read(struct drm_dp_sideband_msg_rx struct drm_dp_sideband_msg_reply_body *repmsg) { int idx = 1; + repmsg->u.remote_dpcd_read_ack.port_number = raw->msg[idx] & 0xf; idx++; if (idx > raw->curlen) @@ -818,6 +825,7 @@ static bool drm_dp_sideband_parse_remote_dpcd_write(struct drm_dp_sideband_msg_r struct drm_dp_sideband_msg_reply_body *repmsg) { int idx = 1; + repmsg->u.remote_dpcd_write_ack.port_number = raw->msg[idx] & 0xf; idx++; if (idx > raw->curlen) @@ -851,6 +859,7 @@ static bool drm_dp_sideband_parse_enum_path_resources_ack(struct drm_dp_sideband struct drm_dp_sideband_msg_reply_body *repmsg) { int idx = 1; + repmsg->u.path_resources.port_number = (raw->msg[idx] >> 4) & 0xf; repmsg->u.path_resources.fec_capable = raw->msg[idx] & 0x1; idx++; @@ -874,6 +883,7 @@ static bool drm_dp_sideband_parse_allocate_payload_ack(struct drm_dp_sideband_ms struct drm_dp_sideband_msg_reply_body *repmsg) { int idx = 1; + repmsg->u.allocate_payload.port_number = (raw->msg[idx] >> 4) & 0xf; idx++; if (idx > raw->curlen) @@ -896,6 +906,7 @@ static bool drm_dp_sideband_parse_query_payload_ack(struct drm_dp_sideband_msg_r struct drm_dp_sideband_msg_reply_body *repmsg) { int idx = 1; + repmsg->u.query_payload.port_number = (raw->msg[idx] >> 4) & 0xf; idx++; if (idx > raw->curlen) @@ -1082,6 +1093,7 @@ static void build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, u8 *sdp_stream_sink) { struct drm_dp_sideband_msg_req_body req; + memset(&req, 0, sizeof(req)); req.req_type = DP_ALLOCATE_PAYLOAD; req.u.allocate_payload.port_number = port_num; @@ -1142,6 +1154,7 @@ static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr, int vcpi) { int i; + if (vcpi == 0) return; @@ -1940,6 +1953,7 @@ static u8 drm_dp_calculate_rad(struct drm_dp_mst_port *port, int parent_lct = port->parent->lct; int shift = 4; int idx = (parent_lct - 1) / 2; + if (parent_lct > 1) { memcpy(rad, port->parent->rad, idx + 1); shift = (parent_lct % 2) ? 4 : 0; @@ -2118,10 +2132,12 @@ static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb, { int i; char temp[8]; + snprintf(proppath, proppath_size, "mst:%d", mstb->mgr->conn_base_id); for (i = 0; i < (mstb->lct - 1); i++) { int shift = (i % 2) ? 0 : 4; int port_num = (mstb->rad[i / 2] >> shift) & 0xf; + snprintf(temp, sizeof(temp), "-%d", port_num); strlcat(proppath, temp, proppath_size); } @@ -3158,6 +3174,7 @@ static int drm_dp_create_payload_step2(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_payload *payload) { int ret; + ret = drm_dp_payload_send_msg(mgr, port, id, port->vcpi.pbn); if (ret < 0) return ret; @@ -3314,6 +3331,7 @@ int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr) struct drm_dp_mst_port *port; int i; int ret = 0; + mutex_lock(&mgr->payload_lock); for (i = 0; i < mgr->max_payloads; i++) { @@ -3779,6 +3797,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) /* Were we actually expecting a response, and from this mstb? */ if (!txmsg || txmsg->dst != mstb) { struct drm_dp_sideband_msg_hdr *hdr; + hdr = &msg->initial_hdr; DRM_DEBUG_KMS("Got MST reply with no msg %p %d %d %02x %02x\n", mstb, hdr->seqno, hdr->lct, hdr->rad[0], @@ -4326,6 +4345,7 @@ EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi); int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { int slots = 0; + port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) return slots; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 8b559b82a15e..252e89cb54a3 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1672,6 +1672,7 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, if (block == 0) { int score = drm_edid_header_is_valid(raw_edid); + if (score == 8) { if (edid_corrupt) *edid_corrupt = false; @@ -2223,6 +2224,7 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, for (i = 0; i < ARRAY_SIZE(drm_dmt_modes); i++) { const struct drm_display_mode *ptr = &drm_dmt_modes[i]; + if (hsize != ptr->hdisplay) continue; if (vsize != ptr->vdisplay) @@ -2294,6 +2296,7 @@ drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure) for (i = 1; i <= raw_edid[0x7e]; i++) { u8 *ext = raw_edid + (i * EDID_LENGTH); + switch (*ext) { case CEA_EXT: cea_for_each_detailed_block(ext, cb, closure); @@ -2325,6 +2328,7 @@ drm_monitor_supports_rb(struct edid *edid) { if (edid->revision >= 4) { bool ret = false; + drm_for_each_detailed_block((u8 *)edid, is_rb, &ret); return ret; } @@ -2349,6 +2353,7 @@ static int drm_gtf2_hbreak(struct edid *edid) { u8 *r = NULL; + drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r); return r ? (r[12] * 2) : 0; } @@ -2357,6 +2362,7 @@ static int drm_gtf2_2c(struct edid *edid) { u8 *r = NULL; + drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r); return r ? r[13] : 0; } @@ -2365,6 +2371,7 @@ static int drm_gtf2_m(struct edid *edid) { u8 *r = NULL; + drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r); return r ? (r[15] << 8) + r[14] : 0; } @@ -2373,6 +2380,7 @@ static int drm_gtf2_k(struct edid *edid) { u8 *r = NULL; + drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r); return r ? r[16] : 0; } @@ -2381,6 +2389,7 @@ static int drm_gtf2_2j(struct edid *edid) { u8 *r = NULL; + drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r); return r ? r[17] : 0; } @@ -2832,6 +2841,7 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid, for (i = 0; i < ARRAY_SIZE(extra_modes); i++) { const struct minimode *m = &extra_modes[i]; + newmode = drm_gtf_mode(dev, m->w, m->h, m->r, 0, 0); if (!newmode) return modes; @@ -2861,6 +2871,7 @@ drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid, for (i = 0; i < ARRAY_SIZE(extra_modes); i++) { const struct minimode *m = &extra_modes[i]; + newmode = drm_cvt_mode(dev, m->w, m->h, m->r, rb, 0, 0); if (!newmode) return modes; @@ -2996,6 +3007,7 @@ add_established_modes(struct drm_connector *connector, struct edid *edid) for (i = 0; i <= EDID_EST_TIMINGS; i++) { if (est_bits & (1<data.other_data.data.cvt[i]); if (!memcmp(cvt->code, empty, 3)) @@ -3726,6 +3739,7 @@ do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len) for (i = 0; i < len; i++) { struct drm_display_mode *mode; + mode = drm_display_mode_from_vic_index(connector, db, len, i); if (mode) { /* @@ -4567,6 +4581,7 @@ int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads) if (cea_db_tag(db) == AUDIO_BLOCK) { int j; + dbl = cea_db_payload_len(db); count = dbl / 3; /* SAD is 3B */ @@ -5170,6 +5185,7 @@ static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *d unsigned vsync_width = (timings->vsw[0] | timings->vsw[1] << 8) + 1; bool hsync_positive = (timings->hsync[1] >> 7) & 0x1; bool vsync_positive = (timings->vsync[1] >> 7) & 0x1; + mode = drm_mode_create(dev); if (!mode) return NULL; @@ -5351,6 +5367,7 @@ int drm_add_modes_noedid(struct drm_connector *connector, for (i = 0; i < count; i++) { const struct drm_display_mode *ptr = &drm_dmt_modes[i]; + if (hdisplay && vdisplay) { /* * Only when two are valid, they will be used to check diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 02b5ab626edb..0ac4566ae3f4 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -375,6 +375,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) */ if (!dev->hose) { struct pci_dev *pci_dev; + pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); if (pci_dev) { dev->hose = pci_dev->sysdata; @@ -758,6 +759,7 @@ void drm_event_cancel_free(struct drm_device *dev, struct drm_pending_event *p) { unsigned long flags; + spin_lock_irqsave(&dev->event_lock, flags); if (p->file_priv) { p->file_priv->event_space += p->event->length; diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 0375b3d7f8d0..df656366a530 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -1110,6 +1110,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) if (drm_framebuffer_read_refcount(fb) > 1) { if (drm_drv_uses_atomic_modeset(dev)) { int ret = atomic_remove_fb(fb); + WARN(ret, "atomic remove_fb failed with %i\n", ret); } else legacy_remove_fb(fb); diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index ff5d40036e21..f86448ab1fe0 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -388,6 +388,7 @@ static int drm_legacy_infobufs32(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_buf_info32_t *request = data; + return __drm_legacy_infobufs(dev, data, &request->count, copy_one_buf32); } @@ -813,6 +814,7 @@ static int compat_drm_update_draw(struct file *file, unsigned int cmd, unsigned long arg) { drm_update_draw32_t update32; + if (copy_from_user(&update32, (void __user *)arg, sizeof(update32))) return -EFAULT; diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index 825abe38201a..da4f085fc09e 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -166,8 +166,10 @@ uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (_drm_lease_held_master(master, crtc->base.id)) { uint32_t mask_in = 1ul << count_in; + if ((crtcs_in & mask_in) != 0) { uint32_t mask_out = 1ul << count_out; + crtcs_out |= mask_out; } count_out++; @@ -423,6 +425,7 @@ static int fill_object_idr(struct drm_device *dev, for (o = 0; o < object_count; o++) { struct drm_mode_object *obj = objects[o]; u32 object_id = objects[o]->id; + DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id); /* @@ -441,6 +444,7 @@ static int fill_object_idr(struct drm_device *dev, } if (obj->type == DRM_MODE_OBJECT_CRTC && !universal_planes) { struct drm_crtc *crtc = obj_to_crtc(obj); + ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL); if (ret < 0) { DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n", diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index f16eefbf2829..1efbd5389d89 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -330,6 +330,7 @@ static int drm_legacy_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv) { struct drm_master *master = file_priv->master; + return (file_priv->lock_count && master->lock.hw_lock && _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && master->lock.file_priv == file_priv); diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 5761f838a057..f1affc1bb679 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -538,6 +538,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) WARN_ON(!list_empty(&dev->mode_config.fb_list)); list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { struct drm_printer p = drm_debug_printer("[leaked fb]"); + drm_printf(&p, "framebuffer[%u]:\n", fb->base.id); drm_framebuffer_print_info(&p, 1, fb); drm_framebuffer_free(&fb->base.refcount); diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 75e2b7053f35..c250fb5a88ca 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -298,6 +298,7 @@ EXPORT_SYMBOL(drm_legacy_pci_init); void drm_legacy_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver) { struct drm_device *dev, *tmp; + DRM_DEBUG("\n"); if (!(driver->driver_features & DRIVER_LEGACY)) { diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 4af173ced327..b7b90b3a2e38 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -216,6 +216,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, if (format_modifiers) { const uint64_t *temp_modifiers = format_modifiers; + while (*temp_modifiers++ != DRM_FORMAT_MOD_INVALID) format_modifier_count++; } diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index bbfc713bfdc3..1693aa7c14b5 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -1014,6 +1014,7 @@ void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg) { struct dma_buf_attachment *attach; struct dma_buf *dma_buf; + attach = obj->import_attach; if (sg) dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL); diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 42d46414f767..3bf73971daf3 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -1188,6 +1188,7 @@ static void drm_syncobj_array_free(struct drm_syncobj **syncobjs, uint32_t count) { uint32_t i; + for (i = 0; i < count; i++) drm_syncobj_put(syncobjs[i]); kfree(syncobjs); diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 85e5f2db1608..42a84eb4cc8c 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -1623,6 +1623,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, e->event.vbl.crtc_id = 0; if (drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + if (crtc) e->event.vbl.crtc_id = crtc->base.id; } -- cgit v1.2.3