diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h index 46f2ae646544..81394936b249 100644 --- a/drivers/gpu/msm/a6xx_reg.h +++ b/drivers/gpu/msm/a6xx_reg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _A6XX_REG_H @@ -394,6 +394,7 @@ #define A6XX_RBBM_ISDB_CNT 0x533 #define A6XX_RBBM_NC_MODE_CNTL 0X534 +#define A6XX_RBBM_SNAPSHOT_STATUS 0x535 #define A6XX_RBBM_SECVID_TRUST_CNTL 0xF400 #define A6XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO 0xF800 diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c index 85eda2115e88..c93590aac48c 100644 --- a/drivers/gpu/msm/adreno_a6xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "adreno.h" @@ -805,6 +805,22 @@ static void a6xx_snapshot_shader(struct kgsl_device *device, } } +static void a650_snapshot_mempool(struct kgsl_device *device, + struct kgsl_snapshot *snapshot) +{ + u32 val; + + /* set CP_CHICKEN_DBG[StabilizeMVC] to stabilize it while dumping */ + kgsl_regread(device, A6XX_CP_CHICKEN_DBG, &val); + kgsl_regwrite(device, A6XX_CP_CHICKEN_DBG, val | BIT(2)); + + kgsl_snapshot_indexed_registers(device, snapshot, + A6XX_CP_MEM_POOL_DBG_ADDR, A6XX_CP_MEM_POOL_DBG_DATA, + 0, 0x2100); + + kgsl_regwrite(device, A6XX_CP_CHICKEN_DBG, val); +} + static void a6xx_snapshot_mempool(struct kgsl_device *device, struct kgsl_snapshot *snapshot) { @@ -817,7 +833,7 @@ static void a6xx_snapshot_mempool(struct kgsl_device *device, kgsl_snapshot_indexed_registers(device, snapshot, A6XX_CP_MEM_POOL_DBG_ADDR, A6XX_CP_MEM_POOL_DBG_DATA, - 0, 0x2060); + 0, 0x2100); /* * Data at offset 0x2000 in the mempool section is the mempool size. @@ -1765,7 +1781,7 @@ void a6xx_snapshot(struct adreno_device *adreno_dev, struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_ringbuffer *rb; bool sptprac_on; - unsigned int i, roq_size, ucode_dbg_size; + unsigned int i, roq_size; /* GMU TCM data dumped through AHB */ gmu_core_dev_snapshot(device, snapshot); @@ -1814,6 +1830,10 @@ void a6xx_snapshot(struct adreno_device *adreno_dev, if (!gmu_core_dev_gx_is_on(device)) return; + /* Assert the isStatic bit before triggering snapshot */ + if (adreno_is_a660(adreno_dev)) + kgsl_regwrite(device, A6XX_RBBM_SNAPSHOT_STATUS, 0x1); + /* Dump the registers which get affected by crash dumper trigger */ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, a6xx_snapshot_pre_crashdump_regs, NULL); @@ -1846,13 +1866,10 @@ void a6xx_snapshot(struct adreno_device *adreno_dev, A6XX_CP_DRAW_STATE_ADDR, A6XX_CP_DRAW_STATE_DATA, 0, 0x100); - ucode_dbg_size = adreno_is_a650_family(adreno_dev) - ? 0x7000 : 0x6000; - /* SQE_UCODE Cache */ kgsl_snapshot_indexed_registers(device, snapshot, A6XX_CP_SQE_UCODE_DBG_ADDR, A6XX_CP_SQE_UCODE_DBG_DATA, - 0, ucode_dbg_size); + 0, 0x8000); /* * CP ROQ dump units is 4dwords. The number of units is stored @@ -1869,7 +1886,10 @@ void a6xx_snapshot(struct adreno_device *adreno_dev, snapshot, a6xx_snapshot_sqe, NULL); /* Mempool debug data */ - a6xx_snapshot_mempool(device, snapshot); + if (adreno_is_a650_family(adreno_dev)) + a650_snapshot_mempool(device, snapshot); + else + a6xx_snapshot_mempool(device, snapshot); if (sptprac_on) { /* Shader memory */ @@ -1882,6 +1902,18 @@ void a6xx_snapshot(struct adreno_device *adreno_dev, a6xx_snapshot_dbgahb_regs(device, snapshot); } + if (adreno_is_a660(adreno_dev)) { + u32 val; + + kgsl_regread(device, A6XX_RBBM_SNAPSHOT_STATUS, &val); + + if (!val) + dev_err(device->dev, + "Interface signals may have changed during snapshot\n"); + + kgsl_regwrite(device, A6XX_RBBM_SNAPSHOT_STATUS, 0x0); + } + /* Preemption record */ if (adreno_is_preemption_enabled(adreno_dev)) { FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { diff --git a/drivers/gpu/msm/kgsl_bus.c b/drivers/gpu/msm/kgsl_bus.c index 106961e5604c..8d0aafbc7d77 100644 --- a/drivers/gpu/msm/kgsl_bus.c +++ b/drivers/gpu/msm/kgsl_bus.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #include @@ -147,15 +147,28 @@ u32 *kgsl_bus_get_table(struct platform_device *pdev, int kgsl_bus_init(struct kgsl_device *device, struct platform_device *pdev) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; - int ret, count; + int count; + int ddr = of_fdt_get_ddrtype(); + if (ddr >= 0) { + char str[32]; + + snprintf(str, sizeof(str), "qcom,bus-table-ddr%d", ddr); + + pwr->ddr_table = kgsl_bus_get_table(pdev, str, &count); + if (!IS_ERR(pwr->ddr_table)) + goto done; + } + + /* Look if a generic table is present */ pwr->ddr_table = kgsl_bus_get_table(pdev, "qcom,bus-table-ddr", &count); if (IS_ERR(pwr->ddr_table)) { - ret = PTR_ERR(pwr->ddr_table); + int ret = PTR_ERR(pwr->ddr_table); + pwr->ddr_table = NULL; return ret; } - +done: pwr->ddr_table_count = count; validate_pwrlevels(device, pwr->ddr_table, pwr->ddr_table_count); diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index edf880a1c237..d3961bf1b067 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -1390,8 +1390,6 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node) gmu->num_gpupwrlevels = pwr->num_pwrlevels + 1; - gmu->icc_path = of_icc_get(&gmu->pdev->dev, NULL); - /* Populates RPMh configurations */ ret = gmu_rpmh_init(device, gmu); if (ret) @@ -1572,7 +1570,7 @@ static int gmu_start(struct kgsl_device *device) /* Vote for minimal DDR BW for GMU to init */ level = pwr->pwrlevels[pwr->default_pwrlevel].bus_min; - icc_set_bw(gmu->icc_path, 0, + icc_set_bw(pwr->icc_path, 0, MBps_to_icc(pwr->ddr_table[level])); ret = gmu_dev_ops->rpmh_gpu_pwrctrl(device, GMU_FW_START, @@ -1650,6 +1648,7 @@ static void gmu_stop(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; int ret = 0; if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags)) @@ -1676,7 +1675,7 @@ static void gmu_stop(struct kgsl_device *device) gmu_disable_clks(device); gmu_disable_gdsc(gmu); - icc_set_bw(gmu->icc_path, 0, 0); + icc_set_bw(pwr->icc_path, 0, 0); return; error: @@ -1710,8 +1709,6 @@ static void gmu_remove(struct kgsl_device *device) clear_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); - icc_put(gmu->icc_path); - if (gmu->fw_image) { release_firmware(gmu->fw_image); gmu->fw_image = NULL; diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 73b82e4aee08..312f7d5256d5 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef __KGSL_GMU_H #define __KGSL_GMU_H @@ -210,8 +210,6 @@ struct gmu_device { unsigned long kmem_bitmap; const struct gmu_vma_entry *vma; unsigned int log_wptr_retention; - /** @icc_path: Interconnect path for the GMU */ - struct icc_path *icc_path; }; struct gmu_memdesc *gmu_get_memdesc(struct gmu_device *gmu, diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 211b22e9ae31..adee3f6063e6 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -567,6 +567,26 @@ iommu_context_by_name(struct kgsl_iommu *iommu, u32 name) return &iommu->user_context; } +static int kgsl_iommu_lpac_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long addr, int flags, void *token) +{ + struct kgsl_pagetable *pt = token; + struct kgsl_mmu *mmu = pt->mmu; + struct kgsl_device *device = KGSL_MMU_DEVICE(mmu); + struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); + struct kgsl_iommu_context *ctx = &iommu->lpac_context; + u32 fsynr0, fsynr1; + + fsynr0 = KGSL_IOMMU_GET_CTX_REG(ctx, FSYNR0); + fsynr1 = KGSL_IOMMU_GET_CTX_REG(ctx, FSYNR1); + + dev_crit(device->dev, + "LPAC PAGE FAULT iova=0x%16lx, fsynr0=0x%x, fsynr1=0x%x\n", + addr, fsynr0, fsynr1); + + return 0; +} + static int kgsl_iommu_fault_handler(struct iommu_domain *domain, struct device *dev, unsigned long addr, int flags, void *token) { @@ -1011,11 +1031,7 @@ static int _init_global_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) struct kgsl_device *device = KGSL_MMU_DEVICE(mmu); int ret = 0; struct kgsl_iommu_pt *iommu_pt = NULL; - unsigned int mmu_idr1; - unsigned int mmu_pagesize; - unsigned int mmu_npages; unsigned int cb_num; - unsigned int cb0_offset; struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); struct kgsl_iommu_context *ctx = &iommu->user_context; @@ -1029,8 +1045,8 @@ static int _init_global_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) DOMAIN_ATTR_PROCID, &pt->name); if (ret) { dev_err(device->dev, - "set DOMAIN_ATTR_PROCID failed: %d\n", - ret); + "%s: set DOMAIN_ATTR_PROCID failed: %d\n", + ctx->name, ret); goto done; } } @@ -1048,8 +1064,8 @@ static int _init_global_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) DOMAIN_ATTR_CONTEXT_BANK, &cb_num); if (ret) { dev_err(device->dev, - "get DOMAIN_ATTR_CONTEXT_BANK failed: %d\n", - ret); + "%s: get DOMAIN_ATTR_CONTEXT_BANK failed: %d\n", + ctx->name, ret); goto done; } @@ -1061,28 +1077,21 @@ static int _init_global_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) } ctx->cb_num = cb_num; - mmu_idr1 = readl_relaxed(iommu->regbase + KGSL_IOMMU_IDR1_OFFSET); - mmu_pagesize = FIELD_GET(IDR1_PAGESIZE, mmu_idr1) ? SZ_64K : SZ_4K; - - /* - * The number of pages in the global address space or translation - * bank address space is 2^(NUMPAGENDXB + 1). - */ - mmu_npages = 1 << (FIELD_GET(IDR1_NUMPAGENDXB, mmu_idr1) + 1); - cb0_offset = mmu_pagesize * mmu_npages; - ctx->regbase = iommu->regbase + cb0_offset + (cb_num * mmu_pagesize); + ctx->regbase = iommu->regbase + iommu->cb0_offset + + (cb_num * iommu->pagesize); ret = iommu_domain_get_attr(iommu_pt->domain, DOMAIN_ATTR_TTBR0, &iommu_pt->ttbr0); if (ret) { - dev_err(device->dev, "get DOMAIN_ATTR_TTBR0 failed: %d\n", ret); + dev_err(device->dev, "%s: get DOMAIN_ATTR_TTBR0 failed: %d\n", + ctx->name, ret); goto done; } ret = iommu_domain_get_attr(iommu_pt->domain, DOMAIN_ATTR_CONTEXTIDR, &iommu_pt->contextidr); if (ret) { - dev_err(device->dev, "get DOMAIN_ATTR_CONTEXTIDR failed: %d\n", - ret); + dev_err(device->dev, "%s: get DOMAIN_ATTR_CONTEXTIDR failed: %d\n", + ctx->name, ret); goto done; } @@ -1095,6 +1104,61 @@ done: return ret; } +static int _init_global_lpac_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) +{ + struct kgsl_device *device = KGSL_MMU_DEVICE(mmu); + int ret = 0; + struct kgsl_iommu_pt *iommu_pt = NULL; + unsigned int cb_num; + struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); + struct kgsl_iommu_context *ctx = &iommu->lpac_context; + + iommu_pt = _alloc_pt(&ctx->pdev->dev, mmu, pt); + + if (IS_ERR(iommu_pt)) + return PTR_ERR(iommu_pt); + + _enable_gpuhtw_llc(mmu, iommu_pt); + + ret = _attach_pt(iommu_pt, ctx); + if (ret) + goto done; + + iommu_set_fault_handler(iommu_pt->domain, + kgsl_iommu_lpac_fault_handler, pt); + + /* Try to get the ID of the context bank */ + ret = iommu_domain_get_attr(iommu_pt->domain, DOMAIN_ATTR_CONTEXT_BANK, + &cb_num); + + /* + * If this returns -ENODEV then we can't figure out what the current + * context bank is. This isn't fatal, but it does limit our ability to + * debug in a pagefault. + */ + if (ret) { + if (ret != -ENODEV) { + dev_err(device->dev, + "%s: Unable to get DOMAIN_ATTR_CONTEXT_BANK: %d\n", + ctx->name, ret); + goto done; + } + + } + + ctx->cb_num = cb_num; + ctx->regbase = iommu->regbase + iommu->cb0_offset + + (cb_num * iommu->pagesize); + + kgsl_iommu_map_globals(mmu, pt); + +done: + if (ret) + _free_pt(ctx, pt); + + return ret; +} + #if IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) static int _init_secure_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) { @@ -1231,6 +1295,9 @@ static int kgsl_iommu_init_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) case KGSL_MMU_SECURE_PT: return _init_secure_pt(mmu, pt); + case KGSL_MMU_GLOBAL_LPAC_PT: + return _init_global_lpac_pt(mmu, pt); + default: return _init_per_process_pt(mmu, pt); } @@ -1422,6 +1489,43 @@ static int _setup_user_context(struct kgsl_mmu *mmu) return 0; } +static int _setup_lpac_context(struct kgsl_mmu *mmu) +{ + int ret = 0; + struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); + struct kgsl_iommu_context *ctx = &iommu->lpac_context; + struct kgsl_iommu_pt *iommu_pt = NULL; + + /* If there was no lpac device node, then we don't need to set it up */ + if (!ctx->pdev) + return 0; + + if (mmu->lpac_pagetable == NULL) { + mmu->lpac_pagetable = kgsl_mmu_getpagetable(mmu, + KGSL_MMU_GLOBAL_LPAC_PT); + /* if we don't have a default pagetable, nothing will work */ + if (IS_ERR(mmu->lpac_pagetable)) { + ret = PTR_ERR(mmu->lpac_pagetable); + mmu->lpac_pagetable = NULL; + return ret; + } else if (mmu->lpac_pagetable == NULL) { + return -ENOMEM; + } + } + + iommu_pt = mmu->lpac_pagetable->priv; + if (iommu_pt == NULL) + return -ENODEV; + + ret = _attach_pt(iommu_pt, ctx); + if (ret) + return ret; + + ctx->default_pt = mmu->lpac_pagetable; + + return 0; +} + static int _setup_secure_context(struct kgsl_mmu *mmu) { int ret; @@ -1450,11 +1554,37 @@ static int _setup_secure_context(struct kgsl_mmu *mmu) static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt); +static void get_cb0_offset(struct kgsl_mmu *mmu) +{ + struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); + u32 mmu_idr1, mmu_npages; + + if (iommu->cb0_offset) + return; + + kgsl_mmu_enable_clk(mmu); + + mmu_idr1 = readl_relaxed(iommu->regbase + KGSL_IOMMU_IDR1_OFFSET); + + kgsl_mmu_disable_clk(mmu); + + iommu->pagesize = FIELD_GET(IDR1_PAGESIZE, mmu_idr1) ? SZ_64K : SZ_4K; + + /* + * The number of pages in the global address space or translation + * bank address space is 2^(NUMPAGENDXB + 1). + */ + mmu_npages = 1 << (FIELD_GET(IDR1_NUMPAGENDXB, mmu_idr1) + 1); + iommu->cb0_offset = iommu->pagesize * mmu_npages; +} + static int kgsl_iommu_start(struct kgsl_mmu *mmu) { int status; struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); + get_cb0_offset(mmu); + /* Set the following registers only when the MMU type is QSMMU */ if (mmu->subtype != KGSL_IOMMU_SMMU_V500) { /* Enable hazard check from GPU_SMMU_HUM_CFG */ @@ -1471,9 +1601,16 @@ static int kgsl_iommu_start(struct kgsl_mmu *mmu) if (status) return status; + status = _setup_lpac_context(mmu); + if (status) { + _detach_context(&iommu->user_context); + return status; + } + status = _setup_secure_context(mmu); if (status) { _detach_context(&iommu->user_context); + _detach_context(&iommu->lpac_context); return status; } @@ -2430,6 +2567,10 @@ static int _kgsl_iommu_probe(struct kgsl_device *device, platform_device_put(pdev); } + /* Probe "lpac" context bank if the platform demands it */ + if (!ret) + kgsl_iommu_probe_child(device, node, + &iommu->lpac_context, "gfx3d_lpac"); return ret; } diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h index 645525a9eee0..c20b051f6a84 100644 --- a/drivers/gpu/msm/kgsl_iommu.h +++ b/drivers/gpu/msm/kgsl_iommu.h @@ -110,6 +110,8 @@ struct kgsl_iommu { struct kgsl_iommu_context user_context; /** @secure_context: Container for the secure iommu context */ struct kgsl_iommu_context secure_context; + /** @lpac_context: Container for the LPAC iommu context */ + struct kgsl_iommu_context lpac_context; void __iomem *regbase; unsigned long regstart; unsigned int regsize; @@ -125,6 +127,10 @@ struct kgsl_iommu { * be mapped in all contexts */ bool ppt_active; + /** @cb0_offset: Offset of context bank 0 from iommu register base */ + u32 cb0_offset; + /** @pagesize: Size of each context bank register space */ + u32 pagesize; }; /* diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 3a77ad98e569..04d3878c6899 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -16,6 +16,7 @@ */ #define KGSL_MMU_GLOBAL_PT 0 #define KGSL_MMU_SECURE_PT 1 +#define KGSL_MMU_GLOBAL_LPAC_PT 2 #define MMU_DEFAULT_TTBR0(_d) \ (kgsl_mmu_pagetable_get_ttbr0((_d)->mmu.defaultpagetable)) @@ -144,6 +145,8 @@ struct kgsl_mmu { enum kgsl_mmutype type; u32 subtype; struct kgsl_pagetable *defaultpagetable; + /** @lpac_pagetable: Default lpac pagetable object for the MMU */ + struct kgsl_pagetable *lpac_pagetable; struct kgsl_pagetable *securepagetable; const struct kgsl_mmu_ops *mmu_ops; bool secured;