Skip to content

Commit

Permalink
drm: Replace mode->export_head with a boolean
Browse files Browse the repository at this point in the history
In order to shrink drm_display_mode below the magic two cacheline
mark in 64bit we need to shrink it by another 8 bytes. The easiest
thing to eliminate is the 'export_head' list head which is only
used during the getconnector ioctl to temporarly track which modes
on the connector's mode list are to be exposed and which are to
remain hidden.

We can simply replace the list head with a boolean which we use
to tag the modes that are to be exposed. If we make sure to clear
the tags after we're done with them we don't even need an extra
loop over the modes to reset the tags at the start of the
getconnector ioctl.

Conveniently we already have a hole for the boolean left
behind by the removal of mode->private_flags. The final size
of the struct is now 112 bytes on 32bit and 120 bytes on 64bit.

Another alternative would be a temp bitmask so we wouldn't have
to have anything in the mode struct itself. The main issue is
how large of a bitmask do we need? I guess we could allocate
it dynamically but that means an extra kcalloc() and an extra
loop through the modes to count them first (or grow the bitmask
with krealloc() as needed).

CC: Sam Ravnborg <sam@ravnborg.org>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Emil Velikov <emil.l.velikov@gmail.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200428171940.19552-17-ville.syrjala@linux.intel.com
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
  • Loading branch information
Ville Syrjälä committed Sep 1, 2020
1 parent 0e09c4f commit 8445e2c
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 25 deletions.
45 changes: 32 additions & 13 deletions drivers/gpu/drm/drm_connector.c
Original file line number Diff line number Diff line change
Expand Up @@ -2289,7 +2289,7 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne

static bool
drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
const struct list_head *export_list,
const struct list_head *modes,
const struct drm_file *file_priv)
{
/*
Expand All @@ -2305,15 +2305,17 @@ drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
* while preparing the list of user-modes.
*/
if (!file_priv->aspect_ratio_allowed) {
struct drm_display_mode *mode_itr;
const struct drm_display_mode *mode_itr;

list_for_each_entry(mode_itr, export_list, export_head)
if (drm_mode_match(mode_itr, mode,
list_for_each_entry(mode_itr, modes, head) {
if (mode_itr->expose_to_userspace &&
drm_mode_match(mode_itr, mode,
DRM_MODE_MATCH_TIMINGS |
DRM_MODE_MATCH_CLOCK |
DRM_MODE_MATCH_FLAGS |
DRM_MODE_MATCH_3D_FLAGS))
return false;
}
}

return true;
Expand All @@ -2333,7 +2335,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
struct drm_mode_modeinfo u_mode;
struct drm_mode_modeinfo __user *mode_ptr;
uint32_t __user *encoder_ptr;
LIST_HEAD(export_list);

if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EOPNOTSUPP;
Expand Down Expand Up @@ -2377,25 +2378,30 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
out_resp->connection = connector->status;

/* delayed so we get modes regardless of pre-fill_modes state */
list_for_each_entry(mode, &connector->modes, head)
if (drm_mode_expose_to_userspace(mode, &export_list,
list_for_each_entry(mode, &connector->modes, head) {
WARN_ON(mode->expose_to_userspace);

if (drm_mode_expose_to_userspace(mode, &connector->modes,
file_priv)) {
list_add_tail(&mode->export_head, &export_list);
mode->expose_to_userspace = true;
mode_count++;
}
}

/*
* This ioctl is called twice, once to determine how much space is
* needed, and the 2nd time to fill it.
* The modes that need to be exposed to the user are maintained in the
* 'export_list'. When the ioctl is called first time to determine the,
* space, the export_list gets filled, to find the no.of modes. In the
* 2nd time, the user modes are filled, one by one from the export_list.
*/
if ((out_resp->count_modes >= mode_count) && mode_count) {
copied = 0;
mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
list_for_each_entry(mode, &export_list, export_head) {
list_for_each_entry(mode, &connector->modes, head) {
if (!mode->expose_to_userspace)
continue;

/* Clear the tag for the next time around */
mode->expose_to_userspace = false;

drm_mode_convert_to_umode(&u_mode, mode);
/*
* Reset aspect ratio flags of user-mode, if modes with
Expand All @@ -2406,13 +2412,26 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
if (copy_to_user(mode_ptr + copied,
&u_mode, sizeof(u_mode))) {
ret = -EFAULT;

/*
* Clear the tag for the rest of
* the modes for the next time around.
*/
list_for_each_entry_continue(mode, &connector->modes, head)
mode->expose_to_userspace = false;

mutex_unlock(&dev->mode_config.mutex);

goto out;
}
copied++;
}
} else {
/* Clear the tag for the next time around */
list_for_each_entry(mode, &connector->modes, head)
mode->expose_to_userspace = false;
}

out_resp->count_modes = mode_count;
mutex_unlock(&dev->mode_config.mutex);

Expand Down
22 changes: 10 additions & 12 deletions include/drm/drm_modes.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,24 +350,22 @@ struct drm_display_mode {
u8 type;

/**
* @head:
* @expose_to_userspace:
*
* struct list_head for mode lists.
* Indicates whether the mode is to be exposed to the userspace.
* This is to maintain a set of exposed modes while preparing
* user-mode's list in drm_mode_getconnector ioctl. The purpose of
* this only lies in the ioctl function, and is not to be used
* outside the function.
*/
struct list_head head;
bool expose_to_userspace;

/**
* @export_head:
* @head:
*
* struct list_head for modes to be exposed to the userspace.
* This is to maintain a list of exposed modes while preparing
* user-mode's list in drm_mode_getconnector ioctl. The purpose of this
* list_head only lies in the ioctl function, and is not expected to be
* used outside the function.
* Once used, the stale pointers are not reset, but left as it is, to
* avoid overhead of protecting it by mode_config.mutex.
* struct list_head for mode lists.
*/
struct list_head export_head;
struct list_head head;

/**
* @name:
Expand Down

0 comments on commit 8445e2c

Please sign in to comment.