diff options
author | Shreyas Narayan <shrena@codeaurora.org> | 2019-08-07 16:10:33 +0530 |
---|---|---|
committer | Shreyas Narayan <shrena@codeaurora.org> | 2019-08-07 16:10:39 +0530 |
commit | fd6ec63d84c41eb6ebb6b23d856d6925d57e09fb (patch) | |
tree | bf73db23fa14c6212c94f0e0c405e3b5b7884ad7 | |
parent | 815f857fdd4474ea903bbffd28c3eec5e407cae7 (diff) | |
parent | 2fba0187381825b99c39bf0d3a1cd991b151d9a0 (diff) |
Merge commit '2fba0187381825b99c39bf0d3a1cd991b151d9a0' into HEADLA.UM.7.8.r3-01700-SDM710.0
Change-Id: Ic5dfc3e3fc6d770ad29e59dddba2b4ebc5080af1
Signed-off-by: Shreyas Narayan <shrena@codeaurora.org>
129 files changed, 3579 insertions, 742 deletions
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi index 76b7b058d9af..6209bbb249d6 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, 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 @@ -320,10 +320,10 @@ }; iova-mem-region-shared { - /* Shared region is 100MB long */ + /* Shared region is 150MB long */ iova-region-name = "shared"; iova-region-start = <0x7400000>; - iova-region-len = <0x6400000>; + iova-region-len = <0x9600000>; iova-region-id = <0x1>; iova-granularity = <0x15>; status = "ok"; @@ -332,7 +332,7 @@ iova-mem-region-secondary-heap { /* Secondary heap region is 1MB long */ iova-region-name = "secheap"; - iova-region-start = <0xd800000>; + iova-region-start = <0x10A00000>; iova-region-len = <0x100000>; iova-region-id = <0x4>; status = "ok"; @@ -341,8 +341,8 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xda00000>; - iova-region-len = <0xd2500000>; + iova-region-start = <0x10C00000>; + iova-region-len = <0xCF300000>; iova-region-id = <0x3>; status = "ok"; }; @@ -350,7 +350,7 @@ iova-mem-qdss-region { /* qdss region is approximately 1MB */ iova-region-name = "qdss"; - iova-region-start = <0xd900000>; + iova-region-start = <0x10B00000>; iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index b967af9d2ab7..ec7400e2da03 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -2615,6 +2615,7 @@ qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>; qcom,smmu-s1-bypass; + #cooling-cells = <2>; }; cpubw: qcom,cpubw { diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index 86b17046ed31..8bb6d2386530 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, 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 @@ -294,10 +294,10 @@ }; iova-mem-region-shared { - /* Shared region is 100MB long */ + /* Shared region is 150MB long */ iova-region-name = "shared"; iova-region-start = <0x7400000>; - iova-region-len = <0x6400000>; + iova-region-len = <0x9600000>; iova-region-id = <0x1>; status = "ok"; }; @@ -305,7 +305,7 @@ iova-mem-region-secondary-heap { /* Secondary heap region is 1MB long */ iova-region-name = "secheap"; - iova-region-start = <0xd800000>; + iova-region-start = <0x10A00000>; iova-region-len = <0x100000>; iova-region-id = <0x4>; status = "ok"; @@ -314,8 +314,8 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xda00000>; - iova-region-len = <0xd2500000>; + iova-region-start = <0x10C00000>; + iova-region-len = <0xCF300000>; iova-region-id = <0x3>; status = "ok"; }; @@ -323,7 +323,7 @@ iova-mem-qdss-region { /* qdss region is approximately 1MB */ iova-region-name = "qdss"; - iova-region-start = <0xd900000>; + iova-region-start = <0x10B00000>; iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi index c9669d958c2c..55bdcb073ef3 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, 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 @@ -227,10 +227,10 @@ }; iova-mem-region-shared { - /* Shared region is 100MB long */ + /* Shared region is 150MB long */ iova-region-name = "shared"; iova-region-start = <0x7400000>; - iova-region-len = <0x6400000>; + iova-region-len = <0x9600000>; iova-region-id = <0x1>; iova-granularity = <0x15>; status = "ok"; @@ -239,7 +239,7 @@ iova-mem-region-secondary-heap { /* Secondary heap region is 1MB long */ iova-region-name = "secheap"; - iova-region-start = <0xd800000>; + iova-region-start = <0x10A00000>; iova-region-len = <0x100000>; iova-region-id = <0x4>; status = "ok"; @@ -248,8 +248,8 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xda00000>; - iova-region-len = <0xd2500000>; + iova-region-start = <0x10C00000>; + iova-region-len = <0xCF300000>; iova-region-id = <0x3>; status = "ok"; }; @@ -257,7 +257,7 @@ iova-mem-qdss-region { /* qdss region is approximately 1MB */ iova-region-name = "qdss"; - iova-region-start = <0xd900000>; + iova-region-start = <0x10B00000>; iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; diff --git a/arch/arm64/boot/dts/qcom/sxr1130.dtsi b/arch/arm64/boot/dts/qcom/sxr1130.dtsi index 75707b197902..0311ae2c5801 100644 --- a/arch/arm64/boot/dts/qcom/sxr1130.dtsi +++ b/arch/arm64/boot/dts/qcom/sxr1130.dtsi @@ -16,4 +16,31 @@ / { model = "Qualcomm Technologies, Inc. SXR1130"; qcom,msm-id = <371 0x0>; + + reserved-memory { + mdsp_mem: mdsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x12c00000>; + }; + }; + + qcom,msm-mdsprpc-mem { + compatible = "qcom,msm-mdsprpc-mem-region"; + memory-region = <&mdsp_mem>; + }; +}; + +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + + qcom,ion-heap@22 { /* MDSP HEAP */ + reg = <22>; + memory-region = <&mdsp_mem>; + qcom,ion-heap-type = "DMA"; + }; + }; }; diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 2b35b67540b9..0421d0872f95 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -271,7 +271,7 @@ void __init arm64_memblock_init(void) * memory spans, randomize the linear region as well. */ if (memstart_offset_seed > 0 && range >= ARM64_MEMSTART_ALIGN) { - range = range / ARM64_MEMSTART_ALIGN + 1; + range /= ARM64_MEMSTART_ALIGN; memstart_addr -= ARM64_MEMSTART_ALIGN * ((range * memstart_offset_seed) >> 16); } diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 2d0574200459..a7fe093a63dc 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -224,9 +224,11 @@ struct smq_invoke_ctx { int tgid; remote_arg_t *lpra; remote_arg64_t *rpra; + remote_arg64_t *lrpra; /* Local copy of rpra for put_args */ int *fds; struct fastrpc_mmap **maps; struct fastrpc_buf *buf; + struct fastrpc_buf *lbuf; size_t used; struct fastrpc_file *fl; uint32_t sc; @@ -303,6 +305,8 @@ struct fastrpc_channel_ctx { struct fastrpc_glink_info link; /* Indicates, if channel is restricted to secure node only */ int secure; + int memshareenabled; + struct smq_phy_page memsharerange; }; struct fastrpc_apps { @@ -319,6 +323,7 @@ struct fastrpc_apps { spinlock_t hlock; struct ion_client *client; struct device *dev; + struct device *mdev; unsigned int latency; bool glink; bool legacy; @@ -620,8 +625,13 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, if (va >= map->va && va + len <= map->va + map->len && map->fd == fd) { - if (refs) + if (refs) { + if (map->refs + 1 == INT_MAX) { + spin_unlock(&me->hlock); + return -ETOOMANYREFS; + } map->refs++; + } match = map; break; } @@ -632,8 +642,11 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, if (va >= map->va && va + len <= map->va + map->len && map->fd == fd) { - if (refs) + if (refs) { + if (map->refs + 1 == INT_MAX) + return -ETOOMANYREFS; map->refs++; + } match = map; break; } @@ -927,9 +940,17 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, vmid = fl->apps->channel[fl->cid].vmid; if (!sess->smmu.enabled && !vmid) { - VERIFY(err, map->phys >= me->range.addr && - map->phys + map->size <= - me->range.addr + me->range.size); + if (fl->apps->channel[cid].memshareenabled == 2) { + VERIFY(err, map->phys >= + fl->apps->channel[cid].memsharerange.addr && + map->phys + map->size <= + fl->apps->channel[cid].memsharerange.addr + + fl->apps->channel[cid].memsharerange.size); + } else { + VERIFY(err, map->phys >= me->range.addr && + map->phys + map->size <= + me->range.addr + me->range.size); + } if (err) { pr_err("adsprpc: mmap fail out of range\n"); goto bail; @@ -1272,6 +1293,7 @@ static void context_free(struct smq_invoke_ctx *ctx) mutex_unlock(&ctx->fl->fl_map_mutex); fastrpc_buf_free(ctx->buf, 1); + fastrpc_buf_free(ctx->lbuf, 1); ctx->magic = 0; ctx->ctxid = 0; @@ -1418,7 +1440,7 @@ static void fastrpc_file_list_dtor(struct fastrpc_apps *me) static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) { struct fastrpc_apps *me = &gfa; - remote_arg64_t *rpra; + remote_arg64_t *rpra, *lrpra; remote_arg_t *lpra = ctx->lpra; struct smq_invoke_buf *list; struct smq_phy_page *pages, *ipage; @@ -1427,7 +1449,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) int outbufs = REMOTE_SCALARS_OUTBUFS(sc); int handles, bufs = inbufs + outbufs; uintptr_t args; - size_t rlen = 0, copylen = 0, metalen = 0; + size_t rlen = 0, copylen = 0, metalen = 0, lrpralen = 0; int i, oix; int err = 0; int mflags = 0; @@ -1485,7 +1507,20 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) metalen = copylen = (size_t)&ipage[0]; } - /* calculate len requreed for copying */ + /* allocate new local rpra buffer */ + lrpralen = (size_t)&list[0]; + if (lrpralen) { + err = fastrpc_buf_alloc(ctx->fl, lrpralen, 0, 0, 0, &ctx->lbuf); + if (err) + goto bail; + } + if (ctx->lbuf->virt) + memset(ctx->lbuf->virt, 0, lrpralen); + + lrpra = ctx->lbuf->virt; + ctx->lrpra = lrpra; + + /* calculate len required for copying */ for (oix = 0; oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; uintptr_t mstart, mend; @@ -1536,13 +1571,13 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) /* map ion buffers */ PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_MAP), - for (i = 0; rpra && i < inbufs + outbufs; ++i) { + for (i = 0; rpra && lrpra && i < inbufs + outbufs; ++i) { struct fastrpc_mmap *map = ctx->maps[i]; uint64_t buf = ptr_to_uint64(lpra[i].buf.pv); size_t len = lpra[i].buf.len; - rpra[i].buf.pv = 0; - rpra[i].buf.len = len; + rpra[i].buf.pv = lrpra[i].buf.pv = 0; + rpra[i].buf.len = lrpra[i].buf.len = len; if (!len) continue; if (map) { @@ -1570,7 +1605,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) pages[idx].addr = map->phys + offset; pages[idx].size = num << PAGE_SHIFT; } - rpra[i].buf.pv = buf; + rpra[i].buf.pv = lrpra[i].buf.pv = buf; } PERF_END); for (i = bufs; i < bufs + handles; ++i) { @@ -1590,7 +1625,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) /* copy non ion buffers */ PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_COPY), rlen = copylen - metalen; - for (oix = 0; rpra && oix < inbufs + outbufs; ++oix) { + for (oix = 0; rpra && lrpra && oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; struct fastrpc_mmap *map = ctx->maps[i]; size_t mlen; @@ -1609,7 +1644,8 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) VERIFY(err, rlen >= mlen); if (err) goto bail; - rpra[i].buf.pv = (args - ctx->overps[oix]->offset); + rpra[i].buf.pv = lrpra[i].buf.pv = + (args - ctx->overps[oix]->offset); pages[list[i].pgidx].addr = ctx->buf->phys - ctx->overps[oix]->offset + (copylen - rlen); @@ -1641,7 +1677,8 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (map && (map->attr & FASTRPC_ATTR_COHERENT)) continue; - if (rpra && rpra[i].buf.len && ctx->overps[oix]->mstart) { + if (rpra && lrpra && rpra[i].buf.len && + ctx->overps[oix]->mstart) { if (map && map->handle) msm_ion_do_cache_op(ctx->fl->apps->client, map->handle, @@ -1655,10 +1692,11 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) } } PERF_END); - for (i = bufs; rpra && i < bufs + handles; i++) { - rpra[i].dma.fd = ctx->fds[i]; - rpra[i].dma.len = (uint32_t)lpra[i].buf.len; - rpra[i].dma.offset = (uint32_t)(uintptr_t)lpra[i].buf.pv; + for (i = bufs; rpra && lrpra && i < bufs + handles; i++) { + rpra[i].dma.fd = lrpra[i].dma.fd = ctx->fds[i]; + rpra[i].dma.len = lrpra[i].dma.len = (uint32_t)lpra[i].buf.len; + rpra[i].dma.offset = lrpra[i].dma.offset = + (uint32_t)(uintptr_t)lpra[i].buf.pv; } bail: @@ -1676,7 +1714,7 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, uint64_t *fdlist = NULL; uint32_t *crclist = NULL; - remote_arg64_t *rpra = ctx->rpra; + remote_arg64_t *rpra = ctx->lrpra; int i, inbufs, outbufs, handles; int err = 0; @@ -1783,7 +1821,7 @@ static void inv_args(struct smq_invoke_ctx *ctx) { int i, inbufs, outbufs; uint32_t sc = ctx->sc; - remote_arg64_t *rpra = ctx->rpra; + remote_arg64_t *rpra = ctx->lrpra; inbufs = REMOTE_SCALARS_INBUFS(sc); outbufs = REMOTE_SCALARS_OUTBUFS(sc); @@ -2788,6 +2826,7 @@ static int fastrpc_session_alloc_locked(struct fastrpc_channel_ctx *chan, { struct fastrpc_apps *me = &gfa; int idx = 0, err = 0; + int cid = 0; if (chan->sesscount) { for (idx = 0; idx < chan->sesscount; ++idx) { @@ -2804,11 +2843,24 @@ static int fastrpc_session_alloc_locked(struct fastrpc_channel_ctx *chan, goto bail; chan->session[idx].smmu.faults = 0; } else { - VERIFY(err, me->dev != NULL); - if (err) - goto bail; - chan->session[0].dev = me->dev; - chan->session[0].smmu.dev = me->dev; + cid = chan - &gcinfo[0]; + if (cid == MDSP_DOMAIN_ID) { + VERIFY(err, me->mdev != NULL); + if (err) { + pr_info("ADSPRPC: mdsprpc-mem not initialized\n"); + goto bail; + } + chan->session[0].dev = me->mdev; + chan->session[0].smmu.dev = me->mdev; + } else { + VERIFY(err, me->dev != NULL); + if (err) { + pr_info("ADSPRPC: adsprpc-mem not initialized\n"); + goto bail; + } + chan->session[0].dev = me->dev; + chan->session[0].smmu.dev = me->dev; + } } *session = &chan->session[idx]; @@ -3520,6 +3572,22 @@ static int fastrpc_get_info(struct fastrpc_file *fl, uint32_t *info) } fl->cid = cid; fl->ssrcount = fl->apps->channel[cid].ssrcount; + if (fl->apps->channel[cid].memshareenabled == 1) { + int srcVM[1] = {VMID_HLOS}; + int destVM[3] = {VMID_HLOS, VMID_MSS_MSA, VMID_ADSP_Q6}; + int destVMperm[3] = {PERM_READ | PERM_WRITE | PERM_EXEC, + PERM_READ | PERM_WRITE | PERM_EXEC, + PERM_READ | PERM_WRITE | PERM_EXEC, + }; + + VERIFY(err, !hyp_assign_phys( + fl->apps->channel[cid].memsharerange.addr, + fl->apps->channel[cid].memsharerange.size, + srcVM, 1, destVM, destVMperm, 3)); + if (err) + goto bail; + fl->apps->channel[cid].memshareenabled = 2; + } VERIFY(err, !fastrpc_session_alloc_locked( &fl->apps->channel[cid], 0, fl->sharedcb, &fl->sctx)); if (err) @@ -3928,6 +3996,7 @@ static const struct of_device_id fastrpc_match_table[] = { { .compatible = "qcom,msm-fastrpc-legacy-compute", }, { .compatible = "qcom,msm-fastrpc-legacy-compute-cb", }, { .compatible = "qcom,msm-adsprpc-mem-region", }, + { .compatible = "qcom,msm-mdsprpc-mem-region", }, {} }; @@ -4138,6 +4207,7 @@ static int fastrpc_probe(struct platform_device *pdev) int err = 0; struct fastrpc_apps *me = &gfa; struct device *dev = &pdev->dev; + struct smq_phy_page range; struct device_node *ion_node, *node; struct platform_device *ion_pdev; struct cma *cma; @@ -4223,6 +4293,39 @@ static int fastrpc_probe(struct platform_device *pdev) } return 0; } + if (of_device_is_compatible(dev->of_node, + "qcom,msm-mdsprpc-mem-region")) { + me->mdev = dev; + range.addr = 0; + range.size = 0; + ion_node = of_find_compatible_node(NULL, NULL, "qcom,msm-ion"); + if (ion_node) { + for_each_available_child_of_node(ion_node, node) { + if (of_property_read_u32(node, "reg", &val)) + continue; + if (val != ION_ADSP_HEAP_ID) + continue; + ion_pdev = of_find_device_by_node(node); + if (!ion_pdev) + break; + cma = dev_get_cma_area(&ion_pdev->dev); + if (cma) { + range.addr = cma_get_base(cma); + range.size = (size_t)cma_get_size(cma); + } + break; + } + } + if (range.addr && !of_property_read_bool(dev->of_node, + "restrict-access")) { + me->channel[MDSP_DOMAIN_ID].memshareenabled = 1; + me->channel[MDSP_DOMAIN_ID].memsharerange.addr = + range.addr; + me->channel[MDSP_DOMAIN_ID].memsharerange.size = + range.size; + } + return 0; + } if (of_property_read_bool(dev->of_node, "qcom,fastrpc-adsp-audio-pdr")) { int session; diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index bb4c16b4fa07..b3d2bb36a7b9 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -2070,9 +2070,9 @@ int diag_process_dci_transaction(unsigned char *buf, int len) uint8_t *event_mask_ptr; struct diag_dci_client_tbl *dci_entry = NULL; - if (!temp) { - pr_err("diag: Invalid buffer in %s\n", __func__); - return -ENOMEM; + if (!temp || len < sizeof(int)) { + pr_err("diag: Invalid input in %s\n", __func__); + return -EINVAL; } /* This is Pkt request/response transaction */ @@ -2128,7 +2128,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len) count = 0; /* iterator for extracting log codes */ while (count < num_codes) { - if (read_len >= USER_SPACE_DATA) { + if (read_len + sizeof(uint16_t) > len) { pr_err("diag: dci: Invalid length for log type in %s", __func__); mutex_unlock(&driver->dci_mutex); @@ -2242,7 +2242,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len) pr_debug("diag: head of dci event mask %pK\n", event_mask_ptr); count = 0; /* iterator for extracting log codes */ while (count < num_codes) { - if (read_len >= USER_SPACE_DATA) { + if (read_len + sizeof(int) > len) { pr_err("diag: dci: Invalid length for event type in %s", __func__); mutex_unlock(&driver->dci_mutex); diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h index 835c0c1708cf..f727609a54f0 100644 --- a/drivers/char/diag/diag_dci.h +++ b/drivers/char/diag/diag_dci.h @@ -26,7 +26,7 @@ #define DISABLE_LOG_MASK 0 #define MAX_EVENT_SIZE 512 #define DCI_CLIENT_INDEX_INVALID -1 -#define DCI_LOG_CON_MIN_LEN 14 +#define DCI_LOG_CON_MIN_LEN 16 #define DCI_EVENT_CON_MIN_LEN 16 #define EXT_HDR_LEN 8 diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 8d53a06c62a3..a17518c5f249 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, 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 @@ -641,7 +641,8 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, struct diag_build_mask_req_t *req = NULL; struct diag_msg_build_mask_t rsp; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) { + if (!src_buf || !dest_buf || dest_len <= 0 || + src_len < sizeof(struct diag_build_mask_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d\n", __func__, src_buf, src_len, dest_buf, dest_len); return -EINVAL; @@ -702,8 +703,8 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, info = diag_md_session_get_pid(pid); mask_info = (!info) ? &msg_mask : info->msg_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || + !mask_info || (src_len < sizeof(struct diag_build_mask_req_t))) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -781,8 +782,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, info = diag_md_session_get_pid(pid); mask_info = (!info) ? &msg_mask : info->msg_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || + (src_len < sizeof(struct diag_msg_build_mask_t))) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -867,7 +868,9 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, break; } mask_size = mask_size * sizeof(uint32_t); - memcpy(mask->ptr + offset, src_buf + header_len, mask_size); + if (mask_size && src_len >= header_len + mask_size) + memcpy(mask->ptr + offset, src_buf + header_len, + mask_size); mutex_unlock(&mask->lock); mask_info->status = DIAG_CTRL_MASK_VALID; break; @@ -930,8 +933,8 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, info = diag_md_session_get_pid(pid); mask_info = (!info) ? &msg_mask : info->msg_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || + (src_len < sizeof(struct diag_msg_config_rsp_t))) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -1054,8 +1057,8 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); mask_info = (!info) ? &event_mask : info->event_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || + src_len < sizeof(struct diag_event_mask_config_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -1078,7 +1081,8 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, } mutex_lock(&mask_info->lock); - memcpy(mask_info->ptr, src_buf + header_len, mask_len); + if (src_len >= header_len + mask_len) + memcpy(mask_info->ptr, src_buf + header_len, mask_len); mask_info->status = DIAG_CTRL_MASK_VALID; mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); @@ -1127,8 +1131,8 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); mask_info = (!info) ? &event_mask : info->event_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || src_len <= sizeof(uint8_t) || + dest_len <= 0 || !mask_info) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -1201,8 +1205,8 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, info = diag_md_session_get_pid(pid); mask_info = (!info) ? &log_mask : info->log_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || + src_len < sizeof(struct diag_log_config_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -1343,8 +1347,8 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, info = diag_md_session_get_pid(pid); mask_info = (!info) ? &log_mask : info->log_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info || + src_len < sizeof(struct diag_log_config_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); @@ -1418,7 +1422,7 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, mask->range_tools = mask_size; } req->num_items = mask->num_items_tools; - if (mask_size > 0) + if (mask_size > 0 && src_len >= read_len + mask_size) memcpy(mask->ptr, src_buf + read_len, mask_size); DIAG_LOG(DIAG_DEBUG_MASKS, "copying log mask, e %d num %d range %d size %d\n", diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 8a88cf08e574..ebbe26dfd654 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, 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 @@ -1159,15 +1159,19 @@ static int diag_process_userspace_remote(int proc, void *buf, int len) } #endif -static int mask_request_validate(unsigned char mask_buf[]) +static int mask_request_validate(unsigned char mask_buf[], int len) { uint8_t packet_id; uint8_t subsys_id; uint16_t ss_cmd; + if (len <= 0) + return 0; packet_id = mask_buf[0]; if (packet_id == DIAG_CMD_DIAG_SUBSYS_DELAY) { + if (len < 2*sizeof(uint8_t) + sizeof(uint16_t)) + return 0; subsys_id = mask_buf[1]; ss_cmd = *(uint16_t *)(mask_buf + 2); switch (subsys_id) { @@ -1183,6 +1187,8 @@ static int mask_request_validate(unsigned char mask_buf[]) return 0; } } else if (packet_id == 0x4B) { + if (len < 2*sizeof(uint8_t) + sizeof(uint16_t)) + return 0; subsys_id = mask_buf[1]; ss_cmd = *(uint16_t *)(mask_buf + 2); /* Packets with SSID which are allowed */ @@ -3160,7 +3166,8 @@ static int diag_user_process_raw_data(const char __user *buf, int len) } /* Check for proc_type */ - remote_proc = diag_get_remote(*(int *)user_space_data); + if (len >= sizeof(int)) + remote_proc = diag_get_remote(*(int *)user_space_data); if (remote_proc) { token_offset = sizeof(int); if (len <= MIN_SIZ_ALLOW) { @@ -3174,7 +3181,7 @@ static int diag_user_process_raw_data(const char __user *buf, int len) } if (driver->mask_check) { if (!mask_request_validate(user_space_data + - token_offset)) { + token_offset, len)) { pr_alert("diag: mask request Invalid\n"); diagmem_free(driver, user_space_data, mempool); user_space_data = NULL; @@ -3252,7 +3259,7 @@ static int diag_user_process_userspace_data(const char __user *buf, int len) /* Check masks for On-Device logging */ if (driver->mask_check) { if (!mask_request_validate(driver->user_space_data_buf + - token_offset)) { + token_offset, len)) { pr_alert("diag: mask request Invalid\n"); return -EFAULT; } diff --git a/drivers/devfreq/governor_gpubw_mon.c b/drivers/devfreq/governor_gpubw_mon.c index 9c24eef6a497..f7bb7ebf41ea 100644 --- a/drivers/devfreq/governor_gpubw_mon.c +++ b/drivers/devfreq/governor_gpubw_mon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, 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 @@ -224,10 +224,11 @@ static int devfreq_gpubw_event_handler(struct devfreq *devfreq, case DEVFREQ_GOV_SUSPEND: { struct devfreq_msm_adreno_tz_data *priv = devfreq->data; - - priv->bus.total_time = 0; - priv->bus.gpu_time = 0; - priv->bus.ram_time = 0; + if (priv) { + priv->bus.total_time = 0; + priv->bus.gpu_time = 0; + priv->bus.ram_time = 0; + } } break; default: diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 612cea70f4f1..1d4cc994de3d 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -1036,6 +1036,9 @@ static ssize_t debugfs_dump_info_read(struct file *file, "\tClock master = %s\n", display->ctrl[display->clk_master_idx].ctrl->name); + if (len > user_len) + len = user_len; + if (copy_to_user(user_buf, buf, len)) { kfree(buf); return -EFAULT; diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index e0094d7ec766..bb7c63e37645 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -757,6 +757,25 @@ static bool sde_crtc_mode_fixup(struct drm_crtc *crtc, return true; } +static int _sde_crtc_get_ctlstart_timeout(struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + int rc = 0; + + if (!crtc || !crtc->dev) + return 0; + + list_for_each_entry(encoder, + &crtc->dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + + if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_CMD) + rc += sde_encoder_get_ctlstart_timeout_state(encoder); + } + + return rc; +} static void _sde_crtc_setup_blend_cfg(struct sde_crtc_mixer *mixer, struct sde_plane_state *pstate, struct sde_format *format) @@ -3160,7 +3179,13 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, if (unlikely(!sde_crtc->num_mixers)) return; - _sde_crtc_blend_setup(crtc, old_state, true); + if (_sde_crtc_get_ctlstart_timeout(crtc)) { + _sde_crtc_blend_setup(crtc, old_state, false); + SDE_ERROR("border fill only commit after ctlstart timeout\n"); + } else { + _sde_crtc_blend_setup(crtc, old_state, true); + } + _sde_crtc_dest_scaler_setup(crtc); /* cancel the idle notify delayed work */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 122f319c7c00..4dd37dc11f00 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -3114,6 +3114,24 @@ int sde_encoder_idle_request(struct drm_encoder *drm_enc) return 0; } +int sde_encoder_get_ctlstart_timeout_state(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + int i, count = 0; + + if (!drm_enc) + return 0; + + sde_enc = to_sde_encoder_virt(drm_enc); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + count += atomic_read(&sde_enc->phys_encs[i]->ctlstart_timeout); + atomic_set(&sde_enc->phys_encs[i]->ctlstart_timeout, 0); + } + + return count; +} + /** * _sde_encoder_trigger_flush - trigger flush for a physical encoder * drm_enc: Pointer to drm encoder structure diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h index c40db41adecf..38ae13cae082 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -264,4 +264,11 @@ int sde_encoder_in_clone_mode(struct drm_encoder *enc); */ void sde_encoder_control_idle_pc(struct drm_encoder *enc, bool enable); +/** + * sde_encoder_get_ctlstart_timeout_state - checks if ctl start timeout happened + * @drm_enc: Pointer to drm encoder structure + * @Return: non zero value if ctl start timeout occurred + */ +int sde_encoder_get_ctlstart_timeout_state(struct drm_encoder *enc); + #endif /* __SDE_ENCODER_H__ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 953106ee9823..ab007b61e59a 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -267,6 +267,7 @@ struct sde_encoder_irq { * @pending_retire_fence_cnt: Atomic counter tracking the pending retire * fences that have to be signalled. * @pending_kickoff_wq: Wait queue for blocking until kickoff completes + * @ctlstart_timeout: Indicates if ctl start timeout occurred * @irq: IRQ tracking structures * @cont_splash_single_flush Variable to check if single flush is enabled. * @cont_splash_settings Variable to store continuous splash settings. @@ -301,6 +302,7 @@ struct sde_encoder_phys { atomic_t pending_kickoff_cnt; atomic_t pending_retire_fence_cnt; wait_queue_head_t pending_kickoff_wq; + atomic_t ctlstart_timeout; struct sde_encoder_irq irq[INTR_IDX_MAX]; u32 cont_splash_single_flush; bool cont_splash_settings; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 4409408ba3fe..d6e8fd34e051 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019 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 @@ -193,6 +193,7 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) phys_enc, SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0); + atomic_set(&phys_enc->ctlstart_timeout, 0); } /* notify all synchronous clients first, then asynchronous clients */ @@ -292,6 +293,7 @@ static void sde_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx) ctl = phys_enc->hw_ctl; atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0); + atomic_set(&phys_enc->ctlstart_timeout, 0); time_diff_us = ktime_us_delta(ktime_get(), cmd_enc->rd_ptr_timestamp); @@ -1054,6 +1056,7 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc) SDE_ERROR("invalid encoder\n"); return; } + atomic_set(&phys_enc->ctlstart_timeout, 0); SDE_DEBUG_CMDENC(cmd_enc, "pp %d state %d\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->enable_state); @@ -1176,6 +1179,9 @@ static int _sde_encoder_phys_cmd_wait_for_ctl_start( "ctl start interrupt wait failed\n"); else ret = 0; + + if (sde_encoder_phys_cmd_is_master(phys_enc)) + atomic_inc_return(&phys_enc->ctlstart_timeout); } return ret; @@ -1476,6 +1482,7 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( atomic_set(&phys_enc->pending_retire_fence_cnt, 0); atomic_set(&cmd_enc->pending_rd_ptr_cnt, 0); atomic_set(&cmd_enc->pending_vblank_cnt, 0); + atomic_set(&phys_enc->ctlstart_timeout, 0); init_waitqueue_head(&phys_enc->pending_kickoff_wq); init_waitqueue_head(&cmd_enc->pending_vblank_wq); atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0); diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index 22939199c28c..089c46063bbc 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019 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 @@ -70,6 +70,19 @@ void kgsl_snapshot_push_object(struct kgsl_process_private *process, for (index = 0; index < objbufptr; index++) { if (objbuf[index].gpuaddr == gpuaddr && objbuf[index].entry->priv == process) { + /* + * Check if newly requested size is within the + * allocated range or not, otherwise continue + * with previous size. + */ + if (!kgsl_gpuaddr_in_memdesc( + &objbuf[index].entry->memdesc, + gpuaddr, dwords << 2)) { + KGSL_CORE_ERR( + "snapshot: IB 0x%016llx size is not within the memdesc range\n", + gpuaddr); + return; + } objbuf[index].size = max_t(uint64_t, objbuf[index].size, diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c index 3dbaea4a0ccb..0431885e2408 100644 --- a/drivers/gpu/msm/kgsl_drawobj.c +++ b/drivers/gpu/msm/kgsl_drawobj.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017,2019, 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 @@ -201,8 +201,13 @@ static void drawobj_sync_func(struct kgsl_device *device, trace_syncpoint_timestamp_expire(event->syncobj, event->context, event->timestamp); - drawobj_sync_expire(device, event); - kgsl_context_put(event->context); + /* + * Put down the context ref count only if + * this thread successfully clears the pending bit mask. + */ + if (drawobj_sync_expire(device, event)) + kgsl_context_put(event->context); + kgsl_drawobj_put(&event->syncobj->base); } @@ -232,33 +237,24 @@ static void drawobj_destroy_sparse(struct kgsl_drawobj *drawobj) static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) { struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj); - unsigned long pending = 0; unsigned int i; /* Zap the canary timer */ del_timer_sync(&syncobj->timer); /* - * Copy off the pending list and clear each pending event atomically - - * this will render any subsequent asynchronous callback harmless. - * This marks each event for deletion. If any pending fence callbacks - * run between now and the actual cancel, the associated structures - * are kfreed only in the cancel call. - */ - for_each_set_bit(i, &syncobj->pending, KGSL_MAX_SYNCPOINTS) { - if (test_and_clear_bit(i, &syncobj->pending)) - __set_bit(i, &pending); - } - - /* * Clear all pending events - this will render any subsequent async * callbacks harmless */ for (i = 0; i < syncobj->numsyncs; i++) { struct kgsl_drawobj_sync_event *event = &syncobj->synclist[i]; - /* Don't do anything if the event has already expired */ - if (!test_bit(i, &pending)) + /* + * Don't do anything if the event has already expired. + * If this thread clears the pending bit mask then it is + * responsible for doing context put. + */ + if (!test_and_clear_bit(i, &syncobj->pending)) continue; switch (event->type) { @@ -266,6 +262,11 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) kgsl_cancel_event(drawobj->device, &event->context->events, event->timestamp, drawobj_sync_func, event); + /* + * Do context put here to make sure the context is alive + * till this thread cancels kgsl event. + */ + kgsl_context_put(event->context); break; case KGSL_CMD_SYNCPOINT_TYPE_FENCE: kgsl_sync_fence_async_cancel(event->handle); @@ -278,7 +279,7 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) * If we cancelled an event, there's a good chance that the context is * on a dispatcher queue, so schedule to get it removed. */ - if (!bitmap_empty(&pending, KGSL_MAX_SYNCPOINTS) && + if (!bitmap_empty(&syncobj->pending, KGSL_MAX_SYNCPOINTS) && drawobj->device->ftbl->drawctxt_sched) drawobj->device->ftbl->drawctxt_sched(drawobj->device, drawobj->context); diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c index 4ae2f0a3bee2..804adb1605d6 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -509,8 +509,8 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, if (!rc) { CAM_DBG(CAM_CDM, - "write BL success for cnt=%d with tag=%d", - i, core->bl_tag); + "write BL success for cnt=%d with tag=%d total_cnt=%d", + i, core->bl_tag, req->data->cmd_arrary_count); CAM_DBG(CAM_CDM, "Now commit the BL"); if (cam_hw_cdm_commit_bl_write(cdm_hw)) { @@ -550,35 +550,33 @@ static void cam_hw_cdm_work(struct work_struct *work) cdm_hw = payload->hw; core = (struct cam_cdm *)cdm_hw->core_info; - CAM_DBG(CAM_CDM, "IRQ status=%x", payload->irq_status); + CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status); if (payload->irq_status & CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { - struct cam_cdm_bl_cb_request_entry *node; + struct cam_cdm_bl_cb_request_entry *node, *tnode; - CAM_DBG(CAM_CDM, "inline IRQ data=%x", + CAM_DBG(CAM_CDM, "inline IRQ data=0x%x", payload->irq_data); mutex_lock(&cdm_hw->hw_mutex); - node = cam_cdm_find_request_by_bl_tag( - payload->irq_data, - &core->bl_request_list); - if (node) { + list_for_each_entry_safe(node, tnode, + &core->bl_request_list, entry) { if (node->request_type == CAM_HW_CDM_BL_CB_CLIENT) { cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_BL_SUCCESS, (void *)node); } else if (node->request_type == - CAM_HW_CDM_BL_CB_INTERNAL) { + CAM_HW_CDM_BL_CB_INTERNAL) { CAM_ERR(CAM_CDM, "Invalid node=%pK %d", node, node->request_type); } list_del_init(&node->entry); + if (node->bl_tag == payload->irq_data) { + kfree(node); + break; + } kfree(node); - } else { - CAM_ERR(CAM_CDM, - "Inval node, inline_irq st=%x data=%x", - payload->irq_status, payload->irq_data); } mutex_unlock(&cdm_hw->hw_mutex); } @@ -684,7 +682,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ cmd"); work_status = queue_work(cdm_core->work_queue, &payload->work); if (work_status == false) { - CAM_ERR(CAM_CDM, "Failed to queue work for irq=%x", + CAM_ERR(CAM_CDM, "Failed to queue work for irq=0x%x", payload->irq_status); kfree(payload); } diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h index 3d0ee725dcad..f3a0fe4343ac 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -38,6 +38,7 @@ struct hfi_mem { * @sfr_buf: buffer for subsystem failure reason[SFR] * @sec_heap: secondary heap hfi memory for firmware * @qdss: qdss mapped memory for fw + * @io_mem: io memory info * @icp_base: icp base address */ struct hfi_mem_info { @@ -49,6 +50,7 @@ struct hfi_mem_info { struct hfi_mem sec_heap; struct hfi_mem shmem; struct hfi_mem qdss; + struct hfi_mem io_mem; void __iomem *icp_base; }; diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h index f652cfa3d2a3..2579153d600b 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, 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 @@ -42,8 +42,11 @@ #define HFI_REG_UNCACHED_HEAP_PTR 0x5C #define HFI_REG_UNCACHED_HEAP_SIZE 0x60 #define HFI_REG_QDSS_IOVA 0x6C -#define HFI_REG_QDSS_IOVA_SIZE 0x70 #define HFI_REG_SFR_PTR 0x68 +#define HFI_REG_QDSS_IOVA_SIZE 0x70 +#define HFI_REG_IO_REGION_IOVA 0x74 +#define HFI_REG_IO_REGION_SIZE 0x78 + /* end of ICP CSR registers */ /* flags for ICP CSR registers */ diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c index cbe6886e5712..a53a86f00926 100644 --- a/drivers/media/platform/msm/camera/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -632,6 +632,10 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem, icp_base + HFI_REG_QDSS_IOVA); cam_io_w_mb((uint32_t)hfi_mem->qdss.len, icp_base + HFI_REG_QDSS_IOVA_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.iova, + icp_base + HFI_REG_IO_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, + icp_base + HFI_REG_IO_REGION_SIZE); return rc; } @@ -820,6 +824,10 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, icp_base + HFI_REG_QDSS_IOVA); cam_io_w_mb((uint32_t)hfi_mem->qdss.len, icp_base + HFI_REG_QDSS_IOVA_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.iova, + icp_base + HFI_REG_IO_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, + icp_base + HFI_REG_IO_REGION_SIZE); hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION); diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 94e259311326..272721a0e990 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -2176,6 +2176,25 @@ static int cam_icp_allocate_qdss_mem(void) return rc; } +static int cam_icp_get_io_mem_info(void) +{ + int rc; + size_t len; + dma_addr_t iova; + + rc = cam_smmu_get_io_region_info(icp_hw_mgr.iommu_hdl, + &iova, &len); + if (rc) + return rc; + + icp_hw_mgr.hfi_mem.io_mem.iova_len = len; + icp_hw_mgr.hfi_mem.io_mem.iova_start = iova; + + CAM_DBG(CAM_ICP, "iova: %llx, len: %zu", iova, len); + + return rc; +} + static int cam_icp_allocate_hfi_mem(void) { int rc; @@ -2236,7 +2255,15 @@ static int cam_icp_allocate_hfi_mem(void) goto sec_heap_alloc_failed; } + rc = cam_icp_get_io_mem_info(); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get I/O region info"); + goto get_io_mem_failed; + } + return rc; +get_io_mem_failed: + cam_mem_mgr_free_memory_region(&icp_hw_mgr.hfi_mem.sec_heap); sec_heap_alloc_failed: cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sfr_buf); sfr_buf_alloc_failed: @@ -2455,6 +2482,14 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; + + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + + CAM_DBG(CAM_ICP, "IO region IOVA = %X length = %lld", + hfi_mem.io_mem.iova, + hfi_mem.io_mem.len); + return cam_hfi_resume(&hfi_mem, a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, hw_mgr->a5_jtag_debug); @@ -2837,6 +2872,9 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + return cam_hfi_init(0, &hfi_mem, a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, hw_mgr->a5_jtag_debug); diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 8c132c52739d..b3fcd7aa6768 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -80,6 +80,8 @@ * @fw_buf: Memory info of firmware * @qdss_buf: Memory info of qdss * @sfr_buf: Memory info for sfr buffer + * @shmem: Memory info for shared region + * @io_mem: Memory info for io region */ struct icp_hfi_mem_info { struct cam_mem_mgr_memory_desc qtbl; @@ -91,6 +93,7 @@ struct icp_hfi_mem_info { struct cam_mem_mgr_memory_desc qdss_buf; struct cam_mem_mgr_memory_desc sfr_buf; struct cam_smmu_region_info shmem; + struct cam_smmu_region_info io_mem; }; /** diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 45f88b3e79da..3318476dfc3c 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1474,8 +1474,8 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { complete(&ctx->config_done_complete); CAM_DBG(CAM_ISP, - "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", - handle, userdata, status, cookie); + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", + handle, userdata, status, cookie, ctx->ctx_index); } else { CAM_WARN(CAM_ISP, "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", @@ -1798,15 +1798,15 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, msecs_to_jiffies(30)); if (rc <= 0) { CAM_ERR(CAM_ISP, - "config done completion timeout for req_id=%llu rc = %d", - cfg->request_id, rc); + "config done completion timeout for req_id=%llu rc=%d ctx_index %d", + cfg->request_id, rc, ctx->ctx_index); if (rc == 0) rc = -ETIMEDOUT; } else { rc = 0; CAM_DBG(CAM_ISP, - "config done Success for req_id=%llu", - cfg->request_id); + "config done Success for req_id=%llu ctx_index %d", + cfg->request_id, ctx->ctx_index); } } } else { @@ -2580,8 +2580,8 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, struct cam_hw_prepare_update_args *prepare = NULL; if (!blob_data || (blob_size == 0) || !blob_info) { - CAM_ERR(CAM_ISP, "Invalid info blob %pK %d prepare %pK", - blob_data, blob_size, prepare); + CAM_ERR(CAM_ISP, "Invalid args data %pK size %d info %pK", + blob_data, blob_size, blob_info); return -EINVAL; } @@ -2600,8 +2600,29 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, switch (blob_type) { case CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG: { - struct cam_isp_resource_hfr_config *hfr_config = - (struct cam_isp_resource_hfr_config *)blob_data; + struct cam_isp_resource_hfr_config *hfr_config; + + if (blob_size < sizeof(struct cam_isp_resource_hfr_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + hfr_config = (struct cam_isp_resource_hfr_config *)blob_data; + + if (hfr_config->num_ports > CAM_ISP_IFE_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_ports %u in hfr config", + hfr_config->num_ports); + return -EINVAL; + } + + if (blob_size < (sizeof(uint32_t) * 2 + hfr_config->num_ports * + sizeof(struct cam_isp_port_hfr_config))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, (unsigned long)(sizeof(uint32_t) + * 2 + sizeof(struct cam_isp_port_hfr_config) * + hfr_config->num_ports)); + return -EINVAL; + } rc = cam_isp_blob_hfr_update(blob_type, blob_info, hfr_config, prepare); @@ -2610,8 +2631,29 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } break; case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: { - struct cam_isp_clock_config *clock_config = - (struct cam_isp_clock_config *)blob_data; + struct cam_isp_clock_config *clock_config; + + if (blob_size < sizeof(struct cam_isp_clock_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + clock_config = (struct cam_isp_clock_config *)blob_data; + + if (clock_config->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in clock config", + clock_config->num_rdi); + return -EINVAL; + } + + if (blob_size < (sizeof(uint32_t) * 2 + sizeof(uint64_t) * + (clock_config->num_rdi + 2))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, (unsigned long)(sizeof(uint32_t) + * 2 + sizeof(uint64_t) * + (clock_config->num_rdi + 2))); + return -EINVAL; + } rc = cam_isp_blob_clock_update(blob_type, blob_info, clock_config, prepare); @@ -2620,10 +2662,31 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } break; case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: { - struct cam_isp_bw_config *bw_config = - (struct cam_isp_bw_config *)blob_data; + struct cam_isp_bw_config *bw_config; struct cam_isp_prepare_hw_update_data *prepare_hw_data; + if (blob_size < sizeof(struct cam_isp_bw_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + bw_config = (struct cam_isp_bw_config *)blob_data; + + if (bw_config->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in bw config", + bw_config->num_rdi); + return -EINVAL; + } + + if (blob_size < (sizeof(uint32_t) * 2 + (bw_config->num_rdi + 2) + * sizeof(struct cam_isp_bw_vote))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, (unsigned long)(sizeof(uint32_t) + * 2 + (bw_config->num_rdi + 2) + * sizeof(struct cam_isp_bw_vote))); + return -EINVAL; + } + if (!prepare || !prepare->priv || (bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) { CAM_ERR(CAM_ISP, "Invalid inputs"); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 4dce293eb7ab..6797ba4e58d6 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -439,17 +439,32 @@ static int32_t cam_eeprom_parse_memory_map( else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) validate_size = sizeof(struct cam_cmd_unconditional_wait); - if (remain_buf_len < validate_size) { + if (remain_buf_len < validate_size || + *num_map >= (MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE)) { CAM_ERR(CAM_EEPROM, "not enough buffer"); return -EINVAL; } switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; + + if (i2c_random_wr->header.count == 0 || + i2c_random_wr->header.count >= MSM_EEPROM_MAX_MEM_MAP_CNT || + (size_t)*num_map >= ((MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE) - + i2c_random_wr->header.count)) { + CAM_ERR(CAM_EEPROM, "OOB Error"); + return -EINVAL; + } cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_random_wr) + ((i2c_random_wr->header.count - 1) * sizeof(struct i2c_random_wr_payload)); + if (cmd_length_in_bytes > remain_buf_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer remaining"); + return -EINVAL; + } for (cnt = 0; cnt < (i2c_random_wr->header.count); cnt++) { map[*num_map + cnt].page.addr = @@ -472,6 +487,11 @@ static int32_t cam_eeprom_parse_memory_map( i2c_cont_rd = (struct cam_cmd_i2c_continuous_rd *)cmd_buf; cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_continuous_rd); + if (i2c_cont_rd->header.count >= U32_MAX - data->num_data) { + CAM_ERR(CAM_EEPROM, + "int overflow on eeprom memory block"); + return -EINVAL; + } map[*num_map].mem.addr = i2c_cont_rd->reg_addr; map[*num_map].mem.addr_type = i2c_cont_rd->header.addr_type; map[*num_map].mem.data_type = i2c_cont_rd->header.data_type; diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c index 7a489d7204ff..e65351354932 100644 --- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c @@ -1376,6 +1376,42 @@ end: } EXPORT_SYMBOL(cam_smmu_dealloc_qdss); +int cam_smmu_get_io_region_info(int32_t smmu_hdl, + dma_addr_t *iova, size_t *len) +{ + int32_t idx; + + if (!iova || !len || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].io_support) { + CAM_ERR(CAM_SMMU, + "I/O memory not supported for this SMMU handle"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + *iova = iommu_cb_set.cb_info[idx].io_info.iova_start; + *len = iommu_cb_set.cb_info[idx].io_info.iova_len; + + CAM_DBG(CAM_SMMU, + "I/O area for hdl = %x start addr = %pK len = %zu", + smmu_hdl, *iova, *len); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return 0; +} + int cam_smmu_get_region_info(int32_t smmu_hdl, enum cam_smmu_region_id region_id, struct cam_smmu_region_info *region_info) diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h index caf326d6c716..6a6492dc60e8 100644 --- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h +++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, 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 @@ -389,4 +389,16 @@ int cam_smmu_alloc_qdss(int32_t smmu_hdl, */ int cam_smmu_dealloc_qdss(int32_t smmu_hdl); +/** + * @brief Get start addr & len of I/O region for a given cb + * + * @param smmu_hdl: SMMU handle identifying the context bank + * @param iova: IOVA address of allocated I/O region + * @param len: Length of allocated I/O memory + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_io_region_info(int32_t smmu_hdl, + dma_addr_t *iova, size_t *len); + #endif /* _CAM_SMMU_API_H_ */ 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 6f2cfcfabb86..634e34dcfc8c 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, 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 @@ -1473,6 +1473,7 @@ static struct platform_driver fd_driver = { .name = MSM_FD_DRV_NAME, .owner = THIS_MODULE, .of_match_table = msm_fd_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index 63287925eead..874249547072 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, 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 @@ -414,6 +414,12 @@ enum msm_isp_comp_irq_types { #define MSM_VFE_REQUESTQ_SIZE 8 +struct msm_isp_pending_buf_info { + uint32_t is_buf_done_pending; + struct msm_isp_buffer *buf; + uint32_t frame_id; +}; + struct msm_vfe_axi_stream { uint32_t frame_id; enum msm_vfe_axi_state state; @@ -470,6 +476,7 @@ struct msm_vfe_axi_stream { uint32_t vfe_mask; uint32_t composite_irq[MSM_ISP_COMP_IRQ_MAX]; int lpm_mode; + struct msm_isp_pending_buf_info pending_buf_info; }; struct msm_vfe_axi_composite_info { @@ -845,6 +852,9 @@ struct vfe_device { /* total bandwidth per vfe */ uint64_t total_bandwidth; struct isp_kstate *isp_page; + + /* irq info */ + uint32_t irq_sof_id; }; struct vfe_parent_device { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 1ded01a81754..d57cdf581183 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, 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 @@ -709,8 +709,10 @@ void msm_isp47_preprocess_camif_irq(struct vfe_device *vfe_dev, { if (irq_status0 & BIT(3)) vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = false; - if (irq_status0 & BIT(0)) + if (irq_status0 & BIT(0)) { vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = true; + vfe_dev->irq_sof_id++; + } } void msm_vfe47_reg_update(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 4d4fd78c6a6e..5d48c7b2ed40 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -16,9 +16,11 @@ #include "msm_isp_stats_util.h" #include "msm_isp_axi_util.h" #include "msm_isp48.h" +#include "trace/events/msm_cam.h" #define HANDLE_TO_IDX(handle) (handle & 0xFF) #define ISP_SOF_DEBUG_COUNT 0 +#define OTHER_VFE(vfe_id) (vfe_id == ISP_VFE0 ? ISP_VFE1 : ISP_VFE0) #ifdef CONFIG_MSM_AVTIMER static struct avtimer_fptr_t avtimer_func; @@ -30,6 +32,13 @@ static void __msm_isp_axi_stream_update( struct msm_vfe_axi_stream *stream_info, struct msm_isp_timestamp *ts); +static int msm_isp_process_done_buf(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf, + struct timeval *time_stamp, uint32_t frame_id); +static void msm_isp_free_pending_buffer( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + struct msm_isp_timestamp *ts); static int msm_isp_update_stream_bandwidth( struct msm_vfe_axi_stream *stream_info, int enable); @@ -617,11 +626,9 @@ static void msm_isp_update_framedrop_reg(struct msm_vfe_axi_stream *stream_info, MSM_VFE_STREAM_STOP_PERIOD; } - if (stream_info->undelivered_request_cnt > 0 && - drop_reconfig != 1) + if (stream_info->undelivered_request_cnt > 0) stream_info->current_framedrop_period = MSM_VFE_STREAM_STOP_PERIOD; - /* * re-configure the period pattern, only if it's not already * set to what we want @@ -669,12 +676,29 @@ void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev, case MSM_ISP_COMP_IRQ_REG_UPD: stream_info->activated_framedrop_period = stream_info->requested_framedrop_period; + /* Free Pending Buffers which are backed-up due to + * delay in RUP from userspace to Avoid pageFault + */ + msm_isp_free_pending_buffer(vfe_dev, stream_info, ts); __msm_isp_axi_stream_update(stream_info, ts); break; case MSM_ISP_COMP_IRQ_EPOCH: - if (stream_info->state == ACTIVE) + if (stream_info->state == ACTIVE) { + struct vfe_device *temp = NULL; + struct msm_vfe_common_dev_data *c_data; + uint32_t drop_reconfig = + vfe_dev->isp_page->drop_reconfig; + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0) { + c_data = vfe_dev->common_data; + temp = c_data->dual_vfe_res->vfe_dev[ + ISP_VFE1]; + drop_reconfig = + temp->isp_page->drop_reconfig; + } msm_isp_update_framedrop_reg(stream_info, - vfe_dev->isp_page->drop_reconfig); + drop_reconfig); + } break; default: WARN(1, "Invalid irq %d\n", irq); @@ -1050,8 +1074,12 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, vfe_dev->isp_raw2_debug++; } - ISP_DBG("%s: vfe %d frame_src %d\n", __func__, - vfe_dev->pdev->id, frame_src); + ISP_DBG("%s: vfe %d frame_src %d frameid %d\n", __func__, + vfe_dev->pdev->id, frame_src, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); + trace_msm_cam_isp_status_dump("SOFNOTIFY:", vfe_dev->pdev->id, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, + 0, 0); /* * Cannot support dual_cam and framedrop same time in union. @@ -1567,6 +1595,40 @@ static void msm_isp_axi_stream_enable_cfg( } } +static void msm_isp_free_pending_buffer( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + struct msm_isp_timestamp *ts) +{ + struct timeval *time_stamp; + struct msm_isp_buffer *done_buf = NULL; + uint32_t frame_id; + int rc; + + if (!stream_info->controllable_output || + !stream_info->pending_buf_info.is_buf_done_pending) { + return; + } + + if (vfe_dev->vt_enable) { + msm_isp_get_avtimer_ts(ts); + time_stamp = &ts->vt_time; + } else { + time_stamp = &ts->buf_time; + } + + done_buf = stream_info->pending_buf_info.buf; + frame_id = stream_info->pending_buf_info.frame_id; + if (done_buf) { + rc = msm_isp_process_done_buf(vfe_dev, stream_info, + done_buf, time_stamp, frame_id); + if (rc == 0) { + stream_info->pending_buf_info.buf = NULL; + stream_info->pending_buf_info.is_buf_done_pending = 0; + } + } +} + static void __msm_isp_axi_stream_update( struct msm_vfe_axi_stream *stream_info, struct msm_isp_timestamp *ts) @@ -2032,6 +2094,8 @@ static int msm_isp_cfg_ping_pong_address( if (!buf) { msm_isp_cfg_stream_scratch(stream_info, pingpong_status); + if (stream_info->controllable_output) + return 1; return 0; } @@ -2118,7 +2182,6 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev, uint32_t buf_src; uint8_t drop_frame = 0; struct msm_isp_bufq *bufq = NULL; - memset(&buf_event, 0, sizeof(buf_event)); if (stream_idx >= VFE_AXI_SRC_MAX) { @@ -2448,6 +2511,7 @@ static void msm_isp_input_enable(struct vfe_device *vfe_dev, continue; /* activate the input since it is deactivated */ axi_data->src_info[i].frame_id = 0; + vfe_dev->irq_sof_id = 0; if (axi_data->src_info[i].input_mux != EXTERNAL_READ) axi_data->src_info[i].active = 1; if (i >= VFE_RAW_0 && sync_frame_id_src) { @@ -2710,7 +2774,11 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, struct msm_isp_timestamp timestamp; struct msm_vfe_frame_request_queue *queue_req; unsigned long flags; + uint32_t pingpong_status; int vfe_idx; + uint32_t pingpong_bit = 0; + uint32_t frame_id = 0; + struct timeval *time_stamp; if (!reset_cmd) { pr_err("%s: NULL pointer reset cmd %pK\n", __func__, reset_cmd); @@ -2719,6 +2787,7 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, } msm_isp_get_timestamp(×tamp, vfe_dev); + time_stamp = ×tamp.buf_time; for (i = 0; i < VFE_AXI_SRC_MAX; i++) { stream_info = msm_isp_get_stream_common_data( @@ -2741,6 +2810,28 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, /* set ping pong to scratch before flush */ spin_lock_irqsave(&stream_info->lock, flags); + frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; + if (stream_info->controllable_output && + stream_info->undelivered_request_cnt > 0) { + pingpong_status = VFE_PING_FLAG; + pingpong_bit = (~(pingpong_status >> + stream_info->wm[0][0]) & 0x1); + if (stream_info->buf[pingpong_bit] != NULL) { + msm_isp_process_done_buf(vfe_dev, stream_info, + stream_info->buf[pingpong_bit], + time_stamp, + frame_id); + } + pingpong_status = VFE_PONG_FLAG; + pingpong_bit = (~(pingpong_status >> + stream_info->wm[0][0]) & 0x1); + if (stream_info->buf[pingpong_bit] != NULL) { + msm_isp_process_done_buf(vfe_dev, stream_info, + stream_info->buf[pingpong_bit], + time_stamp, + frame_id); + } + } msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG); msm_isp_cfg_stream_scratch(stream_info, @@ -2792,6 +2883,7 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, axi_data->src_info[SRC_TO_INTF(stream_info-> stream_src)].frame_id = reset_cmd->frame_id; + temp_vfe_dev->irq_sof_id = reset_cmd->frame_id; } msm_isp_reset_burst_count_and_frame_drop( vfe_dev, stream_info); @@ -3064,6 +3156,12 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG); msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); stream_info->undelivered_request_cnt = 0; + if (stream_info->controllable_output && + stream_info->pending_buf_info.is_buf_done_pending) { + msm_isp_free_pending_buffer(vfe_dev, stream_info, + ×tamp); + stream_info->pending_buf_info.is_buf_done_pending = 0; + } for (k = 0; k < stream_info->num_isp; k++) { vfe_dev = stream_info->vfe_dev[k]; if (stream_info->num_planes > 1) @@ -3226,7 +3324,6 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, mutex_unlock(&vfe_dev_ioctl->buf_mgr->lock); goto error; } - msm_isp_calculate_bandwidth(stream_info); for (k = 0; k < stream_info->num_isp; k++) { msm_isp_get_stream_wm_mask(stream_info->vfe_dev[k], @@ -3242,9 +3339,8 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, msm_isp_reset_framedrop(vfe_dev_ioctl, stream_info); rc = msm_isp_init_stream_ping_pong_reg(stream_info); if (rc < 0) { - pr_err("%s: No buffer for stream%d\n", __func__, - HANDLE_TO_IDX( - stream_cfg_cmd->stream_handle[i])); + pr_err("%s: No buffer for stream%x\n", __func__, + stream_info->stream_id); spin_unlock_irqrestore(&stream_info->lock, flags); mutex_unlock(&vfe_dev_ioctl->buf_mgr->lock); goto error; @@ -3573,20 +3669,26 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, */ if (vfe_dev->axi_data.src_info[frame_src].active && frame_src == VFE_PIX_0 && - vfe_dev->axi_data.src_info[frame_src].accept_frame == false) { - pr_debug("%s:%d invalid time to request frame %d\n", + vfe_dev->axi_data.src_info[frame_src].accept_frame == false && + (stream_info->undelivered_request_cnt <= + MAX_BUFFERS_IN_HW) + ) { + pr_debug("%s:%d invalid time to request frame %d try drop_reconfig\n", __func__, __LINE__, frame_id); vfe_dev->isp_page->drop_reconfig = 1; + return 0; } else if ((vfe_dev->axi_data.src_info[frame_src].active) && - (frame_id == - vfe_dev->axi_data.src_info[frame_src].frame_id) && + ((frame_id == + vfe_dev->axi_data.src_info[frame_src].frame_id) || + (frame_id == vfe_dev->irq_sof_id)) && (stream_info->undelivered_request_cnt <= MAX_BUFFERS_IN_HW)) { vfe_dev->isp_page->drop_reconfig = 1; - pr_debug("%s: vfe_%d request_frame %d cur frame id %d pix %d\n", + pr_debug("%s: vfe_%d request_frame %d cur frame id %d pix %d try drop_reconfig\n", __func__, vfe_dev->pdev->id, frame_id, vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, vfe_dev->axi_data.src_info[VFE_PIX_0].active); + return 0; } else if ((vfe_dev->axi_data.src_info[frame_src].active && (frame_id != vfe_dev->axi_data.src_info[frame_src].frame_id + vfe_dev-> axi_data.src_info[frame_src].sof_counter_step)) || @@ -3607,19 +3709,18 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, if ((frame_src == VFE_PIX_0) && !stream_info->undelivered_request_cnt && MSM_VFE_STREAM_STOP_PERIOD != stream_info->activated_framedrop_period) { + /* wm is reloaded if undelivered_request_cnt is zero. + * As per the hw behavior wm should be disabled or skip writing + * before reload happens other wise wm could start writing from + * middle of the frame and could result in image corruption. + * instead of dropping frame in this error scenario use + * drop_reconfig flag to process the request in next sof. + */ pr_debug("%s:%d vfe %d frame_id %d prev_pattern %x stream_id %x\n", __func__, __LINE__, vfe_dev->pdev->id, frame_id, stream_info->activated_framedrop_period, stream_info->stream_id); - - rc = msm_isp_return_empty_buffer(vfe_dev, stream_info, - user_stream_id, frame_id, buf_index, frame_src); - if (rc < 0) - pr_err("%s:%d failed: return_empty_buffer src %d\n", - __func__, __LINE__, frame_src); - stream_info->current_framedrop_period = - MSM_VFE_STREAM_STOP_PERIOD; - msm_isp_cfg_framedrop_reg(stream_info); + vfe_dev->isp_page->drop_reconfig = 1; return 0; } @@ -3689,11 +3790,16 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, if (rc) { spin_unlock_irqrestore(&stream_info->lock, flags); stream_info->undelivered_request_cnt--; - pr_err_ratelimited("%s:%d fail to cfg HAL buffer\n", - __func__, __LINE__); - queue_req->cmd_used = 0; - list_del(&queue_req->list); - stream_info->request_q_cnt--; + queue_req = list_first_entry_or_null( + &stream_info->request_q, + struct msm_vfe_frame_request_queue, list); + if (queue_req) { + queue_req->cmd_used = 0; + list_del(&queue_req->list); + stream_info->request_q_cnt--; + } + pr_err_ratelimited("%s:%d fail to cfg HAL buffer stream %x\n", + __func__, __LINE__, stream_info->stream_id); return rc; } @@ -3728,11 +3834,16 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, stream_info->undelivered_request_cnt--; spin_unlock_irqrestore(&stream_info->lock, flags); + queue_req = list_first_entry_or_null( + &stream_info->request_q, + struct msm_vfe_frame_request_queue, list); + if (queue_req) { + queue_req->cmd_used = 0; + list_del(&queue_req->list); + stream_info->request_q_cnt--; + } pr_err_ratelimited("%s:%d fail to cfg HAL buffer\n", __func__, __LINE__); - queue_req->cmd_used = 0; - list_del(&queue_req->list); - stream_info->request_q_cnt--; return rc; } } else { @@ -4225,6 +4336,8 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, struct timeval *time_stamp; uint32_t frame_id, buf_index = -1; int vfe_idx; + struct vfe_device *temp_dev; + int other_vfe_id; if (!ts) { pr_err("%s: Error! Invalid argument\n", __func__); @@ -4322,15 +4435,45 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, ISP_DBG("%s: Error configuring ping_pong\n", __func__); } else if (done_buf && (done_buf->is_drop_reconfig != 1)) { + int32_t frame_id_diff; + /* irq_sof should be always >= tasklet SOF id + * For dual camera usecase irq_sof could be behind + * as software frameid sync logic epoch event could + * update slave frame id so update if irqsof < tasklet sof + */ + if (vfe_dev->irq_sof_id < frame_id) + vfe_dev->irq_sof_id = frame_id; + + frame_id_diff = vfe_dev->irq_sof_id - frame_id; + if (stream_info->controllable_output && frame_id_diff > 1) { + pr_err_ratelimited("%s: scheduling problem do recovery irq_sof_id %d frame_id %d\n", + __func__, vfe_dev->irq_sof_id, frame_id); + /* scheduling problem need to do recovery */ + stream_info->buf[pingpong_bit] = done_buf; + spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_PING_PONG_MISMATCH); + return; + } msm_isp_cfg_stream_scratch(stream_info, pingpong_status); } - if (!done_buf) { if (stream_info->buf_divert) { vfe_dev->error_info.stream_framedrop_count[ stream_info->bufq_handle[ VFE_BUF_QUEUE_DEFAULT] & 0xFF]++; vfe_dev->error_info.framedrop_flag = 1; + if (vfe_dev->is_split) { + other_vfe_id = OTHER_VFE(vfe_dev->pdev->id); + temp_dev = + vfe_dev->common_data->dual_vfe_res->vfe_dev[ + other_vfe_id]; + temp_dev->error_info.stream_framedrop_count[ + stream_info->bufq_handle[ + VFE_BUF_QUEUE_DEFAULT] & 0xFF]++; + temp_dev->error_info.framedrop_flag = 1; + } + } spin_unlock_irqrestore(&stream_info->lock, flags); return; @@ -4373,11 +4516,28 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, * then dont issue buf-done for current buffer */ done_buf->is_drop_reconfig = 0; + if (!stream_info->buf[pingpong_bit]) { + /* samebuffer is not re-programeed so write scratch */ + msm_isp_cfg_stream_scratch(stream_info, + pingpong_status); + } spin_unlock_irqrestore(&stream_info->lock, flags); } else { + /* If there is no regupdate from userspace then dont + * free buffer immediately, delegate it to RegUpdateAck + */ + if (stream_info->controllable_output && + !(vfe_dev->reg_update_requested & + BIT((uint32_t)VFE_PIX_0))) { + stream_info->pending_buf_info.is_buf_done_pending = 1; + stream_info->pending_buf_info.buf = done_buf; + stream_info->pending_buf_info.frame_id = frame_id; + } spin_unlock_irqrestore(&stream_info->lock, flags); - msm_isp_process_done_buf(vfe_dev, stream_info, - done_buf, time_stamp, frame_id); + if (stream_info->pending_buf_info.is_buf_done_pending != 1) { + msm_isp_process_done_buf(vfe_dev, stream_info, + done_buf, time_stamp, frame_id); + } } } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c index b5a6f44f20fa..c237ad23b753 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, 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 @@ -1215,7 +1215,7 @@ static void msm_isp_update_rdi_output_count( for (i = 0; i < stream_cfg_cmd->num_streams; i++) { if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) - > MAX_NUM_STREAM) + >= MAX_NUM_STREAM) return; stream_info = &axi_data->stream_info[ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index e67112267a2e..6d940b533829 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, 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 @@ -2114,6 +2114,9 @@ static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev, return; } atomic_add(1, &vfe_dev->irq_cnt); + trace_msm_cam_isp_status_dump("VFE_IRQ:", vfe_dev->pdev->id, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, + irq_status0, irq_status1); queue_cmd->vfeInterruptStatus0 = irq_status0; queue_cmd->vfeInterruptStatus1 = irq_status1; queue_cmd->vfe_pingpong_status = ping_pong_status; @@ -2213,6 +2216,9 @@ void msm_isp_do_tasklet(unsigned long data) atomic_sub(1, &vfe_dev->irq_cnt); msm_isp_prepare_tasklet_debug_info(vfe_dev, irq_status0, irq_status1, ts); + trace_msm_cam_isp_status_dump("VFE_TASKLET:", vfe_dev->pdev->id, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, + irq_status0, irq_status1); irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops; irq_ops->process_reset_irq(vfe_dev, irq_status0, irq_status1); @@ -2316,7 +2322,7 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) vfe_dev->isp_raw0_debug = 0; vfe_dev->isp_raw1_debug = 0; vfe_dev->isp_raw2_debug = 0; - + vfe_dev->irq_sof_id = 0; if (vfe_dev->hw_info->vfe_ops.core_ops.init_hw(vfe_dev) < 0) { pr_err("%s: init hardware failed\n", __func__); vfe_dev->vfe_open_cnt--; diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c index 0811efbcb130..a366b0115515 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, 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 @@ -297,6 +297,7 @@ static struct platform_driver msm_jpeg_driver = { .name = "msm_jpeg", .owner = THIS_MODULE, .of_match_table = msm_jpeg_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c index ea828324e892..0592526119b5 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, 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 @@ -907,7 +907,7 @@ int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, void msm_jpeg_io_dump(void *base, int size) { - char line_str[128]; + char line_str[140]; void __iomem *addr = (void __iomem *)base; int i; void __iomem *p = addr; @@ -919,10 +919,10 @@ void msm_jpeg_io_dump(void *base, int size) JPEG_DBG_HIGH("%s:%d] %pK %d", __func__, __LINE__, addr, size); line_str[0] = '\0'; - for (i = 0; i < size/4; i++) { + for (i = 0; i < size; i = i+4) { if (i % 4 == 0) { used = snprintf(line_str + offset, - sizeof_line_str - offset, "%pK ", p); + sizeof_line_str - offset, "%pK", p+i); if ((used < min_range) || (offset + used >= sizeof_line_str)) { JPEG_PR_ERR("%s\n", line_str); @@ -932,9 +932,9 @@ void msm_jpeg_io_dump(void *base, int size) offset += used; } } - data = msm_camera_io_r(p++); + data = msm_camera_io_r(p+i); used = snprintf(line_str + offset, - sizeof_line_str - offset, "%08x ", data); + sizeof_line_str - offset, " - %08x ", data); if ((used < min_range) || (offset + used >= sizeof_line_str)) { JPEG_PR_ERR("%s\n", line_str); @@ -943,11 +943,6 @@ void msm_jpeg_io_dump(void *base, int size) } else { offset += used; } - if ((i + 1) % 4 == 0) { - JPEG_DBG_HIGH("%s\n", line_str); - line_str[0] = '\0'; - offset = 0; - } } if (line_str[0] != '\0') JPEG_DBG_HIGH("%s\n", line_str); diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c index 3daee21325c4..0335c406a7ad 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 2018-2019, 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 @@ -1536,6 +1536,46 @@ long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev, return rc; } +static void msm_jpeg_iommu_fault_handler (struct iommu_domain *domain, + struct device *dev, unsigned long iova, int flags, void *token) +{ + struct msm_jpeg_device *pgmn_dev; + + if (token) { + pgmn_dev = token; + JPEG_PR_ERR("%s: core type %d addr 0x%lx\n", + __func__, pgmn_dev->core_type, iova); + JPEG_PR_ERR("%s: FE ion_fd %d y_addr 0x%x y_len %d\n", + __func__, + pgmn_dev->fe_pingpong_buf.buf[1].ion_fd, + pgmn_dev->fe_pingpong_buf.buf[1].y_buffer_addr, + pgmn_dev->fe_pingpong_buf.buf[1].y_len); + JPEG_PR_ERR("%s: FE cbcr_addr %x cbcr_len %d\n", + __func__, + pgmn_dev->fe_pingpong_buf.buf[1].cbcr_buffer_addr, + pgmn_dev->fe_pingpong_buf.buf[1].cbcr_len); + JPEG_PR_ERR("%s: FE pln2_addr %x pln2_len %d frame_len %d\n", + __func__, + pgmn_dev->fe_pingpong_buf.buf[1].pln2_addr, + pgmn_dev->fe_pingpong_buf.buf[1].pln2_len, + pgmn_dev->fe_pingpong_buf.buf[1].framedone_len); + JPEG_PR_ERR("%s: WE ion_fd %d y_addr 0x%x y_len %d\n", + __func__, + pgmn_dev->we_pingpong_buf.buf[0].ion_fd, + pgmn_dev->we_pingpong_buf.buf[0].y_buffer_addr, + pgmn_dev->we_pingpong_buf.buf[0].y_len); + JPEG_PR_ERR("%s: WE cbcr_addr %x cbcr_len %d\n", + __func__, + pgmn_dev->we_pingpong_buf.buf[0].cbcr_buffer_addr, + pgmn_dev->we_pingpong_buf.buf[0].cbcr_len); + JPEG_PR_ERR("%s: WE pln2_addr %x pln2_len %d frame_len %d\n", + __func__, + pgmn_dev->we_pingpong_buf.buf[0].pln2_addr, + pgmn_dev->we_pingpong_buf.buf[0].pln2_len, + pgmn_dev->we_pingpong_buf.buf[0].framedone_len); + } +} + int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev) { int rc = 0; @@ -1569,6 +1609,12 @@ int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev) goto err_smmu; } + cam_smmu_reg_client_page_fault_handler( + pgmn_dev->iommu_hdl, + msm_jpeg_iommu_fault_handler, + NULL, + pgmn_dev); + /* setup all the resources for the jpeg driver */ rc = msm_jpeg_platform_setup(pgmn_dev); if (rc < 0) { diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c index dc316b1006e3..bc3c5c631a30 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2019, 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 @@ -892,8 +892,12 @@ static int msm_jpegdma_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh); + int ret; - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); + mutex_lock(&ctx->lock); + ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); + mutex_unlock(&ctx->lock); + return ret; } /* @@ -908,13 +912,15 @@ static int msm_jpegdma_streamon(struct file *file, struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh); int ret; - if (!msm_jpegdma_config_ok(ctx)) + mutex_lock(&ctx->lock); + if (!msm_jpegdma_config_ok(ctx)) { + mutex_unlock(&ctx->lock); return -EINVAL; - + } ret = v4l2_m2m_streamon(file, ctx->m2m_ctx, buf_type); if (ret < 0) dev_err(ctx->jdma_device->dev, "Stream on fail\n"); - + mutex_unlock(&ctx->lock); return ret; } @@ -1488,6 +1494,7 @@ static struct platform_driver jpegdma_driver = { .name = MSM_JPEGDMA_DRV_NAME, .owner = THIS_MODULE, .of_match_table = msm_jpegdma_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 85ca27540c3e..576d5d6742dd 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, 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 @@ -1453,8 +1453,9 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) VBIF_CLIENT_CPP, cpp_vbif_error_handler); if (cpp_dev->cpp_open_cnt == 1) { - rc = cpp_init_hardware(cpp_dev); + rc = cpp_init_mem(cpp_dev); if (rc < 0) { + pr_err("Error: init memory fail\n"); cpp_dev->cpp_open_cnt--; cpp_dev->cpp_subscribe_list[i].active = 0; cpp_dev->cpp_subscribe_list[i].vfh = NULL; @@ -1462,16 +1463,14 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return rc; } - rc = cpp_init_mem(cpp_dev); + rc = cpp_init_hardware(cpp_dev); if (rc < 0) { - pr_err("Error: init memory fail\n"); cpp_dev->cpp_open_cnt--; cpp_dev->cpp_subscribe_list[i].active = 0; cpp_dev->cpp_subscribe_list[i].vfh = NULL; mutex_unlock(&cpp_dev->mutex); return rc; } - cpp_dev->state = CPP_STATE_IDLE; CPP_DBG("Invoking msm_ion_client_create()\n"); @@ -1491,6 +1490,8 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { uint32_t i; int rc = -1; + int counter = 0; + u32 result = 0; struct cpp_device *cpp_dev = NULL; struct msm_device_queue *processing_q = NULL; struct msm_device_queue *eventData_q = NULL; @@ -1569,6 +1570,61 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88)); pr_debug("DEBUG_R1: 0x%x\n", msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C)); + + /* Update bandwidth usage to enable AXI/ABH clock, + * which will help to reset CPP AXI.Bandwidth will be + * made zero at cpp_release_hardware. + */ + msm_cpp_update_bandwidth(cpp_dev, 0x1000, 0x1000); + + /* mask IRQ status */ + msm_camera_io_w(0xB, cpp_dev->cpp_hw_base + 0xC); + + /* clear IRQ status */ + msm_camera_io_w(0xFFFFF, cpp_dev->cpp_hw_base + 0x14); + + /* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/ + msm_camera_io_w(0x1, cpp_dev->cpp_hw_base + 0x16C); + + while (counter < MSM_CPP_POLL_RETRIES) { + result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10); + if (result & 0x2) + break; + /* + * Below usleep values are chosen based on experiments + * and this was the smallest number which works. This + * sleep is needed to leave enough time for hardware + * to update status register. + */ + usleep_range(200, 250); + counter++; + } + + pr_debug("CPP AXI done counter %d result 0x%x\n", + counter, result); + + /* clear IRQ status */ + msm_camera_io_w(0xFFFFF, cpp_dev->cpp_hw_base + 0x14); + counter = 0; + /* MMSS_A_CPP_RST_CMD_0 = 0x8, firmware reset = 0x3DF77 */ + msm_camera_io_w(0x3DF77, cpp_dev->cpp_hw_base + 0x8); + + while (counter < MSM_CPP_POLL_RETRIES) { + result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10); + if (result & 0x1) + break; + /* + * Below usleep values are chosen based on experiments + * and this was the smallest number which works. This + * sleep is needed to leave enough time for hardware + * to update status register. + */ + usleep_range(200, 250); + counter++; + } + pr_debug("CPP reset done counter %d result 0x%x\n", + counter, result); + msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); msm_cpp_clear_timer(cpp_dev); cpp_release_hardware(cpp_dev); @@ -4765,6 +4821,7 @@ static struct platform_driver cpp_driver = { .name = MSM_CPP_DRV_NAME, .owner = THIS_MODULE, .of_match_table = msm_cpp_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h index d20d217bce91..d891b0bfd96b 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, 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 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 c045eda41385..2806132c09b8 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2019, 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 @@ -1585,6 +1585,13 @@ static int msm_actuator_close(struct v4l2_subdev *sd, } kfree(a_ctrl->i2c_reg_tbl); a_ctrl->i2c_reg_tbl = NULL; + if (a_ctrl->actuator_state == ACT_OPS_ACTIVE) { + rc = msm_actuator_power_down(a_ctrl); + if (rc < 0) { + pr_err("%s:%d Actuator Power down failed\n", + __func__, __LINE__); + } + } a_ctrl->actuator_state = ACT_DISABLE_STATE; mutex_unlock(a_ctrl->actuator_mutex); CDBG("Exit\n"); diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h index 90b8e1cae850..598e541edc1d 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016,2018-2019, 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 @@ -51,7 +51,7 @@ static struct csiphy_reg_3ph_parms_t csiphy_v3_5_3ph = { {0x148, 0xFE}, {0x14C, 0x1}, {0x154, 0x0}, - {0x15C, 0x33}, + {0x15C, 0x23}, {0x160, ULPM_WAKE_UP_TIMER_MODE}, {0x164, 0x48}, {0x168, 0xA0}, diff --git a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm.h b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm.h index ff8be3570bc5..178d33dee308 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm.h +++ b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -251,6 +251,17 @@ struct cam_cdm_intf_mgr { int32_t refcount; }; +/** + * struct cam_cdm_debugfs_entry : debugfs entry struct + * + * @dentry : entry of debugfs + * @dump_register : flag to dump registers + */ +struct cam_cdm_debugfs_entry { + struct dentry *dentry; + bool dump_register; +}; + int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw, struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, uint32_t *index); diff --git a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c index c8c64b49d686..af83aba7a0bc 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c @@ -38,6 +38,8 @@ static void cam_hw_cdm_work(struct work_struct *work); +static struct cam_cdm_debugfs_entry debugfs_entry; + /* DT match table entry for all CDM variants*/ static const struct of_device_id msm_cam_hw_cdm_dt_match[] = { { @@ -69,6 +71,31 @@ int cam_hw_cdm_bl_fifo_pending_bl_rb(struct cam_hw_info *cdm_hw, return rc; } +static int cam_hw_cdm_create_debugfs_entry(void) +{ + int rc = 0; + + debugfs_entry.dentry = debugfs_create_dir("camera_cdm", NULL); + if (!debugfs_entry.dentry) + return -ENOMEM; + + if (!debugfs_create_bool("dump_register", + 0644, + debugfs_entry.dentry, + &debugfs_entry.dump_register)) { + CAM_ERR(CAM_CDM, + "failed to create dump_register entry"); + rc = -ENOMEM; + goto err; + } + + return rc; +err: + debugfs_remove_recursive(debugfs_entry.dentry); + debugfs_entry.dentry = NULL; + return rc; +} + static int cam_hw_cdm_enable_bl_done_irq(struct cam_hw_info *cdm_hw, bool enable) { @@ -186,6 +213,9 @@ void cam_hw_cdm_dump_core_debug_registers( { uint32_t dump_reg, core_dbg, loop_cnt; + if (!debugfs_entry.dump_register) + return; + mutex_lock(&cdm_hw->hw_mutex); cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_EN, &dump_reg); CAM_ERR(CAM_CDM, "CDM HW core status=%x", dump_reg); @@ -1020,6 +1050,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev) } cdm_hw->open_count--; mutex_unlock(&cdm_hw->hw_mutex); + cam_hw_cdm_create_debugfs_entry(); CAM_DBG(CAM_CDM, "CDM%d probe successful", cdm_hw_intf->hw_idx); diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c index 330491256754..7600cbb77cee 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c @@ -574,7 +574,7 @@ int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, req_hdl_param.media_entity_flag = 0; req_hdl_param.priv = ctx; req_hdl_param.ops = ctx->crm_ctx_intf; - + req_hdl_param.dev_id = ctx->dev_id; ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); if (ctx->dev_hdl <= 0) { rc = -EFAULT; diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c index a05901afba71..4276b356da73 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c @@ -568,7 +568,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( struct cam_cpas_axi_port *curr_axi_port = NULL; struct cam_cpas_axi_port *temp_axi_port = NULL; uint64_t required_camnoc_bw = 0; - int32_t clk_rate = 0; + int64_t clk_rate = 0; list_for_each_entry_safe(curr_axi_port, temp_axi_port, &cpas_core->axi_ports_list_head, sibling_port) { @@ -596,13 +596,13 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width; - CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", + CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %lld", required_camnoc_bw, clk_rate); rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); if (rc) CAM_ERR(CAM_CPAS, - "Failed in setting camnoc axi clk %llu %d %d", + "Failed in setting camnoc axi clk %llu %lld %d", required_camnoc_bw, clk_rate, rc); } diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c index 49774f24ba20..719fb12d7353 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -415,6 +415,12 @@ static void cam_cpastop_work(struct work_struct *work) return; } + mutex_lock(&cpas_hw->hw_mutex); + if (cpas_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_CPAS, "CPAS CORE is off"); + mutex_unlock(&cpas_hw->hw_mutex); + return; + } for (i = 0; i < camnoc_info->irq_err_size; i++) { if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) && (camnoc_info->irq_err[i].enable)) { @@ -460,6 +466,7 @@ static void cam_cpastop_work(struct work_struct *work) ~camnoc_info->irq_err[i].sbm_port; } } + mutex_unlock(&cpas_hw->hw_mutex); atomic_dec(&cpas_core->irq_count); wake_up(&cpas_core->irq_count_wq); CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count)); diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c index d4c9326ed5ab..083041c21dff 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -206,10 +206,6 @@ static const struct of_device_id cam_fd_hw_dt_match[] = { .compatible = "qcom,fd501", .data = &cam_fd_wrapper200_core501_info, }, - { - .compatible = "qcom,fd501", - .data = &cam_fd_wrapper200_core501_info, - }, {} }; MODULE_DEVICE_TABLE(of, cam_fd_hw_dt_match); diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/cam_icp_context.c b/drivers/media/platform/msm/camera_v3/cam_icp/cam_icp_context.c index 969f3f461b1f..15574ba6a3f1 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/cam_icp_context.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/cam_icp_context.c @@ -45,6 +45,14 @@ static int cam_icp_context_dump_active_request(void *data, unsigned long iova, return -EINVAL; } + mutex_lock(&ctx->ctx_mutex); + + if (ctx->state < CAM_CTX_ACQUIRED || ctx->state > CAM_CTX_ACTIVATED) { + CAM_ERR(CAM_ICP, "Invalid state icp ctx %d state %d", + ctx->ctx_id, ctx->state); + goto end; + } + CAM_INFO(CAM_ICP, "iommu fault for icp ctx %d state %d", ctx->ctx_id, ctx->state); @@ -63,6 +71,8 @@ static int cam_icp_context_dump_active_request(void *data, unsigned long iova, req->request_id, rc); } +end: + mutex_unlock(&ctx->ctx_mutex); return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_intf.h index 3d0ee725dcad..f3a0fe4343ac 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -38,6 +38,7 @@ struct hfi_mem { * @sfr_buf: buffer for subsystem failure reason[SFR] * @sec_heap: secondary heap hfi memory for firmware * @qdss: qdss mapped memory for fw + * @io_mem: io memory info * @icp_base: icp base address */ struct hfi_mem_info { @@ -49,6 +50,7 @@ struct hfi_mem_info { struct hfi_mem sec_heap; struct hfi_mem shmem; struct hfi_mem qdss; + struct hfi_mem io_mem; void __iomem *icp_base; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_reg.h index f652cfa3d2a3..2579153d600b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_reg.h +++ b/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, 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 @@ -42,8 +42,11 @@ #define HFI_REG_UNCACHED_HEAP_PTR 0x5C #define HFI_REG_UNCACHED_HEAP_SIZE 0x60 #define HFI_REG_QDSS_IOVA 0x6C -#define HFI_REG_QDSS_IOVA_SIZE 0x70 #define HFI_REG_SFR_PTR 0x68 +#define HFI_REG_QDSS_IOVA_SIZE 0x70 +#define HFI_REG_IO_REGION_IOVA 0x74 +#define HFI_REG_IO_REGION_SIZE 0x78 + /* end of ICP CSR registers */ /* flags for ICP CSR registers */ diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_sys_defs.h index 311886ffd6da..d60a25e8b925 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_sys_defs.h +++ b/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_sys_defs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -215,6 +215,27 @@ #define HFI_DEV_VERSION_MAX 0x5 +/* General errors and HFI Specific errors. */ +enum hfi_errors { + CAMERAICP_SUCCESS, + CAMERAICP_EFAILED, + CAMERAICP_ENOMEMORY, + CAMERAICP_EBADSTATE, + CAMERAICP_EBADPARM, + CAMERAICP_EBADITEM, + CAMERAICP_EINVALIDFORMAT, + CAMERAICP_EUNSUPPORTED, + CAMERAICP_EOUTOFBOUND, + CAMERAICP_ETIMEDOUT, + CAMERAICP_EABORTED, + CAMERAICP_EHWVIOLATION, + CAMERAICP_ECDMERROR, + CAMERAICP_HFI_ERR_COMMAND_SIZE = 1000, + CAMERAICP_HFI_ERR_MESSAGE_SIZE, + CAMERAICP_HFI_QUEUE_EMPTY, + CAMERAICP_HFI_QUEUE_FULL, +}; + /** * start of sys command packet types * These commands are used to get system level information diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c b/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c index 74b7aabb7655..e1b0754255a7 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c @@ -637,6 +637,10 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem, icp_base + HFI_REG_QDSS_IOVA); cam_io_w_mb((uint32_t)hfi_mem->qdss.len, icp_base + HFI_REG_QDSS_IOVA_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.iova, + icp_base + HFI_REG_IO_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, + icp_base + HFI_REG_IO_REGION_SIZE); return rc; } @@ -825,6 +829,10 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, icp_base + HFI_REG_QDSS_IOVA); cam_io_w_mb((uint32_t)hfi_mem->qdss.len, icp_base + HFI_REG_QDSS_IOVA_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.iova, + icp_base + HFI_REG_IO_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, + icp_base + HFI_REG_IO_REGION_SIZE); hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION); diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index ae7d446eb757..cfc474afc633 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -64,6 +64,37 @@ static struct cam_icp_hw_mgr icp_hw_mgr; static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl); +static int cam_icp_dump_io_cfg(struct cam_icp_hw_ctx_data *ctx_data, + int32_t buf_handle) +{ + uintptr_t vaddr_ptr; + uint32_t *ptr; + size_t len; + int rc, i; + char buf[512]; + int used = 0; + + rc = cam_mem_get_cpu_buf(buf_handle, &vaddr_ptr, &len); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get io_cfg buf address for %d", + ctx_data->ctx_id); + return rc; + } + + len = len / sizeof(uint32_t); + ptr = (uint32_t *)vaddr_ptr; + for (i = 0; i < len; i++) { + used += snprintf(buf + used, + sizeof(buf) - used, "0X%08X-", ptr[i]); + if (!(i % 8)) { + CAM_INFO(CAM_ICP, "%s: %s", __func__, buf); + used = 0; + } + } + + return rc; +} + static int cam_icp_send_ubwc_cfg(struct cam_icp_hw_mgr *hw_mgr) { struct cam_hw_intf *a5_dev_intf = NULL; @@ -1262,6 +1293,44 @@ end: return rc; } +static int cam_icp_mgr_ipe_bps_get_gdsc_control( + struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong"); + return -EINVAL; + } + + if (icp_hw_mgr.ipe_bps_pc_flag) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_POWER_COLLAPSE, + NULL, 0); + + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0); + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, + NULL, 0); + } + } + + return rc; +} + static int cam_icp_set_dbg_default_clk(void *data, u64 val) { icp_hw_mgr.icp_debug_clk = val; @@ -1532,7 +1601,69 @@ static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) return 0; } +static const char *cam_icp_error_handle_id_to_type( + uint32_t error_handle) +{ + const char *name = NULL; + switch (error_handle) { + case CAMERAICP_SUCCESS: + name = "SUCCESS"; + break; + case CAMERAICP_EFAILED: + name = "EFAILED"; + break; + case CAMERAICP_ENOMEMORY: + name = "ENOMEMORY"; + break; + case CAMERAICP_EBADSTATE: + name = "EBADSTATE"; + break; + case CAMERAICP_EBADPARM: + name = "EBADPARM"; + break; + case CAMERAICP_EBADITEM: + name = "EBADITEM"; + break; + case CAMERAICP_EINVALIDFORMAT: + name = "EINVALIDFORMAT"; + break; + case CAMERAICP_EUNSUPPORTED: + name = "EUNSUPPORTED"; + break; + case CAMERAICP_EOUTOFBOUND: + name = "EOUTOFBOUND"; + break; + case CAMERAICP_ETIMEDOUT: + name = "ETIMEDOUT"; + break; + case CAMERAICP_EABORTED: + name = "EABORTED"; + break; + case CAMERAICP_EHWVIOLATION: + name = "EHWVIOLATION"; + break; + case CAMERAICP_ECDMERROR: + name = "ECDMERROR"; + break; + case CAMERAICP_HFI_ERR_COMMAND_SIZE: + name = "HFI_ERR_COMMAND_SIZE"; + break; + case CAMERAICP_HFI_ERR_MESSAGE_SIZE: + name = "HFI_ERR_MESSAGE_SIZE"; + break; + case CAMERAICP_HFI_QUEUE_EMPTY: + name = "HFI_QUEUE_EMPTY"; + break; + case CAMERAICP_HFI_QUEUE_FULL: + name = "HFI_QUEUE_FULL"; + break; + default: + name = NULL; + break; + } + return name; +} static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr) { struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; @@ -1545,8 +1676,11 @@ static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr) ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) { - CAM_ERR(CAM_ICP, "failed with error : %u", - ioconfig_ack->err_type); + CAM_ERR(CAM_ICP, + "failed with err_no= [%u] err_type= [%s]", + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); cam_icp_mgr_handle_frame_process(msg_ptr, ICP_FRAME_PROCESS_FAILURE); return -EIO; @@ -1586,8 +1720,12 @@ static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr) ipe_config_ack = (struct hfi_msg_ipe_config *)(ioconfig_ack->msg_data); if (ipe_config_ack->rc) { - CAM_ERR(CAM_ICP, "rc = %d err = %u", - ipe_config_ack->rc, ioconfig_ack->err_type); + CAM_ERR(CAM_ICP, "rc = %d failed with\n" + "err_no = [%u] err_type = [%s]", + ipe_config_ack->rc, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); return -EIO; } ctx_data = (struct cam_icp_hw_ctx_data *) @@ -1752,9 +1890,13 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) complete(&ctx_data->wait_complete); - CAM_DBG(CAM_ICP, - "received IPE/BPS MAP ACK:ctx_state =%d err_status =%u", - ctx_data->state, ioconfig_ack->err_type); + CAM_DBG(CAM_ICP, "received IPE/BPS\n" + "MAP ACK:ctx_state =%d\n" + "failed with err_no = [%u] err_type = [%s]", + ctx_data->state, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); break; case HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP: ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; @@ -1762,9 +1904,13 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) complete(&ctx_data->wait_complete); - CAM_DBG(CAM_ICP, - "received IPE/BPS UNMAP ACK:ctx_state =%d err_status =%u", - ctx_data->state, ioconfig_ack->err_type); + CAM_DBG(CAM_ICP, + "received IPE/BPS UNMAP ACK:ctx_state =%d\n" + "failed with err_no = [%u] err_type = [%s]", + ctx_data->state, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); break; default: CAM_ERR(CAM_ICP, "Invalid opcode : %u", @@ -1786,27 +1932,31 @@ static int cam_icp_ipebps_reset(struct cam_icp_hw_mgr *hw_mgr) ipe1_dev_intf = hw_mgr->ipe1_dev_intf; bps_dev_intf = hw_mgr->bps_dev_intf; - rc = bps_dev_intf->hw_ops.process_cmd( - bps_dev_intf->hw_priv, - CAM_ICP_BPS_CMD_RESET, - NULL, 0); - if (rc) - CAM_ERR(CAM_ICP, "bps reset failed"); - - rc = ipe0_dev_intf->hw_ops.process_cmd( - ipe0_dev_intf->hw_priv, - CAM_ICP_IPE_CMD_RESET, - NULL, 0); - if (rc) - CAM_ERR(CAM_ICP, "ipe0 reset failed"); + if (hw_mgr->bps_ctxt_cnt) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "bps reset failed"); + } - if (ipe1_dev_intf) { - rc = ipe1_dev_intf->hw_ops.process_cmd( - ipe1_dev_intf->hw_priv, + if (hw_mgr->ipe_ctxt_cnt) { + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, CAM_ICP_IPE_CMD_RESET, NULL, 0); if (rc) - CAM_ERR(CAM_ICP, "ipe1 reset failed"); + CAM_ERR(CAM_ICP, "ipe0 reset failed"); + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "ipe1 reset failed"); + } } return 0; @@ -1827,6 +1977,7 @@ static int cam_icp_mgr_trigger_recovery(struct cam_icp_hw_mgr *hw_mgr) sfr_buffer = (struct sfr_buf *)icp_hw_mgr.hfi_mem.sfr_buf.kva; CAM_WARN(CAM_ICP, "SFR:%s", sfr_buffer->msg); + cam_icp_mgr_ipe_bps_get_gdsc_control(hw_mgr); cam_icp_ipebps_reset(hw_mgr); atomic_set(&hw_mgr->recovery, 1); @@ -2205,6 +2356,25 @@ static int cam_icp_allocate_qdss_mem(void) return rc; } +static int cam_icp_get_io_mem_info(void) +{ + int rc; + size_t len; + dma_addr_t iova; + + rc = cam_smmu_get_io_region_info(icp_hw_mgr.iommu_hdl, + &iova, &len); + if (rc) + return rc; + + icp_hw_mgr.hfi_mem.io_mem.iova_len = len; + icp_hw_mgr.hfi_mem.io_mem.iova_start = iova; + + CAM_DBG(CAM_ICP, "iova: %llx, len: %zu", iova, len); + + return rc; +} + static int cam_icp_allocate_hfi_mem(void) { int rc; @@ -2265,7 +2435,15 @@ static int cam_icp_allocate_hfi_mem(void) goto sec_heap_alloc_failed; } + rc = cam_icp_get_io_mem_info(); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get I/O region info"); + goto get_io_mem_failed; + } + return rc; +get_io_mem_failed: + cam_mem_mgr_free_memory_region(&icp_hw_mgr.hfi_mem.sec_heap); sec_heap_alloc_failed: cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sfr_buf); sfr_buf_alloc_failed: @@ -2484,6 +2662,14 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; + + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + + CAM_DBG(CAM_ICP, "IO region IOVA = %X length = %lld", + hfi_mem.io_mem.iova, + hfi_mem.io_mem.len); + return cam_hfi_resume(&hfi_mem, a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, hw_mgr->a5_jtag_debug); @@ -2864,6 +3050,9 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + return cam_hfi_init(0, &hfi_mem, a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, hw_mgr->a5_jtag_debug); @@ -4021,8 +4210,12 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, packet = prepare_args->packet; - if (cam_packet_util_validate_packet(packet, prepare_args->remain_len)) + if (cam_packet_util_validate_packet(packet, prepare_args->remain_len)) { + mutex_unlock(&ctx_data->ctx_mutex); + CAM_ERR(CAM_ICP, "ctx id: %u packet req id %lld validate fail", + ctx_data->ctx_id, packet->header.request_id); return -EINVAL; + } rc = cam_icp_mgr_pkt_validation(packet); if (rc) { @@ -4493,6 +4686,13 @@ static int cam_icp_get_acquire_info(struct cam_icp_hw_mgr *hw_mgr, return -EFAULT; } + /* To make sure num_out_res is same as allocated */ + if (ctx_data->icp_dev_acquire_info->num_out_res != + icp_dev_acquire_info.num_out_res) { + CAM_ERR(CAM_ICP, "num_out_res got changed"); + return -EFAULT; + } + CAM_DBG(CAM_ICP, "%x %x %x %x %x %x %x", ctx_data->icp_dev_acquire_info->dev_type, ctx_data->icp_dev_acquire_info->in_res.format, @@ -4643,6 +4843,8 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) rc = cam_icp_mgr_send_config_io(ctx_data, io_buf_addr); if (rc) { CAM_ERR(CAM_ICP, "IO Config command failed %d", rc); + cam_icp_dump_io_cfg(ctx_data, + icp_dev_acquire_info->io_config_cmd_handle); goto ioconfig_failed; } diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 9af4ccc96003..731d2355882f 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -80,6 +80,8 @@ * @fw_buf: Memory info of firmware * @qdss_buf: Memory info of qdss * @sfr_buf: Memory info for sfr buffer + * @shmem: Memory info for shared region + * @io_mem: Memory info for io region */ struct icp_hfi_mem_info { struct cam_mem_mgr_memory_desc qtbl; @@ -91,6 +93,7 @@ struct icp_hfi_mem_info { struct cam_mem_mgr_memory_desc qdss_buf; struct cam_mem_mgr_memory_desc sfr_buf; struct cam_smmu_region_info shmem; + struct cam_smmu_region_info io_mem; }; /** diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c index 2982ce027aa7..57375c4ad50f 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c @@ -2875,7 +2875,7 @@ get_dev_handle: req_hdl_param.media_entity_flag = 0; req_hdl_param.ops = ctx->crm_ctx_intf; req_hdl_param.priv = ctx; - + req_hdl_param.dev_id = CAM_ISP; CAM_DBG(CAM_ISP, "get device handle form bridge"); ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); if (ctx->dev_hdl <= 0) { diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 177538acd0b0..fe3d2f12a6e2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2984,6 +2984,7 @@ start_only: } } + ctx->dual_ife_irq_mismatch_cnt = 0; /* Start IFE root node: do nothing */ CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index); @@ -3066,6 +3067,7 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->is_rdi_only_context = 0; ctx->cdm_handle = 0; ctx->cdm_ops = NULL; + ctx->dual_ife_irq_mismatch_cnt = 0; atomic_set(&ctx->overflow_pending, 0); for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { ctx->sof_cnt[i] = 0; @@ -3573,6 +3575,38 @@ void fill_res_bitmap(uint32_t resource_type, unsigned long *res_bitmap) } } +static int cam_isp_blob_init_frame_drop( + struct cam_isp_init_frame_drop_config *frame_drop_cfg, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + uint32_t hw_idx = UINT_MAX; + uint32_t i; + int rc = 0; + + ctx = prepare->ctxt_to_hw_map; + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_idx == hw_idx) + continue; + + rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_IFE_CSID_SET_INIT_FRAME_DROP, + frame_drop_cfg, + sizeof( + struct cam_isp_init_frame_drop_config *)); + hw_idx = hw_intf->hw_idx; + } + } + return rc; +} + static int cam_isp_packet_generic_blob_handler(void *user_data, uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) { @@ -3818,7 +3852,22 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, CAM_ERR(CAM_ISP, "FS Update Failed rc: %d", rc); } break; + case CAM_ISP_GENERIC_BLOB_TYPE_INIT_FRAME_DROP: { + struct cam_isp_init_frame_drop_config *frame_drop_cfg = + (struct cam_isp_init_frame_drop_config *)blob_data; + if (blob_size < sizeof(struct cam_isp_init_frame_drop_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(struct cam_isp_init_frame_drop_config)); + return -EINVAL; + } + + rc = cam_isp_blob_init_frame_drop(frame_drop_cfg, prepare); + if (rc) + CAM_ERR(CAM_ISP, "Init Frame drop Update Failed"); + } + break; default: CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); break; @@ -4101,6 +4150,36 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, } } +static void cam_ife_mgr_ctx_irq_dump(struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_isp_hw_get_cmd_update cmd_update; + int i = 0; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + switch (hw_mgr_res->hw_res[i]->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + cmd_update.res = hw_mgr_res->hw_res[i]; + cmd_update.cmd_type = + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP; + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, + &cmd_update, sizeof(cmd_update)); + break; + default: + break; + } + } + } +} + static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -4771,11 +4850,26 @@ static int cam_ife_hw_mgr_check_irq_for_dual_vfe( (event_cnt[core_idx1] && (event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) { + if (ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt > 10) { + rc = -1; + return rc; + } + CAM_ERR_RATE_LIMIT(CAM_ISP, "One of the VFE could not generate hw event %d", hw_event_type); - rc = -1; - return rc; + if (event_cnt[core_idx0] >= 2) { + event_cnt[core_idx0]--; + ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt++; + } + if (event_cnt[core_idx1] >= 2) { + event_cnt[core_idx1]--; + ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt++; + } + + if (ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt == 1) + cam_ife_mgr_ctx_irq_dump(ife_hw_mgr_ctx); + rc = 0; } CAM_DBG(CAM_ISP, "Only one core_index has given hw event %d", diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index bf5f1527caa4..0e6d79b75232 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -102,38 +102,42 @@ struct cam_ife_hw_mgr_debug { /** * struct cam_vfe_hw_mgr_ctx - IFE HW manager Context object * - * @list: used by the ctx list. - * @common: common acquired context data - * @ctx_index: acquired context id. - * @hw_mgr: IFE hw mgr which owns this context - * @ctx_in_use: flag to tell whether context is active - * @res_list_ife_in: Starting resource(TPG,PHY0, PHY1...) Can only be - * one. - * @res_list_csid: CSID resource list - * @res_list_ife_src: IFE input resource list - * @res_list_ife_in_rd IFE input resource list for read path - * @res_list_ife_out: IFE output resoruces array - * @free_res_list: Free resources list for the branch node - * @res_pool: memory storage for the free resource list - * @irq_status0_mask: irq_status0_mask for the context - * @irq_status1_mask: irq_status1_mask for the context - * @base device base index array contain the all IFE HW - * instance associated with this context. - * @num_base number of valid base data in the base array - * @cdm_handle cdm hw acquire handle - * @cdm_ops cdm util operation pointer for building - * cdm commands - * @cdm_cmd cdm base and length request pointer - * @sof_cnt sof count value per core, used for dual VFE - * @epoch_cnt epoch count value per core, used for dual VFE - * @eof_cnt eof count value per core, used for dual VFE - * @overflow_pending flat to specify the overflow is pending for the - * context - * @is_rdi_only_context flag to specify the context has only rdi resource - * @config_done_complete indicator for configuration complete - * @init_done indicate whether init hw is done - * @is_fe_enable indicate whether fetch engine\read path is enabled - * @res_bitmap fill resource bitmap for which rup to be set + * @list: used by the ctx list. + * @common: common acquired context data + * @ctx_index: acquired context id. + * @hw_mgr: IFE hw mgr which owns this context + * @ctx_in_use: flag to tell whether context is active + * @res_list_ife_in: Starting resource(TPG,PHY0, PHY1...) Can only be + * one. + * @res_list_csid: CSID resource list + * @res_list_ife_src: IFE input resource list + * @res_list_ife_in_rd IFE input resource list for read path + * @res_list_ife_out: IFE output resoruces array + * @free_res_list: Free resources list for the branch node + * @res_pool: memory storage for the free resource list + * @irq_status0_mask: irq_status0_mask for the context + * @irq_status1_mask: irq_status1_mask for the context + * @base device base index array contain the all IFE HW + * instance associated with this context. + * @num_base number of valid base data in the base array + * @cdm_handle cdm hw acquire handle + * @cdm_ops cdm util operation pointer for building + * cdm commands + * @cdm_cmd cdm base and length request pointer + * @sof_cnt sof count value per core, used for dual VFE + * @epoch_cnt epoch count value per core, used for dual VFE + * @eof_cnt eof count value per core, used for dual VFE + * @overflow_pending flat to specify the overflow is pending + * for the context + * @is_rdi_only_context flag to specify the context has only rdi + * resource + * @config_done_complete indicator for configuration complete + * @init_done indicate whether init hw is done + * @is_fe_enable indicate whether fetch engine\read path + * is enabled + * @res_bitmap fill resource bitmap for which rup to be set + * @dual_ife_irq_mismatch_cnt irq mismatch count value per core, used for + * dual VFE */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -171,6 +175,7 @@ struct cam_ife_hw_mgr_ctx { bool init_done; bool is_fe_enable; unsigned long res_bitmap; + uint32_t dual_ife_irq_mismatch_cnt; }; /** diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 2d6e23cb7961..5610f6d267ff 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -46,7 +46,7 @@ #define CAM_CSID_IRQ_SOF_DEBUG_CNT_MAX 12 /* Max CSI Rx irq error count threshold value */ -#define CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT 100 +#define CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT 5 static int cam_ife_csid_is_ipp_ppp_format_supported( uint32_t in_format) @@ -468,6 +468,9 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) csid_hw->hw_intf->hw_idx, val); csid_hw->error_irq_count = 0; + for (i = 0 ; i < CAM_IFE_PIX_PATH_RES_MAX; i++) + csid_hw->res_sof_cnt[i] = 0; + return rc; } @@ -838,7 +841,6 @@ end: return rc; } - static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, struct cam_csid_hw_reserve_resource_args *reserve) { @@ -953,7 +955,7 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->height = reserve->in_port->height; path_data->start_line = reserve->in_port->line_start; path_data->end_line = reserve->in_port->line_stop; - + path_data->usage_type = reserve->in_port->usage_type; /* Enable RDI crop for single ife use case only */ switch (reserve->res_id) { case CAM_IFE_PIX_PATH_RES_RDI_0: @@ -1119,6 +1121,7 @@ err: static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) { int rc = -EINVAL; + uint32_t i; struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; unsigned long flags; @@ -1159,12 +1162,95 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) spin_lock_irqsave(&csid_hw->lock_state, flags); csid_hw->device_enabled = 0; spin_unlock_irqrestore(&csid_hw->lock_state, flags); + for (i = 0; i < CAM_IFE_PIX_PATH_RES_MAX; i++) + csid_hw->res_sof_cnt[i] = 0; + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; csid_hw->error_irq_count = 0; return rc; } +static int cam_ife_csid_check_path_active(struct cam_ife_csid_hw *csid_hw) +{ + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg; + uint32_t i, path_status = 1; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + /* check the IPP path status */ + if (csid_reg->cmn_reg->num_pix) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d IPP path status:%d", + csid_hw->hw_intf->hw_idx, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + + if (csid_reg->cmn_reg->num_ppp) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d PPP path status:%d", + csid_hw->hw_intf->hw_idx, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + + /* Check the RDI path status */ + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d RDI:%d path status:%d", + csid_hw->hw_intf->hw_idx, i, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + +end: + return path_status; +} + +static void cam_ife_csid_reset_init_frame_drop( + struct cam_ife_csid_hw *csid_hw) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + uint32_t i = 0; + + /* + * Reset CSID init frame drop value only if all resources are + * released + */ + csid_reg = csid_hw->csid_info->csid_reg; + if (csid_reg->cmn_reg->num_pix) { + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) + goto end; + } + + if (csid_reg->cmn_reg->num_ppp) { + if (csid_hw->ppp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) + goto end; + } + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + if (csid_hw->rdi_res[i].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) + goto end; + } + + /* All CSID resources are available reset the init frame drop */ + csid_hw->init_frame_drop = 0; +end: + return; + +} static int cam_ife_csid_tpg_start(struct cam_ife_csid_hw *csid_hw, struct cam_isp_resource_node *res) @@ -1478,15 +1564,13 @@ static void cam_ife_csid_halt_csi2( csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; - CAM_INFO(CAM_ISP, "CSID: %d cnt: %d Halt csi2 rx", - csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt); /* Disable the CSI2 rx inerrupts */ - cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + cam_io_w(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); /* Reset the Rx CFG registers */ - cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + cam_io_w(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); @@ -1726,7 +1810,7 @@ static int cam_ife_csid_enable_pxl_path( struct cam_ife_csid_path_cfg *path_data; const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; bool is_ipp; - uint32_t val = 0; + uint32_t val = 0, path_status; path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; @@ -1769,14 +1853,15 @@ static int cam_ife_csid_enable_pxl_path( /* Default is internal halt mode */ val = 0; - /* - * Resume at frame boundary if Master or No Sync. - * Slave will get resume command from Master. - */ - if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || - path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) - val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; - + /* Resume at frame boundary */ + path_status = cam_ife_csid_check_path_active(csid_hw); + if (!csid_hw->init_frame_drop || + (csid_hw->init_frame_drop && !path_status)) { + CAM_DBG(CAM_ISP, "start pixel path"); + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) + val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + } cam_io_w_mb(val, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_ctrl_addr); @@ -1790,8 +1875,10 @@ static int cam_ife_csid_enable_pxl_path( if (pxl_reg->ccif_violation_en) val |= CSID_PATH_ERROR_CCIF_VIOLATION; - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) || + (csid_hw->init_frame_drop && path_status)) val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) val |= CSID_PATH_INFO_INPUT_EOF; @@ -2088,8 +2175,10 @@ static int cam_ife_csid_enable_rdi_path( { const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; - uint32_t id, val; + struct cam_ife_csid_path_cfg *path_data; + uint32_t id, val, path_status; + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; id = res->res_id; @@ -2104,19 +2193,28 @@ static int cam_ife_csid_enable_rdi_path( return -EINVAL; } - /*resume at frame boundary */ - cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, - soc_info->reg_map[0].mem_base + - csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + if (path_data->usage_type) + path_data->init_frame_drop = csid_hw->init_frame_drop + 1; + /*resume at frame boundary */ + path_status = cam_ife_csid_check_path_active(csid_hw); + if (!path_data->init_frame_drop || + (path_data->init_frame_drop && !path_status)) { + CAM_DBG(CAM_ISP, "Start RDI:%d path", id); + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + } /* Enable the required RDI interrupts */ val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; if (csid_reg->rdi_reg[id]->ccif_violation_en) val |= CSID_PATH_ERROR_CCIF_VIOLATION; - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) || + (path_data->init_frame_drop && path_status)) val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) val |= CSID_PATH_INFO_INPUT_EOF; @@ -2376,6 +2474,19 @@ static int cam_ife_csid_set_csid_debug(struct cam_ife_csid_hw *csid_hw, return 0; } +static int cam_ife_csid_set_init_frame_drop(struct cam_ife_csid_hw *csid_hw, + void *cmd_args) +{ + struct cam_isp_init_frame_drop_config *frame_drop_cfg; + + frame_drop_cfg = (struct cam_isp_init_frame_drop_config *) cmd_args; + csid_hw->init_frame_drop = frame_drop_cfg->init_frame_drop; + CAM_DBG(CAM_ISP, "CSID:%d set init frame drop:%d", + csid_hw->hw_intf->hw_idx, csid_hw->init_frame_drop); + + return 0; +} + static int cam_ife_csid_get_hw_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -2552,6 +2663,7 @@ static int cam_ife_csid_release(void *hw_priv, break; case CAM_ISP_RESOURCE_PIX_PATH: res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + cam_ife_csid_reset_init_frame_drop(csid_hw); break; default: CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", @@ -3016,6 +3128,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE: rc = cam_ife_csid_set_csid_clock(csid_hw, cmd_args); break; + case CAM_IFE_CSID_SET_INIT_FRAME_DROP: + rc = cam_ife_csid_set_init_frame_drop(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); @@ -3033,6 +3148,9 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg; + const struct cam_ife_csid_rdi_reg_offset *rdi_reg; uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; uint32_t irq_status_rdi[4] = {0, 0, 0, 0}; uint32_t val, irq_status_ppp = 0; @@ -3091,13 +3209,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); - CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); - CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); - CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); - CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", irq_status_ppp); - CAM_DBG(CAM_ISP, "irq_status_rdi0= 0x%x", irq_status_rdi[0]); - CAM_DBG(CAM_ISP, "irq_status_rdi1= 0x%x", irq_status_rdi[1]); - CAM_DBG(CAM_ISP, "irq_status_rdi2= 0x%x", irq_status_rdi[2]); + CAM_DBG(CAM_ISP, + "CSID %d irq status 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + csid_hw->hw_intf->hw_idx, irq_status_top, + irq_status_rx, irq_status_ipp, irq_status_ppp, + irq_status_rdi[0], irq_status_rdi[1], irq_status_rdi[2]); if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); @@ -3107,71 +3223,38 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) spin_lock_irqsave(&csid_hw->lock_state, flags); if (csid_hw->device_enabled == 1) { if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow", - csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", - csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", - csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", - csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", - csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d CPHY_EOT_RECEPTION", - csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d CPHY_SOT_RECEPTION", - csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", - csid_hw->hw_intf->hw_idx); - } if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d ERROR_STREAM_UNDERFLOW", - csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } if (irq_status_rx & CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UNBOUNDED_FRAME", - csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } } - spin_unlock_irqrestore(&csid_hw->lock_state, flags); if (csid_hw->error_irq_count > CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT) { @@ -3179,8 +3262,15 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->error_irq_count = 0; } - if (fatal_err_detected) +handle_fatal_error: + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + if (fatal_err_detected) { + CAM_INFO(CAM_ISP, + "CSID: %d cnt: %d Halt csi2 rx irq_status_rx:0x%x", + csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt, + irq_status_rx); cam_ife_csid_halt_csi2(csid_hw); + } if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) { if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { @@ -3281,7 +3371,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) /* IPP reset done bit */ if (irq_status_ipp & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { - CAM_DBG(CAM_ISP, "CSID IPP reset complete"); complete(&csid_hw->csid_ipp_complete); } @@ -3293,24 +3382,69 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->init_frame_drop) && + (csid_hw->ipp_res.res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_IPP]++; + CAM_DBG(CAM_ISP, + "CSID:%d IPP SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_IPP], + csid_hw->init_frame_drop); + if (csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_IPP] == + csid_hw->init_frame_drop) { + pxl_reg = csid_reg->ipp_reg; + path_data = csid_hw->ipp_res.res_priv; + if (path_data->sync_mode == + CAM_ISP_HW_SYNC_MASTER) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + val |= + CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + } else if (path_data->sync_mode == + CAM_ISP_HW_SYNC_NONE) { + cam_io_w_mb( + CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + } + } + } + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", csid_hw->hw_intf->hw_idx); - if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) - CAM_INFO_RATE_LIMIT(CAM_ISP, - "CSID:%d IPP CCIF violation", - csid_hw->hw_intf->hw_idx); - - if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION) || + (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW)) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d IPP fifo over flow", - csid_hw->hw_intf->hw_idx); - /* Stop IPP path immediately */ - cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, - soc_info->reg_map[0].mem_base + - csid_reg->ipp_reg->csid_pxl_ctrl_addr); + "CSID:%d irq_status_ipp:0x%x", + csid_hw->hw_intf->hw_idx, irq_status_ipp); + if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + /* Stop IPP path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_ctrl_addr); + } } } @@ -3319,7 +3453,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) /* PPP reset done bit */ if (irq_status_ppp & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { - CAM_DBG(CAM_ISP, "CSID PPP reset complete"); complete(&csid_hw->csid_ppp_complete); } @@ -3331,31 +3464,77 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } + if ((irq_status_ppp & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->init_frame_drop) && + (csid_hw->ppp_res.res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_PPP]++; + CAM_DBG(CAM_ISP, + "CSID:%d PPP SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_PPP], + csid_hw->init_frame_drop); + if (csid_hw->res_sof_cnt[CAM_IFE_PIX_PATH_RES_PPP] == + csid_hw->init_frame_drop) { + path_data = csid_hw->ppp_res.res_priv; + pxl_reg = csid_reg->ppp_reg; + if (path_data->sync_mode == + CAM_ISP_HW_SYNC_MASTER) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + val |= + CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } else if (path_data->sync_mode == + CAM_ISP_HW_SYNC_NONE) { + cam_io_w_mb( + CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + } + } + } + if ((irq_status_ppp & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", csid_hw->hw_intf->hw_idx); - if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) - CAM_INFO_RATE_LIMIT(CAM_ISP, - "CSID:%d PPP CCIF violation", - csid_hw->hw_intf->hw_idx); - - if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if ((irq_status_ppp & CSID_PATH_ERROR_CCIF_VIOLATION) || + (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW)) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d PPP fifo over flow", - csid_hw->hw_intf->hw_idx); - /* Stop PPP path immediately */ - cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, - soc_info->reg_map[0].mem_base + - csid_reg->ppp_reg->csid_pxl_ctrl_addr); + "CSID:%d irq_status_ppp:0x%x", + csid_hw->hw_intf->hw_idx, irq_status_ppp); + if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + /* Stop PPP path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_ctrl_addr); + } } } for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + path_data = (struct cam_ife_csid_path_cfg *) + csid_hw->rdi_res[i].res_priv; + rdi_reg = csid_reg->rdi_reg[i]; if (irq_status_rdi[i] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { - CAM_DBG(CAM_ISP, "CSID RDI%d reset complete", i); complete(&csid_hw->csid_rdin_complete[i]); } @@ -3367,19 +3546,48 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_SOF) && + (path_data->init_frame_drop) && + (csid_hw->rdi_res[i].res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + csid_hw->res_sof_cnt[i]++; + CAM_DBG(CAM_ISP, + "CSID:%d RDI:%d SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, i, + csid_hw->res_sof_cnt[i], + path_data->init_frame_drop); + if (csid_hw->res_sof_cnt[i] == + path_data->init_frame_drop) { + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_ctrl_addr); + + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_irq_mask_addr); + } + } + } + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI:%d EOF received", i); - if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) - CAM_INFO_RATE_LIMIT(CAM_ISP, - "CSIDi RDI :%d CCIF violation", i); - - if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION) || + (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW)) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d RDI fifo over flow", - csid_hw->hw_intf->hw_idx); + "CSID:%d irq_status_rdi[%d]:0x%x", + csid_hw->hw_intf->hw_idx, i, + irq_status_rdi[i]); + } + if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { /* Stop RDI path immediately */ cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, soc_info->reg_map[0].mem_base + diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 3a093d205f59..600deb245f32 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -419,6 +419,9 @@ struct cam_ife_csid_cid_data { * @master_idx: For Slave reservation, Give master IFE instance Index. * Slave will synchronize with master Start and stop operations * @clk_rate Clock rate + * @usage_type Usage type ie dual or single ife usecase + * @init_frame_drop init frame drop value. In dual ife case rdi need to drop one + * more frame than pix. * */ struct cam_ife_csid_path_cfg { @@ -437,6 +440,8 @@ struct cam_ife_csid_path_cfg { enum cam_isp_hw_sync_mode sync_mode; uint32_t master_idx; uint64_t clk_rate; + uint32_t usage_type; + uint32_t init_frame_drop; }; /** @@ -468,6 +473,13 @@ struct cam_ife_csid_path_cfg { * @irq_debug_cnt: Counter to track sof irq's when above flag is set. * @error_irq_count Error IRQ count, if continuous error irq comes * need to stop the CSID and mask interrupts. + * @device_enabled Device enabled will set once CSID powered on and + * initial configuration are done. + * @lock_state csid spin lock + * @dual_usage usage type, dual ife or single ife + * @init_frame_drop Initial frame drop number + * @res_sof_cnt path resource sof count value. it used for initial + * frame drop * */ struct cam_ife_csid_hw { @@ -496,6 +508,9 @@ struct cam_ife_csid_hw { uint32_t error_irq_count; uint32_t device_enabled; spinlock_t lock_state; + uint32_t dual_usage; + uint32_t init_frame_drop; + uint32_t res_sof_cnt[CAM_IFE_PIX_PATH_RES_MAX]; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 58818fbecf67..0c45bd1268b9 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -157,6 +157,7 @@ enum cam_ife_csid_cmd_type { CAM_IFE_CSID_CMD_GET_TIME_STAMP, CAM_IFE_CSID_SET_CSID_DEBUG, CAM_IFE_CSID_SOF_IRQ_DEBUG, + CAM_IFE_CSID_SET_INIT_FRAME_DROP, CAM_IFE_CSID_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 61542566a924..b23014773022 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -104,6 +104,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 2bd6db9954f1..a26c11264d2c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -760,6 +760,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_CLOCK_UPDATE: case CAM_ISP_HW_CMD_BW_UPDATE: case CAM_ISP_HW_CMD_BW_CONTROL: + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index c40936525c73..4e9a97501749 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -421,6 +421,40 @@ static int cam_vfe_camif_reg_dump_bh( return 0; } +static int cam_vfe_camif_irq_reg_dump( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_soc_private *soc_private; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments\n"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) { + CAM_ERR(CAM_ISP, "Error! Invalid state\n"); + return 0; + } + + camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + soc_private = camif_priv->soc_info->soc_private; + + CAM_INFO(CAM_ISP, + "Core Id =%d Mask reg: offset 0x%x val 0x%x offset 0x%x val 0x%x", + camif_priv->hw_intf->hw_idx, + 0x5c, cam_io_r_mb(camif_priv->mem_base + 0x5c), + 0x60, cam_io_r_mb(camif_priv->mem_base + 0x60)); + CAM_INFO(CAM_ISP, + "Core Id =%d Status reg: offset 0x%x val 0x%x offset 0x%x val 0x%x", + camif_priv->hw_intf->hw_idx, + 0x6c, cam_io_r_mb(camif_priv->mem_base + 0x6c), + 0x70, cam_io_r_mb(camif_priv->mem_base + 0x70)); + return rc; +} + static int cam_vfe_camif_resource_stop( struct cam_isp_resource_node *camif_res) { @@ -508,6 +542,9 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; camif_priv->camif_debug = *((uint32_t *)cmd_args); break; + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: + rc = cam_vfe_camif_irq_reg_dump(rsrc_node); + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index c5acbe5dbd16..b0ac94b895f1 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -438,6 +438,19 @@ static int cam_vfe_top_mux_get_reg_update( return -EINVAL; } +static int cam_vfe_get_irq_register_dump( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *cmd_update = cmd_args; + + if (cmd_update->res->process_cmd) + cmd_update->res->process_cmd(cmd_update->res, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, cmd_args, arg_size); + + return 0; +} + int cam_vfe_top_get_hw_caps(void *device_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -723,6 +736,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_BW_CONTROL: rc = cam_vfe_top_bw_control(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: + rc = cam_vfe_get_irq_register_dump(top_priv, + cmd_args, arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type); diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c index f1b3ccefe62c..c8e2a023b0d4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c @@ -348,10 +348,12 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, struct cam_req_mgr_req_queue *in_q = link->req.in_q; slot = &in_q->slot[idx]; - CAM_DBG(CAM_CRM, "RESET: idx: %d: slot->status %d", idx, slot->status); + CAM_DBG(CAM_CRM, "RESET: last applied idx %d: idx %d: slot->status %d", + in_q->last_applied_idx, idx, slot->status); /* Check if CSL has already pushed new request*/ - if (slot->status == CRM_SLOT_STATUS_REQ_ADDED) + if (slot->status == CRM_SLOT_STATUS_REQ_ADDED || + in_q->last_applied_idx == idx) return; /* Reset input queue slot */ @@ -512,9 +514,11 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, } if (link->req.apply_data[pd].skip_idx || link->req.apply_data[pd].req_id < 0) { - CAM_DBG(CAM_CRM, "skip %d req_id %lld", + CAM_DBG(CAM_CRM, + "skip %d req_id %lld pd %d dev_name %s", link->req.apply_data[pd].skip_idx, - link->req.apply_data[pd].req_id); + link->req.apply_data[pd].req_id, + pd, dev->dev_info.name); continue; } if (!(dev->dev_info.trigger & trigger)) @@ -893,6 +897,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( int64_t req_id = 0; int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; int32_t sync_num_slots = 0; + bool ready = true, sync_ready = true; if (!link->sync_link) { CAM_ERR(CAM_CRM, "Sync link null"); @@ -921,17 +926,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( CAM_DBG(CAM_CRM, "Skip Process Req: %lld on link: %x", req_id, link->link_hdl); - link->sync_link_sof_skip = true; - return rc; - } - - rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); - if (rc) { - CAM_DBG(CAM_CRM, - "Req: %lld [My link] not ready on link: %x, rc=%d", - req_id, link->link_hdl, rc); - link->sync_link_sof_skip = true; - return rc; + ready = false; } sync_slot_idx = __cam_req_mgr_find_slot_for_req( @@ -939,8 +934,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( if (sync_slot_idx == -1) { CAM_DBG(CAM_CRM, "Req: %lld not found on link: %x [other link]", req_id, sync_link->link_hdl); - link->sync_link_sof_skip = true; - return -EINVAL; + sync_ready = false; } sync_rd_idx = sync_link->req.in_q->rd_idx; @@ -956,14 +950,38 @@ static int __cam_req_mgr_check_sync_req_is_ready( return -EAGAIN; } + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [My link] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + ready = false; + } + rc = __cam_req_mgr_check_link_is_ready(sync_link, sync_slot_idx, true); if (rc && (sync_link->req.in_q->slot[sync_slot_idx].status != CRM_SLOT_STATUS_REQ_APPLIED)) { CAM_DBG(CAM_CRM, "Req: %lld not ready on [other link] link: %x, rc=%d", req_id, sync_link->link_hdl, rc); + sync_ready = false; + } + + /* + * If both of them are ready or not ready, then just + * skip this sof and don't skip sync link next SOF. + */ + if (sync_ready != ready) { + CAM_DBG(CAM_CRM, + "Req: %lld ready %d sync_ready %d, ignore sync link next SOF", + req_id, ready, sync_ready); link->sync_link_sof_skip = true; - return rc; + return -EINVAL; + } else if (ready == false) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on link: %x", + req_id, link->link_hdl); + return -EINVAL; } CAM_DBG(CAM_REQ, @@ -995,7 +1013,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, uint32_t trigger) { - int rc = 0, idx; + int rc = 0, idx, last_app_idx; int reset_step = 0; struct cam_req_mgr_slot *slot = NULL; struct cam_req_mgr_req_queue *in_q; @@ -1129,6 +1147,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, slot->req_id, link->link_hdl); idx = in_q->rd_idx; + reset_step = link->max_delay; if (link->sync_link) { if ((link->in_msync_mode) && @@ -1136,6 +1155,25 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, reset_step = link->sync_link->max_delay; } + + /* This is to handle a rare scenario of scheduling + * issue. If ISP sends multiple sofs due to scheduling + * issue, it is required to retain last applied index + * to help recover. + * In this case, ISP goes into Bubble, asking to reapply + * the bubbled request which has already been reset by + * CRM. Below code retains the last applied request. + */ + + if (slot->req_id > 0) { + last_app_idx = in_q->last_applied_idx; + in_q->last_applied_idx = idx; + if (abs(last_app_idx - idx) >= + reset_step + 1) + __cam_req_mgr_reset_req_slot(link, + last_app_idx); + } + __cam_req_mgr_dec_idx( &idx, reset_step + 1, in_q->num_slots); @@ -2359,18 +2397,24 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { * */ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, - struct cam_req_mgr_link_info *link_info) + struct cam_req_mgr_ver_info *link_info) { - int rc = 0, i = 0; + int rc = 0, i = 0, num_devices = 0; struct cam_req_mgr_core_dev_link_setup link_data; struct cam_req_mgr_connected_device *dev; struct cam_req_mgr_req_tbl *pd_tbl; enum cam_pipeline_delay max_delay; uint32_t subscribe_event = 0; - - if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) - return -EPERM; - + if (link_info->version == VERSION_1) { + if (link_info->u.link_info_v1.num_devices > + CAM_REQ_MGR_MAX_HANDLES) + return -EPERM; + } + else if (link_info->version == VERSION_2) { + if (link_info->u.link_info_v2.num_devices > + CAM_REQ_MGR_MAX_HANDLES_V2) + return -EPERM; + } mutex_init(&link->req.lock); CAM_DBG(CAM_CRM, "LOCK_DBG in_q lock %pK", &link->req.lock); link->req.num_tbl = 0; @@ -2380,11 +2424,21 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, return rc; max_delay = CAM_PIPELINE_DELAY_0; - for (i = 0; i < link_info->num_devices; i++) { + if (link_info->version == VERSION_1) + num_devices = link_info->u.link_info_v1.num_devices; + else if (link_info->version == VERSION_2) + num_devices = link_info->u.link_info_v2.num_devices; + for (i = 0; i < num_devices; i++) { dev = &link->l_dev[i]; /* Using dev hdl, get ops ptr to communicate with device */ - dev->ops = (struct cam_req_mgr_kmd_ops *) - cam_get_device_ops(link_info->dev_hdls[i]); + if (link_info->version == VERSION_1) + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops( + link_info->u.link_info_v1.dev_hdls[i]); + else if (link_info->version == VERSION_2) + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops( + link_info->u.link_info_v2.dev_hdls[i]); if (!dev->ops || !dev->ops->get_dev_info || !dev->ops->link_setup) { @@ -2392,18 +2446,29 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, rc = -ENXIO; goto error; } - dev->dev_hdl = link_info->dev_hdls[i]; + if (link_info->version == VERSION_1) + dev->dev_hdl = link_info->u.link_info_v1.dev_hdls[i]; + else if (link_info->version == VERSION_2) + dev->dev_hdl = link_info->u.link_info_v2.dev_hdls[i]; dev->parent = (void *)link; dev->dev_info.dev_hdl = dev->dev_hdl; rc = dev->ops->get_dev_info(&dev->dev_info); trace_cam_req_mgr_connect_device(link, &dev->dev_info); - - CAM_DBG(CAM_CRM, - "%x: connected: %s, id %d, delay %d, trigger %x", - link_info->session_hdl, dev->dev_info.name, - dev->dev_info.dev_id, dev->dev_info.p_delay, - dev->dev_info.trigger); + if (link_info->version == VERSION_1) + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); + else if (link_info->version == VERSION_2) + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->u.link_info_v2.session_hdl, + dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); if (rc < 0 || dev->dev_info.p_delay >= CAM_PIPELINE_DELAY_MAX || @@ -2412,10 +2477,18 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, CAM_ERR(CAM_CRM, "get device info failed"); goto error; } else { - CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", - link_info->session_hdl, - dev->dev_info.name, - dev->dev_info.p_delay); + if (link_info->version == VERSION_1) { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + } + else if (link_info->version == VERSION_2) { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->u.link_info_v2.session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + } if (dev->dev_info.p_delay > max_delay) max_delay = dev->dev_info.p_delay; @@ -2430,7 +2503,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, link_data.max_delay = max_delay; link_data.subscribe_event = subscribe_event; - for (i = 0; i < link_info->num_devices; i++) { + for (i = 0; i < num_devices; i++) { dev = &link->l_dev[i]; link_data.dev_hdl = dev->dev_hdl; @@ -2473,7 +2546,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, if (link->max_delay < dev->dev_info.p_delay) link->max_delay = dev->dev_info.p_delay; } - link->num_devs = link_info->num_devices; + link->num_devs = num_devices; /* Assign id for pd tables */ __cam_req_mgr_tbl_set_id(link->req.l_tbl, &link->req); @@ -2631,7 +2704,115 @@ end: return rc; } -int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) +int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) +{ + int rc = 0; + int wq_flag = 0; + char buf[128]; + struct cam_create_dev_hdl root_dev; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link; + + if (!link_info) { + CAM_DBG(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + if (link_info->u.link_info_v1.num_devices > CAM_REQ_MGR_MAX_HANDLES) { + CAM_ERR(CAM_CRM, "Invalid num devices %d", + link_info->u.link_info_v1.num_devices); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(link_info->u.link_info_v1.session_hdl); + if (!cam_session) { + CAM_DBG(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + /* Allocate link struct and map it with session's request queue */ + link = __cam_req_mgr_reserve_link(cam_session); + if (!link) { + CAM_ERR(CAM_CRM, "failed to reserve new link"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); + + memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); + root_dev.session_hdl = link_info->u.link_info_v1.session_hdl; + root_dev.priv = (void *)link; + root_dev.dev_id = CAM_CRM; + mutex_lock(&link->lock); + /* Create unique dev handle for link */ + link->link_hdl = cam_create_device_hdl(&root_dev); + if (link->link_hdl < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new device handle"); + rc = link->link_hdl; + goto link_hdl_fail; + } + link_info->u.link_info_v1.link_hdl = link->link_hdl; + link->last_flush_id = 0; + + /* Allocate memory to hold data of all linked devs */ + rc = __cam_req_mgr_create_subdevs(&link->l_dev, + link_info->u.link_info_v1.num_devices); + if (rc < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new crm subdevs"); + goto create_subdev_failed; + } + + /* Using device ops query connected devs, prepare request tables */ + rc = __cam_req_mgr_setup_link_info(link, link_info); + if (rc < 0) + goto setup_failed; + + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_READY; + spin_unlock_bh(&link->link_state_spin_lock); + + /* Create worker for current link */ + snprintf(buf, sizeof(buf), "%x-%x", + link_info->u.link_info_v1.session_hdl, link->link_hdl); + wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; + rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); + if (rc < 0) { + CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); + __cam_req_mgr_destroy_link_info(link); + goto setup_failed; + } + + /* Assign payload to workqueue tasks */ + rc = __cam_req_mgr_setup_payload(link->workq); + if (rc < 0) { + __cam_req_mgr_destroy_link_info(link); + cam_req_mgr_workq_destroy(&link->workq); + goto setup_failed; + } + + mutex_unlock(&link->lock); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +setup_failed: + __cam_req_mgr_destroy_subdev(link->l_dev); +create_subdev_failed: + cam_destroy_device_hdl(link->link_hdl); + link_info->u.link_info_v1.link_hdl = -1; +link_hdl_fail: + mutex_unlock(&link->lock); + __cam_req_mgr_unreserve_link(cam_session, link); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) { int rc = 0; int wq_flag = 0; @@ -2644,9 +2825,10 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) CAM_DBG(CAM_CRM, "NULL pointer"); return -EINVAL; } - if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) { + if (link_info->u.link_info_v2.num_devices > + CAM_REQ_MGR_MAX_HANDLES_V2) { CAM_ERR(CAM_CRM, "Invalid num devices %d", - link_info->num_devices); + link_info->u.link_info_v2.num_devices); return -EINVAL; } @@ -2654,7 +2836,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) - cam_get_device_priv(link_info->session_hdl); + cam_get_device_priv(link_info->u.link_info_v2.session_hdl); if (!cam_session) { CAM_DBG(CAM_CRM, "NULL pointer"); mutex_unlock(&g_crm_core_dev->crm_lock); @@ -2671,7 +2853,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); - root_dev.session_hdl = link_info->session_hdl; + root_dev.session_hdl = link_info->u.link_info_v2.session_hdl; root_dev.priv = (void *)link; mutex_lock(&link->lock); @@ -2683,12 +2865,12 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) rc = link->link_hdl; goto link_hdl_fail; } - link_info->link_hdl = link->link_hdl; + link_info->u.link_info_v2.link_hdl = link->link_hdl; link->last_flush_id = 0; /* Allocate memory to hold data of all linked devs */ rc = __cam_req_mgr_create_subdevs(&link->l_dev, - link_info->num_devices); + link_info->u.link_info_v2.num_devices); if (rc < 0) { CAM_ERR(CAM_CRM, "Insufficient memory to create new crm subdevs"); @@ -2706,7 +2888,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) /* Create worker for current link */ snprintf(buf, sizeof(buf), "%x-%x", - link_info->session_hdl, link->link_hdl); + link_info->u.link_info_v2.session_hdl, link->link_hdl); wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); @@ -2731,7 +2913,7 @@ setup_failed: __cam_req_mgr_destroy_subdev(link->l_dev); create_subdev_failed: cam_destroy_device_hdl(link->link_hdl); - link_info->link_hdl = -1; + link_info->u.link_info_v2.link_hdl = -1; link_hdl_fail: mutex_unlock(&link->lock); __cam_req_mgr_unreserve_link(cam_session, link); @@ -2739,6 +2921,7 @@ link_hdl_fail: return rc; } + int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info) { int rc = 0; diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h index 9bff66b36ebb..05fe0860bfa0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h @@ -36,6 +36,9 @@ #define MAXIMUM_LINKS_PER_SESSION 4 +#define VERSION_1 1 +#define VERSION_2 2 + /** * enum crm_workq_task_type * @codes: to identify which type of task is present @@ -233,12 +236,14 @@ struct cam_req_mgr_slot { * @slot : request slot holding incoming request id and bubble info. * @rd_idx : indicates slot index currently in process. * @wr_idx : indicates slot index to hold new upcoming req. + * @last_applied_idx : indicates slot index last applied successfully. */ struct cam_req_mgr_req_queue { int32_t num_slots; struct cam_req_mgr_slot slot[MAX_REQ_SLOTS]; int32_t rd_idx; int32_t wr_idx; + int32_t last_applied_idx; }; /** @@ -411,7 +416,9 @@ int cam_req_mgr_destroy_session(struct cam_req_mgr_session_info *ses_info); * a unique link handle for the link and is specific to a * session. Returns link handle */ -int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info); +int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info); +int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info); + /** * cam_req_mgr_unlink() diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_dev.c index 5cf1d844f5e2..31607ac6391f 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, 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 @@ -268,27 +268,50 @@ static long cam_private_ioctl(struct file *file, void *fh, break; case CAM_REQ_MGR_LINK: { - struct cam_req_mgr_link_info link_info; + struct cam_req_mgr_ver_info ver_info; - if (k_ioctl->size != sizeof(link_info)) + if (k_ioctl->size != sizeof(ver_info.u.link_info_v1)) return -EINVAL; - if (copy_from_user(&link_info, + if (copy_from_user(&ver_info.u.link_info_v1, u64_to_user_ptr(k_ioctl->handle), sizeof(struct cam_req_mgr_link_info))) { return -EFAULT; } - - rc = cam_req_mgr_link(&link_info); + ver_info.version = VERSION_1; + rc = cam_req_mgr_link(&ver_info); if (!rc) if (copy_to_user( u64_to_user_ptr(k_ioctl->handle), - &link_info, + &ver_info.u.link_info_v1, sizeof(struct cam_req_mgr_link_info))) rc = -EFAULT; } break; + case CAM_REQ_MGR_LINK_V2: { + struct cam_req_mgr_ver_info ver_info; + + if (k_ioctl->size != sizeof(ver_info.u.link_info_v2)) + return -EINVAL; + + if (copy_from_user(&ver_info.u.link_info_v2, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_link_info_v2))) { + return -EFAULT; + } + ver_info.version = VERSION_2; + rc = cam_req_mgr_link_v2(&ver_info); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &ver_info.u.link_info_v2, + sizeof(struct + cam_req_mgr_link_info_v2))) + rc = -EFAULT; + } + break; + case CAM_REQ_MGR_UNLINK: { struct cam_req_mgr_unlink_info unlink_info; diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_util.c b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_util.c index dda04f8e5164..d531fdcf388b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -128,6 +128,21 @@ static int32_t cam_get_free_handle_index(void) return idx; } +void cam_dump_tbl_info(void) +{ + int i; + + for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES; i++) + CAM_INFO(CAM_CRM, "session_hdl=%x hdl_value=%x\n" + "type=%d state=%d dev_id=%lld", + hdl_tbl->hdl[i].session_hdl, + hdl_tbl->hdl[i].hdl_value, + hdl_tbl->hdl[i].type, + hdl_tbl->hdl[i].state, + hdl_tbl->hdl[i].dev_id); + +} + int32_t cam_create_session_hdl(void *priv) { int idx; @@ -144,6 +159,7 @@ int32_t cam_create_session_hdl(void *priv) idx = cam_get_free_handle_index(); if (idx < 0) { CAM_ERR(CAM_CRM, "Unable to create session handle"); + cam_dump_tbl_info(); spin_unlock_bh(&hdl_tbl_lock); return idx; } @@ -177,6 +193,7 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) idx = cam_get_free_handle_index(); if (idx < 0) { CAM_ERR(CAM_CRM, "Unable to create device handle"); + cam_dump_tbl_info(); spin_unlock_bh(&hdl_tbl_lock); return idx; } @@ -189,6 +206,7 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) hdl_tbl->hdl[idx].state = HDL_ACTIVE; hdl_tbl->hdl[idx].priv = hdl_data->priv; hdl_tbl->hdl[idx].ops = hdl_data->ops; + hdl_tbl->hdl[idx].dev_id = hdl_data->dev_id; spin_unlock_bh(&hdl_tbl_lock); pr_debug("%s: handle = %x", __func__, handle); diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_util.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_util.h index 7b8e3e601ed8..50d6f309da15 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_util.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, 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 @@ -50,6 +50,7 @@ struct handle { uint32_t hdl_value; enum hdl_type type; enum hdl_state state; + uint64_t dev_id; void *ops; void *priv; }; @@ -80,6 +81,7 @@ struct cam_create_dev_hdl { int32_t v4l2_sub_dev_flag; int32_t media_entity_flag; int32_t reserved; + uint64_t dev_id; void *ops; void *priv; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c index 1262db7646dc..3837aac6a2e5 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -786,7 +786,7 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = a_ctrl; - + bridge_params.dev_id = CAM_ACTUATOR; actuator_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); a_ctrl->bridge_intf.device_hdl = actuator_acq_dev.device_handle; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c index f41cb4753f39..a06a4c6c6339 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1094,7 +1094,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, * RD_DONE exclusively. */ rem_jiffies = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, + &cci_dev->cci_master_info[master].rd_done, CCI_TIMEOUT); if (!rem_jiffies) { rc = -ETIMEDOUT; @@ -1275,10 +1275,11 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, val = 1 << ((master * 2) + queue); cam_io_w_mb(val, base + CCI_QUEUE_START_ADDR); CAM_DBG(CAM_CCI, - "waiting_for_rd_done [exp_words: %d]", exp_words); + "waiting_for_rd_done [exp_words: %d]", + ((read_cfg->num_byte / 4) + 1)); rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); + &cci_dev->cci_master_info[master].rd_done, CCI_TIMEOUT); if (rc <= 0) { #ifdef DUMP_CCI_REGISTERS cam_cci_dump_registers(cci_dev, master, queue); @@ -1692,14 +1693,19 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, struct cam_cci_ctrl *cci_ctrl) { int32_t rc = 0; - + struct cci_device *cci_dev = v4l2_get_subdevdata(sd); CAM_DBG(CAM_CCI, "cmd %d", cci_ctrl->cmd); + switch (cci_ctrl->cmd) { case MSM_CCI_INIT: + mutex_lock(&cci_dev->init_mutex); rc = cam_cci_init(sd, cci_ctrl); + mutex_unlock(&cci_dev->init_mutex); break; case MSM_CCI_RELEASE: + mutex_lock(&cci_dev->init_mutex); rc = cam_cci_release(sd); + mutex_unlock(&cci_dev->init_mutex); break; case MSM_CCI_I2C_READ: rc = cam_cci_read_bytes(sd, cci_ctrl); diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c index 7934aa50767c..69b5af002610 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -71,20 +71,26 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) irq_status0 = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR); irq_status1 = cam_io_r_mb(base + CCI_IRQ_STATUS_1_ADDR); + CAM_DBG(CAM_CCI, "BASE: %pK", base); CAM_DBG(CAM_CCI, "irq0:%x irq1:%x", irq_status0, irq_status1); if (irq_status0 & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { + struct cam_cci_master_info *cci_master_info; if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { + cci_master_info = &cci_dev->cci_master_info[MASTER_0]; cci_dev->cci_master_info[MASTER_0].reset_pending = FALSE; - complete( - &cci_dev->cci_master_info[MASTER_0].reset_complete); + if (!cci_master_info->status) + complete(&cci_master_info->reset_complete); + cci_master_info->status = 0; } if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { + cci_master_info = &cci_dev->cci_master_info[MASTER_1]; cci_dev->cci_master_info[MASTER_1].reset_pending = FALSE; - complete( - &cci_dev->cci_master_info[MASTER_1].reset_complete); + if (!cci_master_info->status) + complete(&cci_master_info->reset_complete); + cci_master_info->status = 0; } } @@ -93,7 +99,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) cci_dev->cci_master_info[MASTER_0].status = 0; rd_done_th_assert = true; complete(&cci_dev->cci_master_info[MASTER_0].th_complete); - complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_0].rd_done); } if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) && (!rd_done_th_assert)) { @@ -102,7 +108,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) if (cci_dev->is_burst_read) complete( &cci_dev->cci_master_info[MASTER_0].th_complete); - complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_0].rd_done); } if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) && (!rd_done_th_assert)) { @@ -149,7 +155,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) cci_dev->cci_master_info[MASTER_1].status = 0; rd_done_th_assert = true; complete(&cci_dev->cci_master_info[MASTER_1].th_complete); - complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_1].rd_done); } if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && (!rd_done_th_assert)) { @@ -158,7 +164,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) if (cci_dev->is_burst_read) complete( &cci_dev->cci_master_info[MASTER_1].th_complete); - complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + complete(&cci_dev->cci_master_info[MASTER_1].rd_done); } if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) && (!rd_done_th_assert)) { @@ -217,16 +223,33 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_0].status = -EINVAL; - cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, - base + CCI_HALT_REQ_ADDR); - CAM_DBG(CAM_CCI, "MASTER_0 error 0x%x", irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) + CAM_ERR(CAM_CCI, "Base:%pK, M0 NACK ERROR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M0 QUEUE_OVER/UNDER_FLOW OR CMD ERR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base: %pK, M0 RD_OVER/UNDER_FLOW ERROR: 0x%x", + base, irq_status0); + cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_1].status = -EINVAL; - cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, - base + CCI_HALT_REQ_ADDR); - CAM_DBG(CAM_CCI, "MASTER_1 error 0x%x", irq_status0); - + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) + CAM_ERR(CAM_CCI, "Base:%pK, M1 NACK ERROR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M1 QUEUE_OVER_UNDER_FLOW OR CMD ERROR:0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M1 RD_OVER/UNDER_FLOW ERROR: 0x%x", + base, irq_status0); + cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); } cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR); @@ -402,7 +425,8 @@ static int cam_cci_platform_probe(struct platform_device *pdev) } g_cci_subdev[soc_info->index] = &new_cci_dev->v4l2_dev_str.sd; - CAM_ERR(CAM_CCI, "Device Type :%d", soc_info->index); + mutex_init(&(new_cci_dev->init_mutex)); + CAM_INFO(CAM_CCI, "Device Type :%d", soc_info->index); cam_register_subdev_fops(&cci_v4l2_subdev_fops); cci_v4l2_subdev_fops.unlocked_ioctl = cam_cci_subdev_fops_ioctl; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h index 349effcc057b..54eed834be07 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -140,6 +140,7 @@ struct cam_cci_master_info { uint8_t reset_pending; struct mutex mutex; struct completion reset_complete; + struct completion rd_done; struct completion th_complete; struct mutex mutex_q[NUM_QUEUES]; struct completion report_q[NUM_QUEUES]; @@ -171,41 +172,41 @@ enum cam_cci_state_t { }; /** - * struct cci_device - * @pdev: Platform device - * @subdev: V4L2 sub device - * @base: Base address of CCI device - * @hw_version: Hardware version - * @ref_count: Reference Count - * @cci_state: CCI state machine - * @num_clk: Number of CCI clock - * @cci_clk: CCI clock structure - * @cci_clk_info: CCI clock information - * @cam_cci_i2c_queue_info: CCI queue information - * @i2c_freq_mode: I2C frequency of operations - * @cci_clk_params: CCI hw clk params - * @cci_gpio_tbl: CCI GPIO table - * @cci_gpio_tbl_size: GPIO table size - * @cci_pinctrl: Pinctrl structure - * @cci_pinctrl_status: CCI pinctrl status - * @cci_clk_src: CCI clk src rate - * @cci_vreg: CCI regulator structure - * @cci_reg_ptr: CCI individual regulator structure - * @regulator_count: Regulator count - * @support_seq_write: - * Set this flag when sequential write is enabled - * @write_wq: Work queue structure - * @valid_sync: Is it a valid sync with CSID - * @v4l2_dev_str: V4L2 device structure - * @cci_wait_sync_cfg: CCI sync config - * @cycles_per_us: Cycles per micro sec - * @payload_size: CCI packet payload size - * @irq_status1: Store irq_status1 to be cleared after - * draining FIFO buffer for burst read - * @lock_status: to protect changes to irq_status1 - * @is_burst_read: Flag to determine if we are performing - * a burst read operation or not - * @irqs_disabled: Mask for IRQs that are disabled + * @pdev: Platform device + * @subdev: V4L2 sub device + * @base: Base address of CCI device + * @hw_version: Hardware version + * @ref_count: Reference Count + * @cci_state: CCI state machine + * @num_clk: Number of CCI clock + * @cci_clk: CCI clock structure + * @cci_clk_info: CCI clock information + * @cam_cci_i2c_queue_info: CCI queue information + * @i2c_freq_mode: I2C frequency of operations + * @cci_clk_params: CCI hw clk params + * @cci_gpio_tbl: CCI GPIO table + * @cci_gpio_tbl_size: GPIO table size + * @cci_pinctrl: Pinctrl structure + * @cci_pinctrl_status: CCI pinctrl status + * @cci_clk_src: CCI clk src rate + * @cci_vreg: CCI regulator structure + * @cci_reg_ptr: CCI individual regulator structure + * @regulator_count: Regulator count + * @support_seq_write: Set this flag when sequential write is enabled + * @write_wq: Work queue structure + * @valid_sync: Is it a valid sync with CSID + * @v4l2_dev_str: V4L2 device structure + * @cci_wait_sync_cfg: CCI sync config + * @cycles_per_us: Cycles per micro sec + * @payload_size: CCI packet payload size + * @irq_status1: Store irq_status1 to be cleared after + * draining FIFO buffer for burst read + * @lock_status: to protect changes to irq_status1 + * @is_burst_read: Flag to determine if we are performing + * a burst read operation or not + * @irqs_disabled: Mask for IRQs that are disabled + * @init_mutex: Mutex for maintaining refcount for attached + * devices to cci during init/deinit. */ struct cci_device { struct v4l2_subdev subdev; @@ -234,6 +235,7 @@ struct cci_device { spinlock_t lock_status; bool is_burst_read; uint32_t irqs_disabled; + struct mutex init_mutex; }; enum cam_cci_i2c_cmd_type { diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_hwreg.h index 027a0501dcae..ead18afc77ad 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_hwreg.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017-2019, 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 @@ -61,6 +61,12 @@ #define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 #define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 #define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 +#define CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK 0x18000000 +#define CCI_IRQ_STATUS_0_I2C_M1_NACK_ERROR_BMSK 0x60000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK 0xEE0 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK 0xEE0000 +#define CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK 0x6 +#define CCI_IRQ_STATUS_0_I2C_M1_RD_ERROR_BMSK 0x6000 #define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1 #define CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD 0x10000 #define CCI_IRQ_STATUS_1_I2C_M0_RD_PAUSE 0x20000 diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c index fa290c0b982c..0181a4d8e2ff 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -19,7 +19,7 @@ int cam_cci_init(struct v4l2_subdev *sd, uint8_t i = 0, j = 0; int32_t rc = 0; struct cci_device *cci_dev; - enum cci_i2c_master_t master = MASTER_0; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; struct cam_ahb_vote ahb_vote; struct cam_axi_vote axi_vote; struct cam_hw_soc_info *soc_info = NULL; @@ -47,7 +47,6 @@ int cam_cci_init(struct v4l2_subdev *sd, if (cci_dev->ref_count++) { CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); - master = c_ctrl->cci_info->cci_i2c_master; CAM_DBG(CAM_CCI, "master %d", master); if (master < MASTER_MAX && master >= 0) { mutex_lock(&cci_dev->cci_master_info[master].mutex); @@ -55,6 +54,8 @@ int cam_cci_init(struct v4l2_subdev *sd, /* Re-initialize the completion */ reinit_completion( &cci_dev->cci_master_info[master].reset_complete); + reinit_completion( + &cci_dev->cci_master_info[master].rd_done); for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); @@ -93,6 +94,7 @@ int cam_cci_init(struct v4l2_subdev *sd, /* Re-initialize the completion */ reinit_completion(&cci_dev->cci_master_info[master].reset_complete); + reinit_completion(&cci_dev->cci_master_info[master].rd_done); for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); @@ -128,12 +130,12 @@ int cam_cci_init(struct v4l2_subdev *sd, } } - cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; + cci_dev->cci_master_info[master].reset_pending = TRUE; cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[MASTER_0].reset_complete, + &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); if (rc <= 0) { CAM_ERR(CAM_CCI, "wait_for_completion_timeout"); @@ -205,6 +207,8 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) &new_cci_dev->cci_master_info[i].reset_complete); init_completion( &new_cci_dev->cci_master_info[i].th_complete); + init_completion( + &new_cci_dev->cci_master_info[i].rd_done); for (j = 0; j < NUM_QUEUES; j++) { mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]); diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 85b8e37de5f6..8074ecd9112a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -232,13 +232,18 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, csiphy_dev->csiphy_info.csiphy_3phase = cam_cmd_csiphy_info->csiphy_3phase; csiphy_dev->csiphy_info.combo_mode |= cam_cmd_csiphy_info->combo_mode; - if (cam_cmd_csiphy_info->combo_mode == 1) + if (cam_cmd_csiphy_info->combo_mode == 1) { csiphy_dev->csiphy_info.settle_time_combo_sensor = cam_cmd_csiphy_info->settle_time; - else + csiphy_dev->csiphy_info.data_rate_combo_sensor = + cam_cmd_csiphy_info->data_rate; + } else { csiphy_dev->csiphy_info.settle_time = cam_cmd_csiphy_info->settle_time; - csiphy_dev->csiphy_info.data_rate = cam_cmd_csiphy_info->data_rate; + csiphy_dev->csiphy_info.data_rate = + cam_cmd_csiphy_info->data_rate; + } + if (cam_cmd_csiphy_info->secure_mode == 1) cam_csiphy_update_secure_info(csiphy_dev, @@ -269,6 +274,65 @@ void cam_csiphy_cphy_irq_config(struct csiphy_device *csiphy_dev) csiphy_dev->ctrl_reg->csiphy_irq_reg[i].reg_addr); } +void cam_csiphy_cphy_data_rate_config(struct csiphy_device *csiphy_device) +{ + int i = 0, j = 0; + uint64_t phy_data_rate = 0; + void __iomem *csiphybase = NULL; + ssize_t num_table_entries = 0; + struct data_rate_settings_t *settings_table = NULL; + + if ((csiphy_device == NULL) || + (csiphy_device->ctrl_reg == NULL) || + (csiphy_device->ctrl_reg->data_rates_settings_table == NULL)) { + CAM_DBG(CAM_CSIPHY, + "Data rate specific register table not found"); + return; + } + + phy_data_rate = csiphy_device->csiphy_info.data_rate; + csiphybase = + csiphy_device->soc_info.reg_map[0].mem_base; + settings_table = + csiphy_device->ctrl_reg->data_rates_settings_table; + num_table_entries = + settings_table->num_data_rate_settings; + + CAM_DBG(CAM_CSIPHY, "required data rate : %llu", phy_data_rate); + for (i = 0; i < num_table_entries; i++) { + struct data_rate_reg_info_t *drate_settings = + settings_table->data_rate_settings; + uint64_t bandwidth = + drate_settings[i].bandwidth; + ssize_t num_reg_entries = + drate_settings[i].data_rate_reg_array_size; + + if (phy_data_rate > bandwidth) { + CAM_DBG(CAM_CSIPHY, + "Skipping table [%d] %llu required: %llu", + i, bandwidth, phy_data_rate); + continue; + } + + CAM_DBG(CAM_CSIPHY, + "table[%d] BW : %llu Selected", i, bandwidth); + for (j = 0; j < num_reg_entries; j++) { + uint32_t reg_addr = + drate_settings[i].csiphy_data_rate_regs[j].reg_addr; + + uint32_t reg_data = + drate_settings[i].csiphy_data_rate_regs[j].reg_data; + + CAM_DBG(CAM_CSIPHY, + "writing reg : %x val : %x", + reg_addr, reg_data); + cam_io_w_mb(reg_data, + csiphybase + reg_addr); + } + break; + } +} + void cam_csiphy_cphy_irq_disable(struct csiphy_device *csiphy_dev) { int32_t i; @@ -476,6 +540,9 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) lane_pos++; } + if (csiphy_dev->csiphy_info.csiphy_3phase) + cam_csiphy_cphy_data_rate_config(csiphy_dev); + cam_csiphy_cphy_irq_config(csiphy_dev); return rc; @@ -658,7 +725,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = csiphy_dev; - + bridge_params.dev_id = CAM_CSIPHY; if (csiphy_acq_params.combo_mode >= 2) { CAM_ERR(CAM_CSIPHY, "Invalid combo_mode %d", csiphy_acq_params.combo_mode); diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 51cf9e953a41..cf81924d970a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -44,8 +44,10 @@ #define MAX_CSIPHY_REG_ARRAY 70 #define MAX_CSIPHY_CMN_REG_ARRAY 5 -#define MAX_LANES 5 -#define MAX_SETTINGS_PER_LANE 43 +#define MAX_LANES 5 +#define MAX_SETTINGS_PER_LANE 43 +#define MAX_DATA_RATES 3 +#define MAX_DATA_RATE_REGS 30 #define MAX_REGULATOR 5 #define CAMX_CSIPHY_DEV_NAME "cam-csiphy-driver" @@ -155,6 +157,32 @@ struct csiphy_reg_t { uint32_t csiphy_param_type; }; +struct csiphy_device; + +/* + * struct data_rate_reg_info_t + * @bandwidth: max bandwidth supported by this reg settings + * @data_rate_reg_array_size: number of reg value pairs in the array + * @csiphy_data_rate_regs: array of data rate specific reg value pairs + */ +struct data_rate_reg_info_t { + uint64_t bandwidth; + ssize_t data_rate_reg_array_size; + struct csiphy_reg_t csiphy_data_rate_regs[MAX_DATA_RATE_REGS]; +}; + +/** + * struct data_rate_settings_t + * @num_data_rate_settings: number of valid settings + * present in the data rate settings array + * @data_rate_settings: array of regsettings which are specific to + * data rate + */ +struct data_rate_settings_t { + ssize_t num_data_rate_settings; + struct data_rate_reg_info_t data_rate_settings[MAX_DATA_RATES]; +}; + /** * struct csiphy_ctrl_t * @csiphy_reg: Register address @@ -166,6 +194,12 @@ struct csiphy_reg_t { * @csiphy_3ph_reg: 3phase register set * @csiphy_2ph_3ph_mode_reg: * 2 phase 3phase combo register set + * @getclockvoting: function pointer which + * is used to find the clock voting + * for the sensor output data rate + * @data_rate_settings_table: + * Table which maintains the resgister + * settings specific to data rate */ struct csiphy_ctrl_t { struct csiphy_reg_parms_t csiphy_reg; @@ -176,6 +210,8 @@ struct csiphy_ctrl_t { struct csiphy_reg_t (*csiphy_2ph_combo_mode_reg)[MAX_SETTINGS_PER_LANE]; struct csiphy_reg_t (*csiphy_3ph_reg)[MAX_SETTINGS_PER_LANE]; struct csiphy_reg_t (*csiphy_2ph_3ph_mode_reg)[MAX_SETTINGS_PER_LANE]; + enum cam_vote_level (*getclockvoting)(struct csiphy_device *phy_dev); + struct data_rate_settings_t *data_rates_settings_table; }; /** @@ -190,6 +226,8 @@ struct csiphy_ctrl_t { * @settle_time : Settling time in ms * @settle_time_combo_sensor : Settling time in ms * @data_rate : Data rate in mbps + * @data_rate_combo_sensor: data rate of combo sensor + * in the the same phy * */ struct cam_csiphy_param { @@ -202,6 +240,7 @@ struct cam_csiphy_param { uint64_t settle_time; uint64_t settle_time_combo_sensor; uint64_t data_rate; + uint64_t data_rate_combo_sensor; }; /** diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index 0902601cebd5..0bf5aac2f090 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -17,6 +17,9 @@ #include "include/cam_csiphy_1_2_hwreg.h" #include "include/cam_csiphy_2_0_hwreg.h" +#define CSIPHY_3PH_DIVISOR 16 +#define CSIPHY_3PH_DIVISOR_12 32 +#define CSIPHY_2PH_DIVISOR 8 #define BYTES_PER_REGISTER 4 #define NUM_REGISTER_PER_LINE 4 #define REG_OFFSET(__start, __i) ((__start) + ((__i) * BYTES_PER_REGISTER)) @@ -79,10 +82,62 @@ int32_t cam_csiphy_mem_dmp(struct cam_hw_soc_info *soc_info) return rc; } +enum cam_vote_level get_clk_vote_default(struct csiphy_device *csiphy_dev) +{ + CAM_DBG(CAM_CSIPHY, "voting for SVS"); + return CAM_SVS_VOTE; +} + +enum cam_vote_level get_clk_voting_dynamic(struct csiphy_device *csiphy_dev) +{ + uint32_t cam_vote_level = 0; + uint32_t last_valid_vote = 0; + struct cam_hw_soc_info *soc_info; + uint64_t phy_data_rate = csiphy_dev->csiphy_info.data_rate; + + soc_info = &csiphy_dev->soc_info; + + if (csiphy_dev->is_acquired_dev_combo_mode) + phy_data_rate = max(phy_data_rate, + csiphy_dev->csiphy_info.data_rate_combo_sensor); + + if (csiphy_dev->csiphy_info.csiphy_3phase) { + if (csiphy_dev->is_csiphy_3phase_hw == CSI_3PHASE_HW_12) + do_div(phy_data_rate, CSIPHY_3PH_DIVISOR_12); + else + do_div(phy_data_rate, CSIPHY_3PH_DIVISOR); + } else { + do_div(phy_data_rate, CSIPHY_2PH_DIVISOR); + } + + /* round off to next integer */ + phy_data_rate += 1; + + for (cam_vote_level = 0; + cam_vote_level < CAM_MAX_VOTE; cam_vote_level++) { + if (soc_info->clk_level_valid[cam_vote_level] != true) + continue; + + if (soc_info->clk_rate[cam_vote_level][0] > + phy_data_rate) { + CAM_DBG(CAM_CSIPHY, + "match detected %s : %llu:%d level : %d", + soc_info->clk_name[0], + phy_data_rate, + soc_info->clk_rate[cam_vote_level][0], + cam_vote_level); + return cam_vote_level; + } + last_valid_vote = cam_vote_level; + } + return last_valid_vote; +} + int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) { int32_t rc = 0; struct cam_hw_soc_info *soc_info; + enum cam_vote_level vote_level = CAM_SVS_VOTE; soc_info = &csiphy_dev->soc_info; @@ -92,8 +147,9 @@ int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) return rc; } + vote_level = csiphy_dev->ctrl_reg->getclockvoting(csiphy_dev); rc = cam_soc_util_enable_platform_resource(soc_info, true, - CAM_SVS_VOTE, ENABLE_IRQ); + vote_level, ENABLE_IRQ); if (rc < 0) { CAM_ERR(CAM_CSIPHY, "failed to enable platform resources %d", rc); @@ -174,9 +230,11 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_1_0; csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_0; csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_0; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; csiphy_dev->hw_version = CSIPHY_VERSION_V10; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v1.1")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_1_reg; @@ -191,9 +249,11 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_1; csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_1; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->hw_version = CSIPHY_VERSION_V11; csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v1.2")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_reg; @@ -206,10 +266,13 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_common_reg_1_2; csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_2; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_voting_dynamic; csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; - csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW_12; csiphy_dev->hw_version = CSIPHY_VERSION_V12; csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v2.0")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; @@ -221,9 +284,11 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_2_0; csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_2_0; csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; csiphy_dev->hw_version = CSIPHY_VERSION_V20; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; } else { CAM_ERR(CAM_CSIPHY, "invalid hw version : 0x%x", csiphy_dev->hw_version); diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h index 68ca68ced31b..64d05616d2e3 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -34,6 +34,7 @@ #define CDBG(fmt, args...) pr_debug(fmt, ##args) #define CSI_3PHASE_HW 1 +#define CSI_3PHASE_HW_12 0x12 #define CSIPHY_VERSION_V35 0x35 #define CSIPHY_VERSION_V10 0x10 #define CSIPHY_VERSION_V11 0x11 diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 945910e96a55..edde07091d9e 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -19,10 +19,10 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 4, + .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 21, - .csiphy_3ph_config_array_size = 31, + .csiphy_2ph_config_array_size = 22, + .csiphy_3ph_config_array_size = 38, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; @@ -30,8 +30,10 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { struct csiphy_reg_t csiphy_common_reg_1_2[] = { {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, + {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, }; struct csiphy_reg_t csiphy_reset_reg_1_2[] = { @@ -76,10 +78,11 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -103,6 +106,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -126,6 +130,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -149,6 +154,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -172,6 +178,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -195,10 +202,11 @@ struct csiphy_reg_t {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -222,6 +230,7 @@ struct csiphy_reg_t {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -245,6 +254,7 @@ struct csiphy_reg_t {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -268,6 +278,7 @@ struct csiphy_reg_t {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -291,13 +302,14 @@ struct csiphy_reg_t {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, }; struct csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { - {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -305,10 +317,10 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x098C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x010C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -321,27 +333,34 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0144, 0x30, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { - {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x030C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -354,16 +373,23 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0344, 0x30, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AB0, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { - {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -371,10 +397,10 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x050C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -387,14 +413,107 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0544, 0x30, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BB0, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; +struct data_rate_settings_t data_rate_delta_table = { + .num_data_rate_settings = 3, + .data_rate_settings = { + { + /* (2.5 * 10**3 * 2.28) rounded value*/ + .bandwidth = 5700000000, + .data_rate_reg_array_size = 12, + .csiphy_data_rate_regs = { + {0x15C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + } + }, + { + /* (3.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 7980000000, + .data_rate_reg_array_size = 24, + .csiphy_data_rate_regs = { + {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + }, + { + /* (4.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 10260000000, + .data_rate_reg_array_size = 24, + .csiphy_data_rate_regs = { + {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + } + } +}; #endif /* _CAM_CSIPHY_1_2_HWREG_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index a04d97143592..06d6bd49b3b0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -357,7 +357,7 @@ static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = e_ctrl; - + bridge_params.dev_id = CAM_EEPROM; eeprom_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); e_ctrl->bridge_intf.device_hdl = eeprom_acq_dev.device_handle; @@ -439,17 +439,32 @@ static int32_t cam_eeprom_parse_memory_map( else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) validate_size = sizeof(struct cam_cmd_unconditional_wait); - if (remain_buf_len < validate_size) { + if (remain_buf_len < validate_size || + *num_map >= (MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE)) { CAM_ERR(CAM_EEPROM, "not enough buffer"); return -EINVAL; } switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; + + if (i2c_random_wr->header.count == 0 || + i2c_random_wr->header.count >= MSM_EEPROM_MAX_MEM_MAP_CNT || + (size_t)*num_map >= ((MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE) - + i2c_random_wr->header.count)) { + CAM_ERR(CAM_EEPROM, "OOB Error"); + return -EINVAL; + } cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_random_wr) + ((i2c_random_wr->header.count - 1) * sizeof(struct i2c_random_wr_payload)); + if (cmd_length_in_bytes > remain_buf_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer remaining"); + return -EINVAL; + } for (cnt = 0; cnt < (i2c_random_wr->header.count); cnt++) { map[*num_map + cnt].page.addr = @@ -472,6 +487,11 @@ static int32_t cam_eeprom_parse_memory_map( i2c_cont_rd = (struct cam_cmd_i2c_continuous_rd *)cmd_buf; cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_continuous_rd); + if (i2c_cont_rd->header.count >= U32_MAX - data->num_data) { + CAM_ERR(CAM_EEPROM, + "int overflow on eeprom memory block"); + return -EINVAL; + } map[*num_map].mem.addr = i2c_cont_rd->reg_addr; map[*num_map].mem.addr_type = i2c_cont_rd->header.addr_type; map[*num_map].mem.data_type = i2c_cont_rd->header.data_type; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h index 7ffafc377da6..9c36134a1b8f 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h @@ -35,7 +35,7 @@ #define PROPERTY_MAXSIZE 32 #define MSM_EEPROM_MEMORY_MAP_MAX_SIZE 80 -#define MSM_EEPROM_MAX_MEM_MAP_CNT 8 +#define MSM_EEPROM_MAX_MEM_MAP_CNT 16 #define MSM_EEPROM_MEM_MAP_PROPERTIES_CNT 8 enum cam_eeprom_state { diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c index 1a0edb8d4d02..f4c9d254df7c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -71,7 +71,7 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = fctrl; - + bridge_params.dev_id = CAM_FLASH; flash_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); fctrl->bridge_intf.device_hdl = diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c index a5c7039cc2da..711077cdfdf8 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c @@ -90,7 +90,7 @@ static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = o_ctrl; - + bridge_params.dev_id = CAM_OIS; ois_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); o_ctrl->bridge_intf.device_hdl = ois_acq_dev.device_handle; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c index 111f121757c1..a2a738d85714 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -776,7 +776,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = s_ctrl; - + bridge_params.dev_id = CAM_SENSOR; sensor_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); s_ctrl->bridge_intf.device_hdl = sensor_acq_dev.device_handle; diff --git a/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.c index 62b81aad8dd0..626473f8769a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, 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 @@ -1405,6 +1405,42 @@ end: } EXPORT_SYMBOL(cam_smmu_dealloc_qdss); +int cam_smmu_get_io_region_info(int32_t smmu_hdl, + dma_addr_t *iova, size_t *len) +{ + int32_t idx; + + if (!iova || !len || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].io_support) { + CAM_ERR(CAM_SMMU, + "I/O memory not supported for this SMMU handle"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + *iova = iommu_cb_set.cb_info[idx].io_info.iova_start; + *len = iommu_cb_set.cb_info[idx].io_info.iova_len; + + CAM_DBG(CAM_SMMU, + "I/O area for hdl = %x start addr = %pK len = %zu", + smmu_hdl, *iova, *len); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return 0; +} + int cam_smmu_get_region_info(int32_t smmu_hdl, enum cam_smmu_region_id region_id, struct cam_smmu_region_info *region_info) diff --git a/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.h b/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.h index caf326d6c716..6a6492dc60e8 100644 --- a/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.h +++ b/drivers/media/platform/msm/camera_v3/cam_smmu/cam_smmu_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, 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 @@ -389,4 +389,16 @@ int cam_smmu_alloc_qdss(int32_t smmu_hdl, */ int cam_smmu_dealloc_qdss(int32_t smmu_hdl); +/** + * @brief Get start addr & len of I/O region for a given cb + * + * @param smmu_hdl: SMMU handle identifying the context bank + * @param iova: IOVA address of allocated I/O region + * @param len: Length of allocated I/O memory + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_io_region_info(int32_t smmu_hdl, + dma_addr_t *iova, size_t *len); + #endif /* _CAM_SMMU_API_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c index d3f62d6a3e20..d4487efbf090 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c @@ -29,6 +29,20 @@ struct sync_device *sync_dev; */ static bool trigger_cb_without_switch; +void cam_sync_print_fence_table(void) +{ + int cnt; + + for (cnt = 0; cnt < CAM_SYNC_MAX_OBJS; cnt++) { + CAM_INFO(CAM_SYNC, "%d, %s, %d, %d, %d", + sync_dev->sync_table[cnt].sync_id, + sync_dev->sync_table[cnt].name, + sync_dev->sync_table[cnt].type, + sync_dev->sync_table[cnt].state, + atomic_read(&sync_dev->sync_table[cnt].ref_cnt)); + } +} + int cam_sync_create(int32_t *sync_obj, const char *name) { int rc; @@ -37,8 +51,15 @@ int cam_sync_create(int32_t *sync_obj, const char *name) do { idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); - if (idx >= CAM_SYNC_MAX_OBJS) + if (idx >= CAM_SYNC_MAX_OBJS) { + CAM_ERR(CAM_SYNC, + "Error: Unable to Create Sync Idx = %ld Reached Max!!", + idx); + sync_dev->err_cnt++; + if (sync_dev->err_cnt == 1) + cam_sync_print_fence_table(); return -ENOMEM; + } CAM_DBG(CAM_SYNC, "Index location available at idx: %ld", idx); bit = test_and_set_bit(idx, sync_dev->bitmap); } while (bit); @@ -765,6 +786,7 @@ static int cam_sync_open(struct file *filep) CAM_ERR(CAM_SYNC, "Sync device NULL"); return -ENODEV; } + sync_dev->err_cnt = 0; mutex_lock(&sync_dev->table_lock); if (sync_dev->open_cnt >= 1) { @@ -797,6 +819,7 @@ static int cam_sync_close(struct file *filep) rc = -ENODEV; return rc; } + sync_dev->err_cnt = 0; mutex_lock(&sync_dev->table_lock); sync_dev->open_cnt--; if (!sync_dev->open_cnt) { @@ -972,6 +995,7 @@ static int cam_sync_probe(struct platform_device *pdev) if (!sync_dev) return -ENOMEM; + sync_dev->err_cnt = 0; mutex_init(&sync_dev->table_lock); spin_lock_init(&sync_dev->cam_sync_eventq_lock); diff --git a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync_private.h b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync_private.h index eb2fb34fc33c..c3cb345a13fa 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync_private.h +++ b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync_private.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, 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 @@ -184,6 +184,7 @@ struct cam_signalable_info { * @work_queue : Work queue used for dispatching kernel callbacks * @cam_sync_eventq : Event queue used to dispatch user payloads to user space * @bitmap : Bitmap representation of all sync objects + * @err_cnt : Error counter to dump fence table */ struct sync_device { struct video_device *vdev; @@ -197,6 +198,7 @@ struct sync_device { struct v4l2_fh *cam_sync_eventq; spinlock_t cam_sync_eventq_lock; DECLARE_BITMAP(bitmap, CAM_SYNC_MAX_OBJS); + int err_cnt; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c index f3af61936625..36e6e1ca5410 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c @@ -77,7 +77,7 @@ static char supported_clk_info[256]; static char debugfs_dir_name[64]; static int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, - int32_t src_clk_idx, int32_t clk_rate) + int32_t src_clk_idx, int64_t clk_rate) { int i; long clk_rate_round; @@ -92,7 +92,7 @@ static int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, for (i = 0; i < CAM_MAX_VOTE; i++) { if (soc_info->clk_rate[i][src_clk_idx] >= clk_rate_round) { CAM_DBG(CAM_UTIL, - "soc = %d round rate = %ld actual = %d", + "soc = %d round rate = %ld actual = %lld", soc_info->clk_rate[i][src_clk_idx], clk_rate_round, clk_rate); return i; @@ -441,7 +441,7 @@ int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, * @return: Success or failure */ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, - int32_t clk_rate) + int64_t clk_rate) { int rc = 0; long clk_rate_round; @@ -449,7 +449,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, if (!clk || !clk_name) return -EINVAL; - CAM_DBG(CAM_UTIL, "set %s, rate %d", clk_name, clk_rate); + CAM_DBG(CAM_UTIL, "set %s, rate %lld", clk_name, clk_rate); if (clk_rate > 0) { clk_rate_round = clk_round_rate(clk, clk_rate); CAM_DBG(CAM_UTIL, "new_rate %ld", clk_rate_round); @@ -485,7 +485,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, } int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int32_t clk_rate) + int64_t clk_rate) { int32_t src_clk_idx; struct clk *clk = NULL; @@ -506,7 +506,7 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, if (soc_info->cam_cx_ipeak_enable && clk_rate >= 0) { apply_level = cam_soc_util_get_clk_level(soc_info, src_clk_idx, clk_rate); - CAM_DBG(CAM_UTIL, "set %s, rate %d dev_name = %s\n" + CAM_DBG(CAM_UTIL, "set %s, rate %lld dev_name = %s\n" "apply level = %d", soc_info->clk_name[src_clk_idx], clk_rate, soc_info->dev_name, apply_level); diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h index ee07f0eb0a5d..859fee7dfd8c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h @@ -397,7 +397,7 @@ int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, * @return: success or failure */ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int32_t clk_rate); + int64_t clk_rate); /** * cam_soc_util_get_option_clk_by_name() diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index 225bd239d9c8..5b0cec43d3eb 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -103,12 +103,22 @@ static enum msm_vidc_pixel_depth get_hal_pixel_depth(u32 hfi_bit_depth) return MSM_VIDC_BIT_DEPTH_UNSUPPORTED; } +static inline int validate_pkt_size(u32 rem_size, u32 msg_size) +{ + if (rem_size < msg_size) { + dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", + __func__, rem_size); + return false; + } + return true; +} + static int hfi_process_sess_evt_seq_changed(u32 device_id, struct hfi_msg_event_notify_packet *pkt, struct msm_vidc_cb_info *info) { struct msm_vidc_cb_event event_notify = {0}; - int num_properties_changed; + u32 num_properties_changed; struct hfi_frame_size *frame_sz; struct hfi_profile_level *profile_level; struct hfi_bit_depth *pixel_depth; @@ -116,17 +126,15 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, struct hfi_buffer_requirements *buf_req; struct hfi_index_extradata_input_crop_payload *crop_info; struct hfi_dpb_counts *dpb_counts; - u32 entropy_mode = 0; + u32 rem_size, entropy_mode = 0; u8 *data_ptr; int prop_id; enum msm_vidc_pixel_depth luma_bit_depth, chroma_bit_depth; struct hfi_colour_space *colour_info; - if (sizeof(struct hfi_msg_event_notify_packet) > pkt->size) { - dprintk(VIDC_ERR, - "hal_process_session_init_done: bad_pkt_size\n"); + if (!validate_pkt_size(pkt->size, + sizeof(struct hfi_msg_event_notify_packet))) return -E2BIG; - } event_notify.device_id = device_id; event_notify.session_id = (void *)(uintptr_t)pkt->session_id; @@ -147,10 +155,18 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, if (num_properties_changed) { data_ptr = (u8 *) &pkt->rg_ext_event_data[0]; + rem_size = pkt->size - sizeof(struct + hfi_msg_event_notify_packet) + sizeof(u32); do { + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; prop_id = (int) *((u32 *)data_ptr); + rem_size -= sizeof(u32); switch (prop_id) { case HFI_PROPERTY_PARAM_FRAME_SIZE: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_frame_size))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); frame_sz = (struct hfi_frame_size *) data_ptr; @@ -160,8 +176,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, frame_sz->height, frame_sz->width); data_ptr += sizeof(struct hfi_frame_size); + rem_size -= sizeof(struct hfi_frame_size); break; case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_profile_level))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); profile_level = (struct hfi_profile_level *) data_ptr; @@ -172,8 +192,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, profile_level->level); data_ptr += sizeof(struct hfi_profile_level); + rem_size -= sizeof(struct hfi_profile_level); break; case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_bit_depth))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); pixel_depth = (struct hfi_bit_depth *) data_ptr; /* @@ -204,8 +228,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, event_notify.bit_depth, luma_bit_depth, chroma_bit_depth); data_ptr += sizeof(struct hfi_bit_depth); + rem_size -= sizeof(struct hfi_bit_depth); break; case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_pic_struct))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); pic_struct = (struct hfi_pic_struct *) data_ptr; event_notify.pic_struct = @@ -215,8 +243,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, pic_struct->progressive_only); data_ptr += sizeof(struct hfi_pic_struct); + rem_size -= sizeof(struct hfi_pic_struct); break; case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_dpb_counts))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); dpb_counts = (struct hfi_dpb_counts *) data_ptr; event_notify.max_dpb_count = @@ -231,9 +263,13 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, dpb_counts->max_ref_count, dpb_counts->max_dec_buffering); data_ptr += - sizeof(struct hfi_pic_struct); + sizeof(struct hfi_dpb_counts); + rem_size -= sizeof(struct hfi_dpb_counts); break; case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_colour_space))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); colour_info = (struct hfi_colour_space *) data_ptr; @@ -244,8 +280,11 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, colour_info->colour_space); data_ptr += sizeof(struct hfi_colour_space); + rem_size -= sizeof(struct hfi_colour_space); break; case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); entropy_mode = *(u32 *)data_ptr; event_notify.entropy_mode = entropy_mode; @@ -253,8 +292,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, "Entropy Mode: 0x%x\n", entropy_mode); data_ptr += sizeof(u32); + rem_size -= sizeof(u32); break; case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_buffer_requirements))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); buf_req = (struct hfi_buffer_requirements *) @@ -266,8 +309,13 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, event_notify.capture_buf_count); data_ptr += sizeof(struct hfi_buffer_requirements); + rem_size -= + sizeof(struct hfi_buffer_requirements); break; case HFI_INDEX_EXTRADATA_INPUT_CROP: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_index_extradata_input_crop_payload))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); crop_info = (struct hfi_index_extradata_input_crop_payload *) @@ -288,6 +336,8 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, data_ptr += sizeof(struct hfi_index_extradata_input_crop_payload); + rem_size -= sizeof(struct + hfi_index_extradata_input_crop_payload); break; default: dprintk(VIDC_ERR, @@ -747,7 +797,7 @@ static inline void copy_cap_prop( } static int hfi_fill_codec_info(u8 *data_ptr, - struct vidc_hal_sys_init_done *sys_init_done) { + struct vidc_hal_sys_init_done *sys_init_done, u32 rem_size) { u32 i; u32 codecs = 0, codec_count = 0, size = 0; struct msm_vidc_capability *capability; @@ -757,6 +807,9 @@ static int hfi_fill_codec_info(u8 *data_ptr, if (prop_id == HFI_PROPERTY_PARAM_CODEC_SUPPORTED) { struct hfi_codec_supported *prop; + if (!validate_pkt_size(rem_size - sizeof(u32), + sizeof(struct hfi_codec_supported))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); prop = (struct hfi_codec_supported *) data_ptr; sys_init_done->dec_codec_supported = @@ -764,6 +817,8 @@ static int hfi_fill_codec_info(u8 *data_ptr, sys_init_done->enc_codec_supported = prop->encoder_codec_supported; size = sizeof(struct hfi_codec_supported) + sizeof(u32); + rem_size -= + sizeof(struct hfi_codec_supported) + sizeof(u32); } else { dprintk(VIDC_WARN, "%s: prop_id %#x, expected codec_supported property\n", @@ -804,14 +859,22 @@ static int hfi_fill_codec_info(u8 *data_ptr, } sys_init_done->codec_count = codec_count; + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; prop_id = *((u32 *)(orig_data_ptr + size)); if (prop_id == HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED) { - struct hfi_max_sessions_supported *prop = - (struct hfi_max_sessions_supported *) + struct hfi_max_sessions_supported *prop; + + if (!validate_pkt_size(rem_size - sizeof(u32), sizeof(struct + hfi_max_sessions_supported))) + return -E2BIG; + prop = (struct hfi_max_sessions_supported *) (orig_data_ptr + size + sizeof(u32)); sys_init_done->max_sessions_supported = prop->max_sessions; size += sizeof(struct hfi_max_sessions_supported) + sizeof(u32); + rem_size -= + sizeof(struct hfi_max_sessions_supported) + sizeof(u32); dprintk(VIDC_DBG, "max_sessions_supported %d\n", prop->max_sessions); } @@ -933,6 +996,21 @@ static enum vidc_status hfi_parse_init_done_properties( u32 prop_id, next_offset; u32 codecs = 0, domain = 0; +#define VALIDATE_PROPERTY_STRUCTURE_SIZE(pkt_size, property_size) ({\ + if (pkt_size < property_size) { \ + status = VIDC_ERR_BAD_PARAM; \ + break; \ + } \ +}) + +#define VALIDATE_PROPERTY_PAYLOAD_SIZE(pkt_size, payload_size, \ + property_count) ({\ + if (pkt_size/payload_size < property_count) { \ + status = VIDC_ERR_BAD_PARAM; \ + break; \ + } \ +}) + while (status == VIDC_ERR_NONE && num_properties && rem_bytes >= sizeof(u32)) { @@ -946,6 +1024,10 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_codec_mask_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + codecs = prop->codecs; domain = prop->video_domains; next_offset += sizeof(struct hfi_codec_mask_supported); @@ -958,11 +1040,14 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_capability_supported_info *) (data_ptr + next_offset); - if ((rem_bytes - next_offset) < prop->num_capabilities * - sizeof(struct hfi_capability_supported)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - sizeof(u32), + sizeof(struct hfi_capability_supported), + prop->num_capabilities); + next_offset += sizeof(u32) + prop->num_capabilities * sizeof(struct hfi_capability_supported); @@ -983,10 +1068,10 @@ static enum vidc_status hfi_parse_init_done_properties( char *fmt_ptr; struct hfi_uncompressed_plane_info *plane_info; - if ((rem_bytes - next_offset) < sizeof(*prop)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + num_format_entries = prop->format_entries; next_offset = sizeof(*prop); fmt_ptr = (char *)&prop->rg_format_info[0]; @@ -997,11 +1082,10 @@ static enum vidc_status hfi_parse_init_done_properties( plane_info = (struct hfi_uncompressed_plane_info *) fmt_ptr; - if ((rem_bytes - next_offset) < - sizeof(*plane_info)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*plane_info)); + bytes_to_skip = sizeof(*plane_info) - sizeof(struct hfi_uncompressed_plane_constraints) + @@ -1009,6 +1093,10 @@ static enum vidc_status hfi_parse_init_done_properties( sizeof(struct hfi_uncompressed_plane_constraints); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + bytes_to_skip); + fmt_ptr += bytes_to_skip; next_offset += bytes_to_skip; num_format_entries--; @@ -1021,6 +1109,15 @@ static enum vidc_status hfi_parse_init_done_properties( struct hfi_properties_supported *prop = (struct hfi_properties_supported *) (data_ptr + next_offset); + + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - sizeof(*prop) + + sizeof(u32), sizeof(u32), + prop->num_properties); + next_offset += sizeof(*prop) - sizeof(u32) + prop->num_properties * sizeof(u32); num_properties--; @@ -1032,6 +1129,15 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_profile_level_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - + sizeof(u32), + sizeof(struct hfi_profile_level), + prop->profile_count); + next_offset += sizeof(u32) + prop->profile_count * sizeof(struct hfi_profile_level); @@ -1056,6 +1162,10 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_nal_stream_format_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + copy_nal_stream_format_caps_to_sessions( prop->nal_stream_format_supported, capabilities, num_sessions, @@ -1068,12 +1178,18 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(u32)); next_offset += sizeof(u32); num_properties--; break; } case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(struct hfi_intra_refresh)); next_offset += sizeof(struct hfi_intra_refresh); num_properties--; @@ -1081,6 +1197,9 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_TME_VERSION_SUPPORTED: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(u32)); capabilities->tme_version = *((u32 *)(data_ptr + next_offset)); next_offset += @@ -1094,8 +1213,13 @@ static enum vidc_status hfi_parse_init_done_properties( __func__, data_ptr, prop_id); break; } - rem_bytes -= next_offset; - data_ptr += next_offset; + + if (rem_bytes > next_offset) { + rem_bytes -= next_offset; + data_ptr += next_offset; + } else { + rem_bytes = 0; + } } return status; @@ -1106,7 +1230,8 @@ enum vidc_status hfi_process_sys_init_done_prop_read( struct vidc_hal_sys_init_done *sys_init_done) { enum vidc_status status = VIDC_ERR_NONE; - u32 rem_bytes, bytes_read, num_properties; + int bytes_read; + u32 rem_bytes, num_properties; u8 *data_ptr; if (!pkt || !sys_init_done) { @@ -1114,6 +1239,11 @@ enum vidc_status hfi_process_sys_init_done_prop_read( "hfi_msg_sys_init_done: Invalid input\n"); return VIDC_ERR_FAIL; } + if (pkt->size < sizeof(struct hfi_msg_sys_init_done_packet)) { + dprintk(VIDC_ERR, "%s: bad_packet_size: %d\n", + __func__, pkt->size); + return VIDC_ERR_FAIL; + } rem_bytes = pkt->size - sizeof(struct hfi_msg_sys_init_done_packet) + sizeof(u32); @@ -1141,7 +1271,9 @@ enum vidc_status hfi_process_sys_init_done_prop_read( "Venus didn't set any properties in SYS_INIT_DONE"); return status; } - bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done); + bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done, rem_bytes); + if (bytes_read < 0) + return VIDC_ERR_FAIL; data_ptr += bytes_read; rem_bytes -= bytes_read; num_properties--; diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index faa47a6d538b..c2b259907cd4 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, 2019 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 @@ -685,7 +685,8 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) if (inst->fmts[fmt->type].fourcc == f->fmt.pix_mp.pixelformat && inst->prop.width[OUTPUT_PORT] == f->fmt.pix_mp.width && inst->prop.height[OUTPUT_PORT] == - f->fmt.pix_mp.height) { + f->fmt.pix_mp.height && + !inst->buffer_size_limit) { dprintk(VIDC_DBG, "No change in OUTPUT port params\n"); return 0; } diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index d8478fd5a903..a85bdaadbf35 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -40,6 +40,7 @@ #define FIRMWARE_SIZE 0X00A00000 #define REG_ADDR_OFFSET_BITMASK 0x000FFFFF #define QDSS_IOVA_START 0x80001000 +#define MIN_PAYLOAD_SIZE 3 static struct hal_device_data hal_ctxt; @@ -2971,25 +2972,55 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) log_level = VIDC_ERR; } +#define SKIP_INVALID_PKT(pkt_size, payload_size, pkt_hdr_size) ({ \ + if (pkt_size < pkt_hdr_size || \ + payload_size < MIN_PAYLOAD_SIZE || \ + payload_size > \ + (pkt_size - pkt_hdr_size + sizeof(u8))) { \ + dprintk(VIDC_ERR, \ + "%s: invalid msg size - %d\n", \ + __func__, pkt->msg_size); \ + continue; \ + } \ + }) + while (!__iface_dbgq_read(device, packet)) { - struct hfi_msg_sys_coverage_packet *pkt = - (struct hfi_msg_sys_coverage_packet *) packet; + struct hfi_packet_header *pkt = + (struct hfi_packet_header *) packet; + + if (pkt->size < sizeof(struct hfi_packet_header)) { + dprintk(VIDC_ERR, "Invalid pkt size - %s\n", + __func__); + continue; + } if (pkt->packet_type == HFI_MSG_SYS_COV) { + struct hfi_msg_sys_coverage_packet *pkt = + (struct hfi_msg_sys_coverage_packet *) packet; int stm_size = 0; + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + stm_size = stm_log_inv_ts(0, 0, pkt->rg_msg_data, pkt->msg_size); if (stm_size == 0) dprintk(VIDC_ERR, "In %s, stm_log returned size of 0\n", __func__); - } else { + + } else if (pkt->packet_type == HFI_MSG_SYS_DEBUG) { struct hfi_msg_sys_debug_packet *pkt = (struct hfi_msg_sys_debug_packet *) packet; + + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + + pkt->rg_msg_data[pkt->msg_size-1] = '\0'; dprintk(log_level, "%s", pkt->rg_msg_data); } } +#undef SKIP_INVALID_PKT if (local_packet) kfree(packet); diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index dd94a888deff..77a2cc0b3d2c 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, 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 @@ -900,6 +900,11 @@ struct vidc_hal_session_cmd_pkt { u32 session_id; }; +struct hfi_packet_header { + u32 size; + u32 packet_type; +}; + struct hfi_cmd_sys_init_packet { u32 size; u32 packet_type; diff --git a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c index 9f85f5d8b0f0..0e8f12369924 100644 --- a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c @@ -100,12 +100,22 @@ static enum msm_vidc_pixel_depth get_hal_pixel_depth(u32 hfi_bit_depth) return MSM_VIDC_BIT_DEPTH_UNSUPPORTED; } +static inline int validate_pkt_size(u32 rem_size, u32 msg_size) +{ + if (rem_size < msg_size) { + dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", + __func__, rem_size); + return false; + } + return true; +} + static int hfi_process_sess_evt_seq_changed(u32 device_id, struct hfi_msg_event_notify_packet *pkt, struct msm_vidc_cb_info *info) { struct msm_vidc_cb_event event_notify = {0}; - int num_properties_changed; + u32 num_properties_changed, rem_size; struct hfi_frame_size *frame_sz; struct hfi_profile_level *profile_level; struct hfi_bit_depth *pixel_depth; @@ -114,15 +124,11 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, int prop_id; enum msm_vidc_pixel_depth luma_bit_depth, chroma_bit_depth; struct hfi_colour_space *colour_info; - /* Initialize pic_struct to unknown as default */ event_notify.pic_struct = MSM_VIDC_PIC_STRUCT_UNKNOWN; - - if (sizeof(struct hfi_msg_event_notify_packet) > pkt->size) { - dprintk(VIDC_ERR, - "hal_process_session_init_done: bad_pkt_size\n"); + if (!validate_pkt_size(pkt->size, + sizeof(struct hfi_msg_event_notify_packet))) return -E2BIG; - } event_notify.device_id = device_id; event_notify.session_id = (void *)(uintptr_t)pkt->session_id; @@ -143,10 +149,18 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, if (num_properties_changed) { data_ptr = (u8 *) &pkt->rg_ext_event_data[0]; + rem_size = pkt->size - sizeof(struct + hfi_msg_event_notify_packet) + sizeof(u32); do { + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; prop_id = (int) *((u32 *)data_ptr); + rem_size -= sizeof(u32); switch (prop_id) { case HFI_PROPERTY_PARAM_FRAME_SIZE: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_frame_size))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); frame_sz = (struct hfi_frame_size *) data_ptr; @@ -156,8 +170,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, frame_sz->height, frame_sz->width); data_ptr += sizeof(struct hfi_frame_size); + rem_size -= sizeof(struct hfi_frame_size); break; case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_profile_level))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); profile_level = (struct hfi_profile_level *) data_ptr; @@ -166,8 +184,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, profile_level->level); data_ptr += sizeof(struct hfi_profile_level); + rem_size -= sizeof(struct hfi_profile_level); break; case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_bit_depth))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); pixel_depth = (struct hfi_bit_depth *) data_ptr; /* @@ -198,8 +220,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, event_notify.bit_depth, luma_bit_depth, chroma_bit_depth); data_ptr += sizeof(struct hfi_bit_depth); + rem_size -= sizeof(struct hfi_bit_depth); break; case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_pic_struct))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); pic_struct = (struct hfi_pic_struct *) data_ptr; event_notify.pic_struct = @@ -209,8 +235,12 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, pic_struct->progressive_only); data_ptr += sizeof(struct hfi_pic_struct); + rem_size -= sizeof(struct hfi_pic_struct); break; case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_colour_space))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); colour_info = (struct hfi_colour_space *) data_ptr; @@ -221,6 +251,8 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, colour_info->colour_space); data_ptr += sizeof(struct hfi_colour_space); + rem_size -= sizeof(struct hfi_colour_space); + break; break; default: dprintk(VIDC_ERR, @@ -579,7 +611,7 @@ static inline void copy_cap_prop( } static int hfi_fill_codec_info(u8 *data_ptr, - struct vidc_hal_sys_init_done *sys_init_done) { + struct vidc_hal_sys_init_done *sys_init_done, u32 rem_size) { u32 i; u32 codecs = 0, codec_count = 0, size = 0; struct msm_vidc_capability *capability; @@ -589,6 +621,9 @@ static int hfi_fill_codec_info(u8 *data_ptr, if (prop_id == HFI_PROPERTY_PARAM_CODEC_SUPPORTED) { struct hfi_codec_supported *prop; + if (!validate_pkt_size(rem_size - sizeof(u32), + sizeof(struct hfi_codec_supported))) + return -E2BIG; data_ptr = data_ptr + sizeof(u32); prop = (struct hfi_codec_supported *) data_ptr; sys_init_done->dec_codec_supported = @@ -596,6 +631,8 @@ static int hfi_fill_codec_info(u8 *data_ptr, sys_init_done->enc_codec_supported = prop->encoder_codec_supported; size = sizeof(struct hfi_codec_supported) + sizeof(u32); + rem_size -= + sizeof(struct hfi_codec_supported) + sizeof(u32); } else { dprintk(VIDC_WARN, "%s: prop_id %#x, expected codec_supported property\n", @@ -636,14 +673,22 @@ static int hfi_fill_codec_info(u8 *data_ptr, } sys_init_done->codec_count = codec_count; + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; prop_id = *((u32 *)(orig_data_ptr + size)); if (prop_id == HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED) { - struct hfi_max_sessions_supported *prop = - (struct hfi_max_sessions_supported *) + struct hfi_max_sessions_supported *prop; + + if (!validate_pkt_size(rem_size - sizeof(u32), sizeof(struct + hfi_max_sessions_supported))) + return -E2BIG; + prop = (struct hfi_max_sessions_supported *) (orig_data_ptr + size + sizeof(u32)); sys_init_done->max_sessions_supported = prop->max_sessions; size += sizeof(struct hfi_max_sessions_supported) + sizeof(u32); + rem_size -= + sizeof(struct hfi_max_sessions_supported) + sizeof(u32); dprintk(VIDC_DBG, "max_sessions_supported %d\n", prop->max_sessions); } @@ -798,6 +843,20 @@ static enum vidc_status hfi_parse_init_done_properties( { enum vidc_status status = VIDC_ERR_NONE; u32 prop_id, next_offset; +#define VALIDATE_PROPERTY_STRUCTURE_SIZE(pkt_size, property_size) ({\ + if (pkt_size < property_size) { \ + status = VIDC_ERR_BAD_PARAM; \ + break; \ + } \ +}) + +#define VALIDATE_PROPERTY_PAYLOAD_SIZE(pkt_size, payload_size, \ + property_count) ({\ + if (pkt_size/payload_size < property_count) { \ + status = VIDC_ERR_BAD_PARAM; \ + break; \ + } \ +}) while (status == VIDC_ERR_NONE && num_properties && rem_bytes >= sizeof(u32)) { @@ -811,6 +870,9 @@ static enum vidc_status hfi_parse_init_done_properties( struct hfi_codec_mask_supported *prop = (struct hfi_codec_mask_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); codecs = prop->codecs; domain = prop->video_domains; @@ -824,11 +886,14 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_capability_supported_info *) (data_ptr + next_offset); - if ((rem_bytes - next_offset) < prop->num_capabilities * - sizeof(struct hfi_capability_supported)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - sizeof(u32), + sizeof(struct hfi_capability_supported), + prop->num_capabilities); + next_offset += sizeof(u32) + prop->num_capabilities * sizeof(struct hfi_capability_supported); @@ -849,10 +914,10 @@ static enum vidc_status hfi_parse_init_done_properties( char *fmt_ptr; struct hfi_uncompressed_plane_info *plane_info; - if ((rem_bytes - next_offset) < sizeof(*prop)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + num_format_entries = prop->format_entries; next_offset = sizeof(*prop); fmt_ptr = (char *)&prop->rg_format_info[0]; @@ -863,17 +928,19 @@ static enum vidc_status hfi_parse_init_done_properties( plane_info = (struct hfi_uncompressed_plane_info *) fmt_ptr; - if ((rem_bytes - next_offset) < - sizeof(*plane_info)) { - status = VIDC_ERR_BAD_PARAM; - break; - } + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*plane_info)); + bytes_to_skip = sizeof(*plane_info) - sizeof(struct hfi_uncompressed_plane_constraints) + plane_info->num_planes * sizeof(struct hfi_uncompressed_plane_constraints); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + bytes_to_skip); fmt_ptr += bytes_to_skip; next_offset += bytes_to_skip; @@ -887,6 +954,13 @@ static enum vidc_status hfi_parse_init_done_properties( struct hfi_properties_supported *prop = (struct hfi_properties_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - sizeof(*prop) + + sizeof(u32), sizeof(u32), + prop->num_properties); next_offset += sizeof(*prop) - sizeof(u32) + prop->num_properties * sizeof(u32); num_properties--; @@ -903,6 +977,9 @@ static enum vidc_status hfi_parse_init_done_properties( (struct hfi_profile_level_supported *) (data_ptr + next_offset); + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); ptr = (char *) &prop->rg_profile_level[0]; prof_count = prop->profile_count; next_offset += sizeof(u32); @@ -915,6 +992,9 @@ static enum vidc_status hfi_parse_init_done_properties( } while (prof_count) { prof_level = (struct hfi_profile_level *)ptr; + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prof_level)); capability. profile_level.profile_level[count].profile = prof_level->profile; @@ -931,6 +1011,9 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(struct hfi_interlace_format_supported)); next_offset += sizeof(struct hfi_interlace_format_supported); num_properties--; @@ -938,6 +1021,9 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(struct hfi_nal_stream_format_supported)); next_offset += sizeof(struct hfi_nal_stream_format_supported); num_properties--; @@ -945,18 +1031,27 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(u32)); next_offset += sizeof(u32); num_properties--; break; } case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(u32)); next_offset += sizeof(u32); num_properties--; break; } case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(struct hfi_intra_refresh)); next_offset += sizeof(struct hfi_intra_refresh); num_properties--; @@ -967,13 +1062,21 @@ static enum vidc_status hfi_parse_init_done_properties( struct hfi_buffer_alloc_mode_supported *prop = (struct hfi_buffer_alloc_mode_supported *) (data_ptr + next_offset); - + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); if (prop->num_entries >= 32) { dprintk(VIDC_ERR, "%s - num_entries: %d from f/w seems suspect\n", __func__, prop->num_entries); break; } + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - + sizeof(struct hfi_buffer_alloc_mode_supported) + + sizeof(u32), + sizeof(u32), + prop->num_entries); next_offset += sizeof(struct hfi_buffer_alloc_mode_supported) - sizeof(u32) + prop->num_entries * sizeof(u32); @@ -991,8 +1094,12 @@ static enum vidc_status hfi_parse_init_done_properties( __func__, data_ptr, prop_id); break; } + if (rem_bytes > next_offset) { rem_bytes -= next_offset; data_ptr += next_offset; + } else { + rem_bytes = 0; + } } return status; @@ -1003,7 +1110,8 @@ enum vidc_status hfi_process_sys_init_done_prop_read( struct vidc_hal_sys_init_done *sys_init_done) { enum vidc_status status = VIDC_ERR_NONE; - u32 rem_bytes, bytes_read, num_properties; + int bytes_read; + u32 rem_bytes, num_properties; u8 *data_ptr; u32 codecs = 0, domain = 0; @@ -1012,6 +1120,11 @@ enum vidc_status hfi_process_sys_init_done_prop_read( "hfi_msg_sys_init_done: Invalid input\n"); return VIDC_ERR_FAIL; } + if (pkt->size < sizeof(struct hfi_msg_sys_init_done_packet)) { + dprintk(VIDC_ERR, "%s: bad_packet_size: %d\n", + __func__, pkt->size); + return VIDC_ERR_FAIL; + } rem_bytes = pkt->size - sizeof(struct hfi_msg_sys_init_done_packet) + sizeof(u32); @@ -1039,7 +1152,9 @@ enum vidc_status hfi_process_sys_init_done_prop_read( "Venus didn't set any properties in SYS_INIT_DONE"); return status; } - bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done); + bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done, rem_bytes); + if (bytes_read < 0) + return VIDC_ERR_FAIL; data_ptr += bytes_read; rem_bytes -= bytes_read; num_properties--; diff --git a/drivers/media/platform/msm/vidc_3x/venus_hfi.c b/drivers/media/platform/msm/vidc_3x/venus_hfi.c index 2db49fa558f5..f29e7f67d221 100644 --- a/drivers/media/platform/msm/vidc_3x/venus_hfi.c +++ b/drivers/media/platform/msm/vidc_3x/venus_hfi.c @@ -38,6 +38,7 @@ #define FIRMWARE_SIZE 0X00A00000 #define REG_ADDR_OFFSET_BITMASK 0x000FFFFF #define QDSS_IOVA_START 0x80001000 +#define MIN_PAYLOAD_SIZE 3 static struct hal_device_data hal_ctxt; @@ -3399,24 +3400,55 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) local_packet = true; } +#define SKIP_INVALID_PKT(pkt_size, payload_size, pkt_hdr_size) ({ \ + if (pkt_size < pkt_hdr_size || \ + payload_size < MIN_PAYLOAD_SIZE || \ + payload_size > \ + (pkt_size - pkt_hdr_size + sizeof(u8))) { \ + dprintk(VIDC_ERR, \ + "%s: invalid msg size - %d\n", \ + __func__, pkt->msg_size); \ + continue; \ + } \ + }) + while (!__iface_dbgq_read(device, packet)) { - struct hfi_msg_sys_coverage_packet *pkt = - (struct hfi_msg_sys_coverage_packet *) packet; + struct hfi_packet_header *pkt = + (struct hfi_packet_header *) packet; + + if (pkt->size < sizeof(struct hfi_packet_header)) { + dprintk(VIDC_ERR, "Invalid pkt size - %s\n", + __func__); + continue; + } + if (pkt->packet_type == HFI_MSG_SYS_COV) { + struct hfi_msg_sys_coverage_packet *pkt = + (struct hfi_msg_sys_coverage_packet *) packet; int stm_size = 0; + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + stm_size = stm_log_inv_ts(0, 0, pkt->rg_msg_data, pkt->msg_size); if (stm_size == 0) dprintk(VIDC_ERR, "In %s, stm_log returned size of 0\n", __func__); - } else { + + } else if (pkt->packet_type == HFI_MSG_SYS_DEBUG) { struct hfi_msg_sys_debug_packet *pkt = (struct hfi_msg_sys_debug_packet *) packet; + + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + + pkt->rg_msg_data[pkt->msg_size-1] = '\0'; dprintk(VIDC_FW, "%s", pkt->rg_msg_data); } } +#undef SKIP_INVALID_PKT if (local_packet) kfree(packet); diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h index 39904a584eb7..c09cf84c5d39 100644 --- a/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, 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 @@ -974,6 +974,11 @@ struct vidc_hal_session_cmd_pkt { u32 session_id; }; +struct hfi_packet_header { + u32 size; + u32 packet_type; +}; + struct hfi_cmd_sys_init_packet { u32 size; u32 packet_type; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index 25152eacb855..95925a01f99a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -839,10 +839,11 @@ int ipa3_qmi_ul_filter_request_send( if (req->firewall_rules_list[i].ip_type != QMI_IPA_IP_TYPE_V4_V01 && req->firewall_rules_list[i].ip_type != - QMI_IPA_IP_TYPE_V6_V01) + QMI_IPA_IP_TYPE_V6_V01) { IPAWANERR("Invalid IP type %d\n", req->firewall_rules_list[i].ip_type); - return -EINVAL; + return -EINVAL; + } } req_desc.max_msg_len = diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index ec438df89a2a..7756b9f3333a 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -342,6 +342,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(fcc_stepper_enable), POWER_SUPPLY_ATTR(cc_soc), POWER_SUPPLY_ATTR(qg_vbms_mode), + POWER_SUPPLY_ATTR(real_capacity), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index fff399f7f2ce..f18d7d306dd0 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -936,6 +936,11 @@ static int fg_get_prop_capacity(struct fg_chip *chip, int *val) return 0; } +static int fg_get_prop_real_capacity(struct fg_chip *chip, int *val) +{ + return fg_get_msoc(chip, val); +} + #define DEFAULT_BATT_TYPE "Unknown Battery" #define MISSING_BATT_TYPE "Missing Battery" #define LOADING_BATT_TYPE "Loading Battery" @@ -4084,6 +4089,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CC_STEP_SEL: pval->intval = chip->ttf.cc_step.sel; break; + case POWER_SUPPLY_PROP_REAL_CAPACITY: + rc = fg_get_prop_real_capacity(chip, &pval->intval); + break; default: pr_err("unsupported property %d\n", psp); rc = -EINVAL; @@ -4286,6 +4294,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_CC_STEP, POWER_SUPPLY_PROP_CC_STEP_SEL, + POWER_SUPPLY_PROP_REAL_CAPACITY, }; static const struct power_supply_desc fg_psy_desc = { diff --git a/drivers/power/supply/qcom/qpnp-fg.c b/drivers/power/supply/qcom/qpnp-fg.c index deccb20fec83..7df1f062db43 100644 --- a/drivers/power/supply/qcom/qpnp-fg.c +++ b/drivers/power/supply/qcom/qpnp-fg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, 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 @@ -1341,10 +1341,15 @@ static int fg_check_ima_exception(struct fg_chip *chip, bool check_hw_sts) if (run_err_clr_seq) { ret = fg_run_iacs_clear_sequence(chip); - if (!ret) - return -EAGAIN; - else + if (ret) { pr_err("Error clearing IMA exception ret=%d\n", ret); + return ret; + } + + if (check_hw_sts) + return 0; + else + return -EAGAIN; } return rc; diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 5030352ea650..9aef9b0e4ffc 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -1544,6 +1544,15 @@ static int qg_get_battery_capacity(struct qpnp_qg *chip, int *soc) return 0; } +static int qg_get_battery_capacity_real(struct qpnp_qg *chip, int *soc) +{ + mutex_lock(&chip->soc_lock); + *soc = chip->msoc; + mutex_unlock(&chip->soc_lock); + + return 0; +} + static int qg_get_charge_counter(struct qpnp_qg *chip, int *charge_counter) { int rc, cc_soc = 0; @@ -1704,6 +1713,9 @@ static int qg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: rc = qg_get_battery_capacity(chip, &pval->intval); break; + case POWER_SUPPLY_PROP_REAL_CAPACITY: + rc = qg_get_battery_capacity_real(chip, &pval->intval); + break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: rc = qg_get_battery_voltage(chip, &pval->intval); break; @@ -1823,6 +1835,7 @@ static int qg_property_is_writeable(struct power_supply *psy, static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_REAL_CAPACITY, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_OCV, diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index a68f2b02830f..7d79eacffc0c 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -2787,7 +2787,8 @@ static void smblib_eval_chg_termination(struct smb_charger *chg, u8 batt_status) union power_supply_propval pval = {0, }; int rc = 0; - rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CAPACITY, &pval); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_REAL_CAPACITY, &pval); if (rc < 0) { smblib_err(chg, "Couldn't read SOC value, rc=%d\n", rc); return; @@ -2801,6 +2802,8 @@ static void smblib_eval_chg_termination(struct smb_charger *chg, u8 batt_status) * to prevent overcharing. */ if ((batt_status == TERMINATE_CHARGE) && (pval.intval == 100)) { + chg->cc_soc_ref = 0; + chg->last_cc_soc = 0; alarm_start_relative(&chg->chg_termination_alarm, ms_to_ktime(CHG_TERM_WA_ENTRY_DELAY_MS)); } else if (pval.intval < 100) { @@ -2809,6 +2812,7 @@ static void smblib_eval_chg_termination(struct smb_charger *chg, u8 batt_status) * we exit the TERMINATE_CHARGE state and soc drops below 100% */ chg->cc_soc_ref = 0; + chg->last_cc_soc = 0; } } @@ -4160,7 +4164,8 @@ static void smblib_chg_termination_work(struct work_struct *work) if (rc < 0 || !pval.intval) goto out; - rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CAPACITY, &pval); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_REAL_CAPACITY, &pval); if (rc < 0 || (pval.intval < 100)) { vote(chg->usb_icl_votable, CHG_TERMINATION_VOTER, false, 0); goto out; @@ -4193,6 +4198,18 @@ static void smblib_chg_termination_work(struct work_struct *work) } /* + * In BSM a sudden jump in CC_SOC is not expected. If seen, its a + * good_ocv or updated capacity, reject it. + */ + if (chg->last_cc_soc && pval.intval > (chg->last_cc_soc + 100)) { + /* CC_SOC has increased by 1% from last time */ + chg->cc_soc_ref = pval.intval; + smblib_dbg(chg, PR_MISC, "cc_soc jumped(%d->%d), reset cc_soc_ref\n", + chg->last_cc_soc, pval.intval); + } + chg->last_cc_soc = pval.intval; + + /* * Suspend/Unsuspend USB input to keep cc_soc within the 0.5% to 0.75% * overshoot range of the cc_soc value at termination, to prevent * overcharging. diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 64b640fcfc5e..63061dae6271 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -413,6 +413,7 @@ struct smb_charger { bool fcc_stepper_enable; int charge_full_cc; int cc_soc_ref; + int last_cc_soc; /* workaround flag */ u32 wa_flags; diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index f131c79abeaa..bf10f2ed09fa 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -997,6 +997,7 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) SMEM_IPC_LOG(einfo, "kthread", cmd.id, cmd.param1, cmd.param2); } else { + memset(&cmd, 0, sizeof(cmd)); fifo_read(einfo, &cmd, sizeof(cmd)); SMEM_IPC_LOG(einfo, "IRQ", cmd.id, cmd.param1, cmd.param2); @@ -1101,6 +1102,7 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) cmd_data)->size; kfree(cmd_data); } else { + memset(&intent, 0, sizeof(intent)); fifo_read(einfo, &intent, sizeof(intent)); } diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index c895d219cf85..1e7a6395c533 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -49,6 +49,7 @@ #include <soc/qcom/service-notifier.h> #include <soc/qcom/socinfo.h> #include <soc/qcom/ramdump.h> +#include <linux/thermal.h> #include "wlan_firmware_service_v01.h" @@ -479,6 +480,9 @@ static struct icnss_priv { uint32_t fw_error_fatal_irq; uint32_t fw_early_crash_irq; struct completion unblock_shutdown; + struct thermal_cooling_device *tcdev; + unsigned long curr_thermal_state; + unsigned long max_thermal_state; } *penv; #ifdef CONFIG_ICNSS_DEBUG @@ -2364,16 +2368,20 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv) icnss_hw_power_on(priv); + icnss_block_shutdown(true); + ret = priv->ops->reinit(&priv->pdev->dev); if (ret < 0) { icnss_pr_err("Driver reinit failed: %d, state: 0x%lx\n", ret, priv->state); if (!priv->allow_recursive_recovery) ICNSS_ASSERT(false); + icnss_block_shutdown(false); goto out_power_off; } out: + icnss_block_shutdown(false); clear_bit(ICNSS_SHUTDOWN_DONE, &penv->state); return 0; @@ -2416,6 +2424,115 @@ out: return ret; } +static int icnss_tcdev_get_max_state(struct thermal_cooling_device *tcdev, + unsigned long *thermal_state) +{ + struct icnss_priv *priv = tcdev->devdata; + + *thermal_state = priv->max_thermal_state; + + return 0; +} + + +static int icnss_tcdev_get_cur_state(struct thermal_cooling_device *tcdev, + unsigned long *thermal_state) +{ + struct icnss_priv *priv = tcdev->devdata; + + *thermal_state = priv->curr_thermal_state; + + return 0; +} + + +static int icnss_tcdev_set_cur_state(struct thermal_cooling_device *tcdev, + unsigned long thermal_state) +{ + struct icnss_priv *priv = tcdev->devdata; + struct device *dev = &priv->pdev->dev; + int ret = 0; + + priv->curr_thermal_state = thermal_state; + + if (!priv->ops || !priv->ops->set_therm_state) + return 0; + + icnss_pr_vdbg("Cooling device set current state: %ld", + thermal_state); + + ret = priv->ops->set_therm_state(dev, thermal_state); + + if (ret) + icnss_pr_err("Setting Current Thermal State Failed: %d\n", ret); + + return 0; +} + +static struct thermal_cooling_device_ops icnss_cooling_ops = { + .get_max_state = icnss_tcdev_get_max_state, + .get_cur_state = icnss_tcdev_get_cur_state, + .set_cur_state = icnss_tcdev_set_cur_state, +}; + +int icnss_thermal_register(struct device *dev, unsigned long max_state) +{ + struct icnss_priv *priv = dev_get_drvdata(dev); + int ret = 0; + + priv->max_thermal_state = max_state; + + if (of_find_property(dev->of_node, "#cooling-cells", NULL)) { + priv->tcdev = thermal_of_cooling_device_register(dev->of_node, + "icnss", priv, + &icnss_cooling_ops); + if (IS_ERR_OR_NULL(priv->tcdev)) { + ret = PTR_ERR(priv->tcdev); + icnss_pr_err("Cooling device register failed: %d\n", + ret); + } else { + icnss_pr_vdbg("Cooling device registered"); + } + } else { + icnss_pr_dbg("Cooling device registration not supported"); + ret = -EOPNOTSUPP; + } + + return ret; +} +EXPORT_SYMBOL(icnss_thermal_register); + +void icnss_thermal_unregister(struct device *dev) +{ + struct icnss_priv *priv = dev_get_drvdata(dev); + + if (!IS_ERR_OR_NULL(priv->tcdev)) + thermal_cooling_device_unregister(priv->tcdev); + + priv->tcdev = NULL; +} +EXPORT_SYMBOL(icnss_thermal_unregister); + +int icnss_get_curr_therm_state(struct device *dev, + unsigned long *thermal_state) +{ + struct icnss_priv *priv = dev_get_drvdata(dev); + int ret = 0; + + if (IS_ERR_OR_NULL(priv->tcdev)) { + ret = PTR_ERR(priv->tcdev); + icnss_pr_err("Get current thermal state failed: %d\n", ret); + return ret; + } + + icnss_pr_vdbg("Cooling device current state: %ld", + priv->curr_thermal_state); + + *thermal_state = priv->curr_thermal_state; + return ret; +} +EXPORT_SYMBOL(icnss_get_curr_therm_state); + static int icnss_driver_event_register_driver(void *data) { int ret = 0; diff --git a/drivers/soc/qcom/msm_smem.c b/drivers/soc/qcom/msm_smem.c index 959aab998ee1..e4b40347490b 100644 --- a/drivers/soc/qcom/msm_smem.c +++ b/drivers/soc/qcom/msm_smem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, 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 @@ -182,6 +182,20 @@ static struct restart_notifier_block restart_notifiers[] = { static int init_smem_remote_spinlock(void); /** + * smem_get_toc() - Used for getting partitions TOC + * + * @return - Base address off partitions TOC + * + * Helper function to get base address of partition TOC, + * that is present in top 4K of first smem region. + */ +static struct smem_toc __iomem *smem_get_toc(void) +{ + return smem_areas[0].virt_addr + + smem_areas[0].size - 4 * 1024; +} + +/** * is_probe_done() - Did the probe function successfully complete * * @return - true if probe successfully completed, false if otherwise @@ -315,6 +329,7 @@ static void *__smem_get_entry_nonsecure(unsigned int id, unsigned int *size, int use_spinlocks = spinlocks_initialized && use_rspinlock; void *ret = 0; unsigned long flags = 0; + uint32_t e_size; int rc; if (!skip_init_check && !smem_initialized_check()) @@ -333,7 +348,11 @@ static void *__smem_get_entry_nonsecure(unsigned int id, unsigned int *size, if (toc[id].allocated) { phys_addr_t phys_base; - *size = toc[id].size; + e_size = toc[id].size; + if (e_size > smem_ram_size) + return ret; + *size = e_size; + barrier(); phys_base = toc[id].reserved & BASE_ADDR_MASK; @@ -368,12 +387,19 @@ static void *__smem_get_entry_secure(unsigned int id, bool skip_init_check, bool use_rspinlock) { + struct smem_partition_allocation_header *alloc_hdr; struct smem_partition_header *hdr; + uint32_t offset_free_uncached; + struct smem_toc __iomem *toc; + uint32_t offset_free_cached; unsigned long lflags = 0; - void *item = NULL; - struct smem_partition_allocation_header *alloc_hdr; + uint32_t partition_size; uint32_t partition_num; + uint32_t padding_data; + uint32_t padding_hdr; uint32_t a_hdr_size; + uint32_t item_size; + void *item = NULL; int rc; SMEM_DBG("%s(%u, %u, %u, %d, %d)\n", __func__, id, to_proc, @@ -393,9 +419,13 @@ static void *__smem_get_entry_secure(unsigned int id, return NULL; } + toc = smem_get_toc(); + if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset) { if (use_comm_partition) { partition_num = comm_partition.partition_num; + partition_size = + readl_relaxed(&toc->entry[partition_num].size); hdr = smem_areas[0].virt_addr + comm_partition.offset; } else { return __smem_get_entry_nonsecure(id, size, @@ -403,6 +433,7 @@ static void *__smem_get_entry_secure(unsigned int id, } } else { partition_num = partitions[to_proc].partition_num; + partition_size = readl_relaxed(&toc->entry[partition_num].size); hdr = smem_areas[0].virt_addr + partitions[to_proc].offset; } if (unlikely(!spinlocks_initialized)) { @@ -433,11 +464,20 @@ static void *__smem_get_entry_secure(unsigned int id, if (flags & SMEM_ITEM_CACHED_FLAG) { a_hdr_size = ALIGN(sizeof(*alloc_hdr), partitions[to_proc].size_cacheline); - for (alloc_hdr = (void *)(hdr) + hdr->size - a_hdr_size; + offset_free_cached = hdr->offset_free_cached; + if (WARN_ON(offset_free_cached > partition_size)) + return NULL; + + for (alloc_hdr = (void *)(hdr) + partition_size - a_hdr_size; (void *)(alloc_hdr) > (void *)(hdr) + - hdr->offset_free_cached; + offset_free_cached; alloc_hdr = (void *)(alloc_hdr) - - alloc_hdr->size - a_hdr_size) { + item_size - a_hdr_size) { + item_size = alloc_hdr->size; + padding_data = alloc_hdr->padding_data; + if (WARN_ON(padding_data > item_size + || item_size > partition_size)) + return NULL; if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) { LOG_ERR( "%s: SMEM corruption detected. Partition %d to %d at %p\n", @@ -450,20 +490,30 @@ static void *__smem_get_entry_secure(unsigned int id, } if (alloc_hdr->smem_type == id) { /* 8 byte alignment to match legacy */ - *size = ALIGN(alloc_hdr->size - - alloc_hdr->padding_data, 8); - item = (void *)(alloc_hdr) - alloc_hdr->size; + *size = ALIGN(item_size - padding_data, 8); + item = (void *)(alloc_hdr) - item_size; break; } } } else { + offset_free_uncached = hdr->offset_free_uncached; + if (WARN_ON(offset_free_uncached > partition_size)) + return NULL; + for (alloc_hdr = (void *)(hdr) + sizeof(*hdr); (void *)(alloc_hdr) < (void *)(hdr) + - hdr->offset_free_uncached; + offset_free_uncached; alloc_hdr = (void *)(alloc_hdr) + sizeof(*alloc_hdr) + - alloc_hdr->padding_hdr + - alloc_hdr->size) { + padding_hdr + + item_size) { + padding_hdr = alloc_hdr->padding_hdr; + padding_data = alloc_hdr->padding_data; + item_size = alloc_hdr->size; + if (WARN_ON(padding_hdr > partition_size + || item_size > partition_size + || padding_data > item_size)) + return NULL; if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) { LOG_ERR( "%s: SMEM corruption detected. Partition %d to %d at %p\n", @@ -476,11 +526,10 @@ static void *__smem_get_entry_secure(unsigned int id, } if (alloc_hdr->smem_type == id) { /* 8 byte alignment to match legacy */ - *size = ALIGN(alloc_hdr->size - - alloc_hdr->padding_data, 8); + *size = ALIGN(item_size - padding_data, 8); item = (void *)(alloc_hdr) + sizeof(*alloc_hdr) + - alloc_hdr->padding_hdr; + padding_hdr; break; } } @@ -571,10 +620,17 @@ static void *alloc_item_nonsecure(unsigned int id, unsigned int size_in) void *smem_base = smem_ram_base; struct smem_shared *shared = smem_base; struct smem_heap_entry *toc = shared->heap_toc; + uint32_t free_offset, heap_remaining; void *ret = NULL; - if (shared->heap_info.heap_remaining >= size_in) { - toc[id].offset = shared->heap_info.free_offset; + heap_remaining = shared->heap_info.heap_remaining; + free_offset = shared->heap_info.free_offset; + if (WARN_ON(heap_remaining > smem_ram_size + || free_offset > smem_ram_size)) + return NULL; + + if (heap_remaining >= size_in) { + toc[id].offset = free_offset; toc[id].size = size_in; /* * wmb() is necessary to ensure the allocation data is @@ -586,7 +642,7 @@ static void *alloc_item_nonsecure(unsigned int id, unsigned int size_in) shared->heap_info.free_offset += size_in; shared->heap_info.heap_remaining -= size_in; - ret = smem_base + toc[id].offset; + ret = smem_base + free_offset; /* * wmb() is necessary to ensure the heap data is consistent * before continuing to prevent race conditions with remote @@ -622,11 +678,15 @@ static void *alloc_item_secure(unsigned int id, unsigned int size_in, void *smem_base = smem_ram_base; struct smem_partition_header *hdr; struct smem_partition_allocation_header *alloc_hdr; + uint32_t offset_free_uncached; + struct smem_toc __iomem *toc; + uint32_t offset_free_cached; + uint32_t partition_size; + uint32_t partition_num; uint32_t a_hdr_size; uint32_t a_data_size; uint32_t size_cacheline; uint32_t free_space; - uint32_t partition_num; void *ret = NULL; if (to_proc == SMEM_COMM_HOST) { @@ -653,27 +713,35 @@ static void *alloc_item_secure(unsigned int id, unsigned int size_in, BUG(); } - free_space = hdr->offset_free_cached - - hdr->offset_free_uncached; + toc = smem_get_toc(); + partition_size = readl_relaxed(&toc->entry[partition_num].size); + + offset_free_cached = hdr->offset_free_cached; + offset_free_uncached = hdr->offset_free_uncached; + if (WARN_ON(offset_free_uncached > offset_free_cached + || offset_free_cached > partition_size)) + return NULL; + + free_space = offset_free_cached - offset_free_uncached; if (flags & SMEM_ITEM_CACHED_FLAG) { a_hdr_size = ALIGN(sizeof(*alloc_hdr), size_cacheline); a_data_size = ALIGN(size_in, size_cacheline); - if (free_space < a_hdr_size + a_data_size) { + if (free_space < a_hdr_size + a_data_size + || free_space < size_in) { SMEM_INFO( - "%s: id %u not enough memory %u (required %u)\n", - __func__, id, free_space, - a_hdr_size + a_data_size); + "%s: id %u not enough memory %u (required %u), (size_in %u)\n", + __func__, id, free_space, + a_hdr_size + a_data_size, size_in); return ret; } - alloc_hdr = (void *)(hdr) + hdr->offset_free_cached - - a_hdr_size; + alloc_hdr = (void *)(hdr) + offset_free_cached - a_hdr_size; alloc_hdr->canary = SMEM_ALLOCATION_CANARY; alloc_hdr->smem_type = id; alloc_hdr->size = a_data_size; alloc_hdr->padding_data = a_data_size - size_in; alloc_hdr->padding_hdr = a_hdr_size - sizeof(*alloc_hdr); - hdr->offset_free_cached = hdr->offset_free_cached - + hdr->offset_free_cached = offset_free_cached - a_hdr_size - a_data_size; ret = (void *)(alloc_hdr) - a_data_size; /* @@ -688,20 +756,21 @@ static void *alloc_item_secure(unsigned int id, unsigned int size_in, } else { a_hdr_size = sizeof(*alloc_hdr); a_data_size = ALIGN(size_in, 8); - if (free_space < a_hdr_size + a_data_size) { + if (free_space < a_hdr_size + a_data_size + || free_space < size_in) { SMEM_INFO( - "%s: id %u not enough memory %u (required %u)\n", - __func__, id, free_space, - a_hdr_size + a_data_size); + "%s: id %u not enough memory %u (required %u) (size_in %u)\n", + __func__, id, free_space, + a_hdr_size + a_data_size, size_in); return ret; } - alloc_hdr = (void *)(hdr) + hdr->offset_free_uncached; + alloc_hdr = (void *)(hdr) + offset_free_uncached; alloc_hdr->canary = SMEM_ALLOCATION_CANARY; alloc_hdr->smem_type = id; alloc_hdr->size = a_data_size; alloc_hdr->padding_data = a_data_size - size_in; alloc_hdr->padding_hdr = a_hdr_size - sizeof(*alloc_hdr); - hdr->offset_free_uncached = hdr->offset_free_uncached + + hdr->offset_free_uncached = offset_free_uncached + a_hdr_size + a_data_size; ret = alloc_hdr + 1; } @@ -892,6 +961,12 @@ unsigned int smem_get_free_space(unsigned int to_proc) { struct smem_partition_header *hdr; struct smem_shared *shared; + uint32_t offset_free_uncached; + struct smem_toc __iomem *toc; + uint32_t offset_free_cached; + uint32_t heap_remaining; + uint32_t p_size; + uint32_t p_num; if (to_proc >= NUM_SMEM_SUBSYSTEMS) { pr_err("%s: invalid to_proc:%d\n", __func__, to_proc); @@ -906,10 +981,24 @@ unsigned int smem_get_free_space(unsigned int to_proc) return UINT_MAX; } hdr = smem_areas[0].virt_addr + partitions[to_proc].offset; - return hdr->offset_free_cached - hdr->offset_free_uncached; + offset_free_cached = hdr->offset_free_cached; + offset_free_uncached = hdr->offset_free_uncached; + + toc = smem_get_toc(); + p_num = partitions[to_proc].partition_num; + p_size = readl_relaxed(&toc->entry[p_num].size); + if (WARN_ON(offset_free_uncached > offset_free_cached + || offset_free_cached > p_size)) + return -EINVAL; + + return offset_free_cached - offset_free_uncached; } shared = smem_ram_base; - return shared->heap_info.heap_remaining; + heap_remaining = shared->heap_info.heap_remaining; + if (WARN_ON(heap_remaining > smem_ram_size)) + return -EINVAL; + + return heap_remaining; } EXPORT_SYMBOL(smem_get_free_space); @@ -1216,8 +1305,8 @@ static void smem_init_security_partition(struct smem_toc_entry *entry, LOG_ERR("Smem partition %d hdr magic is bad\n", num); BUG(); } - if (!hdr->size) { - LOG_ERR("Smem partition %d size is 0\n", num); + if (hdr->size != entry->size) { + LOG_ERR("Smem partition %d size is invalid\n", num); BUG(); } if (hdr->offset_free_uncached > hdr->size) { diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c index 3f31fb1216b2..b99d6133aaea 100644 --- a/drivers/soc/qcom/smcinvoke.c +++ b/drivers/soc/qcom/smcinvoke.c @@ -1,7 +1,7 @@ /* * SMC Invoke driver * - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017,2019 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 @@ -306,7 +306,7 @@ static int marshal_in(const struct smcinvoke_cmd_req *req, const union smcinvoke_arg *args_buf, uint32_t tzhandle, uint8_t *buf, size_t buf_size, struct file **arr_filp) { - int ret = -EINVAL, i = 0; + int ret = -EINVAL, i = 0, j = 0; union smcinvoke_tz_args *tz_args = NULL; struct smcinvoke_msg_hdr msg_hdr = {tzhandle, req->op, req->counts}; uint32_t offset = sizeof(struct smcinvoke_msg_hdr) + @@ -351,7 +351,7 @@ static int marshal_in(const struct smcinvoke_cmd_req *req, } FOR_ARGS(i, req->counts, OI) { if (get_tzhandle_from_fd(args_buf[i].o.fd, - &arr_filp[i], &(tz_args->tzhandle))) + &arr_filp[j++], &(tz_args->tzhandle))) goto out; tz_args++; } diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 18ec52f2078a..bd1ced19fa85 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Sony Mobile Communications AB. - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2019 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 @@ -228,7 +228,7 @@ struct smem_region { * struct qcom_smem - device data for the smem device * @dev: device pointer * @hwlock: reference to a hwspinlock - * @partitions: list of pointers to partitions affecting the current + * @ptable_entries: list of pointers to partitions table entry of current * processor/host * @num_regions: number of @regions * @regions: list of the memory regions defining the shared memory @@ -238,12 +238,24 @@ struct qcom_smem { struct hwspinlock *hwlock; - struct smem_partition_header *partitions[SMEM_HOST_COUNT]; + struct smem_ptable_entry *ptable_entries[SMEM_HOST_COUNT]; unsigned num_regions; struct smem_region regions[0]; }; +/* Pointer to the one and only smem handle */ +static struct qcom_smem *__smem; + +/* Timeout (ms) for the trylock of remote spinlocks */ +#define HWSPINLOCK_TIMEOUT 1000 + +static struct smem_partition_header * +ptable_entry_to_phdr(struct smem_ptable_entry *entry) +{ + return __smem->regions[0].virt_base + le32_to_cpu(entry->offset); +} + static struct smem_private_entry * phdr_to_last_private_entry(struct smem_partition_header *phdr) { @@ -283,32 +295,32 @@ static void *entry_to_item(struct smem_private_entry *e) return p + sizeof(*e) + le16_to_cpu(e->padding_hdr); } -/* Pointer to the one and only smem handle */ -static struct qcom_smem *__smem; - -/* Timeout (ms) for the trylock of remote spinlocks */ -#define HWSPINLOCK_TIMEOUT 1000 - static int qcom_smem_alloc_private(struct qcom_smem *smem, - unsigned host, + struct smem_ptable_entry *entry, unsigned item, size_t size) { - struct smem_partition_header *phdr; struct smem_private_entry *hdr, *end; + struct smem_partition_header *phdr; size_t alloc_size; void *cached; + void *p_end; + + phdr = ptable_entry_to_phdr(entry); + p_end = (void *)phdr + le32_to_cpu(entry->size); - phdr = smem->partitions[host]; hdr = phdr_to_first_private_entry(phdr); end = phdr_to_last_private_entry(phdr); cached = phdr_to_first_cached_entry(phdr); + if (WARN_ON((void *)end > p_end || (void *)cached > p_end)) + return -EINVAL; + while (hdr < end) { if (hdr->canary != SMEM_PRIVATE_CANARY) { dev_err(smem->dev, - "Found invalid canary in host %d partition\n", - host); + "Found invalid canary in host %d:%d partition\n", + phdr->host0, phdr->host1); return -EINVAL; } @@ -317,6 +329,8 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem, hdr = private_entry_next(hdr); } + if (WARN_ON((void *)hdr > p_end)) + return -EINVAL; /* Check that we don't grow into the cached region */ alloc_size = sizeof(*hdr) + ALIGN(size, 8); @@ -389,6 +403,7 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem, */ int qcom_smem_alloc(unsigned host, unsigned item, size_t size) { + struct smem_ptable_entry *entry; unsigned long flags; int ret; @@ -407,10 +422,12 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size) if (ret) return ret; - if (host < SMEM_HOST_COUNT && __smem->partitions[host]) - ret = qcom_smem_alloc_private(__smem, host, item, size); - else + if (host < SMEM_HOST_COUNT && __smem->ptable_entries[host]) { + entry = __smem->ptable_entries[host]; + ret = qcom_smem_alloc_private(__smem, entry, item, size); + } else { ret = qcom_smem_alloc_global(__smem, item, size); + } hwspin_unlock_irqrestore(__smem->hwlock, &flags); @@ -422,9 +439,11 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, unsigned item, size_t *size) { + struct smem_global_entry *entry; struct smem_header *header; struct smem_region *area; - struct smem_global_entry *entry; + u64 entry_offset; + u32 e_size; u32 aux_base; unsigned i; @@ -442,9 +461,16 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, area = &smem->regions[i]; if (area->aux_base == aux_base || !aux_base) { + e_size = le32_to_cpu(entry->size); + entry_offset = le32_to_cpu(entry->offset); + + if (WARN_ON(e_size + entry_offset > area->size)) + return ERR_PTR(-EINVAL); + if (size != NULL) - *size = le32_to_cpu(entry->size); - return area->virt_base + le32_to_cpu(entry->offset); + *size = e_size; + + return area->virt_base + entry_offset; } } @@ -452,35 +478,58 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, } static void *qcom_smem_get_private(struct qcom_smem *smem, - unsigned host, + struct smem_ptable_entry *entry, unsigned item, size_t *size) { struct smem_partition_header *phdr; struct smem_private_entry *e, *end; + void *item_ptr, *p_end; + u32 partition_size; + u32 padding_data; + u32 e_size; + + phdr = ptable_entry_to_phdr(entry); + partition_size = le32_to_cpu(entry->size); + p_end = (void *)phdr + partition_size; - phdr = smem->partitions[host]; e = phdr_to_first_private_entry(phdr); end = phdr_to_last_private_entry(phdr); + if (WARN_ON((void *)end > p_end)) + return ERR_PTR(-EINVAL); + while (e < end) { if (e->canary != SMEM_PRIVATE_CANARY) { dev_err(smem->dev, - "Found invalid canary in host %d partition\n", - host); + "Found invalid canary in host %d:%d partition\n", + phdr->host0, phdr->host1); return ERR_PTR(-EINVAL); } if (le16_to_cpu(e->item) == item) { - if (size != NULL) - *size = le32_to_cpu(e->size) - - le16_to_cpu(e->padding_data); - - return entry_to_item(e); + if (size != NULL) { + e_size = le32_to_cpu(e->size); + padding_data = le16_to_cpu(e->padding_data); + + if (e_size < partition_size + && padding_data < e_size) + *size = e_size - padding_data; + else + return ERR_PTR(-EINVAL); + } + + item_ptr = entry_to_item(e); + if (WARN_ON(item_ptr > p_end)) + return ERR_PTR(-EINVAL); + + return item_ptr; } e = private_entry_next(e); } + if (WARN_ON((void *)e > p_end)) + return ERR_PTR(-EINVAL); return ERR_PTR(-ENOENT); } @@ -496,6 +545,7 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, */ void *qcom_smem_get(unsigned host, unsigned item, size_t *size) { + struct smem_ptable_entry *entry; unsigned long flags; int ret; void *ptr = ERR_PTR(-EPROBE_DEFER); @@ -509,11 +559,12 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size) if (ret) return ERR_PTR(ret); - if (host < SMEM_HOST_COUNT && __smem->partitions[host]) - ptr = qcom_smem_get_private(__smem, host, item, size); - else + if (host < SMEM_HOST_COUNT && __smem->ptable_entries[host]) { + entry = __smem->ptable_entries[host]; + ptr = qcom_smem_get_private(__smem, entry, item, size); + } else { ptr = qcom_smem_get_global(__smem, item, size); - + } hwspin_unlock_irqrestore(__smem->hwlock, &flags); return ptr; @@ -531,19 +582,28 @@ EXPORT_SYMBOL(qcom_smem_get); int qcom_smem_get_free_space(unsigned host) { struct smem_partition_header *phdr; + struct smem_ptable_entry *entry; struct smem_header *header; unsigned ret; if (!__smem) return -EPROBE_DEFER; - if (host < SMEM_HOST_COUNT && __smem->partitions[host]) { - phdr = __smem->partitions[host]; + if (host < SMEM_HOST_COUNT && __smem->ptable_entries[host]) { + entry = __smem->ptable_entries[host]; + phdr = ptable_entry_to_phdr(entry); + ret = le32_to_cpu(phdr->offset_free_cached) - le32_to_cpu(phdr->offset_free_uncached); + + if (ret > le32_to_cpu(entry->size)) + return -EINVAL; } else { header = __smem->regions[0].virt_base; ret = le32_to_cpu(header->available); + + if (ret > __smem->regions[0].size) + return -EINVAL; } return ret; @@ -616,7 +676,7 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, return -EINVAL; } - if (smem->partitions[remote_host]) { + if (smem->ptable_entries[remote_host]) { dev_err(smem->dev, "Already found a partition for host %d\n", remote_host); @@ -658,7 +718,7 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, return -EINVAL; } - smem->partitions[remote_host] = header; + smem->ptable_entries[remote_host] = entry; } return 0; diff --git a/drivers/soc/qcom/subsys-pil-bg.c b/drivers/soc/qcom/subsys-pil-bg.c index d1b5feadf989..b40c46c27db7 100644 --- a/drivers/soc/qcom/subsys-pil-bg.c +++ b/drivers/soc/qcom/subsys-pil-bg.c @@ -294,7 +294,6 @@ static int bg_powerup(const struct subsys_desc *subsys) __func__, bg_data->status_irq, ret); return ret; } - disable_irq(bg_data->status_irq); /* Enable status and err fatal irqs */ ret = pil_boot(&bg_data->desc); @@ -303,9 +302,6 @@ static int bg_powerup(const struct subsys_desc *subsys) "%s: BG PIL Boot failed\n", __func__); return ret; } - /* wait for msm_gpio_irq_handler to get invoked before enable irq */ - usleep_range(5000, 6000); - enable_irq(bg_data->status_irq); ret = wait_for_err_ready(bg_data); if (ret) { dev_err(bg_data->desc.dev, diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index b4e4bdde0d46..171ad5b1af96 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, 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 @@ -1015,7 +1015,8 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p, static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id) { struct buf_data *pcmds = file->private_data; - int blen, len, i; + unsigned int len; + int blen, i; char *buf, *bufp, *bp; struct dsi_ctrl_hdr *dchdr; @@ -1059,7 +1060,7 @@ static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id) while (len >= sizeof(*dchdr)) { dchdr = (struct dsi_ctrl_hdr *)bp; dchdr->dlen = ntohs(dchdr->dlen); - if (dchdr->dlen > len || dchdr->dlen < 0) { + if (dchdr->dlen > (len - sizeof(*dchdr)) || dchdr->dlen < 0) { pr_err("%s: dtsi cmd=%x error, len=%d\n", __func__, dchdr->dtype, dchdr->dlen); kfree(buf); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 44a2e3228b2a..7c244b461a69 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2560,7 +2560,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) if (!pin) { clear_inode_flag(inode, FI_PIN_FILE); - F2FS_I(inode)->i_gc_failures = 1; + f2fs_i_gc_failures_write(inode, 0); goto done; } diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index e0d9e8f27ed2..d440c2791ea7 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -221,8 +221,10 @@ static int do_read_inode(struct inode *inode) inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec); inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec); inode->i_generation = le32_to_cpu(ri->i_generation); - - fi->i_current_depth = le32_to_cpu(ri->i_current_depth); + if (S_ISDIR(inode->i_mode)) + fi->i_current_depth = le32_to_cpu(ri->i_current_depth); + else if (S_ISREG(inode->i_mode)) + fi->i_gc_failures = le16_to_cpu(ri->i_gc_failures); fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid); fi->i_flags = le32_to_cpu(ri->i_flags); fi->flags = 0; @@ -408,7 +410,11 @@ void update_inode(struct inode *inode, struct page *node_page) ri->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); ri->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); ri->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); - ri->i_current_depth = cpu_to_le32(F2FS_I(inode)->i_current_depth); + if (S_ISDIR(inode->i_mode)) + ri->i_current_depth = + cpu_to_le32(F2FS_I(inode)->i_current_depth); + else if (S_ISREG(inode->i_mode)) + ri->i_gc_failures = cpu_to_le16(F2FS_I(inode)->i_gc_failures); ri->i_xattr_nid = cpu_to_le32(F2FS_I(inode)->i_xattr_nid); ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags); ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino); diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index f1e1ff155d0d..b67a4c25af92 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -54,6 +54,9 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) F2FS_I(inode)->i_crtime = current_time(inode); inode->i_generation = sbi->s_next_generation++; + if (S_ISDIR(inode->i_mode)) + F2FS_I(inode)->i_current_depth = 1; + err = insert_inode_locked(inode); if (err) { err = -EINVAL; diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 4ddc2262baf1..8ed21e0836d2 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -223,6 +223,8 @@ static void recover_inode(struct inode *inode, struct page *page) inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); F2FS_I(inode)->i_advise = raw->i_advise; + F2FS_I(inode)->i_gc_failures = + le16_to_cpu(raw->i_gc_failures); recover_inline_flags(inode, raw); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index c850618b0a31..4180aadd185a 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -830,7 +830,6 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) /* Initialize f2fs-specific inode info */ atomic_set(&fi->dirty_pages, 0); - fi->i_current_depth = 1; init_rwsem(&fi->i_sem); INIT_LIST_HEAD(&fi->dirty_list); INIT_LIST_HEAD(&fi->gdirty_list); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 93b79a4b1dcc..905d070a4a9b 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -305,6 +305,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, POWER_SUPPLY_PROP_CC_SOC, POWER_SUPPLY_PROP_QG_VBMS_MODE, + POWER_SUPPLY_PROP_REAL_CAPACITY, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 0732a6fd33d1..40ce97a86e13 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -50,6 +50,7 @@ struct icnss_driver_ops { int (*suspend_noirq)(struct device *dev); int (*resume_noirq)(struct device *dev); int (*uevent)(struct device *dev, struct icnss_uevent_data *uevent); + int (*set_therm_state)(struct device *dev, unsigned long thermal_state); }; @@ -145,4 +146,8 @@ extern bool icnss_is_fw_down(void); extern bool icnss_is_rejuvenate(void); extern int icnss_trigger_recovery(struct device *dev); extern void icnss_block_shutdown(bool status); +extern int icnss_thermal_register(struct device *dev, unsigned long max_state); +extern void icnss_thermal_unregister(struct device *dev); +extern int icnss_get_curr_therm_state(struct device *dev, + unsigned long *thermal_state); #endif /* _ICNSS_WLAN_H_ */ diff --git a/include/trace/events/msm_cam.h b/include/trace/events/msm_cam.h index 3fc1a299e815..b0dc7eac8b7a 100644 --- a/include/trace/events/msm_cam.h +++ b/include/trace/events/msm_cam.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 2019, 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 @@ -131,6 +131,34 @@ TRACE_EVENT(msm_cam_ping_pong_debug_dump, ) ); +TRACE_EVENT(msm_cam_isp_status_dump, + TP_PROTO(char *event, uint32_t vfe_id, uint32_t frame_id, + uint32_t irq_status0, uint32_t irq_status1), + TP_ARGS(event, vfe_id, frame_id, irq_status0, + irq_status1), + TP_STRUCT__entry( + __field(char *, event) + __field(unsigned int, vfe_id) + __field(unsigned int, frame_id) + __field(unsigned int, irq_status0) + __field(unsigned int, irq_status1) + ), + TP_fast_assign( + __entry->event = event; + __entry->vfe_id = vfe_id; + __entry->frame_id = frame_id; + __entry->irq_status0 = irq_status0; + __entry->irq_status1 = irq_status1; + ), + TP_printk("%s vfe %d, frame %d, irq_st0 %x, irq_st1 %x\n", + __entry->event, + __entry->vfe_id, + __entry->frame_id, + __entry->irq_status0, + __entry->irq_status1 + ) +); + #endif /* _MSM_CAM_TRACE_H */ /* This part must be outside protection */ #include <trace/define_trace.h> diff --git a/include/uapi/media/cam_cpas.h b/include/uapi/media/cam_cpas.h index c5cbac82e71b..371b74c74500 100644 --- a/include/uapi/media/cam_cpas.h +++ b/include/uapi/media/cam_cpas.h @@ -6,6 +6,40 @@ #define CAM_FAMILY_CAMERA_SS 1 #define CAM_FAMILY_CPAS_SS 2 +/* AXI BW Voting Version */ +#define CAM_AXI_BW_VOTING_V2 2 + +/* AXI BW Voting Transaction Type */ +#define CAM_AXI_TRANSACTION_READ 0 +#define CAM_AXI_TRANSACTION_WRITE 1 + +/* AXI BW Voting Path Data Type */ +#define CAM_AXI_PATH_DATA_IFE_START_OFFSET 0 +#define CAM_AXI_PATH_DATA_IFE_LINEAR (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 0) +#define CAM_AXI_PATH_DATA_IFE_VID (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 1) +#define CAM_AXI_PATH_DATA_IFE_DISP (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 2) +#define CAM_AXI_PATH_DATA_IFE_STATS (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 3) +#define CAM_AXI_PATH_DATA_IFE_RDI0 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 4) +#define CAM_AXI_PATH_DATA_IFE_RDI1 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 5) +#define CAM_AXI_PATH_DATA_IFE_RDI2 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 6) +#define CAM_AXI_PATH_DATA_IFE_RDI3 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 7) +#define CAM_AXI_PATH_DATA_IFE_PDAF (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 8) +#define CAM_AXI_PATH_DATA_IFE_PIXEL_RAW \ + (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 9) +#define CAM_AXI_PATH_DATA_IFE_MAX_OFFSET \ + (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 31) + +#define CAM_AXI_PATH_DATA_IPE_START_OFFSET 32 +#define CAM_AXI_PATH_DATA_IPE_RD_IN (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 0) +#define CAM_AXI_PATH_DATA_IPE_RD_REF (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 1) +#define CAM_AXI_PATH_DATA_IPE_WR_VID (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 2) +#define CAM_AXI_PATH_DATA_IPE_WR_DISP (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 3) +#define CAM_AXI_PATH_DATA_IPE_WR_REF (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 4) +#define CAM_AXI_PATH_DATA_IPE_MAX_OFFSET \ + (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 31) + +#define CAM_AXI_PATH_DATA_ALL 256 + /** * struct cam_cpas_query_cap - CPAS query device capability payload * @@ -22,4 +56,29 @@ struct cam_cpas_query_cap { struct cam_hw_version cpas_version; }; +/** + * struct cam_axi_per_path_bw_vote - Per path bandwidth vote information + * + * @usage_data client usage data (left/right/rdi) + * @transac_type Transaction type on the path (read/write) + * @path_data_type Path for which vote is given (video, display, rdi) + * @reserved Reserved for alignment + * @camnoc_bw CAMNOC bw for this path + * @mnoc_ab_bw MNOC AB bw for this path + * @mnoc_ib_bw MNOC IB bw for this path + * @ddr_ab_bw DDR AB bw for this path + * @ddr_ib_bw DDR IB bw for this path + */ +struct cam_axi_per_path_bw_vote { + uint32_t usage_data; + uint32_t transac_type; + uint32_t path_data_type; + uint32_t reserved; + uint64_t camnoc_bw; + uint64_t mnoc_ab_bw; + uint64_t mnoc_ib_bw; + uint64_t ddr_ab_bw; + uint64_t ddr_ib_bw; +}; + #endif /* __UAPI_CAM_CPAS_H__ */ diff --git a/include/uapi/media/cam_icp.h b/include/uapi/media/cam_icp.h index f2c1c91692d4..5b4a6045d9ce 100644 --- a/include/uapi/media/cam_icp.h +++ b/include/uapi/media/cam_icp.h @@ -2,6 +2,7 @@ #define __UAPI_CAM_ICP_H__ #include "cam_defs.h" +#include "cam_cpas.h" /* icp, ipe, bps, cdm(ipe/bps) are used in querycap */ #define CAM_ICP_DEV_TYPE_A5 1 @@ -66,6 +67,26 @@ #define CAM_ICP_CMD_GENERIC_BLOB_CFG_IO 0x2 #define CAM_ICP_CMD_GENERIC_BLOB_FW_MEM_MAP 0x3 #define CAM_ICP_CMD_GENERIC_BLOB_FW_MEM_UNMAP 0x4 +#define CAM_ICP_CMD_GENERIC_BLOB_CLK_V2 0x5 + +/** + * struct cam_icp_clk_bw_request_v2 + * + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @reserved: For memory alignment + * @num_paths: Number of axi paths in bw request + * @axi_path: Per path vote info for IPE/BPS + */ +struct cam_icp_clk_bw_request_v2 { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint32_t reserved; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +}; /** * struct cam_icp_clk_bw_request diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index 995d6ec7e4b2..7489b72031b7 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -4,7 +4,7 @@ #include "cam_defs.h" #include "cam_isp_vfe.h" #include "cam_isp_ife.h" - +#include "cam_cpas.h" /* ISP driver name */ #define CAM_ISP_DEV_NAME "cam-isp" @@ -91,6 +91,13 @@ #define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 4 #define CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG 5 #define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 6 +#define CAM_ISP_GENERIC_BLOB_TYPE_INIT_FRAME_DROP 10 + +/* Per Path Usage Data */ +#define CAM_ISP_USAGE_INVALID 0 +#define CAM_ISP_USAGE_LEFT_PX 1 +#define CAM_ISP_USAGE_RIGHT_PX 2 +#define CAM_ISP_USAGE_RDI 3 /* Query devices */ /** @@ -362,7 +369,6 @@ struct cam_isp_csid_clock_config { * @cam_bw_bps: Bandwidth vote for CAMNOC * @ext_bw_bps: Bandwidth vote for path-to-DDR after CAMNOC */ - struct cam_isp_bw_vote { uint32_t resource_id; uint32_t reserved; @@ -379,7 +385,6 @@ struct cam_isp_bw_vote { * @right_pix_vote: Bandwidth vote for right ISP * @rdi_vote: RDI bandwidth requirements */ - struct cam_isp_bw_config { uint32_t usage_type; uint32_t num_rdi; @@ -408,6 +413,19 @@ struct cam_isp_bw_config_ab { } __attribute__((packed)); /** + * struct cam_isp_bw_config_v2 - Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_paths: Number of axi data paths + * @axi_path Per path vote info + */ +struct cam_isp_bw_config_v2 { + uint32_t usage_type; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +} __attribute__((packed)); + +/** * struct cam_fe_config - Fetch Engine configuration * * @version: fetch engine veriosn @@ -479,4 +497,14 @@ struct cam_isp_acquire_hw_info { #define CAM_ISP_ACQUIRE_OUT_VER0 0x3000 +/** + * struct cam_isp_init_frame_drop_config - init frame drop configuration + * + * @init_frame_drop: Initial number of frames needs to drop + */ + +struct cam_isp_init_frame_drop_config { + uint32_t init_frame_drop; +} __attribute__((packed)); + #endif /* __UAPI_CAM_ISP_H__ */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index b903078dccbd..9b9f97bd50d5 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -35,6 +35,7 @@ * It includes both session and device handles */ #define CAM_REQ_MGR_MAX_HANDLES 64 +#define CAM_REQ_MGR_MAX_HANDLES_V2 128 #define MAX_LINKS_PER_SESSION 2 /* V4L event type which user space will subscribe to */ @@ -121,6 +122,20 @@ struct cam_req_mgr_link_info { int32_t link_hdl; }; +struct cam_req_mgr_link_info_v2 { + int32_t session_hdl; + uint32_t num_devices; + int32_t dev_hdls[CAM_REQ_MGR_MAX_HANDLES_V2]; + int32_t link_hdl; +}; + +struct cam_req_mgr_ver_info { + uint32_t version; + union { + struct cam_req_mgr_link_info link_info_v1; + struct cam_req_mgr_link_info_v2 link_info_v2; + } u; +}; /** * struct cam_req_mgr_unlink_info * @session_hdl: input param - session handle @@ -230,6 +245,7 @@ struct cam_req_mgr_link_control { #define CAM_REQ_MGR_RELEASE_BUF (CAM_COMMON_OPCODE_MAX + 11) #define CAM_REQ_MGR_CACHE_OPS (CAM_COMMON_OPCODE_MAX + 12) #define CAM_REQ_MGR_LINK_CONTROL (CAM_COMMON_OPCODE_MAX + 13) +#define CAM_REQ_MGR_LINK_V2 (CAM_COMMON_OPCODE_MAX + 14) /* end of cam_req_mgr opcodes */ #define CAM_MEM_FLAG_HW_READ_WRITE (1<<0) diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 5639d7b0873d..bde2b7bed16d 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, 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 @@ -323,14 +323,19 @@ update_window_start(struct rq *rq, u64 wallclock, int event) int register_cpu_cycle_counter_cb(struct cpu_cycle_counter_cb *cb) { + unsigned long flags; + mutex_lock(&cluster_lock); if (!cb->get_cpu_cycle_counter) { mutex_unlock(&cluster_lock); return -EINVAL; } + acquire_rq_locks_irqsave(cpu_possible_mask, &flags); cpu_cycle_counter_cb = *cb; use_cycle_counter = true; + release_rq_locks_irqrestore(cpu_possible_mask, &flags); + mutex_unlock(&cluster_lock); return 0; diff --git a/net/core/sockev_nlmcast.c b/net/core/sockev_nlmcast.c index 6bc3d7a5cdc6..7b872a1d09b4 100644 --- a/net/core/sockev_nlmcast.c +++ b/net/core/sockev_nlmcast.c @@ -72,11 +72,13 @@ static int sockev_client_cb(struct notifier_block *nb, sock = (struct socket *)data; if (!socknlmsgsk || !sock) - goto done; + goto sk_null; sk = sock->sk; if (!sk) - goto done; + goto sk_null; + + sock_hold(sk); if (sk->sk_family != AF_INET && sk->sk_family != AF_INET6) goto done; @@ -109,6 +111,8 @@ static int sockev_client_cb(struct notifier_block *nb, smsg->skflags = sk->sk_flags; nlmsg_notify(socknlmsgsk, skb, 0, SKNLGRP_SOCKEV, 0, GFP_KERNEL); done: + sock_put(sk); +sk_null: return 0; } |