diff options
48 files changed, 693 insertions, 151 deletions
diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi index 9c6d12f38563..9e14211bdac8 100644 --- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi @@ -828,15 +828,14 @@ <&clock_mmss clk_camss_vfe0_ahb_clk>, <&clock_mmss clk_camss_vfe1_ahb_clk>, <&clock_mmss clk_camss_vfe_axi_clk>, - <&clock_mmss clk_camss_vfe0_stream_clk>, - <&clock_mmss clk_camss_vfe1_stream_clk>, <&clock_mmss clk_smmu_vfe_axi_clk>, <&clock_mmss clk_smmu_vfe_ahb_clk>, - <&clock_mmss clk_camss_csi_vfe0_clk>, - <&clock_mmss clk_camss_csi_vfe1_clk>, <&clock_mmss clk_vfe0_clk_src>, <&clock_mmss clk_vfe1_clk_src>, + <&clock_mmss clk_camss_vfe0_stream_clk>, + <&clock_mmss clk_camss_vfe1_stream_clk>, <&clock_mmss clk_camss_csi_vfe0_clk>, + <&clock_mmss clk_camss_csi_vfe1_clk>, <&clock_mmss clk_camss_csi2_ahb_clk>, <&clock_mmss clk_camss_csi2_clk>, <&clock_mmss clk_camss_csi2phy_clk>, @@ -858,15 +857,14 @@ "camss_vfe0_ahb_clk", "camss_vfe1_ahb_clk", "camss_vfe_axi_clk", - "camss_vfe0_stream_clk", - "camss_vfe1_stream_clk", "smmu_vfe_axi_clk", "smmu_vfe_ahb_clk", - "camss_csi_vfe0_clk", - "camss_csi_vfe1_clk", "vfe0_clk_src", "vfe1_clk_src", + "camss_vfe0_stream_clk", + "camss_vfe1_stream_clk", "camss_csi_vfe0_clk", + "camss_csi_vfe1_clk", "camss_csi2_ahb_clk", "camss_csi2_clk", "camss_csi2phy_clk", @@ -876,7 +874,6 @@ "camss_ispif_ahb_clk", "clk_camss_vfe0_clk", "clk_camss_vfe1_clk"; - qcom,clock-rates = <19200000 19200000 19200000 @@ -890,13 +887,12 @@ 320000000 0 0 + 320000000 + 320000000 0 0 0 0 - 320000000 - 320000000 - 0 0 200000000 200000000 @@ -906,6 +902,21 @@ 0 100000000 100000000>; + qcom,clock-cntl-support; + qcom,clock-control = "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "INIT_RATE", + "INIT_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE", + "INIT_RATE","NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE"; }; qcom,ntn_avb { diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi index 0c648a93aaab..5c08acbbcd19 100644 --- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi @@ -593,15 +593,14 @@ <&clock_mmss clk_camss_vfe0_ahb_clk>, <&clock_mmss clk_camss_vfe1_ahb_clk>, <&clock_mmss clk_camss_vfe_axi_clk>, - <&clock_mmss clk_camss_vfe0_stream_clk>, - <&clock_mmss clk_camss_vfe1_stream_clk>, <&clock_mmss clk_smmu_vfe_axi_clk>, <&clock_mmss clk_smmu_vfe_ahb_clk>, - <&clock_mmss clk_camss_csi_vfe0_clk>, - <&clock_mmss clk_camss_csi_vfe1_clk>, <&clock_mmss clk_vfe0_clk_src>, <&clock_mmss clk_vfe1_clk_src>, + <&clock_mmss clk_camss_vfe0_stream_clk>, + <&clock_mmss clk_camss_vfe1_stream_clk>, <&clock_mmss clk_camss_csi_vfe0_clk>, + <&clock_mmss clk_camss_csi_vfe1_clk>, <&clock_mmss clk_camss_csi2_ahb_clk>, <&clock_mmss clk_camss_csi2_clk>, <&clock_mmss clk_camss_csi2phy_clk>, @@ -623,15 +622,14 @@ "camss_vfe0_ahb_clk", "camss_vfe1_ahb_clk", "camss_vfe_axi_clk", - "camss_vfe0_stream_clk", - "camss_vfe1_stream_clk", "smmu_vfe_axi_clk", "smmu_vfe_ahb_clk", - "camss_csi_vfe0_clk", - "camss_csi_vfe1_clk", "vfe0_clk_src", "vfe1_clk_src", + "camss_vfe0_stream_clk", + "camss_vfe1_stream_clk", "camss_csi_vfe0_clk", + "camss_csi_vfe1_clk", "camss_csi2_ahb_clk", "camss_csi2_clk", "camss_csi2phy_clk", @@ -641,7 +639,6 @@ "camss_ispif_ahb_clk", "clk_camss_vfe0_clk", "clk_camss_vfe1_clk"; - qcom,clock-rates = <19200000 19200000 19200000 @@ -655,13 +652,12 @@ 320000000 0 0 + 320000000 + 320000000 0 0 0 0 - 320000000 - 320000000 - 0 0 200000000 200000000 @@ -671,6 +667,21 @@ 0 100000000 100000000>; + qcom,clock-cntl-support; + qcom,clock-control = "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "INIT_RATE", + "INIT_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE", + "INIT_RATE","NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE"; }; ntn1: ntn_avb@1 { /* Neutrno device on RC1*/ diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index 44d4c072dd29..a8d66b122429 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -387,7 +387,7 @@ CONFIG_MSM_AIS_DEBUG=y CONFIG_MSM_AIS_CAMERA_SENSOR=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_VIDEO_ADV7481=m -CONFIG_VIDEO_TVTUNER=y +CONFIG_VIDEO_TVTUNER=m CONFIG_QCOM_KGSL=y CONFIG_DRM=y CONFIG_MSM_BA_V4L2=y diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index b691690187c2..3a7e60990a81 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -391,7 +391,7 @@ CONFIG_MSM_AIS_DEBUG=y CONFIG_MSM_AIS_CAMERA_SENSOR=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_VIDEO_ADV7481=m -CONFIG_VIDEO_TVTUNER=y +CONFIG_VIDEO_TVTUNER=m CONFIG_QCOM_KGSL=y CONFIG_DRM=y CONFIG_MSM_BA_V4L2=y diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c index 8cc803eef552..8d766e1ae583 100644 --- a/drivers/char/diag/diag_mux.c +++ b/drivers/char/diag/diag_mux.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -239,6 +239,8 @@ int diag_mux_switch_logging(int *req_mode, int *peripheral_mask) new_mask = ~(*peripheral_mask) & diag_mux->mux_mask; if (new_mask != DIAG_CON_NONE) *req_mode = DIAG_MULTI_MODE; + if (new_mask == DIAG_CON_ALL) + *req_mode = DIAG_MEMORY_DEVICE_MODE; break; case DIAG_MEMORY_DEVICE_MODE: new_mask = (*peripheral_mask) | diag_mux->mux_mask; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 678e3a2b051c..4885412dd014 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1710,19 +1710,20 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) return -EINVAL; } + i = upd - UPD_WLAN; + if (driver->md_session_map[peripheral] && (MD_PERIPHERAL_MASK(peripheral) & - diag_mux->mux_mask)) { + diag_mux->mux_mask) && + !driver->pd_session_clear[i]) { DIAG_LOG(DIAG_DEBUG_USERSPACE, "diag_fr: User PD is already logging onto active peripheral logging\n"); - i = upd - UPD_WLAN; driver->pd_session_clear[i] = 0; return -EINVAL; } peripheral_mask = diag_translate_mask(param->pd_mask); param->peripheral_mask = peripheral_mask; - i = upd - UPD_WLAN; if (!driver->pd_session_clear[i]) { driver->pd_logging_mode[i] = 1; driver->num_pd_session += 1; diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index f876489e202d..f6027ae96833 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1003,8 +1003,11 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) } else { mutex_unlock(&driver->md_session_lock); if (MD_PERIPHERAL_MASK(reg_item->proc) & - driver->logging_mask) + driver->logging_mask) { + mutex_unlock(&driver->cmd_reg_mutex); diag_send_error_rsp(buf, len, pid); + return write_len; + } else write_len = diag_send_data(reg_item, buf, len); } diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c index 510a9803bd82..68f4afde0d0c 100644 --- a/drivers/clk/qcom/clk-cpu-osm.c +++ b/drivers/clk/qcom/clk-cpu-osm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2691,7 +2691,7 @@ static ssize_t debugfs_trace_method_get(struct file *file, char __user *buf, else if (c->trace_method == XOR_PACKET) len = snprintf(debug_buf, sizeof(debug_buf), "xor\n"); - rc = simple_read_from_buffer((void __user *) buf, len, ppos, + rc = simple_read_from_buffer((void __user *) buf, count, ppos, (void *) debug_buf, len); mutex_unlock(&debug_buf_mutex); diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 0c119ec5d97c..7d40f38092d4 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2014 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -562,6 +562,11 @@ int msm_atomic_commit(struct drm_device *dev, struct msm_commit *commit; int i, ret; + if (!priv || priv->shutdown_in_progress) { + DRM_ERROR("priv is null or shutdwon is in-progress\n"); + return -EINVAL; + } + SDE_ATRACE_BEGIN("atomic_commit"); ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) { diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 6f968e93d959..b57663013dcb 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -439,6 +439,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) struct msm_kms *kms; struct sde_dbg_power_ctrl dbg_power_ctrl = { NULL }; int ret, i; + struct sched_param param; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { @@ -532,7 +533,12 @@ static int msm_load(struct drm_device *dev, unsigned long flags) goto fail; } } - + /** + * this priority was found during empiric testing to have appropriate + * realtime scheduling to process display updates and interact with + * other real time and normal priority task + */ + param.sched_priority = 16; /* initialize commit thread structure */ for (i = 0; i < priv->num_crtcs; i++) { priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; @@ -543,6 +549,11 @@ static int msm_load(struct drm_device *dev, unsigned long flags) &priv->disp_thread[i].worker, "crtc_commit:%d", priv->disp_thread[i].crtc_id); + ret = sched_setscheduler(priv->disp_thread[i].thread, + SCHED_FIFO, ¶m); + if (ret) + pr_warn("display thread priority update failed: %d\n", + ret); if (IS_ERR(priv->disp_thread[i].thread)) { dev_err(dev->dev, "failed to create kthread\n"); @@ -2199,6 +2210,28 @@ static const struct platform_device_id msm_id[] = { { } }; +static void msm_pdev_shutdown(struct platform_device *pdev) +{ + struct drm_device *ddev = platform_get_drvdata(pdev); + struct msm_drm_private *priv = NULL; + + if (!ddev) { + DRM_ERROR("invalid drm device node\n"); + return; + } + + priv = ddev->dev_private; + if (!priv) { + DRM_ERROR("invalid msm drm private node\n"); + return; + } + + msm_lastclose(ddev); + + /* set this after lastclose to allow kickoff from lastclose */ + priv->shutdown_in_progress = true; +} + static const struct of_device_id dt_match[] = { { .compatible = "qcom,mdp" }, /* mdp4 */ { .compatible = "qcom,sde-kms" }, /* sde */ @@ -2209,6 +2242,7 @@ MODULE_DEVICE_TABLE(of, dt_match); static struct platform_driver msm_platform_driver = { .probe = msm_pdev_probe, .remove = msm_pdev_remove, + .shutdown = msm_pdev_shutdown, .driver = { .name = "msm_drm", .of_match_table = dt_match, diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index fb24b833082c..e0ac0582e791 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -375,6 +375,9 @@ struct msm_drm_private { /* list of clients waiting for events */ struct list_head client_event_list; + + /* update the flag when msm driver receives shutdown notification */ + bool shutdown_in_progress; }; struct msm_format { diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index cd3a710f8f27..74dea95d90de 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -46,6 +46,10 @@ struct msm_mmu_funcs { void (*destroy)(struct msm_mmu *mmu); void (*enable)(struct msm_mmu *mmu); void (*disable)(struct msm_mmu *mmu); + int (*early_splash_map)(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt, u32 flags); + void (*early_splash_unmap)(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt); int (*set_property)(struct msm_mmu *mmu, enum iommu_attr attr, void *data); }; diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index 4247243055b6..aefbe0988fe5 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -120,30 +120,19 @@ static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova, { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); - struct iommu_domain *domain; int ret; if (!client || !sgt) return -EINVAL; - if (iova != 0) { - if (!client->mmu_mapping || !client->mmu_mapping->domain) - return -EINVAL; - - domain = client->mmu_mapping->domain; - - return iommu_map_sg(domain, iova, sgt->sgl, - sgt->nents, flags); - } else { - if (priv) - ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, - sgt->nents, DMA_BIDIRECTIONAL, priv); - else - ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, - DMA_BIDIRECTIONAL); + if (priv) + ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, + sgt->nents, DMA_BIDIRECTIONAL, priv); + else + ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, + DMA_BIDIRECTIONAL); - return (ret != sgt->nents) ? -ENOMEM : 0; - } + return (ret != sgt->nents) ? -ENOMEM : 0; } static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, @@ -160,6 +149,47 @@ static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, DMA_BIDIRECTIONAL); } +static int msm_smmu_early_splash_map(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt, u32 flags) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + struct iommu_domain *domain; + + if (!client || !sgt) + return -EINVAL; + + if (!client->mmu_mapping || !client->mmu_mapping->domain) + return -EINVAL; + + domain = client->mmu_mapping->domain; + + return iommu_map_sg(domain, iova, sgt->sgl, sgt->nents, flags); +} + +static void msm_smmu_early_splash_unmap(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + struct iommu_domain *domain; + struct scatterlist *sg; + size_t len = 0; + int unmapped, i = 0; + + if (!client || !client->mmu_mapping || !client->mmu_mapping->domain) + return; + + domain = client->mmu_mapping->domain; + + for_each_sg(sgt->sgl, sg, sgt->nents, i) + len += sg->length; + + unmapped = iommu_unmap(domain, iova, len); + if (unmapped < len) + DRM_ERROR("could not unmap iova@%llx\n", iova); +} + static void msm_smmu_destroy(struct msm_mmu *mmu) { struct msm_smmu *smmu = to_msm_smmu(mmu); @@ -199,6 +229,8 @@ static const struct msm_mmu_funcs funcs = { .map = msm_smmu_map, .unmap = msm_smmu_unmap, .destroy = msm_smmu_destroy, + .early_splash_map = msm_smmu_early_splash_map, + .early_splash_unmap = msm_smmu_early_splash_unmap, .set_property = msm_smmu_set_property, }; diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c index 83c8982b2e00..4f7e688650de 100644 --- a/drivers/gpu/drm/msm/sde/sde_core_irq.c +++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c @@ -31,23 +31,35 @@ static void sde_core_irq_callback_handler(void *arg, int irq_idx) struct sde_irq *irq_obj = &sde_kms->irq_obj; struct sde_irq_callback *cb; unsigned long irq_flags; + bool cb_tbl_error = false; + int enable_counts = 0; pr_debug("irq_idx=%d\n", irq_idx); - if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) - SDE_ERROR("irq_idx=%d has no registered callback\n", irq_idx); + spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags); + if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) { + /* print error outside lock */ + cb_tbl_error = true; + enable_counts = atomic_read( + &sde_kms->irq_obj.enable_counts[irq_idx]); + } atomic_inc(&irq_obj->irq_counts[irq_idx]); /* * Perform registered function callback */ - spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags); list_for_each_entry(cb, &irq_obj->irq_cb_tbl[irq_idx], list) if (cb->func) cb->func(cb->arg, irq_idx); spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags); + if (cb_tbl_error) { + SDE_ERROR("irq has no registered callback, idx %d enables %d\n", + irq_idx, enable_counts); + SDE_EVT32_IRQ(irq_idx, enable_counts, SDE_EVTLOG_ERROR); + } + /* * Clear pending interrupt status in HW. * NOTE: sde_core_irq_callback_handler is protected by top-level diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 96ef909e14f4..ea3f138ee461 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -1441,43 +1441,67 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, goto end; } - /* - * enforce pipe priority restrictions + /* validate source split: * use pstates sorted by stage to check planes on same stage * we assume that all pipes are in source split so its valid to compare * without taking into account left/right mixer placement */ for (i = 1; i < cnt; i++) { struct plane_state *prv_pstate, *cur_pstate; - int32_t prv_x, cur_x, prv_id, cur_id; + struct sde_rect left_rect, right_rect; + int32_t left_pid, right_pid; + int32_t stage; prv_pstate = &pstates[i - 1]; cur_pstate = &pstates[i]; if (prv_pstate->stage != cur_pstate->stage) continue; - prv_x = prv_pstate->drm_pstate->crtc_x; - cur_x = cur_pstate->drm_pstate->crtc_x; - prv_id = prv_pstate->sde_pstate->base.plane->base.id; - cur_id = cur_pstate->sde_pstate->base.plane->base.id; + stage = cur_pstate->stage; - /* - * Planes are enumerated in pipe-priority order such that planes - * with lower drm_id must be left-most in a shared blend-stage - * when using source split. + left_pid = prv_pstate->sde_pstate->base.plane->base.id; + POPULATE_RECT(&left_rect, prv_pstate->drm_pstate->crtc_x, + prv_pstate->drm_pstate->crtc_y, + prv_pstate->drm_pstate->crtc_w, + prv_pstate->drm_pstate->crtc_h, false); + + right_pid = cur_pstate->sde_pstate->base.plane->base.id; + POPULATE_RECT(&right_rect, cur_pstate->drm_pstate->crtc_x, + cur_pstate->drm_pstate->crtc_y, + cur_pstate->drm_pstate->crtc_w, + cur_pstate->drm_pstate->crtc_h, false); + + if (right_rect.x < left_rect.x) { + swap(left_pid, right_pid); + swap(left_rect, right_rect); + } + + /** + * - planes are enumerated in pipe-priority order such that + * planes with lower drm_id must be left-most in a shared + * blend-stage when using source split. + * - planes in source split must be contiguous in width + * - planes in source split must have same dest yoff and height */ - if (cur_x > prv_x && cur_id < prv_id) { + if (right_pid < left_pid) { + SDE_ERROR( + "invalid src split cfg. priority mismatch. stage: %d left: %d right: %d\n", + stage, left_pid, right_pid); + rc = -EINVAL; + goto end; + } else if (right_rect.x != (left_rect.x + left_rect.w)) { SDE_ERROR( - "shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n", - cur_pstate->stage, cur_id, cur_x, - prv_id, prv_x); + "non-contiguous coordinates for src split. stage: %d left: %d - %d right: %d - %d\n", + stage, left_rect.x, left_rect.w, + right_rect.x, right_rect.w); rc = -EINVAL; goto end; - } else if (cur_x < prv_x && cur_id > prv_id) { + } else if ((left_rect.y != right_rect.y) || + (left_rect.h != right_rect.h)) { SDE_ERROR( - "shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n", - cur_pstate->stage, prv_id, prv_x, - cur_id, cur_x); + "source split at stage: %d. invalid yoff/height: l_y: %d r_y: %d l_h: %d r_h: %d\n", + stage, left_rect.y, right_rect.y, + left_rect.h, right_rect.h); rc = -EINVAL; goto end; } diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 6e4de62c6957..fa17768d9939 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-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -602,6 +602,12 @@ static void sde_encoder_underrun_callback(struct drm_encoder *drm_enc, SDE_ATRACE_BEGIN("encoder_underrun_callback"); atomic_inc(&phy_enc->underrun_cnt); SDE_EVT32(DRMID(drm_enc), atomic_read(&phy_enc->underrun_cnt)); + + trace_sde_encoder_underrun(DRMID(drm_enc), + atomic_read(&phy_enc->underrun_cnt)); + SDE_DBG_CTRL("stop_ftrace"); + SDE_DBG_CTRL("panic_underrun"); + SDE_ATRACE_END("encoder_underrun_callback"); } diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c index eeb7a0002eab..7864b9fef87b 100644 --- a/drivers/gpu/drm/msm/sde/sde_irq.c +++ b/drivers/gpu/drm/msm/sde/sde_irq.c @@ -19,6 +19,8 @@ #include "sde_irq.h" #include "sde_core_irq.h" +static uint32_t g_sde_irq_status; + irqreturn_t sde_irq(struct msm_kms *kms) { struct sde_kms *sde_kms = to_sde_kms(kms); @@ -27,6 +29,9 @@ irqreturn_t sde_irq(struct msm_kms *kms) sde_kms->hw_intr->ops.get_interrupt_sources(sde_kms->hw_intr, &interrupts); + /* store irq status in case of irq-storm debugging */ + g_sde_irq_status = interrupts; + /* * Taking care of MDP interrupt */ @@ -40,13 +45,30 @@ irqreturn_t sde_irq(struct msm_kms *kms) */ while (interrupts) { irq_hw_number_t hwirq = fls(interrupts) - 1; + unsigned int mapping; + int rc; + + mapping = irq_find_mapping(sde_kms->irq_controller.domain, + hwirq); + if (mapping == 0) { + SDE_EVT32(hwirq, SDE_EVTLOG_ERROR); + goto error; + } + + rc = generic_handle_irq(mapping); + if (rc < 0) { + SDE_EVT32(hwirq, mapping, rc, SDE_EVTLOG_ERROR); + goto error; + } - generic_handle_irq(irq_find_mapping( - sde_kms->irq_controller.domain, hwirq)); interrupts &= ~(1 << hwirq); } return IRQ_HANDLED; + +error: + /* bad situation, inform irq system, it may disable overall MDSS irq */ + return IRQ_NONE; } void sde_irq_preinstall(struct msm_kms *kms) diff --git a/drivers/gpu/drm/msm/sde/sde_splash.c b/drivers/gpu/drm/msm/sde/sde_splash.c index 19e6406600cd..2789ae053663 100644 --- a/drivers/gpu/drm/msm/sde/sde_splash.c +++ b/drivers/gpu/drm/msm/sde/sde_splash.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -301,8 +301,8 @@ static int _sde_splash_free_resource(struct msm_mmu *mmu, return -EINVAL; if (mmu->funcs && mmu->funcs->unmap) - mmu->funcs->unmap(mmu, sinfo->splash_mem_paddr[conn], - msm_obj->sgt, NULL); + mmu->funcs->early_splash_unmap(mmu, + sinfo->splash_mem_paddr[conn], msm_obj->sgt); _sde_splash_free_bootup_memory_to_system(sinfo->splash_mem_paddr[conn], sinfo->splash_mem_size[conn]); @@ -489,8 +489,9 @@ int sde_splash_smmu_map(struct drm_device *dev, struct msm_mmu *mmu, msm_obj = to_msm_bo(sinfo->obj[i]); if (mmu->funcs && mmu->funcs->map) { - ret = mmu->funcs->map(mmu, sinfo->splash_mem_paddr[i], - msm_obj->sgt, IOMMU_READ | IOMMU_NOEXEC, NULL); + ret = mmu->funcs->early_splash_map(mmu, + sinfo->splash_mem_paddr[i], msm_obj->sgt, + IOMMU_READ | IOMMU_NOEXEC); if (!ret) { SDE_ERROR("Map blk %d @%pK failed.\n", diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h index 2a4e6b59a08c..d28562eabccb 100644 --- a/drivers/gpu/drm/msm/sde/sde_trace.h +++ b/drivers/gpu/drm/msm/sde/sde_trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -125,6 +125,22 @@ TRACE_EVENT(sde_cmd_release_bw, TP_printk("crtc:%d", __entry->crtc_id) ); +TRACE_EVENT(sde_encoder_underrun, + TP_PROTO(u32 enc_id, u32 underrun_cnt), + TP_ARGS(enc_id, underrun_cnt), + TP_STRUCT__entry( + __field(u32, enc_id) + __field(u32, underrun_cnt) + ), + TP_fast_assign( + __entry->enc_id = enc_id; + __entry->underrun_cnt = underrun_cnt; + + ), + TP_printk("enc:%d underrun_cnt:%d", __entry->enc_id, + __entry->underrun_cnt) +); + TRACE_EVENT(sde_mark_write, TP_PROTO(int pid, const char *name, bool trace_begin), TP_ARGS(pid, name, trace_begin), diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c index ea133619cf62..c886950e5212 100644 --- a/drivers/gpu/drm/msm/sde_dbg.c +++ b/drivers/gpu/drm/msm/sde_dbg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -57,6 +57,9 @@ /* print debug ranges in groups of 4 u32s */ #define REG_DUMP_ALIGN 16 +#define DBG_CTRL_STOP_FTRACE BIT(0) +#define DBG_CTRL_PANIC_UNDERRUN BIT(1) +#define DBG_CTRL_MAX BIT(2) /** * struct sde_dbg_reg_offset - tracking for start and end of region @@ -162,6 +165,7 @@ struct sde_dbg_vbif_debug_bus { * @enable_reg_dump: whether to dump registers into memory, kernel log, or both * @dbgbus_sde: debug bus structure for the sde * @dbgbus_vbif_rt: debug bus structure for the realtime vbif + * @dump_all: dump all entries in register dump */ static struct sde_dbg_base { struct sde_dbg_evtlog *evtlog; @@ -180,6 +184,8 @@ static struct sde_dbg_base { struct sde_dbg_sde_debug_bus dbgbus_sde; struct sde_dbg_vbif_debug_bus dbgbus_vbif_rt; + bool dump_all; + u32 debugfs_ctrl; } sde_dbg_base; /* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */ @@ -1448,7 +1454,7 @@ static void _sde_dbg_dump_vbif_dbg_bus(struct sde_dbg_vbif_debug_bus *bus) */ static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[], u32 len, bool do_panic, const char *name, bool dump_dbgbus_sde, - bool dump_dbgbus_vbif_rt) + bool dump_dbgbus_vbif_rt, bool dump_all) { int i; @@ -1460,7 +1466,8 @@ static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[], sde_dbg_base.enable_reg_dump); } - sde_evtlog_dump_all(sde_dbg_base.evtlog); + if (dump_all) + sde_evtlog_dump_all(sde_dbg_base.evtlog); if (dump_dbgbus_sde) _sde_dbg_dump_sde_dbg_bus(&sde_dbg_base.dbgbus_sde); @@ -1484,7 +1491,8 @@ static void _sde_dump_work(struct work_struct *work) ARRAY_SIZE(sde_dbg_base.req_dump_blks), sde_dbg_base.work_panic, "evtlog_workitem", sde_dbg_base.dbgbus_sde.cmn.include_in_deferred_work, - sde_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work); + sde_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work, + sde_dbg_base.dump_all); } void sde_dbg_dump(bool queue_work, const char *name, ...) @@ -1493,6 +1501,7 @@ void sde_dbg_dump(bool queue_work, const char *name, ...) bool do_panic = false; bool dump_dbgbus_sde = false; bool dump_dbgbus_vbif_rt = false; + bool dump_all = false; va_list args; char *blk_name = NULL; struct sde_dbg_reg_base *blk_base = NULL; @@ -1510,6 +1519,7 @@ void sde_dbg_dump(bool queue_work, const char *name, ...) memset(sde_dbg_base.req_dump_blks, 0, sizeof(sde_dbg_base.req_dump_blks)); + sde_dbg_base.dump_all = false; va_start(args, name); i = 0; @@ -1531,6 +1541,8 @@ void sde_dbg_dump(bool queue_work, const char *name, ...) blk_name); } } + if (!strcmp(blk_name, "all")) + dump_all = true; if (!strcmp(blk_name, "dbg_bus")) dump_dbgbus_sde = true; @@ -1550,11 +1562,51 @@ void sde_dbg_dump(bool queue_work, const char *name, ...) dump_dbgbus_sde; sde_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work = dump_dbgbus_vbif_rt; + sde_dbg_base.dump_all = dump_all; schedule_work(&sde_dbg_base.dump_work); } else { _sde_dump_array(blk_arr, blk_len, do_panic, name, - dump_dbgbus_sde, dump_dbgbus_vbif_rt); + dump_dbgbus_sde, dump_dbgbus_vbif_rt, dump_all); + } +} + +void sde_dbg_ctrl(const char *name, ...) +{ + int i = 0; + va_list args; + char *blk_name = NULL; + + + /* no debugfs controlled events are enabled, just return */ + if (!sde_dbg_base.debugfs_ctrl) + return; + + va_start(args, name); + + while ((blk_name = va_arg(args, char*))) { + if (i++ >= SDE_EVTLOG_MAX_DATA) { + pr_err("could not parse all dbg arguments\n"); + break; + } + + if (IS_ERR_OR_NULL(blk_name)) + break; + + if (!strcmp(blk_name, "stop_ftrace") && + sde_dbg_base.debugfs_ctrl & + DBG_CTRL_STOP_FTRACE) { + pr_debug("tracing off\n"); + tracing_off(); + } + + if (!strcmp(blk_name, "panic_underrun") && + sde_dbg_base.debugfs_ctrl & + DBG_CTRL_PANIC_UNDERRUN) { + pr_debug("panic underrun\n"); + panic("underrun"); + } } + } /* @@ -1564,6 +1616,9 @@ void sde_dbg_dump(bool queue_work, const char *name, ...) */ static int sde_dbg_debugfs_open(struct inode *inode, struct file *file) { + if (!inode || !file) + return -EINVAL; + /* non-seekable */ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); file->private_data = inode->i_private; @@ -1583,8 +1638,11 @@ static ssize_t sde_evtlog_dump_read(struct file *file, char __user *buff, ssize_t len = 0; char evtlog_buf[SDE_EVTLOG_BUF_MAX]; + if (!buff || !ppos) + return -EINVAL; + len = sde_evtlog_dump_to_buffer(sde_dbg_base.evtlog, evtlog_buf, - SDE_EVTLOG_BUF_MAX); + SDE_EVTLOG_BUF_MAX, true); if (copy_to_user(buff, evtlog_buf, len)) return -EFAULT; *ppos += len; @@ -1621,6 +1679,82 @@ static const struct file_operations sde_evtlog_fops = { .write = sde_evtlog_dump_write, }; +/** + * sde_dbg_ctrl_read - debugfs read handler for debug ctrl read + * @file: file handler + * @buff: user buffer content for debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_dbg_ctrl_read(struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + ssize_t len = 0; + char buf[24] = {'\0'}; + + if (!buff || !ppos) + return -EINVAL; + + if (*ppos) + return 0; /* the end */ + + len = snprintf(buf, sizeof(buf), "0x%x\n", sde_dbg_base.debugfs_ctrl); + pr_debug("%s: ctrl:0x%x len:0x%zx\n", + __func__, sde_dbg_base.debugfs_ctrl, len); + + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) { + pr_err("error copying the buffer! count:0x%zx\n", count); + return -EFAULT; + } + + *ppos += len; /* increase offset */ + return len; +} + +/** + * sde_dbg_ctrl_write - debugfs read handler for debug ctrl write + * @file: file handler + * @user_buf: user buffer content from debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_dbg_ctrl_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + u32 dbg_ctrl = 0; + char buf[24]; + + if (!file) { + pr_err("DbgDbg: %s: error no file --\n", __func__); + return -EINVAL; + } + + if (count >= sizeof(buf)) + return -EFAULT; + + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (kstrtouint(buf, 0, &dbg_ctrl)) { + pr_err("%s: error in the number of bytes\n", __func__); + return -EFAULT; + } + + pr_debug("dbg_ctrl_read:0x%x\n", dbg_ctrl); + sde_dbg_base.debugfs_ctrl = dbg_ctrl; + + return count; +} + +static const struct file_operations sde_dbg_ctrl_fops = { + .open = sde_dbg_debugfs_open, + .read = sde_dbg_ctrl_read, + .write = sde_dbg_ctrl_write, +}; + void sde_dbg_init_dbg_buses(u32 hwversion) { static struct sde_dbg_base *dbg = &sde_dbg_base; @@ -1695,6 +1829,8 @@ int sde_dbg_init(struct dentry *debugfs_root, struct device *dev, for (i = 0; i < SDE_EVTLOG_ENTRY; i++) sde_dbg_base.evtlog->logs[i].counter = i; + debugfs_create_file("dbg_ctrl", 0600, sde_dbg_base.root, NULL, + &sde_dbg_ctrl_fops); debugfs_create_file("dump", 0600, sde_dbg_base.root, NULL, &sde_evtlog_fops); debugfs_create_u32("enable", 0600, sde_dbg_base.root, @@ -1736,7 +1872,14 @@ void sde_dbg_destroy(void) */ static int sde_dbg_reg_base_release(struct inode *inode, struct file *file) { - struct sde_dbg_reg_base *dbg = file->private_data; + struct sde_dbg_reg_base *dbg; + + if (!file) + return -EINVAL; + + dbg = file->private_data; + if (!dbg) + return -ENODEV; mutex_lock(&sde_dbg_base.mutex); if (dbg && dbg->buf) { @@ -1760,12 +1903,16 @@ static int sde_dbg_reg_base_release(struct inode *inode, struct file *file) static ssize_t sde_dbg_reg_base_offset_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct sde_dbg_reg_base *dbg = file->private_data; + struct sde_dbg_reg_base *dbg; u32 off = 0; u32 cnt = DEFAULT_BASE_REG_CNT; char buf[24]; ssize_t rc = count; + if (!file) + return -EINVAL; + + dbg = file->private_data; if (!dbg) return -ENODEV; @@ -1799,6 +1946,9 @@ static ssize_t sde_dbg_reg_base_offset_write(struct file *file, goto exit; } + if (cnt == 0) + return -EINVAL; + dbg->off = off; dbg->cnt = cnt; @@ -1819,17 +1969,29 @@ exit: static ssize_t sde_dbg_reg_base_offset_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { - struct sde_dbg_reg_base *dbg = file->private_data; + struct sde_dbg_reg_base *dbg; int len = 0; char buf[24] = {'\0'}; + if (!file) + return -EINVAL; + + dbg = file->private_data; if (!dbg) return -ENODEV; + if (!ppos) + return -EINVAL; + if (*ppos) return 0; /* the end */ mutex_lock(&sde_dbg_base.mutex); + if (dbg->off % sizeof(u32)) { + mutex_unlock(&sde_dbg_base.mutex); + return -EFAULT; + } + len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt); if (len < 0 || len >= sizeof(buf)) { mutex_unlock(&sde_dbg_base.mutex); @@ -1857,11 +2019,15 @@ static ssize_t sde_dbg_reg_base_offset_read(struct file *file, static ssize_t sde_dbg_reg_base_reg_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct sde_dbg_reg_base *dbg = file->private_data; + struct sde_dbg_reg_base *dbg; size_t off; u32 data, cnt; char buf[24]; + if (!file) + return -EINVAL; + + dbg = file->private_data; if (!dbg) return -ENODEV; @@ -1907,14 +2073,21 @@ static ssize_t sde_dbg_reg_base_reg_write(struct file *file, static ssize_t sde_dbg_reg_base_reg_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct sde_dbg_reg_base *dbg = file->private_data; + struct sde_dbg_reg_base *dbg; size_t len; + if (!file) + return -EINVAL; + + dbg = file->private_data; if (!dbg) { pr_err("invalid handle\n"); return -ENODEV; } + if (!ppos) + return -EINVAL; + mutex_lock(&sde_dbg_base.mutex); if (!dbg->buf) { char *hwbuf; diff --git a/drivers/gpu/drm/msm/sde_dbg.h b/drivers/gpu/drm/msm/sde_dbg.h index 74fd4c94b490..ce36cba08039 100644 --- a/drivers/gpu/drm/msm/sde_dbg.h +++ b/drivers/gpu/drm/msm/sde_dbg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,9 +17,10 @@ #include <linux/debugfs.h> #include <linux/list.h> -#define SDE_EVTLOG_DATA_LIMITER (-1) +#define SDE_EVTLOG_DATA_LIMITER (0xC0DEBEEF) #define SDE_EVTLOG_FUNC_ENTRY 0x1111 #define SDE_EVTLOG_FUNC_EXIT 0x2222 +#define SDE_EVTLOG_ERROR 0xebad #define SDE_DBG_DUMP_DATA_LIMITER (NULL) @@ -52,7 +53,7 @@ enum sde_dbg_dump_flag { * number must be greater than print entry to prevent out of bound evtlog * entry array access. */ -#define SDE_EVTLOG_ENTRY (SDE_EVTLOG_PRINT_ENTRY * 4) +#define SDE_EVTLOG_ENTRY (SDE_EVTLOG_PRINT_ENTRY * 8) #define SDE_EVTLOG_MAX_DATA 15 #define SDE_EVTLOG_BUF_MAX 512 #define SDE_EVTLOG_BUF_ALIGN 32 @@ -77,6 +78,7 @@ struct sde_dbg_evtlog { struct sde_dbg_evtlog_log logs[SDE_EVTLOG_ENTRY]; u32 first; u32 last; + u32 last_dump; u32 curr; u32 next; u32 enable; @@ -123,6 +125,13 @@ extern struct sde_dbg_evtlog *sde_dbg_base_evtlog; #define SDE_DBG_DUMP_WQ(...) sde_dbg_dump(true, __func__, ##__VA_ARGS__, \ SDE_DBG_DUMP_DATA_LIMITER) +/** + * SDE_DBG_EVT_CTRL - trigger a different driver events + * event: event that trigger different behavior in the driver + */ +#define SDE_DBG_CTRL(...) sde_dbg_ctrl(__func__, ##__VA_ARGS__, \ + SDE_DBG_DUMP_DATA_LIMITER) + #if defined(CONFIG_DEBUG_FS) /** @@ -172,10 +181,12 @@ bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, u32 flag); * @evtlog: pointer to evtlog * @evtlog_buf: target buffer to print into * @evtlog_buf_size: size of target buffer + * @update_last_entry:ยป whether or not to stop at most recent entry * Returns: number of bytes written to buffer */ ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, - char *evtlog_buf, ssize_t evtlog_buf_size); + char *evtlog_buf, ssize_t evtlog_buf_size, + bool update_last_entry); /** * sde_dbg_init_dbg_buses - initialize debug bus dumping support for the chipset @@ -214,6 +225,15 @@ void sde_dbg_destroy(void); void sde_dbg_dump(bool queue_work, const char *name, ...); /** + * sde_dbg_ctrl - trigger specific actions for the driver with debugging + * purposes. Those actions need to be enabled by the debugfs entry + * so the driver executes those actions in the corresponding calls. + * @va_args: list of actions to trigger + * Returns: none + */ +void sde_dbg_ctrl(const char *name, ...); + +/** * sde_dbg_reg_register_base - register a hw register address section for later * dumping. call this before calling sde_dbg_reg_register_dump_range * to be able to specify sub-ranges within the base hw range. @@ -272,7 +292,8 @@ static inline bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, } static inline ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, - char *evtlog_buf, ssize_t evtlog_buf_size) + char *evtlog_buf, ssize_t evtlog_buf_size, + bool update_last_entry) { return 0; } @@ -295,6 +316,10 @@ static inline void sde_dbg_dump(bool queue_work, const char *name, ...) { } +static inline void sde_dbg_ctrl(const char *name, ...) +{ +} + static inline int sde_dbg_reg_register_base(const char *name, void __iomem *base, size_t max_offset) { diff --git a/drivers/gpu/drm/msm/sde_dbg_evtlog.c b/drivers/gpu/drm/msm/sde_dbg_evtlog.c index 759bdab48840..70ba127ceb08 100644 --- a/drivers/gpu/drm/msm/sde_dbg_evtlog.c +++ b/drivers/gpu/drm/msm/sde_dbg_evtlog.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -75,7 +75,8 @@ void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line, } /* always dump the last entries which are not dumped yet */ -static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog) +static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog, + bool update_last_entry) { bool need_dump = true; unsigned long flags; @@ -87,21 +88,26 @@ static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog) evtlog->first = evtlog->next; - if (evtlog->last == evtlog->first) { + if (update_last_entry) + evtlog->last_dump = evtlog->last; + + if (evtlog->last_dump == evtlog->first) { need_dump = false; goto dump_exit; } - if (evtlog->last < evtlog->first) { + if (evtlog->last_dump < evtlog->first) { evtlog->first %= SDE_EVTLOG_ENTRY; - if (evtlog->last < evtlog->first) - evtlog->last += SDE_EVTLOG_ENTRY; + if (evtlog->last_dump < evtlog->first) + evtlog->last_dump += SDE_EVTLOG_ENTRY; } - if ((evtlog->last - evtlog->first) > SDE_EVTLOG_PRINT_ENTRY) { - pr_warn("evtlog buffer overflow before dump: %d\n", - evtlog->last - evtlog->first); - evtlog->first = evtlog->last - SDE_EVTLOG_PRINT_ENTRY; + if ((evtlog->last_dump - evtlog->first) > SDE_EVTLOG_PRINT_ENTRY) { + pr_info("evtlog skipping %d entries, last=%d\n", + evtlog->last_dump - evtlog->first - + SDE_EVTLOG_PRINT_ENTRY, + evtlog->last_dump - 1); + evtlog->first = evtlog->last_dump - SDE_EVTLOG_PRINT_ENTRY; } evtlog->next = evtlog->first + 1; @@ -112,7 +118,8 @@ dump_exit: } ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, - char *evtlog_buf, ssize_t evtlog_buf_size) + char *evtlog_buf, ssize_t evtlog_buf_size, + bool update_last_entry) { int i; ssize_t off = 0; @@ -123,7 +130,7 @@ ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, return 0; /* update markers, exit if nothing to print */ - if (!_sde_evtlog_dump_calc_range(evtlog)) + if (!_sde_evtlog_dump_calc_range(evtlog, update_last_entry)) return 0; spin_lock_irqsave(&evtlog->spin_lock, flags); @@ -159,12 +166,16 @@ ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, void sde_evtlog_dump_all(struct sde_dbg_evtlog *evtlog) { char buf[SDE_EVTLOG_BUF_MAX]; + bool update_last_entry = true; if (!evtlog) return; - while (sde_evtlog_dump_to_buffer(evtlog, buf, sizeof(buf))) + while (sde_evtlog_dump_to_buffer(evtlog, buf, sizeof(buf), + update_last_entry)) { pr_info("%s", buf); + update_last_entry = false; + } } struct sde_dbg_evtlog *sde_evtlog_init(void) diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index 4ec04001ae7e..bc3f794555a5 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -300,6 +300,22 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .busy_mask = 0xFFFFFFFE, }, { + .gpurev = ADRENO_REV_A509, + .core = 5, + .major = 0, + .minor = 9, + .patchid = ANY_ID, + .features = ADRENO_PREEMPTION | ADRENO_64BIT | + ADRENO_CONTENT_PROTECTION | ADRENO_CPZ_RETENTION, + .pm4fw_name = "a530_pm4.fw", + .pfpfw_name = "a530_pfp.fw", + .zap_name = "a512_zap", + .gpudev = &adreno_a5xx_gpudev, + .gmem_size = (SZ_256K + SZ_16K), + .num_protected_regs = 0x20, + .busy_mask = 0xFFFFFFFE, + }, + { .gpurev = ADRENO_REV_A508, .core = 5, .major = 0, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 305163147c1a..9ea50007ec38 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -170,6 +170,7 @@ enum adreno_gpurev { ADRENO_REV_A505 = 505, ADRENO_REV_A506 = 506, ADRENO_REV_A508 = 508, + ADRENO_REV_A509 = 509, ADRENO_REV_A510 = 510, ADRENO_REV_A512 = 512, ADRENO_REV_A530 = 530, @@ -1007,6 +1008,7 @@ static inline int adreno_is_a5xx(struct adreno_device *adreno_dev) ADRENO_TARGET(a505, ADRENO_REV_A505) ADRENO_TARGET(a506, ADRENO_REV_A506) ADRENO_TARGET(a508, ADRENO_REV_A508) +ADRENO_TARGET(a509, ADRENO_REV_A509) ADRENO_TARGET(a510, ADRENO_REV_A510) ADRENO_TARGET(a512, ADRENO_REV_A512) ADRENO_TARGET(a530, ADRENO_REV_A530) diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index cd8cb7837911..119741f7ce47 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -59,6 +59,7 @@ static const struct adreno_vbif_platform a5xx_vbif_platforms[] = { { adreno_is_a530, a530_vbif }, { adreno_is_a512, a540_vbif }, { adreno_is_a510, a530_vbif }, + { adreno_is_a509, a540_vbif }, { adreno_is_a508, a530_vbif }, { adreno_is_a505, a530_vbif }, { adreno_is_a506, a530_vbif }, @@ -161,6 +162,7 @@ static const struct { { adreno_is_a530, a530_efuse_speed_bin }, { adreno_is_a505, a530_efuse_speed_bin }, { adreno_is_a512, a530_efuse_speed_bin }, + { adreno_is_a509, a530_efuse_speed_bin }, { adreno_is_a508, a530_efuse_speed_bin }, }; @@ -201,7 +203,8 @@ static void a5xx_platform_setup(struct adreno_device *adreno_dev) gpudev->vbif_xin_halt_ctrl0_mask = A510_VBIF_XIN_HALT_CTRL0_MASK; } else if (adreno_is_a540(adreno_dev) || - adreno_is_a512(adreno_dev)) { + adreno_is_a512(adreno_dev) || + adreno_is_a509(adreno_dev)) { gpudev->snapshot_data->sect_sizes->cp_merciu = 1024; } @@ -539,7 +542,8 @@ static void a5xx_regulator_disable(struct adreno_device *adreno_dev) unsigned int reg; struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - if (adreno_is_a512(adreno_dev) || adreno_is_a508(adreno_dev)) + if (adreno_is_a512(adreno_dev) || adreno_is_a509(adreno_dev) || + adreno_is_a508(adreno_dev)) return; /* If feature is not supported or not enabled */ @@ -1199,6 +1203,7 @@ static const struct { { adreno_is_a540, a540_hwcg_regs, ARRAY_SIZE(a540_hwcg_regs) }, { adreno_is_a530, a530_hwcg_regs, ARRAY_SIZE(a530_hwcg_regs) }, { adreno_is_a512, a512_hwcg_regs, ARRAY_SIZE(a512_hwcg_regs) }, + { adreno_is_a509, a512_hwcg_regs, ARRAY_SIZE(a512_hwcg_regs) }, { adreno_is_a510, a510_hwcg_regs, ARRAY_SIZE(a510_hwcg_regs) }, { adreno_is_a505, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) }, { adreno_is_a506, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) }, @@ -1651,7 +1656,7 @@ static void a5xx_clk_set_options(struct adreno_device *adreno_dev, { if (!adreno_is_a540(adreno_dev) && !adreno_is_a512(adreno_dev) && - !adreno_is_a508(adreno_dev)) + !adreno_is_a508(adreno_dev) && !adreno_is_a509(adreno_dev)) return; /* Handle clock settings for GFX PSCBCs */ @@ -1957,7 +1962,8 @@ static void a5xx_start(struct adreno_device *adreno_dev) kgsl_regwrite(device, A5XX_CP_MERCIU_SIZE, 0x20); kgsl_regwrite(device, A5XX_CP_ROQ_THRESHOLDS_2, 0x40000030); kgsl_regwrite(device, A5XX_CP_ROQ_THRESHOLDS_1, 0x20100D0A); - } else if (adreno_is_a540(adreno_dev) || adreno_is_a512(adreno_dev)) { + } else if (adreno_is_a540(adreno_dev) || adreno_is_a512(adreno_dev) || + adreno_is_a509(adreno_dev)) { kgsl_regwrite(device, A5XX_CP_MEQ_THRESHOLDS, 0x40); kgsl_regwrite(device, A5XX_CP_MERCIU_SIZE, 0x400); kgsl_regwrite(device, A5XX_CP_ROQ_THRESHOLDS_2, 0x80000060); @@ -1976,7 +1982,8 @@ static void a5xx_start(struct adreno_device *adreno_dev) if (adreno_is_a505_or_a506(adreno_dev) || adreno_is_a508(adreno_dev)) kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL, (0x100 << 11 | 0x100 << 22)); - else if (adreno_is_a510(adreno_dev) || adreno_is_a512(adreno_dev)) + else if (adreno_is_a510(adreno_dev) || adreno_is_a512(adreno_dev) || + adreno_is_a509(adreno_dev)) kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL, (0x200 << 11 | 0x200 << 22)); else @@ -2069,7 +2076,8 @@ static void a5xx_start(struct adreno_device *adreno_dev) kgsl_regwrite(device, A5XX_TPL1_MODE_CNTL, bit << 7); kgsl_regwrite(device, A5XX_RB_MODE_CNTL, bit << 1); if (adreno_is_a540(adreno_dev) || - adreno_is_a512(adreno_dev)) + adreno_is_a512(adreno_dev) || + adreno_is_a509(adreno_dev)) kgsl_regwrite(device, A5XX_UCHE_DBG_ECO_CNTL_2, bit); } diff --git a/drivers/media/i2c/adv7481.c b/drivers/media/i2c/adv7481.c index 7cac0a8abd81..aa9dcc67c66c 100644 --- a/drivers/media/i2c/adv7481.c +++ b/drivers/media/i2c/adv7481.c @@ -1998,7 +1998,7 @@ static int adv7481_get_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; fmt->width = 720; - fmt->height = 576; + fmt->height = 507; break; default: return -EINVAL; diff --git a/drivers/media/platform/msm/ais/isp/msm_isp.h b/drivers/media/platform/msm/ais/isp/msm_isp.h index 419615cc9b4a..856bf55f8c29 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp.h +++ b/drivers/media/platform/msm/ais/isp/msm_isp.h @@ -782,6 +782,7 @@ struct vfe_device { uint32_t is_split; uint32_t dual_vfe_enable; unsigned long page_fault_addr; + bool clk_enabled; /* Debug variables */ int dump_reg; diff --git a/drivers/media/platform/msm/ais/isp/msm_isp47.c b/drivers/media/platform/msm/ais/isp/msm_isp47.c index 6ca91b4fcf83..52bf8121f32b 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp47.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp47.c @@ -1038,16 +1038,18 @@ int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev, vfe_dev->buf_mgr, fe_cfg->session_id, fe_cfg->stream_id); vfe_dev->fetch_engine_info.bufq_handle = bufq_handle; - + mutex_lock(&vfe_dev->buf_mgr->lock); rc = vfe_dev->buf_mgr->ops->get_buf_by_index( vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf); if (rc < 0 || !buf) { pr_err("%s: No fetch buffer rc= %d buf= %pK\n", __func__, rc, buf); + mutex_unlock(&vfe_dev->buf_mgr->lock); return -EINVAL; } mapped_info = buf->mapped_info[0]; buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED; + mutex_unlock(&vfe_dev->buf_mgr->lock); } else { rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr, &mapped_info, fe_cfg->fd); @@ -1100,14 +1102,15 @@ int msm_vfe47_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev, mutex_lock(&vfe_dev->buf_mgr->lock); rc = vfe_dev->buf_mgr->ops->get_buf_by_index( vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf); - mutex_unlock(&vfe_dev->buf_mgr->lock); if (rc < 0 || !buf) { pr_err("%s: No fetch buffer rc= %d buf= %pK\n", __func__, rc, buf); + mutex_unlock(&vfe_dev->buf_mgr->lock); return -EINVAL; } mapped_info = buf->mapped_info[0]; buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED; + mutex_unlock(&vfe_dev->buf_mgr->lock); } else { rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr, &mapped_info, fe_cfg->fd); @@ -2423,9 +2426,30 @@ void msm_vfe47_put_clks(struct vfe_device *vfe_dev) int msm_vfe47_enable_clks(struct vfe_device *vfe_dev, int enable) { - return msm_camera_clk_enable(&vfe_dev->pdev->dev, + unsigned long flags; + int rc; + + if (!enable) { + spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); + vfe_dev->clk_enabled = false; + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + } + + rc = msm_camera_clk_enable(&vfe_dev->pdev->dev, vfe_dev->vfe_clk_info, vfe_dev->vfe_clk, vfe_dev->num_clk, enable); + if (rc < 0) { + pr_err("%s: clk set %d failed %d\n", __func__, enable, rc); + return rc; + } + + if (enable) { + spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); + vfe_dev->clk_enabled = true; + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + } + + return rc; } int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate) diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c index c0a36843d7ff..22820a0b8e79 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c @@ -3822,10 +3822,12 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) &update_cmd->update_info[i]; stream_info = &axi_data->stream_info[HANDLE_TO_IDX( update_info->stream_handle)]; + mutex_lock(&vfe_dev->buf_mgr->lock); rc = msm_isp_request_frame(vfe_dev, stream_info, update_info->user_stream_id, update_info->frame_id, MSM_ISP_INVALID_BUF_INDEX); + mutex_unlock(&vfe_dev->buf_mgr->lock); if (rc) pr_err("%s failed to request frame!\n", __func__); @@ -3898,10 +3900,12 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) stream_info = &axi_data->stream_info[HANDLE_TO_IDX( req_frm->stream_handle)]; + mutex_lock(&vfe_dev->buf_mgr->lock); rc = msm_isp_request_frame(vfe_dev, stream_info, req_frm->user_stream_id, req_frm->frame_id, req_frm->buf_index); + mutex_unlock(&vfe_dev->buf_mgr->lock); if (rc) pr_err("%s failed to request frame!\n", __func__); diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_util.c b/drivers/media/platform/msm/ais/isp/msm_isp_util.c index 5ca3b8d531a2..3cacb5b0db10 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp_util.c @@ -392,9 +392,10 @@ static int msm_isp_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 1); msm_isp_reset_framedrop(vfe_dev, stream_info); - + mutex_lock(&vfe_dev->buf_mgr->lock); rc = msm_isp_cfg_offline_ping_pong_address(vfe_dev, stream_info, VFE_PING_FLAG, fe_cfg->output_buf_idx); + mutex_unlock(&vfe_dev->buf_mgr->lock); if (rc < 0) { pr_err("%s: Fetch engine config failed\n", __func__); return -EINVAL; @@ -851,6 +852,7 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, { long rc = 0; long rc2 = 0; + unsigned long flags; struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); if (!vfe_dev || !vfe_dev->vfe_base) { @@ -917,7 +919,9 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, break; case VIDIOC_MSM_ISP_CFG_STREAM: mutex_lock(&vfe_dev->core_mutex); + mutex_lock(&vfe_dev->buf_mgr->lock); rc = msm_isp_cfg_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->buf_mgr->lock); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_CFG_HW_STATE: @@ -947,6 +951,7 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, break; case VIDIOC_MSM_ISP_AXI_RESTART: mutex_lock(&vfe_dev->core_mutex); + mutex_lock(&vfe_dev->buf_mgr->lock); if (atomic_read(&vfe_dev->error_info.overflow_state) != HALT_ENFORCED) { rc = msm_isp_stats_restart(vfe_dev); @@ -957,6 +962,7 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, pr_err_ratelimited("%s: no AXI restart, halt enforced.\n", __func__); } + mutex_unlock(&vfe_dev->buf_mgr->lock); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_INPUT_CFG: @@ -1016,7 +1022,9 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, break; case VIDIOC_MSM_ISP_CFG_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); + mutex_lock(&vfe_dev->buf_mgr->lock); rc = msm_isp_cfg_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->buf_mgr->lock); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_UPDATE_STATS_STREAM: @@ -1061,6 +1069,11 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, while (vfe_dev->vfe_open_cnt != 0) msm_isp_close_node(sd, NULL); break; + case VIDIOC_MSM_ISP_SET_CLK_STATUS: + spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); + vfe_dev->clk_enabled = *((unsigned int *)arg); + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + break; default: pr_err_ratelimited("%s: Invalid ISP command %d\n", __func__, @@ -2113,11 +2126,21 @@ void msm_isp_do_tasklet(unsigned long data) } atomic_sub(1, &vfe_dev->irq_cnt); list_del(&queue_cmd->list); + + if (!vfe_dev->clk_enabled) { + /* client closed, delayed task should exit directly */ + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + return; + } + queue_cmd->cmd_used = 0; irq_status0 = queue_cmd->vfeInterruptStatus0; irq_status1 = queue_cmd->vfeInterruptStatus1; pingpong_status = queue_cmd->vfePingPongStatus; ts = queue_cmd->ts; + /* related to rw reg, need to be protected */ + irq_ops->process_halt_irq(vfe_dev, + irq_status0, irq_status1); spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); ISP_DBG("%s: vfe_id %d status0: 0x%x status1: 0x%x\n", __func__, vfe_dev->pdev->id, irq_status0, irq_status1); @@ -2141,8 +2164,6 @@ void msm_isp_do_tasklet(unsigned long data) } irq_ops->process_reset_irq(vfe_dev, irq_status0, irq_status1); - irq_ops->process_halt_irq(vfe_dev, - irq_status0, irq_status1); if (atomic_read(&vfe_dev->error_info.overflow_state) != NO_OVERFLOW) { ISP_DBG("%s: Recovery in processing, Ignore IRQs!!!\n", 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 7079044526b2..fa116b180682 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 @@ -3722,13 +3722,6 @@ static int msm_isp_stream_axi_cfg_update(struct vfe_device *vfe_dev, unsigned long flags; int vfe_idx; - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[ - SRC_TO_INTF(stream_info->stream_src)])) { - pr_err("%s: Update in progress for vfe %d intf %d\n", - __func__, vfe_dev->pdev->id, - SRC_TO_INTF(stream_info->stream_src)); - return -EINVAL; - } spin_lock_irqsave(&stream_info->lock, flags); if (stream_info->state != ACTIVE) { spin_unlock_irqrestore(&stream_info->lock, flags); diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c index f760481026db..1a067a4ece4d 100644 --- a/drivers/net/wireless/ath/ath10k/testmode.c +++ b/drivers/net/wireless/ath/ath10k/testmode.c @@ -137,6 +137,13 @@ static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[]) return ret; } + ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION, + ar->normal_mode_fw.fw_file.wmi_op_version); + if (ret) { + kfree_skb(skb); + return ret; + } + return cfg80211_testmode_reply(skb); } diff --git a/drivers/net/wireless/ath/ath10k/testmode_i.h b/drivers/net/wireless/ath/ath10k/testmode_i.h index ba81bf66ce85..191a8f34c8ea 100644 --- a/drivers/net/wireless/ath/ath10k/testmode_i.h +++ b/drivers/net/wireless/ath/ath10k/testmode_i.h @@ -33,6 +33,7 @@ enum ath10k_tm_attr { ATH10K_TM_ATTR_WMI_CMDID = 3, ATH10K_TM_ATTR_VERSION_MAJOR = 4, ATH10K_TM_ATTR_VERSION_MINOR = 5, + ATH10K_TM_ATTR_WMI_OP_VERSION = 6, /* keep last */ __ATH10K_TM_ATTR_AFTER_LAST, diff --git a/drivers/power/qcom/lpm-stats.c b/drivers/power/qcom/lpm-stats.c index 90458d6a7212..46056255e5c0 100644 --- a/drivers/power/qcom/lpm-stats.c +++ b/drivers/power/qcom/lpm-stats.c @@ -682,9 +682,10 @@ static void cleanup_stats(struct lpm_stats *stats) { struct list_head *centry = NULL; struct lpm_stats *pos = NULL; + struct lpm_stats *n = NULL; centry = &stats->child; - list_for_each_entry_reverse(pos, centry, sibling) { + list_for_each_entry_safe_reverse(pos, n, centry, sibling) { if (!list_empty(&pos->child)) { cleanup_stats(pos); continue; diff --git a/drivers/regulator/kryo-regulator.c b/drivers/regulator/kryo-regulator.c index fd853e7323bb..d403ee43d924 100644 --- a/drivers/regulator/kryo-regulator.c +++ b/drivers/regulator/kryo-regulator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -311,7 +311,6 @@ done: static int kryo_regulator_disable(struct regulator_dev *rdev) { struct kryo_regulator *kvreg = rdev_get_drvdata(rdev); - int rc; unsigned long flags; if (kvreg->vreg_en == false) @@ -322,7 +321,7 @@ static int kryo_regulator_disable(struct regulator_dev *rdev) kvreg_debug(kvreg, "disabled\n"); spin_unlock_irqrestore(&kvreg->slock, flags); - return rc; + return 0; } static int kryo_regulator_is_enabled(struct regulator_dev *rdev) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 105d861a2325..aaddf2fff99c 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -2596,7 +2596,7 @@ bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host, int ufs_qcom_testbus_config(struct ufs_qcom_host *host) { int reg = 0; - int offset, ret = 0, testbus_sel_offset = 19; + int offset = 0, ret = 0, testbus_sel_offset = 19; u32 mask = TEST_BUS_SUB_SEL_MASK; unsigned long flags; struct ufs_hba *hba; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 10021f25afdd..6d43254d84b9 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -635,6 +635,7 @@ static void __ufshcd_cmd_log(struct ufs_hba *hba, char *str, char *cmd_type, entry.str = str; entry.lba = lba; + entry.cmd_id = cmd_id; entry.transfer_len = transfer_len; entry.doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); entry.tag = tag; diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c index 5ca94579b6f1..4136f2995046 100644 --- a/drivers/soc/qcom/hab/hab.c +++ b/drivers/soc/qcom/hab/hab.c @@ -47,6 +47,8 @@ static struct hab_device hab_devices[] = { HAB_DEVICE_CNSTR(DEVICE_QCPE4_NAME, MM_QCPE_VM4, 17), HAB_DEVICE_CNSTR(DEVICE_CLK1_NAME, MM_CLK_VM1, 18), HAB_DEVICE_CNSTR(DEVICE_CLK2_NAME, MM_CLK_VM2, 19), + HAB_DEVICE_CNSTR(DEVICE_FDE1_NAME, MM_FDE_1, 20), + HAB_DEVICE_CNSTR(DEVICE_BUFFERQ1_NAME, MM_BUFFERQ_1, 21), }; struct hab_driver hab_driver = { @@ -624,7 +626,24 @@ static void hab_generate_pchan(struct local_vmid *settings, int i, int j) HABCFG_GET_BE(settings, i, j)); } break; - + case MM_FDE_START/100: + for (k = MM_FDE_START + 1; k < MM_FDE_END; k++) { + ret += hab_initialize_pchan_entry( + find_hab_device(k), + settings->self, + HABCFG_GET_VMID(settings, i), + HABCFG_GET_BE(settings, i, j)); + } + break; + case MM_BUFFERQ_START/100: + for (k = MM_BUFFERQ_START + 1; k < MM_BUFFERQ_END; k++) { + ret += hab_initialize_pchan_entry( + find_hab_device(k), + settings->self, + HABCFG_GET_VMID(settings, i), + HABCFG_GET_BE(settings, i, j)); + } + break; default: pr_err("failed to find mmid %d, i %d, j %d\n", HABCFG_GET_MMID(settings, i, j), i, j); diff --git a/drivers/soc/qcom/hab/hab.h b/drivers/soc/qcom/hab/hab.h index d94467e6bc76..f13d6f44b929 100644 --- a/drivers/soc/qcom/hab/hab.h +++ b/drivers/soc/qcom/hab/hab.h @@ -81,6 +81,8 @@ enum hab_payload_type { #define DEVICE_QCPE4_NAME "hab_qcpe_vm4" #define DEVICE_CLK1_NAME "hab_clock_vm1" #define DEVICE_CLK2_NAME "hab_clock_vm2" +#define DEVICE_FDE1_NAME "hab_fde1" +#define DEVICE_BUFFERQ1_NAME "hab_bufferq1" /* make sure concascaded name is less than this value */ #define MAX_VMID_NAME_SIZE 30 diff --git a/drivers/soc/qcom/hab/hab_qvm.c b/drivers/soc/qcom/hab/hab_qvm.c index 280eb3148337..9aa41320a33f 100644 --- a/drivers/soc/qcom/hab/hab_qvm.c +++ b/drivers/soc/qcom/hab/hab_qvm.c @@ -52,7 +52,8 @@ static struct shmem_irq_config pchan_factory_settings[] = { {0x1b011000, 24}, {0x1b012000, 25}, {0x1b013000, 26}, - + {0x1b014000, 27}, + {0x1b015000, 28}, }; static struct qvm_plugin_info { diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index fc89a2ea772e..d357a616b05e 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -2643,6 +2643,7 @@ int mdp3_ctrl_init(struct msm_fb_data_type *mfd) mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff; mdp3_interface->lut_update = NULL; mdp3_interface->configure_panel = mdp3_update_panel_info; + mdp3_interface->signal_retire_fence = NULL; mdp3_session = kzalloc(sizeof(struct mdp3_session_data), GFP_KERNEL); if (!mdp3_session) { diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index d35858137191..6c4db0f1f5bd 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -3743,8 +3743,11 @@ skip_commit: if (IS_ERR_VALUE(ret) || !sync_pt_data->flushed) { mdss_fb_release_kickoff(mfd); mdss_fb_signal_timeline(sync_pt_data); - } + if ((mfd->panel.type == MIPI_CMD_PANEL) && + (mfd->mdp.signal_retire_fence)) + mfd->mdp.signal_retire_fence(mfd, 1); + } if (dynamic_dsi_switch) { MDSS_XLOG(mfd->index, mfd->split_mode, new_dsi_mode, XLOG_FUNC_EXIT); @@ -4658,6 +4661,7 @@ static int mdss_fb_atomic_commit_ioctl(struct fb_info *info, struct mdp_destination_scaler_data *ds_data = NULL; struct mdp_destination_scaler_data __user *ds_data_user; struct msm_fb_data_type *mfd; + struct mdss_overlay_private *mdp5_data = NULL; ret = copy_from_user(&commit, argp, sizeof(struct mdp_layer_commit)); if (ret) { @@ -4669,9 +4673,20 @@ static int mdss_fb_atomic_commit_ioctl(struct fb_info *info, if (!mfd) return -EINVAL; + mdp5_data = mfd_to_mdp5_data(mfd); + if (mfd->panel_info->panel_dead) { pr_debug("early commit return\n"); MDSS_XLOG(mfd->panel_info->panel_dead); + /* + * In case of an ESD attack, since we early return from the + * commits, we need to signal the outstanding fences. + */ + mdss_fb_release_fences(mfd); + if ((mfd->panel.type == MIPI_CMD_PANEL) && + mfd->mdp.signal_retire_fence && mdp5_data) + mfd->mdp.signal_retire_fence(mfd, + mdp5_data->retire_cnt); return 0; } diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 6e52390c2886..301c1386a639 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -234,6 +234,8 @@ struct msm_mdp_interface { int (*input_event_handler)(struct msm_fb_data_type *mfd); void (*footswitch_ctrl)(bool on); int (*pp_release_fnc)(struct msm_fb_data_type *mfd); + void (*signal_retire_fence)(struct msm_fb_data_type *mfd, + int retire_cnt); void *private1; }; diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 747b4e3e2f81..2c92a480af6b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -406,7 +406,7 @@ static void mdss_mdp_cmd_wait4_autorefresh_pp(struct mdss_mdp_ctl *ctl) return; } - if (line_out < ctl->mixer_left->roi.h) { + if ((line_out < ctl->mixer_left->roi.h) && (line_out)) { reinit_completion(&ctx->autorefresh_ppdone); /* enable ping pong done */ @@ -2510,6 +2510,7 @@ int mdss_mdp_cmd_set_autorefresh_mode(struct mdss_mdp_ctl *mctl, int frame_cnt) */ ctx->autorefresh_state = MDP_AUTOREFRESH_ON_REQUESTED; ctx->autorefresh_frame_cnt = frame_cnt; + mctl->mdata->serialize_wait4pp = true; /* Cancel GATE Work Item */ if (cancel_work_sync(&ctx->gate_clk_work)) @@ -2523,8 +2524,10 @@ int mdss_mdp_cmd_set_autorefresh_mode(struct mdss_mdp_ctl *mctl, int frame_cnt) if (frame_cnt == 0) { ctx->autorefresh_state = MDP_AUTOREFRESH_OFF; ctx->autorefresh_frame_cnt = 0; + mctl->mdata->serialize_wait4pp = false; } else { ctx->autorefresh_frame_cnt = frame_cnt; + mctl->mdata->serialize_wait4pp = true; } break; case MDP_AUTOREFRESH_ON: @@ -2536,6 +2539,7 @@ int mdss_mdp_cmd_set_autorefresh_mode(struct mdss_mdp_ctl *mctl, int frame_cnt) ctx->autorefresh_state = MDP_AUTOREFRESH_OFF_REQUESTED; } else { ctx->autorefresh_frame_cnt = frame_cnt; + mctl->mdata->serialize_wait4pp = true; } break; case MDP_AUTOREFRESH_OFF_REQUESTED: @@ -2545,6 +2549,7 @@ int mdss_mdp_cmd_set_autorefresh_mode(struct mdss_mdp_ctl *mctl, int frame_cnt) pr_debug("cancelling autorefresh off request\n"); ctx->autorefresh_state = MDP_AUTOREFRESH_ON; ctx->autorefresh_frame_cnt = frame_cnt; + mctl->mdata->serialize_wait4pp = true; } break; default: @@ -2873,6 +2878,7 @@ static int mdss_mdp_disable_autorefresh(struct mdss_mdp_ctl *ctl, cfg |= BIT(20); mdss_mdp_pingpong_write(pp_base, MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg); + ctl->mdata->serialize_wait4pp = false; return 0; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 791c73baa9e7..f3984201fbc5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -6140,6 +6140,9 @@ static void __vsync_retire_signal(struct msm_fb_data_type *mfd, int val) sw_sync_timeline_inc(mdp5_data->vsync_timeline, val); mdp5_data->retire_cnt -= min(val, mdp5_data->retire_cnt); + pr_debug("Retire signaled! timeline val=%d remaining=%d\n", + mdp5_data->vsync_timeline->value, + mdp5_data->retire_cnt); if (mdp5_data->retire_cnt == 0) { mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); mdp5_data->ctl->ops.remove_vsync_handler(mdp5_data->ctl, @@ -6361,6 +6364,13 @@ void mdss_mdp_footswitch_ctrl_handler(bool on) mdss_mdp_footswitch_ctrl(mdata, on); } +static void mdss_mdp_signal_retire_fence(struct msm_fb_data_type *mfd, + int retire_cnt) +{ + __vsync_retire_signal(mfd, retire_cnt); + pr_debug("Signaled (%d) pending retire fence\n", retire_cnt); +} + int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) { struct device *dev = mfd->fbi->dev; @@ -6402,6 +6412,7 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) mdp5_interface->splash_init_fnc = mdss_mdp_splash_init; mdp5_interface->configure_panel = mdss_mdp_update_panel_info; mdp5_interface->input_event_handler = mdss_mdp_input_event_handler; + mdp5_interface->signal_retire_fence = mdss_mdp_signal_retire_fence; /* * Register footswitch control only for primary fb pm diff --git a/include/uapi/linux/habmm.h b/include/uapi/linux/habmm.h index 59b603a0fcf7..8586048e20c0 100644 --- a/include/uapi/linux/habmm.h +++ b/include/uapi/linux/habmm.h @@ -109,7 +109,15 @@ struct hab_unimport { #define MM_CLK_VM2 802 #define MM_CLK_END 803 -#define MM_ID_MAX 804 +#define MM_FDE_START 900 +#define MM_FDE_1 901 +#define MM_FDE_END 902 + +#define MM_BUFFERQ_START 1000 +#define MM_BUFFERQ_1 1001 +#define MM_BUFFERQ_END 1002 + +#define MM_ID_MAX 1003 #define HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_SINGLE_FE 0x00000000 #define HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_SINGLE_DOMU 0x00000001 diff --git a/include/uapi/media/ais/msm_ais_isp.h b/include/uapi/media/ais/msm_ais_isp.h index f323d3bf7baf..55bc5290ce28 100644 --- a/include/uapi/media/ais/msm_ais_isp.h +++ b/include/uapi/media/ais/msm_ais_isp.h @@ -973,6 +973,8 @@ enum msm_isp_ioctl_cmd_code { MSM_ISP_AXI_OUTPUT_CFG, MSM_ISP_START, MSM_ISP_STOP, + + MSM_ISP_SET_CLK_STATUS, }; @@ -1104,5 +1106,8 @@ enum msm_isp_ioctl_cmd_code { _IOWR('V', MSM_ISP_CAMIF_CFG, \ struct msm_vfe_camif_cfg) +#define VIDIOC_MSM_ISP_SET_CLK_STATUS \ + _IOWR('V', MSM_ISP_SET_CLK_STATUS, \ + unsigned int) #endif /* __UAPI_MSM_AIS_ISP__ */ diff --git a/sound/soc/msm/sdm660-common.c b/sound/soc/msm/sdm660-common.c index 90b661dff7ec..271697747dd2 100644 --- a/sound/soc/msm/sdm660-common.c +++ b/sound/soc/msm/sdm660-common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2552,11 +2552,9 @@ void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream) mutex_lock(&mi2s_intf_conf[index].lock); if (--mi2s_intf_conf[index].ref_cnt == 0) { ret = msm_mi2s_set_sclk(substream, false); - if (ret < 0) { + if (ret < 0) pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n", __func__, index, ret); - mi2s_intf_conf[index].ref_cnt++; - } if (mi2s_intf_conf[index].msm_is_ext_mclk) { mi2s_mclk[index].enable = 0; pr_debug("%s: Disabling mclk, clk_freq_in_hz = %u\n", |
