diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2019-06-21 03:16:55 -0700 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2019-06-21 03:16:55 -0700 |
commit | d96dd278eb4cb0755bc77ea866d9ea75bd169b3c (patch) | |
tree | e69ef3ba8cb663c3e78331a59b1ace911a571001 | |
parent | cb2608fb6c759ccab3470f841778a7130fa10a09 (diff) | |
parent | c6f5ddba623003a06b373def156264fa993723df (diff) |
Merge c6f5ddba623003a06b373def156264fa993723df on remote branchLA.UM.7.3.r1-07900-sdm845.0
Change-Id: I05e169bcbc3c51c7205311c29bb9418fd65afe88
90 files changed, 1897 insertions, 602 deletions
diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi index c437ef1dbfac..6f46c7ed2886 100644 --- a/arch/arm64/boot/dts/qcom/qcs605.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi @@ -84,6 +84,10 @@ status = "disabled"; }; +&sde_dp { + qcom,max-pclk-frequency-khz = <675000>; +}; + &mem_dump { rpmh { qcom,dump-size = <0x400000>; diff --git a/arch/arm64/boot/dts/qcom/qm215-regulator.dtsi b/arch/arm64/boot/dts/qcom/qm215-regulator.dtsi index a6dc66a7621e..6b44215b8ab9 100644 --- a/arch/arm64/boot/dts/qcom/qm215-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/qm215-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 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 @@ -549,9 +549,15 @@ qcom,cpr-voltage-scaling-factor-max = <0 2000 2000>; qcom,cpr-scaled-init-voltage-as-ceiling; qcom,cpr-fuse-revision = <69 39 3 0>; + qcom,pvs-version-fuse-sel = <37 40 3 0>; /* foundry */ + qcom,cpr-fuse-version-map = + <(-1) 1 (-1) (-1) (-1) (-1)>, + <(-1) (-1) (-1) (-1) (-1) (-1)>; qcom,cpr-quotient-adjustment = + <30 20 0>, <50 40 50>; qcom,cpr-init-voltage-adjustment = + <0 0 0>, <30000 5000 10000>; qcom,cpr-enable; }; diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi index cef55344925f..867193af64cc 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi @@ -1,5 +1,5 @@ /* - * 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 @@ -15,6 +15,8 @@ &blsp1_uart2 { status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; }; &pm8953_gpios { diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi index 913d079bdb98..e1623e0b960d 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi @@ -1,5 +1,5 @@ /* - * 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 @@ -15,6 +15,8 @@ &blsp1_uart2 { status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; }; &pm8953_gpios { diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi index 4da0e524e9cb..537d9fc278d8 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi @@ -1,5 +1,5 @@ /* - * 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 @@ -16,6 +16,8 @@ &blsp1_uart2 { status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; }; &sdhc_1 { diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi index 9a567a39ff3d..cf31c40f7076 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi @@ -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 @@ -605,7 +605,7 @@ qcom,aux-cfg8-settings = [40 bb]; qcom,aux-cfg9-settings = [44 03]; - qcom,max-pclk-frequency-khz = <675000>; + qcom,max-pclk-frequency-khz = <300000>; qcom,ctrl-supply-entries { #address-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts index 109c72006b88..7c69f192d6cc 100644 --- a/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts +++ b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts @@ -25,7 +25,8 @@ compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; qcom,msm-id = <265 0>, <301 0>; - qcom,board-id = <8 0x10f>; + qcom,board-id = <8 0x10f>, + <8 0x117>; qcom,pmic-id = <0x0001001b 0x0 0x0 0x0>, <0x0001011b 0x0 0x0 0x0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-1gb-wtp.dts b/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-1gb-wtp.dts index 34c887dc2915..7bd95f164690 100644 --- a/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-1gb-wtp.dts +++ b/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-1gb-wtp.dts @@ -1,5 +1,5 @@ /* - * 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 @@ -27,7 +27,8 @@ <258 0>, <275 0>, <300 0>; - qcom,board-id = <8 0xf>; + qcom,board-id = <8 0xf>, + <8 0x17>; qcom,pmic-id = <0x0001001b 0x0 0x0 0x0>, <0x0001011b 0x0 0x0 0x0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts b/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts index 5df6dc42f122..e271b89c6b49 100644 --- a/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts +++ b/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts @@ -26,8 +26,7 @@ qcom,msm-id = <245 0>, <258 0>, <275 0>, - <300 0>, - <301 0>; + <300 0>; qcom,board-id = <8 0x10f>, <8 0x117>; qcom,pmic-id = <0x0001001b 0x0 0x0 0x0>, diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig index 5c305104dd12..2d7eb0f59ac2 100644 --- a/arch/arm64/configs/sdm670-perf_defconfig +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -580,6 +580,7 @@ CONFIG_ARM_GIC_V3_ACL=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_NVMEM=y +# CONFIG_NVMEM_SYSFS is not set CONFIG_QCOM_QFPROM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig index 35539f0aaba2..9e588c5ccd7b 100644 --- a/arch/arm64/configs/sdm670_defconfig +++ b/arch/arm64/configs/sdm670_defconfig @@ -600,6 +600,7 @@ CONFIG_PHY_XGENE=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_NVMEM=y +# CONFIG_NVMEM_SYSFS is not set CONFIG_QCOM_QFPROM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 9f1bba621829..cd63d71551fe 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -386,6 +386,7 @@ static inline int pmd_protnone(pmd_t pmd) #define pud_write(pud) pte_write(pud_pte(pud)) #define pud_pfn(pud) (((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT) +#define pfn_pud(pfn,prot) (__pud(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) #define set_pmd_at(mm, addr, pmdp, pmd) set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd)) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 6e989ebdb9ca..a9dbfc9893a7 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -135,6 +135,17 @@ static phys_addr_t __init early_pgtable_alloc(void) return phys; } +static bool pgattr_change_is_safe(u64 old, u64 new) +{ + /* + * The following mapping attributes may be updated in live + * kernel mappings without the need for break-before-make. + */ + static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE; + + return old == 0 || new == 0 || ((old ^ new) & ~mask) == 0; +} + static void alloc_init_pte(pmd_t *pmd, unsigned long addr, unsigned long end, unsigned long pfn, pgprot_t prot, @@ -826,23 +837,33 @@ int __init arch_ioremap_pmd_supported(void) int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot) { - /* ioremap_page_range doesn't honour BBM */ - if (pud_present(READ_ONCE(*pud))) + pgprot_t sect_prot = __pgprot(PUD_TYPE_SECT | + pgprot_val(mk_sect_prot(prot))); + pud_t new_pud = pfn_pud(__phys_to_pfn(phys), sect_prot); + + /* Only allow permission changes for now */ + if (!pgattr_change_is_safe(READ_ONCE(pud_val(*pud)), + pud_val(new_pud))) return 0; BUG_ON(phys & ~PUD_MASK); - set_pud(pud, __pud(phys | PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot)))); + set_pud(pud, new_pud); return 1; } int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot) { - /* ioremap_page_range doesn't honour BBM */ - if (pmd_present(READ_ONCE(*pmd))) + pgprot_t sect_prot = __pgprot(PMD_TYPE_SECT | + pgprot_val(mk_sect_prot(prot))); + pmd_t new_pmd = pfn_pmd(__phys_to_pfn(phys), sect_prot); + + /* Only allow permission changes for now */ + if (!pgattr_change_is_safe(READ_ONCE(pmd_val(*pmd)), + pmd_val(new_pmd))) return 0; BUG_ON(phys & ~PMD_MASK); - set_pmd(pmd, __pmd(phys | PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot)))); + set_pmd(pmd, new_pmd); return 1; } diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 2d0574200459..b066cb03e811 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; @@ -620,8 +622,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 +639,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; } @@ -1272,6 +1282,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 +1429,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 +1438,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 +1496,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 +1560,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 +1594,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 +1614,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 +1633,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 +1666,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 +1681,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 +1703,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 +1810,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); diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 5a1afd0e41c7..bb4c16b4fa07 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -986,7 +986,7 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, int save_req_uid = 0; struct diag_dci_pkt_rsp_header_t pkt_rsp_header; - if (!buf) { + if (!buf || len <= 0) { pr_err("diag: Invalid pointer in %s\n", __func__); return; } @@ -1000,6 +1000,8 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, dci_cmd_code); return; } + if (len < (cmd_code_len + sizeof(int))) + return; temp += cmd_code_len; tag = *(int *)temp; temp += sizeof(int); @@ -1008,10 +1010,16 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, * The size of the response is (total length) - (length of the command * code, the tag (int) */ - rsp_len = len - (cmd_code_len + sizeof(int)); - if ((rsp_len == 0) || (rsp_len > (len - 5))) { - pr_err("diag: Invalid length in %s, len: %d, rsp_len: %d", - __func__, len, rsp_len); + if (len >= cmd_code_len + sizeof(int)) { + rsp_len = len - (cmd_code_len + sizeof(int)); + if ((rsp_len == 0) || (rsp_len > (len - 5))) { + pr_err("diag: Invalid length in %s, len: %d, rsp_len: %d\n", + __func__, len, rsp_len); + return; + } + } else { + pr_err("diag:%s: Invalid length(%d) for calculating rsp_len\n", + __func__, len); return; } diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 8d53a06c62a3..27aa81948423 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 @@ -703,7 +703,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, mask_info = (!info) ? &msg_mask : info->msg_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { + !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); diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index d637405a71d1..b930d476ce55 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -707,7 +707,8 @@ int diag_process_time_sync_query_cmd(unsigned char *src_buf, int src_len, struct diag_cmd_time_sync_query_req_t *req = NULL; struct diag_cmd_time_sync_query_rsp_t rsp; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) { + if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || + src_len < sizeof(struct diag_cmd_time_sync_query_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d", __func__, src_buf, src_len, dest_buf, dest_len); return -EINVAL; @@ -737,7 +738,8 @@ int diag_process_diag_id_query_cmd(unsigned char *src_buf, int src_len, int num_entries = 0; uint8_t process_name_len = 0; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) { + if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || + src_len < sizeof(struct diag_cmd_diag_id_query_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; @@ -783,7 +785,8 @@ int diag_process_time_sync_switch_cmd(unsigned char *src_buf, int src_len, int msg_size = sizeof(struct diag_ctrl_msg_time_sync); int err = 0, write_len = 0; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) { + if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || + src_len < sizeof(struct diag_cmd_time_sync_switch_req_t)) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d", __func__, src_buf, src_len, dest_buf, dest_len); return -EINVAL; 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/kgsl.c b/drivers/gpu/msm/kgsl.c index eb4c29d535d5..596d17381799 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.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 @@ -327,7 +327,7 @@ kgsl_mem_entry_destroy(struct kref *kref) entry->memdesc.sgt->nents, i) { page = sg_page(sg); for (j = 0; j < (sg->length >> PAGE_SHIFT); j++) - set_page_dirty(nth_page(page, j)); + set_page_dirty_lock(nth_page(page, j)); } } 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..48f4a95d5603 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 @@ -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_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c index 01ee5d45b024..cd1c7f10b4ec 100644 --- a/drivers/media/platform/msm/camera_v2/camera/camera.c +++ b/drivers/media/platform/msm/camera_v2/camera/camera.c @@ -369,9 +369,12 @@ static int camera_v4l2_s_fmt_vid_cap_mplane(struct file *filep, void *fh, if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - if (WARN_ON(!sp->vb2_q.drv_priv)) - return -ENOMEM; - + mutex_lock(sp->vb2_q.lock); + if (WARN_ON(!sp->vb2_q.drv_priv)) { + rc = -ENOMEM; + mutex_unlock(sp->vb2_q.lock); + goto done; + } memcpy(sp->vb2_q.drv_priv, pfmt->fmt.raw_data, sizeof(struct msm_v4l2_format_data)); user_fmt = (struct msm_v4l2_format_data *)sp->vb2_q.drv_priv; @@ -381,27 +384,29 @@ static int camera_v4l2_s_fmt_vid_cap_mplane(struct file *filep, void *fh, /* num_planes need to bound checked, otherwise for loop * can execute forever */ - if (WARN_ON(user_fmt->num_planes > VIDEO_MAX_PLANES)) - return -EINVAL; + if (WARN_ON(user_fmt->num_planes > VIDEO_MAX_PLANES)) { + rc = -EINVAL; + mutex_unlock(sp->vb2_q.lock); + goto done; + } for (i = 0; i < user_fmt->num_planes; i++) pr_debug("%s: plane size[%d]\n", __func__, user_fmt->plane_sizes[i]); - + mutex_unlock(sp->vb2_q.lock); if (msm_is_daemon_present() != false) { camera_pack_event(filep, MSM_CAMERA_SET_PARM, MSM_CAMERA_PRIV_S_FMT, -1, &event); rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); if (rc < 0) - return rc; - + goto done; rc = camera_check_event_status(&event); if (rc < 0) - return rc; + goto done; } sp->is_vb2_valid = 1; } - +done: return rc; } @@ -600,6 +605,12 @@ static int camera_v4l2_vb2_q_init(struct file *filep) pr_err("%s : memory not available\n", __func__); return -ENOMEM; } + q->lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); + if (!q->lock) { + kzfree(q->drv_priv); + return -ENOMEM; + } + mutex_init(q->lock); q->mem_ops = msm_vb2_get_q_mem_ops(); q->ops = msm_vb2_get_q_ops(); @@ -619,6 +630,8 @@ static void camera_v4l2_vb2_q_release(struct file *filep) kzfree(sp->vb2_q.drv_priv); mutex_lock(&sp->lock); vb2_queue_release(&sp->vb2_q); + mutex_destroy(sp->vb2_q.lock); + kzfree(sp->vb2_q.lock); mutex_unlock(&sp->lock); } diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c index 9a21282531f9..f1ed1c90085a 100644 --- a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c +++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c @@ -1,5 +1,4 @@ -/* Copyright (c) 2011-2014, 2017-2018, The Linux Foundation. - * All rights reserved. +/* Copyright (c) 2011-2014, 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 @@ -367,12 +366,13 @@ int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, } } else { for (i = num_clk - 1; i >= 0; i--) { - if (clk_ptr[i] != NULL) { + if (!IS_ERR_OR_NULL(clk_ptr[i])) { CDBG("%s disable %s\n", __func__, clk_info[i].clk_name); clk_disable(clk_ptr[i]); clk_unprepare(clk_ptr[i]); clk_put(clk_ptr[i]); + clk_ptr[i] = NULL; } } } @@ -386,10 +386,11 @@ cam_clk_set_err: clk_put(clk_ptr[i]); cam_clk_get_err: for (i--; i >= 0; i--) { - if (clk_ptr[i] != NULL) { + if (!IS_ERR_OR_NULL(clk_ptr[i])) { clk_disable(clk_ptr[i]); clk_unprepare(clk_ptr[i]); clk_put(clk_ptr[i]); + clk_ptr[i] = NULL; } } return rc; 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 1ddbb94d66b9..4d4fd78c6a6e 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 @@ -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 @@ -538,6 +538,12 @@ static void msm_isp_cfg_framedrop_reg( enum msm_vfe_input_src frame_src = SRC_TO_INTF(stream_info->stream_src); int i; + if (vfe_dev == NULL) { + pr_err("%s %d returning vfe_dev is NULL\n", + __func__, __LINE__); + return; + } + if (vfe_dev->axi_data.src_info[frame_src].frame_id >= stream_info->init_frame_drop) runtime_init_frame_drop = 0; @@ -3550,7 +3556,8 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, vfe_ops.axi_ops.get_pingpong_status(vfe_dev); /* As MCT is still processing it, need to drop the additional requests*/ - if (vfe_dev->isp_page->drop_reconfig) { + if (vfe_dev->isp_page->drop_reconfig && + frame_src == VFE_PIX_0) { pr_err("%s: MCT has not yet delayed %d drop request %d\n", __func__, vfe_dev->isp_page->drop_reconfig, frame_id); goto error; diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c index 6e528a65ecc3..b29a6f65ee41 100644 --- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c +++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-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 @@ -19,15 +19,19 @@ static int msm_vb2_queue_setup(struct vb2_queue *q, unsigned int sizes[], struct device *alloc_ctxs[]) { int i; - struct msm_v4l2_format_data *data = q->drv_priv; + struct msm_v4l2_format_data *data = NULL; + int rc = -EINVAL; + + mutex_lock(q->lock); + data = q->drv_priv; if (!data) { pr_err("%s: drv_priv NULL\n", __func__); - return -EINVAL; + goto done; } if (data->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { if (WARN_ON(data->num_planes > VIDEO_MAX_PLANES)) - return -EINVAL; + goto done; *num_planes = data->num_planes; @@ -36,9 +40,13 @@ static int msm_vb2_queue_setup(struct vb2_queue *q, } else { pr_err("%s: Unsupported buf type :%d\n", __func__, data->type); - return -EINVAL; + goto done; } - return 0; + rc = 0; + +done: + mutex_unlock(q->lock); + return rc; } static int msm_vb2_buf_init(struct vb2_buffer *vb) 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_core_common.c b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_core_common.c index 506de5e88309..b1f4fe87e8fa 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_core_common.c +++ b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_core_common.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 @@ -280,6 +280,7 @@ int cam_cdm_stream_ops_internal(void *hw_priv, ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_SVS_VOTE; axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.compressed_bw_ab = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; rc = cam_cpas_start(core->cpas_handle, 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 e1809a1d789c..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); @@ -482,6 +512,14 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, if ((!rc) && (hw_vaddr_ptr) && (len) && (len >= cdm_cmd->cmd[i].offset)) { + + if ((len - cdm_cmd->cmd[i].offset) < + cdm_cmd->cmd[i].len) { + CAM_ERR(CAM_CDM, "Not enough buffer"); + rc = -EINVAL; + break; + } + CAM_DBG(CAM_CDM, "Got the HW VA"); if (core->bl_tag >= (CAM_CDM_HWFIFO_SIZE - 1)) @@ -947,6 +985,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev) ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_SVS_VOTE; axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.compressed_bw_ab = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; rc = cam_cpas_start(cdm_core->cpas_handle, &ahb_vote, &axi_vote); if (rc) { @@ -1011,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.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c index 98f72da87df6..42f5a840de46 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c @@ -248,7 +248,7 @@ int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, rc = ctx->state_machine[ctx->state].pagefault_ops(ctx, iova, buf_info); } else { - CAM_WARN(CAM_CORE, "No dump ctx in dev %d, state %d", + CAM_INFO(CAM_CORE, "No dump ctx in dev %d, state %d", ctx->dev_hdl, ctx->state); } mutex_unlock(&ctx->ctx_mutex); 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 174469e473da..330491256754 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 @@ -482,9 +482,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, ctx->dev_name, ctx->ctx_id, req->request_id); - cam_context_putref(ctx); - - goto put_ref; + goto put_ctx_ref; } CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d", req->in_map_entries[j].sync_id, rc); @@ -493,7 +491,9 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, } return rc; - +put_ctx_ref: + for (--j; j >= 0; j--) + cam_context_putref(ctx); put_ref: for (--i; i >= 0; i--) { rc = cam_sync_put_obj_ref(req->out_map_entries[i].sync_id); @@ -1018,6 +1018,7 @@ int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx, cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; cmd_args.cmd_type = CAM_HW_MGR_CMD_DUMP_PF_INFO; cmd_args.u.pf_args.pf_data.packet = packet; + cmd_args.u.pf_args.pf_data.ctx_id = ctx->ctx_id; cmd_args.u.pf_args.iova = iova; cmd_args.u.pf_args.buf_info = buf_info; cmd_args.u.pf_args.mem_found = mem_found; diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h index c3d1c2eff4e9..6b7a9007cff9 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h @@ -144,9 +144,11 @@ struct cam_hw_stop_args { * struct cam_hw_mgr_dump_pf_data - page fault debug data * * packet: pointer to packet + * ctx_id: context id */ struct cam_hw_mgr_dump_pf_data { void *packet; + uint32_t ctx_id; }; /** 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 017e810e07c0..a05901afba71 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 @@ -620,7 +620,7 @@ static int cam_cpas_util_apply_client_axi_vote( struct cam_cpas_client *temp_client; struct cam_axi_vote req_axi_vote = *axi_vote; struct cam_cpas_axi_port *axi_port = cpas_client->axi_port; - uint64_t camnoc_bw = 0, mnoc_bw = 0; + uint64_t camnoc_bw = 0, mnoc_bw = 0, mnoc_bw_ab = 0; int rc = 0; if (!axi_port) { @@ -632,14 +632,21 @@ static int cam_cpas_util_apply_client_axi_vote( * Make sure we use same bw for both compressed, uncompressed * in case client has requested either of one only */ - if (req_axi_vote.compressed_bw == 0) + if (req_axi_vote.compressed_bw == 0) { req_axi_vote.compressed_bw = req_axi_vote.uncompressed_bw; + req_axi_vote.compressed_bw_ab = req_axi_vote.uncompressed_bw; + } + + if (req_axi_vote.compressed_bw_ab == 0) + req_axi_vote.compressed_bw_ab = req_axi_vote.compressed_bw; if (req_axi_vote.uncompressed_bw == 0) req_axi_vote.uncompressed_bw = req_axi_vote.compressed_bw; if ((cpas_client->axi_vote.compressed_bw == req_axi_vote.compressed_bw) && + (cpas_client->axi_vote.compressed_bw_ab == + req_axi_vote.compressed_bw_ab) && (cpas_client->axi_vote.uncompressed_bw == req_axi_vote.uncompressed_bw)) return 0; @@ -651,23 +658,27 @@ static int cam_cpas_util_apply_client_axi_vote( &axi_port->clients_list_head, axi_sibling_client) { camnoc_bw += curr_client->axi_vote.uncompressed_bw; mnoc_bw += curr_client->axi_vote.compressed_bw; + mnoc_bw_ab += curr_client->axi_vote.compressed_bw_ab; } if ((!soc_private->axi_camnoc_based) && (mnoc_bw < camnoc_bw)) mnoc_bw = camnoc_bw; + if ((!soc_private->axi_camnoc_based) && (mnoc_bw_ab < camnoc_bw)) + mnoc_bw_ab = mnoc_bw; + axi_port->consolidated_axi_vote.compressed_bw = mnoc_bw; axi_port->consolidated_axi_vote.uncompressed_bw = camnoc_bw; CAM_DBG(CAM_CPAS, - "axi[(%d, %d),(%d, %d)] : camnoc_bw[%llu], mnoc_bw[%llu]", + "axi[(%d, %d),(%d, %d)] : camnoc_bw[%llu], mnoc_bw[ab: %llu, ib: %llu]", axi_port->mnoc_bus.src, axi_port->mnoc_bus.dst, axi_port->camnoc_bus.src, axi_port->camnoc_bus.dst, - camnoc_bw, mnoc_bw); + camnoc_bw, mnoc_bw_ab, mnoc_bw); if (axi_port->ib_bw_voting_needed) rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus, - mnoc_bw, mnoc_bw, false); + mnoc_bw_ab, mnoc_bw, false); else rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus, mnoc_bw, 0, false); @@ -675,9 +686,7 @@ static int cam_cpas_util_apply_client_axi_vote( if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", - mnoc_bw, - (axi_port->ib_bw_voting_needed ? mnoc_bw : 0), - rc); + mnoc_bw_ab, mnoc_bw, rc); goto unlock_axi_port; } @@ -723,11 +732,13 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, axi_vote = *client_axi_vote; if ((axi_vote.compressed_bw == 0) && - (axi_vote.uncompressed_bw == 0)) { + (axi_vote.uncompressed_bw == 0) && + (axi_vote.compressed_bw_ab == 0)) { CAM_DBG(CAM_CPAS, "0 vote from client_handle=%d", client_handle); axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.compressed_bw_ab = CAM_CPAS_DEFAULT_AXI_BW; } if (!CAM_CPAS_CLIENT_VALID(client_indx)) @@ -746,10 +757,10 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, } CAM_DBG(CAM_PERF, - "Client=[%d][%s][%d] Requested compressed[%llu], uncompressed[%llu]", + "Client=[%d][%s][%d] Req comp[%llu], comp_ab[%llu], uncomp[%llu]", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, axi_vote.compressed_bw, - axi_vote.uncompressed_bw); + axi_vote.compressed_bw_ab, axi_vote.uncompressed_bw); rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_core->cpas_client[client_indx], &axi_vote); @@ -1001,11 +1012,11 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, if (rc) goto done; - CAM_DBG(CAM_CPAS, - "AXI client=[%d][%s][%d] compressed_bw[%llu], uncompressed_bw[%llu]", + CAM_INFO(CAM_CPAS, + "AXI client=[%d][%s][%d] comp[%llu], comp_ab[%llu], uncomp[%llu]", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, axi_vote->compressed_bw, - axi_vote->uncompressed_bw); + axi_vote->compressed_bw_ab, axi_vote->uncompressed_bw); rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, axi_vote); if (rc) @@ -1156,6 +1167,7 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, axi_vote.uncompressed_bw = 0; axi_vote.compressed_bw = 0; + axi_vote.compressed_bw_ab = 0; rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote); diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/include/cam_cpas_api.h b/drivers/media/platform/msm/camera_v3/cam_cpas/include/cam_cpas_api.h index 5dbd94a1fa9b..7b534a93c71d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cpas/include/cam_cpas_api.h +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/include/cam_cpas_api.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 @@ -348,6 +348,7 @@ struct cam_ahb_vote { struct cam_axi_vote { uint64_t uncompressed_bw; uint64_t compressed_bw; + uint64_t compressed_bw_ab; }; /** diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index 8403d4dbe533..887783321d19 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -595,6 +595,14 @@ static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, return -ENOMEM; } + if (io_cfg[i].offsets[plane] >= size) { + CAM_ERR(CAM_FD, + "Invalid cpu buf %d %d %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane); + return -EINVAL; + } + io_addr[plane] += io_cfg[i].offsets[plane]; } @@ -1598,7 +1606,7 @@ static int cam_fd_mgr_hw_prepare_update(void *hw_mgr_priv, /* We do not expect any patching, but just do it anyway */ rc = cam_packet_util_process_patches(prepare->packet, - hw_mgr->device_iommu.non_secure, -1); + hw_mgr->device_iommu.non_secure, -1, 0); if (rc) { CAM_ERR(CAM_FD, "Patch FD packet failed, rc=%d", rc); return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c index adfd4d839a59..3b16789eece6 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_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 @@ -151,6 +151,7 @@ int cam_fd_soc_enable_resources(struct cam_hw_soc_info *soc_info) ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_SVS_VOTE; axi_vote.compressed_bw = 7200000; + axi_vote.compressed_bw_ab = 7200000; axi_vote.uncompressed_bw = 7200000; rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); if (rc) { 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 cd50cfb3f613..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; } @@ -137,6 +147,12 @@ static int __cam_icp_config_dev_in_ready(struct cam_context *ctx, return rc; } + if ((len < sizeof(struct cam_packet)) || + (cmd->offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_CTXT, "Not enough buf"); + return -EINVAL; + } + packet = (struct cam_packet *) ((uint8_t *)packet_addr + (uint32_t)cmd->offset); 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 bf80938985f1..74b7aabb7655 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c @@ -43,7 +43,7 @@ #define HFI_MAX_POLL_TRY 5 #define HFI_MAX_PC_POLL_TRY 150 -#define HFI_POLL_TRY_SLEEP 2 +#define HFI_POLL_TRY_SLEEP 1 static struct hfi_info *g_hfi; unsigned int g_icp_mmu_hdl; @@ -73,24 +73,28 @@ void cam_hfi_queue_dump(void) qtbl_hdr->qtbl_num_q, qtbl_hdr->qtbl_qhdr_size); cmd_q_hdr = &qtbl->q_hdr[Q_CMD]; - CAM_DBG(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x", + CAM_INFO(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x", cmd_q_hdr->qhdr_q_size, cmd_q_hdr->qhdr_read_idx, cmd_q_hdr->qhdr_write_idx, hfi_mem->cmd_q.iova); read_q = (uint32_t *)g_hfi->map.cmd_q.kva; read_ptr = (uint32_t *)(read_q + 0); + CAM_INFO(CAM_HFI, "CMD Q %p", read_q); CAM_DBG(CAM_HFI, "CMD Q START"); for (i = 0; i < ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) CAM_DBG(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); + CAM_DBG(CAM_HFI, "CMD Q END"); msg_q_hdr = &qtbl->q_hdr[Q_MSG]; - CAM_DBG(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x", + CAM_INFO(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x", msg_q_hdr->qhdr_q_size, msg_q_hdr->qhdr_read_idx, msg_q_hdr->qhdr_write_idx, hfi_mem->msg_q.iova); read_q = (uint32_t *)g_hfi->map.msg_q.kva; read_ptr = (uint32_t *)(read_q + 0); + CAM_INFO(CAM_HFI, "MSG Q %p", read_ptr); CAM_DBG(CAM_HFI, "MSG Q START"); for (i = 0; i < ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) CAM_DBG(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); + CAM_DBG(CAM_HFI, "MSG Q END"); } int hfi_write_cmd(void *cmd_ptr) @@ -526,7 +530,8 @@ void cam_hfi_disable_cpu(void __iomem *icp_base) * and Host can the proceed. No interrupt is expected from FW * at this time. */ - msleep_interruptible(HFI_POLL_TRY_SLEEP); + usleep_range(HFI_POLL_TRY_SLEEP * 1000, + (HFI_POLL_TRY_SLEEP * 1000) + 1000); try++; } diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/a5_hw/a5_core.c index 18bd6d8dd2c7..e13d7f2edcee 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/a5_hw/a5_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 @@ -268,6 +268,7 @@ int cam_a5_init_hw(void *device_priv, cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; cpas_vote.axi_vote.compressed_bw = CAM_ICP_A5_BW_BYTES_VOTE; + cpas_vote.axi_vote.compressed_bw_ab = CAM_ICP_A5_BW_BYTES_VOTE; cpas_vote.axi_vote.uncompressed_bw = CAM_ICP_A5_BW_BYTES_VOTE; rc = cam_cpas_start(core_info->cpas_handle, diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c index a330cff293d6..c94276ce8778 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c @@ -164,11 +164,9 @@ static int cam_bps_handle_pc(struct cam_hw_info *bps_dev) CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, 0x1); - if ((pwr_status >> BPS_PWR_ON_MASK)) { - CAM_ERR(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)", + if ((pwr_status >> BPS_PWR_ON_MASK)) + CAM_WARN(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)", pwr_status, pwr_ctrl); - return -EINVAL; - } } cam_bps_get_gdsc_control(soc_info); cam_cpas_reg_read(core_info->cpas_handle, 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 3a2d854fb1f4..b90fcd0be3c6 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; @@ -109,6 +140,7 @@ static void cam_icp_hw_mgr_reset_clk_info(struct cam_icp_hw_mgr *hw_mgr) hw_mgr->clk_info[i].over_clked = 0; hw_mgr->clk_info[i].uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; hw_mgr->clk_info[i].compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + hw_mgr->clk_info[i].compressed_bw_ab = CAM_CPAS_DEFAULT_AXI_BW; } hw_mgr->icp_default_clk = ICP_CLK_SVS_HZ; } @@ -245,6 +277,7 @@ static int cam_icp_ctx_clk_info_init(struct cam_icp_hw_ctx_data *ctx_data) ctx_data->clk_info.base_clk = 0; ctx_data->clk_info.uncompressed_bw = 0; ctx_data->clk_info.compressed_bw = 0; + ctx_data->clk_info.compressed_bw_ab = 0; cam_icp_supported_clk_rates(&icp_hw_mgr, ctx_data); return 0; @@ -403,10 +436,11 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) } CAM_DBG(CAM_ICP, - "E :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u", + "E :ctx_id %d, ubw %lld, cbw %lld, cbw_a %ld, curr_fc %u, bc %u", ctx_data->ctx_id, ctx_data->clk_info.uncompressed_bw, ctx_data->clk_info.compressed_bw, + ctx_data->clk_info.compressed_bw_ab, ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk); ipe0_dev_intf = hw_mgr->ipe0_dev_intf; @@ -436,9 +470,11 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) } clk_info->compressed_bw -= ctx_data->clk_info.compressed_bw; + clk_info->compressed_bw_ab -= ctx_data->clk_info.compressed_bw_ab; clk_info->uncompressed_bw -= ctx_data->clk_info.uncompressed_bw; ctx_data->clk_info.uncompressed_bw = 0; ctx_data->clk_info.compressed_bw = 0; + ctx_data->clk_info.compressed_bw_ab = 0; ctx_data->clk_info.curr_fc = 0; ctx_data->clk_info.base_clk = 0; @@ -446,16 +482,18 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) clk_update.ahb_vote.vote.freq = 0; clk_update.ahb_vote_valid = false; clk_update.axi_vote.compressed_bw = clk_info->compressed_bw; + clk_update.axi_vote.compressed_bw_ab = clk_info->compressed_bw; clk_update.axi_vote.uncompressed_bw = clk_info->uncompressed_bw; clk_update.axi_vote_valid = true; dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, &clk_update, sizeof(clk_update)); CAM_DBG(CAM_ICP, - "X :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u", + "X :ctx_id %d, ubw %lld cbw %lld abw_a %lld, curr_fc %u, bc %u", ctx_data->ctx_id, ctx_data->clk_info.uncompressed_bw, ctx_data->clk_info.compressed_bw, + ctx_data->clk_info.compressed_bw_ab, ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk); mutex_unlock(&ctx_data->ctx_mutex); @@ -523,6 +561,7 @@ static int cam_icp_clk_info_init(struct cam_icp_hw_mgr *hw_mgr, hw_mgr->clk_info[i].over_clked = 0; hw_mgr->clk_info[i].uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; hw_mgr->clk_info[i].compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + hw_mgr->clk_info[i].compressed_bw_ab = CAM_CPAS_DEFAULT_AXI_BW; hw_mgr->clk_info[i].hw_type = i; hw_mgr->clk_info[i].watch_dog_reset_counter = 0; } @@ -812,6 +851,7 @@ static bool cam_icp_debug_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_debug_clk; hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_debug_clk; hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_debug_clk; + hw_mgr_clk_info->compressed_bw_ab = icp_hw_mgr.icp_debug_clk; CAM_DBG(CAM_ICP, "bc = %d cc = %d", hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); return true; @@ -827,6 +867,7 @@ static bool cam_icp_default_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_default_clk; hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_default_clk; hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_default_clk; + hw_mgr_clk_info->compressed_bw_ab = icp_hw_mgr.icp_default_clk; CAM_DBG(CAM_ICP, "bc = %d cc = %d", hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); return true; @@ -864,8 +905,10 @@ static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, ctx_data->clk_info.uncompressed_bw = clk_info->uncompressed_bw; ctx_data->clk_info.compressed_bw = clk_info->compressed_bw; + ctx_data->clk_info.compressed_bw_ab = clk_info->compressed_bw; hw_mgr_clk_info->uncompressed_bw = 0; hw_mgr_clk_info->compressed_bw = 0; + hw_mgr_clk_info->compressed_bw_ab = 0; for (i = 0; i < CAM_ICP_CTX_MAX; i++) { ctx = &hw_mgr->ctx_data[i]; if (ctx->state == CAM_ICP_CTX_STATE_ACQUIRED && @@ -877,9 +920,12 @@ static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, ctx->clk_info.uncompressed_bw; hw_mgr_clk_info->compressed_bw += ctx->clk_info.compressed_bw; - CAM_DBG(CAM_ICP, "ubw = %lld, cbw = %lld", + hw_mgr_clk_info->compressed_bw_ab += + ctx->clk_info.compressed_bw_ab; + CAM_DBG(CAM_ICP, "ubw = %lld, cbw = %lld cbw_ab", hw_mgr_clk_info->uncompressed_bw, - hw_mgr_clk_info->compressed_bw); + hw_mgr_clk_info->compressed_bw, + hw_mgr_clk_info->compressed_bw_ab); } } @@ -960,9 +1006,10 @@ static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr, rc = cam_icp_update_bw(hw_mgr, ctx_data, hw_mgr_clk_info, clk_info, busy); - CAM_DBG(CAM_ICP, "ubw = %lld, cbw = %lld, update_bw = %d", + CAM_DBG(CAM_ICP, "ubw %lld, cbw %lld, cbw_a %lld, update_bw %d", hw_mgr_clk_info->uncompressed_bw, - hw_mgr_clk_info->compressed_bw, rc); + hw_mgr_clk_info->compressed_bw, + hw_mgr_clk_info->compressed_bw_ab, rc); return rc; } @@ -1050,6 +1097,7 @@ static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, clk_update.ahb_vote.vote.freq = 0; clk_update.ahb_vote_valid = false; clk_update.axi_vote.compressed_bw = clk_info->compressed_bw; + clk_update.axi_vote.compressed_bw_ab = clk_info->compressed_bw; clk_update.axi_vote.uncompressed_bw = clk_info->uncompressed_bw; clk_update.axi_vote_valid = true; dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, @@ -1063,8 +1111,10 @@ static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, * anyway. */ - CAM_DBG(CAM_ICP, "compress_bw %llu uncompress_bw %llu dev_type %d", - clk_info->compressed_bw, clk_info->uncompressed_bw, + CAM_DBG(CAM_ICP, + "comp_bw %llu comp_bw_ab %lld uncomp_bw %llu dev_type %d", + clk_info->compressed_bw, clk_info->compressed_bw_ab, + clk_info->uncompressed_bw, ctx_data->icp_dev_acquire_info->dev_type); return 0; @@ -1835,6 +1885,10 @@ static int cam_icp_mgr_process_fatal_error( if (event_notify->event_id == HFI_EVENT_SYS_ERROR) { CAM_INFO(CAM_ICP, "received HFI_EVENT_SYS_ERROR"); + if (event_notify->event_data1 == HFI_ERR_SYS_FATAL) { + CAM_ERR(CAM_ICP, "received HFI_ERR_SYS_FATAL"); + BUG(); + } rc = cam_icp_mgr_trigger_recovery(hw_mgr); cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); } @@ -3386,6 +3440,17 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, goto rel_cmd_buf; } *fw_cmd_buf_iova_addr = addr; + + if (cmd_desc[i].offset >= len || + ((len - cmd_desc[i].offset) < + cmd_desc[i].size)){ + CAM_ERR(CAM_ICP, + "Invalid offset/length, i %d offset 0x%x len %u size 0x%x", + i, cmd_desc[i].offset, + (uint32_t)len, cmd_desc[i].size); + goto rel_cmd_buf; + } + *fw_cmd_buf_iova_addr = (*fw_cmd_buf_iova_addr + cmd_desc[i].offset); rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, @@ -3890,14 +3955,19 @@ static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, } CAM_INFO(CAM_ICP, - "pln %d dir %d w %d h %d s %u sh %u sz %d addr 0x%x off 0x%x memh %x", + "pln %d dir %d w %d h %d s %u sh %u sz %d", j, io_cfg[i].direction, io_cfg[i].planes[j].width, io_cfg[i].planes[j].height, io_cfg[i].planes[j].plane_stride, io_cfg[i].planes[j].slice_height, - (int32_t)src_buf_size, + (uint32_t)src_buf_size); + + CAM_INFO(CAM_ICP, + "addr (0x%x, 0x%x) off 0x%x memh %x", (unsigned int)iova_addr, + ((unsigned int)iova_addr + + (uint32_t)src_buf_size), io_cfg[i].offsets[j], io_cfg[i].mem_handle[j]); @@ -3982,8 +4052,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) { @@ -4004,7 +4078,7 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, packet->header.request_id, ctx_data->ctx_id); /* Update Buffer Address from handles and patch information */ rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl, - hw_mgr->iommu_sec_hdl); + hw_mgr->iommu_sec_hdl, 0); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); return rc; @@ -4426,8 +4500,9 @@ static int cam_icp_get_acquire_info(struct cam_icp_hw_mgr *hw_mgr, return -EINVAL; } - if (icp_dev_acquire_info.num_out_res > ICP_MAX_OUTPUT_SUPPORTED) { - CAM_ERR(CAM_ICP, "num of out resources exceeding : %u", + if ((icp_dev_acquire_info.num_out_res > ICP_MAX_OUTPUT_SUPPORTED) || + (icp_dev_acquire_info.num_out_res <= 0)) { + CAM_ERR(CAM_ICP, "Invalid num of out resources: %u", icp_dev_acquire_info.num_out_res); return -EINVAL; } @@ -4603,6 +4678,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; } @@ -4932,6 +5009,110 @@ cmd_work_failed: return rc; } +static int cam_icp_util_dump_frame_data(struct cam_packet *packet, + struct cam_icp_hw_mgr *hw_mgr, uint32_t ctx_id) +{ + int num_cmd_buf = 0, i = 0, rc = 0; + size_t len; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uintptr_t cpu_addr = 0; + struct ipe_frame_process_data *ipe_frame_process_data = NULL; + struct bps_frame_process_data *bps_frame_process_data = NULL; + struct cam_icp_hw_ctx_data *ctx_data; + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + ctx_data = &hw_mgr->ctx_data[ctx_id]; + + for (i = 0; i < packet->num_cmd_buf; i++, num_cmd_buf++) { + if (cmd_desc[i].type == CAM_CMD_BUF_FW) { + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &cpu_addr, &len); + if (rc || !cpu_addr) { + CAM_ERR(CAM_ICP, "get cmd buf failed %x", + hw_mgr->iommu_hdl); + return -EINVAL; + } + cpu_addr = cpu_addr + cmd_desc[i].offset; + break; + } + } + + if (!cpu_addr) { + CAM_ERR(CAM_ICP, "CPU address is NULL"); + return -ENOMEM; + } + + if (ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS) { + ipe_frame_process_data = + (struct ipe_frame_process_data *)cpu_addr; + CAM_INFO(CAM_ICP, + "IPE: requestID %d, maxCores %d, targetTime %d, batchSize %d", + ipe_frame_process_data->request_id, + ipe_frame_process_data->max_num_cores, + ipe_frame_process_data->target_time, + ipe_frame_process_data->frames_in_batch); + CAM_INFO(CAM_ICP, + "IPE: scratch 0x%016x sz %d ubwc addr 0x%016x sz %d", + ipe_frame_process_data->scratch_buffer_addr, + ipe_frame_process_data->scratch_buffer_size, + ipe_frame_process_data->ubwc_stats_buffer_addr, + ipe_frame_process_data->ubwc_stats_buffer_size); + CAM_INFO(CAM_ICP, + "IPE: iqSet 0x%016x striping 0x%016x cdm addr 0x%016x sz %d", + ipe_frame_process_data->iq_settings_addr, + ipe_frame_process_data->strip_lib_out_addr, + ipe_frame_process_data->cdm_buffer_addr, + ipe_frame_process_data->cdm_buffer_size); + CAM_INFO(CAM_ICP, + "IPE: cdmProgBase 0x%016x cdmPreLtm 0x%016x cdmPost:tm 0x%016x", + ipe_frame_process_data->cdm_prog_base, + ipe_frame_process_data->cdm_pre_ltm, + ipe_frame_process_data->cdm_post_ltm); + CAM_INFO(CAM_ICP, + "IPE: ANR 0x%016x, 0x%016x, 0x%016x, 0x%016x", + ipe_frame_process_data->cdm_anr_full_pass, + ipe_frame_process_data->cdm_anr_ds4, + ipe_frame_process_data->cdm_anr_ds16, + ipe_frame_process_data->cdm_anr_ds64); + CAM_INFO(CAM_ICP, + "IPE: TF 0x%016x, 0x%016x, 0x%016x, 0x%016x", + ipe_frame_process_data->cdm_tf_full_pass, + ipe_frame_process_data->cdm_tf_ds4, + ipe_frame_process_data->cdm_tf_ds16, + ipe_frame_process_data->cdm_tf_ds64); + for (i = 0; i < ipe_frame_process_data->frames_in_batch; i++) { + CAM_INFO(CAM_ICP, + "IPE: frame %d, ICA1Buf 0x%016x, ICA2Buf 0x%016x", + i+1, + ipe_frame_process_data->framesets[i].cdm_ica1_addr, + ipe_frame_process_data->framesets[i].cdm_ica2_addr); + } + } else { + bps_frame_process_data = + (struct bps_frame_process_data *)cpu_addr; + CAM_INFO(CAM_ICP, + "BPS: requestId %d targetTime %d maxCores %d", + bps_frame_process_data->request_id, + bps_frame_process_data->target_time, + bps_frame_process_data->max_num_cores); + CAM_INFO(CAM_ICP, + "BPS: ubwc addr 0x%016x sz %d cdm buff addr 0x%016x sz %d", + bps_frame_process_data->ubwc_stats_buffer_addr, + bps_frame_process_data->ubwc_stats_buffer_size, + bps_frame_process_data->cdm_buffer_addr, + bps_frame_process_data->cdm_buffer_size); + CAM_INFO(CAM_ICP, + "BPS: iqSet 0x%016x Striping 0x%016x cdmProgAddr 0x%016x", + bps_frame_process_data->iq_settings_addr, + bps_frame_process_data->strip_lib_out_addr, + bps_frame_process_data->cdm_prog_addr); + } + + return rc; +} + static int cam_icp_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -4952,6 +5133,17 @@ static int cam_icp_mgr_cmd(void *hw_mgr_priv, void *cmd_args) hw_cmd_args->u.pf_args.buf_info, hw_cmd_args->u.pf_args.mem_found); + cam_packet_util_process_patches( + hw_cmd_args->u.pf_args.pf_data.packet, + hw_mgr->iommu_hdl, + hw_mgr->iommu_sec_hdl, + 1); + + cam_icp_util_dump_frame_data( + hw_cmd_args->u.pf_args.pf_data.packet, + hw_mgr, + hw_cmd_args->u.pf_args.pf_data.ctx_id); + break; default: CAM_ERR(CAM_ICP, "Invalid cmd"); 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 5a93df33925f..9af4ccc96003 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 @@ -185,6 +185,7 @@ struct cam_ctx_clk_info { uint32_t reserved; uint64_t uncompressed_bw; uint64_t compressed_bw; + uint64_t compressed_bw_ab; int32_t clk_rate[CAM_MAX_VOTE]; }; /** @@ -249,6 +250,7 @@ struct icp_cmd_generic_blob { * @over_clked: Over clock count * @uncompressed_bw: Current bandwidth voting * @compressed_bw: Current compressed bandwidth voting + * @compressed_bw_ab: Current absolute compressed bandwidth voting * @hw_type: IPE/BPS device type * @watch_dog: watchdog timer handle * @watch_dog_reset_counter: Counter for watch dog reset @@ -260,6 +262,7 @@ struct cam_icp_clk_info { uint32_t over_clked; uint64_t uncompressed_bw; uint64_t compressed_bw; + uint64_t compressed_bw_ab; uint32_t hw_type; struct cam_req_mgr_timer *watch_dog; uint32_t watch_dog_reset_counter; diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c index 1f71c7d4cd36..ae3d1343c1c4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -78,6 +78,7 @@ int cam_ipe_init_hw(void *device_priv, cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; cpas_vote.axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.compressed_bw_ab = CAM_CPAS_DEFAULT_AXI_BW; cpas_vote.axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; rc = cam_cpas_start(core_info->cpas_handle, @@ -162,7 +163,8 @@ static int cam_ipe_handle_pc(struct cam_hw_info *ipe_dev) hw_info->pwr_ctrl, true, 0x1); if (pwr_status >> IPE_PWR_ON_MASK) - return -EINVAL; + CAM_WARN(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)", + pwr_status, pwr_ctrl); } cam_ipe_get_gdsc_control(soc_info); 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 8685e34e0ea9..2982ce027aa7 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 @@ -2541,6 +2541,8 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, ctx_isp->reported_req_id = 0; ctx_isp->hw_acquired = false; ctx_isp->init_received = false; + ctx_isp->rdi_only_context = false; + ctx_isp->split_acquire = false; /* * Ideally, we should never have any active request here. 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 582d4858e18b..177538acd0b0 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 @@ -43,7 +43,7 @@ (CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1) #define CAM_ISP_GENERIC_BLOB_TYPE_MAX \ - (CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG + 1) + (CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 + 1) static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_GET_HFR_UPDATE, @@ -1691,6 +1691,14 @@ static int cam_ife_mgr_check_and_update_fe( ((uint8_t *)&acquire_hw_info->data + acquire_hw_info->input_info_offset); for (i = 0; i < acquire_hw_info->num_inputs; i++) { + + if ((in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) || + (in_port->num_out_res <= 0)) { + CAM_ERR(CAM_ISP, "Invalid num output res %u", + in_port->num_out_res); + return -EINVAL; + } + in_port_length = sizeof(struct cam_isp_in_port_info) + (in_port->num_out_res - 1) * sizeof(struct cam_isp_out_port_info); @@ -1927,7 +1935,6 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) } cdm_acquire.base_array_cnt = j; - cdm_acquire.id = CAM_CDM_VIRTUAL; cdm_acquire.cam_cdm_callback = cam_ife_cam_cdm_callback; rc = cam_cdm_acquire(&cdm_acquire); @@ -1943,21 +1950,23 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) acquire_hw_info = (struct cam_isp_acquire_hw_info *)acquire_args->acquire_info; - in_port = (struct cam_isp_in_port_info *) - ((uint8_t *)&acquire_hw_info->data + - acquire_hw_info->input_info_offset); rc = cam_ife_mgr_check_and_update_fe(ife_ctx, acquire_hw_info); if (rc) { CAM_ERR(CAM_ISP, "buffer size is not enough"); - goto free_ctx; + goto free_cdm; } + in_port = (struct cam_isp_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset); + /* acquire HW resources */ for (i = 0; i < acquire_hw_info->num_inputs; i++) { - if (in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) { - CAM_ERR(CAM_ISP, "too many output res %d", + if ((in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) || + (in_port->num_out_res <= 0)) { + CAM_ERR(CAM_ISP, "Invalid num output res %u", in_port->num_out_res); rc = -EINVAL; goto free_res; @@ -2010,6 +2019,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) return 0; free_res: cam_ife_hw_mgr_release_hw_for_ctx(ife_ctx); +free_cdm: cam_cdm_release(ife_ctx->cdm_handle); free_ctx: cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx); @@ -2202,6 +2212,7 @@ static int cam_ife_mgr_acquire(void *hw_mgr_priv, static int cam_isp_blob_bw_update( struct cam_isp_bw_config *bw_config, + struct cam_isp_bw_config_ab *bw_config_ab, struct cam_ife_hw_mgr_ctx *ctx) { struct cam_ife_hw_mgr_res *hw_mgr_res; @@ -2209,6 +2220,7 @@ static int cam_isp_blob_bw_update( struct cam_vfe_bw_update_args bw_upd_args; uint64_t cam_bw_bps = 0; uint64_t ext_bw_bps = 0; + uint64_t ext_bw_bps_ab = 0; int rc = -EINVAL; uint32_t i; bool camif_l_bw_updated = false; @@ -2238,6 +2250,8 @@ static int cam_isp_blob_bw_update( bw_config->left_pix_vote.cam_bw_bps; ext_bw_bps = bw_config->left_pix_vote.ext_bw_bps; + ext_bw_bps_ab = + bw_config_ab->left_pix_vote_ab; camif_l_bw_updated = true; } else { @@ -2248,6 +2262,8 @@ static int cam_isp_blob_bw_update( bw_config->right_pix_vote.cam_bw_bps; ext_bw_bps = bw_config->right_pix_vote.ext_bw_bps; + ext_bw_bps_ab = + bw_config_ab->right_pix_vote_ab; camif_r_bw_updated = true; } @@ -2263,6 +2279,8 @@ static int cam_isp_blob_bw_update( bw_config->rdi_vote[idx].cam_bw_bps; ext_bw_bps = bw_config->rdi_vote[idx].ext_bw_bps; + ext_bw_bps_ab = + bw_config_ab->rdi_vote_ab[idx]; } else if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF_LITE) { if (i == CAM_ISP_HW_SPLIT_LEFT) { @@ -2273,6 +2291,8 @@ static int cam_isp_blob_bw_update( bw_config->left_pix_vote.cam_bw_bps; ext_bw_bps = bw_config->left_pix_vote.ext_bw_bps; + ext_bw_bps_ab = + bw_config_ab->left_pix_vote_ab; camif_l_bw_updated = true; } else { @@ -2283,6 +2303,9 @@ static int cam_isp_blob_bw_update( bw_config->right_pix_vote.cam_bw_bps; ext_bw_bps = bw_config->right_pix_vote.ext_bw_bps; + ext_bw_bps_ab = + bw_config_ab->right_pix_vote_ab; + camif_r_bw_updated = true; } @@ -2301,6 +2324,8 @@ static int cam_isp_blob_bw_update( bw_upd_args.camnoc_bw_bytes = cam_bw_bps; bw_upd_args.external_bw_bytes = ext_bw_bps; + bw_upd_args.external_bw_bytes_ab = + ext_bw_bps_ab; rc = hw_intf->hw_ops.process_cmd( hw_intf->hw_priv, @@ -2351,10 +2376,15 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv; for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + CAM_DBG(CAM_ISP, "hw_update_data->bw_config_valid[%d]:%d", i, + hw_update_data->bw_config_valid[i]); if (hw_update_data->bw_config_valid[i] == true) { rc = cam_isp_blob_bw_update( (struct cam_isp_bw_config *) - &hw_update_data->bw_config[i], ctx); + &hw_update_data->bw_config[i], + (struct cam_isp_bw_config_ab *) + &hw_update_data->bw_config_ab[i], + ctx); if (rc) CAM_ERR(CAM_ISP, "Bandwidth Update Failed"); } @@ -3557,9 +3587,9 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } if (blob_type >= CAM_ISP_GENERIC_BLOB_TYPE_MAX) { - CAM_ERR(CAM_ISP, "Invalid Blob Type %d Max %d", blob_type, + CAM_WARN(CAM_ISP, "Invalid Blob Type %d Max %d", blob_type, CAM_ISP_GENERIC_BLOB_TYPE_MAX); - return -EINVAL; + return 0; } prepare = blob_info->prepare; @@ -3668,13 +3698,60 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) prepare->priv; - memcpy(&prepare_hw_data->bw_config[bw_config->usage_type], bw_config, sizeof(prepare_hw_data->bw_config[0])); + memset(&prepare_hw_data->bw_config_ab[bw_config->usage_type], + 0, sizeof(prepare_hw_data->bw_config_ab[0])); prepare_hw_data->bw_config_valid[bw_config->usage_type] = true; } break; + case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2: { + struct cam_isp_bw_config_ab *bw_config_ab; + + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + if (blob_size < sizeof(struct cam_isp_bw_config_ab)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + bw_config_ab = (struct cam_isp_bw_config_ab *)blob_data; + + if (bw_config_ab->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in bw config ab", + bw_config_ab->num_rdi); + return -EINVAL; + } + + if (blob_size < (sizeof(uint32_t) * 2 + + (bw_config_ab->num_rdi + 2) + * sizeof(struct cam_isp_bw_vote))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(uint32_t) * 2 + + (bw_config_ab->num_rdi + 2) + * sizeof(struct cam_isp_bw_vote)); + return -EINVAL; + } + CAM_DBG(CAM_ISP, "AB L:%lld R:%lld usage_type %d", + bw_config_ab->left_pix_vote_ab, + bw_config_ab->right_pix_vote_ab, + bw_config_ab->usage_type); + + if (!prepare || !prepare->priv || + (bw_config_ab->usage_type >= CAM_IFE_HW_NUM_MAX)) { + CAM_ERR(CAM_ISP, "Invalid inputs"); + rc = -EINVAL; + break; + } + prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) + prepare->priv; + + memcpy(&prepare_hw_data->bw_config_ab[bw_config_ab->usage_type], + bw_config_ab, sizeof(prepare_hw_data->bw_config_ab[0])); + } + break; case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG: { struct cam_ubwc_config *ubwc_config; @@ -3789,7 +3866,8 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, rc = cam_packet_util_process_patches(prepare->packet, hw_mgr->mgr_common.cmd_iommu_hdl, - hw_mgr->mgr_common.cmd_iommu_hdl_secure); + hw_mgr->mgr_common.cmd_iommu_hdl_secure, + 0); if (rc) { CAM_ERR(CAM_ISP, "Patch ISP packet failed."); return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index e9bcc98a8956..096e0f186bbf 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -95,6 +95,14 @@ struct cam_isp_start_args { bool start_only; }; +struct cam_isp_bw_config_internal_ab { + uint32_t usage_type; + uint32_t num_rdi; + uint64_t left_pix_vote_ab; + uint64_t right_pix_vote_ab; + uint64_t rdi_vote_ab[CAM_IFE_RDI_NUM_MAX]; +}; + /** * struct cam_isp_bw_config_internal - Internal Bandwidth configuration * @@ -106,11 +114,11 @@ struct cam_isp_start_args { */ struct cam_isp_bw_config_internal { - uint32_t usage_type; - uint32_t num_rdi; - struct cam_isp_bw_vote left_pix_vote; - struct cam_isp_bw_vote right_pix_vote; - struct cam_isp_bw_vote rdi_vote[CAM_IFE_RDI_NUM_MAX]; + uint32_t usage_type; + uint32_t num_rdi; + struct cam_isp_bw_vote left_pix_vote; + struct cam_isp_bw_vote right_pix_vote; + struct cam_isp_bw_vote rdi_vote[CAM_IFE_RDI_NUM_MAX]; }; /** @@ -125,9 +133,10 @@ struct cam_isp_bw_config_internal { * */ struct cam_isp_prepare_hw_update_data { - uint32_t packet_opcode_type; - struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX]; - bool bw_config_valid[CAM_IFE_HW_NUM_MAX]; + uint32_t packet_opcode_type; + struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX]; + struct cam_isp_bw_config_internal_ab bw_config_ab[CAM_IFE_HW_NUM_MAX]; + bool bw_config_valid[CAM_IFE_HW_NUM_MAX]; }; 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..8fba017cfe27 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) @@ -1478,15 +1478,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); @@ -3091,13 +3089,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 +3103,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 +3142,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 +3251,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); } @@ -3298,19 +3267,17 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) 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 +3286,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); } @@ -3336,26 +3302,23 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) 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++) { 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]); } @@ -3372,14 +3335,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) 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_soc.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c index 5e02609088c4..eb9e63f30ba6 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c @@ -129,6 +129,7 @@ int cam_ife_csid_enable_soc_resources( ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_SVS_VOTE; axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.compressed_bw_ab = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; CAM_DBG(CAM_ISP, "csid vote compressed_bw:%lld uncompressed_bw:%lld", diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index f60bf6e4b3d4..9d6bcb71bb69 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -189,6 +189,7 @@ struct cam_vfe_bw_update_args { struct cam_isp_resource_node *node_res; uint64_t camnoc_bw_bytes; uint64_t external_bw_bytes; + uint64_t external_bw_bytes_ab; }; /* diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c index b57762644082..78dd64c4cccf 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c @@ -235,6 +235,7 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) ahb_vote.vote.level = CAM_SVS_VOTE; axi_vote.compressed_bw = 10640000000L; + axi_vote.compressed_bw_ab = 10640000000L; axi_vote.uncompressed_bw = 10640000000L; rc = cam_cpas_start(soc_private->cpas_handle[0], &ahb_vote, &axi_vote); 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 569bbb6b2ce0..c5acbe5dbd16 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 @@ -34,7 +34,7 @@ struct cam_vfe_top_ver2_priv { struct cam_vfe_top_ver2_common_data common_data; struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_VER2_MUX_MAX]; unsigned long hw_clk_rate; - struct cam_axi_vote applied_axi_vote; + struct cam_axi_vote applied_axi_vote; struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX]; unsigned long req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX]; struct cam_axi_vote last_vote[CAM_CPAS_HANDLE_MAX] @@ -127,8 +127,8 @@ static int cam_vfe_top_set_axi_bw_vote( struct cam_vfe_top_ver2_priv *top_priv, bool start_stop) { - struct cam_axi_vote sum = {0, 0}; - struct cam_axi_vote to_be_applied_axi_vote = {0, 0}; + struct cam_axi_vote sum = {0, 0, 0}; + struct cam_axi_vote to_be_applied_axi_vote = {0, 0, 0}; int i, rc = 0; struct cam_hw_soc_info *soc_info = top_priv->common_data.soc_info; @@ -137,6 +137,7 @@ static int cam_vfe_top_set_axi_bw_vote( bool apply_bw_update = false; enum cam_cpas_handle_id cpashdl_type; struct cam_axi_vote *last_vote = NULL; + struct cam_axi_vote *applied_axi_vote = NULL; if (!soc_private) { CAM_ERR(CAM_ISP, "Error soc_private NULL"); @@ -151,8 +152,10 @@ static int cam_vfe_top_set_axi_bw_vote( continue; sum.uncompressed_bw = sum.compressed_bw = 0; + sum.compressed_bw_ab = 0; to_be_applied_axi_vote.uncompressed_bw = 0; to_be_applied_axi_vote.compressed_bw = 0; + to_be_applied_axi_vote.compressed_bw_ab = 0; apply_bw_update = false; for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { @@ -164,14 +167,20 @@ static int cam_vfe_top_set_axi_bw_vote( top_priv->req_axi_vote[i].uncompressed_bw; sum.compressed_bw += top_priv->req_axi_vote[i].compressed_bw; + sum.compressed_bw_ab += + top_priv->req_axi_vote[i].compressed_bw_ab; } } + applied_axi_vote = &top_priv->applied_axi_vote; - CAM_DBG(CAM_ISP, "Updating BW from (%llu %llu) to (%llu %llu)", - top_priv->applied_axi_vote.uncompressed_bw, - top_priv->applied_axi_vote.compressed_bw, + CAM_DBG(CAM_ISP, + "Updating BW (ib, ib, ab) from (%llu %llu %llu) to (%llu %llu %llu)", + applied_axi_vote->uncompressed_bw, + applied_axi_vote->compressed_bw, + applied_axi_vote->compressed_bw_ab, sum.uncompressed_bw, - sum.compressed_bw); + sum.compressed_bw, + sum.compressed_bw_ab); last_vote = top_priv->last_vote[cpashdl_type]; @@ -181,13 +190,16 @@ static int cam_vfe_top_set_axi_bw_vote( (CAM_VFE_TOP_VER2_MUX_MAX * CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); - if ((top_priv->applied_axi_vote.uncompressed_bw == + if ((applied_axi_vote->uncompressed_bw == sum.uncompressed_bw) && - (top_priv->applied_axi_vote.compressed_bw == - sum.compressed_bw)) { - CAM_DBG(CAM_ISP, "BW config unchanged %llu %llu", - top_priv->applied_axi_vote.uncompressed_bw, - top_priv->applied_axi_vote.compressed_bw); + (applied_axi_vote->compressed_bw == + sum.compressed_bw) && + (applied_axi_vote->compressed_bw_ab == + sum.compressed_bw_ab)) { + CAM_DBG(CAM_ISP, "BW config unchanged %llu %llu %llu", + applied_axi_vote->uncompressed_bw, + applied_axi_vote->compressed_bw, + applied_axi_vote->compressed_bw_ab); return 0; } @@ -196,10 +208,12 @@ static int cam_vfe_top_set_axi_bw_vote( soc_private->cpas_handle[cpashdl_type], &to_be_applied_axi_vote); if (!rc) { - top_priv->applied_axi_vote.uncompressed_bw = + applied_axi_vote->uncompressed_bw = to_be_applied_axi_vote.uncompressed_bw; - top_priv->applied_axi_vote.compressed_bw = + applied_axi_vote->compressed_bw = to_be_applied_axi_vote.compressed_bw; + applied_axi_vote->compressed_bw_ab = + to_be_applied_axi_vote.compressed_bw_ab; } return rc; } @@ -215,6 +229,11 @@ static int cam_vfe_top_set_axi_bw_vote( to_be_applied_axi_vote.compressed_bw = last_vote[i].compressed_bw; + if (to_be_applied_axi_vote.compressed_bw_ab < + last_vote[i].compressed_bw_ab) + to_be_applied_axi_vote.compressed_bw_ab = + last_vote[i].compressed_bw_ab; + if (to_be_applied_axi_vote.uncompressed_bw < last_vote[i].uncompressed_bw) to_be_applied_axi_vote.uncompressed_bw = @@ -222,9 +241,11 @@ static int cam_vfe_top_set_axi_bw_vote( } if ((to_be_applied_axi_vote.uncompressed_bw != - top_priv->applied_axi_vote.uncompressed_bw) || + applied_axi_vote->uncompressed_bw) || (to_be_applied_axi_vote.compressed_bw != - top_priv->applied_axi_vote.compressed_bw)) + applied_axi_vote->compressed_bw) || + (to_be_applied_axi_vote.compressed_bw_ab != + applied_axi_vote->compressed_bw_ab)) apply_bw_update = true; CAM_DBG(CAM_ISP, "apply_bw_update=%d", apply_bw_update); @@ -234,10 +255,12 @@ static int cam_vfe_top_set_axi_bw_vote( soc_private->cpas_handle[cpashdl_type], &to_be_applied_axi_vote); if (!rc) { - top_priv->applied_axi_vote.uncompressed_bw = - to_be_applied_axi_vote.uncompressed_bw; - top_priv->applied_axi_vote.compressed_bw = + applied_axi_vote->uncompressed_bw = + to_be_applied_axi_vote.uncompressed_bw; + applied_axi_vote->compressed_bw = to_be_applied_axi_vote.compressed_bw; + applied_axi_vote->compressed_bw_ab = + to_be_applied_axi_vote.compressed_bw_ab; } else { CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc); @@ -338,6 +361,8 @@ static int cam_vfe_top_bw_update( bw_update->camnoc_bw_bytes; top_priv->req_axi_vote[i].compressed_bw = bw_update->external_bw_bytes; + top_priv->req_axi_vote[i].compressed_bw_ab = + bw_update->external_bw_bytes_ab; top_priv->axi_vote_control[i] = CAM_VFE_BW_CONTROL_INCLUDE; break; @@ -639,6 +664,7 @@ int cam_vfe_top_stop(void *device_priv, if (top_priv->mux_rsrc[i].res_id == mux_res->res_id) { top_priv->req_clk_rate[i] = 0; top_priv->req_axi_vote[i].compressed_bw = 0; + top_priv->req_axi_vote[i].compressed_bw_ab = 0; top_priv->req_axi_vote[i].uncompressed_bw = 0; top_priv->axi_vote_control[i] = CAM_VFE_BW_CONTROL_EXCLUDE; @@ -742,6 +768,7 @@ int cam_vfe_top_ver2_init( vfe_top->top_priv = top_priv; top_priv->hw_clk_rate = 0; top_priv->applied_axi_vote.compressed_bw = 0; + top_priv->applied_axi_vote.compressed_bw_ab = 0; top_priv->applied_axi_vote.uncompressed_bw = 0; memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * (CAM_VFE_TOP_VER2_MUX_MAX * CAM_CPAS_HANDLE_MAX * @@ -756,6 +783,7 @@ int cam_vfe_top_ver2_init( CAM_ISP_RESOURCE_STATE_AVAILABLE; top_priv->req_clk_rate[i] = 0; top_priv->req_axi_vote[i].compressed_bw = 0; + top_priv->req_axi_vote[i].compressed_bw_ab = 0; top_priv->req_axi_vote[i].uncompressed_bw = 0; top_priv->axi_vote_control[i] = CAM_VFE_BW_CONTROL_EXCLUDE; diff --git a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index f27b54a81e4a..f7b42d5a7699 100644 --- a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -156,6 +156,12 @@ static int cam_jpeg_mgr_process_irq(void *priv, void *data) cmd_buf_kaddr = (uint32_t *)kaddr; + if ((p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].offset / + sizeof(uint32_t)) >= cmd_buf_len) { + CAM_ERR(CAM_JPEG, "Not enough buf"); + return -EINVAL; + } + cmd_buf_kaddr = (cmd_buf_kaddr + (p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].offset @@ -740,7 +746,7 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, (void *)packet, (void *)cmd_desc, sizeof(struct cam_cmd_buf_desc)); - rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl, -1); + rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl, -1, 0); if (rc) { CAM_ERR(CAM_JPEG, "Patch processing failed %d", rc); return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c index b6f1d56de67f..9a523f7479d9 100644 --- a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_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 @@ -65,6 +65,7 @@ int cam_jpeg_dma_init_hw(void *device_priv, ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_SVS_VOTE; axi_vote.compressed_bw = JPEG_VOTE; + axi_vote.compressed_bw_ab = JPEG_VOTE; axi_vote.uncompressed_bw = JPEG_VOTE; rc = cam_cpas_start(core_info->cpas_handle, diff --git a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index 7fcc1ada1a36..52907cd6803e 100644 --- a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_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 @@ -76,6 +76,7 @@ int cam_jpeg_enc_init_hw(void *device_priv, ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_SVS_VOTE; axi_vote.compressed_bw = JPEG_VOTE; + axi_vote.compressed_bw_ab = JPEG_VOTE; axi_vote.uncompressed_bw = JPEG_VOTE; rc = cam_cpas_start(core_info->cpas_handle, diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index 11e9069b3c79..f46426f50e97 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -871,7 +871,8 @@ static int cam_lrme_mgr_hw_prepare_update(void *hw_mgr_priv, kmd_buf.size, kmd_buf.used_bytes); rc = cam_packet_util_process_patches(args->packet, - hw_mgr->device_iommu.non_secure, hw_mgr->device_iommu.secure); + hw_mgr->device_iommu.non_secure, + hw_mgr->device_iommu.secure, 0); if (rc) { CAM_ERR(CAM_LRME, "Patch packet failed, rc=%d", rc); return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c index 8c58685696ad..d32e5f7edc1a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_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 @@ -33,6 +33,7 @@ int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw) ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_SVS_VOTE; axi_vote.compressed_bw = 7200000; + axi_vote.compressed_bw_ab = 7200000; axi_vote.uncompressed_bw = 7200000; rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); if (rc) { 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 234c51453476..f1b3ccefe62c 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 @@ -680,6 +680,7 @@ static int __cam_req_mgr_check_sync_for_mslave( struct cam_req_mgr_slot *sync_slot = NULL; int sync_slot_idx = 0, prev_idx, next_idx, rd_idx, sync_rd_idx, rc = 0; int64_t req_id = 0, sync_req_id = 0; + int32_t sync_num_slots = 0; if (!link->sync_link) { CAM_ERR(CAM_CRM, "Sync link null"); @@ -688,6 +689,7 @@ static int __cam_req_mgr_check_sync_for_mslave( sync_link = link->sync_link; req_id = slot->req_id; + sync_num_slots = sync_link->req.in_q->num_slots; sync_rd_idx = sync_link->req.in_q->rd_idx; CAM_DBG(CAM_CRM, @@ -765,7 +767,8 @@ static int __cam_req_mgr_check_sync_for_mslave( if ((sync_link->req.in_q->slot[sync_slot_idx].status != CRM_SLOT_STATUS_REQ_APPLIED) && - ((sync_slot_idx - rd_idx) >= 1) && + (((sync_slot_idx - rd_idx + sync_num_slots) % + sync_num_slots) >= 1) && (sync_link->req.in_q->slot[rd_idx].status != CRM_SLOT_STATUS_REQ_APPLIED)) { CAM_DBG(CAM_CRM, @@ -831,7 +834,8 @@ static int __cam_req_mgr_check_sync_for_mslave( if ((sync_link->req.in_q->slot[sync_slot_idx].status != CRM_SLOT_STATUS_REQ_APPLIED) && - ((sync_slot_idx - rd_idx) >= 1) && + (((sync_slot_idx - rd_idx + sync_num_slots) % + sync_num_slots) >= 1) && (sync_link->req.in_q->slot[rd_idx].status != CRM_SLOT_STATUS_REQ_APPLIED)) { CAM_DBG(CAM_CRM, @@ -888,6 +892,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( struct cam_req_mgr_core_link *sync_link = NULL; int64_t req_id = 0; int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; + int32_t sync_num_slots = 0; if (!link->sync_link) { CAM_ERR(CAM_CRM, "Sync link null"); @@ -896,6 +901,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( sync_link = link->sync_link; req_id = slot->req_id; + sync_num_slots = sync_link->req.in_q->num_slots; CAM_DBG(CAM_REQ, "link_hdl %x req %lld frame_skip_flag %d ", @@ -940,7 +946,8 @@ static int __cam_req_mgr_check_sync_req_is_ready( sync_rd_idx = sync_link->req.in_q->rd_idx; if ((sync_link->req.in_q->slot[sync_slot_idx].status != CRM_SLOT_STATUS_REQ_APPLIED) && - ((sync_slot_idx - sync_rd_idx) >= 1) && + (((sync_slot_idx - sync_rd_idx + sync_num_slots) % + sync_num_slots) >= 1) && (sync_link->req.in_q->slot[sync_rd_idx].status != CRM_SLOT_STATUS_REQ_APPLIED)) { CAM_DBG(CAM_CRM, @@ -1886,7 +1893,9 @@ int cam_req_mgr_process_add_req(void *priv, void *data) mutex_lock(&link->req.lock); idx = __cam_req_mgr_find_slot_for_req(link->req.in_q, add_req->req_id); if (idx < 0) { - CAM_ERR(CAM_CRM, "req %lld not found in in_q", add_req->req_id); + CAM_ERR(CAM_CRM, + "req %lld not found in in_q for dev %s on link 0x%x", + add_req->req_id, device->dev_info.name, link->link_hdl); rc = -EBADSLT; mutex_unlock(&link->req.lock); goto end; @@ -1906,8 +1915,10 @@ int cam_req_mgr_process_add_req(void *priv, void *data) if (slot->state != CRM_REQ_STATE_PENDING && slot->state != CRM_REQ_STATE_EMPTY) { - CAM_WARN(CAM_CRM, "Unexpected state %d for slot %d map %x", - slot->state, idx, slot->req_ready_map); + CAM_WARN(CAM_CRM, + "Unexpected state %d for slot %d map %x for dev %s on link 0x%x", + slot->state, idx, slot->req_ready_map, + device->dev_info.name, link->link_hdl); } slot->state = CRM_REQ_STATE_PENDING; 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 7d71cd57573e..fa290c0b982c 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 @@ -81,6 +81,7 @@ int cam_cci_init(struct v4l2_subdev *sd, ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_SVS_VOTE; axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.compressed_bw_ab = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; rc = cam_cpas_start(cci_dev->cpas_handle, 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 17499489184b..318ea555e98c 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; @@ -850,6 +917,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_SVS_VOTE; axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.compressed_bw_ab = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; rc = cam_cpas_start(csiphy_dev->cpas_handle, 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..67653e81fde1 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_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[] = { @@ -297,7 +299,7 @@ struct csiphy_reg_t 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 +307,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 +323,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 +363,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 +387,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 +403,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 220cd1598922..a04d97143592 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 @@ -913,7 +913,7 @@ error: vfree(e_ctrl->cal_data.map); e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; - e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; release_buf: if (cam_mem_put_cpu_buf(dev_config.packet_handle)) CAM_WARN(CAM_EEPROM, "Put cpu buffer failed : %llu", 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 5f77ca0a5293..111f121757c1 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 @@ -937,9 +937,13 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, rc = cam_sensor_apply_settings(s_ctrl, 0, CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG); + + s_ctrl->i2c_data.init_settings.request_id = -1; + if (rc < 0) { CAM_ERR(CAM_SENSOR, "cannot apply init settings"); + delete_request(&s_ctrl->i2c_data.init_settings); goto release_mutex; } rc = delete_request(&s_ctrl->i2c_data.init_settings); @@ -948,16 +952,20 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, "Fail in deleting the Init settings"); goto release_mutex; } - s_ctrl->i2c_data.init_settings.request_id = -1; } if (s_ctrl->i2c_data.config_settings.is_settings_valid && (s_ctrl->i2c_data.config_settings.request_id == 0)) { rc = cam_sensor_apply_settings(s_ctrl, 0, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG); + + s_ctrl->i2c_data.config_settings.request_id = -1; + if (rc < 0) { CAM_ERR(CAM_SENSOR, "cannot apply config settings"); + delete_request( + &s_ctrl->i2c_data.config_settings); goto release_mutex; } rc = delete_request(&s_ctrl->i2c_data.config_settings); @@ -967,7 +975,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto release_mutex; } s_ctrl->sensor_state = CAM_SENSOR_CONFIG; - s_ctrl->i2c_data.config_settings.request_id = -1; } } break; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 7f6f3aa40998..4d314964effd 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -37,8 +37,7 @@ static struct i2c_settings_list* return NULL; tmp->i2c_settings.reg_setting = (struct cam_sensor_i2c_reg_array *) - kcalloc(size, sizeof(struct cam_sensor_i2c_reg_array), - GFP_KERNEL); + vzalloc(size * sizeof(struct cam_sensor_i2c_reg_array)); if (tmp->i2c_settings.reg_setting == NULL) { list_del(&(tmp->list)); kfree(tmp); @@ -61,7 +60,7 @@ int32_t delete_request(struct i2c_settings_array *i2c_array) list_for_each_entry_safe(i2c_list, i2c_next, &(i2c_array->list_head), list) { - kfree(i2c_list->i2c_settings.reg_setting); + vfree(i2c_list->i2c_settings.reg_setting); list_del(&(i2c_list->list)); kfree(i2c_list); } @@ -338,6 +337,7 @@ int cam_sensor_i2c_command_parser( cmd_buf = (uint32_t *)generic_ptr; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + remain_len -= cmd_desc[i].offset; if (remain_len < cmd_desc[i].length) { CAM_ERR(CAM_SENSOR, "buffer provided too small"); return -EINVAL; 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 7ddfa3d2ec56..62b81aad8dd0 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 @@ -24,6 +24,7 @@ #include <soc/qcom/scm.h> #include <soc/qcom/secure_buffer.h> #include <uapi/media/cam_req_mgr.h> +#include <linux/debugfs.h> #include "cam_smmu_api.h" #include "cam_debug_util.h" @@ -188,6 +189,10 @@ static const char *qdss_region_name = "qdss"; static struct cam_iommu_cb_set iommu_cb_set; +static struct dentry *smmu_dentry; + +static bool smmu_fatal_flag; + static enum dma_data_direction cam_smmu_translate_dir( enum cam_smmu_map_dir dir); @@ -297,6 +302,30 @@ static void cam_smmu_page_fault_work(struct work_struct *work) kfree(payload); } +static int cam_smmu_create_debugfs_entry(void) +{ + int rc = 0; + + smmu_dentry = debugfs_create_dir("camera_smmu", NULL); + if (!smmu_dentry) + return -ENOMEM; + + if (!debugfs_create_bool("cam_smmu_fatal", + 0644, + smmu_dentry, + &smmu_fatal_flag)) { + CAM_ERR(CAM_SMMU, "failed to create cam_smmu_fatal entry"); + rc = -ENOMEM; + goto err; + } + + return rc; +err: + debugfs_remove_recursive(smmu_dentry); + smmu_dentry = NULL; + return rc; +} + static void cam_smmu_print_user_list(int idx) { struct cam_dma_buff_info *mapping; @@ -682,10 +711,6 @@ static int cam_smmu_create_add_handle_in_table(char *name, if (!strcmp(iommu_cb_set.cb_info[i].name, name)) { mutex_lock(&iommu_cb_set.cb_info[i].lock); if (iommu_cb_set.cb_info[i].handle != HANDLE_INIT) { - CAM_ERR(CAM_SMMU, - "Error: %s already got handle 0x%x", - name, - iommu_cb_set.cb_info[i].handle); if (iommu_cb_set.cb_info[i].is_secure) iommu_cb_set.cb_info[i].secure_count++; @@ -695,6 +720,11 @@ static int cam_smmu_create_add_handle_in_table(char *name, *hdl = iommu_cb_set.cb_info[i].handle; return 0; } + + CAM_ERR(CAM_SMMU, + "Error: %s already got handle 0x%x", + name, iommu_cb_set.cb_info[i].handle); + return -EINVAL; } @@ -3150,7 +3180,7 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, goto end; } - iommu_cb_set.non_fatal_fault = 1; + iommu_cb_set.non_fatal_fault = smmu_fatal_flag; if (iommu_domain_set_attr(cb->mapping->domain, DOMAIN_ATTR_NON_FATAL_FAULTS, &iommu_cb_set.non_fatal_fault) < 0) { @@ -3509,6 +3539,7 @@ static struct platform_driver cam_smmu_driver = { static int __init cam_smmu_init_module(void) { + cam_smmu_create_debugfs_entry(); return platform_driver_register(&cam_smmu_driver); } 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 1be244bb7c3a..d3f62d6a3e20 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 @@ -322,7 +322,7 @@ int cam_sync_get_obj_ref(int32_t sync_obj) if (row->state != CAM_SYNC_STATE_ACTIVE) { spin_unlock(&sync_dev->row_spinlocks[sync_obj]); - CAM_ERR(CAM_SYNC, + CAM_ERR_RATE_LIMIT_CUSTOM(CAM_SYNC, 1, 5, "accessing an uninitialized sync obj = %d state = %d", sync_obj, row->state); return -EINVAL; diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_debug_util.h index 9093517de1e4..0aa898f8e11f 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_debug_util.h +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_debug_util.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 @@ -120,6 +120,27 @@ const char *cam_get_module_name(unsigned int module_id); cam_get_module_name(__module), __func__, __LINE__, ##args) /* + * CAM_INFO_RATE_LIMIT_CUSTOM + * @brief : This Macro will print info logs with custom ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @interval : Time interval in seconds + * @burst : No of logs to print in interval time + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_INFO_RATE_LIMIT_CUSTOM(__module, interval, burst, fmt, args...) \ + ({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + (interval * HZ), \ + burst); \ + if (__ratelimit(&_rs)) \ + pr_info("CAM_INFO: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__,\ + __LINE__, ##args); \ + }) + +/* * CAM_DBG * @brief : This Macro will print debug logs when enabled using GROUP * @@ -138,4 +159,25 @@ const char *cam_get_module_name(unsigned int module_id); pr_err_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, __LINE__, ##args) +/* + * CAM_ERR_RATE_LIMIT_CUSTOM + * @brief : This Macro will print error logs with custom ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @interval : Time interval in seconds + * @burst : No of logs to print in interval time + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_ERR_RATE_LIMIT_CUSTOM(__module, interval, burst, fmt, args...) \ + ({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + (interval * HZ), \ + burst); \ + if (__ratelimit(&_rs)) \ + pr_err("CAM_ERR: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__,\ + __LINE__, ##args); \ + }) + #endif /* _CAM_DEBUG_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c index ba244e780336..0f910c9e8273 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c @@ -169,7 +169,7 @@ rel_kmd_buf: } int cam_packet_util_process_patches(struct cam_packet *packet, - int32_t iommu_hdl, int32_t sec_mmu_hdl) + int32_t iommu_hdl, int32_t sec_mmu_hdl, int pf_dump_flag) { struct cam_patch_desc *patch_desc = NULL; dma_addr_t iova_addr; @@ -242,6 +242,14 @@ int cam_packet_util_process_patches(struct cam_packet *packet, if (cam_mem_put_cpu_buf(patch_desc[i].dst_buf_hdl)) CAM_WARN(CAM_UTIL, "unable to put dst buf address:0x%x", patch_desc[i].dst_buf_hdl); + + if (pf_dump_flag) { + CAM_INFO(CAM_UTIL, + "patch[%d]: patched addr %llx sz 0x%x offset:0x%x", + i, *((uint64_t *)dst_cpu_addr), + (uint32_t)src_buf_size, + patch_desc[i].src_offset); + } } return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h index 412eba52b05a..33c07ad89f4e 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h @@ -106,12 +106,14 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, * @iommu_hdl: IOMMU handle of the HW Device that received the packet * @sec_iommu_hdl: Secure IOMMU handle of the HW Device that * received the packet + * @pf_dump_flag: if set, it will dump the info, + * otherwise will do patching * * @return: 0: Success * Negative: Failure */ int cam_packet_util_process_patches(struct cam_packet *packet, - int32_t iommu_hdl, int32_t sec_mmu_hdl); + int32_t iommu_hdl, int32_t sec_mmu_hdl, int pf_dump_flag); /** * cam_packet_util_process_generic_cmd_buffer() 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 693b0da29be2..f3af61936625 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 @@ -490,14 +490,17 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, int32_t src_clk_idx; struct clk *clk = NULL; int32_t apply_level; + uint32_t clk_level_override = 0; if (!soc_info || (soc_info->src_clk_idx < 0)) return -EINVAL; - if (soc_info->clk_level_override && clk_rate) - clk_rate = soc_info->clk_level_override; - src_clk_idx = soc_info->src_clk_idx; + clk_level_override = soc_info->clk_level_override; + if (clk_level_override && clk_rate) + clk_rate = + soc_info->clk_rate[clk_level_override][src_clk_idx]; + clk = soc_info->clk[src_clk_idx]; if (soc_info->cam_cx_ipeak_enable && clk_rate >= 0) { 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/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index 802e58140d85..1b711b33873b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.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 @@ -953,7 +953,7 @@ void msm_clock_data_reset(struct msm_vidc_inst *inst) dprintk(VIDC_DBG, "Init DCVS Load\n"); - if (!inst || !inst->core) { + if (!inst || !inst->core || !inst->clk_data.entry) { dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n", __func__, inst); return; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index e38439778329..ab7381305179 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.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 @@ -5231,6 +5231,14 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) "Invalid params, inst %pK\n", inst); return -EINVAL; } + + if (inst->state < MSM_VIDC_OPEN_DONE) { + dprintk(VIDC_ERR, + "Invalid state to call flush, inst %pK, state %#x\n", + inst, inst->state); + return -EINVAL; + } + core = inst->core; hdev = core->device; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 6dd88ff389a3..13a3a971610d 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1210,6 +1210,8 @@ static void mmc_sd_detect(struct mmc_host *host) goto out; } + mmc_power_up(host, host->ocr_avail); + /* * Just check if our card has been removed. */ @@ -1349,6 +1351,9 @@ static int _mmc_sd_resume(struct mmc_host *host) mmc_card_set_removed(host->card); mmc_detect_change(host, msecs_to_jiffies(200)); } else if (err) { + pr_err("%s: %s: mmc_sd_init_card_failed (%d)\n", + mmc_hostname(host), __func__, err); + mmc_power_off(host); goto out; } mmc_card_clr_suspended(host->card); diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 5b5ad0f5578a..7fc220aaff14 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -13,6 +13,16 @@ menuconfig NVMEM if NVMEM +config NVMEM_SYSFS + bool "/sys/bus/nvmem/devices/*/nvmem (sysfs interface)" + depends on SYSFS + default y + help + Say Y here to add a sysfs interface for NVMEM. + + This interface is mostly used by userspace applications to + read/write directly into nvmem. + config NVMEM_IMX_OCOTP tristate "i.MX6 On-Chip OTP Controller support" depends on SOC_IMX6 || COMPILE_TEST diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 1e99e8cc0ed2..248ac34b6e72 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -5,6 +5,9 @@ obj-$(CONFIG_NVMEM) += nvmem_core.o nvmem_core-y := core.o +obj-$(CONFIG_NVMEM_SYSFS) += nvmem_sysfs.o +nvmem_sysfs-y := nvmem-sysfs.o + # Devices obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o nvmem-imx-ocotp-y := imx-ocotp.o diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 1b4d93e9157e..3e3f599e53b7 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -25,26 +25,7 @@ #include <linux/of.h> #include <linux/slab.h> -struct nvmem_device { - const char *name; - struct module *owner; - struct device dev; - int stride; - int word_size; - int ncells; - int id; - int users; - size_t size; - bool read_only; - int flags; - struct bin_attribute eeprom; - struct device *base_dev; - nvmem_reg_read_t reg_read; - nvmem_reg_write_t reg_write; - void *priv; -}; - -#define FLAG_COMPAT BIT(0) +#include "nvmem.h" struct nvmem_cell { const char *name; @@ -62,11 +43,6 @@ static DEFINE_IDA(nvmem_ida); static LIST_HEAD(nvmem_cells); static DEFINE_MUTEX(nvmem_cells_mutex); -#ifdef CONFIG_DEBUG_LOCK_ALLOC -static struct lock_class_key eeprom_lock_key; -#endif - -#define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, void *val, size_t bytes) { @@ -85,168 +61,6 @@ static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, return -EINVAL; } -static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t pos, size_t count) -{ - struct device *dev; - struct nvmem_device *nvmem; - int rc; - - if (attr->private) - dev = attr->private; - else - dev = container_of(kobj, struct device, kobj); - nvmem = to_nvmem_device(dev); - - /* Stop the user from reading */ - if (pos >= nvmem->size) - return 0; - - if (count < nvmem->word_size) - return -EINVAL; - - if (pos + count > nvmem->size) - count = nvmem->size - pos; - - count = round_down(count, nvmem->word_size); - - rc = nvmem_reg_read(nvmem, pos, buf, count); - - if (rc) - return rc; - - return count; -} - -static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t pos, size_t count) -{ - struct device *dev; - struct nvmem_device *nvmem; - int rc; - - if (attr->private) - dev = attr->private; - else - dev = container_of(kobj, struct device, kobj); - nvmem = to_nvmem_device(dev); - - /* Stop the user from writing */ - if (pos >= nvmem->size) - return 0; - - if (count < nvmem->word_size) - return -EINVAL; - - if (pos + count > nvmem->size) - count = nvmem->size - pos; - - count = round_down(count, nvmem->word_size); - - rc = nvmem_reg_write(nvmem, pos, buf, count); - - if (rc) - return rc; - - return count; -} - -/* default read/write permissions */ -static struct bin_attribute bin_attr_rw_nvmem = { - .attr = { - .name = "nvmem", - .mode = S_IWUSR | S_IRUGO, - }, - .read = bin_attr_nvmem_read, - .write = bin_attr_nvmem_write, -}; - -static struct bin_attribute *nvmem_bin_rw_attributes[] = { - &bin_attr_rw_nvmem, - NULL, -}; - -static const struct attribute_group nvmem_bin_rw_group = { - .bin_attrs = nvmem_bin_rw_attributes, -}; - -static const struct attribute_group *nvmem_rw_dev_groups[] = { - &nvmem_bin_rw_group, - NULL, -}; - -/* read only permission */ -static struct bin_attribute bin_attr_ro_nvmem = { - .attr = { - .name = "nvmem", - .mode = S_IRUGO, - }, - .read = bin_attr_nvmem_read, -}; - -static struct bin_attribute *nvmem_bin_ro_attributes[] = { - &bin_attr_ro_nvmem, - NULL, -}; - -static const struct attribute_group nvmem_bin_ro_group = { - .bin_attrs = nvmem_bin_ro_attributes, -}; - -static const struct attribute_group *nvmem_ro_dev_groups[] = { - &nvmem_bin_ro_group, - NULL, -}; - -/* default read/write permissions, root only */ -static struct bin_attribute bin_attr_rw_root_nvmem = { - .attr = { - .name = "nvmem", - .mode = S_IWUSR | S_IRUSR, - }, - .read = bin_attr_nvmem_read, - .write = bin_attr_nvmem_write, -}; - -static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { - &bin_attr_rw_root_nvmem, - NULL, -}; - -static const struct attribute_group nvmem_bin_rw_root_group = { - .bin_attrs = nvmem_bin_rw_root_attributes, -}; - -static const struct attribute_group *nvmem_rw_root_dev_groups[] = { - &nvmem_bin_rw_root_group, - NULL, -}; - -/* read only permission, root only */ -static struct bin_attribute bin_attr_ro_root_nvmem = { - .attr = { - .name = "nvmem", - .mode = S_IRUSR, - }, - .read = bin_attr_nvmem_read, -}; - -static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { - &bin_attr_ro_root_nvmem, - NULL, -}; - -static const struct attribute_group nvmem_bin_ro_root_group = { - .bin_attrs = nvmem_bin_ro_root_attributes, -}; - -static const struct attribute_group *nvmem_ro_root_dev_groups[] = { - &nvmem_bin_ro_root_group, - NULL, -}; - static void nvmem_release(struct device *dev) { struct nvmem_device *nvmem = to_nvmem_device(dev); @@ -388,43 +202,6 @@ err: return rval; } -/* - * nvmem_setup_compat() - Create an additional binary entry in - * drivers sys directory, to be backwards compatible with the older - * drivers/misc/eeprom drivers. - */ -static int nvmem_setup_compat(struct nvmem_device *nvmem, - const struct nvmem_config *config) -{ - int rval; - - if (!config->base_dev) - return -EINVAL; - - if (nvmem->read_only) - nvmem->eeprom = bin_attr_ro_root_nvmem; - else - nvmem->eeprom = bin_attr_rw_root_nvmem; - nvmem->eeprom.attr.name = "eeprom"; - nvmem->eeprom.size = nvmem->size; -#ifdef CONFIG_DEBUG_LOCK_ALLOC - nvmem->eeprom.attr.key = &eeprom_lock_key; -#endif - nvmem->eeprom.private = &nvmem->dev; - nvmem->base_dev = config->base_dev; - - rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); - if (rval) { - dev_err(&nvmem->dev, - "Failed to create eeprom binary file %d\n", rval); - return rval; - } - - nvmem->flags |= FLAG_COMPAT; - - return 0; -} - /** * nvmem_register() - Register a nvmem device for given nvmem_config. * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem @@ -473,15 +250,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->read_only = of_property_read_bool(np, "read-only") | config->read_only; - if (config->root_only) - nvmem->dev.groups = nvmem->read_only ? - nvmem_ro_root_dev_groups : - nvmem_rw_root_dev_groups; - else - nvmem->dev.groups = nvmem->read_only ? - nvmem_ro_dev_groups : - nvmem_rw_dev_groups; - + nvmem->dev.groups = nvmem_sysfs_get_groups(nvmem, config); device_initialize(&nvmem->dev); dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); @@ -491,7 +260,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) goto err_put_device; if (config->compat) { - rval = nvmem_setup_compat(nvmem, config); + rval = nvmem_sysfs_setup_compat(nvmem, config); if (rval) goto err_device_del; } diff --git a/drivers/nvmem/nvmem-sysfs.c b/drivers/nvmem/nvmem-sysfs.c new file mode 100644 index 000000000000..cb1fbafc52ce --- /dev/null +++ b/drivers/nvmem/nvmem-sysfs.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019, Linaro Limited + */ +#include "nvmem.h" + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +static struct lock_class_key eeprom_lock_key; +#endif + +static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t pos, size_t count) +{ + struct device *dev; + struct nvmem_device *nvmem; + int rc; + + if (attr->private) + dev = attr->private; + else + dev = container_of(kobj, struct device, kobj); + nvmem = to_nvmem_device(dev); + + /* Stop the user from reading */ + if (pos >= nvmem->size) + return 0; + + if (count < nvmem->word_size) + return -EINVAL; + + if (pos + count > nvmem->size) + count = nvmem->size - pos; + + count = round_down(count, nvmem->word_size); + + rc = nvmem->reg_read(nvmem->priv, pos, buf, count); + + if (rc) + return rc; + + return count; +} + +static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t pos, size_t count) +{ + struct device *dev; + struct nvmem_device *nvmem; + int rc; + + if (attr->private) + dev = attr->private; + else + dev = container_of(kobj, struct device, kobj); + nvmem = to_nvmem_device(dev); + + /* Stop the user from writing */ + if (pos >= nvmem->size) + return -EFBIG; + + if (count < nvmem->word_size) + return -EINVAL; + + if (pos + count > nvmem->size) + count = nvmem->size - pos; + + count = round_down(count, nvmem->word_size); + + rc = nvmem->reg_write(nvmem->priv, pos, buf, count); + + if (rc) + return rc; + + return count; +} + +/* default read/write permissions */ +static struct bin_attribute bin_attr_rw_nvmem = { + .attr = { + .name = "nvmem", + .mode = S_IWUSR | S_IRUGO, + }, + .read = bin_attr_nvmem_read, + .write = bin_attr_nvmem_write, +}; + +static struct bin_attribute *nvmem_bin_rw_attributes[] = { + &bin_attr_rw_nvmem, + NULL, +}; + +static const struct attribute_group nvmem_bin_rw_group = { + .bin_attrs = nvmem_bin_rw_attributes, +}; + +static const struct attribute_group *nvmem_rw_dev_groups[] = { + &nvmem_bin_rw_group, + NULL, +}; + +/* read only permission */ +static struct bin_attribute bin_attr_ro_nvmem = { + .attr = { + .name = "nvmem", + .mode = S_IRUGO, + }, + .read = bin_attr_nvmem_read, +}; + +static struct bin_attribute *nvmem_bin_ro_attributes[] = { + &bin_attr_ro_nvmem, + NULL, +}; + +static const struct attribute_group nvmem_bin_ro_group = { + .bin_attrs = nvmem_bin_ro_attributes, +}; + +static const struct attribute_group *nvmem_ro_dev_groups[] = { + &nvmem_bin_ro_group, + NULL, +}; + +/* default read/write permissions, root only */ +static struct bin_attribute bin_attr_rw_root_nvmem = { + .attr = { + .name = "nvmem", + .mode = S_IWUSR | S_IRUSR, + }, + .read = bin_attr_nvmem_read, + .write = bin_attr_nvmem_write, +}; + +static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { + &bin_attr_rw_root_nvmem, + NULL, +}; + +static const struct attribute_group nvmem_bin_rw_root_group = { + .bin_attrs = nvmem_bin_rw_root_attributes, +}; + +static const struct attribute_group *nvmem_rw_root_dev_groups[] = { + &nvmem_bin_rw_root_group, + NULL, +}; + +/* read only permission, root only */ +static struct bin_attribute bin_attr_ro_root_nvmem = { + .attr = { + .name = "nvmem", + .mode = S_IRUSR, + }, + .read = bin_attr_nvmem_read, +}; + +static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { + &bin_attr_ro_root_nvmem, + NULL, +}; + +static const struct attribute_group nvmem_bin_ro_root_group = { + .bin_attrs = nvmem_bin_ro_root_attributes, +}; + +static const struct attribute_group *nvmem_ro_root_dev_groups[] = { + &nvmem_bin_ro_root_group, + NULL, +}; + +const struct attribute_group **nvmem_sysfs_get_groups( + struct nvmem_device *nvmem, + const struct nvmem_config *config) +{ + if (config->root_only) + return nvmem->read_only ? + nvmem_ro_root_dev_groups : + nvmem_rw_root_dev_groups; + + return nvmem->read_only ? nvmem_ro_dev_groups : nvmem_rw_dev_groups; +} + +/* + * nvmem_setup_compat() - Create an additional binary entry in + * drivers sys directory, to be backwards compatible with the older + * drivers/misc/eeprom drivers. + */ +int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, + const struct nvmem_config *config) +{ + int rval; + + if (!config->compat) + return 0; + + if (!config->base_dev) + return -EINVAL; + + if (nvmem->read_only) + nvmem->eeprom = bin_attr_ro_root_nvmem; + else + nvmem->eeprom = bin_attr_rw_root_nvmem; + nvmem->eeprom.attr.name = "eeprom"; + nvmem->eeprom.size = nvmem->size; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + nvmem->eeprom.attr.key = &eeprom_lock_key; +#endif + nvmem->eeprom.private = &nvmem->dev; + nvmem->base_dev = config->base_dev; + + rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); + if (rval) { + dev_err(&nvmem->dev, + "Failed to create eeprom binary file %d\n", rval); + return rval; + } + + nvmem->flags |= FLAG_COMPAT; + + return 0; +} + +void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, + const struct nvmem_config *config) +{ + if (config->compat) + device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); +} diff --git a/drivers/nvmem/nvmem.h b/drivers/nvmem/nvmem.h new file mode 100644 index 000000000000..d020479cd0b1 --- /dev/null +++ b/drivers/nvmem/nvmem.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _DRIVERS_NVMEM_H +#define _DRIVERS_NVMEM_H + +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/kref.h> +#include <linux/list.h> +#include <linux/nvmem-consumer.h> +#include <linux/nvmem-provider.h> + +struct nvmem_device { + const char *name; + struct module *owner; + struct device dev; + int stride; + int word_size; + int ncells; + int id; + int users; + size_t size; + bool read_only; + int flags; + struct bin_attribute eeprom; + struct device *base_dev; + nvmem_reg_read_t reg_read; + nvmem_reg_write_t reg_write; + void *priv; +}; + +#define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) +#define FLAG_COMPAT BIT(0) + +#ifdef CONFIG_NVMEM_SYSFS +const struct attribute_group **nvmem_sysfs_get_groups( + struct nvmem_device *nvmem, + const struct nvmem_config *config); +int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, + const struct nvmem_config *config); +void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, + const struct nvmem_config *config); +#else +static inline const struct attribute_group **nvmem_sysfs_get_groups( + struct nvmem_device *nvmem, + const struct nvmem_config *config) +{ + return NULL; +} + +static inline int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, + const struct nvmem_config *config) +{ + return -ENOSYS; +} +static inline void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, + const struct nvmem_config *config) +{ +} +#endif /* CONFIG_NVMEM_SYSFS */ + +#endif /* _DRIVERS_NVMEM_H */ 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 3aa8a01f75af..25152eacb855 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.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 @@ -794,7 +794,7 @@ int ipa3_qmi_ul_filter_request_send( { struct ipa_configure_ul_firewall_rules_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - int rc; + int rc, i; IPAWANDBG("IPACM pass %u rules to Q6\n", req->firewall_rules_list_len); @@ -814,6 +814,37 @@ int ipa3_qmi_ul_filter_request_send( } mutex_unlock(&ipa3_qmi_lock); + /* check if modem is up */ + if (!ipa3_qmi_indication_fin || + !ipa3_qmi_modem_init_fin || + !ipa_q6_clnt) { + IPAWANDBG("modem QMI service is not up yet\n"); + return -EINVAL; + } + + /* Passing 0 rules means that firewall is disabled */ + if (req->firewall_rules_list_len == 0) + IPAWANDBG("IPACM passed 0 rules to Q6\n"); + + if (req->firewall_rules_list_len >= QMI_IPA_MAX_UL_FIREWALL_RULES_V01) { + IPAWANERR( + "Number of rules passed by IPACM, %d, exceed limit %d\n", + req->firewall_rules_list_len, + QMI_IPA_MAX_UL_FIREWALL_RULES_V01); + return -EINVAL; + } + + /* Check for valid IP type */ + for (i = 0; i < req->firewall_rules_list_len; i++) { + 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) + IPAWANERR("Invalid IP type %d\n", + req->firewall_rules_list[i].ip_type); + return -EINVAL; + } + req_desc.max_msg_len = QMI_IPA_INSTALL_UL_FIREWALL_RULES_REQ_MAX_MSG_LEN_V01; req_desc.msg_id = QMI_IPA_INSTALL_UL_FIREWALL_RULES_REQ_V01; diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index f3acd4113b06..c895d219cf85 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -1326,6 +1326,7 @@ static int wlfw_msa_mem_info_send_sync_msg(void) struct wlfw_msa_info_req_msg_v01 req; struct wlfw_msa_info_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; + uint64_t max_mapped_addr; if (!penv || !penv->wlfw_clnt) return -ENODEV; @@ -1372,9 +1373,23 @@ static int wlfw_msa_mem_info_send_sync_msg(void) goto out; } + max_mapped_addr = penv->msa_pa + penv->msa_mem_size; penv->stats.msa_info_resp++; penv->nr_mem_region = resp.mem_region_info_len; for (i = 0; i < resp.mem_region_info_len; i++) { + + if (resp.mem_region_info[i].size > penv->msa_mem_size || + resp.mem_region_info[i].region_addr > max_mapped_addr || + resp.mem_region_info[i].region_addr < penv->msa_pa || + resp.mem_region_info[i].size + + resp.mem_region_info[i].region_addr > max_mapped_addr) { + icnss_pr_dbg("Received out of range Addr: 0x%llx Size: 0x%x\n", + resp.mem_region_info[i].region_addr, + resp.mem_region_info[i].size); + ret = -EINVAL; + goto fail_unwind; + } + penv->mem_region[i].reg_addr = resp.mem_region_info[i].region_addr; penv->mem_region[i].size = @@ -1389,6 +1404,8 @@ static int wlfw_msa_mem_info_send_sync_msg(void) return 0; +fail_unwind: + memset(&penv->mem_region[0], 0, sizeof(penv->mem_region[0]) * i); out: penv->stats.msa_info_err++; ICNSS_QMI_ASSERT(); 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/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index 91360e240b49..995d6ec7e4b2 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -90,6 +90,7 @@ #define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG 3 #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 /* Query devices */ /** @@ -387,6 +388,25 @@ struct cam_isp_bw_config { struct cam_isp_bw_vote rdi_vote[1]; } __attribute__((packed)); + +/** + * struct cam_isp_bw_config_ab - Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_vote_ab: AB Bandwidth vote for left ISP + * @right_pix_vote_ab: AB Bandwidth vote for right ISP + * @rdi_vote_ab: AB RDI bandwidth requirements + */ + +struct cam_isp_bw_config_ab { + uint32_t usage_type; + uint32_t num_rdi; + uint64_t left_pix_vote_ab; + uint64_t right_pix_vote_ab; + uint64_t rdi_vote_ab[1]; +} __attribute__((packed)); + /** * struct cam_fe_config - Fetch Engine configuration * diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index e213b3e498d8..fcb62fe15eee 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -169,6 +169,7 @@ unsigned int sysctl_sched_capacity_margin_down = 1205; /* ~15% margin */ #ifdef CONFIG_SCHED_WALT unsigned int sysctl_sched_min_task_util_for_boost_colocation; #endif +static unsigned int __maybe_unused sched_small_task_threshold = 102; static inline void update_load_add(struct load_weight *lw, unsigned long inc) { @@ -9854,6 +9855,18 @@ static struct rq *find_busiest_queue(struct lb_env *env, capacity = capacity_of(i); + /* + * For ASYM_CPUCAPACITY domains, don't pick a cpu that could + * eventually lead to active_balancing high->low capacity. + * Higher per-cpu capacity is considered better than balancing + * average load. + */ + if (env->sd->flags & SD_ASYM_CPUCAPACITY && + capacity_of(env->dst_cpu) < capacity && + (rq->nr_running == 1 || (rq->nr_running == 2 && + task_util(rq->curr) < sched_small_task_threshold))) + continue; + wl = weighted_cpuload(i); /* @@ -10328,6 +10341,27 @@ update_next_balance(struct sched_domain *sd, unsigned long *next_balance) *next_balance = next; } +#ifdef CONFIG_SCHED_WALT +static inline bool min_cap_cluster_has_misfit_task(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + if (!is_min_capacity_cpu(cpu)) + break; + if (cpu_rq(cpu)->walt_stats.nr_big_tasks) + return true; + } + + return false; +} +#else +static inline bool min_cap_cluster_has_misfit_task(void) +{ + return false; +} +#endif + /* * idle_balance is called by schedule() if this_cpu is about to become * idle. Attempts to pull tasks from other CPUs. @@ -10339,17 +10373,25 @@ static int idle_balance(struct rq *this_rq) struct sched_domain *sd; int pulled_task = 0; u64 curr_cost = 0; + bool force_lb = false; if (cpu_isolated(this_cpu)) return 0; /* + * Force higher capacity CPUs doing load balance, when the lower + * capacity CPUs has some misfit tasks. + */ + if (!is_min_capacity_cpu(this_cpu) && min_cap_cluster_has_misfit_task()) + force_lb = true; + + /* * We must set idle_stamp _before_ calling idle_balance(), such that we * measure the duration of idle_balance() as idle time. */ this_rq->idle_stamp = rq_clock(this_rq); - if (!energy_aware() && + if (!energy_aware() && !force_lb && (this_rq->avg_idle < sysctl_sched_migration_cost || !this_rq->rd->overload)) { rcu_read_lock(); @@ -10372,7 +10414,8 @@ static int idle_balance(struct rq *this_rq) if (!(sd->flags & SD_LOAD_BALANCE)) continue; - if (this_rq->avg_idle < curr_cost + sd->max_newidle_lb_cost) { + if (!force_lb && + this_rq->avg_idle < curr_cost + sd->max_newidle_lb_cost) { update_next_balance(sd, &next_balance); break; } |