diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 586f48811a213a0c618188568a03771d678e9d39..25279fb60f778d25793711f486d9fa77b458bf8e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2899,6 +2899,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. spia_pedr= spia_peddr= + stack_guard_gap= [MM] + override the default stack gap protection. The value + is in page units and it defines how many pages prior + to (for stacks growing down) resp. after (for stacks + growing up) the main stack are reserved for no other + mapping. Default value is 256 pages. + stacktrace [FTRACE] Enabled the stack tracer on boot up. diff --git a/arch/arc/mm/mmap.c b/arch/arc/mm/mmap.c index 2e06d56e987bf84c773b01bbfa6a7b4af1ac6fc9..cf4ae6958240074d265b4f26cb6f0d4271105b92 100644 --- a/arch/arc/mm/mmap.c +++ b/arch/arc/mm/mmap.c @@ -64,7 +64,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index 2d689d1f88fefe7701354402e61dbaf0054e4014..dae47dfc8dae6e1af65b075f060a5aaa0b9b9279 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c @@ -89,7 +89,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -140,7 +140,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/frv/mm/elf-fdpic.c b/arch/frv/mm/elf-fdpic.c index 836f14707a627f156343154f359ac1f7758e9fd4..efa59f1f80226e6c951182ad0124aeccd38c7787 100644 --- a/arch/frv/mm/elf-fdpic.c +++ b/arch/frv/mm/elf-fdpic.c @@ -74,7 +74,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi addr = PAGE_ALIGN(addr); vma = find_vma(current->mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) goto success; } diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c index 5ab9e96d5225271c344ec7033be643de89ffc98d..7f463465b4e81604b5a868077b59a23c546c7c3f 100644 --- a/arch/mips/mm/mmap.c +++ b/arch/mips/mm/mmap.c @@ -92,7 +92,7 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 7ce9cf3b698835c0dd2b2644d137ff7549c68e72..887365a82c012a491c3b1cc7337202cb946d71bf 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -103,7 +103,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr, if ((mm->task_size - len) < addr) return 0; vma = find_vma(mm, addr); - return (!vma || (addr + len) <= vma->vm_start); + return (!vma || (addr + len) <= vm_start_gap(vma)); } static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice) diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index 6777177807c26f5d6630ec48535bb4f7d5eba0e2..7df7d59441889aa8bc4a748cd4a40dc94ab89cff 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c @@ -63,7 +63,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -113,7 +113,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index d3280f9e2fb9fc91792519605fe76941c092da55..e411139666054f1222247faf8f34091820aad8e3 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -119,7 +119,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi vma = find_vma(mm, addr); if (task_size - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -182,7 +182,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, vma = find_vma(mm, addr); if (task_size - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 96399646570a780e1b38a6324994c5f71470bb0b..64ee8884f37a1a7c47039088f74bf941fcf98796 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -118,7 +118,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, HPAGE_SIZE); vma = find_vma(mm, addr); if (task_size - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } if (mm->get_unmapped_area == arch_get_unmapped_area) diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c index 0ac3599e5784aa3ae49af24f795f9c3131488775..d4352152337c5920449f028ade1b751177cf342d 100644 --- a/arch/tile/mm/hugetlbpage.c +++ b/arch/tile/mm/hugetlbpage.c @@ -302,7 +302,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } if (current->mm->get_unmapped_area == arch_get_unmapped_area) diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 30277e27431acde9a9320e0b1be4470bddb40e3a..d050393d3be2565c5ff80e1623db1d4b9bda089f 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -127,7 +127,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (end - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -166,7 +166,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c index 4348803b55335cb6fccebb77b4f6bb1817b08e9f..1bb55700a24ade6055b483775490408d280323ec 100644 --- a/arch/x86/mm/hugetlbpage.c +++ b/arch/x86/mm/hugetlbpage.c @@ -349,7 +349,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } if (mm->get_unmapped_area == arch_get_unmapped_area) diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c index 5d3f7a119ed1e91a5baf6fe5af7a33d842146533..1ff0b92eeae7cc85fbc84cb006471d1f516764fd 100644 --- a/arch/xtensa/kernel/syscall.c +++ b/arch/xtensa/kernel/syscall.c @@ -86,7 +86,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, /* At this point: (!vmm || addr < vmm->vm_end). */ if (TASK_SIZE - len < addr) return -ENOMEM; - if (!vmm || addr + len <= vmm->vm_start) + if (!vmm || addr + len <= vm_start_gap(vmm)) return addr; addr = vmm->vm_end; if (flags & MAP_SHARED) diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index f6e779e4f11eceeb5fa657c297a61627190e91f6..9313bfc12c1c9339610c129e39ede9eefdc519fe 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -589,7 +589,7 @@ static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count) * global one. Requires architecture specific get_dev_cma_area() helper * function. */ -unsigned long dma_alloc_from_contiguous(struct device *dev, int count, +unsigned long dma_alloc_from_contiguous(struct device *dev, size_t count, unsigned int align) { unsigned long mask, pfn = 0, pageno, start = 0; @@ -604,7 +604,7 @@ unsigned long dma_alloc_from_contiguous(struct device *dev, int count, if (align > CONFIG_CMA_ALIGNMENT) align = CONFIG_CMA_ALIGNMENT; - pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma, + pr_debug("%s(cma %p, count %zu, align %d)\n", __func__, (void *)cma, count, align); if (!count) diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index f8baf287d21fca0f38d9d708fe6677655bcadc4f..cfbd7a9c671657b36b94628064f1fe4735ca30f6 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -63,6 +63,7 @@ static uint8_t _std_init_vector_sha256_uint8[] = { static DEFINE_MUTEX(send_cmd_lock); static DEFINE_MUTEX(qcedev_sent_bw_req); +static DEFINE_MUTEX(hash_access_lock); static void qcedev_ce_high_bw_req(struct qcedev_control *podev, bool high_bw_req) @@ -1651,12 +1652,18 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; - if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) + mutex_lock(&hash_access_lock); + if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) { + mutex_unlock(&hash_access_lock); return -EINVAL; + } qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA; err = qcedev_hash_init(&qcedev_areq, handle, &sg_src); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } + mutex_unlock(&hash_access_lock); if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1674,32 +1681,42 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; - if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) + mutex_lock(&hash_access_lock); + if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) { + mutex_unlock(&hash_access_lock); return -EINVAL; + } qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA; if (qcedev_areq.sha_op_req.alg == QCEDEV_ALG_AES_CMAC) { err = qcedev_hash_cmac(&qcedev_areq, handle, &sg_src); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } } else { if (handle->sha_ctxt.init_done == false) { pr_err("%s Init was not called\n", __func__); + mutex_unlock(&hash_access_lock); return -EINVAL; } err = qcedev_hash_update(&qcedev_areq, handle, &sg_src); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } } if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { pr_err("Invalid sha_ctxt.diglen %d\n", handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); return -EINVAL; } memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1716,22 +1733,29 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; - if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) + mutex_lock(&hash_access_lock); + if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) { + mutex_unlock(&hash_access_lock); return -EINVAL; + } qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA; err = qcedev_hash_final(&qcedev_areq, handle); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { pr_err("Invalid sha_ctxt.diglen %d\n", handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); return -EINVAL; } qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen; memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1746,26 +1770,35 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; - if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) + mutex_lock(&hash_access_lock); + if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) { + mutex_unlock(&hash_access_lock); return -EINVAL; + } qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA; qcedev_hash_init(&qcedev_areq, handle, &sg_src); err = qcedev_hash_update(&qcedev_areq, handle, &sg_src); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } err = qcedev_hash_final(&qcedev_areq, handle); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { pr_err("Invalid sha_ctxt.diglen %d\n", handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); return -EINVAL; } qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen; memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 1debe0433ec6fa4de6828c040fd14d553aab552b..31f84993151547d7142ac1e03a571644de3f505c 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1767,7 +1767,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) if (r) goto out; - param->data_size = sizeof(*param); + param->data_size = offsetof(struct dm_ioctl, data); r = fn(param, input_param_size); if (unlikely(param->flags & DM_BUFFER_FULL_FLAG) && diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c index f65454f3b765e7af76f3ba598f5b47bb9ea58e10..a267a8e4d3206a092a8c2917a3f0013ce5853a2f 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c @@ -676,9 +676,13 @@ static int msm_fd_s_fmt_vid_out(struct file *file, static int msm_fd_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) { + int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - return vb2_reqbufs(&ctx->vb2_q, req); + mutex_lock(&ctx->fd_device->recovery_lock); + ret = vb2_reqbufs(&ctx->vb2_q, req); + mutex_unlock(&ctx->fd_device->recovery_lock); + return ret; } /* @@ -690,9 +694,14 @@ static int msm_fd_reqbufs(struct file *file, static int msm_fd_qbuf(struct file *file, void *fh, struct v4l2_buffer *pb) { + int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - return vb2_qbuf(&ctx->vb2_q, pb); + mutex_lock(&ctx->fd_device->recovery_lock); + ret = vb2_qbuf(&ctx->vb2_q, pb); + mutex_unlock(&ctx->fd_device->recovery_lock); + return ret; + } /* @@ -704,9 +713,13 @@ static int msm_fd_qbuf(struct file *file, void *fh, static int msm_fd_dqbuf(struct file *file, void *fh, struct v4l2_buffer *pb) { + int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - return vb2_dqbuf(&ctx->vb2_q, pb, file->f_flags & O_NONBLOCK); + mutex_lock(&ctx->fd_device->recovery_lock); + ret = vb2_dqbuf(&ctx->vb2_q, pb, file->f_flags & O_NONBLOCK); + mutex_unlock(&ctx->fd_device->recovery_lock); + return ret; } /* @@ -1212,6 +1225,7 @@ static int fd_probe(struct platform_device *pdev) mutex_init(&fd->lock); spin_lock_init(&fd->slock); + mutex_init(&fd->recovery_lock); init_completion(&fd->hw_halt_completion); INIT_LIST_HEAD(&fd->buf_queue); fd->dev = &pdev->dev; diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h index 7532d5ed6724333fe2a9ed0752941d793e75932b..2f54f42a323da8b6b6a70beb284ab859b20e2499 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h @@ -215,6 +215,7 @@ struct msm_fd_device { struct mutex lock; spinlock_t slock; + struct mutex recovery_lock; int ref_count; int irq_num; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c index 7f9ff4f08f5a41a7f113e64c3a3be93da5b2d7bd..75976114df4bca62620a572a4495b56a68dc61a9 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -46,7 +46,7 @@ struct msm_isp_bufq *msm_isp_get_bufq( /* bufq_handle cannot be 0 */ if ((bufq_handle == 0) || - (bufq_index > buf_mgr->num_buf_q)) + (bufq_index >= buf_mgr->num_buf_q)) return NULL; bufq = &buf_mgr->bufq[bufq_index]; @@ -154,6 +154,12 @@ static int msm_isp_prepare_isp_buf(struct msm_isp_buf_mgr *buf_mgr, else domain_num = buf_mgr->iommu_domain_num_secure; + if (qbuf_buf->num_planes > MAX_PLANES_PER_STREAM) { + pr_err("%s: Invalid num_planes %d\n", + __func__, qbuf_buf->num_planes); + return -EINVAL; + } + for (i = 0; i < qbuf_buf->num_planes; i++) { mapped_info = &buf_info->mapped_info[i]; mapped_info->handle = @@ -216,6 +222,12 @@ static void msm_isp_unprepare_v4l2_buf( else domain_num = buf_mgr->iommu_domain_num_secure; + if (buf_info->num_planes > VIDEO_MAX_PLANES) { + pr_err("%s: Invalid num_planes %d\n", + __func__, buf_info->num_planes); + return; + } + for (i = 0; i < buf_info->num_planes; i++) { mapped_info = &buf_info->mapped_info[i]; spin_lock_irqsave(&buf_mgr->bufq_list_lock, flags); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c index a0eed95606cf3dfa56f57eb8acdbe8c20b32c326..da7405c452b428da6ac2958edfa1544086c86b54 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c @@ -550,6 +550,12 @@ static int msm_isp_stats_update_cgc_override(struct vfe_device *vfe_dev, int i; uint32_t stats_mask = 0, idx; + if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) { + pr_err("%s invalid num_streams %d\n", __func__, + stream_cfg_cmd->num_streams); + return -EINVAL; + } + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); @@ -630,6 +636,13 @@ static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, stats_data->stream_info); if (rc < 0) return rc; + + if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) { + pr_err("%s invalid num_streams %d\n", __func__, + stream_cfg_cmd->num_streams); + return -EINVAL; + } + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); @@ -702,6 +715,12 @@ static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, num_stats_comp_mask = vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) { + pr_err("%s invalid num_streams %d\n", __func__, + stream_cfg_cmd->num_streams); + return -EINVAL; + } + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); @@ -776,6 +795,12 @@ int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg) if (vfe_dev->stats_data.num_active_stream == 0) vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev); + if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) { + pr_err("%s invalid num_streams %d\n", __func__, + stream_cfg_cmd->num_streams); + return -EINVAL; + } + if (stream_cfg_cmd->enable) { msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd); @@ -803,7 +828,7 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg) update_info = &update_cmd->update_info[i]; /*check array reference bounds*/ if (STATS_IDX(update_info->stream_handle) - > vfe_dev->hw_info->stats_hw_info->num_stats_type) { + >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { pr_err("%s: stats idx %d out of bound!", __func__, STATS_IDX(update_info->stream_handle)); return -EINVAL; diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 6f5334abccc9d4cd72bea25f340f6f804355d64c..5296b005be09b82b2fd71573a265c176901e3f2c 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -313,7 +313,7 @@ static int msm_ispif_reset(struct ispif_device *ispif) ispif->base + ISPIF_VFE_m_INTF_CMD_0(i)); msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, ispif->base + ISPIF_VFE_m_INTF_CMD_1(i)); - pr_debug("%s: base %lx", __func__, (unsigned long)ispif->base); + pr_debug("%s: base %pK", __func__, ispif->base); msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0)); msm_camera_io_w(0, ispif->base + diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c index b76bdc3afd525d5a82a902c0369dc57933ff0eea..e517f0f589ce6ac972c2f6804289cc82265ab9b6 100644 --- a/drivers/media/platform/msm/camera_v2/msm.c +++ b/drivers/media/platform/msm/camera_v2/msm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -30,7 +30,6 @@ #include "msm_sd.h" #include <media/msmb_generic_buf_mgr.h> - static struct v4l2_device *msm_v4l2_dev; static struct list_head ordered_sd_list; @@ -131,7 +130,7 @@ typedef int (*msm_queue_find_func)(void *d1, void *d2); #define msm_queue_find(queue, type, member, func, data) ({\ unsigned long flags; \ struct msm_queue_head *__q = (queue); \ - type *node = 0; \ + type *node = NULL; \ typeof(node) __ret = NULL; \ msm_queue_find_func __f = (func); \ spin_lock_irqsave(&__q->lock, flags); \ @@ -229,22 +228,46 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) struct msm_session *session = NULL; struct msm_stream *stream = NULL; unsigned long flags; + int try_count = 0; session = msm_queue_find(msm_session_q, struct msm_session, list, __msm_queue_find_session, &session_id); + if (!session) return; - stream = msm_queue_find(&session->stream_q, struct msm_stream, - list, __msm_queue_find_stream, &stream_id); - if (!stream) - return; - spin_lock_irqsave(&(session->stream_q.lock), flags); - list_del_init(&stream->list); - session->stream_q.len--; - kfree(stream); - stream = NULL; - spin_unlock_irqrestore(&(session->stream_q.lock), flags); + while (1) { + + if (try_count > 5) { + pr_err("%s : not able to delete stream %d\n", + __func__, __LINE__); + break; + } + + write_lock(&session->stream_rwlock); + try_count++; + stream = msm_queue_find(&session->stream_q, struct msm_stream, + list, __msm_queue_find_stream, &stream_id); + + if (!stream) { + write_unlock(&session->stream_rwlock); + return; + } + + if (msm_vb2_get_stream_state(stream) != 1) { + write_unlock(&session->stream_rwlock); + continue; + } + + spin_lock_irqsave(&(session->stream_q.lock), flags); + list_del_init(&stream->list); + session->stream_q.len--; + kfree(stream); + stream = NULL; + spin_unlock_irqrestore(&(session->stream_q.lock), flags); + write_unlock(&session->stream_rwlock); + break; + } } @@ -371,6 +394,7 @@ int msm_create_session(unsigned int session_id, struct video_device *vdev) msm_init_queue(&session->stream_q); msm_enqueue(msm_session_q, &session->list); mutex_init(&session->lock); + rwlock_init(&session->stream_rwlock); return 0; } @@ -844,11 +868,9 @@ static int msm_open(struct file *filep) BUG_ON(!pvdev); /* !!! only ONE open is allowed !!! */ - if (atomic_read(&pvdev->opened)) + if (atomic_cmpxchg(&pvdev->opened, 0, 1)) return -EBUSY; - atomic_set(&pvdev->opened, 1); - spin_lock_irqsave(&msm_pid_lock, flags); msm_pid = get_pid(task_pid(current)); spin_unlock_irqrestore(&msm_pid_lock, flags); @@ -876,17 +898,25 @@ static struct v4l2_file_operations msm_fops = { #endif }; -struct msm_stream *msm_get_stream(unsigned int session_id, - unsigned int stream_id) +struct msm_session *msm_get_session(unsigned int session_id) { struct msm_session *session; - struct msm_stream *stream; session = msm_queue_find(msm_session_q, struct msm_session, list, __msm_queue_find_session, &session_id); if (!session) return ERR_PTR(-EINVAL); + return session; +} +EXPORT_SYMBOL(msm_get_session); + + +struct msm_stream *msm_get_stream(struct msm_session *session, + unsigned int stream_id) +{ + struct msm_stream *stream; + stream = msm_queue_find(&session->stream_q, struct msm_stream, list, __msm_queue_find_stream, &stream_id); @@ -940,6 +970,33 @@ struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q) return NULL; } +struct msm_session *msm_get_session_from_vb2q(struct vb2_queue *q) +{ + struct msm_session *session; + struct msm_stream *stream; + unsigned long flags1; + unsigned long flags2; + + spin_lock_irqsave(&msm_session_q->lock, flags1); + list_for_each_entry(session, &(msm_session_q->list), list) { + spin_lock_irqsave(&(session->stream_q.lock), flags2); + list_for_each_entry( + stream, &(session->stream_q.list), list) { + if (stream->vb2_q == q) { + spin_unlock_irqrestore + (&(session->stream_q.lock), flags2); + spin_unlock_irqrestore + (&msm_session_q->lock, flags1); + return session; + } + } + spin_unlock_irqrestore(&(session->stream_q.lock), flags2); + } + spin_unlock_irqrestore(&msm_session_q->lock, flags1); + return NULL; +} +EXPORT_SYMBOL(msm_get_session_from_vb2q); + static struct v4l2_subdev *msm_sd_find(const char *name) { unsigned long flags; diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h index 2b43a36cfd79b3ccb2962c00a854061d6208134f..7b8a2e6b93bc5288f068d99b5a37dcb0eac975aa 100644 --- a/drivers/media/platform/msm/camera_v2/msm.h +++ b/drivers/media/platform/msm/camera_v2/msm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -100,6 +100,7 @@ struct msm_session { * session struct msm_stream */ struct msm_queue_head stream_q; struct mutex lock; + rwlock_t stream_rwlock; }; int msm_post_event(struct v4l2_event *event, int timeout); @@ -111,10 +112,12 @@ int msm_create_stream(unsigned int session_id, void msm_delete_stream(unsigned int session_id, unsigned int stream_id); int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id); void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id); -struct msm_stream *msm_get_stream(unsigned int session_id, +struct msm_session *msm_get_session(unsigned int session_id); +struct msm_stream *msm_get_stream(struct msm_session *session, unsigned int stream_id); struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id, unsigned int stream_id); struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q); +struct msm_session *msm_get_session_from_vb2q(struct vb2_queue *q); struct msm_session *msm_session_find(unsigned int session_id); #endif /*_MSM_H */ diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c index 7bd479aa4d62d0997ddcef544322e9214a126a9f..986a30769a3fd343279a6af05c73301d3e0da100 100644 --- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c +++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -43,16 +43,24 @@ static int msm_vb2_queue_setup(struct vb2_queue *q, int msm_vb2_buf_init(struct vb2_buffer *vb) { struct msm_stream *stream; + struct msm_session *session; struct msm_vb2_buffer *msm_vb2_buf; + session = msm_get_session_from_vb2q(vb->vb2_queue); + if (IS_ERR_OR_NULL(session)) + return -EINVAL; + + read_lock(&session->stream_rwlock); + stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s: Couldn't find stream\n", __func__); + read_unlock(&session->stream_rwlock); return -EINVAL; } msm_vb2_buf = container_of(vb, struct msm_vb2_buffer, vb2_buf); msm_vb2_buf->in_freeq = 0; - + read_unlock(&session->stream_rwlock); return 0; } @@ -60,6 +68,7 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) { struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; + struct msm_session *session; unsigned long flags; msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); @@ -69,21 +78,30 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) return; } + session = msm_get_session_from_vb2q(vb->vb2_queue); + if (IS_ERR_OR_NULL(session)) + return; + + read_lock(&session->stream_rwlock); + stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); + read_unlock(&session->stream_rwlock); return; } spin_lock_irqsave(&stream->stream_lock, flags); list_add_tail(&msm_vb2->list, &stream->queued_list); spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); } static int msm_vb2_buf_finish(struct vb2_buffer *vb) { struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; + struct msm_session *session; unsigned long flags; struct msm_vb2_buffer *msm_vb2_entry, *temp; @@ -94,9 +112,16 @@ static int msm_vb2_buf_finish(struct vb2_buffer *vb) return -EINVAL; } + session = msm_get_session_from_vb2q(vb->vb2_queue); + if (IS_ERR_OR_NULL(session)) + return -EINVAL; + + read_lock(&session->stream_rwlock); + stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); + read_unlock(&session->stream_rwlock); return -EINVAL; } @@ -109,6 +134,7 @@ static int msm_vb2_buf_finish(struct vb2_buffer *vb) } } spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return 0; } @@ -116,6 +142,7 @@ static void msm_vb2_buf_cleanup(struct vb2_buffer *vb) { struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; + struct msm_session *session; unsigned long flags; msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); @@ -125,16 +152,42 @@ static void msm_vb2_buf_cleanup(struct vb2_buffer *vb) return; } + session = msm_get_session_from_vb2q(vb->vb2_queue); + if (IS_ERR_OR_NULL(session)) + return; + + read_lock(&session->stream_rwlock); + stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); + read_unlock(&session->stream_rwlock); return; } spin_lock_irqsave(&stream->stream_lock, flags); INIT_LIST_HEAD(&stream->queued_list); spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); +} + +int msm_vb2_get_stream_state(struct msm_stream *stream) +{ + struct msm_vb2_buffer *msm_vb2, *temp; + unsigned long flags; + int rc = 1; + + spin_lock_irqsave(&stream->stream_lock, flags); + list_for_each_entry_safe(msm_vb2, temp, &(stream->queued_list), list) { + if (msm_vb2->in_freeq != 0) { + rc = 0; + break; + } + } + spin_unlock_irqrestore(&stream->stream_lock, flags); + return rc; } +EXPORT_SYMBOL(msm_vb2_get_stream_state); static struct vb2_ops msm_vb2_get_q_op = { .queue_setup = msm_vb2_queue_setup, @@ -188,14 +241,23 @@ static struct vb2_buffer *msm_vb2_get_buf(int session_id, unsigned int stream_id) { struct msm_stream *stream; + struct msm_session *session; struct vb2_buffer *vb2_buf = NULL; struct msm_vb2_buffer *msm_vb2 = NULL; unsigned long flags; - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) + session = msm_get_session(session_id); + if (IS_ERR_OR_NULL(session)) return NULL; + read_lock(&session->stream_rwlock); + + stream = msm_get_stream(session, stream_id); + if (IS_ERR_OR_NULL(stream)) { + read_unlock(&session->stream_rwlock); + return NULL; + } + spin_lock_irqsave(&stream->stream_lock, flags); if (!stream->vb2_q) { @@ -218,6 +280,7 @@ static struct vb2_buffer *msm_vb2_get_buf(int session_id, vb2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return vb2_buf; } @@ -225,14 +288,24 @@ static int msm_vb2_put_buf(struct vb2_buffer *vb, int session_id, unsigned int stream_id) { struct msm_stream *stream; + struct msm_session *session; struct msm_vb2_buffer *msm_vb2; struct vb2_buffer *vb2_buf = NULL; int rc = 0; unsigned long flags; - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) + + session = msm_get_session(session_id); + if (IS_ERR_OR_NULL(session)) return -EINVAL; + read_lock(&session->stream_rwlock); + + stream = msm_get_stream(session, stream_id); + if (IS_ERR_OR_NULL(stream)) { + read_unlock(&session->stream_rwlock); + return -EINVAL; + } + spin_lock_irqsave(&stream->stream_lock, flags); if (vb) { list_for_each_entry(msm_vb2, &(stream->queued_list), list) { @@ -244,6 +317,7 @@ static int msm_vb2_put_buf(struct vb2_buffer *vb, int session_id, pr_err("VB buffer is INVALID vb=%pK, ses_id=%d, str_id=%d\n", vb, session_id, stream_id); spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } msm_vb2 = @@ -259,6 +333,7 @@ static int msm_vb2_put_buf(struct vb2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return rc; } @@ -268,12 +343,22 @@ static int msm_vb2_buf_done(struct vb2_buffer *vb, int session_id, unsigned long flags; struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; + struct msm_session *session; struct vb2_buffer *vb2_buf = NULL; int rc = 0; - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) + session = msm_get_session(session_id); + if (IS_ERR_OR_NULL(session)) return 0; + + read_lock(&session->stream_rwlock); + + stream = msm_get_stream(session, stream_id); + if (IS_ERR_OR_NULL(stream)) { + read_unlock(&session->stream_rwlock); + return -EINVAL; + } + spin_lock_irqsave(&stream->stream_lock, flags); if (vb) { list_for_each_entry(msm_vb2, &(stream->queued_list), list) { @@ -285,6 +370,7 @@ static int msm_vb2_buf_done(struct vb2_buffer *vb, int session_id, pr_err("VB buffer is INVALID ses_id=%d, str_id=%d, vb=%pK\n", session_id, stream_id, vb); spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } msm_vb2 = @@ -302,6 +388,7 @@ static int msm_vb2_buf_done(struct vb2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return rc; } @@ -319,4 +406,3 @@ int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req) return 0; } - diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h index 7082f8583d1dafbfe0c8b51113b8b1d51a4c1290..b04d31b1e44d000dbedf1b93aeeae17b120997cb 100644 --- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h +++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2013, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -66,5 +66,6 @@ struct msm_stream { struct vb2_ops *msm_vb2_get_q_ops(void); struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void); int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd); +int msm_vb2_get_stream_state(struct msm_stream *stream); #endif /*_MSM_VB_H */ diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index 073b12940aa54caca413645dd208623430d8c8c6..5b077c9195a71b0ecdb0b17d323613888fbe518e 100755 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1292,7 +1292,7 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, { struct msm_actuator_cfg_data *cdata = (struct msm_actuator_cfg_data *)argp; - int32_t rc = 0; + int32_t rc = -EINVAL; mutex_lock(a_ctrl->actuator_mutex); CDBG("Enter\n"); CDBG("%s type %d\n", __func__, cdata->cfgtype); @@ -1305,6 +1305,7 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, case CFG_GET_ACTUATOR_INFO: cdata->is_af_supported = 1; cdata->cfg.cam_name = a_ctrl->cam_name; + rc = 0; break; case CFG_SET_ACTUATOR_INFO: @@ -1314,15 +1315,19 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, break; case CFG_SET_DEFAULT_FOCUS: - rc = a_ctrl->func_tbl->actuator_set_default_focus(a_ctrl, - &cdata->cfg.move); + if (a_ctrl->func_tbl && + a_ctrl->func_tbl->actuator_set_default_focus) + rc = a_ctrl->func_tbl->actuator_set_default_focus( + a_ctrl, &cdata->cfg.move); if (rc < 0) pr_err("move focus failed %d\n", rc); break; case CFG_MOVE_FOCUS: - rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, - &cdata->cfg.move); + if (a_ctrl->func_tbl && + a_ctrl->func_tbl->actuator_move_focus) + rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, + &cdata->cfg.move); if (rc < 0) pr_err("move focus failed %d\n", rc); break; @@ -1333,8 +1338,10 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, break; case CFG_SET_POSITION: - rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl, - &cdata->cfg.setpos); + if (a_ctrl->func_tbl && + a_ctrl->func_tbl->actuator_set_position) + rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl, + &cdata->cfg.setpos); if (rc < 0) pr_err("actuator_set_position failed %d\n", rc); break; diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 87e741b651c4a4d31b39973e9983deebb8cfc641..5d3c56191e0d44788da6431e56a46414c0dc0eb6 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -407,17 +407,11 @@ static int32_t msm_sensor_create_pd_settings(void *setting, #ifdef CONFIG_COMPAT if (is_compat_task()) { - int i = 0; - struct msm_sensor_power_setting32 *power_setting_iter = - (struct msm_sensor_power_setting32 *)compat_ptr(( - (struct msm_camera_sensor_slave_info32 *)setting)-> - power_setting_array.power_setting); - - for (i = 0; i < size_down; i++) { - pd[i].config_val = power_setting_iter[i].config_val; - pd[i].delay = power_setting_iter[i].delay; - pd[i].seq_type = power_setting_iter[i].seq_type; - pd[i].seq_val = power_setting_iter[i].seq_val; + rc = msm_sensor_get_pw_settings_compat( + pd, pu, size_down); + if (rc < 0) { + pr_err("failed"); + return -EFAULT; } } else #endif diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c index 07de5a22b1ec5ebd1f4f4ed79e39a188ba09f0c9..42a3ea7d1e19504342bc6e5b72edc7b7cd122ffa 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c +++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c @@ -1,6 +1,6 @@ /* Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -119,7 +119,10 @@ static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr, list_for_each_entry(region_elt, &audio->ion_region_queue, list) { if (addr >= region_elt->vaddr && addr < region_elt->vaddr + region_elt->len && - addr + len <= region_elt->vaddr + region_elt->len) { + addr + len <= region_elt->vaddr + region_elt->len && + addr + len > addr) { + /* to avoid integer addition overflow */ + /* offset since we could pass vaddr inside a registerd * ion buffer */ diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c index 7ed9739c0eddf1e304a35b49e7e46cbc6b3aa6c2..30e10d93237ed19196e760065673d19b2487e393 100644 --- a/drivers/net/wireless/bcmdhd/bcmevent.c +++ b/drivers/net/wireless/bcmdhd/bcmevent.c @@ -157,7 +157,6 @@ static const bcmevent_name_str_t bcmevent_names[] = { BCMEVENT_NAME(WLC_E_TXFAIL_THRESH), #ifdef GSCAN_SUPPORT BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT), - BCMEVENT_NAME(WLC_E_PFN_SWC), #endif /* GSCAN_SUPPORT */ #ifdef WLBSSLOAD_REPORT BCMEVENT_NAME(WLC_E_BSS_LOAD), diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index 1fbb5c42e965aa1325ef9ee502e3cb9320a545d4..d3f04a78afbbd8f7be53b01fa2d77db64bad030a 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -1325,7 +1325,6 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, case WLC_E_PFN_SCAN_NONE: case WLC_E_PFN_SCAN_ALLGONE: case WLC_E_PFN_GSCAN_FULL_RESULT: - case WLC_E_PFN_SWC: case WLC_E_PFN_SSID_EXT: DHD_EVENT(("PNOEVENT: %s\n", event_name)); break; diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 8f5078132238d841ec4bfa319cb5b66e979ddf69..5bf73f264ae3e73395bbe647d9d359f45c3ce8ae 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -6077,7 +6077,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef GSCAN_SUPPORT setbit(eventmask_msg->mask, WLC_E_PFN_GSCAN_FULL_RESULT); setbit(eventmask_msg->mask, WLC_E_PFN_SCAN_COMPLETE); - setbit(eventmask_msg->mask, WLC_E_PFN_SWC); setbit(eventmask_msg->mask, WLC_E_PFN_SSID_EXT); setbit(eventmask_msg->mask, WLC_E_ROAM_EXP_EVENT); #endif /* GSCAN_SUPPORT */ @@ -8423,14 +8422,6 @@ int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time_f return (dhd_pno_enable_full_scan_result(&dhd->pub, real_time_flag)); } -/* Linux wrapper to call common dhd_handle_swc_evt */ -void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_handle_swc_evt(&dhd->pub, data, send_evt_bytes)); -} - /* Linux wrapper to call common dhd_handle_hotlist_scan_evt */ void * dhd_dev_hotlist_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes, hotlist_type_t type) @@ -8442,11 +8433,12 @@ void * dhd_dev_hotlist_scan_event(struct net_device *dev, /* Linux wrapper to call common dhd_process_full_gscan_result */ void * dhd_dev_process_full_gscan_result(struct net_device *dev, -const void *data, int *send_evt_bytes) +const void *data, uint32 len, int *send_evt_bytes) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_process_full_gscan_result(&dhd->pub, data, send_evt_bytes)); + return dhd_process_full_gscan_result(&dhd->pub, data, len, + send_evt_bytes); } void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c index 4a57d74cc70efc9915c803a6e546f8052ea5872f..31a3b7c73ea999d670c52f6e1bcedb6279ebcee3 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd/dhd_pno.c @@ -98,6 +98,11 @@ #define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") #define TIME_MIN_DIFF 5 +#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) +#define EVENT_MAX_NETCNT \ + ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_t)) \ + / sizeof(wl_pfn_net_info_t) + 1) + #ifdef GSCAN_SUPPORT static int _dhd_pno_flush_ssid(dhd_pub_t *dhd); static wl_pfn_gscan_ch_bucket_cfg_t * @@ -1051,34 +1056,6 @@ exit: return err; } -#ifdef GSCAN_SUPPORT -static int -_dhd_pno_add_significant_bssid(dhd_pub_t *dhd, - wl_pfn_significant_bssid_t *p_pfn_significant_bssid, int nbssid) -{ - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - - if (!nbssid) { - err = BCME_ERROR; - goto exit; - } - - NULL_CHECK(p_pfn_significant_bssid, "bssid list is NULL", err); - - err = dhd_iovar(dhd, 0, "pfn_add_swc_bssid", - (char *)p_pfn_significant_bssid, - sizeof(wl_pfn_significant_bssid_t) * nbssid, NULL, 0, - TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_significant_bssid %d\n", __FUNCTION__, err)); - goto exit; - } -exit: - return err; -} -#endif /* GSCAN_SUPPORT */ - int dhd_pno_stop_for_ssid(dhd_pub_t *dhd) { @@ -1677,19 +1654,6 @@ static void dhd_pno_reset_cfg_gscan(dhd_pno_params_t *_params, _params->params_gscan.nbssid_hotlist = 0; DHD_PNO(("Flush Hotlist Config\n")); } - if (flags & GSCAN_FLUSH_SIGNIFICANT_CFG) { - dhd_pno_significant_bssid_t *iter, *next; - - if (_params->params_gscan.nbssid_significant_change > 0) { - list_for_each_entry_safe(iter, next, - &_params->params_gscan.significant_bssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - _params->params_gscan.nbssid_significant_change = 0; - DHD_PNO(("Flush Significant Change Config\n")); - } if (flags & GSCAN_FLUSH_EPNO_CFG) { dhd_pno_ssid_t *iter, *next; dhd_epno_ssid_cfg_t *epno_cfg = &_params->params_gscan.epno_cfg; @@ -1831,8 +1795,10 @@ void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN; ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX; ptr->max_scan_reporting_threshold = 100; - ptr->max_hotlist_aps = PFN_HOTLIST_MAX_NUM_APS; - ptr->max_significant_wifi_change_aps = PFN_SWC_MAX_NUM_APS; + ptr->max_hotlist_bssids = PFN_HOTLIST_MAX_NUM_APS; + ptr->max_hotlist_ssids = 0; + ptr->max_significant_wifi_change_aps = 0; + ptr->max_bssid_history_entries = 0; ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM; ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID; ptr->max_white_list_ssid = MAX_WHITELIST_SSID; @@ -1966,10 +1932,10 @@ int dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, INIT_LIST_HEAD(&_params->params_gscan.hotlist_bssid_list); if ((_params->params_gscan.nbssid_hotlist + - ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { + ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { DHD_ERROR(("Excessive number of hotlist APs programmed %d\n", - (_params->params_gscan.nbssid_hotlist + - ptr->nbssid))); + (_params->params_gscan.nbssid_hotlist + + ptr->nbssid))); err = BCME_RANGE; goto exit; } @@ -1995,61 +1961,6 @@ int dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, _params->params_gscan.lost_ap_window = ptr->lost_ap_window; } break; - case DHD_PNO_SIGNIFICANT_SCAN_CFG_ID: - { - gscan_swc_params_t *ptr = (gscan_swc_params_t *)buf; - dhd_pno_significant_bssid_t *_pno_significant_change_bssid; - wl_pfn_significant_bssid_t *significant_bssid_ptr; - - if (flush) { - dhd_pno_reset_cfg_gscan(_params, _pno_state, - GSCAN_FLUSH_SIGNIFICANT_CFG); - } - - if (!ptr->nbssid) - break; - - if (!_params->params_gscan.nbssid_significant_change) - INIT_LIST_HEAD(&_params->params_gscan.significant_bssid_list); - - if ((_params->params_gscan.nbssid_significant_change + - ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { - DHD_ERROR(("Excessive number of SWC APs programmed %d\n", - (_params->params_gscan.nbssid_significant_change + - ptr->nbssid))); - err = BCME_RANGE; - goto exit; - } - - for (i = 0, significant_bssid_ptr = ptr->bssid_elem_list; - i < ptr->nbssid; i++, significant_bssid_ptr++) { - _pno_significant_change_bssid = - kzalloc(sizeof(dhd_pno_significant_bssid_t), - GFP_KERNEL); - - if (!_pno_significant_change_bssid) { - DHD_ERROR(("SWC bssidptr is NULL, cannot kalloc %zd bytes", - sizeof(dhd_pno_significant_bssid_t))); - err = BCME_NOMEM; - goto exit; - } - memcpy(&_pno_significant_change_bssid->BSSID, - &significant_bssid_ptr->macaddr, ETHER_ADDR_LEN); - _pno_significant_change_bssid->rssi_low_threshold = - significant_bssid_ptr->rssi_low_threshold; - _pno_significant_change_bssid->rssi_high_threshold = - significant_bssid_ptr->rssi_high_threshold; - list_add_tail(&_pno_significant_change_bssid->list, - &_params->params_gscan.significant_bssid_list); - } - - _params->params_gscan.swc_nbssid_threshold = ptr->swc_threshold; - _params->params_gscan.swc_rssi_window_size = ptr->rssi_window; - _params->params_gscan.lost_ap_window = ptr->lost_ap_window; - _params->params_gscan.nbssid_significant_change += ptr->nbssid; - - } - break; case DHD_PNO_SCAN_CFG_ID: { int i, k; @@ -2168,7 +2079,6 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL; wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL; - wl_pfn_significant_bssid_t *p_pfn_significant_bssid = NULL; wl_pfn_bssid_t *p_pfn_bssid = NULL; dhd_pno_params_t *params_legacy; dhd_pno_params_t *_params; @@ -2242,7 +2152,8 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); - pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOC(dhd->osh, gscan_param_size); + pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) + MALLOCZ(dhd->osh, gscan_param_size); if (!pfn_gscan_cfg_t) { DHD_ERROR(("%s: failed to malloc memory of size %d\n", @@ -2257,16 +2168,6 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) else pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET; - if (gscan_params->nbssid_significant_change) { - pfn_gscan_cfg_t->swc_nbssid_threshold = gscan_params->swc_nbssid_threshold; - pfn_gscan_cfg_t->swc_rssi_window_size = gscan_params->swc_rssi_window_size; - pfn_gscan_cfg_t->lost_ap_window = gscan_params->lost_ap_window; - } else { - pfn_gscan_cfg_t->swc_nbssid_threshold = 0; - pfn_gscan_cfg_t->swc_rssi_window_size = 0; - pfn_gscan_cfg_t->lost_ap_window = 0; - } - pfn_gscan_cfg_t->flags = (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); pfn_gscan_cfg_t->flags |= FORCE_ALL_CHANNEL_BUCKETS_IN_FIRST_SCAN; @@ -2301,38 +2202,6 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) __FUNCTION__, err)); goto exit; } - if (gscan_params->nbssid_significant_change) { - dhd_pno_significant_bssid_t *iter, *next; - - p_pfn_significant_bssid = kzalloc(sizeof(wl_pfn_significant_bssid_t) * - gscan_params->nbssid_significant_change, GFP_KERNEL); - if (p_pfn_significant_bssid == NULL) { - DHD_ERROR(("%s : failed to allocate memory %zd\n", - __FUNCTION__, - sizeof(wl_pfn_significant_bssid_t) * - gscan_params->nbssid_significant_change)); - err = BCME_NOMEM; - goto exit; - } - i = 0; - /* convert dhd_pno_significant_bssid_t to wl_pfn_significant_bssid_t */ - list_for_each_entry_safe(iter, next, &gscan_params->significant_bssid_list, list) { - p_pfn_significant_bssid[i].rssi_low_threshold = iter->rssi_low_threshold; - p_pfn_significant_bssid[i].rssi_high_threshold = iter->rssi_high_threshold; - memcpy(&p_pfn_significant_bssid[i].macaddr, &iter->BSSID, ETHER_ADDR_LEN); - i++; - } - - DHD_PNO(("nbssid_significant_change %d \n", - gscan_params->nbssid_significant_change)); - err = _dhd_pno_add_significant_bssid(dhd, p_pfn_significant_bssid, - gscan_params->nbssid_significant_change); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_add_significant_bssid(err :%d)\n", - __FUNCTION__, err)); - goto exit; - } - } /* Reprogram ePNO cfg from dhd cache if FW has been flushed */ if (fw_flushed) { dhd_pno_set_epno(dhd); @@ -2386,7 +2255,6 @@ exit: _pno_state->pno_mode &= ~DHD_PNO_GSCAN_MODE; } } - kfree(p_pfn_significant_bssid); kfree(p_pfn_bssid); if (pfn_gscan_cfg_t) MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size); @@ -3605,91 +3473,6 @@ int dhd_retreive_batch_scan_results(dhd_pub_t *dhd) return err; } -/* Handle Significant WiFi Change (SWC) event from FW - * Send event to HAL when all results arrive from FW - */ -void * dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes) -{ - void *ptr = NULL; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - struct dhd_pno_gscan_params *gscan_params; - struct dhd_pno_swc_evt_param *params; - wl_pfn_swc_results_t *results = (wl_pfn_swc_results_t *)event_data; - wl_pfn_significant_net_t *change_array; - int i; - - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - params = &(gscan_params->param_significant); - - if (!results->total_count) { - *send_evt_bytes = 0; - return ptr; - } - - if (!params->results_rxed_so_far) { - if (!params->change_array) { - params->change_array = (wl_pfn_significant_net_t *) - kmalloc(sizeof(wl_pfn_significant_net_t) * results->total_count, - GFP_KERNEL); - - if (!params->change_array) { - DHD_ERROR(("%s Cannot Malloc %zd bytes!!\n", __FUNCTION__, - sizeof(wl_pfn_significant_net_t) * results->total_count)); - *send_evt_bytes = 0; - return ptr; - } - } else { - DHD_ERROR(("RX'ed WLC_E_PFN_SWC evt from FW, previous evt not complete!!")); - *send_evt_bytes = 0; - return ptr; - } - - } - - DHD_PNO(("%s: pkt_count %d total_count %d\n", __FUNCTION__, - results->pkt_count, results->total_count)); - - for (i = 0; i < results->pkt_count; i++) { - DHD_PNO(("\t %02x:%02x:%02x:%02x:%02x:%02x\n", - results->list[i].BSSID.octet[0], - results->list[i].BSSID.octet[1], - results->list[i].BSSID.octet[2], - results->list[i].BSSID.octet[3], - results->list[i].BSSID.octet[4], - results->list[i].BSSID.octet[5])); - } - - change_array = ¶ms->change_array[params->results_rxed_so_far]; - if ((params->results_rxed_so_far + results->pkt_count) > - results->total_count) { - DHD_ERROR(("Error: Invalid data reset the counters!!\n")); - *send_evt_bytes = 0; - kfree(params->change_array); - params->change_array = NULL; - return ptr; - } - - memcpy(change_array, results->list, - sizeof(wl_pfn_significant_net_t) * results->pkt_count); - params->results_rxed_so_far += results->pkt_count; - - if (params->results_rxed_so_far == results->total_count) { - params->results_rxed_so_far = 0; - *send_evt_bytes = sizeof(wl_pfn_significant_net_t) * results->total_count; - /* Pack up change buffer to send up and reset - * results_rxed_so_far, after its done. - */ - ptr = (void *) params->change_array; - /* expecting the callee to free this mem chunk */ - params->change_array = NULL; - } - else { - *send_evt_bytes = 0; - } - - return ptr; -} - void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) { dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); @@ -3718,7 +3501,8 @@ void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) } void * -dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) +dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, + int *size) { wl_bss_info_t *bi = NULL; wl_gscan_result_t *gscan_result; @@ -3727,15 +3511,25 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) uint8 channel; uint32 mem_needed; struct timespec ts; + u32 bi_ie_length = 0; + u32 bi_ie_offset = 0; *size = 0; - gscan_result = (wl_gscan_result_t *)data; - if (!gscan_result) { DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); goto exit; } + + if ((len < sizeof(*gscan_result)) || + (len < dtoh32(gscan_result->buflen)) || + (dtoh32(gscan_result->buflen) > + (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { + DHD_ERROR(("%s: invalid gscan buflen:%u\n", __func__, + dtoh32(gscan_result->buflen))); + goto exit; + } + if (!gscan_result->bss_info) { DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); goto exit; @@ -3747,12 +3541,21 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } + + bi_ie_offset = dtoh32(bi->ie_offset); + bi_ie_length = dtoh32(bi->ie_length); + if ((bi_ie_offset + bi_ie_length) > bi_length) { + DHD_ERROR(("%s: Invalid ie_length:%u or ie_offset:%u\n", + __func__, bi_ie_length, bi_ie_offset)); + goto exit; + } if (bi->SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", bi->SSID_len)); - bi->SSID_len = DOT11_MAX_SSID_LEN; + DHD_ERROR(("%s: Invalid SSID length %u\n", + __func__, bi->SSID_len)); + goto exit; } - mem_needed = OFFSETOF(wifi_gscan_full_result_t, ie_data) + bi->ie_length; + mem_needed = OFFSETOF(wifi_gscan_full_result_t, ie_data) + bi_ie_length; result = (wifi_gscan_full_result_t *) kmalloc(mem_needed, GFP_KERNEL); if (!result) { @@ -3774,9 +3577,9 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) result->fixed.ts = (uint64) TIMESPEC_TO_US(ts); result->fixed.beacon_period = dtoh16(bi->beacon_period); result->fixed.capability = dtoh16(bi->capability); - result->ie_length = dtoh32(bi->ie_length); + result->ie_length = bi_ie_length; memcpy(&result->fixed.macaddr, &bi->BSSID, ETHER_ADDR_LEN); - memcpy(result->ie_data, ((uint8 *)bi + bi->ie_offset), bi->ie_length); + memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi_ie_length); *size = mem_needed; exit: return result; @@ -3801,7 +3604,12 @@ dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) { wl_pfn_scanresults_t *pfn_result = (wl_pfn_scanresults_t *)data; wl_pfn_net_info_t *net; - + if ((pfn_result->count == 0) || + (pfn_result->count > EVENT_MAX_NETCNT)) { + DHD_ERROR(("%s event %d: incorrect results count:%d\n", + __FUNCTION__, event, pfn_result->count)); + return NULL; + } if (pfn_result->version != PFN_SCANRESULT_VERSION) { DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, pfn_result->version, PFN_SCANRESULT_VERSION)); @@ -3916,7 +3724,9 @@ void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *s gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - if (!results->count) { + if ((results->count == 0) || (results->count > EVENT_MAX_NETCNT)) { + DHD_ERROR(("%s: wrong count:%d\n", __FUNCTION__, + results->count)); *send_evt_bytes = 0; return ptr; } diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h index a0edf54049acff7243f95114f5a7e37ad2cccbd8..9a348f93ada8ca033a6f86d036c7e76bd9a40689 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd/dhd_pno.h @@ -359,16 +359,18 @@ typedef struct { } wifi_passpoint_network; typedef struct dhd_pno_gscan_capabilities { - int max_scan_cache_size; - int max_scan_buckets; - int max_ap_cache_per_scan; - int max_rssi_sample_size; - int max_scan_reporting_threshold; - int max_hotlist_aps; - int max_significant_wifi_change_aps; - int max_epno_ssid_crc32; - int max_epno_hidden_ssid; - int max_white_list_ssid; + int max_scan_cache_size; + int max_scan_buckets; + int max_ap_cache_per_scan; + int max_rssi_sample_size; + int max_scan_reporting_threshold; + int max_hotlist_bssids; + int max_hotlist_ssids; + int max_significant_wifi_change_aps; + int max_bssid_history_entries; + int max_epno_ssid_crc32; + int max_epno_hidden_ssid; + int max_white_list_ssid; } dhd_pno_gscan_capabilities_t; typedef struct dhd_epno_ssid_cfg { @@ -426,26 +428,6 @@ typedef struct gscan_hotlist_scan_params { struct bssid_t bssid[1]; /* n bssids to follow */ } gscan_hotlist_scan_params_t; -/* SWC (Significant WiFi Change) params */ -typedef struct gscan_swc_params { - /* Rssi averaging window size */ - uint8 rssi_window; - /* Number of scans that the AP has to be absent before - * being declared LOST - */ - uint8 lost_ap_window; - /* if x Aps have a significant change generate an event. */ - uint8 swc_threshold; - uint8 nbssid; - wl_pfn_significant_bssid_t bssid_elem_list[1]; -} gscan_swc_params_t; - -typedef struct dhd_pno_significant_bssid { - struct ether_addr BSSID; - int8 rssi_low_threshold; - int8 rssi_high_threshold; - struct list_head list; -} dhd_pno_significant_bssid_t; #endif /* GSCAN_SUPPORT */ typedef union dhd_pno_params { struct dhd_pno_legacy_params params_legacy; @@ -506,13 +488,11 @@ int dhd_dev_pno_lock_access_batch_results(struct net_device *dev); void dhd_dev_pno_unlock_access_batch_results(struct net_device *dev); extern int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush); extern int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time); -extern void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data, - int *send_evt_bytes); int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes, hotlist_type_t type); void * dhd_dev_process_full_gscan_result(struct net_device *dev, - const void *data, int *send_evt_bytes); + const void *data, uint32 len, int *send_evt_bytes); extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); extern int dhd_dev_wait_batch_results_complete(struct net_device *dev); @@ -560,11 +540,11 @@ extern int dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush); extern int dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag); extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *buf); extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); -extern void *dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes); extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes, hotlist_type_t type); -extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, - int *send_evt_bytes); +extern void * +dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, + uint32 len, int *send_evt_bytes); extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd); diff --git a/drivers/net/wireless/bcmdhd/dhd_rtt.c b/drivers/net/wireless/bcmdhd/dhd_rtt.c index d35c21d32baaad9fb70d4d983d785d3e54131b5f..7ad5df66408b5224a1576406f746b68f2fed7763 100644 --- a/drivers/net/wireless/bcmdhd/dhd_rtt.c +++ b/drivers/net/wireless/bcmdhd/dhd_rtt.c @@ -1716,6 +1716,10 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) return ret; } } + if (!event_data) { + DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__)); + return -EINVAL; + } p_event = (wl_proxd_event_t *) event_data; version = ltoh16(p_event->version); if (version < WL_PROXD_API_VERSION) { @@ -1738,6 +1742,11 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) goto exit; /* ignore this event */ } /* get TLVs len, skip over event header */ + if (ltoh16(p_event->len) < OFFSETOF(wl_proxd_event_t, tlvs)) { + DHD_ERROR(("invalid FTM event length:%d\n", ltoh16(p_event->len))); + ret = -EINVAL; + goto exit; + } tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs); DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n", p_loginfo->text, diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h index 098da15f45f7d188edc4f8d842599ad677153d89..d6f7cd4e1a0d494561e5cf0df7346f1568545af1 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h @@ -236,7 +236,7 @@ typedef union bcm_event_msg_u { #define WLC_E_FBT_AUTH_REQ_IND 132 /* FBT Authentication Request Indication */ #define WLC_E_RSSI_LQM 133 /* Enhancement addition for WLC_E_RSSI */ #define WLC_E_PFN_GSCAN_FULL_RESULT 134 /* Full probe/beacon (IEs etc) results */ -#define WLC_E_PFN_SWC 135 /* Significant change in rssi of bssids being tracked */ +/* 135 was legacy entry for WLC_E_PFN_SWC can be reused */ #define WLC_E_PFN_SCAN_COMPLETE 138 /* PFN completed scan of network list */ #define WLC_E_RMC_EVENT 139 /* RMC event */ #define WLC_E_PFN_SSID_EXT 142 /* SSID EXT event */ diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h index 831b0bfba3b3970b5391122b225092a58e1d9b3c..ba1ad5853e4506db9afa70b1e188d718d88cd70e 100644 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h @@ -2705,12 +2705,6 @@ typedef struct wl_pfn_bssid { uint16 flags; } wl_pfn_bssid_t; -typedef struct wl_pfn_significant_bssid { - struct ether_addr macaddr; - int8 rssi_low_threshold; - int8 rssi_high_threshold; -} wl_pfn_significant_bssid_t; - #define WL_PFN_SUPPRESSFOUND_MASK 0x08 #define WL_PFN_SUPPRESSLOST_MASK 0x10 #define WL_PFN_RSSI_MASK 0xff00 diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 842091ffb3414a0b163d903ec772b773f1d455c6..e7ababd395be6ffdc84ed5d2fa5f7fd464b216c0 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -9397,14 +9397,6 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, u32 len = ntoh32(e->datalen); switch (event) { - case WLC_E_PFN_SWC: - ptr = dhd_dev_swc_scan_event(ndev, data, &send_evt_bytes); - if (send_evt_bytes) { - wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_GSCAN_SIGNIFICANT_EVENT, ptr, send_evt_bytes); - kfree(ptr); - } - break; case WLC_E_PFN_BEST_BATCHING: err = dhd_dev_retrieve_batch_scan(ndev); if (err < 0) { @@ -9452,10 +9444,13 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, err = -EINVAL; break; case WLC_E_PFN_GSCAN_FULL_RESULT: - ptr = dhd_dev_process_full_gscan_result(ndev, data, &send_evt_bytes); + ptr = + dhd_dev_process_full_gscan_result(ndev, data, len, + &send_evt_bytes); if (ptr) { wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes); + GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, + send_evt_bytes); kfree(ptr); } else err = -ENOMEM; @@ -9657,9 +9652,15 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, u32 event = ntoh32(e->event_type); u8 *mgmt_frame; u8 bsscfgidx = e->bsscfgidx; - u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); + u32 mgmt_frame_len = ntoh32(e->datalen); u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); + if (mgmt_frame_len < sizeof(wl_event_rx_frame_data_t)) { + WL_ERR(("wrong datalen:%d\n", mgmt_frame_len)); + return -EINVAL; + } + mgmt_frame_len -= sizeof(wl_event_rx_frame_data_t); + memset(&bssid, 0, ETHER_ADDR_LEN); ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); @@ -9781,7 +9782,11 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_DBG((" Event WLC_E_PROBREQ_MSG received\n")); mgmt_frame = (u8 *)(data); mgmt_frame_len = ntoh32(e->datalen); - + if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) { + WL_ERR(("WLC_E_PROBREQ_MSG - wrong datalen:%d\n", + mgmt_frame_len)); + return -EINVAL; + } prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN; /* Parse prob_req IEs */ @@ -10081,7 +10086,6 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event; - cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event; @@ -10503,6 +10507,13 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("Invalid escan result (NULL pointer)\n")); goto exit; } + if ((dtoh32(escan_result->buflen) > ESCAN_BUF_SIZE) || + (dtoh32(escan_result->buflen) < + sizeof(wl_escan_result_t))) { + WL_ERR(("Invalid escan buffer len:%d\n", + dtoh32(escan_result->buflen))); + goto exit; + } if (dtoh16(escan_result->bss_count) != 1) { WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); goto exit; diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c index af651b4eaaa773298dbda5446c7466992f56b759..ece2b39364e2238bb14c10cd8f3ab5d9312d9e79 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c @@ -1164,106 +1164,6 @@ static int wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy, return err; } -static int wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - int err = 0; - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - gscan_swc_params_t *significant_params; - int tmp, tmp1, tmp2, type, j = 0; - const struct nlattr *outer, *inner, *iter; - bool flush = FALSE; - wl_pfn_significant_bssid_t *pbssid; - uint16 num_bssid = 0; - uint16 max_buf_size = sizeof(gscan_swc_params_t) + - sizeof(wl_pfn_significant_bssid_t) * (PFN_SWC_MAX_NUM_APS - 1); - - significant_params = kzalloc(max_buf_size, GFP_KERNEL); - - if (!significant_params) { - WL_ERR(("Cannot Malloc mem size:%d\n", len)); - return BCME_NOMEM; - } - - - nla_for_each_attr(iter, data, len, tmp2) { - type = nla_type(iter); - - switch (type) { - case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH: - flush = (bool) nla_get_u8(iter); - break; - case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE: - significant_params->rssi_window = nla_get_u16(iter); - break; - case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: - significant_params->lost_ap_window = nla_get_u16(iter); - break; - case GSCAN_ATTRIBUTE_MIN_BREACHING: - significant_params->swc_threshold = nla_get_u16(iter); - break; - case GSCAN_ATTRIBUTE_NUM_BSSID: - num_bssid = nla_get_u16(iter); - if (num_bssid > PFN_SWC_MAX_NUM_APS) { - WL_ERR(("ovar max SWC bssids:%d\n", - num_bssid)); - err = BCME_BADARG; - goto exit; - } - break; - case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS: - if (num_bssid == 0) { - WL_ERR(("num_bssid : 0\n")); - err = BCME_BADARG; - goto exit; - } - pbssid = significant_params->bssid_elem_list; - nla_for_each_nested(outer, iter, tmp) { - if (j >= num_bssid) { - j++; - break; - } - nla_for_each_nested(inner, outer, tmp1) { - switch (nla_type(inner)) { - case GSCAN_ATTRIBUTE_BSSID: - memcpy(&(pbssid[j].macaddr), - nla_data(inner), - ETHER_ADDR_LEN); - break; - case GSCAN_ATTRIBUTE_RSSI_HIGH: - pbssid[j].rssi_high_threshold = - (int8) nla_get_u8(inner); - break; - case GSCAN_ATTRIBUTE_RSSI_LOW: - pbssid[j].rssi_low_threshold = - (int8) nla_get_u8(inner); - break; - } - } - j++; - } - break; - } - } - if (j != num_bssid) { - WL_ERR(("swc bssids count:%d not matched to num_bssid:%d\n", - j, num_bssid)); - err = BCME_BADARG; - goto exit; - } - significant_params->nbssid = j; - - if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg), - DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, significant_params, flush) < 0) { - WL_ERR(("Could not set GSCAN significant cfg\n")); - err = -EINVAL; - goto exit; - } -exit: - kfree(significant_params); - return err; -} - static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { @@ -3024,14 +2924,6 @@ static const struct wiphy_vendor_command wl_vendor_cmds [] = { .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, .doit = wl_cfgvendor_hotlist_cfg }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_significant_change_cfg - }, { { .vendor_id = OUI_GOOGLE, diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 6264e1783f6a727060a87374cea1b2ad0d17bb3e..a457b43cc1837f30b1d20ea1dec89b639e3b465e 100755 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1707,8 +1707,15 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, dev->res[base_sel - 1].base, wr_offset, wr_mask, wr_value); - msm_pcie_write_reg_field(dev->res[base_sel - 1].base, - wr_offset, wr_mask, wr_value); + base_sel_size = resource_size(dev->res[base_sel - 1].resource); + + if (wr_offset > base_sel_size - 4 || + msm_pcie_check_align(dev, wr_offset)) + pr_alert("PCIe: RC%d: Invalid wr_offset: 0x%x. wr_offset should be no more than 0x%x\n", + dev->rc_idx, wr_offset, base_sel_size - 4); + else + msm_pcie_write_reg_field(dev->res[base_sel - 1].base, + wr_offset, wr_mask, wr_value); break; case 13: /* dump all registers of base_sel */ diff --git a/drivers/platform/msm/ipa/rmnet_ipa.c b/drivers/platform/msm/ipa/rmnet_ipa.c index a149a9eb4f7b331e44cb08de3fa0c0336b1c634f..0d6fb33194698d0ad8a7b4ab41dc6073ec0b39b3 100644 --- a/drivers/platform/msm/ipa/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/rmnet_ipa.c @@ -57,6 +57,7 @@ static atomic_t is_initialized; static atomic_t is_ssr; u32 apps_to_ipa_hdl, ipa_to_apps_hdl; /* get handler from ipa */ +static struct mutex add_mux_channel_lock; static int wwan_add_ul_flt_rule_to_ipa(void); static int wwan_del_ul_flt_rule_to_ipa(void); @@ -1242,9 +1243,11 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) rmnet_mux_val.mux_id); return rc; } + mutex_lock(&add_mux_channel_lock); if (rmnet_index >= MAX_NUM_OF_MUX_CHANNEL) { IPAWANERR("Exceed mux_channel limit(%d)\n", rmnet_index); + mutex_unlock(&add_mux_channel_lock); return -EFAULT; } IPAWANDBG("ADD_MUX_CHANNEL(%d, name: %s)\n", @@ -1270,6 +1273,7 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) IPAWANERR("device %s reg IPA failed\n", extend_ioctl_data.u. rmnet_mux_val.vchannel_name); + mutex_unlock(&add_mux_channel_lock); return -ENODEV; } mux_channel[rmnet_index].mux_channel_set = true; @@ -1282,6 +1286,7 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) mux_channel[rmnet_index].ul_flt_reg = false; } rmnet_index++; + mutex_unlock(&add_mux_channel_lock); break; case RMNET_IOCTL_SET_EGRESS_DATA_FORMAT: IPAWANDBG("get RMNET_IOCTL_SET_EGRESS_DATA_FORMAT\n"); @@ -2050,7 +2055,7 @@ static int __init ipa_wwan_init(void) atomic_set(&is_initialized, 0); atomic_set(&is_ssr, 0); - + mutex_init(&add_mux_channel_lock); /* Register for Modem SSR */ subsys = subsys_notif_register_notifier(SUBSYS_MODEM, &ssr_notifier); if (!IS_ERR(subsys)) @@ -2061,6 +2066,7 @@ static int __init ipa_wwan_init(void) static void __exit ipa_wwan_cleanup(void) { + mutex_destroy(&add_mux_channel_lock); platform_driver_unregister(&rmnet_ipa_driver); } diff --git a/drivers/platform/msm/msm_bus/msm_bus_dbg.c b/drivers/platform/msm/msm_bus/msm_bus_dbg.c index cbaf1d71b1b700188c993e2b96daa13745cb4e89..460ec163bb18782ce6594ba8f8a657d145508e2e 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_dbg.c +++ b/drivers/platform/msm/msm_bus/msm_bus_dbg.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2010-2012, 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012, 2014-2017, The Linux Foundation. All rights + * reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,6 +38,7 @@ static struct dentry *clients; static struct dentry *dir; static DEFINE_MUTEX(msm_bus_dbg_fablist_lock); +static DEFINE_RT_MUTEX(msm_bus_dbg_cllist_lock); struct msm_bus_dbg_state { uint32_t cl; uint8_t enable; @@ -288,7 +290,9 @@ static ssize_t client_data_read(struct file *file, char __user *buf, struct msm_bus_cldata *cldata = NULL; const struct msm_bus_client_handle *handle = file->private_data; int found = 0; + ssize_t ret; + rt_mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { if ((cldata->clid == cl) || (cldata->handle && (cldata->handle == handle))) { @@ -297,12 +301,17 @@ static ssize_t client_data_read(struct file *file, char __user *buf, } } - if (!found) + if (!found) { + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); return 0; + } bsize = cldata->size; - return simple_read_from_buffer(buf, count, ppos, + ret = simple_read_from_buffer(buf, count, ppos, cldata->buffer, bsize); + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); + + return ret; } static int client_data_open(struct inode *inode, struct file *file) @@ -338,7 +347,9 @@ int msm_bus_dbg_add_client(const struct msm_bus_client_handle *pdata) return -ENOMEM; } cldata->handle = pdata; + rt_mutex_lock(&msm_bus_dbg_cllist_lock); list_add_tail(&cldata->list, &cl_list); + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); return 0; } @@ -351,6 +362,7 @@ int msm_bus_dbg_rec_transaction(const struct msm_bus_client_handle *pdata, bool found = false; char *buf = NULL; + rt_mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { if (cldata->handle == pdata) { found = true; @@ -358,12 +370,15 @@ int msm_bus_dbg_rec_transaction(const struct msm_bus_client_handle *pdata, } } - if (!found) + if (!found) { + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); return -ENOENT; + } if (cldata->file == NULL) { if (pdata->name == NULL) { MSM_BUS_DBG("Client doesn't have a name\n"); + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); return -EINVAL; } pr_err("\n%s setting up debugfs %s", __func__, pdata->name); @@ -393,6 +408,7 @@ int msm_bus_dbg_rec_transaction(const struct msm_bus_client_handle *pdata, i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu ", ib); i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n"); cldata->size = i; + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); trace_bus_update_request((int)ts.tv_sec, (int)ts.tv_nsec, pdata->name, pdata->mas, pdata->slv, ab, ib, @@ -405,6 +421,7 @@ void msm_bus_dbg_remove_client(const struct msm_bus_client_handle *pdata) { struct msm_bus_cldata *cldata = NULL; + rt_mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { if (cldata->handle == pdata) { debugfs_remove(cldata->file); @@ -413,6 +430,7 @@ void msm_bus_dbg_remove_client(const struct msm_bus_client_handle *pdata) break; } } + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); } static int msm_bus_dbg_record_client(const struct msm_bus_scale_pdata *pdata, @@ -430,7 +448,9 @@ static int msm_bus_dbg_record_client(const struct msm_bus_scale_pdata *pdata, cldata->clid = clid; cldata->file = file; cldata->size = 0; + rt_mutex_lock(&msm_bus_dbg_cllist_lock); list_add_tail(&cldata->list, &cl_list); + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); return 0; } @@ -438,6 +458,7 @@ static void msm_bus_dbg_free_client(uint32_t clid) { struct msm_bus_cldata *cldata = NULL; + rt_mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { if (cldata->clid == clid) { debugfs_remove(cldata->file); @@ -446,6 +467,7 @@ static void msm_bus_dbg_free_client(uint32_t clid) break; } } + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); } static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata, @@ -457,6 +479,7 @@ static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata, struct timespec ts; int found = 0; + rt_mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { if (cldata->clid == clid) { found = 1; @@ -464,11 +487,14 @@ static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata, } } - if (!found) + if (!found) { + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); return -ENOENT; + } if (cldata->file == NULL) { if (pdata->name == NULL) { + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); MSM_BUS_DBG("Client doesn't have a name\n"); return -EINVAL; } @@ -517,19 +543,9 @@ static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata, cldata->index = index; cldata->size = i; - return i; -} + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); -static int msm_bus_dbg_update_request(struct msm_bus_cldata *cldata, int index) -{ - int ret = 0; - - if ((index < 0) || (index > cldata->pdata->num_usecases)) { - MSM_BUS_DBG("Invalid index!\n"); - return -EINVAL; - } - ret = msm_bus_scale_client_update_request(cldata->clid, index); - return ret; + return i; } static ssize_t msm_bus_dbg_update_request_write(struct file *file, @@ -541,19 +557,26 @@ static ssize_t msm_bus_dbg_update_request_write(struct file *file, char *chid; char *buf = kmalloc((sizeof(char) * (cnt + 1)), GFP_KERNEL); int found = 0; + uint32_t clid; + ssize_t res = cnt; if (!buf || IS_ERR(buf)) { MSM_BUS_ERR("Memory allocation for buffer failed\n"); return -ENOMEM; } - if (cnt == 0) - return 0; - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; + if (cnt == 0) { + res = 0; + goto out; + } + if (copy_from_user(buf, ubuf, cnt)) { + res = -EFAULT; + goto out; + } buf[cnt] = '\0'; chid = buf; MSM_BUS_DBG("buffer: %s\n size: %zu\n", buf, sizeof(ubuf)); + rt_mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { if (strnstr(chid, cldata->pdata->name, cnt)) { found = 1; @@ -564,21 +587,35 @@ static ssize_t msm_bus_dbg_update_request_write(struct file *file, if (ret) { MSM_BUS_DBG("Index conversion" " failed\n"); - return -EFAULT; + rt_mutex_unlock( + &msm_bus_dbg_cllist_lock); + res = -EFAULT; + goto out; } } else { MSM_BUS_DBG("Error parsing input. Index not" " found\n"); found = 0; } + if ((index < 0) || + (index > cldata->pdata->num_usecases)) { + MSM_BUS_DBG("Invalid index!\n"); + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); + res = -EINVAL; + goto out; + } + clid = cldata->clid; break; } } + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); if (found) - msm_bus_dbg_update_request(cldata, index); + msm_bus_scale_client_update_request(clid, index); + +out: kfree(buf); - return cnt; + return res; } /** @@ -601,8 +638,10 @@ static ssize_t fabric_data_read(struct file *file, char __user *buf, break; } } - if (!found) + if (!found) { + mutex_unlock(&msm_bus_dbg_fablist_lock); return -ENOENT; + } bsize = fablist->size; ret = simple_read_from_buffer(buf, count, ppos, fablist->buffer, bsize); @@ -691,8 +730,10 @@ static int msm_bus_dbg_fill_fab_buffer(const char *fabname, break; } } - if (!found) + if (!found) { + mutex_unlock(&msm_bus_dbg_fablist_lock); return -ENOENT; + } if (fablist->file == NULL) { MSM_BUS_DBG("Fabric dbg entry does not exist\n"); @@ -841,6 +882,7 @@ static int __init msm_bus_debugfs_init(void) goto err; } + rt_mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { if (cldata->pdata) { if (cldata->pdata->name == NULL) { @@ -860,6 +902,7 @@ static int __init msm_bus_debugfs_init(void) &client_data_fops); } } + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); mutex_lock(&msm_bus_dbg_fablist_lock); list_for_each_entry(fablist, &fabdata_list, list) { @@ -868,6 +911,7 @@ static int __init msm_bus_debugfs_init(void) if (fablist->file == NULL) { MSM_BUS_DBG("Cannot create files for commit data\n"); kfree(rules_buf); + mutex_unlock(&msm_bus_dbg_fablist_lock); goto err; } } @@ -887,10 +931,14 @@ static void __exit msm_bus_dbg_teardown(void) struct msm_bus_cldata *cldata = NULL, *cldata_temp; debugfs_remove_recursive(dir); + + rt_mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry_safe(cldata, cldata_temp, &cl_list, list) { list_del(&cldata->list); kfree(cldata); } + rt_mutex_unlock(&msm_bus_dbg_cllist_lock); + mutex_lock(&msm_bus_dbg_fablist_lock); list_for_each_entry_safe(fablist, fablist_temp, &fabdata_list, list) { list_del(&fablist->list); diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c index 2253972ab313181388bcbbc0b41074208e1b37e8..935f6e8a26c4d3a88f206ed984eb7ab4d464cfc6 100644 --- a/drivers/platform/msm/sps/sps.c +++ b/drivers/platform/msm/sps/sps.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -101,6 +101,7 @@ static char *debugfs_buf; static u32 debugfs_buf_size; static u32 debugfs_buf_used; static int wraparound; +static struct mutex sps_debugfs_lock; struct dentry *dent; struct dentry *dfile_info; @@ -118,6 +119,7 @@ static struct sps_bam *phy2bam(phys_addr_t phys_addr); /* record debug info for debugfs */ void sps_debugfs_record(const char *msg) { + mutex_lock(&sps_debugfs_lock); if (debugfs_record_enabled) { if (debugfs_buf_used + MAX_MSG_LEN >= debugfs_buf_size) { debugfs_buf_used = 0; @@ -131,6 +133,7 @@ void sps_debugfs_record(const char *msg) debugfs_buf_size - debugfs_buf_used, "\n**** end line of sps log ****\n\n"); } + mutex_unlock(&sps_debugfs_lock); } /* read the recorded debug info to userspace */ @@ -140,6 +143,7 @@ static ssize_t sps_read_info(struct file *file, char __user *ubuf, int ret = 0; int size; + mutex_lock(&sps_debugfs_lock); if (debugfs_record_enabled) { if (wraparound) size = debugfs_buf_size - MAX_MSG_LEN; @@ -149,6 +153,7 @@ static ssize_t sps_read_info(struct file *file, char __user *ubuf, ret = simple_read_from_buffer(ubuf, count, ppos, debugfs_buf, size); } + mutex_unlock(&sps_debugfs_lock); return ret; } @@ -193,11 +198,13 @@ static ssize_t sps_set_info(struct file *file, const char __user *buf, new_buf_size = buf_size_kb * SZ_1K; + mutex_lock(&sps_debugfs_lock); if (debugfs_record_enabled) { if (debugfs_buf_size == new_buf_size) { /* need do nothing */ pr_info("sps:debugfs: input buffer size " "is the same as before.\n"); + mutex_unlock(&sps_debugfs_lock); return count; } else { /* release the current buffer */ @@ -217,12 +224,14 @@ static ssize_t sps_set_info(struct file *file, const char __user *buf, if (!debugfs_buf) { debugfs_buf_size = 0; pr_err("sps:fail to allocate memory for debug_fs.\n"); + mutex_unlock(&sps_debugfs_lock); return -ENOMEM; } debugfs_buf_used = 0; wraparound = false; debugfs_record_enabled = true; + mutex_unlock(&sps_debugfs_lock); return count; } @@ -270,6 +279,7 @@ static ssize_t sps_set_logging_option(struct file *file, const char __user *buf, return count; } + mutex_lock(&sps_debugfs_lock); if (((option == 0) || (option == 2)) && ((logging_option == 1) || (logging_option == 3))) { debugfs_record_enabled = false; @@ -281,6 +291,7 @@ static ssize_t sps_set_logging_option(struct file *file, const char __user *buf, } logging_option = option; + mutex_unlock(&sps_debugfs_lock); return count; } @@ -607,6 +618,8 @@ static void sps_debugfs_init(void) goto bam_addr_err; } + mutex_init(&sps_debugfs_lock); + return; bam_addr_err: diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h index 535f5a3b27db48e529cd65ba7f7ec058dab66b7a..e453078d2643b2b62598f7cc8b8abbd8185fe1e0 100644 --- a/drivers/platform/msm/sps/spsi.h +++ b/drivers/platform/msm/sps/spsi.h @@ -61,11 +61,6 @@ extern u8 logging_option; extern u8 debug_level_option; extern u8 print_limit_option; -#define SPS_DEBUGFS(msg, args...) do { \ - char buf[MAX_MSG_LEN]; \ - snprintf(buf, MAX_MSG_LEN, msg"\n", ##args); \ - sps_debugfs_record(buf); \ - } while (0) #define SPS_ERR(msg, args...) do { \ if (logging_option != 1) { \ if (unlikely(print_limit_option > 2)) \ @@ -73,8 +68,6 @@ extern u8 print_limit_option; else \ pr_err(msg, ##args); \ } \ - if (unlikely(debugfs_record_enabled)) \ - SPS_DEBUGFS(msg, ##args); \ } while (0) #define SPS_INFO(msg, args...) do { \ if (logging_option != 1) { \ @@ -83,8 +76,6 @@ extern u8 print_limit_option; else \ pr_info(msg, ##args); \ } \ - if (unlikely(debugfs_record_enabled)) \ - SPS_DEBUGFS(msg, ##args); \ } while (0) #define SPS_DBG(msg, args...) do { \ if ((unlikely(logging_option > 1)) \ @@ -95,8 +86,6 @@ extern u8 print_limit_option; pr_info(msg, ##args); \ } else \ pr_debug(msg, ##args); \ - if (unlikely(debugfs_record_enabled)) \ - SPS_DEBUGFS(msg, ##args); \ } while (0) #define SPS_DBG1(msg, args...) do { \ if ((unlikely(logging_option > 1)) \ @@ -107,8 +96,6 @@ extern u8 print_limit_option; pr_info(msg, ##args); \ } else \ pr_debug(msg, ##args); \ - if (unlikely(debugfs_record_enabled)) \ - SPS_DEBUGFS(msg, ##args); \ } while (0) #define SPS_DBG2(msg, args...) do { \ if ((unlikely(logging_option > 1)) \ @@ -119,8 +106,6 @@ extern u8 print_limit_option; pr_info(msg, ##args); \ } else \ pr_debug(msg, ##args); \ - if (unlikely(debugfs_record_enabled)) \ - SPS_DEBUGFS(msg, ##args); \ } while (0) #define SPS_DBG3(msg, args...) do { \ if ((unlikely(logging_option > 1)) \ @@ -131,8 +116,6 @@ extern u8 print_limit_option; pr_info(msg, ##args); \ } else \ pr_debug(msg, ##args); \ - if (unlikely(debugfs_record_enabled)) \ - SPS_DEBUGFS(msg, ##args); \ } while (0) #else #define SPS_DBG3(x...) pr_debug(x) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 721d839d6c543c63b16797f015fe90dbe3ddf3d3..9a600f05ab57a3cf61561e6c4b7cf26db90a5c9b 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -486,7 +486,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) old_hdr->result = EIO; break; case DID_ERROR: - old_hdr->result = (srp->sense_b[0] == 0 && + old_hdr->result = (srp->sense_b[0] == 0 && hp->masked_status == GOOD) ? 0 : EIO; break; default: @@ -832,8 +832,10 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) return -ENXIO; if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR)) return -EFAULT; + mutex_lock(&sfp->parentdp->open_rel_lock); result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, 1, read_only, 1, &srp); + mutex_unlock(&sfp->parentdp->open_rel_lock); if (result < 0) return result; result = wait_event_interruptible(sfp->read_wait, @@ -873,8 +875,10 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) sfp->low_dma = 1; if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) { val = (int) sfp->reserve.bufflen; + mutex_lock(&sfp->parentdp->open_rel_lock); sg_remove_scat(&sfp->reserve); sg_build_reserve(sfp, val); + mutex_unlock(&sfp->parentdp->open_rel_lock); } } else { if (sdp->detached) @@ -942,15 +946,17 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) result = get_user(val, ip); if (result) return result; - if (val < 0) - return -EINVAL; + if (val < 0) + return -EINVAL; val = min_t(int, val, queue_max_sectors(sdp->device->request_queue) * 512); if (val != sfp->reserve.bufflen) { if (sg_res_in_use(sfp) || sfp->mmap_called) return -EBUSY; + mutex_lock(&sfp->parentdp->open_rel_lock); sg_remove_scat(&sfp->reserve); sg_build_reserve(sfp, val); + mutex_unlock(&sfp->parentdp->open_rel_lock); } return 0; case SG_GET_RESERVED_SIZE: @@ -1003,8 +1009,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) if (srp) { rinfo[val].req_state = srp->done + 1; rinfo[val].problem = - srp->header.masked_status & - srp->header.host_status & + srp->header.masked_status & + srp->header.host_status & srp->header.driver_status; if (srp->done) rinfo[val].duration = @@ -1025,7 +1031,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) } } read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - result = __copy_to_user(p, rinfo, + result = __copy_to_user(p, rinfo, SZ_SG_REQ_INFO * SG_MAX_QUEUE); result = result ? -EFAULT : 0; kfree(rinfo); @@ -1127,14 +1133,14 @@ static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned lon return -ENXIO; sdev = sdp->device; - if (sdev->host->hostt->compat_ioctl) { + if (sdev->host->hostt->compat_ioctl) { int ret; ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); return ret; } - + return -ENOIOCTLCMD; } #endif @@ -1594,7 +1600,7 @@ init_sg(void) else def_reserved_size = sg_big_buff; - rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), + rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS, "sg"); if (rc) return rc; @@ -2234,7 +2240,7 @@ static const struct file_operations adio_fops = { }; static int sg_proc_single_open_dressz(struct inode *inode, struct file *file); -static ssize_t sg_proc_write_dressz(struct file *filp, +static ssize_t sg_proc_write_dressz(struct file *filp, const char __user *buffer, size_t count, loff_t *off); static const struct file_operations dressz_fops = { .owner = THIS_MODULE, @@ -2374,7 +2380,7 @@ static int sg_proc_single_open_adio(struct inode *inode, struct file *file) return single_open(file, sg_proc_seq_show_int, &sg_allow_dio); } -static ssize_t +static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer, size_t count, loff_t *off) { @@ -2395,7 +2401,7 @@ static int sg_proc_single_open_dressz(struct inode *inode, struct file *file) return single_open(file, sg_proc_seq_show_int, &sg_big_buff); } -static ssize_t +static ssize_t sg_proc_write_dressz(struct file *filp, const char __user *buffer, size_t count, loff_t *off) { @@ -2552,7 +2558,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) hp = &srp->header; new_interface = (hp->interface_id == '\0') ? 0 : 1; if (srp->res_used) { - if (new_interface && + if (new_interface && (SG_FLAG_MMAP_IO & hp->flags)) cp = " mmap>> "; else @@ -2566,7 +2572,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_printf(s, cp); blen = srp->data.bufflen; usg = srp->data.k_use_sg; - seq_printf(s, srp->done ? + seq_printf(s, srp->done ? ((1 == srp->done) ? "rcv:" : "fin:") : "act:"); seq_printf(s, " id=%d blen=%d", diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2ab445fe77969aafa2d8b7015983a2e9a586b379..8f8de667db99ac5af8c0144da6b647fc2dc69fea 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -661,6 +661,20 @@ has_zeroout: ret = check_block_validity(inode, map); if (ret != 0) return ret; + + /* + * Inodes with freshly allocated blocks where contents will be + * visible after transaction commit must be on transaction's + * ordered data list. + */ + if (map->m_flags & EXT4_MAP_NEW && + !(map->m_flags & EXT4_MAP_UNWRITTEN) && + !IS_NOQUOTA(inode) && + ext4_should_order_data(inode)) { + ret = ext4_jbd2_file_inode(handle, inode); + if (ret) + return ret; + } } return retval; } @@ -1116,15 +1130,6 @@ static int ext4_write_end(struct file *file, int i_size_changed = 0; trace_ext4_write_end(inode, pos, len, copied); - if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) { - ret = ext4_jbd2_file_inode(handle, inode); - if (ret) { - unlock_page(page); - page_cache_release(page); - goto errout; - } - } - if (ext4_has_inline_data(inode)) { ret = ext4_write_inline_data_end(inode, pos, len, copied, page); diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 4e5f332f15d99267e1b70c83450f2f42fb2d4a76..db7d89cea2ce00031114de61178dba6ae37eaef2 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -169,7 +169,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 8cc0c19e33e436b5e74253cb01f632e95ba28ccf..2759cee0e2989fd1ae0570a28c13bddb4e058da2 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -320,11 +320,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) /* We don't show the stack guard page in /proc/maps */ start = vma->vm_start; - if (stack_guard_page_start(vma, start)) - start += PAGE_SIZE; end = vma->vm_end; - if (stack_guard_page_end(vma, end)) - end -= PAGE_SIZE; seq_setwidth(m, 25 + sizeof(void *) * 6 - 1); seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ", diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h index 9e6fee91bae4b06c763cdacaa2bf78a2b9a46b68..d8d124e2285997ab48d5c0641558f4cf6040792b 100644 --- a/include/linux/dma-contiguous.h +++ b/include/linux/dma-contiguous.h @@ -117,7 +117,7 @@ static inline int dma_declare_contiguous_reserved(struct device *dev, return ret; } -unsigned long dma_alloc_from_contiguous(struct device *dev, int count, +unsigned long dma_alloc_from_contiguous(struct device *dev, size_t count, unsigned int order); bool dma_release_from_contiguous(struct device *dev, unsigned long pfn, int count); @@ -136,7 +136,7 @@ int dma_declare_contiguous(struct device *dev, phys_addr_t size, } static inline -unsigned long dma_alloc_from_contiguous(struct device *dev, int count, +unsigned long dma_alloc_from_contiguous(struct device *dev, size_t count, unsigned int order) { return 0; diff --git a/include/linux/mm.h b/include/linux/mm.h index 54567b0c41d6360594f96b6be4f9effeae5b11ae..fb3b142b3138b425c10050a61e77a4ecd159da68 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1090,34 +1090,6 @@ int set_page_dirty(struct page *page); int set_page_dirty_lock(struct page *page); int clear_page_dirty_for_io(struct page *page); -/* Is the vma a continuation of the stack vma above it? */ -static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr) -{ - return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); -} - -static inline int stack_guard_page_start(struct vm_area_struct *vma, - unsigned long addr) -{ - return (vma->vm_flags & VM_GROWSDOWN) && - (vma->vm_start == addr) && - !vma_growsdown(vma->vm_prev, addr); -} - -/* Is the vma a continuation of the stack vma below it? */ -static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr) -{ - return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP); -} - -static inline int stack_guard_page_end(struct vm_area_struct *vma, - unsigned long addr) -{ - return (vma->vm_flags & VM_GROWSUP) && - (vma->vm_end == addr) && - !vma_growsup(vma->vm_next, addr); -} - extern pid_t vm_is_stack(struct task_struct *task, struct vm_area_struct *vma, int in_group); @@ -1659,6 +1631,7 @@ unsigned long ra_submit(struct file_ra_state *ra, struct address_space *mapping, struct file *filp); +extern unsigned long stack_guard_gap; /* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */ extern int expand_stack(struct vm_area_struct *vma, unsigned long address); @@ -1687,6 +1660,30 @@ static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * m return vma; } +static inline unsigned long vm_start_gap(struct vm_area_struct *vma) +{ + unsigned long vm_start = vma->vm_start; + + if (vma->vm_flags & VM_GROWSDOWN) { + vm_start -= stack_guard_gap; + if (vm_start > vma->vm_start) + vm_start = 0; + } + return vm_start; +} + +static inline unsigned long vm_end_gap(struct vm_area_struct *vma) +{ + unsigned long vm_end = vma->vm_end; + + if (vma->vm_flags & VM_GROWSUP) { + vm_end += stack_guard_gap; + if (vm_end < vma->vm_end) + vm_end = -PAGE_SIZE; + } + return vm_end; +} + static inline unsigned long vma_pages(struct vm_area_struct *vma) { return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; diff --git a/mm/memory.c b/mm/memory.c index f224af43d04e6b383853c9429752e6669a724206..bc29378238df058aa21e6279be0a7d03368df43b 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1659,12 +1659,6 @@ no_page_table: return page; } -static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) -{ - return stack_guard_page_start(vma, addr) || - stack_guard_page_end(vma, addr+PAGE_SIZE); -} - /** * __get_user_pages() - pin user pages in memory * @tsk: task_struct of target task @@ -1845,11 +1839,6 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, int ret; unsigned int fault_flags = 0; - /* For mlock, just skip the stack guard page. */ - if (foll_flags & FOLL_MLOCK) { - if (stack_guard_page(vma, start)) - goto next_page; - } if (foll_flags & FOLL_WRITE) fault_flags |= FAULT_FLAG_WRITE; if (nonblocking) @@ -3218,40 +3207,6 @@ out_release: return ret; } -/* - * This is like a special single-page "expand_{down|up}wards()", - * except we must first make sure that 'address{-|+}PAGE_SIZE' - * doesn't hit another vma. - */ -static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned long address) -{ - address &= PAGE_MASK; - if ((vma->vm_flags & VM_GROWSDOWN) && address == vma->vm_start) { - struct vm_area_struct *prev = vma->vm_prev; - - /* - * Is there a mapping abutting this one below? - * - * That's only ok if it's the same stack mapping - * that has gotten split.. - */ - if (prev && prev->vm_end == address) - return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; - - return expand_downwards(vma, address - PAGE_SIZE); - } - if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) { - struct vm_area_struct *next = vma->vm_next; - - /* As VM_GROWSDOWN but s/below/above/ */ - if (next && next->vm_start == address + PAGE_SIZE) - return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; - - return expand_upwards(vma, address + PAGE_SIZE); - } - return 0; -} - /* * We enter with non-exclusive mmap_sem (to exclude vma changes, * but allow concurrent faults), and pte mapped but not yet locked. @@ -3271,10 +3226,6 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, if (vma->vm_flags & VM_SHARED) return VM_FAULT_SIGBUS; - /* Check if we need to add a guard page to the stack */ - if (check_stack_guard_page(vma, address) < 0) - return VM_FAULT_SIGBUS; - /* Use the zero-page for reads */ if (!(flags & FAULT_FLAG_WRITE)) { entry = pte_mkspecial(pfn_pte(my_zero_pfn(address), diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 420e4b97ffab5853d6e543080c612b341a171ce3..984419bbe565c1b4f9d4df41bfa5faeb8f0a93ba 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1537,7 +1537,6 @@ asmlinkage long compat_sys_get_mempolicy(int __user *policy, asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask, compat_ulong_t maxnode) { - long err = 0; unsigned long __user *nm = NULL; unsigned long nr_bits, alloc_size; DECLARE_BITMAP(bm, MAX_NUMNODES); @@ -1546,14 +1545,13 @@ asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask, alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8; if (nmask) { - err = compat_get_bitmap(bm, nmask, nr_bits); + if (compat_get_bitmap(bm, nmask, nr_bits)) + return -EFAULT; nm = compat_alloc_user_space(alloc_size); - err |= copy_to_user(nm, bm, alloc_size); + if (copy_to_user(nm, bm, alloc_size)) + return -EFAULT; } - if (err) - return -EFAULT; - return sys_set_mempolicy(mode, nm, nr_bits+1); } @@ -1561,7 +1559,6 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len, compat_ulong_t mode, compat_ulong_t __user *nmask, compat_ulong_t maxnode, compat_ulong_t flags) { - long err = 0; unsigned long __user *nm = NULL; unsigned long nr_bits, alloc_size; nodemask_t bm; @@ -1570,14 +1567,13 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len, alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8; if (nmask) { - err = compat_get_bitmap(nodes_addr(bm), nmask, nr_bits); + if (compat_get_bitmap(nodes_addr(bm), nmask, nr_bits)) + return -EFAULT; nm = compat_alloc_user_space(alloc_size); - err |= copy_to_user(nm, nodes_addr(bm), alloc_size); + if (copy_to_user(nm, nodes_addr(bm), alloc_size)) + return -EFAULT; } - if (err) - return -EFAULT; - return sys_mbind(start, len, mode, nm, nr_bits+1, flags); } diff --git a/mm/mmap.c b/mm/mmap.c index fbadaaef0564d0a27ea4ec19ec9c00dadaa92ce0..e3c6241c33ad95da281a9fed1af8c09c9912bcb2 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -275,6 +275,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) unsigned long rlim, retval; unsigned long newbrk, oldbrk; struct mm_struct *mm = current->mm; + struct vm_area_struct *next; unsigned long min_brk; bool populate; @@ -320,7 +321,8 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) } /* Check against existing mmap mappings. */ - if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) + next = find_vma(mm, oldbrk); + if (next && newbrk + PAGE_SIZE > vm_start_gap(next)) goto out; /* Ok, looks good - let it rip. */ @@ -343,10 +345,22 @@ out: static long vma_compute_subtree_gap(struct vm_area_struct *vma) { - unsigned long max, subtree_gap; - max = vma->vm_start; - if (vma->vm_prev) - max -= vma->vm_prev->vm_end; + unsigned long max, prev_end, subtree_gap; + + /* + * Note: in the rare case of a VM_GROWSDOWN above a VM_GROWSUP, we + * allow two stack_guard_gaps between them here, and when choosing + * an unmapped area; whereas when expanding we only require one. + * That's a little inconsistent, but keeps the code here simpler. + */ + max = vm_start_gap(vma); + if (vma->vm_prev) { + prev_end = vm_end_gap(vma->vm_prev); + if (max > prev_end) + max -= prev_end; + else + max = 0; + } if (vma->vm_rb.rb_left) { subtree_gap = rb_entry(vma->vm_rb.rb_left, struct vm_area_struct, vm_rb)->rb_subtree_gap; @@ -430,7 +444,7 @@ void validate_mm(struct mm_struct *mm) list_for_each_entry(avc, &vma->anon_vma_chain, same_vma) anon_vma_interval_tree_verify(avc); vma_unlock_anon_vma(vma); - highest_address = vma->vm_end; + highest_address = vm_end_gap(vma); vma = vma->vm_next; i++; } @@ -598,7 +612,7 @@ void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, if (vma->vm_next) vma_gap_update(vma->vm_next); else - mm->highest_vm_end = vma->vm_end; + mm->highest_vm_end = vm_end_gap(vma); /* * vma->vm_prev wasn't known when we followed the rbtree to find the @@ -847,7 +861,7 @@ again: remove_next = 1 + (end > next->vm_end); vma_gap_update(vma); if (end_changed) { if (!next) - mm->highest_vm_end = end; + mm->highest_vm_end = vm_end_gap(vma); else if (!adjust_next) vma_gap_update(next); } @@ -890,7 +904,7 @@ again: remove_next = 1 + (end > next->vm_end); else if (next) vma_gap_update(next); else - mm->highest_vm_end = end; + WARN_ON(mm->highest_vm_end != vm_end_gap(vma)); } if (insert && file) uprobe_mmap(insert); @@ -1689,7 +1703,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info) while (true) { /* Visit left subtree if it looks promising */ - gap_end = vma->vm_start; + gap_end = vm_start_gap(vma); if (gap_end >= low_limit && vma->vm_rb.rb_left) { struct vm_area_struct *left = rb_entry(vma->vm_rb.rb_left, @@ -1700,12 +1714,13 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info) } } - gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; + gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0; check_current: /* Check if current node has a suitable gap */ if (gap_start > high_limit) return -ENOMEM; - if (gap_end >= low_limit && gap_end - gap_start >= length) + if (gap_end >= low_limit && + gap_end > gap_start && gap_end - gap_start >= length) goto found; /* Visit right subtree if it looks promising */ @@ -1727,8 +1742,8 @@ check_current: vma = rb_entry(rb_parent(prev), struct vm_area_struct, vm_rb); if (prev == vma->vm_rb.rb_left) { - gap_start = vma->vm_prev->vm_end; - gap_end = vma->vm_start; + gap_start = vm_end_gap(vma->vm_prev); + gap_end = vm_start_gap(vma); goto check_current; } } @@ -1792,7 +1807,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) while (true) { /* Visit right subtree if it looks promising */ - gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; + gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0; if (gap_start <= high_limit && vma->vm_rb.rb_right) { struct vm_area_struct *right = rb_entry(vma->vm_rb.rb_right, @@ -1805,10 +1820,11 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) check_current: /* Check if current node has a suitable gap */ - gap_end = vma->vm_start; + gap_end = vm_start_gap(vma); if (gap_end < low_limit) return -ENOMEM; - if (gap_start <= high_limit && gap_end - gap_start >= length) + if (gap_start <= high_limit && + gap_end > gap_start && gap_end - gap_start >= length) goto found; /* Visit left subtree if it looks promising */ @@ -1831,7 +1847,7 @@ check_current: struct vm_area_struct, vm_rb); if (prev == vma->vm_rb.rb_right) { gap_start = vma->vm_prev ? - vma->vm_prev->vm_end : 0; + vm_end_gap(vma->vm_prev) : 0; goto check_current; } } @@ -1869,7 +1885,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; + struct vm_area_struct *vma, *prev; struct vm_unmapped_area_info info; if (len > TASK_SIZE - mmap_min_addr) @@ -1880,9 +1896,10 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, if (addr) { addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); + vma = find_vma_prev(mm, addr, &prev); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma)) && + (!prev || addr >= vm_end_gap(prev))) return addr; } @@ -1905,7 +1922,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, const unsigned long len, const unsigned long pgoff, const unsigned long flags) { - struct vm_area_struct *vma; + struct vm_area_struct *vma, *prev; struct mm_struct *mm = current->mm; unsigned long addr = addr0; struct vm_unmapped_area_info info; @@ -1920,9 +1937,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, /* requesting a specific address */ if (addr) { addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); + vma = find_vma_prev(mm, addr, &prev); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma)) && + (!prev || addr >= vm_end_gap(prev))) return addr; } @@ -2049,7 +2067,8 @@ find_vma_prev(struct mm_struct *mm, unsigned long addr, * update accounting. This is shared with both the * grow-up and grow-down cases. */ -static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow) +static int acct_stack_growth(struct vm_area_struct *vma, + unsigned long size, unsigned long grow) { struct mm_struct *mm = vma->vm_mm; struct rlimit *rlim = current->signal->rlim; @@ -2104,32 +2123,40 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns */ int expand_upwards(struct vm_area_struct *vma, unsigned long address) { - int error; + struct vm_area_struct *next; + unsigned long gap_addr; + int error = 0; if (!(vma->vm_flags & VM_GROWSUP)) return -EFAULT; - /* - * We must make sure the anon_vma is allocated - * so that the anon_vma locking is not a noop. - */ + /* Guard against wrapping around to address 0. */ + address &= PAGE_MASK; + address += PAGE_SIZE; + if (!address) + return -ENOMEM; + + /* Enforce stack_guard_gap */ + gap_addr = address + stack_guard_gap; + if (gap_addr < address) + return -ENOMEM; + next = vma->vm_next; + if (next && next->vm_start < gap_addr) { + if (!(next->vm_flags & VM_GROWSUP)) + return -ENOMEM; + /* Check that both stack segments have the same anon_vma? */ + } + + /* We must make sure the anon_vma is allocated. */ if (unlikely(anon_vma_prepare(vma))) return -ENOMEM; - vma_lock_anon_vma(vma); /* * vma->vm_start/vm_end cannot change under us because the caller * is required to hold the mmap_sem in read mode. We need the * anon_vma lock to serialize against concurrent expand_stacks. - * Also guard against wrapping around to address 0. */ - if (address < PAGE_ALIGN(address+4)) - address = PAGE_ALIGN(address+4); - else { - vma_unlock_anon_vma(vma); - return -ENOMEM; - } - error = 0; + vma_lock_anon_vma(vma); /* Somebody else might have raced and expanded it already */ if (address > vma->vm_end) { @@ -2160,7 +2187,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) if (vma->vm_next) vma_gap_update(vma->vm_next); else - vma->vm_mm->highest_vm_end = address; + vma->vm_mm->highest_vm_end = vm_end_gap(vma); spin_unlock(&vma->vm_mm->page_table_lock); perf_event_mmap(vma); @@ -2180,27 +2207,36 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) int expand_downwards(struct vm_area_struct *vma, unsigned long address) { + struct vm_area_struct *prev; + unsigned long gap_addr; int error; - /* - * We must make sure the anon_vma is allocated - * so that the anon_vma locking is not a noop. - */ - if (unlikely(anon_vma_prepare(vma))) - return -ENOMEM; - address &= PAGE_MASK; error = security_mmap_addr(address); if (error) return error; - vma_lock_anon_vma(vma); + /* Enforce stack_guard_gap */ + gap_addr = address - stack_guard_gap; + if (gap_addr > address) + return -ENOMEM; + prev = vma->vm_prev; + if (prev && prev->vm_end > gap_addr) { + if (!(prev->vm_flags & VM_GROWSDOWN)) + return -ENOMEM; + /* Check that both stack segments have the same anon_vma? */ + } + + /* We must make sure the anon_vma is allocated. */ + if (unlikely(anon_vma_prepare(vma))) + return -ENOMEM; /* * vma->vm_start/vm_end cannot change under us because the caller * is required to hold the mmap_sem in read mode. We need the * anon_vma lock to serialize against concurrent expand_stacks. */ + vma_lock_anon_vma(vma); /* Somebody else might have raced and expanded it already */ if (address < vma->vm_start) { @@ -2242,28 +2278,25 @@ int expand_downwards(struct vm_area_struct *vma, return error; } -/* - * Note how expand_stack() refuses to expand the stack all the way to - * abut the next virtual mapping, *unless* that mapping itself is also - * a stack mapping. We want to leave room for a guard page, after all - * (the guard page itself is not added here, that is done by the - * actual page faulting logic) - * - * This matches the behavior of the guard page logic (see mm/memory.c: - * check_stack_guard_page()), which only allows the guard page to be - * removed under these circumstances. - */ +/* enforced gap between the expanding stack and other mappings. */ +unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT; + +static int __init cmdline_parse_stack_guard_gap(char *p) +{ + unsigned long val; + char *endptr; + + val = simple_strtoul(p, &endptr, 10); + if (!*endptr) + stack_guard_gap = val << PAGE_SHIFT; + + return 0; +} +__setup("stack_guard_gap=", cmdline_parse_stack_guard_gap); + #ifdef CONFIG_STACK_GROWSUP int expand_stack(struct vm_area_struct *vma, unsigned long address) { - struct vm_area_struct *next; - - address &= PAGE_MASK; - next = vma->vm_next; - if (next && next->vm_start == address + PAGE_SIZE) { - if (!(next->vm_flags & VM_GROWSUP)) - return -ENOMEM; - } return expand_upwards(vma, address); } @@ -2285,14 +2318,6 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr) #else int expand_stack(struct vm_area_struct *vma, unsigned long address) { - struct vm_area_struct *prev; - - address &= PAGE_MASK; - prev = vma->vm_prev; - if (prev && prev->vm_end == address) { - if (!(prev->vm_flags & VM_GROWSDOWN)) - return -ENOMEM; - } return expand_downwards(vma, address); } @@ -2388,7 +2413,7 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma, vma->vm_prev = prev; vma_gap_update(vma); } else - mm->highest_vm_end = prev ? prev->vm_end : 0; + mm->highest_vm_end = prev ? vm_end_gap(prev) : 0; tail_vma->vm_next = NULL; mm->mmap_cache = NULL; /* Kill the cache. */ } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 86eedbaf037ff2bc18d23bc5c764dd3ba8ae5d2c..6298599cd974d8ba822d7c28b6c8b3485547685d 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -483,6 +483,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, newsk->sk_backlog_rcv = dccp_v4_do_rcv; newnp->pktoptions = NULL; newnp->opt = NULL; + newnp->ipv6_mc_list = NULL; + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; @@ -558,6 +561,10 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, /* Clone RX bits */ newnp->rxopt.all = np->rxopt.all; + newnp->ipv6_mc_list = NULL; + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; + /* Clone pktoptions received with SYN */ newnp->pktoptions = NULL; if (ireq6->pktopts != NULL) { diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 19bb4491514bd952c5088cb42088af25f41480ce..912cb4dedfe59dbf2d8c7db877965961d1fbdd83 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -697,6 +697,8 @@ struct sock *inet_csk_clone_lock(const struct sock *sk, inet_sk(newsk)->inet_sport = inet_rsk(req)->loc_port; newsk->sk_write_space = sk_stream_write_space; + inet_sk(newsk)->mc_list = NULL; + newsk->sk_mark = inet_rsk(req)->ir_mark; newicsk->icsk_retransmits = 0; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 884e50f4098a5c3aaa286c4253f6bd871c49c01b..8fa7ad2427c1192aa21e72e52fd775d8cd849020 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -734,6 +734,12 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, ret = -EAGAIN; break; } + /* if __tcp_splice_read() got nothing while we have + * an skb in receive queue, we do not want to loop. + * This might happen with URG data. + */ + if (!skb_queue_empty(&sk->sk_receive_queue)) + break; sk_wait_data(sk, &timeo); if (signal_pending(current)) { ret = sock_intr_errno(timeo); diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 153507a74c82f8164f588b87c4810b1703a8e652..3a9420eff60d750d6cbf3bbb9044d3dfb55e1dde 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -364,35 +364,37 @@ static void ip6gre_tunnel_uninit(struct net_device *dev) static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { - const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data; - __be16 *p = (__be16 *)(skb->data + offset); - int grehlen = offset + 4; + const struct gre_base_hdr *greh; + const struct ipv6hdr *ipv6h; + int grehlen = sizeof(*greh); struct ip6_tnl *t; + int key_off = 0; __be16 flags; + __be32 key; - flags = p[0]; - if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { - if (flags&(GRE_VERSION|GRE_ROUTING)) - return; - if (flags&GRE_KEY) { - grehlen += 4; - if (flags&GRE_CSUM) - grehlen += 4; - } + if (!pskb_may_pull(skb, offset + grehlen)) + return; + greh = (const struct gre_base_hdr *)(skb->data + offset); + flags = greh->flags; + if (flags & (GRE_VERSION | GRE_ROUTING)) + return; + if (flags & GRE_CSUM) + grehlen += 4; + if (flags & GRE_KEY) { + key_off = grehlen + offset; + grehlen += 4; } - /* If only 8 bytes returned, keyed message will be dropped here */ - if (!pskb_may_pull(skb, grehlen)) + if (!pskb_may_pull(skb, offset + grehlen)) return; ipv6h = (const struct ipv6hdr *)skb->data; - p = (__be16 *)(skb->data + offset); + greh = (const struct gre_base_hdr *)(skb->data + offset); + key = key_off ? *(__be32 *)(skb->data + key_off) : 0; t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr, - flags & GRE_KEY ? - *(((__be32 *)p) + (grehlen / 4) - 1) : 0, - p[1]); + key, greh->protocol); if (t == NULL) return; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index fd256a7b37dd0e479be66dddf124c3f123d6c53a..3ba57fc842068d8b053d0400415ccd4d71c063f1 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1135,6 +1135,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newtp->af_specific = &tcp_sock_ipv6_mapped_specific; #endif + newnp->ipv6_mc_list = NULL; newnp->ipv6_ac_list = NULL; newnp->ipv6_fl_list = NULL; newnp->pktoptions = NULL; @@ -1202,6 +1203,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, First: no IPv4 options. */ newinet->inet_opt = NULL; + newnp->ipv6_mc_list = NULL; newnp->ipv6_ac_list = NULL; newnp->ipv6_fl_list = NULL; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 45b64637aa9bc16081f8095f46869644cfd856a4..cc05702529e49e8a909f07346c495a8d17d3c124 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1318,13 +1318,16 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) return -EINVAL; } + mutex_lock(&fanout_mutex); + + err = -EINVAL; if (!po->running) - return -EINVAL; + goto out; + err = -EALREADY; if (po->fanout) - return -EALREADY; + goto out; - mutex_lock(&fanout_mutex); match = NULL; list_for_each_entry(f, &fanout_list, list) { if (f->id == id && @@ -1380,17 +1383,16 @@ static void fanout_release(struct sock *sk) struct packet_sock *po = pkt_sk(sk); struct packet_fanout *f; - f = po->fanout; - if (!f) - return; - mutex_lock(&fanout_mutex); - po->fanout = NULL; + f = po->fanout; + if (f) { + po->fanout = NULL; - if (atomic_dec_and_test(&f->sk_ref)) { - list_del(&f->list); - dev_remove_pack(&f->prot_hook); - kfree(f); + if (atomic_dec_and_test(&f->sk_ref)) { + list_del(&f->list); + dev_remove_pack(&f->prot_hook); + kfree(f); + } } mutex_unlock(&fanout_mutex); } diff --git a/sound/core/timer.c b/sound/core/timer.c index ee81c947c24bb9fb08e67b8c8db050a082a291ed..0641d14bc42383136d3b49f8d345a5f98b8656e3 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1534,6 +1534,7 @@ static int snd_timer_user_tselect(struct file *file, if (err < 0) goto __err; + tu->qhead = tu->qtail = tu->qused = 0; kfree(tu->queue); tu->queue = NULL; kfree(tu->tqueue); @@ -1858,6 +1859,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, tu = file->private_data; unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); + mutex_lock(&tu->ioctl_lock); spin_lock_irq(&tu->qlock); while ((long)count - result >= unit) { while (!tu->qused) { @@ -1873,7 +1875,9 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, add_wait_queue(&tu->qchange_sleep, &wait); spin_unlock_irq(&tu->qlock); + mutex_unlock(&tu->ioctl_lock); schedule(); + mutex_lock(&tu->ioctl_lock); spin_lock_irq(&tu->qlock); remove_wait_queue(&tu->qchange_sleep, &wait); @@ -1912,6 +1916,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, } spin_unlock_irq(&tu->qlock); _error: + mutex_unlock(&tu->ioctl_lock); return result > 0 ? result : err; } diff --git a/sound/soc/msm/apq8084-i2s.c b/sound/soc/msm/apq8084-i2s.c index 794aa25d5e5e179ec008b31f855489ddede783ce..5897e9cc505ab8952b93c7d73da3b6cec90f1e19 100644 --- a/sound/soc/msm/apq8084-i2s.c +++ b/sound/soc/msm/apq8084-i2s.c @@ -1826,7 +1826,7 @@ static struct snd_soc_dai_link apq8084_dai_links[] = { .name = "APQ8084 Compr8", .stream_name = "COMPR8", .cpu_dai_name = "MultiMedia8", - .platform_name = "msm-compr-dsp", + .platform_name = "msm-compress-dsp", .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, diff --git a/sound/soc/msm/apq8084.c b/sound/soc/msm/apq8084.c index aa2e25f62bcf90bc109a9e71ba877c9bd75bf3d2..2b02e5ddfa9a56b5b5f38af24be4f6a2654b1832 100644 --- a/sound/soc/msm/apq8084.c +++ b/sound/soc/msm/apq8084.c @@ -3046,7 +3046,7 @@ static struct snd_soc_dai_link apq8084_common_dai_links[] = { .name = "APQ8084 Compr8", .stream_name = "COMPR8", .cpu_dai_name = "MultiMedia8", - .platform_name = "msm-compr-dsp", + .platform_name = "msm-compress-dsp", .dynamic = 1, .async_ops = ASYNC_DPCM_SND_SOC_PREPARE | ASYNC_DPCM_SND_SOC_HW_PARAMS, diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c index 4095c12d0f69acb9420251cc1bf0353884704a72..113d77b068b9538f6613e44361a64c3a4602e0f8 100644 --- a/sound/soc/msm/msm8226.c +++ b/sound/soc/msm/msm8226.c @@ -1495,7 +1495,7 @@ static struct snd_soc_dai_link msm8226_common_dai[] = { .name = "MSM8226 Compr8", .stream_name = "COMPR8", .cpu_dai_name = "MultiMedia8", - .platform_name = "msm-compr-dsp", + .platform_name = "msm-compress-dsp", .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c index fd69611fa92277ebbc79104739623b51a20347ab..4cfd7c33120a31368d23b946aa4c83642b32564a 100644 --- a/sound/soc/msm/msm8974.c +++ b/sound/soc/msm/msm8974.c @@ -2164,7 +2164,7 @@ static struct snd_soc_dai_link msm8974_common_dai_links[] = { .name = "MSM8974 Compr8", .stream_name = "COMPR8", .cpu_dai_name = "MultiMedia8", - .platform_name = "msm-compr-dsp", + .platform_name = "msm-compress-dsp", .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, diff --git a/sound/soc/msm/msm8994.c b/sound/soc/msm/msm8994.c index d3dac1b94e26896ba8dd572ec58922eaa2071b58..d69174e99bdc166c73007c37c007071f8cc7f37b 100644 --- a/sound/soc/msm/msm8994.c +++ b/sound/soc/msm/msm8994.c @@ -3252,7 +3252,7 @@ static struct snd_soc_dai_link msm8994_common_dai_links[] = { .name = "MSM8994 Compr8", .stream_name = "COMPR8", .cpu_dai_name = "MultiMedia8", - .platform_name = "msm-compr-dsp", + .platform_name = "msm-compress-dsp", .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile index 5865eb9d94fdd3572d8720b18ecca197e034635f..41f398456c5ea39c5f658893ed24fcad70ff8900 100644 --- a/sound/soc/msm/qdsp6v2/Makefile +++ b/sound/soc/msm/qdsp6v2/Makefile @@ -1,5 +1,5 @@ snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \ - msm-compress-q6-v2.o msm-compr-q6-v2.o \ + msm-compress-q6-v2.o \ msm-pcm-lpa-v2.o \ msm-pcm-afe-v2.o msm-pcm-voip-v2.o \ msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \ diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c deleted file mode 100644 index 5fe5f24f4187ebf8709551b374888276fae7fb3b..0000000000000000000000000000000000000000 --- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c +++ /dev/null @@ -1,1707 +0,0 @@ -/* Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - - -#include <linux/init.h> -#include <linux/err.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/time.h> -#include <linux/wait.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <sound/core.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/pcm.h> -#include <sound/initval.h> -#include <sound/control.h> -#include <sound/q6asm-v2.h> -#include <sound/pcm_params.h> -#include <asm/dma.h> -#include <linux/dma-mapping.h> -#include <linux/msm_audio_ion.h> - -#include <sound/timer.h> - -#include "msm-compr-q6-v2.h" -#include "msm-pcm-routing-v2.h" -#include "audio_ocmem.h" -#include <sound/tlv.h> - -#define COMPRE_CAPTURE_NUM_PERIODS 16 -/* Allocate the worst case frame size for compressed audio */ -#define COMPRE_CAPTURE_HEADER_SIZE (sizeof(struct snd_compr_audio_info)) -/* Changing period size to 4032. 4032 will make sure COMPRE_CAPTURE_PERIOD_SIZE - * is 4096 with meta data size of 64 and MAX_NUM_FRAMES_PER_BUFFER 1 - */ -#define COMPRE_CAPTURE_MAX_FRAME_SIZE (4032) -#define COMPRE_CAPTURE_PERIOD_SIZE ((COMPRE_CAPTURE_MAX_FRAME_SIZE + \ - COMPRE_CAPTURE_HEADER_SIZE) * \ - MAX_NUM_FRAMES_PER_BUFFER) -#define COMPRE_OUTPUT_METADATA_SIZE (sizeof(struct output_meta_data_st)) -#define COMPRESSED_LR_VOL_MAX_STEPS 0x20002000 - -#define MAX_AC3_PARAM_SIZE (18*2*sizeof(int)) -#define AMR_WB_BAND_MODE 8 -#define AMR_WB_DTX_MODE 0 - - -const DECLARE_TLV_DB_LINEAR(compr_rx_vol_gain, 0, - COMPRESSED_LR_VOL_MAX_STEPS); -struct snd_msm { - atomic_t audio_ocmem_req; -}; -static struct snd_msm compressed_audio; - -static struct audio_locks the_locks; - -static struct snd_pcm_hardware msm_compr_hardware_capture = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_8000_48000, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 8, - .buffer_bytes_max = - COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS , - .period_bytes_min = COMPRE_CAPTURE_PERIOD_SIZE, - .period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE, - .periods_min = COMPRE_CAPTURE_NUM_PERIODS, - .periods_max = COMPRE_CAPTURE_NUM_PERIODS, - .fifo_size = 0, -}; - -static struct snd_pcm_hardware msm_compr_hardware_playback = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 8, - .buffer_bytes_max = 1024 * 1024, - .period_bytes_min = 128 * 1024, - .period_bytes_max = 256 * 1024, - .periods_min = 4, - .periods_max = 8, - .fifo_size = 0, -}; - -/* Conventional and unconventional sample rate supported */ -static unsigned int supported_sample_rates[] = { - 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 -}; - -/* Add supported codecs for compress capture path */ -static uint32_t supported_compr_capture_codecs[] = { - SND_AUDIOCODEC_AMRWB -}; - -static struct snd_pcm_hw_constraint_list constraints_sample_rates = { - .count = ARRAY_SIZE(supported_sample_rates), - .list = supported_sample_rates, - .mask = 0, -}; - -static bool msm_compr_capture_codecs(uint32_t req_codec) -{ - int i; - pr_debug("%s req_codec:%d\n", __func__, req_codec); - if (req_codec == 0) - return false; - for (i = 0; i < ARRAY_SIZE(supported_compr_capture_codecs); i++) { - if (req_codec == supported_compr_capture_codecs[i]) - return true; - } - return false; -} - -static void compr_event_handler(uint32_t opcode, - uint32_t token, uint32_t *payload, void *priv) -{ - struct compr_audio *compr = priv; - struct msm_audio *prtd = &compr->prtd; - struct snd_pcm_substream *substream = prtd->substream; - struct snd_pcm_runtime *runtime = substream->runtime; - struct audio_aio_write_param param; - struct audio_aio_read_param read_param; - struct audio_buffer *buf = NULL; - phys_addr_t temp; - struct output_meta_data_st output_meta_data; - uint32_t *ptrmem = (uint32_t *)payload; - int i = 0; - int time_stamp_flag = 0; - int buffer_length = 0; - int stop_playback = 0; - - pr_debug("%s opcode =%08x\n", __func__, opcode); - switch (opcode) { - case ASM_DATA_EVENT_WRITE_DONE_V2: { - uint32_t *ptrmem = (uint32_t *)¶m; - pr_debug("ASM_DATA_EVENT_WRITE_DONE\n"); - pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem); - prtd->pcm_irq_pos += prtd->pcm_count; - if (atomic_read(&prtd->start)) - snd_pcm_period_elapsed(substream); - else - if (substream->timer_running) - snd_timer_interrupt(substream->timer, 1); - atomic_inc(&prtd->out_count); - wake_up(&the_locks.write_wait); - if (!atomic_read(&prtd->start)) { - atomic_set(&prtd->pending_buffer, 1); - break; - } else - atomic_set(&prtd->pending_buffer, 0); - - /* - * check for underrun - */ - snd_pcm_stream_lock_irq(substream); - if (runtime->status->hw_ptr >= runtime->control->appl_ptr) { - runtime->render_flag |= SNDRV_RENDER_STOPPED; - stop_playback = 1; - } - snd_pcm_stream_unlock_irq(substream); - - if (stop_playback) { - pr_err("underrun! render stopped\n"); - break; - } - - buf = prtd->audio_client->port[IN].buf; - pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n", - __func__, prtd->pcm_count, prtd->out_head); - temp = buf[0].phys + (prtd->out_head * prtd->pcm_count); - pr_debug("%s:writing buffer[%d] from 0x%pa\n", - __func__, prtd->out_head, &temp); - - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - time_stamp_flag = SET_TIMESTAMP; - else - time_stamp_flag = NO_TIMESTAMP; - memcpy(&output_meta_data, (char *)(buf->data + - prtd->out_head * prtd->pcm_count), - COMPRE_OUTPUT_METADATA_SIZE); - - buffer_length = output_meta_data.frame_size; - pr_debug("meta_data_length: %d, frame_length: %d\n", - output_meta_data.meta_data_length, - output_meta_data.frame_size); - pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n", - output_meta_data.timestamp_msw, - output_meta_data.timestamp_lsw); - if (buffer_length == 0) { - pr_debug("Recieved a zero length buffer-break out"); - break; - } - param.paddr = temp + output_meta_data.meta_data_length; - param.len = buffer_length; - param.msw_ts = output_meta_data.timestamp_msw; - param.lsw_ts = output_meta_data.timestamp_lsw; - param.flags = time_stamp_flag; - param.uid = prtd->session_id; - for (i = 0; i < sizeof(struct audio_aio_write_param)/4; - i++, ++ptrmem) - pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem); - if (q6asm_async_write(prtd->audio_client, - ¶m) < 0) - pr_err("%s:q6asm_async_write failed\n", - __func__); - else - prtd->out_head = - (prtd->out_head + 1) & (runtime->periods - 1); - break; - } - case ASM_DATA_EVENT_RENDERED_EOS: - pr_debug("ASM_DATA_CMDRSP_EOS\n"); - if (atomic_read(&prtd->eos)) { - pr_debug("ASM_DATA_CMDRSP_EOS wake up\n"); - prtd->cmd_ack = 1; - wake_up(&the_locks.eos_wait); - atomic_set(&prtd->eos, 0); - } - break; - case ASM_DATA_EVENT_READ_DONE_V2: { - pr_debug("ASM_DATA_EVENT_READ_DONE\n"); - pr_debug("buf = %pK, data = 0x%X, *data = %pK,\n" - "prtd->pcm_irq_pos = %d\n", - prtd->audio_client->port[OUT].buf, - *(uint32_t *)prtd->audio_client->port[OUT].buf->data, - prtd->audio_client->port[OUT].buf->data, - prtd->pcm_irq_pos); - - memcpy(prtd->audio_client->port[OUT].buf->data + - prtd->pcm_irq_pos, (ptrmem + READDONE_IDX_SIZE), - COMPRE_CAPTURE_HEADER_SIZE); - pr_debug("buf = %pK, updated data = 0x%X, *data = %pK\n", - prtd->audio_client->port[OUT].buf, - *(uint32_t *)(prtd->audio_client->port[OUT].buf->data + - prtd->pcm_irq_pos), - prtd->audio_client->port[OUT].buf->data); - if (!atomic_read(&prtd->start)) - break; - pr_debug("frame size=%d, buffer = 0x%X\n", - ptrmem[READDONE_IDX_SIZE], - ptrmem[READDONE_IDX_BUFADD_LSW]); - if (ptrmem[READDONE_IDX_SIZE] > COMPRE_CAPTURE_MAX_FRAME_SIZE) { - pr_err("Frame length exceeded the max length"); - break; - } - buf = prtd->audio_client->port[OUT].buf; - - pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%pa\n", - prtd->pcm_irq_pos, &buf[0].phys); - read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE; - read_param.paddr = buf[0].phys + - prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE; - prtd->pcm_irq_pos += prtd->pcm_count; - - if (atomic_read(&prtd->start)) - snd_pcm_period_elapsed(substream); - - q6asm_async_read(prtd->audio_client, &read_param); - break; - } - case APR_BASIC_RSP_RESULT: { - switch (payload[0]) { - case ASM_SESSION_CMD_RUN_V2: { - if (substream->stream - != SNDRV_PCM_STREAM_PLAYBACK) { - atomic_set(&prtd->start, 1); - break; - } - if (!atomic_read(&prtd->pending_buffer)) - break; - pr_debug("%s: writing %d bytes of buffer[%d] to dsp\n", - __func__, prtd->pcm_count, prtd->out_head); - buf = prtd->audio_client->port[IN].buf; - pr_debug("%s: writing buffer[%d] from 0x%pa head %d count %d\n", - __func__, prtd->out_head, &buf[0].phys, - prtd->pcm_count, prtd->out_head); - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - time_stamp_flag = SET_TIMESTAMP; - else - time_stamp_flag = NO_TIMESTAMP; - memcpy(&output_meta_data, (char *)(buf->data + - prtd->out_head * prtd->pcm_count), - COMPRE_OUTPUT_METADATA_SIZE); - buffer_length = output_meta_data.frame_size; - pr_debug("meta_data_length: %d, frame_length: %d\n", - output_meta_data.meta_data_length, - output_meta_data.frame_size); - pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n", - output_meta_data.timestamp_msw, - output_meta_data.timestamp_lsw); - param.paddr = buf[prtd->out_head].phys - + output_meta_data.meta_data_length; - param.len = buffer_length; - param.msw_ts = output_meta_data.timestamp_msw; - param.lsw_ts = output_meta_data.timestamp_lsw; - param.flags = time_stamp_flag; - param.uid = prtd->session_id; - param.metadata_len = COMPRE_OUTPUT_METADATA_SIZE; - if (q6asm_async_write(prtd->audio_client, - ¶m) < 0) - pr_err("%s:q6asm_async_write failed\n", - __func__); - else - prtd->out_head = - (prtd->out_head + 1) - & (runtime->periods - 1); - atomic_set(&prtd->pending_buffer, 0); - } - break; - case ASM_STREAM_CMD_FLUSH: - pr_debug("ASM_STREAM_CMD_FLUSH\n"); - prtd->cmd_ack = 1; - wake_up(&the_locks.flush_wait); - break; - default: - break; - } - break; - } - default: - pr_debug("Not Supported Event opcode[0x%x]\n", opcode); - break; - } -} - -static int msm_compr_send_ddp_cfg(struct audio_client *ac, - struct snd_dec_ddp *ddp) -{ - int i, rc; - pr_debug("%s\n", __func__); - for (i = 0; i < ddp->params_length/2; i++) { - rc = q6asm_ds1_set_endp_params(ac, ddp->params_id[i], - ddp->params_value[i]); - if (rc) { - pr_err("sending params_id: %d failed\n", - ddp->params_id[i]); - return rc; - } - } - return 0; -} - -static int msm_compr_playback_prepare(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct msm_audio *prtd = &compr->prtd; - struct snd_pcm_hw_params *params; - struct asm_aac_cfg aac_cfg; - uint16_t bits_per_sample = 16; - int ret; - - struct asm_softpause_params softpause = { - .enable = SOFT_PAUSE_ENABLE, - .period = SOFT_PAUSE_PERIOD, - .step = SOFT_PAUSE_STEP, - .rampingcurve = SOFT_PAUSE_CURVE_LINEAR, - }; - struct asm_softvolume_params softvol = { - .period = SOFT_VOLUME_PERIOD, - .step = SOFT_VOLUME_STEP, - .rampingcurve = SOFT_VOLUME_CURVE_LINEAR, - }; - - pr_debug("%s\n", __func__); - - params = &soc_prtd->dpcm[substream->stream].hw_params; - if (runtime->format == SNDRV_PCM_FORMAT_S24_LE) - bits_per_sample = 24; - - ret = q6asm_open_write_v2(prtd->audio_client, - compr->codec, bits_per_sample); - if (ret < 0) { - pr_err("%s: Session out open failed\n", - __func__); - return -ENOMEM; - } - msm_pcm_routing_reg_phy_stream( - soc_prtd->dai_link->be_id, - prtd->audio_client->perf_mode, - prtd->session_id, - substream->stream); - /* - * the number of channels are required to call volume api - * accoridngly. So, get channels from hw params - */ - if ((params_channels(params) > 0) && - (params_periods(params) <= runtime->hw.channels_max)) - prtd->channel_mode = params_channels(params); - - ret = q6asm_set_softpause(prtd->audio_client, &softpause); - if (ret < 0) - pr_err("%s: Send SoftPause Param failed ret=%d\n", - __func__, ret); - ret = q6asm_set_softvolume(prtd->audio_client, &softvol); - if (ret < 0) - pr_err("%s: Send SoftVolume Param failed ret=%d\n", - __func__, ret); - - ret = q6asm_set_io_mode(prtd->audio_client, - (COMPRESSED_IO | ASYNC_IO_MODE)); - if (ret < 0) { - pr_err("%s: Set IO mode failed\n", __func__); - return -ENOMEM; - } - - prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream); - prtd->pcm_count = snd_pcm_lib_period_bytes(substream); - prtd->pcm_irq_pos = 0; - /* rate and channels are sent to audio driver */ - prtd->samp_rate = runtime->rate; - prtd->channel_mode = runtime->channels; - prtd->out_head = 0; - atomic_set(&prtd->out_count, runtime->periods); - - if (prtd->enabled) - return 0; - - switch (compr->info.codec_param.codec.id) { - case SND_AUDIOCODEC_MP3: - /* No media format block for mp3 */ - break; - case SND_AUDIOCODEC_AAC: - pr_debug("%s: SND_AUDIOCODEC_AAC\n", __func__); - memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg)); - aac_cfg.aot = AAC_ENC_MODE_EAAC_P; - aac_cfg.format = 0x03; - aac_cfg.ch_cfg = runtime->channels; - aac_cfg.sample_rate = runtime->rate; - ret = q6asm_media_format_block_aac(prtd->audio_client, - &aac_cfg); - if (ret < 0) - pr_err("%s: CMD Format block failed\n", __func__); - break; - case SND_AUDIOCODEC_AC3: { - struct snd_dec_ddp *ddp = - &compr->info.codec_param.codec.options.ddp; - pr_debug("%s: SND_AUDIOCODEC_AC3\n", __func__); - ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp); - if (ret < 0) - pr_err("%s: DDP CMD CFG failed\n", __func__); - break; - } - case SND_AUDIOCODEC_EAC3: { - struct snd_dec_ddp *ddp = - &compr->info.codec_param.codec.options.ddp; - pr_debug("%s: SND_AUDIOCODEC_EAC3\n", __func__); - ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp); - if (ret < 0) - pr_err("%s: DDP CMD CFG failed\n", __func__); - break; - } - default: - return -EINVAL; - } - - prtd->enabled = 1; - prtd->cmd_ack = 0; - prtd->cmd_interrupt = 0; - - return 0; -} - -static int msm_compr_capture_prepare(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - struct audio_buffer *buf = prtd->audio_client->port[OUT].buf; - struct snd_codec *codec = &compr->info.codec_param.codec; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct audio_aio_read_param read_param; - uint16_t bits_per_sample = 16; - int ret = 0; - int i; - - prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream); - prtd->pcm_count = snd_pcm_lib_period_bytes(substream); - prtd->pcm_irq_pos = 0; - - if (runtime->format == SNDRV_PCM_FORMAT_S24_LE) - bits_per_sample = 24; - - if (!msm_compr_capture_codecs( - compr->info.codec_param.codec.id)) { - /* - * request codec invalid or not supported, - * use default compress format - */ - compr->info.codec_param.codec.id = - SND_AUDIOCODEC_AMRWB; - } - switch (compr->info.codec_param.codec.id) { - case SND_AUDIOCODEC_AMRWB: - pr_debug("q6asm_open_read(FORMAT_AMRWB)\n"); - ret = q6asm_open_read(prtd->audio_client, - FORMAT_AMRWB); - if (ret < 0) { - pr_err("%s: compressed Session out open failed\n", - __func__); - return -ENOMEM; - } - pr_debug("msm_pcm_routing_reg_phy_stream\n"); - msm_pcm_routing_reg_phy_stream( - soc_prtd->dai_link->be_id, - prtd->audio_client->perf_mode, - prtd->session_id, substream->stream); - break; - default: - pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n"); - /* - ret = q6asm_open_read_compressed(prtd->audio_client, - MAX_NUM_FRAMES_PER_BUFFER, - COMPRESSED_META_DATA_MODE); - */ - ret = -EINVAL; - break; - } - - if (ret < 0) { - pr_err("%s: compressed Session out open failed\n", - __func__); - return -ENOMEM; - } - - ret = q6asm_set_io_mode(prtd->audio_client, - (COMPRESSED_IO | ASYNC_IO_MODE)); - if (ret < 0) { - pr_err("%s: Set IO mode failed\n", __func__); - return -ENOMEM; - } - - if (!msm_compr_capture_codecs(codec->id)) { - /* - * request codec invalid or not supported, - * use default compress format - */ - codec->id = SND_AUDIOCODEC_AMRWB; - } - /* rate and channels are sent to audio driver */ - prtd->samp_rate = runtime->rate; - prtd->channel_mode = runtime->channels; - - if (prtd->enabled) - return ret; - read_param.len = prtd->pcm_count; - - switch (codec->id) { - case SND_AUDIOCODEC_AMRWB: - pr_debug("SND_AUDIOCODEC_AMRWB\n"); - ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client, - MAX_NUM_FRAMES_PER_BUFFER, - /* - * use fixed band mode and dtx mode - * band mode - 23.85 kbps - */ - AMR_WB_BAND_MODE, - /* dtx mode - disable */ - AMR_WB_DTX_MODE); - if (ret < 0) - pr_err("%s: CMD Format block failed: %d\n", - __func__, ret); - break; - default: - pr_debug("No config for codec %d\n", codec->id); - } - pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n" - "pcm_count = %d, periods = %d\n", - __func__, prtd->samp_rate, prtd->channel_mode, - prtd->pcm_size, prtd->pcm_count, runtime->periods); - - for (i = 0; i < runtime->periods; i++) { - read_param.uid = i; - switch (codec->id) { - case SND_AUDIOCODEC_AMRWB: - read_param.len = prtd->pcm_count - - COMPRE_CAPTURE_HEADER_SIZE; - read_param.paddr = buf[i].phys - + COMPRE_CAPTURE_HEADER_SIZE; - pr_debug("Push buffer [%d] to DSP, paddr: %pa, vaddr: %pK\n", - i, &read_param.paddr, - buf[i].data); - q6asm_async_read(prtd->audio_client, &read_param); - break; - default: - read_param.paddr = buf[i].phys; - /*q6asm_async_read_compressed(prtd->audio_client, - &read_param);*/ - pr_debug("%s: To add support for read compressed\n", - __func__); - ret = -EINVAL; - break; - } - } - prtd->periods = runtime->periods; - - prtd->enabled = 1; - - return ret; -} - -static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd) -{ - int ret = 0; - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - - pr_debug("%s\n", __func__); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->pcm_irq_pos = 0; - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - if (!msm_compr_capture_codecs( - compr->info.codec_param.codec.id)) { - /* - * request codec invalid or not supported, - * use default compress format - */ - compr->info.codec_param.codec.id = - SND_AUDIOCODEC_AMRWB; - } - switch (compr->info.codec_param.codec.id) { - case SND_AUDIOCODEC_AMRWB: - break; - default: - msm_pcm_routing_reg_psthr_stream( - soc_prtd->dai_link->be_id, - prtd->session_id, substream->stream); - break; - } - } - atomic_set(&prtd->pending_buffer, 1); - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - pr_debug("%s: Trigger start\n", __func__); - q6asm_run_nowait(prtd->audio_client, 0, 0, 0); - atomic_set(&prtd->start, 1); - break; - case SNDRV_PCM_TRIGGER_STOP: - pr_debug("SNDRV_PCM_TRIGGER_STOP\n"); - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - switch (compr->info.codec_param.codec.id) { - case SND_AUDIOCODEC_AMRWB: - break; - default: - msm_pcm_routing_reg_psthr_stream( - soc_prtd->dai_link->be_id, - prtd->session_id, substream->stream); - break; - } - } - atomic_set(&prtd->start, 0); - runtime->render_flag &= ~SNDRV_RENDER_STOPPED; - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n"); - q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE); - atomic_set(&prtd->start, 0); - runtime->render_flag &= ~SNDRV_RENDER_STOPPED; - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static void populate_codec_list(struct compr_audio *compr, - struct snd_pcm_runtime *runtime) -{ - pr_debug("%s\n", __func__); - /* MP3 Block */ - compr->info.compr_cap.num_codecs = 5; - compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min; - compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max; - compr->info.compr_cap.min_fragments = runtime->hw.periods_min; - compr->info.compr_cap.max_fragments = runtime->hw.periods_max; - compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3; - compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC; - compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3; - compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3; - compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_AMRWB; - /* Add new codecs here */ -} - -static int msm_compr_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr; - struct msm_audio *prtd; - int ret = 0; - - pr_debug("%s\n", __func__); - compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL); - if (compr == NULL) { - pr_err("Failed to allocate memory for msm_audio\n"); - return -ENOMEM; - } - prtd = &compr->prtd; - prtd->substream = substream; - runtime->render_flag = SNDRV_DMA_MODE; - prtd->audio_client = q6asm_audio_client_alloc( - (app_cb)compr_event_handler, compr); - if (!prtd->audio_client) { - pr_info("%s: Could not allocate memory\n", __func__); - kfree(prtd); - return -ENOMEM; - } - - prtd->audio_client->perf_mode = false; - pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session); - - prtd->session_id = prtd->audio_client->session; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - runtime->hw = msm_compr_hardware_playback; - prtd->cmd_ack = 1; - } else { - runtime->hw = msm_compr_hardware_capture; - } - - - ret = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_sample_rates); - if (ret < 0) - pr_info("snd_pcm_hw_constraint_list failed\n"); - /* Ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - pr_info("snd_pcm_hw_constraint_integer failed\n"); - - prtd->dsp_cnt = 0; - atomic_set(&prtd->pending_buffer, 1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - compr->codec = FORMAT_MP3; - populate_codec_list(compr, runtime); - runtime->private_data = compr; - atomic_set(&prtd->eos, 0); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (!atomic_cmpxchg(&compressed_audio.audio_ocmem_req, 0, 1)) - audio_ocmem_process_req(AUDIO, true); - else - atomic_inc(&compressed_audio.audio_ocmem_req); - pr_debug("%s: req: %d\n", __func__, - atomic_read(&compressed_audio.audio_ocmem_req)); - } - return 0; -} - -static int compressed_set_volume(struct msm_audio *prtd, uint32_t volume) -{ - int rc = 0; - int avg_vol = 0; - int lgain = (volume >> 16) & 0xFFFF; - int rgain = volume & 0xFFFF; - if (prtd && prtd->audio_client) { - pr_debug("%s: channels %d volume 0x%x\n", __func__, - prtd->channel_mode, volume); - if ((prtd->channel_mode == 2) && - (lgain != rgain)) { - pr_debug("%s: call q6asm_set_lrgain\n", __func__); - rc = q6asm_set_lrgain(prtd->audio_client, lgain, rgain); - } else { - avg_vol = (lgain + rgain)/2; - pr_debug("%s: call q6asm_set_volume\n", __func__); - rc = q6asm_set_volume(prtd->audio_client, avg_vol); - } - if (rc < 0) { - pr_err("%s: Send Volume command failed rc=%d\n", - __func__, rc); - } - } - return rc; -} - -static int msm_compr_playback_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - int dir = 0; - - pr_debug("%s\n", __func__); - - dir = IN; - atomic_set(&prtd->pending_buffer, 0); - - if (atomic_read(&compressed_audio.audio_ocmem_req) > 1) - atomic_dec(&compressed_audio.audio_ocmem_req); - else if (atomic_cmpxchg(&compressed_audio.audio_ocmem_req, 1, 0)) - audio_ocmem_process_req(AUDIO, false); - - pr_debug("%s: req: %d\n", __func__, - atomic_read(&compressed_audio.audio_ocmem_req)); - prtd->pcm_irq_pos = 0; - q6asm_cmd(prtd->audio_client, CMD_CLOSE); - q6asm_audio_client_buf_free_contiguous(dir, - prtd->audio_client); - msm_pcm_routing_dereg_phy_stream( - soc_prtd->dai_link->be_id, - SNDRV_PCM_STREAM_PLAYBACK); - q6asm_audio_client_free(prtd->audio_client); - kfree(prtd); - return 0; -} - -static int msm_compr_capture_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - int dir = OUT; - - pr_debug("%s\n", __func__); - atomic_set(&prtd->pending_buffer, 0); - q6asm_cmd(prtd->audio_client, CMD_CLOSE); - q6asm_audio_client_buf_free_contiguous(dir, - prtd->audio_client); - msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, - SNDRV_PCM_STREAM_CAPTURE); - q6asm_audio_client_free(prtd->audio_client); - kfree(prtd); - return 0; -} - -static int msm_compr_close(struct snd_pcm_substream *substream) -{ - int ret = 0; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ret = msm_compr_playback_close(substream); - else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - ret = msm_compr_capture_close(substream); - return ret; -} - -static int msm_compr_prepare(struct snd_pcm_substream *substream) -{ - int ret = 0; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ret = msm_compr_playback_prepare(substream); - else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - ret = msm_compr_capture_prepare(substream); - return ret; -} - -static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream) -{ - - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - - if (prtd->pcm_irq_pos >= prtd->pcm_size) - prtd->pcm_irq_pos = 0; - - pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n" - "frame_bits = %d\n", __func__, prtd->pcm_irq_pos, - prtd->pcm_size, runtime->sample_bits, - runtime->frame_bits); - return bytes_to_frames(runtime, (prtd->pcm_irq_pos)); -} - -static int msm_compr_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct msm_audio *prtd = runtime->private_data; - struct audio_client *ac = prtd->audio_client; - struct audio_port_data *apd = ac->port; - struct audio_buffer *ab; - int dir = -1; - - prtd->mmap_flag = 1; - runtime->render_flag = SNDRV_NON_DMA_MODE; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir = IN; - else - dir = OUT; - ab = &(apd[dir].buf[0]); - - return msm_audio_ion_mmap(ab, vma); -} - -static int msm_compr_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - struct snd_dma_buffer *dma_buf = &substream->dma_buffer; - struct audio_buffer *buf; - int dir, ret; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir = IN; - else - dir = OUT; - /* Modifying kernel hardware params based on userspace config */ - if (params_periods(params) > 0 && - (params_periods(params) != runtime->hw.periods_max)) { - runtime->hw.periods_max = params_periods(params); - } - if (params_period_bytes(params) > 0 && - (params_period_bytes(params) != runtime->hw.period_bytes_min)) { - runtime->hw.period_bytes_min = params_period_bytes(params); - } - runtime->hw.buffer_bytes_max = - runtime->hw.period_bytes_min * runtime->hw.periods_max; - pr_debug("allocate %zd buffers each of size %d\n", - runtime->hw.period_bytes_min, - runtime->hw.periods_max); - ret = q6asm_audio_client_buf_alloc_contiguous(dir, - prtd->audio_client, - runtime->hw.period_bytes_min, - runtime->hw.periods_max); - if (ret < 0) { - pr_err("Audio Start: Buffer Allocation failed rc = %d\n", - ret); - return -ENOMEM; - } - buf = prtd->audio_client->port[dir].buf; - - dma_buf->dev.type = SNDRV_DMA_TYPE_DEV; - dma_buf->dev.dev = substream->pcm->card->dev; - dma_buf->private_data = NULL; - dma_buf->area = buf[0].data; - dma_buf->addr = buf[0].phys; - dma_buf->bytes = runtime->hw.buffer_bytes_max; - - pr_debug("%s: buf[%pK]dma_buf->area[%pK]dma_buf->addr[%pa]\n" - "dma_buf->bytes[%zd]\n", __func__, - (void *)buf, (void *)dma_buf->area, - &dma_buf->addr, dma_buf->bytes); - if (!dma_buf->area) - return -ENOMEM; - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - return 0; -} - -static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - int rc = 0; - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - uint64_t timestamp; - uint64_t temp; - - switch (cmd) { - case SNDRV_COMPRESS_TSTAMP: { - struct snd_compr_tstamp *tstamp; - pr_debug("SNDRV_COMPRESS_TSTAMP\n"); - tstamp = arg; - memset(tstamp, 0x0, sizeof(*tstamp)); - rc = q6asm_get_session_time(prtd->audio_client, ×tamp); - if (rc < 0) { - pr_err("%s: Get Session Time return value =%lld\n", - __func__, timestamp); - return -EAGAIN; - } - temp = (timestamp * 2 * runtime->channels); - temp = temp * (runtime->rate/1000); - temp = div_u64(temp, 1000); - tstamp->sampling_rate = runtime->rate; - tstamp->timestamp = timestamp; - pr_debug("%s: bytes_consumed:,timestamp = %lld,\n", - __func__, - tstamp->timestamp); - return 0; - } - case SNDRV_COMPRESS_GET_CAPS: { - struct snd_compr_caps *caps; - caps = arg; - memset(caps, 0, sizeof(*caps)); - pr_debug("SNDRV_COMPRESS_GET_CAPS\n"); - memcpy(caps, &compr->info.compr_cap, sizeof(*caps)); - return 0; - } - case SNDRV_COMPRESS_SET_PARAMS: - pr_debug("SNDRV_COMPRESS_SET_PARAMS:\n"); - memcpy(&compr->info.codec_param, (void *) arg, - sizeof(struct snd_compr_params)); - switch (compr->info.codec_param.codec.id) { - case SND_AUDIOCODEC_MP3: - /* For MP3 we dont need any other parameter */ - pr_debug("SND_AUDIOCODEC_MP3\n"); - compr->codec = FORMAT_MP3; - break; - case SND_AUDIOCODEC_AAC: - pr_debug("SND_AUDIOCODEC_AAC\n"); - compr->codec = FORMAT_MPEG4_AAC; - break; - case SND_AUDIOCODEC_AC3: { - char params_value[MAX_AC3_PARAM_SIZE]; - int *params_value_data = (int *)params_value; - /* 36 is the max param length for ddp */ - int i; - struct snd_dec_ddp *ddp = - &compr->info.codec_param.codec.options.ddp; - uint32_t params_length = 0; - memset(params_value, 0, MAX_AC3_PARAM_SIZE); - /* check integer overflow */ - if (ddp->params_length > UINT_MAX/sizeof(int)) { - pr_err("%s: Integer overflow ddp->params_length %d\n", - __func__, ddp->params_length); - return -EINVAL; - } - params_length = ddp->params_length*sizeof(int); - if (params_length > MAX_AC3_PARAM_SIZE) { - /*MAX is 36*sizeof(int) this should not happen*/ - pr_err("%s: params_length(%d) is greater than %zd\n", - __func__, params_length, MAX_AC3_PARAM_SIZE); - return -EINVAL; - } - pr_debug("SND_AUDIOCODEC_AC3\n"); - compr->codec = FORMAT_AC3; - pr_debug("params_length: %d\n", ddp->params_length); - for (i = 0; i < params_length/sizeof(int); i++) - pr_debug("params_value[%d]: %x\n", i, - params_value_data[i]); - for (i = 0; i < ddp->params_length/2; i++) { - ddp->params_id[i] = params_value_data[2*i]; - ddp->params_value[i] = params_value_data[2*i+1]; - } - if (atomic_read(&prtd->start)) { - rc = msm_compr_send_ddp_cfg(prtd->audio_client, - ddp); - if (rc < 0) - pr_err("%s: DDP CMD CFG failed\n", - __func__); - } - break; - } - case SND_AUDIOCODEC_EAC3: { - char params_value[MAX_AC3_PARAM_SIZE]; - int *params_value_data = (int *)params_value; - /* 36 is the max param length for ddp */ - int i; - struct snd_dec_ddp *ddp = - &compr->info.codec_param.codec.options.ddp; - uint32_t params_length = 0; - memset(params_value, 0, MAX_AC3_PARAM_SIZE); - /* check integer overflow */ - if (ddp->params_length > UINT_MAX/sizeof(int)) { - pr_err("%s: Integer overflow ddp->params_length %d\n", - __func__, ddp->params_length); - return -EINVAL; - } - params_length = ddp->params_length*sizeof(int); - if (params_length > MAX_AC3_PARAM_SIZE) { - /*MAX is 36*sizeof(int) this should not happen*/ - pr_err("%s: params_length(%d) is greater than %zd\n", - __func__, params_length, MAX_AC3_PARAM_SIZE); - return -EINVAL; - } - pr_debug("SND_AUDIOCODEC_EAC3\n"); - compr->codec = FORMAT_EAC3; - pr_debug("params_length: %d\n", ddp->params_length); - for (i = 0; i < ddp->params_length; i++) - pr_debug("params_value[%d]: %x\n", i, - params_value_data[i]); - for (i = 0; i < ddp->params_length/2; i++) { - ddp->params_id[i] = params_value_data[2*i]; - ddp->params_value[i] = params_value_data[2*i+1]; - } - if (atomic_read(&prtd->start)) { - rc = msm_compr_send_ddp_cfg(prtd->audio_client, - ddp); - if (rc < 0) - pr_err("%s: DDP CMD CFG failed\n", - __func__); - } - break; - } - default: - pr_debug("FORMAT_LINEAR_PCM\n"); - compr->codec = FORMAT_LINEAR_PCM; - break; - } - return 0; - case SNDRV_PCM_IOCTL1_RESET: - pr_debug("SNDRV_PCM_IOCTL1_RESET\n"); - /* Flush only when session is started during CAPTURE, - while PLAYBACK has no such restriction. */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || - (substream->stream == SNDRV_PCM_STREAM_CAPTURE && - atomic_read(&prtd->start))) { - if (atomic_read(&prtd->eos)) { - prtd->cmd_interrupt = 1; - wake_up(&the_locks.eos_wait); - atomic_set(&prtd->eos, 0); - } - - /* A unlikely race condition possible with FLUSH - DRAIN if ack is set by flush and reset by drain */ - prtd->cmd_ack = 0; - rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH); - if (rc < 0) { - pr_err("%s: flush cmd failed rc=%d\n", - __func__, rc); - return rc; - } - rc = wait_event_timeout(the_locks.flush_wait, - prtd->cmd_ack, 5 * HZ); - if (!rc) - pr_err("Flush cmd timeout\n"); - prtd->pcm_irq_pos = 0; - } - break; - case SNDRV_COMPRESS_DRAIN: - pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__); - if (atomic_read(&prtd->pending_buffer)) { - pr_debug("%s: no pending writes, drain would block\n", - __func__); - return -EWOULDBLOCK; - } - - atomic_set(&prtd->eos, 1); - atomic_set(&prtd->pending_buffer, 0); - prtd->cmd_ack = 0; - q6asm_cmd_nowait(prtd->audio_client, CMD_EOS); - /* Wait indefinitely for DRAIN. Flush can also signal this*/ - rc = wait_event_interruptible(the_locks.eos_wait, - (prtd->cmd_ack || prtd->cmd_interrupt)); - - if (rc < 0) - pr_err("EOS cmd interrupted\n"); - pr_debug("%s: SNDRV_COMPRESS_DRAIN out of wait\n", __func__); - - if (prtd->cmd_interrupt) - rc = -EINTR; - - prtd->cmd_interrupt = 0; - return rc; - default: - break; - } - return snd_pcm_lib_ioctl(substream, cmd, arg); -} -#ifdef CONFIG_COMPAT -struct snd_enc_wma32 { - u32 super_block_align; /* WMA Type-specific data */ - u32 encodeopt1; - u32 encodeopt2; -}; - -struct snd_enc_vorbis32 { - s32 quality; - u32 managed; - u32 max_bit_rate; - u32 min_bit_rate; - u32 downmix; -}; - -struct snd_enc_real32 { - u32 quant_bits; - u32 start_region; - u32 num_regions; -}; - -struct snd_enc_flac32 { - u32 num; - u32 gain; -}; - -struct snd_enc_generic32 { - u32 bw; /* encoder bandwidth */ - s32 reserved[15]; -}; -struct snd_dec_ddp32 { - u32 params_length; - u32 params_id[18]; - u32 params_value[18]; -}; - -union snd_codec_options32 { - struct snd_enc_wma32 wma; - struct snd_enc_vorbis32 vorbis; - struct snd_enc_real32 real; - struct snd_enc_flac32 flac; - struct snd_enc_generic32 generic; - struct snd_dec_ddp32 ddp; -}; - -struct snd_codec32 { - u32 id; - u32 ch_in; - u32 ch_out; - u32 sample_rate; - u32 bit_rate; - u32 rate_control; - u32 profile; - u32 level; - u32 ch_mode; - u32 format; - u32 align; - union snd_codec_options32 options; - u32 reserved[3]; -}; - -struct snd_compressed_buffer32 { - u32 fragment_size; - u32 fragments; -}; - -struct snd_compr_params32 { - struct snd_compressed_buffer32 buffer; - struct snd_codec32 codec; - u8 no_wake_mode; -}; - -struct snd_compr_caps32 { - u32 num_codecs; - u32 direction; - u32 min_fragment_size; - u32 max_fragment_size; - u32 min_fragments; - u32 max_fragments; - u32 codecs[MAX_NUM_CODECS]; - u32 reserved[11]; -}; -struct snd_compr_tstamp32 { - u32 byte_offset; - u32 copied_total; - compat_ulong_t pcm_frames; - compat_ulong_t pcm_io_frames; - u32 sampling_rate; - compat_u64 timestamp; -}; -enum { - SNDRV_COMPRESS_TSTAMP32 = _IOR('C', 0x20, struct snd_compr_tstamp32), - SNDRV_COMPRESS_GET_CAPS32 = _IOWR('C', 0x10, struct snd_compr_caps32), - SNDRV_COMPRESS_SET_PARAMS32 = - _IOW('C', 0x12, struct snd_compr_params32), -}; -static int msm_compr_compat_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - int err = 0; - switch (cmd) { - case SNDRV_COMPRESS_TSTAMP32: { - struct snd_compr_tstamp tstamp; - struct snd_compr_tstamp32 tstamp32; - memset(&tstamp, 0, sizeof(tstamp)); - memset(&tstamp32, 0, sizeof(tstamp32)); - cmd = SNDRV_COMPRESS_TSTAMP; - err = msm_compr_ioctl_shared(substream, cmd, &tstamp); - if (err) { - pr_err("%s: COMPRESS_TSTAMP failed rc %d\n", - __func__, err); - goto bail_out; - } - tstamp32.byte_offset = tstamp.byte_offset; - tstamp32.copied_total = tstamp.copied_total; - tstamp32.pcm_frames = tstamp.pcm_frames; - tstamp32.pcm_io_frames = tstamp.pcm_io_frames; - tstamp32.sampling_rate = tstamp.sampling_rate; - tstamp32.timestamp = tstamp.timestamp; - if (copy_to_user(arg, &tstamp32, sizeof(tstamp32))) { - pr_err("%s: copytouser failed COMPRESS_TSTAMP32\n", - __func__); - err = -EFAULT; - } - break; - } - case SNDRV_COMPRESS_GET_CAPS32: { - struct snd_compr_caps caps; - struct snd_compr_caps32 caps32; - u32 i; - memset(&caps, 0, sizeof(caps)); - memset(&caps32, 0, sizeof(caps32)); - cmd = SNDRV_COMPRESS_GET_CAPS; - err = msm_compr_ioctl_shared(substream, cmd, &caps); - if (err) { - pr_err("%s: GET_CAPS failed rc %d\n", - __func__, err); - goto bail_out; - } - pr_debug("SNDRV_COMPRESS_GET_CAPS_32\n"); - if (!err && caps.num_codecs >= MAX_NUM_CODECS) { - pr_err("%s: Invalid number of codecs\n", __func__); - err = -EINVAL; - goto bail_out; - } - caps32.direction = caps.direction; - caps32.max_fragment_size = caps.max_fragment_size; - caps32.max_fragments = caps.max_fragments; - caps32.min_fragment_size = caps.min_fragment_size; - caps32.num_codecs = caps.num_codecs; - for (i = 0; i < caps.num_codecs; i++) - caps32.codecs[i] = caps.codecs[i]; - if (copy_to_user(arg, &caps32, sizeof(caps32))) { - pr_err("%s: copytouser failed COMPRESS_GETCAPS32\n", - __func__); - err = -EFAULT; - } - break; - } - case SNDRV_COMPRESS_SET_PARAMS32: { - struct snd_compr_params32 params32; - struct snd_compr_params params; - memset(¶ms32, 0 , sizeof(params32)); - memset(¶ms, 0 , sizeof(params)); - cmd = SNDRV_COMPRESS_SET_PARAMS; - if (copy_from_user(¶ms32, arg, sizeof(params32))) { - pr_err("%s: copyfromuser failed SET_PARAMS32\n", - __func__); - err = -EFAULT; - goto bail_out; - } - params.no_wake_mode = params32.no_wake_mode; - params.codec.id = params32.codec.id; - params.codec.ch_in = params32.codec.ch_in; - params.codec.ch_out = params32.codec.ch_out; - params.codec.sample_rate = params32.codec.sample_rate; - params.codec.bit_rate = params32.codec.bit_rate; - params.codec.rate_control = params32.codec.rate_control; - params.codec.profile = params32.codec.profile; - params.codec.level = params32.codec.level; - params.codec.ch_mode = params32.codec.ch_mode; - params.codec.format = params32.codec.format; - params.codec.align = params32.codec.align; - - switch (params.codec.id) { - case SND_AUDIOCODEC_WMA: - case SND_AUDIOCODEC_WMA_PRO: - params.codec.options.wma.encodeopt1 = - params32.codec.options.wma.encodeopt1; - params.codec.options.wma.encodeopt2 = - params32.codec.options.wma.encodeopt2; - params.codec.options.wma.super_block_align = - params32.codec.options.wma.super_block_align; - break; - case SND_AUDIOCODEC_VORBIS: - params.codec.options.vorbis.downmix = - params32.codec.options.vorbis.downmix; - params.codec.options.vorbis.managed = - params32.codec.options.vorbis.managed; - params.codec.options.vorbis.max_bit_rate = - params32.codec.options.vorbis.max_bit_rate; - params.codec.options.vorbis.min_bit_rate = - params32.codec.options.vorbis.min_bit_rate; - params.codec.options.vorbis.quality = - params32.codec.options.vorbis.quality; - break; - case SND_AUDIOCODEC_REAL: - params.codec.options.real.num_regions = - params32.codec.options.real.num_regions; - params.codec.options.real.quant_bits = - params32.codec.options.real.quant_bits; - params.codec.options.real.start_region = - params32.codec.options.real.start_region; - break; - case SND_AUDIOCODEC_FLAC: - params.codec.options.flac.gain = - params32.codec.options.flac.gain; - params.codec.options.flac.num = - params32.codec.options.flac.num; - break; - case SND_AUDIOCODEC_DTS: - case SND_AUDIOCODEC_DTS_PASS_THROUGH: - case SND_AUDIOCODEC_DTS_LBR: - case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH: - case SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK: - break; - case SND_AUDIOCODEC_AC3: - case SND_AUDIOCODEC_EAC3: - params.codec.options.ddp.params_length = - params32.codec.options.ddp.params_length; - memcpy(params.codec.options.ddp.params_value, - params32.codec.options.ddp.params_value, - sizeof(params32.codec.options.ddp.params_value)); - memcpy(params.codec.options.ddp.params_id, - params32.codec.options.ddp.params_id, - sizeof(params32.codec.options.ddp.params_id)); - break; - default: - params.codec.options.generic.bw = - params32.codec.options.generic.bw; - break; - } - if (!err) - err = msm_compr_ioctl_shared(substream, cmd, ¶ms); - break; - } - default: - err = msm_compr_ioctl_shared(substream, cmd, arg); - } -bail_out: - return err; - -} -#endif -static int msm_compr_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - int err = 0; - if (!substream) { - pr_err("%s: Invalid params\n", __func__); - return -EINVAL; - } - pr_debug("%s called with cmd = %d\n", __func__, cmd); - switch (cmd) { - case SNDRV_COMPRESS_TSTAMP: { - struct snd_compr_tstamp tstamp; - if (!arg) { - pr_err("%s: Invalid params Tstamp\n", __func__); - return -EINVAL; - } - err = msm_compr_ioctl_shared(substream, cmd, &tstamp); - if (err) - pr_err("%s: COMPRESS_TSTAMP failed rc %d\n", - __func__, err); - if (!err && copy_to_user(arg, &tstamp, sizeof(tstamp))) { - pr_err("%s: copytouser failed COMPRESS_TSTAMP\n", - __func__); - err = -EFAULT; - } - break; - } - case SNDRV_COMPRESS_GET_CAPS: { - struct snd_compr_caps cap; - if (!arg) { - pr_err("%s: Invalid params getcaps\n", __func__); - return -EINVAL; - } - pr_debug("SNDRV_COMPRESS_GET_CAPS\n"); - err = msm_compr_ioctl_shared(substream, cmd, &cap); - if (err) - pr_err("%s: GET_CAPS failed rc %d\n", - __func__, err); - if (!err && copy_to_user(arg, &cap, sizeof(cap))) { - pr_err("%s: copytouser failed GET_CAPS\n", - __func__); - err = -EFAULT; - } - break; - } - case SNDRV_COMPRESS_SET_PARAMS: { - struct snd_compr_params params; - if (!arg) { - pr_err("%s: Invalid params setparam\n", __func__); - return -EINVAL; - } - if (copy_from_user(¶ms, arg, - sizeof(struct snd_compr_params))) { - pr_err("%s: SET_PARAMS\n", __func__); - return -EFAULT; - } - err = msm_compr_ioctl_shared(substream, cmd, ¶ms); - if (err) - pr_err("%s: SET_PARAMS failed rc %d\n", - __func__, err); - break; - } - default: - err = msm_compr_ioctl_shared(substream, cmd, arg); - } - return err; -} - -static int msm_compr_restart(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - struct audio_aio_write_param param; - struct audio_buffer *buf = NULL; - struct output_meta_data_st output_meta_data; - int time_stamp_flag = 0; - int buffer_length = 0; - - pr_debug("%s, trigger restart\n", __func__); - - if (runtime->render_flag & SNDRV_RENDER_STOPPED) { - buf = prtd->audio_client->port[IN].buf; - pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n", - __func__, prtd->pcm_count, prtd->out_head); - pr_debug("%s:writing buffer[%d] from 0x%08x\n", - __func__, prtd->out_head, - ((unsigned int)buf[0].phys - + (prtd->out_head * prtd->pcm_count))); - - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - time_stamp_flag = SET_TIMESTAMP; - else - time_stamp_flag = NO_TIMESTAMP; - memcpy(&output_meta_data, (char *)(buf->data + - prtd->out_head * prtd->pcm_count), - COMPRE_OUTPUT_METADATA_SIZE); - - buffer_length = output_meta_data.frame_size; - pr_debug("meta_data_length: %d, frame_length: %d\n", - output_meta_data.meta_data_length, - output_meta_data.frame_size); - pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n", - output_meta_data.timestamp_msw, - output_meta_data.timestamp_lsw); - - param.paddr = (unsigned long)buf[0].phys - + (prtd->out_head * prtd->pcm_count) - + output_meta_data.meta_data_length; - param.len = buffer_length; - param.msw_ts = output_meta_data.timestamp_msw; - param.lsw_ts = output_meta_data.timestamp_lsw; - param.flags = time_stamp_flag; - param.uid = prtd->session_id; - if (q6asm_async_write(prtd->audio_client, - ¶m) < 0) - pr_err("%s:q6asm_async_write failed\n", - __func__); - else - prtd->out_head = - (prtd->out_head + 1) & (runtime->periods - 1); - - runtime->render_flag &= ~SNDRV_RENDER_STOPPED; - return 0; - } - return 0; -} - -static int msm_compr_volume_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int rc = 0; - struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol); - struct snd_pcm_substream *substream = - vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - struct msm_audio *prtd; - int volume = ucontrol->value.integer.value[0]; - - pr_debug("%s: volume : %x\n", __func__, volume); - if (!substream) - return -ENODEV; - if (!substream->runtime) - return 0; - prtd = substream->runtime->private_data; - if (prtd) - rc = compressed_set_volume(prtd, volume); - - return rc; -} - -static int msm_compr_volume_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol); - struct snd_pcm_substream *substream = - vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - struct msm_audio *prtd; - - pr_debug("%s\n", __func__); - if (!substream) - return -ENODEV; - if (!substream->runtime) - return 0; - prtd = substream->runtime->private_data; - if (prtd) - ucontrol->value.integer.value[0] = prtd->volume; - return 0; -} - -static int msm_compr_add_controls(struct snd_soc_pcm_runtime *rtd) -{ - int ret = 0; - struct snd_pcm *pcm = rtd->pcm; - struct snd_pcm_volume *volume_info; - struct snd_kcontrol *kctl; - - dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__); - ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, - NULL, 1, rtd->dai_link->be_id, - &volume_info); - if (ret < 0) - return ret; - kctl = volume_info->kctl; - kctl->put = msm_compr_volume_ctl_put; - kctl->get = msm_compr_volume_ctl_get; - kctl->tlv.p = compr_rx_vol_gain; - return 0; -} - -static struct snd_pcm_ops msm_compr_ops = { - .open = msm_compr_open, - .hw_params = msm_compr_hw_params, - .close = msm_compr_close, - .ioctl = msm_compr_ioctl, - .prepare = msm_compr_prepare, - .trigger = msm_compr_trigger, - .pointer = msm_compr_pointer, - .mmap = msm_compr_mmap, - .restart = msm_compr_restart, -#ifdef CONFIG_COMPAT - .compat_ioctl = msm_compr_compat_ioctl, -#endif -}; - -static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_card *card = rtd->card->snd_card; - int ret = 0; - - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_BIT_MASK(32); - - ret = msm_compr_add_controls(rtd); - if (ret) - pr_err("%s, kctl add failed\n", __func__); - return ret; -} - -static struct snd_soc_platform_driver msm_soc_platform = { - .ops = &msm_compr_ops, - .pcm_new = msm_asoc_pcm_new, -}; - -static int msm_compr_probe(struct platform_device *pdev) -{ - - dev_info(&pdev->dev, "%s: dev name %s\n", - __func__, dev_name(&pdev->dev)); - - atomic_set(&compressed_audio.audio_ocmem_req, 0); - return snd_soc_register_platform(&pdev->dev, - &msm_soc_platform); -} - -static int msm_compr_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; -} - -static const struct of_device_id msm_compr_dt_match[] = { - {.compatible = "qcom,msm-compr-dsp"}, - {} -}; -MODULE_DEVICE_TABLE(of, msm_compr_dt_match); - -static struct platform_driver msm_compr_driver = { - .driver = { - .name = "msm-compr-dsp", - .owner = THIS_MODULE, - .of_match_table = msm_compr_dt_match, - }, - .probe = msm_compr_probe, - .remove = msm_compr_remove, -}; - -static int __init msm_soc_platform_init(void) -{ - init_waitqueue_head(&the_locks.enable_wait); - init_waitqueue_head(&the_locks.eos_wait); - init_waitqueue_head(&the_locks.write_wait); - init_waitqueue_head(&the_locks.read_wait); - init_waitqueue_head(&the_locks.flush_wait); - - return platform_driver_register(&msm_compr_driver); -} -module_init(msm_soc_platform_init); - -static void __exit msm_soc_platform_exit(void) -{ - platform_driver_unregister(&msm_compr_driver); -} -module_exit(msm_soc_platform_exit); - -MODULE_DESCRIPTION("PCM module platform driver"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h deleted file mode 100644 index d6e3ec6956b1b7ca97d17f30ff0ddfb1815420b8..0000000000000000000000000000000000000000 --- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2012, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _MSM_COMPR_H -#define _MSM_COMPR_H -#include <sound/apr_audio-v2.h> -#include <sound/q6asm-v2.h> -#include <sound/compress_params.h> -#include <sound/compress_offload.h> -#include <sound/compress_driver.h> - -#include "msm-pcm-q6-v2.h" - -struct compr_info { - struct snd_compr_caps compr_cap; - struct snd_compr_codec_caps codec_caps; - struct snd_compr_params codec_param; -}; - -struct compr_audio { - struct msm_audio prtd; - struct compr_info info; - uint32_t codec; -}; - -#endif /*_MSM_COMPR_H*/