From 2a0a5472af5caa0d0df334abb9975dc496f045da Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 2 Jan 2014 20:06:08 -0300 Subject: [media] omap3isp: Use the ARM DMA IOMMU-aware operations Attach an ARM DMA I/O virtual address space to the ISP device. This switches to the IOMMU-aware ARM DMA backend, we can thus remove the explicit calls to the OMAP IOMMU map and unmap functions. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 102 +++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 26 deletions(-) (limited to 'drivers/media/platform/omap3isp/isp.c') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 06a0df43424..5a4801b7628 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -69,6 +69,8 @@ #include #include +#include + #include #include @@ -1625,7 +1627,7 @@ struct isp_device *omap3isp_get(struct isp_device *isp) * Decrement the reference count on the ISP. If the last reference is released, * power-down all submodules, disable clocks and free temporary buffers. */ -void omap3isp_put(struct isp_device *isp) +static void __omap3isp_put(struct isp_device *isp, bool save_ctx) { if (isp == NULL) return; @@ -1634,7 +1636,7 @@ void omap3isp_put(struct isp_device *isp) BUG_ON(isp->ref_count == 0); if (--isp->ref_count == 0) { isp_disable_interrupts(isp); - if (isp->domain) { + if (save_ctx) { isp_save_ctx(isp); isp->has_context = 1; } @@ -1648,6 +1650,11 @@ void omap3isp_put(struct isp_device *isp) mutex_unlock(&isp->isp_mutex); } +void omap3isp_put(struct isp_device *isp) +{ + __omap3isp_put(isp, true); +} + /* -------------------------------------------------------------------------- * Platform device driver */ @@ -2120,6 +2127,61 @@ error_csiphy: return ret; } +static void isp_detach_iommu(struct isp_device *isp) +{ + arm_iommu_release_mapping(isp->mapping); + isp->mapping = NULL; + iommu_group_remove_device(isp->dev); +} + +static int isp_attach_iommu(struct isp_device *isp) +{ + struct dma_iommu_mapping *mapping; + struct iommu_group *group; + int ret; + + /* Create a device group and add the device to it. */ + group = iommu_group_alloc(); + if (IS_ERR(group)) { + dev_err(isp->dev, "failed to allocate IOMMU group\n"); + return PTR_ERR(group); + } + + ret = iommu_group_add_device(group, isp->dev); + iommu_group_put(group); + + if (ret < 0) { + dev_err(isp->dev, "failed to add device to IPMMU group\n"); + return ret; + } + + /* + * Create the ARM mapping, used by the ARM DMA mapping core to allocate + * VAs. This will allocate a corresponding IOMMU domain. + */ + mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G); + if (IS_ERR(mapping)) { + dev_err(isp->dev, "failed to create ARM IOMMU mapping\n"); + ret = PTR_ERR(mapping); + goto error; + } + + isp->mapping = mapping; + + /* Attach the ARM VA mapping to the device. */ + ret = arm_iommu_attach_device(isp->dev, mapping); + if (ret < 0) { + dev_err(isp->dev, "failed to attach device to VA mapping\n"); + goto error; + } + + return 0; + +error: + isp_detach_iommu(isp); + return ret; +} + /* * isp_remove - Remove ISP platform device * @pdev: Pointer to ISP platform device @@ -2135,10 +2197,8 @@ static int isp_remove(struct platform_device *pdev) isp_xclk_cleanup(isp); __omap3isp_get(isp, false); - iommu_detach_device(isp->domain, &pdev->dev); - iommu_domain_free(isp->domain); - isp->domain = NULL; - omap3isp_put(isp); + isp_detach_iommu(isp); + __omap3isp_put(isp, false); return 0; } @@ -2265,39 +2325,32 @@ static int isp_probe(struct platform_device *pdev) } } - isp->domain = iommu_domain_alloc(pdev->dev.bus); - if (!isp->domain) { - dev_err(isp->dev, "can't alloc iommu domain\n"); - ret = -ENOMEM; + /* IOMMU */ + ret = isp_attach_iommu(isp); + if (ret < 0) { + dev_err(&pdev->dev, "unable to attach to IOMMU\n"); goto error_isp; } - ret = iommu_attach_device(isp->domain, &pdev->dev); - if (ret) { - dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret); - ret = -EPROBE_DEFER; - goto free_domain; - } - /* Interrupt */ isp->irq_num = platform_get_irq(pdev, 0); if (isp->irq_num <= 0) { dev_err(isp->dev, "No IRQ resource\n"); ret = -ENODEV; - goto detach_dev; + goto error_iommu; } if (devm_request_irq(isp->dev, isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) { dev_err(isp->dev, "Unable to request IRQ\n"); ret = -EINVAL; - goto detach_dev; + goto error_iommu; } /* Entities */ ret = isp_initialize_modules(isp); if (ret < 0) - goto detach_dev; + goto error_iommu; ret = isp_register_entities(isp); if (ret < 0) @@ -2310,14 +2363,11 @@ static int isp_probe(struct platform_device *pdev) error_modules: isp_cleanup_modules(isp); -detach_dev: - iommu_detach_device(isp->domain, &pdev->dev); -free_domain: - iommu_domain_free(isp->domain); - isp->domain = NULL; +error_iommu: + isp_detach_iommu(isp); error_isp: isp_xclk_cleanup(isp); - omap3isp_put(isp); + __omap3isp_put(isp, false); error: mutex_destroy(&isp->isp_mutex); -- cgit v1.2.3-70-g09d2 From e8feb876d40f1428e40da33ee7dc2a7807cc145c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 9 Mar 2014 20:57:53 -0300 Subject: [media] omap3isp: Move queue irqlock to isp_video structure This prepares for the move to videobuf2. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 6 +++--- drivers/media/platform/omap3isp/ispqueue.c | 13 +------------ drivers/media/platform/omap3isp/ispqueue.h | 5 +---- drivers/media/platform/omap3isp/ispvideo.c | 21 +++++++++++++-------- drivers/media/platform/omap3isp/ispvideo.h | 1 + 5 files changed, 19 insertions(+), 27 deletions(-) (limited to 'drivers/media/platform/omap3isp/isp.c') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 5a4801b7628..2c7aa672056 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1399,14 +1399,14 @@ int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, if (isp_pipeline_is_last(me)) { struct isp_video *video = pipe->output; unsigned long flags; - spin_lock_irqsave(&video->queue->irqlock, flags); + spin_lock_irqsave(&video->irqlock, flags); if (video->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) { - spin_unlock_irqrestore(&video->queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); atomic_set(stopping, 0); smp_mb(); return 0; } - spin_unlock_irqrestore(&video->queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); if (!wait_event_timeout(*wait, !atomic_read(stopping), msecs_to_jiffies(1000))) { atomic_set(stopping, 0); diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c index dcd9446f01a..77afb637044 100644 --- a/drivers/media/platform/omap3isp/ispqueue.c +++ b/drivers/media/platform/omap3isp/ispqueue.c @@ -660,7 +660,6 @@ int omap3isp_video_queue_init(struct isp_video_queue *queue, struct device *dev, unsigned int bufsize) { INIT_LIST_HEAD(&queue->queue); - spin_lock_init(&queue->irqlock); queue->type = type; queue->ops = ops; @@ -761,7 +760,6 @@ int omap3isp_video_queue_qbuf(struct isp_video_queue *queue, struct v4l2_buffer *vbuf) { struct isp_video_buffer *buf; - unsigned long flags; int ret; if (vbuf->type != queue->type) @@ -801,11 +799,8 @@ int omap3isp_video_queue_qbuf(struct isp_video_queue *queue, buf->state = ISP_BUF_STATE_QUEUED; list_add_tail(&buf->stream, &queue->queue); - if (queue->streaming) { - spin_lock_irqsave(&queue->irqlock, flags); + if (queue->streaming) queue->ops->buffer_queue(buf); - spin_unlock_irqrestore(&queue->irqlock, flags); - } return 0; } @@ -862,17 +857,14 @@ int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue, int omap3isp_video_queue_streamon(struct isp_video_queue *queue) { struct isp_video_buffer *buf; - unsigned long flags; if (queue->streaming) return 0; queue->streaming = 1; - spin_lock_irqsave(&queue->irqlock, flags); list_for_each_entry(buf, &queue->queue, stream) queue->ops->buffer_queue(buf); - spin_unlock_irqrestore(&queue->irqlock, flags); return 0; } @@ -890,7 +882,6 @@ int omap3isp_video_queue_streamon(struct isp_video_queue *queue) void omap3isp_video_queue_streamoff(struct isp_video_queue *queue) { struct isp_video_buffer *buf; - unsigned long flags; unsigned int i; if (!queue->streaming) @@ -898,7 +889,6 @@ void omap3isp_video_queue_streamoff(struct isp_video_queue *queue) queue->streaming = 0; - spin_lock_irqsave(&queue->irqlock, flags); for (i = 0; i < queue->count; ++i) { buf = queue->buffers[i]; @@ -907,7 +897,6 @@ void omap3isp_video_queue_streamoff(struct isp_video_queue *queue) buf->state = ISP_BUF_STATE_IDLE; } - spin_unlock_irqrestore(&queue->irqlock, flags); INIT_LIST_HEAD(&queue->queue); } diff --git a/drivers/media/platform/omap3isp/ispqueue.h b/drivers/media/platform/omap3isp/ispqueue.h index ecff055d7a5..ecf330960ee 100644 --- a/drivers/media/platform/omap3isp/ispqueue.h +++ b/drivers/media/platform/omap3isp/ispqueue.h @@ -114,8 +114,7 @@ struct isp_video_buffer { * the userspace memory address for a USERPTR buffer, with the queue lock * held. Drivers should perform device-specific buffer preparation (such as * mapping the buffer memory in an IOMMU). This operation is optional. - * @buffer_queue: Called when a buffer is being added to the queue with the - * queue irqlock spinlock held. + * @buffer_queue: Called when a buffer is being added. */ struct isp_video_queue_operations { void (*queue_prepare)(struct isp_video_queue *queue, @@ -132,7 +131,6 @@ struct isp_video_queue_operations { * @bufsize: Size of a driver-specific buffer object * @count: Number of currently allocated buffers * @buffers: ISP video buffers - * @irqlock: Spinlock to protect access to the IRQ queue * @streaming: Queue state, indicates whether the queue is streaming * @queue: List of all queued buffers */ @@ -144,7 +142,6 @@ struct isp_video_queue { unsigned int count; struct isp_video_buffer *buffers[ISP_VIDEO_MAX_BUFFERS]; - spinlock_t irqlock; unsigned int streaming:1; diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 12b0f8c8266..85338d33442 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -381,15 +381,20 @@ static void isp_video_buffer_queue(struct isp_video_buffer *buf) unsigned int empty; unsigned int start; + spin_lock_irqsave(&video->irqlock, flags); + if (unlikely(video->error)) { buf->state = ISP_BUF_STATE_ERROR; wake_up(&buf->wait); + spin_unlock_irqrestore(&video->irqlock, flags); return; } empty = list_empty(&video->dmaqueue); list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue); + spin_unlock_irqrestore(&video->irqlock, flags); + if (empty) { if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) state = ISP_PIPELINE_QUEUE_OUTPUT; @@ -445,16 +450,16 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) unsigned long flags; struct timespec ts; - spin_lock_irqsave(&queue->irqlock, flags); + spin_lock_irqsave(&video->irqlock, flags); if (WARN_ON(list_empty(&video->dmaqueue))) { - spin_unlock_irqrestore(&queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); return NULL; } buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, irqlist); list_del(&buf->irqlist); - spin_unlock_irqrestore(&queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage; @@ -520,10 +525,9 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) */ void omap3isp_video_cancel_stream(struct isp_video *video) { - struct isp_video_queue *queue = video->queue; unsigned long flags; - spin_lock_irqsave(&queue->irqlock, flags); + spin_lock_irqsave(&video->irqlock, flags); while (!list_empty(&video->dmaqueue)) { struct isp_video_buffer *buf; @@ -538,7 +542,7 @@ void omap3isp_video_cancel_stream(struct isp_video *video) video->error = true; - spin_unlock_irqrestore(&queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); } /* @@ -1039,10 +1043,10 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) ISP_PIPELINE_STREAM_CONTINUOUS); if (ret < 0) goto err_set_stream; - spin_lock_irqsave(&video->queue->irqlock, flags); + spin_lock_irqsave(&video->irqlock, flags); if (list_empty(&video->dmaqueue)) video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; - spin_unlock_irqrestore(&video->queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); } video->streaming = 1; @@ -1324,6 +1328,7 @@ int omap3isp_video_init(struct isp_video *video, const char *name) spin_lock_init(&video->pipe.lock); mutex_init(&video->stream_lock); mutex_init(&video->queue_lock); + spin_lock_init(&video->irqlock); /* Initialize the video device. */ if (video->ops == NULL) diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h index 254e7d20f79..0fa098cc04b 100644 --- a/drivers/media/platform/omap3isp/ispvideo.h +++ b/drivers/media/platform/omap3isp/ispvideo.h @@ -183,6 +183,7 @@ struct isp_video { /* Video buffers queue */ struct isp_video_queue *queue; struct mutex queue_lock; /* protects the queue */ + spinlock_t irqlock; /* protects dmaqueue */ struct list_head dmaqueue; enum isp_video_dmaqueue_flags dmaqueue_flags; -- cgit v1.2.3-70-g09d2