bcm2835-camera: fix operation on arm64 40/162940/2
authorSeung-Woo Kim <sw0312.kim@samsung.com>
Thu, 7 Dec 2017 06:31:57 +0000 (15:31 +0900)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Thu, 7 Dec 2017 06:36:50 +0000 (15:36 +0900)
The 8MP camera module did not work on arm64 because some struct size
is not valid on 64bit. Fix the camera operation on arm64 with
backporting some struct and their usage from rpi-4.14.y branch of
https://github.com/raspberrypi/linux.git git tree.

Change-Id: I31577b20671ebdc98299d8c58e3e8ac237542ce2
Signed-off-by: Hackseung Lee <lhs@dignsys.com>
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
drivers/media/platform/bcm2835/Kconfig
drivers/media/platform/bcm2835/bcm2835-camera.c
drivers/media/platform/bcm2835/mmal-msg-format.h
drivers/media/platform/bcm2835/mmal-msg-port.h
drivers/media/platform/bcm2835/mmal-msg.h
drivers/media/platform/bcm2835/mmal-vchiq.c
drivers/media/platform/bcm2835/mmal-vchiq.h

index e2f992c7710e9e6df9ea57387e1c3dd64400abdd..d80a3ecd33d8cffc147dd639105d100792569144 100644 (file)
@@ -15,6 +15,7 @@ config VIDEO_BCM2835_MMAL
        tristate "Broadcom BM2835 MMAL camera interface driver"
        depends on BCM2835_VCHIQ
        select VIDEOBUF2_VMALLOC
+       select BTREE
        ---help---
          This is a V4L2 driver for the Broadcom BCM2835 MMAL camera host interface
 
