ubwcp: ioctl for stride alignment and bytes per pixels
Implements stride alignment and stride validate IOCTL. Additional checks on stride value. Fixes spell error in ioctl interface. Change-Id: Ic4a41a12e2ffa8d45fd71938133accd069dff863 Signed-off-by: Amol Jadi <quic_ajadi@quicinc.com>
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

szülő
14742c1cfb
commit
7049c53fc2
@@ -99,7 +99,7 @@ struct ubwcp_smmu_fault_err_info {
|
||||
int iommu_fault_flags;
|
||||
};
|
||||
|
||||
struct unwcp_err_info {
|
||||
struct ubwcp_err_info {
|
||||
enum ubwcp_error err_code;
|
||||
union {
|
||||
struct ubwcp_enc_err_info enc_err;
|
||||
@@ -109,7 +109,7 @@ struct unwcp_err_info {
|
||||
};
|
||||
};
|
||||
|
||||
typedef void (*ubwcp_error_handler_t)(struct unwcp_err_info *err, void *data);
|
||||
typedef void (*ubwcp_error_handler_t)(struct ubwcp_err_info *err, void *data);
|
||||
|
||||
/*
|
||||
* Register an error handler
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __UBWCP_IOCTL_H_
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#define UBWCP_IOCTL_SET_BUF_ATTR _IOW('U', 1, struct ubwcp_ioctl_buffer_attrs)
|
||||
#define UBWCP_IOCTL_GET_HW_VER _IOR('U', 2, struct ubwcp_ioctl_hw_version)
|
||||
#define UBWCP_IOCTL_GET_STRIDE_ALIGN _IOWR('U', 3, struct ubwcp_ioctl_stride_align)
|
||||
#define UBWCP_IOCTL_VALIDATE_STRIDE _IOWR('U', 4, struct ubwcp_ioctl_validate_stride)
|
||||
|
||||
|
||||
enum ubwcp_image_format {
|
||||
@@ -115,4 +117,35 @@ struct ubwcp_ioctl_hw_version {
|
||||
__u32 minor;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stride alignment for given format
|
||||
* @image_format: image format
|
||||
* @stride_align: stride alignment
|
||||
* @unused: must be set to 0
|
||||
* IOCTL will fail for linear image format
|
||||
*/
|
||||
struct ubwcp_ioctl_stride_align {
|
||||
__u16 image_format;
|
||||
__u16 stride_align;
|
||||
__u32 unused;
|
||||
};
|
||||
|
||||
/**
|
||||
* validate stride
|
||||
* @image_format: image format
|
||||
* @width: image width in pixels
|
||||
* @stride: image stride in bytes
|
||||
* @valid: returns 0 (not valid), 1 (valid)
|
||||
* @unusedX: must be set to 0
|
||||
* IOCTL will fail for linear image format
|
||||
*/
|
||||
struct ubwcp_ioctl_validate_stride {
|
||||
__u16 image_format;
|
||||
__u32 width;
|
||||
__u32 stride;
|
||||
__u16 valid;
|
||||
__u16 unused1;
|
||||
__u16 unused2;
|
||||
};
|
||||
|
||||
#endif /* __UBWCP_IOCTL_H_ */
|
||||
|
@@ -211,19 +211,19 @@ static void image_format_init(struct ubwcp_driver *ubwcp)
|
||||
{1, {{4, 1, {16, 4}, {64, 16}}}};
|
||||
ubwcp->format_info[NV12] = (struct ubwcp_image_format_info)
|
||||
{2, {{1, 1, {32, 8}, {128, 32}},
|
||||
{2, 1, {16, 8}, { 64, 32}}}};
|
||||
{2, 1, {16, 8}, { 64, 32}}}};
|
||||
ubwcp->format_info[NV124R] = (struct ubwcp_image_format_info)
|
||||
{2, {{1, 1, {64, 4}, {256, 16}},
|
||||
{2, 1, {32, 4}, {128, 16}}}};
|
||||
{2, 1, {32, 4}, {128, 16}}}};
|
||||
ubwcp->format_info[P010] = (struct ubwcp_image_format_info)
|
||||
{2, {{2, 1, {32, 4}, {128, 16}},
|
||||
{4, 1, {16, 4}, { 64, 16}}}};
|
||||
{4, 1, {16, 4}, { 64, 16}}}};
|
||||
ubwcp->format_info[TP10] = (struct ubwcp_image_format_info)
|
||||
{2, {{4, 3, {48, 4}, {192, 16}},
|
||||
{8, 3, {24, 4}, { 96, 16}}}};
|
||||
{8, 3, {24, 4}, { 96, 16}}}};
|
||||
ubwcp->format_info[P016] = (struct ubwcp_image_format_info)
|
||||
{2, {{2, 1, {32, 4}, {128, 16}},
|
||||
{4, 1, {16, 4}, { 64, 16}}}};
|
||||
{4, 1, {16, 4}, { 64, 16}}}};
|
||||
}
|
||||
|
||||
static void ubwcp_buf_desc_list_init(struct ubwcp_driver *ubwcp)
|
||||
@@ -686,12 +686,111 @@ static void dump_attributes(struct ubwcp_buffer_attrs *attr)
|
||||
DBG_BUF_ATTR("");
|
||||
}
|
||||
|
||||
/* validate buffer attributes */
|
||||
static bool ubwcp_buf_attrs_valid(struct ubwcp_buffer_attrs *attr)
|
||||
static enum ubwcp_std_image_format to_std_format(u16 ioctl_image_format)
|
||||
{
|
||||
bool valid_format;
|
||||
switch (ioctl_image_format) {
|
||||
case UBWCP_RGBA8888:
|
||||
return RGBA;
|
||||
case UBWCP_NV12:
|
||||
case UBWCP_NV12_Y:
|
||||
case UBWCP_NV12_UV:
|
||||
return NV12;
|
||||
case UBWCP_NV124R:
|
||||
case UBWCP_NV124R_Y:
|
||||
case UBWCP_NV124R_UV:
|
||||
return NV124R;
|
||||
case UBWCP_TP10:
|
||||
case UBWCP_TP10_Y:
|
||||
case UBWCP_TP10_UV:
|
||||
return TP10;
|
||||
case UBWCP_P010:
|
||||
case UBWCP_P010_Y:
|
||||
case UBWCP_P010_UV:
|
||||
return P010;
|
||||
case UBWCP_P016:
|
||||
case UBWCP_P016_Y:
|
||||
case UBWCP_P016_UV:
|
||||
return P016;
|
||||
default:
|
||||
WARN(1, "Fix this!!!");
|
||||
return STD_IMAGE_FORMAT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
switch (attr->image_format) {
|
||||
static int get_stride_alignment(enum ubwcp_std_image_format format, u16 *align)
|
||||
{
|
||||
switch (format) {
|
||||
case TP10:
|
||||
*align = 64;
|
||||
return 0;
|
||||
case NV12:
|
||||
*align = 128;
|
||||
return 0;
|
||||
case RGBA:
|
||||
case NV124R:
|
||||
case P010:
|
||||
case P016:
|
||||
*align = 256;
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* returns stride of compressed image */
|
||||
static u32 get_compressed_stride(struct ubwcp_driver *ubwcp,
|
||||
enum ubwcp_std_image_format format, u32 width)
|
||||
{
|
||||
struct ubwcp_plane_info p_info;
|
||||
u16 macro_tile_width_p;
|
||||
u16 pixel_bytes;
|
||||
u16 per_pixel;
|
||||
|
||||
p_info = ubwcp->format_info[format].p_info[0];
|
||||
macro_tile_width_p = p_info.macrotilesize_p.width;
|
||||
pixel_bytes = p_info.pixel_bytes;
|
||||
per_pixel = p_info.per_pixel;
|
||||
|
||||
return UBWCP_ALIGN(width, macro_tile_width_p)*pixel_bytes/per_pixel;
|
||||
}
|
||||
|
||||
/* check if linear stride conforms to hw limitations
|
||||
* always returns false for linear image
|
||||
*/
|
||||
static bool stride_is_valid(struct ubwcp_driver *ubwcp,
|
||||
u16 ioctl_img_fmt, u32 width, u32 lin_stride)
|
||||
{
|
||||
u32 compressed_stride;
|
||||
enum ubwcp_std_image_format format = to_std_format(ioctl_img_fmt);
|
||||
|
||||
if (format == STD_IMAGE_FORMAT_INVALID)
|
||||
return false;
|
||||
|
||||
if ((lin_stride < width) || (lin_stride > 64*1024)) {
|
||||
ERR("stride is not valid (width <= stride <= 64K): %d", lin_stride);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (format == TP10) {
|
||||
if(!IS_ALIGNED(lin_stride, 64)) {
|
||||
ERR("stride must be aligned to 64: %d", lin_stride);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
compressed_stride = get_compressed_stride(ubwcp, format, width);
|
||||
if (lin_stride != compressed_stride) {
|
||||
ERR("linear stride: %d must be same as compressed stride: %d",
|
||||
lin_stride, compressed_stride);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ioctl_format_is_valid(u16 ioctl_image_format)
|
||||
{
|
||||
switch (ioctl_image_format) {
|
||||
case UBWCP_LINEAR:
|
||||
case UBWCP_RGBA8888:
|
||||
case UBWCP_NV12:
|
||||
@@ -709,13 +808,16 @@ static bool ubwcp_buf_attrs_valid(struct ubwcp_buffer_attrs *attr)
|
||||
case UBWCP_P016:
|
||||
case UBWCP_P016_Y:
|
||||
case UBWCP_P016_UV:
|
||||
valid_format = true;
|
||||
break;
|
||||
return true;
|
||||
default:
|
||||
valid_format = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid_format) {
|
||||
/* validate buffer attributes */
|
||||
static bool ubwcp_buf_attrs_valid(struct ubwcp_driver *ubwcp, struct ubwcp_buffer_attrs *attr)
|
||||
{
|
||||
if (!ioctl_format_is_valid(attr->image_format)) {
|
||||
ERR("invalid image format: %d", attr->image_format);
|
||||
goto err;
|
||||
}
|
||||
@@ -749,19 +851,14 @@ static bool ubwcp_buf_attrs_valid(struct ubwcp_buffer_attrs *attr)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (attr->image_format != UBWCP_LINEAR)
|
||||
if(!stride_is_valid(ubwcp, attr->image_format, attr->width, attr->stride)) {
|
||||
ERR("stride is invalid: %d", attr->stride);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* TBD: what's the upper limit for stride? 8K is likely too high. */
|
||||
if (!IS_ALIGNED(attr->stride, 64) ||
|
||||
(attr->stride < attr->width) ||
|
||||
(attr->stride > 4*8192)) {
|
||||
ERR("stride is not valid (aligned to 64 and <= 8192): %d",
|
||||
attr->stride);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* TBD: currently assume height + 10. Replace 10 with right num from camera. */
|
||||
if ((attr->scanlines < attr->height) ||
|
||||
(attr->scanlines > attr->height + 10)) {
|
||||
(attr->scanlines > attr->height + 32*1024)) {
|
||||
ERR("scanlines is not valid - height: %d scanlines: %d",
|
||||
attr->height, attr->scanlines);
|
||||
goto err;
|
||||
@@ -1054,37 +1151,6 @@ int planes_in_format(enum ubwcp_std_image_format format)
|
||||
return 2;
|
||||
}
|
||||
|
||||
enum ubwcp_std_image_format to_std_format(u16 ioctl_image_format)
|
||||
{
|
||||
switch (ioctl_image_format) {
|
||||
case UBWCP_RGBA8888:
|
||||
return RGBA;
|
||||
case UBWCP_NV12:
|
||||
case UBWCP_NV12_Y:
|
||||
case UBWCP_NV12_UV:
|
||||
return NV12;
|
||||
case UBWCP_NV124R:
|
||||
case UBWCP_NV124R_Y:
|
||||
case UBWCP_NV124R_UV:
|
||||
return NV124R;
|
||||
case UBWCP_TP10:
|
||||
case UBWCP_TP10_Y:
|
||||
case UBWCP_TP10_UV:
|
||||
return TP10;
|
||||
case UBWCP_P010:
|
||||
case UBWCP_P010_Y:
|
||||
case UBWCP_P010_UV:
|
||||
return P010;
|
||||
case UBWCP_P016:
|
||||
case UBWCP_P016_Y:
|
||||
case UBWCP_P016_UV:
|
||||
return P016;
|
||||
default:
|
||||
WARN(1, "Fix this!!!");
|
||||
return STD_IMAGE_FORMAT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int ubwcp_get_hw_image_format_value(u16 ioctl_image_format)
|
||||
{
|
||||
enum ubwcp_std_image_format format;
|
||||
@@ -1559,13 +1625,11 @@ int ubwcp_set_buf_attrs(struct dma_buf *dmabuf, struct ubwcp_buffer_attrs *attr)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!ubwcp_buf_attrs_valid(attr)) {
|
||||
if (!ubwcp_buf_attrs_valid(ubwcp, attr)) {
|
||||
ERR("Invalid buf attrs");
|
||||
goto err;
|
||||
}
|
||||
|
||||
DBG_BUF_ATTR("valid buf attrs");
|
||||
|
||||
if (attr->image_format == UBWCP_LINEAR) {
|
||||
DBG_BUF_ATTR("Linear format requested");
|
||||
|
||||
@@ -2234,12 +2298,15 @@ static int ubwcp_close(struct inode *i, struct file *f)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* handle IOCTLs */
|
||||
static long ubwcp_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
|
||||
{
|
||||
struct ubwcp_ioctl_buffer_attrs buf_attr_ioctl;
|
||||
struct ubwcp_ioctl_hw_version hw_ver;
|
||||
struct ubwcp_ioctl_validate_stride validate_stride_ioctl;
|
||||
struct ubwcp_ioctl_stride_align stride_align_ioctl;
|
||||
enum ubwcp_std_image_format format;
|
||||
struct ubwcp_driver *ubwcp;
|
||||
|
||||
switch (ioctl_num) {
|
||||
case UBWCP_IOCTL_SET_BUF_ATTR:
|
||||
@@ -2260,6 +2327,68 @@ static long ubwcp_ioctl(struct file *file, unsigned int ioctl_num, unsigned long
|
||||
}
|
||||
break;
|
||||
|
||||
case UBWCP_IOCTL_GET_STRIDE_ALIGN:
|
||||
DBG("IOCTL : GET_STRIDE_ALIGN");
|
||||
if (copy_from_user(&stride_align_ioctl, (const void __user *) ioctl_param,
|
||||
sizeof(stride_align_ioctl))) {
|
||||
ERR("ERROR: copy_from_user() failed");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
format = to_std_format(stride_align_ioctl.image_format);
|
||||
if (format == STD_IMAGE_FORMAT_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
if (stride_align_ioctl.unused != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (get_stride_alignment(format, &stride_align_ioctl.stride_align)) {
|
||||
ERR("ERROR: copy_to_user() failed");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *)ioctl_param, &stride_align_ioctl,
|
||||
sizeof(stride_align_ioctl))) {
|
||||
ERR("ERROR: copy_to_user() failed");
|
||||
return -EFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case UBWCP_IOCTL_VALIDATE_STRIDE:
|
||||
DBG("IOCTL : VALIDATE_STRIDE");
|
||||
ubwcp = ubwcp_get_driver();
|
||||
if (!ubwcp)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&validate_stride_ioctl, (const void __user *) ioctl_param,
|
||||
sizeof(validate_stride_ioctl))) {
|
||||
ERR("ERROR: copy_from_user() failed");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
format = to_std_format(validate_stride_ioctl.image_format);
|
||||
if (format == STD_IMAGE_FORMAT_INVALID) {
|
||||
ERR("ERROR: invalid format: %d", validate_stride_ioctl.image_format);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (validate_stride_ioctl.unused1 || validate_stride_ioctl.unused2) {
|
||||
ERR("ERROR: unused values must be set to 0");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
validate_stride_ioctl.valid = stride_is_valid(ubwcp,
|
||||
validate_stride_ioctl.image_format,
|
||||
validate_stride_ioctl.width,
|
||||
validate_stride_ioctl.stride);
|
||||
|
||||
if (copy_to_user((void __user *)ioctl_param, &validate_stride_ioctl,
|
||||
sizeof(validate_stride_ioctl))) {
|
||||
ERR("ERROR: copy_to_user() failed");
|
||||
return -EFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ERR("Invalid ioctl_num = %d", ioctl_num);
|
||||
return -EINVAL;
|
||||
@@ -2394,7 +2523,7 @@ int ubwcp_register_error_handler(u32 client_id, ubwcp_error_handler_t handler,
|
||||
}
|
||||
EXPORT_SYMBOL(ubwcp_register_error_handler);
|
||||
|
||||
static void ubwcp_notify_error_handlers(struct unwcp_err_info *err)
|
||||
static void ubwcp_notify_error_handlers(struct ubwcp_err_info *err)
|
||||
{
|
||||
struct handler_node *node;
|
||||
unsigned long flags;
|
||||
@@ -2498,7 +2627,7 @@ int ubwcp_iommu_fault_handler(struct iommu_domain *domain, struct device *dev,
|
||||
unsigned long iova, int flags, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
struct unwcp_err_info err;
|
||||
struct ubwcp_err_info err;
|
||||
struct ubwcp_driver *ubwcp = ubwcp_get_driver();
|
||||
struct device *cb_dev = (struct device *)data;
|
||||
|
||||
@@ -2537,7 +2666,7 @@ irqreturn_t ubwcp_irq_handler(int irq, void *ptr)
|
||||
void __iomem *base;
|
||||
u64 src;
|
||||
phys_addr_t addr;
|
||||
struct unwcp_err_info err;
|
||||
struct ubwcp_err_info err;
|
||||
|
||||
error_print_count++;
|
||||
|
||||
|
Reference in New Issue
Block a user