diff options
author | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2017-07-17 17:17:36 +0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2017-07-17 17:17:36 +0300 |
commit | a3db9d60a118571e696b684a6e8c692a2b064941 (patch) | |
tree | ff7bae0f79b7a2ee0bce03de4f883550200c52a9 /drivers/media | |
parent | 2748e76ddb2967c4030171342ebdd3faa6a5e8e8 (diff) | |
parent | 5771a8c08880cdca3bfb4a3fc6d309d6bba20877 (diff) | |
download | linux-a3db9d60a118571e696b684a6e8c692a2b064941.tar.xz |
Merge tag 'v4.13-rc1' into patchwork
Linux v4.13-rc1
* tag 'v4.13-rc1': (11136 commits)
Linux v4.13-rc1
random: reorder READ_ONCE() in get_random_uXX
random: suppress spammy warnings about unseeded randomness
replace incorrect strscpy use in FORTIFY_SOURCE
kmod: throttle kmod thread limit
kmod: add test driver to stress test the module loader
MAINTAINERS: give kmod some maintainer love
xtensa: use generic fb.h
fault-inject: add /proc/<pid>/fail-nth
fault-inject: simplify access check for fail-nth
fault-inject: make fail-nth read/write interface symmetric
fault-inject: parse as natural 1-based value for fail-nth write interface
fault-inject: automatically detect the number base for fail-nth write interface
kernel/watchdog.c: use better pr_fmt prefix
MAINTAINERS: move the befs tree to kernel.org
lib/atomic64_test.c: add a test that atomic64_inc_not_zero() returns an int
mm: fix overflow check in expand_upwards()
ubifs: Set double hash cookie also for RENAME_EXCHANGE
ubifs: Massage assert in ubifs_xattr_set() wrt. init_xattrs
ubifs: Don't leak kernel memory to the MTD
...
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/dvb-core/dvb_net.c | 5 | ||||
-rw-r--r-- | drivers/media/pci/solo6x10/solo6x10-g723.c | 32 | ||||
-rw-r--r-- | drivers/media/platform/rcar-fcp.c | 17 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1.h | 1 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_dl.c | 23 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_dl.h | 2 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_drm.c | 41 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_drm.h | 11 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_drv.c | 9 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_pipe.c | 13 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_video.c | 2 | ||||
-rw-r--r-- | drivers/media/radio/wl128x/fmdrv_common.c | 4 |
12 files changed, 131 insertions, 29 deletions
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 9947b342633e..06b0dcc13695 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -828,8 +828,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) /* Copy data into our current skb. */ h.how_much = min(h.priv->ule_sndu_remain, (int)h.ts_remain); - memcpy(skb_put(h.priv->ule_skb, h.how_much), - h.from_where, h.how_much); + skb_put_data(h.priv->ule_skb, h.from_where, h.how_much); h.priv->ule_sndu_remain -= h.how_much; h.ts_remain -= h.how_much; h.from_where += h.how_much; @@ -964,7 +963,7 @@ static void dvb_net_sec(struct net_device *dev, skb->dev = dev; /* copy L3 payload */ - eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap); + eth = skb_put(skb, pkt_len - 12 - 4 + 14 - snap); memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap); /* create ethernet header: */ diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 36e93540bb49..3ca947092775 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -223,9 +223,9 @@ static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss) return idx * G723_FRAMES_PER_PAGE; } -static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, - snd_pcm_uframes_t pos, void __user *dst, - snd_pcm_uframes_t count) +static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss, + unsigned long pos, void *dst, + unsigned long count, bool in_kernel) { struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); struct solo_dev *solo_dev = solo_pcm->solo_dev; @@ -242,16 +242,31 @@ static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, if (err) return err; - err = copy_to_user(dst + (i * G723_PERIOD_BYTES), - solo_pcm->g723_buf, G723_PERIOD_BYTES); - - if (err) + if (in_kernel) + memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES); + else if (copy_to_user((void __user *)dst, + solo_pcm->g723_buf, G723_PERIOD_BYTES)) return -EFAULT; + dst += G723_PERIOD_BYTES; } return 0; } +static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel, + unsigned long pos, void __user *dst, + unsigned long count) +{ + return __snd_solo_pcm_copy(ss, pos, (void *)dst, count, false); +} + +static int snd_solo_pcm_copy_kernel(struct snd_pcm_substream *ss, int channel, + unsigned long pos, void *dst, + unsigned long count) +{ + return __snd_solo_pcm_copy(ss, pos, dst, count, true); +} + static const struct snd_pcm_ops snd_solo_pcm_ops = { .open = snd_solo_pcm_open, .close = snd_solo_pcm_close, @@ -261,7 +276,8 @@ static const struct snd_pcm_ops snd_solo_pcm_ops = { .prepare = snd_solo_pcm_prepare, .trigger = snd_solo_pcm_trigger, .pointer = snd_solo_pcm_pointer, - .copy = snd_solo_pcm_copy, + .copy_user = snd_solo_pcm_copy_user, + .copy_kernel = snd_solo_pcm_copy_kernel, }; static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol, diff --git a/drivers/media/platform/rcar-fcp.c b/drivers/media/platform/rcar-fcp.c index 7146fc5ef168..2988031d285d 100644 --- a/drivers/media/platform/rcar-fcp.c +++ b/drivers/media/platform/rcar-fcp.c @@ -53,14 +53,7 @@ struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np) if (fcp->dev->of_node != np) continue; - /* - * Make sure the module won't be unloaded behind our back. This - * is a poor man's safety net, the module should really not be - * unloaded while FCP users can be active. - */ - if (!try_module_get(fcp->dev->driver->owner)) - fcp = NULL; - + get_device(fcp->dev); goto done; } @@ -81,10 +74,16 @@ EXPORT_SYMBOL_GPL(rcar_fcp_get); void rcar_fcp_put(struct rcar_fcp_device *fcp) { if (fcp) - module_put(fcp->dev->driver->owner); + put_device(fcp->dev); } EXPORT_SYMBOL_GPL(rcar_fcp_put); +struct device *rcar_fcp_get_device(struct rcar_fcp_device *fcp) +{ + return fcp->dev; +} +EXPORT_SYMBOL_GPL(rcar_fcp_get_device); + /** * rcar_fcp_enable - Enable an FCP * @fcp: The FCP instance diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 85387a64179a..847963b6e9eb 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -74,6 +74,7 @@ struct vsp1_device { void __iomem *mmio; struct rcar_fcp_device *fcp; + struct device *bus_master; struct vsp1_bru *bru; struct vsp1_clu *clu; diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index 7d8f37772b56..aaf17b13fd78 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c @@ -137,7 +137,7 @@ static int vsp1_dl_body_init(struct vsp1_device *vsp1, dlb->vsp1 = vsp1; dlb->size = size; - dlb->entries = dma_alloc_wc(vsp1->dev, dlb->size, &dlb->dma, + dlb->entries = dma_alloc_wc(vsp1->bus_master, dlb->size, &dlb->dma, GFP_KERNEL); if (!dlb->entries) return -ENOMEM; @@ -150,7 +150,7 @@ static int vsp1_dl_body_init(struct vsp1_device *vsp1, */ static void vsp1_dl_body_cleanup(struct vsp1_dl_body *dlb) { - dma_free_wc(dlb->vsp1->dev, dlb->size, dlb->entries, dlb->dma); + dma_free_wc(dlb->vsp1->bus_master, dlb->size, dlb->entries, dlb->dma); } /** @@ -561,9 +561,19 @@ void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm) spin_unlock(&dlm->lock); } -void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) +/** + * vsp1_dlm_irq_frame_end - Display list handler for the frame end interrupt + * @dlm: the display list manager + * + * Return true if the previous display list has completed at frame end, or false + * if it has been delayed by one frame because the display list commit raced + * with the frame end interrupt. The function always returns true in header mode + * as display list processing is then not continuous and races never occur. + */ +bool vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) { struct vsp1_device *vsp1 = dlm->vsp1; + bool completed = false; spin_lock(&dlm->lock); @@ -575,8 +585,10 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) * perform any operation as there can't be any new display list queued * in that case. */ - if (dlm->mode == VSP1_DL_MODE_HEADER) + if (dlm->mode == VSP1_DL_MODE_HEADER) { + completed = true; goto done; + } /* * The UPD bit set indicates that the commit operation raced with the @@ -594,6 +606,7 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) if (dlm->queued) { dlm->active = dlm->queued; dlm->queued = NULL; + completed = true; } /* @@ -614,6 +627,8 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) done: spin_unlock(&dlm->lock); + + return completed; } /* Hardware Setup */ diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h index 7131aa3c5978..6ec1380a10af 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.h +++ b/drivers/media/platform/vsp1/vsp1_dl.h @@ -28,7 +28,7 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm); void vsp1_dlm_reset(struct vsp1_dl_manager *dlm); void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm); -void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm); +bool vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm); struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm); void vsp1_dl_list_put(struct vsp1_dl_list *dl); diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 9d235e830f5a..9377aafa8996 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -12,6 +12,7 @@ */ #include <linux/device.h> +#include <linux/dma-mapping.h> #include <linux/slab.h> #include <media/media-entity.h> @@ -36,6 +37,14 @@ void vsp1_drm_display_start(struct vsp1_device *vsp1) vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm); } +static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe) +{ + struct vsp1_drm *drm = to_vsp1_drm(pipe); + + if (drm->du_complete) + drm->du_complete(drm->du_private); +} + /* ----------------------------------------------------------------------------- * DU Driver API */ @@ -95,6 +104,7 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) } pipe->num_inputs = 0; + vsp1->drm->du_complete = NULL; vsp1_dlm_reset(pipe->output->dlm); vsp1_device_put(vsp1); @@ -199,6 +209,13 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) if (ret < 0) return ret; + /* + * Register a callback to allow us to notify the DRM driver of frame + * completion events. + */ + vsp1->drm->du_complete = cfg->callback; + vsp1->drm->du_private = cfg->callback_data; + ret = media_pipeline_start(&pipe->output->entity.subdev.entity, &pipe->pipe); if (ret < 0) { @@ -524,6 +541,29 @@ void vsp1_du_atomic_flush(struct device *dev) } EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush); +int vsp1_du_map_sg(struct device *dev, struct sg_table *sgt) +{ + struct vsp1_device *vsp1 = dev_get_drvdata(dev); + + /* + * As all the buffers allocated by the DU driver are coherent, we can + * skip cache sync. This will need to be revisited when support for + * non-coherent buffers will be added to the DU driver. + */ + return dma_map_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents, + DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); +} +EXPORT_SYMBOL_GPL(vsp1_du_map_sg); + +void vsp1_du_unmap_sg(struct device *dev, struct sg_table *sgt) +{ + struct vsp1_device *vsp1 = dev_get_drvdata(dev); + + dma_unmap_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents, + DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); +} +EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg); + /* ----------------------------------------------------------------------------- * Initialization */ @@ -603,6 +643,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1) pipe->lif = &vsp1->lif->entity; pipe->output = vsp1->wpf[0]; pipe->output->pipe = pipe; + pipe->frame_end = vsp1_du_pipeline_frame_end; return 0; } diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h index c8d2f88fc483..e9f80727ff92 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.h +++ b/drivers/media/platform/vsp1/vsp1_drm.h @@ -23,6 +23,8 @@ * @num_inputs: number of active pipeline inputs at the beginning of an update * @inputs: source crop rectangle, destination compose rectangle and z-order * position for every input + * @du_complete: frame completion callback for the DU driver (optional) + * @du_private: data to be passed to the du_complete callback */ struct vsp1_drm { struct vsp1_pipeline pipe; @@ -33,8 +35,17 @@ struct vsp1_drm { struct v4l2_rect compose; unsigned int zpos; } inputs[VSP1_MAX_RPF]; + + /* Frame synchronisation */ + void (*du_complete)(void *); + void *du_private; }; +static inline struct vsp1_drm *to_vsp1_drm(struct vsp1_pipeline *pipe) +{ + return container_of(pipe, struct vsp1_drm, pipe); +} + int vsp1_drm_init(struct vsp1_device *vsp1); void vsp1_drm_cleanup(struct vsp1_device *vsp1); int vsp1_drm_create_links(struct vsp1_device *vsp1); diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 048446af5ae7..95c26edead85 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -764,6 +764,15 @@ static int vsp1_probe(struct platform_device *pdev) PTR_ERR(vsp1->fcp)); return PTR_ERR(vsp1->fcp); } + + /* + * When the FCP is present, it handles all bus master accesses + * for the VSP and must thus be used in place of the VSP device + * to map DMA buffers. + */ + vsp1->bus_master = rcar_fcp_get_device(vsp1->fcp); + } else { + vsp1->bus_master = vsp1->dev; } /* Configure device parameters based on the version register. */ diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index edebf3fa926f..e817623b84e0 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c @@ -330,10 +330,21 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe) void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) { + bool completed; + if (pipe == NULL) return; - vsp1_dlm_irq_frame_end(pipe->output->dlm); + completed = vsp1_dlm_irq_frame_end(pipe->output->dlm); + if (!completed) { + /* + * If the DL commit raced with the frame end interrupt, the + * commit ends up being postponed by one frame. Return + * immediately without calling the pipeline's frame end handler + * or incrementing the sequence number. + */ + return; + } if (pipe->hgo) vsp1_hgo_frame_end(pipe->hgo); diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index eab3c3ea85d7..5af3486afe07 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -1197,7 +1197,7 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1, video->queue.ops = &vsp1_video_queue_qops; video->queue.mem_ops = &vb2_dma_contig_memops; video->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - video->queue.dev = video->vsp1->dev; + video->queue.dev = video->vsp1->bus_master; ret = vb2_queue_init(&video->queue); if (ret < 0) { dev_err(video->vsp1->dev, "failed to initialize vb2 queue\n"); diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 588e2d61c3b4..ab3428bf63fe 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -416,7 +416,7 @@ static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) || test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { /* Fill command header info */ - hdr = (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE); + hdr = skb_put(skb, FM_CMD_MSG_HDR_SIZE); hdr->hdr = FM_PKT_LOGICAL_CHAN_NUMBER; /* 0x08 */ /* 3 (fm_opcode,rd_wr,dlen) + payload len) */ @@ -442,7 +442,7 @@ static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, fm_cb(skb)->fm_op = *((u8 *)payload + 2); } if (payload != NULL) - memcpy(skb_put(skb, payload_len), payload, payload_len); + skb_put_data(skb, payload, payload_len); fm_cb(skb)->completion = wait_completion; skb_queue_tail(&fmdev->tx_q, skb); |