index 6bdec0806126044cf7146d53326e4da5b4269884..39e9f363e93d151e0e4d8c4bfd6a66976f5a304d 100644 (file)
@@ -1612,7 +1612,7 @@ static int set_camera_parameters(struct vchiq_mmal_instance *instance,
 static int __init mmal_init(struct bm2835_mmal_dev *dev)
 {
        int ret;
-       struct mmal_es_format *format;
+       struct mmal_es_format_local *format;
        u32 bool_true = 1;
        u32 supported_encodings[MAX_SUPPORTED_ENCODINGS];
        int param_size;
index 123d86ef582b0d059d1d5d14ba9add56b7365419..ba37d6dca6627f6ea3ea2659598c6e93d70ade0a 100644 (file)
@@ -54,7 +54,7 @@ union mmal_es_specific_format {
 };
 
 /** Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
-struct mmal_es_format {
+struct mmal_es_format_local {
        u32 type;      /* enum mmal_es_type */
 
        u32 encoding;  /* FourCC specifying encoding of the elementary stream.*/
@@ -78,4 +78,26 @@ struct mmal_es_format {
        u8  *extradata;           /**< Codec specific data */
 };
 
+/** Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
+struct mmal_es_format {
+       u32 type;      /* enum mmal_es_type */
+
+       u32 encoding;  /* FourCC specifying encoding of the elementary stream.*/
+       u32 encoding_variant; /* FourCC specifying the specific
+                              * encoding variant of the elementary
+                              * stream.
+                              */
+
+       u32 es; /* Type specific
+                * information for the
+                * elementary stream
+                */
+
+       u32 bitrate;        /**< Bitrate in bits per second */
+       u32 flags; /**< Flags describing properties of the elementary stream. */
+
+       u32 extradata_size;       /**< Size of the codec specific data */
+       u32 extradata;           /**< Codec specific data */
+};
+
 #endif /* MMAL_MSG_FORMAT_H */
index a55c1ea2eceb190689910a6a84370f126b1e9cbb..369d5d02c350312dea1dd54c8b37b0607d2659bf 100644 (file)
@@ -42,15 +42,15 @@ enum mmal_port_type {
  * buffer_num, buffer_size and userdata parameters are writable.
  */
 struct mmal_port {
-       void *priv; /* Private member used by the framework */
-       const char *name; /* Port name. Used for debugging purposes (RO) */
+       u32 priv; /* Private member used by the framework */
+       u32 name; /* Port name. Used for debugging purposes (RO) */
 
        u32 type;      /* Type of the port (RO) enum mmal_port_type */
        u16 index;     /* Index of the port in its type list (RO) */
        u16 index_all; /* Index of the port in the list of all ports (RO) */
 
        u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
-       struct mmal_es_format *format; /* Format of the elementary stream */
+       u32 format; /* Format of the elementary stream */
 
        u32 buffer_num_min; /* Minimum number of buffers the port
                             *   requires (RO).  This is set by the
@@ -94,9 +94,9 @@ struct mmal_port {
                          * the client.
                          */
 
-       void *component; /* Component this port belongs to (Read Only) */
+       u32 component; /* Component this port belongs to (Read Only) */
 
-       void *userdata; /* Field reserved for use by the client */
+       u32 userdata; /* Field reserved for use by the client */
 
        u32 capabilities; /* Flags describing the capabilities of a
                           * port (RO).  Bitwise combination of \ref
index 67b1076015a54646eb0a3b956afdc97e75d2a39c..06936c63ea3562e03cadcbfe80733fc1fd231e06 100644 (file)
@@ -84,9 +84,9 @@ struct mmal_msg_header {
        u32 type; /** enum mmal_msg_type */
 
        /* Opaque handle to the control service */
-       struct mmal_control_service *control_service;
+       u32 control_service;
 
-       struct mmal_msg_context *context; /** a u32 per message context */
+       u32 context; /** a u32 per message context */
        u32 status; /** The status of the vchiq operation */
        u32 padding;
 };
@@ -101,7 +101,7 @@ struct mmal_msg_version {
 
 /* request to VC to create component */
 struct mmal_msg_component_create {
-       void *client_component; /* component context */
+       u32 client_component; /* component context */
        char name[128];
        u32 pid;                /* For debug */
 };
@@ -256,23 +256,23 @@ struct mmal_driver_buffer {
        u32 magic;
        u32 component_handle;
        u32 port_handle;
-       void *client_context;
+       u32 client_context;
 };
 
 /* buffer header */
 struct mmal_buffer_header {
-       struct mmal_buffer_header *next; /* next header */
-       void *priv; /* framework private data */
+       u32 next; /* next header */
+       u32 priv; /* framework private data */
        u32 cmd;
-       void *data;
+       u32 data;
        u32 alloc_size;
        u32 length;
        u32 offset;
        u32 flags;
        s64 pts;
        s64 dts;
-       void *type;
-       void *user_data;
+       u32 type;
+       u32 user_data;
 };
 
 struct mmal_buffer_header_type_specific {
@@ -346,7 +346,7 @@ struct mmal_msg_port_parameter_get_reply {
 #define MMAL_WORKER_EVENT_SPACE 256
 
 struct mmal_msg_event_to_host {
-       void *client_component; /* component context */
+       u32 client_component; /* component context */
 
        u32 port_type;
        u32 port_num;
@@ -354,7 +354,7 @@ struct mmal_msg_event_to_host {
        u32 cmd;
        u32 length;
        u8 data[MMAL_WORKER_EVENT_SPACE];
-       struct mmal_buffer_header *delayed_buffer;
+       u32 delayed_buffer;
 };
 
 /* all mmal messages are serialised through this structure */
index b053195263383dc7eca316ecac675e6599d3a492..00adf2be303e90594797daa9d3fb61d4456f69a3 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/completion.h>
 #include <linux/vmalloc.h>
+#include <linux/btree.h>
 #include <asm/cacheflush.h>
 #include <media/videobuf2-vmalloc.h>
 
@@ -108,8 +109,13 @@ static const char *const port_action_type_names[] = {
 #define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE)
 #endif
 
+struct vchiq_mmal_instance;
+
 /* normal message context */
 struct mmal_msg_context {
+       struct vchiq_mmal_instance *instance;
+       u32 handle;
+
        union {
                struct {
                        /* work struct for defered callback - must come first */
@@ -146,6 +152,13 @@ struct mmal_msg_context {
 
 };
 
+struct vchiq_mmal_context_map {
+       /* ensure serialized access to the btree(contention should be low) */
+       struct mutex lock;
+       struct btree_head32 btree_head;
+       u32 last_handle;
+};
+
 struct vchiq_mmal_instance {
        VCHI_SERVICE_HANDLE_T handle;
 
@@ -158,25 +171,124 @@ struct vchiq_mmal_instance {
        /* vmalloc page to receive scratch bulk xfers into */
        void *bulk_scratch;
 
+       /* mapping table between context handles and mmal_msg_contexts */
+       struct vchiq_mmal_context_map context_map;
+
        /* component to use next */
        int component_idx;
        struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
 };
 
+static int __must_check
+mmal_context_map_init(struct vchiq_mmal_context_map *context_map)
+{
+       mutex_init(&context_map->lock);
+       context_map->last_handle = 0;
+       return btree_init32(&context_map->btree_head);
+}
+
+static void mmal_context_map_destroy(struct vchiq_mmal_context_map *context_map)
+{
+       mutex_lock(&context_map->lock);
+       btree_destroy32(&context_map->btree_head);
+       mutex_unlock(&context_map->lock);
+}
+
+static u32
+mmal_context_map_create_handle(struct vchiq_mmal_context_map *context_map,
+                              struct mmal_msg_context *msg_context,
+                              gfp_t gfp)
+{
+       u32 handle;
+
+       mutex_lock(&context_map->lock);
+
+       while (1) {
+               /* just use a simple count for handles, but do not use 0 */
+               context_map->last_handle++;
+               if (!context_map->last_handle)
+                       context_map->last_handle++;
+
+               handle = context_map->last_handle;
+
+               /* check if the handle is already in use */
+               if (!btree_lookup32(&context_map->btree_head, handle))
+                       break;
+       }
+
+       if (btree_insert32(&context_map->btree_head, handle,
+                          msg_context, gfp)) {
+               /* probably out of memory */
+               mutex_unlock(&context_map->lock);
+               return 0;
+       }
+
+       mutex_unlock(&context_map->lock);
+       return handle;
+}
+
+static struct mmal_msg_context *
+mmal_context_map_lookup_handle(struct vchiq_mmal_context_map *context_map,
+                              u32 handle)
+{
+       struct mmal_msg_context *msg_context;
+
+       if (!handle)
+               return NULL;
+
+       mutex_lock(&context_map->lock);
+
+       msg_context = btree_lookup32(&context_map->btree_head, handle);
+
+       mutex_unlock(&context_map->lock);
+       return msg_context;
+}
+
+static void
+mmal_context_map_destroy_handle(struct vchiq_mmal_context_map *context_map,
+                               u32 handle)
+{
+       mutex_lock(&context_map->lock);
+       btree_remove32(&context_map->btree_head, handle);
+       mutex_unlock(&context_map->lock);
+}
+
 static struct mmal_msg_context *get_msg_context(struct vchiq_mmal_instance
                                                *instance)
 {
        struct mmal_msg_context *msg_context;
 
-       /* todo: should this be allocated from a pool to avoid kmalloc */
-       msg_context = kmalloc(sizeof(*msg_context), GFP_KERNEL);
-       memset(msg_context, 0, sizeof(*msg_context));
+       /* todo: should this be allocated from a pool to avoid kzalloc */
+       msg_context = kzalloc(sizeof(*msg_context), GFP_KERNEL);
+
+       if (!msg_context)
+               return ERR_PTR(-ENOMEM);
+
+       msg_context->instance = instance;
+       msg_context->handle =
+               mmal_context_map_create_handle(&instance->context_map,
+                                              msg_context,
+                                              GFP_KERNEL);
+
+       if (!msg_context->handle) {
+               kfree(msg_context);
+               return ERR_PTR(-ENOMEM);
+       }
 
        return msg_context;
 }
 
+static struct mmal_msg_context *
+lookup_msg_context(struct vchiq_mmal_instance *instance, u32 handle)
+{
+       return mmal_context_map_lookup_handle(&instance->context_map,
+               handle);
+}
+
 static void release_msg_context(struct mmal_msg_context *msg_context)
 {
+       mmal_context_map_destroy_handle(&msg_context->instance->context_map,
+                                       msg_context->handle);
        kfree(msg_context);
 }
 
@@ -185,7 +297,7 @@ static void event_to_host_cb(struct vchiq_mmal_instance *instance,
                             struct mmal_msg *msg, u32 msg_len)
 {
        pr_debug("unhandled event\n");
-       pr_debug("component:%p port type:%d num:%d cmd:0x%x length:%d\n",
+       pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n",
                 msg->u.event_to_host.client_component,
                 msg->u.event_to_host.port_type,
                 msg->u.event_to_host.port_num,
@@ -199,7 +311,8 @@ static void event_to_host_cb(struct vchiq_mmal_instance *instance,
  */
 static void buffer_work_cb(struct work_struct *work)
 {
-       struct mmal_msg_context *msg_context = (struct mmal_msg_context *)work;
+       struct mmal_msg_context *msg_context =
+               container_of(work, struct mmal_msg_context, u.bulk.work);
 
        msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
                                            msg_context->u.bulk.port,
@@ -399,8 +512,10 @@ buffer_from_host(struct vchiq_mmal_instance *instance,
 
        /* get context */
        msg_context = get_msg_context(instance);
-       if (msg_context == NULL)
-               return -ENOMEM;
+       if (IS_ERR(msg_context)) {
+               ret = PTR_ERR(msg_context);
+               goto unlock;
+       }
 
        /* store bulk message context for when data arrives */
        msg_context->u.bulk.instance = instance;
@@ -416,18 +531,19 @@ buffer_from_host(struct vchiq_mmal_instance *instance,
 
        m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST;
        m.h.magic = MMAL_MAGIC;
-       m.h.context = msg_context;
+       m.h.context = msg_context->handle;
        m.h.status = 0;
 
        /* drvbuf is our private data passed back */
        m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC;
        m.u.buffer_from_host.drvbuf.component_handle = port->component->handle;
        m.u.buffer_from_host.drvbuf.port_handle = port->handle;
-       m.u.buffer_from_host.drvbuf.client_context = msg_context;
+       m.u.buffer_from_host.drvbuf.client_context = msg_context->handle;
 
        /* buffer header */
        m.u.buffer_from_host.buffer_header.cmd = 0;
-       m.u.buffer_from_host.buffer_header.data = buf->buffer;
+       m.u.buffer_from_host.buffer_header.data =
+               (u32)(unsigned long)buf->buffer;
        m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
        m.u.buffer_from_host.buffer_header.length = 0;  /* nothing used yet */
        m.u.buffer_from_host.buffer_header.offset = 0;  /* no offset */
@@ -456,6 +572,7 @@ buffer_from_host(struct vchiq_mmal_instance *instance,
 
        vchi_service_release(instance->handle);
 
+unlock:
        mutex_unlock(&instance->bulk_mutex);
 
        return ret;
@@ -504,12 +621,20 @@ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
                              struct mmal_msg *msg, u32 msg_len)
 {
        struct mmal_msg_context *msg_context;
+       u32 handle;
 
        pr_debug("buffer_to_host_cb: instance:%p msg:%p msg_len:%d\n",
                 instance, msg, msg_len);
 
        if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
-               msg_context = msg->u.buffer_from_host.drvbuf.client_context;
+               handle = msg->u.buffer_from_host.drvbuf.client_context;
+               msg_context = lookup_msg_context(instance, handle);
+
+               if (!msg_context) {
+                       pr_err("drvbuf.client_context(%u) is invalid\n",
+                              handle);
+                       return;
+               }
        } else {
                pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n");
                return;
@@ -613,6 +738,7 @@ static void service_callback(void *param,
        u32 msg_len;
        struct mmal_msg *msg;
        VCHI_HELD_MSG_T msg_handle;
+       struct mmal_msg_context *msg_context;
 
        if (!instance) {
                pr_err("Message callback passed NULL instance\n");
@@ -657,16 +783,25 @@ static void service_callback(void *param,
                         * should be verified the address lies in the kernel
                         * address space.
                         */
-                       if (msg->h.context == NULL) {
+                       if (!msg->h.context) {
                                pr_err("received message context was null!\n");
                                vchi_held_msg_release(&msg_handle);
                                break;
                        }
 
+                       msg_context = lookup_msg_context(instance,
+                                                        msg->h.context);
+                       if (!msg_context) {
+                               pr_err("received invalid message context %u!\n",
+                                      msg->h.context);
+                               vchi_held_msg_release(&msg_handle);
+                               break;
+                       }
+
                        /* fill in context values */
-                       msg->h.context->u.sync.msg_handle = msg_handle;
-                       msg->h.context->u.sync.msg = msg;
-                       msg->h.context->u.sync.msg_len = msg_len;
+                       msg_context->u.sync.msg_handle = msg_handle;
+                       msg_context->u.sync.msg = msg;
+                       msg_context->u.sync.msg_len = msg_len;
 
                        /* todo: should this check (completion_done()
                         * == 1) for no one waiting? or do we need a
@@ -678,7 +813,7 @@ static void service_callback(void *param,
                         */
 
                        /* complete message so caller knows it happened */
-                       complete(&msg->h.context->u.sync.cmplt);
+                       complete(&msg_context->u.sync.cmplt);
                        break;
                }
 
@@ -710,7 +845,7 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
                                     struct mmal_msg **msg_out,
                                     VCHI_HELD_MSG_T *msg_handle_out)
 {
-       struct mmal_msg_context msg_context;
+       struct mmal_msg_context *msg_context;
        int ret;
 
        /* payload size must not cause message to exceed max size */
@@ -721,10 +856,14 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
                return -EINVAL;
        }
 
-       init_completion(&msg_context.u.sync.cmplt);
+       msg_context = get_msg_context(instance);
+       if (IS_ERR(msg_context))
+               return PTR_ERR(msg_context);
+
+       init_completion(&msg_context->u.sync.cmplt);
 
        msg->h.magic = MMAL_MAGIC;
-       msg->h.context = &msg_context;
+       msg->h.context = msg_context->handle;
        msg->h.status = 0;
 
        DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len),
@@ -744,17 +883,19 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
                return ret;
        }
 
-       ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, 3*HZ);
+       ret = wait_for_completion_timeout(&msg_context->u.sync.cmplt, 3*HZ);
        if (ret <= 0) {
                pr_err("error %d waiting for sync completion\n", ret);
                if (ret == 0)
                        ret = -ETIME;
                /* todo: what happens if the message arrives after aborting */
+               release_msg_context(msg_context);
                return ret;
        }
 
-       *msg_out = msg_context.u.sync.msg;
-       *msg_handle_out = msg_context.u.sync.msg_handle;
+       *msg_out = msg_context->u.sync.msg;
+       *msg_handle_out = msg_context->u.sync.msg_handle;
+       release_msg_context(msg_context);
 
        return 0;
 }
@@ -817,7 +958,7 @@ static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
        /* only three writable fields in a port */
        p->buffer_num = port->current_buffer.num;
        p->buffer_size = port->current_buffer.size;
-       p->userdata = port;
+       p->userdata = (u32)(unsigned long)port;
 }
 
 static int port_info_set(struct vchiq_mmal_instance *instance,
@@ -988,7 +1129,7 @@ static int create_component(struct vchiq_mmal_instance *instance,
 
        /* build component create message */
        m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
-       m.u.component_create.client_component = component;
+       m.u.component_create.client_component = (u32)(unsigned long)component;
        strncpy(m.u.component_create.name, name,
                sizeof(m.u.component_create.name));
 
@@ -1847,6 +1988,8 @@ int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
 
        vfree(instance->bulk_scratch);
 
+       mmal_context_map_destroy(&instance->context_map);
+
        kfree(instance);
 
        return status;
@@ -1875,7 +2018,6 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
         * directly (de)serialised from memory.
         */
 
-#ifdef CONFIG_ARM
        /* ensure the header structure has packed to the correct size */
        BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24);
 
@@ -1884,7 +2026,6 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
 
        /* mmal port struct is correct size */
        BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
-#endif
 
        /* create a vchi instance */
        status = vchi_initialise(&vchi_instance);
@@ -1900,14 +2041,23 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
                return -EIO;
        }
 
-       instance = kmalloc(sizeof(*instance), GFP_KERNEL);
-       memset(instance, 0, sizeof(*instance));
+       instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+
+       if (!instance)
+               return -ENOMEM;
 
        mutex_init(&instance->vchiq_mutex);
        mutex_init(&instance->bulk_mutex);
 
        instance->bulk_scratch = vmalloc(PAGE_SIZE);
 
+       status = mmal_context_map_init(&instance->context_map);
+       if (status) {
+               pr_err("Failed to init context map (status=%d)\n", status);
+               kfree(instance);
+               return status;
+       }
+
        params.callback_param = instance;
 
        status = vchi_service_open(vchi_instance, &params, &instance->handle);
index 9d1d11e4a53e510c04a416d92d195a7df15012d5..c292bd3c66a368605b069ee559b0dad6f81d0a82 100644 (file)
@@ -74,7 +74,7 @@ struct vchiq_mmal_port {
        struct vchiq_mmal_port_buffer current_buffer;
 
        /* stream format */
-       struct mmal_es_format format;
+       struct mmal_es_format_local format;
        /* elementry stream format */
        union mmal_es_specific_format es;