drm: Branch 'master' - 24 commits
[email protected] (Emil Velikov)
| Newsgroups | gmane.comp.video.dri.patches |
|---|---|
| Message-ID | <[email protected]> |
Makefile.am | 3 exynos/exynos_fimg2d.c | 376 ++++++++++++++++++++++-------------- exynos/exynos_fimg2d.h | 14 - tests/Makefile.am | 1 tests/drmdevice.c | 112 ++++++++++ util_math.h | 1 xf86atomic.h | 2 xf86drm.c | 500 +++++++++++++++++++++++++++++-------------------- xf86drm.h | 3 xf86drmMode.c | 17 + 10 files changed, 672 insertions(+), 357 deletions(-) New commits: commit df21b293e9cf550ec8d6a3e49461350dbdf14260 Author: Tobias Jakobi <[email protected]> Date: Tue Sep 8 17:22:34 2015 +0200 exynos/fimg2d: remove g2d_context from public header All functions from the public API only operation on struct g2d_context*, so this shouldn't break too much. Make the context private since we don't want the user to modify its content directly. Also remove the defines that were only used for fields of g2d_context. Signed-off-by: Tobias Jakobi <[email protected]> diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c index 9746c21..e734144 100644 --- a/exynos/exynos_fimg2d.c +++ b/exynos/exynos_fimg2d.c @@ -44,6 +44,21 @@ #define MSG_PREFIX "exynos/fimg2d: " +#define G2D_MAX_CMD_NR 64 +#define G2D_MAX_GEM_CMD_NR 64 +#define G2D_MAX_CMD_LIST_NR 64 + +struct g2d_context { + int fd; + unsigned int major; + unsigned int minor; + struct drm_exynos_g2d_cmd cmd[G2D_MAX_CMD_NR]; + struct drm_exynos_g2d_cmd cmd_buf[G2D_MAX_GEM_CMD_NR]; + unsigned int cmd_nr; + unsigned int cmd_buf_nr; + unsigned int cmdlist_nr; +}; + enum g2d_base_addr_reg { g2d_dst = 0, g2d_src diff --git a/exynos/exynos_fimg2d.h b/exynos/exynos_fimg2d.h index 9db0c88..4aa1568 100644 --- a/exynos/exynos_fimg2d.h +++ b/exynos/exynos_fimg2d.h @@ -13,9 +13,6 @@ #ifndef _FIMG2D_H_ #define _FIMG2D_H_ -#define G2D_MAX_CMD_NR 64 -#define G2D_MAX_GEM_CMD_NR 64 -#define G2D_MAX_CMD_LIST_NR 64 #define G2D_PLANE_MAX_NR 2 enum e_g2d_color_mode { @@ -289,16 +286,7 @@ struct g2d_image { void *mapped_ptr[G2D_PLANE_MAX_NR]; }; -struct g2d_context { - int fd; - unsigned int major; - unsigned int minor; - struct drm_exynos_g2d_cmd cmd[G2D_MAX_CMD_NR]; - struct drm_exynos_g2d_cmd cmd_buf[G2D_MAX_GEM_CMD_NR]; - unsigned int cmd_nr; - unsigned int cmd_buf_nr; - unsigned int cmdlist_nr; -}; +struct g2d_context; struct g2d_context *g2d_init(int fd); void g2d_fini(struct g2d_context *ctx); commit ce4a4f6e21d4112f0b88c973283b586e1fccddd9 Author: Tobias Jakobi <[email protected]> Date: Tue Sep 8 17:22:33 2015 +0200 exynos/fimg2d: add message prefix Add a prefix to the messages printed to the console via printf() and fprintf() so that one can easily see where the message comes from. Signed-off-by: Tobias Jakobi <[email protected]> Reviewed-by: Emil Velikov <[email protected]> diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c index 5873fe7..9746c21 100644 --- a/exynos/exynos_fimg2d.c +++ b/exynos/exynos_fimg2d.c @@ -42,6 +42,8 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MSG_PREFIX "exynos/fimg2d: " + enum g2d_base_addr_reg { g2d_dst = 0, g2d_src @@ -255,7 +257,7 @@ static int g2d_flush(struct g2d_context *ctx) return 0; if (ctx->cmdlist_nr >= G2D_MAX_CMD_LIST_NR) { - fprintf(stderr, "Overflow cmdlist.\n"); + fprintf(stderr, MSG_PREFIX "command list overflow.\n"); return -EINVAL; } @@ -271,7 +273,7 @@ static int g2d_flush(struct g2d_context *ctx) ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, &cmdlist); if (ret < 0) { - fprintf(stderr, "failed to set cmdlist.\n"); + fprintf(stderr, MSG_PREFIX "failed to set cmdlist.\n"); return ret; } @@ -293,7 +295,7 @@ struct g2d_context *g2d_init(int fd) ctx = calloc(1, sizeof(*ctx)); if (!ctx) { - fprintf(stderr, "failed to allocate context.\n"); + fprintf(stderr, MSG_PREFIX "failed to allocate context.\n"); return NULL; } @@ -301,7 +303,7 @@ struct g2d_context *g2d_init(int fd) ret = drmIoctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, &ver); if (ret < 0) { - fprintf(stderr, "failed to get version.\n"); + fprintf(stderr, MSG_PREFIX "failed to get version.\n"); free(ctx); return NULL; } @@ -309,7 +311,7 @@ struct g2d_context *g2d_init(int fd) ctx->major = ver.major; ctx->minor = ver.minor; - printf("g2d version(%d.%d).\n", ctx->major, ctx->minor); + printf(MSG_PREFIX "G2D version (%d.%d).\n", ctx->major, ctx->minor); return ctx; } @@ -335,7 +337,7 @@ int g2d_exec(struct g2d_context *ctx) ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec); if (ret < 0) { - fprintf(stderr, "failed to execute.\n"); + fprintf(stderr, MSG_PREFIX "failed to execute.\n"); return ret; } @@ -436,7 +438,7 @@ g2d_copy(struct g2d_context *ctx, struct g2d_image *src, h = MIN(src_h, dst_h); if (w <= 0 || h <= 0) { - fprintf(stderr, "invalid width or height.\n"); + fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); return -EINVAL; } @@ -532,7 +534,7 @@ g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src, dst_h = dst->height - dst_y; if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { - fprintf(stderr, "invalid width or height.\n"); + fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); return -EINVAL; } @@ -633,17 +635,17 @@ g2d_blend(struct g2d_context *ctx, struct g2d_image *src, h = MIN(src_h, dst_h); if (w <= 0 || h <= 0) { - fprintf(stderr, "invalid width or height.\n"); + fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); return -EINVAL; } if (!g2d_validate_select_mode(src->select_mode)) { - fprintf(stderr , "invalid select mode for source.\n"); + fprintf(stderr , MSG_PREFIX "invalid select mode for source.\n"); return -EINVAL; } if (!g2d_validate_blending_op(op)) { - fprintf(stderr , "unsupported blending operation.\n"); + fprintf(stderr , MSG_PREFIX "unsupported blending operation.\n"); return -EINVAL; } @@ -752,17 +754,17 @@ g2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src, dst_h = dst->height - dst_y; if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { - fprintf(stderr, "invalid width or height.\n"); + fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); return -EINVAL; } if (!g2d_validate_select_mode(src->select_mode)) { - fprintf(stderr , "invalid select mode for source.\n"); + fprintf(stderr , MSG_PREFIX "invalid select mode for source.\n"); return -EINVAL; } if (!g2d_validate_blending_op(op)) { - fprintf(stderr , "unsupported blending operation.\n"); + fprintf(stderr , MSG_PREFIX "unsupported blending operation.\n"); return -EINVAL; } commit bf666b5e999236ec6406afd60ca35a465c6b3262 Author: Tobias Jakobi <[email protected]> Date: Tue Sep 8 17:22:32 2015 +0200 exynos/fimg2d: make g2d_add_cmd() less heavy The function currently checks for each added command if an overflow of the corresponding command buffers occurs, but none of the callers ever checks the return value. Since all callers are now converted to use g2d_check_space() simplify the function. (1) The overflow checks become asserts, so they're only active for debug builds. This is fine since g2d_add_cmd() is not part of the public API. (2) Switch the return value to void. (3) Explicitly state that the caller has to check buffer space before calling g2d_add_cmd(). Signed-off-by: Tobias Jakobi <[email protected]> Reviewed-by: Emil Velikov <[email protected]> diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c index fbc77a3..5873fe7 100644 --- a/exynos/exynos_fimg2d.c +++ b/exynos/exynos_fimg2d.c @@ -18,6 +18,7 @@ #include <stdio.h> #include <string.h> #include <errno.h> +#include <assert.h> #include <sys/mman.h> #include <linux/stddef.h> @@ -172,8 +173,11 @@ static int g2d_validate_blending_op( * @ctx: a pointer to g2d_context structure. * @cmd: command data. * @value: value data. + * + * The caller has to make sure that the commands buffers have enough space + * left to hold the command. Use g2d_check_space() to ensure this. */ -static int g2d_add_cmd(struct g2d_context *ctx, unsigned long cmd, +static void g2d_add_cmd(struct g2d_context *ctx, unsigned long cmd, unsigned long value) { switch (cmd & ~(G2D_BUF_USERPTR)) { @@ -183,28 +187,20 @@ static int g2d_add_cmd(struct g2d_context *ctx, unsigned long cmd, case DST_PLANE2_BASE_ADDR_REG: case PAT_BASE_ADDR_REG: case MASK_BASE_ADDR_REG: - if (ctx->cmd_buf_nr >= G2D_MAX_GEM_CMD_NR) { - fprintf(stderr, "Overflow cmd_gem size.\n"); - return -EINVAL; - } + assert(ctx->cmd_buf_nr < G2D_MAX_GEM_CMD_NR); ctx->cmd_buf[ctx->cmd_buf_nr].offset = cmd; ctx->cmd_buf[ctx->cmd_buf_nr].data = value; ctx->cmd_buf_nr++; break; default: - if (ctx->cmd_nr >= G2D_MAX_CMD_NR) { - fprintf(stderr, "Overflow cmd size.\n"); - return -EINVAL; - } + assert(ctx->cmd_nr < G2D_MAX_CMD_NR); ctx->cmd[ctx->cmd_nr].offset = cmd; ctx->cmd[ctx->cmd_nr].data = value; ctx->cmd_nr++; break; } - - return 0; } /* commit 6a4479da71e93ef5141d9c493c235c2beb64170a Author: Tobias Jakobi <[email protected]> Date: Tue Sep 8 17:22:31 2015 +0200 exynos/fimg2d: remove superfluous initialization of g2d_point_val The g2d_point_val union consists of two coordinates of 16 bits. Whenever this union is used though, both coordinates are explicitly set. Hence prior initialization is unnecessary. Signed-off-by: Tobias Jakobi <[email protected]> Reviewed-by: Emil Velikov <[email protected]> diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c index d7cbb24..fbc77a3 100644 --- a/exynos/exynos_fimg2d.c +++ b/exynos/exynos_fimg2d.c @@ -380,15 +380,12 @@ g2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img, if (y + h > img->height) h = img->height - y; - pt.val = 0; pt.data.x = x; pt.data.y = y; g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); - pt.val = 0; pt.data.x = x + w; pt.data.y = y + h; - g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); g2d_add_cmd(ctx, SF_COLOR_REG, img->color); @@ -460,20 +457,16 @@ g2d_copy(struct g2d_context *ctx, struct g2d_image *src, g2d_add_base_addr(ctx, src, g2d_src); g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); - pt.val = 0; pt.data.x = src_x; pt.data.y = src_y; g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); - pt.val = 0; pt.data.x = src_x + w; pt.data.y = src_y + h; g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); - pt.val = 0; pt.data.x = dst_x; pt.data.y = dst_y; g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); - pt.val = 0; pt.data.x = dst_x + w; pt.data.y = dst_y + h; g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); @@ -581,20 +574,16 @@ g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src, g2d_add_cmd(ctx, SRC_YSCALE_REG, scale_y); } - pt.val = 0; pt.data.x = src_x; pt.data.y = src_y; g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); - pt.val = 0; pt.data.x = src_x + src_w; pt.data.y = src_y + src_h; g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); - pt.val = 0; pt.data.x = dst_x; pt.data.y = dst_y; g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); - pt.val = 0; pt.data.x = dst_x + dst_w; pt.data.y = dst_y + dst_h; g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); @@ -700,20 +689,16 @@ g2d_blend(struct g2d_context *ctx, struct g2d_image *src, g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val); - pt.val = 0; pt.data.x = src_x; pt.data.y = src_y; g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); - pt.val = 0; pt.data.x = src_x + w; pt.data.y = src_y + h; g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); - pt.val = 0; pt.data.x = dst_x; pt.data.y = dst_y; g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); - pt.val = 0; pt.data.x = dst_x + w; pt.data.y = dst_y + h; g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); @@ -829,20 +814,16 @@ g2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src, g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val); - pt.val = 0; pt.data.x = src_x; pt.data.y = src_y; g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); - pt.val = 0; pt.data.x = src_x + src_w; pt.data.y = src_y + src_h; g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); - pt.val = 0; pt.data.x = dst_x; pt.data.y = dst_y; g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); - pt.val = 0; pt.data.x = dst_x + dst_w; pt.data.y = dst_y + dst_h; g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); commit 76d1c6b15725f1e7de3c60b0398639e06bf295be Author: Tobias Jakobi <[email protected]> Date: Tue Sep 8 17:22:30 2015 +0200 exynos/fimg2d: remove default case from g2d_get_blend_op() We now validate the blending mode via g2d_validate_mode() prior to feeding it to g2d_get_blend_op(). Signed-off-by: Tobias Jakobi <[email protected]> Reviewed-by: Emil Velikov <[email protected]> diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c index 9d9359a..d7cbb24 100644 --- a/exynos/exynos_fimg2d.c +++ b/exynos/exynos_fimg2d.c @@ -64,6 +64,11 @@ static unsigned int g2d_get_blend_op(enum e_g2d_op op) val.val = 0; + /* + * The switch statement is missing the default branch since + * we assume that the caller checks the blending operation + * via g2d_validate_blending_op() first. + */ switch (op) { case G2D_OP_CLEAR: case G2D_OP_DISJOINT_CLEAR: @@ -91,11 +96,6 @@ static unsigned int g2d_get_blend_op(enum e_g2d_op op) SET_BF(val, G2D_COEFF_MODE_SRC_ALPHA, 0, 0, 0, G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0); break; - default: - fprintf(stderr, "Not support operation(%d).\n", op); - SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, G2D_COEFF_MODE_ZERO, - 0, 0, 0); - break; } return val.val; commit e3c97d1a2473cd06a964599d10465f1e6a4d9015 Author: Tobias Jakobi <[email protected]> Date: Tue Sep 8 17:22:29 2015 +0200 exynos/fimg2d: add g2d_validate_xyz() functions The G2D headers define a number of modes through enums (like e.g. color, select, repeat, etc.). This introduces g2d_validate_select_mode() and g2d_validate_blending_op() which validate a select mode or blending operation respectively. Use this together with g2d_check_space() in g2d_{blend,scale_and_blend}(). For this we move parameter validation to the top and also validate the select mode of the source image and the requested blending operation before starting command submission. Signed-off-by: Tobias Jakobi <[email protected]> Reviewed-by: Emil Velikov <[email protected]> diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c index 2e04f4a..9d9359a 100644 --- a/exynos/exynos_fimg2d.c +++ b/exynos/exynos_fimg2d.c @@ -119,6 +119,54 @@ static unsigned int g2d_check_space(const struct g2d_context *ctx, } /* + * g2d_validate_select_mode - validate select mode. + * + * @mode: the mode to validate + * + * Returns zero for an invalid mode and one otherwise. + */ +static int g2d_validate_select_mode( + enum e_g2d_select_mode mode) +{ + switch (mode) { + case G2D_SELECT_MODE_NORMAL: + case G2D_SELECT_MODE_FGCOLOR: + case G2D_SELECT_MODE_BGCOLOR: + return 1; + } + + return 0; +} + +/* + * g2d_validate_blending_op - validate blending operation. + * + * @operation: the operation to validate + * + * Returns zero for an invalid mode and one otherwise. + */ +static int g2d_validate_blending_op( + enum e_g2d_op operation) +{ + switch (operation) { + case G2D_OP_CLEAR: + case G2D_OP_SRC: + case G2D_OP_DST: + case G2D_OP_OVER: + case G2D_OP_INTERPOLATE: + case G2D_OP_DISJOINT_CLEAR: + case G2D_OP_DISJOINT_SRC: + case G2D_OP_DISJOINT_DST: + case G2D_OP_CONJOINT_CLEAR: + case G2D_OP_CONJOINT_SRC: + case G2D_OP_CONJOINT_DST: + return 1; + } + + return 0; +} + +/* * g2d_add_cmd - set given command and value to user side command buffer. * * @ctx: a pointer to g2d_context structure. @@ -579,7 +627,45 @@ g2d_blend(struct g2d_context *ctx, struct g2d_image *src, union g2d_point_val pt; union g2d_bitblt_cmd_val bitblt; union g2d_blend_func_val blend; - unsigned int src_w = 0, src_h = 0, dst_w = 0, dst_h = 0; + unsigned int gem_space; + unsigned int src_w, src_h, dst_w, dst_h; + + src_w = w; + src_h = h; + if (src_x + w > src->width) + src_w = src->width - src_x; + if (src_y + h > src->height) + src_h = src->height - src_y; + + dst_w = w; + dst_h = h; + if (dst_x + w > dst->width) + dst_w = dst->width - dst_x; + if (dst_y + h > dst->height) + dst_h = dst->height - dst_y; + + w = MIN(src_w, dst_w); + h = MIN(src_h, dst_h); + + if (w <= 0 || h <= 0) { + fprintf(stderr, "invalid width or height.\n"); + return -EINVAL; + } + + if (!g2d_validate_select_mode(src->select_mode)) { + fprintf(stderr , "invalid select mode for source.\n"); + return -EINVAL; + } + + if (!g2d_validate_blending_op(op)) { + fprintf(stderr , "unsupported blending operation.\n"); + return -EINVAL; + } + + gem_space = src->select_mode == G2D_SELECT_MODE_NORMAL ? 2 : 1; + + if (g2d_check_space(ctx, 12, gem_space)) + return -ENOSPC; bitblt.val = 0; blend.val = 0; @@ -607,32 +693,6 @@ g2d_blend(struct g2d_context *ctx, struct g2d_image *src, case G2D_SELECT_MODE_BGCOLOR: g2d_add_cmd(ctx, BG_COLOR_REG, src->color); break; - default: - fprintf(stderr , "failed to set src.\n"); - return -EINVAL; - } - - src_w = w; - src_h = h; - if (src_x + w > src->width) - src_w = src->width - src_x; - if (src_y + h > src->height) - src_h = src->height - src_y; - - dst_w = w; - dst_h = h; - if (dst_x + w > dst->width) - dst_w = dst->width - dst_x; - if (dst_y + h > dst->height) - dst_h = dst->height - dst_y; - - w = MIN(src_w, dst_w); - h = MIN(src_h, dst_h); - - if (w <= 0 || h <= 0) { - fprintf(stderr, "invalid width or height.\n"); - g2d_reset(ctx); - return -EINVAL; } bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE; @@ -689,9 +749,47 @@ g2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src, union g2d_point_val pt; union g2d_bitblt_cmd_val bitblt; union g2d_blend_func_val blend; - unsigned int scale; + unsigned int scale, gem_space; unsigned int scale_x, scale_y; + if (src_w == dst_w && src_h == dst_h) + scale = 0; + else { + scale = 1; + scale_x = g2d_get_scaling(src_w, dst_w); + scale_y = g2d_get_scaling(src_h, dst_h); + } + + if (src_x + src_w > src->width) + src_w = src->width - src_x; + if (src_y + src_h > src->height) + src_h = src->height - src_y; + + if (dst_x + dst_w > dst->width) + dst_w = dst->width - dst_x; + if (dst_y + dst_h > dst->height) + dst_h = dst->height - dst_y; + + if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { + fprintf(stderr, "invalid width or height.\n"); + return -EINVAL; + } + + if (!g2d_validate_select_mode(src->select_mode)) { + fprintf(stderr , "invalid select mode for source.\n"); + return -EINVAL; + } + + if (!g2d_validate_blending_op(op)) { + fprintf(stderr , "unsupported blending operation.\n"); + return -EINVAL; + } + + gem_space = src->select_mode == G2D_SELECT_MODE_NORMAL ? 2 : 1; + + if (g2d_check_space(ctx, 12 + scale * 3, gem_space)) + return -ENOSPC; + bitblt.val = 0; blend.val = 0; @@ -718,33 +816,6 @@ g2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src, case G2D_SELECT_MODE_BGCOLOR: g2d_add_cmd(ctx, BG_COLOR_REG, src->color); break; - default: - fprintf(stderr , "failed to set src.\n"); - return -EINVAL; - } - - if (src_w == dst_w && src_h == dst_h) - scale = 0; - else { - scale = 1; - scale_x = g2d_get_scaling(src_w, dst_w); - scale_y = g2d_get_scaling(src_h, dst_h); - } - - if (src_x + src_w > src->width) - src_w = src->width - src_x; - if (src_y + src_h > src->height) - src_h = src->height - src_y; - - if (dst_x + dst_w > dst->width) - dst_w = dst->width - dst_x; - if (dst_y + dst_h > dst->height) - dst_h = dst->height - dst_y; - - if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { - fprintf(stderr, "invalid width or height.\n"); - g2d_reset(ctx); - return -EINVAL; } if (scale) { commit 2362c88251d4bba0bb76d2a25f233004c6f99134 Author: Tobias Jakobi <[email protected]> Date: Tue Sep 8 17:22:28 2015 +0200 exynos/fimg2d: add g2d_check_space() This is going to be used to check if the command buffers have enough space left prior to actual submission of the commands. Use this in g2d_{solid_fill,copy,copy_with_scale}(). For this the parameter validation before buffer space checking so that we can exit early if it fails. Also don't reset the G2D context in this situation since the buffers are not partially submitted anymore. The repeat mode in g2d_copy_with_scale() is checked first to make computation of space easier. Signed-off-by: Tobias Jakobi <[email protected]> Reviewed-by: Emil Velikov <[email protected]> diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c index 85b2317..2e04f4a 100644 --- a/exynos/exynos_fimg2d.c +++ b/exynos/exynos_fimg2d.c @@ -102,6 +102,23 @@ static unsigned int g2d_get_blend_op(enum e_g2d_op op) } /* + * g2d_check_space - check if command buffers have enough space left. + * + * @ctx: a pointer to g2d_context structure. + * @num_cmds: number of (regular) commands. + * @num_gem_cmds: number of GEM commands. + */ +static unsigned int g2d_check_space(const struct g2d_context *ctx, + unsigned int num_cmds, unsigned int num_gem_cmds) +{ + if (ctx->cmd_nr + num_cmds >= G2D_MAX_CMD_NR || + ctx->cmd_buf_nr + num_gem_cmds >= G2D_MAX_GEM_CMD_NR) + return 1; + else + return 0; +} + +/* * g2d_add_cmd - set given command and value to user side command buffer. * * @ctx: a pointer to g2d_context structure. @@ -302,6 +319,9 @@ g2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img, union g2d_bitblt_cmd_val bitblt; union g2d_point_val pt; + if (g2d_check_space(ctx, 7, 1)) + return -ENOSPC; + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); g2d_add_cmd(ctx, DST_COLOR_MODE_REG, img->color_mode); g2d_add_base_addr(ctx, img, g2d_dst); @@ -355,17 +375,7 @@ g2d_copy(struct g2d_context *ctx, struct g2d_image *src, { union g2d_rop4_val rop4; union g2d_point_val pt; - unsigned int src_w = 0, src_h = 0, dst_w = 0, dst_h = 0; - - g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); - g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); - g2d_add_base_addr(ctx, dst, g2d_dst); - g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); - - g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); - g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); - g2d_add_base_addr(ctx, src, g2d_src); - g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); + unsigned int src_w, src_h, dst_w, dst_h; src_w = w; src_h = h; @@ -386,10 +396,22 @@ g2d_copy(struct g2d_context *ctx, struct g2d_image *src, if (w <= 0 || h <= 0) { fprintf(stderr, "invalid width or height.\n"); - g2d_reset(ctx); return -EINVAL; } + if (g2d_check_space(ctx, 11, 2)) + return -ENOSPC; + + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_base_addr(ctx, dst, g2d_dst); + g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); + + g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); + g2d_add_base_addr(ctx, src, g2d_src); + g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); + pt.val = 0; pt.data.x = src_x; pt.data.y = src_y; @@ -445,23 +467,12 @@ g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src, { union g2d_rop4_val rop4; union g2d_point_val pt; - unsigned int scale; + unsigned int scale, repeat_pad; unsigned int scale_x, scale_y; - g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); - g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); - g2d_add_base_addr(ctx, dst, g2d_dst); - g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); - - g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); - g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); - - g2d_add_cmd(ctx, SRC_REPEAT_MODE_REG, src->repeat_mode); - if (src->repeat_mode == G2D_REPEAT_MODE_PAD) - g2d_add_cmd(ctx, SRC_PAD_VALUE_REG, dst->color); - - g2d_add_base_addr(ctx, src, g2d_src); - g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); + /* Sanitize this parameter to facilitate space computation below. */ + if (negative) + negative = 1; if (src_w == dst_w && src_h == dst_h) scale = 0; @@ -471,6 +482,8 @@ g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src, scale_y = g2d_get_scaling(src_h, dst_h); } + repeat_pad = src->repeat_mode == G2D_REPEAT_MODE_PAD ? 1 : 0; + if (src_x + src_w > src->width) src_w = src->width - src_x; if (src_y + src_h > src->height) @@ -483,21 +496,37 @@ g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src, if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { fprintf(stderr, "invalid width or height.\n"); - g2d_reset(ctx); return -EINVAL; } + if (g2d_check_space(ctx, 12 + scale * 3 + negative + repeat_pad, 2)) + return -ENOSPC; + + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_base_addr(ctx, dst, g2d_dst); + g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); + + g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); + + g2d_add_cmd(ctx, SRC_REPEAT_MODE_REG, src->repeat_mode); + if (repeat_pad) + g2d_add_cmd(ctx, SRC_PAD_VALUE_REG, dst->color); + + g2d_add_base_addr(ctx, src, g2d_src); + g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); + + rop4.val = 0; + rop4.data.unmasked_rop3 = G2D_ROP3_SRC; + if (negative) { g2d_add_cmd(ctx, BG_COLOR_REG, 0x00FFFFFF); - rop4.val = 0; - rop4.data.unmasked_rop3 = G2D_ROP3_SRC^G2D_ROP3_DST; - g2d_add_cmd(ctx, ROP4_REG, rop4.val); - } else { - rop4.val = 0; - rop4.data.unmasked_rop3 = G2D_ROP3_SRC; - g2d_add_cmd(ctx, ROP4_REG, rop4.val); + rop4.data.unmasked_rop3 ^= G2D_ROP3_DST; } + g2d_add_cmd(ctx, ROP4_REG, rop4.val); + if (scale) { g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR); g2d_add_cmd(ctx, SRC_XSCALE_REG, scale_x); commit 9017619714eb432fa9bb1e94139cc2ad40fc7001 Author: Tobias Jakobi <[email protected]> Date: Tue Sep 8 17:22:27 2015 +0200 exynos/fimg2d: simplify base address submission in g2d_scale_and_blend() Use g2d_add_base_addr() for source and destination base address just like all other calls. Signed-off-by: Tobias Jakobi <[email protected]> Reviewed-by: Emil Velikov <[email protected]> diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c index 4a88e0c..85b2317 100644 --- a/exynos/exynos_fimg2d.c +++ b/exynos/exynos_fimg2d.c @@ -672,12 +672,7 @@ g2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src, g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); - if (dst->buf_type == G2D_IMGBUF_USERPTR) - g2d_add_cmd(ctx, DST_BASE_ADDR_REG | G2D_BUF_USERPTR, - (unsigned long)&dst->user_ptr[0]); - else - g2d_add_cmd(ctx, DST_BASE_ADDR_REG, dst->bo[0]); - + g2d_add_base_addr(ctx, dst, g2d_dst); g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode); @@ -685,12 +680,7 @@ g2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src, switch (src->select_mode) { case G2D_SELECT_MODE_NORMAL: - if (src->buf_type == G2D_IMGBUF_USERPTR) - g2d_add_cmd(ctx, SRC_BASE_ADDR_REG | G2D_BUF_USERPTR, - (unsigned long)&src->user_ptr[0]); - else - g2d_add_cmd(ctx, SRC_BASE_ADDR_REG, src->bo[0]); - + g2d_add_base_addr(ctx, src, g2d_src); g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); break; case G2D_SELECT_MODE_FGCOLOR: commit a8dc2e75cfb2acecae7cb7aeefa20b9c92abd297 Author: Tobias Jakobi <[email protected]> Date: Tue Sep 8 17:22:26 2015 +0200 exynos/fimg2d: fix empty buffer handling in g2d_flush() Empty command buffers are no error, we just don't have anything to do for flushing then. Signed-off-by: Tobias Jakobi <[email protected]> Reviewed-by: Emil Velikov <[email protected]> diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c index 24a06d0..4a88e0c 100644 --- a/exynos/exynos_fimg2d.c +++ b/exynos/exynos_fimg2d.c @@ -191,7 +191,7 @@ static int g2d_flush(struct g2d_context *ctx) struct drm_exynos_g2d_set_cmdlist cmdlist = {0}; if (ctx->cmd_nr == 0 && ctx->cmd_buf_nr == 0) - return -1; + return 0; if (ctx->cmdlist_nr >= G2D_MAX_CMD_LIST_NR) { fprintf(stderr, "Overflow cmdlist.\n"); commit cec65e2fcc8ddd3a2a094d446d49d7a7f52ff55d Author: Emil Velikov <[email protected]> Date: Mon Sep 21 17:29:55 2015 +0100 Fix SunOS/NetBSD atomic macro Reported-by: Evgeny Litvinenko <[email protected]> Signed-off-by: Emil Velikov <[email protected]> diff --git a/xf86atomic.h b/xf86atomic.h index 194554c..922b37d 100644 --- a/xf86atomic.h +++ b/xf86atomic.h @@ -93,7 +93,7 @@ typedef struct { LIBDRM_ATOMIC_TYPE atomic; } atomic_t; # define atomic_read(x) (int) ((x)->atomic) # define atomic_set(x, val) ((x)->atomic = (LIBDRM_ATOMIC_TYPE)(val)) # define atomic_inc(x) (atomic_inc_uint (&(x)->atomic)) -# define atomic_inc_return (atomic_inc_uint_nv(&(x)->atomic)) +# define atomic_inc_return(x) (atomic_inc_uint_nv(&(x)->atomic)) # define atomic_dec_and_test(x) (atomic_dec_uint_nv(&(x)->atomic) == 0) # define atomic_add(x, v) (atomic_add_int(&(x)->atomic, (v))) # define atomic_dec(x, v) (atomic_add_int(&(x)->atomic, -(v))) commit 8990ed319993c5d1a354adef41c19acc662c81e8 Author: Emil Velikov <[email protected]> Date: Wed Sep 9 18:13:01 2015 +0100 tests/drmdevice: add drm{Get,Free}Device() example Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/tests/drmdevice.c b/tests/drmdevice.c index 4055f45..c336327 100644 --- a/tests/drmdevice.c +++ b/tests/drmdevice.c @@ -23,6 +23,9 @@ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> #include <xf86drm.h> @@ -62,7 +65,8 @@ int main(void) { drmDevicePtr *devices; - int ret, max_devices; + drmDevicePtr device; + int fd, ret, max_devices; max_devices = drmGetDevices(NULL, 0); @@ -84,9 +88,24 @@ main(void) return -1; } - for (int i = 0; i < ret; i++) + for (int i = 0; i < ret; i++) { print_device_info(devices[i], i); + for (int j = 0; j < DRM_NODE_MAX; j++) { + if (devices[i]->available_nodes & 1 << j) { + fd = open(devices[i]->nodes[j], O_RDONLY | O_CLOEXEC, 0); + if (fd < 0) + continue; + + if (drmGetDevice(fd, &device) == 0) { + print_device_info(device, -1); + drmFreeDevice(&device); + } + close(fd); + } + } + } + drmFreeDevices(devices, ret); free(devices); return 0; commit ccedf66b65f6ab245aa6028d7fe9eb603a121b43 Author: Emil Velikov <[email protected]> Date: Wed Sep 9 16:02:18 2015 +0100 xf86drm: add drm{Get,Free}Device Similar interface to the *Devices() ones but they obtain/free the information of the opened device (as given by its fd). Note there is a fair bit of duplication between the two Get functions, and anyone interested is more than welcome to consolidate it. Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/xf86drm.c b/xf86drm.c index aa0fbe4..789bfc2 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -2982,7 +2982,7 @@ static int drmParsePciDeviceInfo(const char *d_name, #endif } -static void drmFreeDevice(drmDevicePtr *device) +void drmFreeDevice(drmDevicePtr *device) { if (device == NULL) return; @@ -3072,6 +3072,119 @@ static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) } /** + * Get information about the opened drm device + * + * \param fd file descriptor of the drm device + * \param device the address of a drmDevicePtr where the information + * will be allocated in stored + * + * \return zero on success, negative error code otherwise. + */ +int drmGetDevice(int fd, drmDevicePtr *device) +{ + drmDevicePtr *local_devices; + drmDevicePtr d; + DIR *sysdir; + struct dirent *dent; + struct stat sbuf; + char node[PATH_MAX + 1]; + int node_type, subsystem_type; + int maj, min; + int ret, i, node_count; + int max_count = 16; + + if (fd == -1 || device == NULL) + return -EINVAL; + + if (fstat(fd, &sbuf)) + return -errno; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) + return -EINVAL; + + subsystem_type = drmParseSubsystemType(maj, min); + + local_devices = calloc(max_count, sizeof(drmDevicePtr)); + if (local_devices == NULL) + return -ENOMEM; + + sysdir = opendir(DRM_DIR_NAME); + if (!sysdir) { + ret = -errno; + goto close_sysdir; + } + + i = 0; + while ((dent = readdir(sysdir))) { + node_type = drmGetNodeType(dent->d_name); + if (node_type < 0) + continue; + + snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name); + if (stat(node, &sbuf)) + continue; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) + continue; + + if (drmParseSubsystemType(maj, min) != subsystem_type) + continue; + + switch (subsystem_type) { + case DRM_BUS_PCI: + ret = drmProcessPciDevice(&d, dent->d_name, node, node_type, + maj, min, true); + if (ret) + goto free_devices; + + break; + default: + fprintf(stderr, "The subsystem type is not supported yet\n"); + break; + } + + if (i >= max_count) { + drmDevicePtr *temp; + + max_count += 16; + temp = realloc(local_devices, max_count * sizeof(drmDevicePtr)); + if (!temp) + goto free_devices; + local_devices = temp; + } + + local_devices[i] = d; + i++; + } + node_count = i; + + /* Fold nodes into a single device if they share the same bus info */ + drmFoldDuplicatedDevices(local_devices, node_count); + + *device = local_devices[0]; + for (i = 1; i < node_count && local_devices[i]; i++) + drmFreeDevice(&local_devices[i]); + + free(local_devices); + closedir(sysdir); + return 0; + +free_devices: + drmFreeDevices(local_devices, i); + free(local_devices); + +close_sysdir: + closedir(sysdir); + return ret; +} + +/** * Get drm devices on the system * * \param devices the array of devices with drmDevicePtr elements diff --git a/xf86drm.h b/xf86drm.h index e82ca84..481d882 100644 --- a/xf86drm.h +++ b/xf86drm.h @@ -790,6 +790,9 @@ typedef struct _drmDevice { } deviceinfo; } drmDevice, *drmDevicePtr; +extern int drmGetDevice(int fd, drmDevicePtr *device); +extern void drmFreeDevice(drmDevicePtr *device); + extern int drmGetDevices(drmDevicePtr devices[], int max_devices); extern void drmFreeDevices(drmDevicePtr devices[], int count); commit fae59d7234caf4827bf5ca74c1b706cbfb70a460 Author: Emil Velikov <[email protected]> Date: Wed Sep 9 17:54:34 2015 +0100 xf86drm: split out drmProcessPciDevice and drmFoldDuplicatedDevices Will be reused in the next commit. Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/xf86drm.c b/xf86drm.c index a783a28..aa0fbe4 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -36,6 +36,7 @@ #endif #include <stdio.h> #include <stdlib.h> +#include <stdbool.h> #include <unistd.h> #include <string.h> #include <strings.h> @@ -3001,6 +3002,75 @@ void drmFreeDevices(drmDevicePtr devices[], int count) drmFreeDevice(&devices[i]); } +static int drmProcessPciDevice(drmDevicePtr *device, const char *d_name, + const char *node, int node_type, + int maj, int min, bool fetch_deviceinfo) +{ + const int max_node_str = drmGetMaxNodeName(); + int ret, i; + void *addr; + + addr = *device = calloc(1, sizeof(drmDevice) + + (DRM_NODE_MAX * + (sizeof(void *) + max_node_str)) + + sizeof(drmPciBusInfo) + + sizeof(drmPciDeviceInfo)); + if (!*device) + return -ENOMEM; + + (*device)->bustype = DRM_BUS_PCI; + (*device)->available_nodes = 1 << node_type; + + addr += sizeof(drmDevice); + (*device)->nodes = addr; + + addr += DRM_NODE_MAX * sizeof(void *); + for (i = 0; i < DRM_NODE_MAX; i++) { + (*device)->nodes[i] = addr; + addr += max_node_str; + } + memcpy((*device)->nodes[node_type], node, max_node_str); + + (*device)->businfo.pci = addr; + + ret = drmParsePciBusInfo(maj, min, (*device)->businfo.pci); + if (ret) + goto free_device; + + // Fetch the device info if the user has requested it + if (fetch_deviceinfo) { + addr += sizeof(drmPciBusInfo); + (*device)->deviceinfo.pci = addr; + + ret = drmParsePciDeviceInfo(d_name, (*device)->deviceinfo.pci); + if (ret) + goto free_device; + } + return 0; + +free_device: + free(*device); + *device = NULL; + return ret; +} + +static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) +{ + int node_type, i, j; + + for (i = 0; i < count; i++) { + for (j = i + 1; j < count; j++) { + if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) { + local_devices[i]->available_nodes |= local_devices[j]->available_nodes; + node_type = log2(local_devices[j]->available_nodes); + memcpy(local_devices[i]->nodes[node_type], + local_devices[j]->nodes[node_type], drmGetMaxNodeName()); + drmFreeDevice(&local_devices[j]); + } + } + } +} + /** * Get drm devices on the system * @@ -3021,12 +3091,10 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) struct dirent *dent; struct stat sbuf; char node[PATH_MAX + 1]; - const int max_node_str = drmGetMaxNodeName(); int node_type, subsystem_type; int maj, min; - int ret, i, j, node_count, device_count; + int ret, i, node_count, device_count; int max_count = 16; - void *addr; local_devices = calloc(max_count, sizeof(drmDevicePtr)); if (local_devices == NULL) @@ -3061,44 +3129,11 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) switch (subsystem_type) { case DRM_BUS_PCI: - addr = device = calloc(1, sizeof(drmDevice) + - (DRM_NODE_MAX * - (sizeof(void *) + max_node_str)) + - sizeof(drmPciBusInfo) + - sizeof(drmPciDeviceInfo)); - if (!device) - goto free_devices; - - device->bustype = subsystem_type; - device->available_nodes = 1 << node_type; - - addr += sizeof(drmDevice); - device->nodes = addr; - - addr += DRM_NODE_MAX * sizeof(void *); - for (j = 0; j < DRM_NODE_MAX; j++) { - device->nodes[j] = addr; - addr += max_node_str; - } - memcpy(device->nodes[node_type], node, max_node_str); - - device->businfo.pci = addr; - - ret = drmParsePciBusInfo(maj, min, device->businfo.pci); + ret = drmProcessPciDevice(&device, dent->d_name, node, node_type, + maj, min, devices != NULL); if (ret) goto free_devices; - // Fetch the device info if the user has requested it - if (devices != NULL) { - addr += sizeof(drmPciBusInfo); - device->deviceinfo.pci = addr; - - ret = drmParsePciDeviceInfo(dent->d_name, - device->deviceinfo.pci); - if (ret) - goto free_devices; - } - break; default: fprintf(stderr, "The subsystem type is not supported yet\n"); @@ -3121,17 +3156,7 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) node_count = i; /* Fold nodes into a single device if they share the same bus info */ - for (i = 0; i < node_count; i++) { - for (j = i + 1; j < node_count; j++) { - if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) { - local_devices[i]->available_nodes |= local_devices[j]->available_nodes; - node_type = log2(local_devices[j]->available_nodes); - memcpy(local_devices[i]->nodes[node_type], - local_devices[j]->nodes[node_type], max_node_str); - drmFreeDevice(&local_devices[j]); - } - } - } + drmFoldDuplicatedDevices(local_devices, node_count); device_count = 0; for (i = 0; i < node_count && local_devices[i]; i++) { commit 8415a00a3f2f5cb4827b58b86e974900d3892d29 Author: Emil Velikov <[email protected]> Date: Mon Sep 7 18:29:05 2015 +0100 xf86drm: warn on missing drmGetMinorNameForFD implementation Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/xf86drm.c b/xf86drm.c index 3d03cbf..a783a28 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -2822,6 +2822,8 @@ static char *drmGetMinorNameForFD(int fd, int type) out_close_dir: closedir(sysdir); +#else +#warning "Missing implementation of drmGetMinorNameForFD" #endif return NULL; } commit 291b2bb92c5fc90101417b80bbdc6c994be5fff2 Author: Emil Velikov <[email protected]> Date: Mon Sep 7 18:26:34 2015 +0100 xf86drm: move ifdef __linux__ guards where needed Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/xf86drm.c b/xf86drm.c index 8105b42..3d03cbf 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -2836,9 +2836,9 @@ char *drmGetRenderDeviceNameFromFd(int fd) return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); } -#ifdef __linux__ static int drmParseSubsystemType(int maj, int min) { +#ifdef __linux__ char path[PATH_MAX + 1]; char link[PATH_MAX + 1] = ""; char *name; @@ -2857,10 +2857,15 @@ static int drmParseSubsystemType(int maj, int min) return DRM_BUS_PCI; return -EINVAL; +#else +#warning "Missing implementation of drmParseSubsystemType" + return -EINVAL; +#endif } static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) { +#ifdef __linux__ char path[PATH_MAX + 1]; char data[128]; char *str; @@ -2893,6 +2898,10 @@ static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) info->func = func; return 0; +#else +#warning "Missing implementation of drmParsePciBusInfo" + return -EINVAL; +#endif } static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b) @@ -2942,6 +2951,7 @@ static int drmGetMaxNodeName(void) static int drmParsePciDeviceInfo(const char *d_name, drmPciDeviceInfoPtr device) { +#ifdef __linux__ char path[PATH_MAX + 1]; unsigned char config[64]; int fd, ret; @@ -2963,6 +2973,10 @@ static int drmParsePciDeviceInfo(const char *d_name, device->subdevice_id = config[46] | (config[47] << 8); return 0; +#else +#warning "Missing implementation of drmParsePciDeviceInfo" + return -EINVAL; +#endif } static void drmFreeDevice(drmDevicePtr *device) @@ -3139,20 +3153,3 @@ close_sysdir: closedir(sysdir); return ret; } -#else -void drmFreeDevices(drmDevicePtr devices[], int count) -{ - (void)devices; - (void)count; -} - -int drmGetDevices(drmDevicePtr devices[], int max_devices) -{ - (void)devices; - (void)max_devices; - return -EINVAL; -} - -#warning "Missing implementation of drmGetDevices/drmFreeDevices" - -#endif commit 5f68d31820315ebda9b49e8bd50d1ab605efd7fa Author: Emil Velikov <[email protected]> Date: Mon Sep 7 13:54:32 2015 +0100 xf86drm: rework drmGetDevices() Do a once off memory allocation for each drmDevice. This allows us to ease the error handling and simplify the de-duplication loop. As part of this we need to rework drmFreeDevice() such so that it frees the relevant hunks, rather than leaving that to the caller. Some memory stats from the drmdevice test before: 22 allocs, 22 frees, 66,922 bytes allocated after: 9 allocs, 9 frees, 66,436 bytes allocated Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/xf86drm.c b/xf86drm.c index 310d1e8..8105b42 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -65,6 +65,8 @@ #include "xf86drm.h" #include "libdrm_macros.h" +#include "util_math.h" + #ifdef __OpenBSD__ #define DRM_PRIMARY_MINOR_NAME "drm" #define DRM_CONTROL_MINOR_NAME "drmC" @@ -2928,6 +2930,15 @@ static int drmGetNodeType(const char *name) return -EINVAL; } +static int drmGetMaxNodeName(void) +{ + return sizeof(DRM_DIR_NAME) + + MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), + sizeof(DRM_CONTROL_MINOR_NAME), + sizeof(DRM_RENDER_MINOR_NAME)) + + 3 /* lenght of the node number */; +} + static int drmParsePciDeviceInfo(const char *d_name, drmPciDeviceInfoPtr device) { @@ -2954,20 +2965,13 @@ static int drmParsePciDeviceInfo(const char *d_name, return 0; } -static void drmFreeDevice(drmDevicePtr device) +static void drmFreeDevice(drmDevicePtr *device) { - int i; - if (device == NULL) return; - if (device->nodes != NULL) - for (i = 0; i < DRM_NODE_MAX; i++) - free(device->nodes[i]); - - free(device->nodes); - free(device->businfo.pci); - free(device->deviceinfo.pci); + free(*device); + *device = NULL; } void drmFreeDevices(drmDevicePtr devices[], int count) @@ -2977,11 +2981,8 @@ void drmFreeDevices(drmDevicePtr devices[], int count) if (devices == NULL) return; - for (i = 0; i < count; i++) { - drmFreeDevice(devices[i]); - free(devices[i]); - devices[i] = NULL; - } + for (i = 0; i < count && devices[i] != NULL; i++) + drmFreeDevice(&devices[i]); } /** @@ -2998,29 +2999,30 @@ void drmFreeDevices(drmDevicePtr devices[], int count) */ int drmGetDevices(drmDevicePtr devices[], int max_devices) { - drmDevicePtr devs = NULL; - drmPciBusInfoPtr pcibus = NULL; - drmPciDeviceInfoPtr pcidevice = NULL; - DIR *sysdir = NULL; - struct dirent *dent = NULL; - struct stat sbuf = {0}; - char node[PATH_MAX + 1] = ""; + drmDevicePtr *local_devices; + drmDevicePtr device; + DIR *sysdir; + struct dirent *dent; + struct stat sbuf; + char node[PATH_MAX + 1]; + const int max_node_str = drmGetMaxNodeName(); int node_type, subsystem_type; int maj, min; - int ret, i = 0, j, node_count, device_count = 0; + int ret, i, j, node_count, device_count; int max_count = 16; - int *duplicated = NULL; + void *addr; - devs = calloc(max_count, sizeof(*devs)); - if (devs == NULL) + local_devices = calloc(max_count, sizeof(drmDevicePtr)); + if (local_devices == NULL) return -ENOMEM; sysdir = opendir(DRM_DIR_NAME); if (!sysdir) { ret = -errno; - goto free_locals; + goto close_sysdir; } + i = 0; while ((dent = readdir(sysdir))) { node_type = drmGetNodeType(dent->d_name); if (node_type < 0) @@ -3043,115 +3045,97 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) switch (subsystem_type) { case DRM_BUS_PCI: - pcibus = calloc(1, sizeof(*pcibus)); - if (pcibus == NULL) { - ret = -ENOMEM; - goto free_locals; + addr = device = calloc(1, sizeof(drmDevice) + + (DRM_NODE_MAX * + (sizeof(void *) + max_node_str)) + + sizeof(drmPciBusInfo) + + sizeof(drmPciDeviceInfo)); + if (!device) + goto free_devices; + + device->bustype = subsystem_type; + device->available_nodes = 1 << node_type; + + addr += sizeof(drmDevice); + device->nodes = addr; + + addr += DRM_NODE_MAX * sizeof(void *); + for (j = 0; j < DRM_NODE_MAX; j++) { + device->nodes[j] = addr; + addr += max_node_str; } + memcpy(device->nodes[node_type], node, max_node_str); - ret = drmParsePciBusInfo(maj, min, pcibus); - if (ret) - goto free_locals; - - if (i >= max_count) { - max_count += 16; - devs = realloc(devs, max_count * sizeof(*devs)); - } + device->businfo.pci = addr; - devs[i].businfo.pci = pcibus; - devs[i].bustype = subsystem_type; - devs[i].nodes = calloc(DRM_NODE_MAX, sizeof(char *)); - if (devs[i].nodes == NULL) { - ret = -ENOMEM; - goto free_locals; - } - devs[i].nodes[node_type] = strdup(node); - if (devs[i].nodes[node_type] == NULL) { - ret = -ENOMEM; - goto free_locals; - } - devs[i].available_nodes = 1 << node_type; + ret = drmParsePciBusInfo(maj, min, device->businfo.pci); + if (ret) + goto free_devices; + // Fetch the device info if the user has requested it if (devices != NULL) { - pcidevice = calloc(1, sizeof(*pcidevice)); - if (pcidevice == NULL) { - ret = -ENOMEM; - goto free_locals; - } + addr += sizeof(drmPciBusInfo); + device->deviceinfo.pci = addr; - ret = drmParsePciDeviceInfo(dent->d_name, pcidevice); + ret = drmParsePciDeviceInfo(dent->d_name, + device->deviceinfo.pci); if (ret) - goto free_locals; - - devs[i].deviceinfo.pci = pcidevice; + goto free_devices; } + break; default: fprintf(stderr, "The subsystem type is not supported yet\n"); break; } - i++; - } - node_count = i; + if (i >= max_count) { + drmDevicePtr *temp; - /* merge duplicated devices with same domain/bus/device/func IDs */ - duplicated = calloc(node_count, sizeof(*duplicated)); - if (duplicated == NULL) { - ret = -ENOMEM; - goto free_locals; + max_count += 16; + temp = realloc(local_devices, max_count * sizeof(drmDevicePtr)); + if (!temp) + goto free_devices; + local_devices = temp; + } + + local_devices[i] = device; + i++; } + node_count = i; + /* Fold nodes into a single device if they share the same bus info */ for (i = 0; i < node_count; i++) { - for (j = i+1; j < node_count; j++) { - if (duplicated[i] || duplicated[j]) - continue; - if (drmCompareBusInfo(&devs[i], &devs[j]) == 0) { - duplicated[j] = 1; - devs[i].available_nodes |= devs[j].available_nodes; - node_type = log2(devs[j].available_nodes); - devs[i].nodes[node_type] = devs[j].nodes[node_type]; - free(devs[j].nodes); - free(devs[j].businfo.pci); - free(devs[j].deviceinfo.pci); + for (j = i + 1; j < node_count; j++) { + if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) { + local_devices[i]->available_nodes |= local_devices[j]->available_nodes; + node_type = log2(local_devices[j]->available_nodes); + memcpy(local_devices[i]->nodes[node_type], + local_devices[j]->nodes[node_type], max_node_str); + drmFreeDevice(&local_devices[j]); } } } - for (i = 0; i < node_count; i++) { - if(duplicated[i] == 0) { - if ((devices != NULL) && (device_count < max_devices)) { - devices[device_count] = calloc(1, sizeof(drmDevice)); - if (devices[device_count] == NULL) { - ret = -ENOMEM; - break; - } - memcpy(devices[device_count], &devs[i], sizeof(drmDevice)); - } else - drmFreeDevice(&devs[i]); - device_count++; - } - } + device_count = 0; + for (i = 0; i < node_count && local_devices[i]; i++) { + if ((devices != NULL) && (device_count < max_devices)) + devices[device_count] = local_devices[i]; + else + drmFreeDevice(&local_devices[i]); - if (i < node_count) { - drmFreeDevices(devices, device_count); - for ( ; i < node_count; i++) - if(duplicated[i] == 0) - drmFreeDevice(&devs[i]); - } else - ret = device_count; + device_count++; + } - free(duplicated); - free(devs); + free(local_devices); closedir(sysdir); - return ret; + return device_count; + +free_devices: + drmFreeDevices(local_devices, i); + free(local_devices); -free_locals: - for (j = 0; j < i; j++) - drmFreeDevice(&devs[j]); - free(pcidevice); - free(pcibus); - free(devs); +close_sysdir: closedir(sysdir); return ret; } commit 6c88173f7ecc2470341ca96e91b6ccb0a5efbef6 Author: Emil Velikov <[email protected]> Date: Mon Sep 7 14:13:32 2015 +0100 util_math: add MAX3 macro Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/util_math.h b/util_math.h index 3bc5f64..02b15a8 100644 --- a/util_math.h +++ b/util_math.h @@ -26,6 +26,7 @@ #define MIN2( A, B ) ( (A)<(B) ? (A) : (B) ) #define MAX2( A, B ) ( (A)>(B) ? (A) : (B) ) +#define MAX3( A, B, C ) ((A) > (B) ? MAX2(A, C) : MAX2(B, C)) #define __align_mask(value, mask) (((value) + (mask)) & ~(mask)) #define ALIGN(value, alignment) __align_mask(value, (typeof(value))((alignment) - 1)) commit bc2aca9e22bf2cc82874f3e44568c684eec9c5e1 Author: Emil Velikov <[email protected]> Date: Mon Sep 7 13:51:54 2015 +0100 xf86drm: rename drmSameDevice to drmCompareBusInfo Move away form the boolean name, change the return value appropriately and check if either argument is NULL. Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/xf86drm.c b/xf86drm.c index dc1782d..310d1e8 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -2893,20 +2893,22 @@ static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) return 0; } -static int drmSameDevice(drmDevicePtr a, drmDevicePtr b) +static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b) { + if (a == NULL || b == NULL) + return -1; + if (a->bustype != b->bustype) - return 0; + return -1; switch (a->bustype) { case DRM_BUS_PCI: - if (memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0) - return 1; + return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)); default: break; } - return 0; + return -1; } static int drmGetNodeType(const char *name) @@ -3104,7 +3106,7 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) for (j = i+1; j < node_count; j++) { if (duplicated[i] || duplicated[j]) continue; - if (drmSameDevice(&devs[i], &devs[j])) { + if (drmCompareBusInfo(&devs[i], &devs[j]) == 0) { duplicated[j] = 1; devs[i].available_nodes |= devs[j].available_nodes; node_type = log2(devs[j].available_nodes); commit a250fceaaa150363accaf3fb71a0e42bcecc40da Author: Emil Velikov <[email protected]> Date: Mon Sep 7 12:54:27 2015 +0100 xf86drm: move the final linux specific bits out of drmGetDevices Third and final piece of making drmGetDevices less crazy/ugly. Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/xf86drm.c b/xf86drm.c index 1174a64..dc1782d 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -2835,21 +2835,23 @@ char *drmGetRenderDeviceNameFromFd(int fd) } #ifdef __linux__ -static int drmParseSubsystemType(const char *str) +static int drmParseSubsystemType(int maj, int min) { + char path[PATH_MAX + 1]; char link[PATH_MAX + 1] = ""; char *name; - if (readlink(str, link, PATH_MAX) < 0) - return -EINVAL; + snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem", + maj, min); + + if (readlink(path, link, PATH_MAX) < 0) + return -errno; name = strrchr(link, '/'); if (!name) return -EINVAL; - name++; - - if (strncmp(name, "pci", 3) == 0) + if (strncmp(name, "/pci", 4) == 0) return DRM_BUS_PCI; return -EINVAL; @@ -3001,7 +3003,6 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) struct dirent *dent = NULL; struct stat sbuf = {0}; char node[PATH_MAX + 1] = ""; - char path[PATH_MAX + 1] = ""; int node_type, subsystem_type; int maj, min; int ret, i = 0, j, node_count, device_count = 0; @@ -3033,9 +3034,7 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) continue; - snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem", - maj, min); - subsystem_type = drmParseSubsystemType(path); + subsystem_type = drmParseSubsystemType(maj, min); if (subsystem_type < 0) continue; commit ef5192e9c7897c82da815a2c893b2e2562997a3a Author: Emil Velikov <[email protected]> Date: Mon Sep 7 12:47:47 2015 +0100 xf86drm: move platform details to drmParsePciDeviceInfo() As with previous commit let's try to keep drmGetDevices clean of linux specifics. Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/xf86drm.c b/xf86drm.c index b4c5aa0..1174a64 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -2924,11 +2924,22 @@ static int drmGetNodeType(const char *name) return -EINVAL; } -static int drmParsePciDeviceInfo(const unsigned char *config, +static int drmParsePciDeviceInfo(const char *d_name, drmPciDeviceInfoPtr device) { - if (config == NULL) - return -EINVAL; + char path[PATH_MAX + 1]; + unsigned char config[64]; + int fd, ret; + + snprintf(path, PATH_MAX, "/sys/class/drm/%s/device/config", d_name); + fd = open(path, O_RDONLY); + if (fd < 0) + return -errno; + + ret = read(fd, config, sizeof(config)); + close(fd); + if (ret < 0) + return -errno; device->vendor_id = config[0] | (config[1] << 8); device->device_id = config[2] | (config[3] << 8); @@ -2991,10 +3002,8 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) struct stat sbuf = {0}; char node[PATH_MAX + 1] = ""; char path[PATH_MAX + 1] = ""; - unsigned char config[64] = ""; int node_type, subsystem_type; int maj, min; - int fd; int ret, i = 0, j, node_count, device_count = 0; int max_count = 16; int *duplicated = NULL; @@ -3063,32 +3072,17 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) devs[i].available_nodes = 1 << node_type; if (devices != NULL) { - snprintf(path, PATH_MAX, "/sys/class/drm/%s/device/config", - dent->d_name); - fd = open(path, O_RDONLY); - if (fd < 0) { - ret = -errno; - goto free_locals; - } - ret = read(fd, config, 64); - if (ret < 0) { - ret = -errno; - close(fd); - goto free_locals; - } - pcidevice = calloc(1, sizeof(*pcidevice)); if (pcidevice == NULL) { ret = -ENOMEM; goto free_locals; } - ret = drmParsePciDeviceInfo(config, pcidevice); + ret = drmParsePciDeviceInfo(dent->d_name, pcidevice); if (ret) goto free_locals; devs[i].deviceinfo.pci = pcidevice; - close(fd); } break; default: commit 536e0deba3829e194aafda6d9a1d9e938ba8277a Author: Emil Velikov <[email protected]> Date: Mon Sep 7 12:37:57 2015 +0100 xf86drm: flex platform specifics into drmParsePciBusInfo This will allow one to reuse the core drmGetDevices implementation on other platforms. Keeping all the platform specifics in ParseFoo. On the plus side this saves a bit of code :) Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/xf86drm.c b/xf86drm.c index a5a7b41..b4c5aa0 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -2855,23 +2855,33 @@ static int drmParseSubsystemType(const char *str) return -EINVAL; } -static int drmParsePciBusInfo(const char *str, drmPciBusInfoPtr info) +static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) { + char path[PATH_MAX + 1]; + char data[128]; + char *str; int domain, bus, dev, func; - char *value; + int fd, ret; - if (str == NULL) - return -EINVAL; + snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/uevent", maj, min); + fd = open(path, O_RDONLY); + if (fd < 0) + return -errno; - value = strstr(str, "PCI_SLOT_NAME="); - if (value == NULL) - return -EINVAL; + ret = read(fd, data, sizeof(data)); + close(fd); + if (ret < 0) + return -errno; - value += strlen("PCI_SLOT_NAME="); +#define TAG "PCI_SLOT_NAME=" + str = strstr(data, TAG); + if (str == NULL) + return -EINVAL; - if (sscanf(value, "%04x:%02x:%02x.%1u", + if (sscanf(str, TAG "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func) != 4) return -EINVAL; +#undef TAG info->domain = domain; info->bus = bus; @@ -2981,7 +2991,6 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) struct stat sbuf = {0}; char node[PATH_MAX + 1] = ""; char path[PATH_MAX + 1] = ""; - char data[128] = ""; unsigned char config[64] = ""; int node_type, subsystem_type; int maj, min; @@ -3030,22 +3039,7 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices) goto free_locals; } - snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/uevent", - maj, min); - fd = open(path, O_RDONLY); - if (fd < 0) { - ret = -errno; - goto free_locals; - } - ret = read(fd, data, sizeof(data)); - if (ret < 0) { - ret = -errno; - close(fd); - goto free_locals; - } - - ret = drmParsePciBusInfo(data, pcibus); - close(fd); + ret = drmParsePciBusInfo(maj, min, pcibus); if (ret) goto free_locals; commit f098d1c130f369f059a53cda5c38b3d4ea06a0b7 Author: Emil Velikov <[email protected]> Date: Wed Sep 9 16:48:29 2015 +0100 tests/drmdevice: add new 'test' A simple example of how to use/what is the new drm{Get,Free}Devices() interface. Signed-off-by: Emil Velikov <[email protected]> Acked-by: Alex Deucher <[email protected]> diff --git a/tests/Makefile.am b/tests/Makefile.am index a511d28..c53f4af 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -31,6 +31,7 @@ LDADD = $(top_builddir)/libdrm.la check_PROGRAMS = \ dristat \ + drmdevice \ drmstat dristat_LDADD = -lm diff --git a/tests/drmdevice.c b/tests/drmdevice.c new file mode 100644 index 0000000..4055f45 --- /dev/null +++ b/tests/drmdevice.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015 Emil Velikov <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <xf86drm.h> + + +static void +print_device_info(drmDevicePtr device, int i) +{ + printf("device[%i]\n", i); + printf("\tavailable_nodes %04x\n", device->available_nodes); + printf("\tnodes\n"); + for (int j = 0; j < DRM_NODE_MAX; j++) + if (device->available_nodes & 1 << j) + printf("\t\tnodes[%d] %s\n", j, device->nodes[j]); + + printf("\tbustype %04x\n", device->bustype); + printf("\tbusinfo\n"); + if (device->bustype == DRM_BUS_PCI) { + printf("\t\tpci\n"); + printf("\t\t\tdomain\t%04x\n",device->businfo.pci->domain); + printf("\t\t\tbu\t%02x\n", device->businfo.pci->bus); + printf("\t\t\tde\t%02x\n", device->businfo.pci->dev); + printf("\t\t\tfunc\t%1u\n", device->businfo.pci->func); + + printf("\tdeviceinfo\n"); + printf("\t\tpci\n"); + printf("\t\t\tvendor_id\t%04x\n", device->deviceinfo.pci->vendor_id); + printf("\t\t\tdevice_id\t%04x\n", device->deviceinfo.pci->device_id); + printf("\t\t\tsubvendor_id\t%04x\n", device->deviceinfo.pci->subvendor_id); + printf("\t\t\tsubdevice_id\t%04x\n", device->deviceinfo.pci->subdevice_id); + printf("\t\t\trevision_id\t%02x\n", device->deviceinfo.pci->revision_id); + } else { + printf("Unknown/unhandled bustype\n"); + } + printf("\n"); +} + +int +main(void) +{ + drmDevicePtr *devices; + int ret, max_devices; + + max_devices = drmGetDevices(NULL, 0); + + if (max_devices <= 0) { + printf("drmGetDevices() has returned %d\n", max_devices); + return -1; + } + + devices = calloc(max_devices, sizeof(drmDevicePtr)); + if (devices == NULL) { + printf("Failed to allocate memory for the drmDevicePtr array\n"); + return -1; + } + + ret = drmGetDevices(devices, max_devices); + if (ret < 0) { + printf("drmGetDevices() returned an error %d\n", ret); + free(devices); + return -1; + } + + for (int i = 0; i < ret; i++) + print_device_info(devices[i], i); + + drmFreeDevices(devices, ret); + free(devices); + return 0; +} commit ed3c665548c2c0400a7e9e91cb9324c9e1f29375 Author: Emil Velikov <[email protected]> Date: Sat Sep 5 17:20:53 2015 +0100 xf86drmMode: smoke-test the atomic API As going through the modetest patches for atomic support I've noticed that if we pass NULL for the drmModeAtomicReqPtr argument we'll crash. So let's handle things appropriately if the user forgot to check the return value of drmModeAtomicAlloc and drmModeAtomicDuplicate or made a typo somewhere along the way. Cc: Ville Syrjälä <[email protected]> Cc: Rob Clark <[email protected]> Cc: Daniel Stone <[email protected]> Signed-off-by: Emil Velikov <[email protected]> diff --git a/xf86drmMode.c b/xf86drmMode.c index 23800dd..ab6b519 100644 --- a/xf86drmMode.c +++ b/xf86drmMode.c @@ -1189,6 +1189,9 @@ drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr old) { drmModeAtomicReqPtr new; + if (!old) + return NULL; + new = drmMalloc(sizeof *new); if (!new) return NULL; @@ -1213,6 +1216,9 @@ drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr old) int drmModeAtomicMerge(drmModeAtomicReqPtr base, drmModeAtomicReqPtr augment) { + if (!base) + return -EINVAL; + if (!augment || augment->cursor == 0) return 0; @@ -1239,12 +1245,15 @@ int drmModeAtomicMerge(drmModeAtomicReqPtr base, drmModeAtomicReqPtr augment) int drmModeAtomicGetCursor(drmModeAtomicReqPtr req) { + if (!req) + return -EINVAL; return req->cursor; } void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor) { - req->cursor = cursor; + if (req) + req->cursor = cursor; } int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, @@ -1252,6 +1261,9 @@ int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, uint32_t property_id, uint64_t value) { + if (!req) + return -EINVAL; + if (req->cursor >= req->size_items) { drmModeAtomicReqItemPtr new; @@ -1309,6 +1321,9 @@ int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, uint32_t flags, int obj_idx = -1; int ret = -1; + if (!req) + return -EINVAL; + if (req->cursor == 0) return 0; commit 00808a99d05929f675bb4ab680a1ffc6d0868ba4 Author: Emil Velikov <[email protected]> Date: Fri Sep 4 22:06:44 2015 +0100 automake: set --enable-valgrind during make distcheck Signed-off-by: Emil Velikov <[email protected]> diff --git a/Makefile.am b/Makefile.am index a7a0cca..ca41508 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,7 +37,8 @@ AM_DISTCHECK_CONFIGURE_FLAGS = \ --enable-tegra-experimental-api \ --enable-install-test-programs \ --enable-cairo-tests \ - --enable-manpages + --enable-manpages \ + --enable-valgrind pkgconfigdir = @pkgconfigdir@ pkgconfig_DATA = libdrm.pc ------------------------------------------------------------------------------ -- _______________________________________________ Dri-patches mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/dri-patches