Merge tag 'LA.UM.10.3.c25-02100-sdm845.0' of https://git.codelinaro.org/clo/la/kernel/msm-4.9 into android13-4.9-sdm845

"LA.UM.10.3.c25-02100-sdm845.0"

* tag 'LA.UM.10.3.c25-02100-sdm845.0' of https://git.codelinaro.org/clo/la/kernel/msm-4.9:
  soc: qcom: smem: Add boundary checks for partitions
  msm: kgsl: Update the protect register list
  msm: kgsl: Do not release dma and anon buffers if unmap fails
  msm: kgsl: Do not free sharedmem if it cannot be unmapped
  msm: ADSPRPC: Restrict untrusted applications from attaching to GuestOS
  msm: kgsl: Use dma_buf_get() to get dma_buf structure
  pinctrl: qcom: Using readl_relaxed/writel_relaxed APIs
  msm: adsprpc: Handle UAF in fastrpc internal munmap
  iommu: Fix missing return check of arm_lpae_init_pte
  bus: mhi: misc: Add check for dev_rp if it is iommu range or not
  net: ipc_router: Add bounds check on tx path
  msm: kgsl: Remove 'fd' dependency to get dma_buf handle
  msm: kgsl: Keep postamble packets in a privileged buffer
  msm: kgsl: Make sure that pool pages don't have any extra references
  msm: kgsl: Prevent wrap around during user address mapping

 Conflicts:
	drivers/char/adsprpc.c
	drivers/gpu/msm/kgsl.c
	drivers/gpu/msm/kgsl_iommu.c
	drivers/gpu/msm/kgsl_mmu.c
	drivers/pinctrl/qcom/pinctrl-msm.c

Change-Id: I431924199616b135e180fd3a6421bb5037bcf164
This commit is contained in:
Michael Bestas 2024-04-20 00:36:50 +03:00
commit 262ef91bdf
No known key found for this signature in database
GPG key ID: CC95044519BE6669
9 changed files with 178 additions and 181 deletions

View file

@ -759,6 +759,12 @@ int mhi_send_cmd(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
enum MHI_CMD cmd);
int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl);
static inline bool is_valid_ring_ptr(struct mhi_ring *ring, dma_addr_t addr)
{
return ((addr >= ring->iommu_base &&
addr < ring->iommu_base + ring->len) && (addr % 16 == 0));
}
/* queue transfer buffer */
int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
void *buf, void *cb, size_t buf_len, enum MHI_FLAGS flags);

View file

@ -1337,6 +1337,13 @@ int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl,
return -EIO;
}
if (!is_valid_ring_ptr(ev_ring, er_ctxt->rp)) {
MHI_ERR(
"Event ring rp points outside of the event ring or unalign rp %llx\n",
er_ctxt->rp);
return 0;
}
dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp);
local_rp = ev_ring->rp;
@ -1425,6 +1432,14 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl,
}
spin_lock_bh(&mhi_event->lock);
if (!is_valid_ring_ptr(ev_ring, er_ctxt->rp)) {
MHI_ERR(
"Event ring rp points outside of the event ring or unalign rp %llx\n",
er_ctxt->rp);
spin_unlock_bh(&mhi_event->lock);
return 0;
}
dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp);
if (ev_ring->rp == dev_rp) {

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2002,2007-2018,2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. 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
@ -2015,17 +2015,6 @@ static int _adreno_start(struct adreno_device *adreno_dev)
}
}
if (kgsl_gmu_isenabled(device) && adreno_dev->perfctr_ifpc_lo == 0) {
ret = adreno_perfcounter_get(adreno_dev,
KGSL_PERFCOUNTER_GROUP_GPMU_PWR, 4,
&adreno_dev->perfctr_ifpc_lo, NULL,
PERFCOUNTER_FLAG_KERNEL);
if (ret) {
WARN_ONCE(1, "Unable to get perf counter for IFPC\n");
adreno_dev->perfctr_ifpc_lo = 0;
}
}
/* Clear the busy_data stats - we're starting over from scratch */
adreno_dev->busy_data.gpu_busy = 0;
adreno_dev->busy_data.bif_ram_cycles = 0;

View file

@ -1,4 +1,5 @@
/* Copyright (c) 2017-2018,2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. 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
@ -244,42 +245,6 @@ static const struct {
{adreno_is_a616, a615_hwcg_regs, ARRAY_SIZE(a615_hwcg_regs)},
};
static struct a6xx_protected_regs {
unsigned int base;
unsigned int count;
int read_protect;
} a6xx_protected_regs_group[] = {
{ 0x600, 0x51, 0 },
{ 0xAE50, 0x2, 1 },
{ 0x9624, 0x13, 1 },
{ 0x8630, 0x8, 1 },
{ 0x9E70, 0x1, 1 },
{ 0x9E78, 0x187, 1 },
{ 0xF000, 0x810, 1 },
{ 0xFC00, 0x3, 0 },
{ 0x50E, 0x0, 1 },
{ 0x50F, 0x0, 0 },
{ 0x510, 0x0, 1 },
{ 0x0, 0x4F9, 0 },
{ 0x501, 0xA, 0 },
{ 0x511, 0x44, 0 },
{ 0xE00, 0x1, 1 },
{ 0xE03, 0xB, 1 },
{ 0x8E00, 0x0, 1 },
{ 0x8E50, 0xF, 1 },
{ 0xBE02, 0x0, 1 },
{ 0xBE20, 0x11F3, 1 },
{ 0x800, 0x82, 1 },
{ 0x8A0, 0x8, 1 },
{ 0x8AB, 0x19, 1 },
{ 0x900, 0x4D, 1 },
{ 0x98D, 0x76, 1 },
{ 0x8D0, 0x23, 0 },
{ 0x980, 0x4, 0 },
{ 0xA630, 0x0, 1 },
{ 0x1b400, 0x1fff, 1 },
};
/* IFPC & Preemption static powerup restore list */
static struct reg_list_pair {
uint32_t offset;
@ -360,6 +325,61 @@ static struct reg_list_pair a615_pwrup_reglist[] = {
{ A6XX_UCHE_GBIF_GX_CONFIG, 0x0 },
};
/**
* struct a6xx_protected_regs - container for a protect register span
*/
static const struct a6xx_protected_regs {
/** @reg: Physical protected mode register to write to */
u32 reg;
/** @start: Dword offset of the starting register in the range */
u32 start;
/**
* @end: Dword offset of the ending register in the range
* (inclusive)
*/
u32 end;
/**
* @noaccess: 1 if the register should not be accessible from
* userspace, 0 if it can be read (but not written)
*/
u32 noaccess;
}
a630_protected_regs[] = {
{ A6XX_CP_PROTECT_REG + 0, 0x00000, 0x004ff, 0 },
{ A6XX_CP_PROTECT_REG + 1, 0x00501, 0x00506, 0 },
{ A6XX_CP_PROTECT_REG + 2, 0x0050b, 0x007ff, 0 },
{ A6XX_CP_PROTECT_REG + 3, 0x0050e, 0x0050e, 1 },
{ A6XX_CP_PROTECT_REG + 4, 0x00510, 0x00510, 1 },
{ A6XX_CP_PROTECT_REG + 5, 0x00534, 0x00534, 1 },
{ A6XX_CP_PROTECT_REG + 6, 0x00800, 0x00882, 1 },
{ A6XX_CP_PROTECT_REG + 7, 0x008a0, 0x008a8, 1 },
{ A6XX_CP_PROTECT_REG + 8, 0x008ab, 0x008cf, 1 },
{ A6XX_CP_PROTECT_REG + 9, 0x008d0, 0x0098c, 0 },
{A6XX_CP_PROTECT_REG + 10, 0x00900, 0x0094d, 1 },
{ A6XX_CP_PROTECT_REG + 11, 0x0098d, 0x00bff, 1 },
{ A6XX_CP_PROTECT_REG + 12, 0x00e00, 0x00e01, 1 },
{ A6XX_CP_PROTECT_REG + 13, 0x00e03, 0x00e0f, 1 },
{ A6XX_CP_PROTECT_REG + 14, 0x03c00, 0x03cc3, 1 },
{ A6XX_CP_PROTECT_REG + 15, 0x03cc4, 0x05cc3, 0 },
{ A6XX_CP_PROTECT_REG + 16, 0x08630, 0x087ff, 1 },
{ A6XX_CP_PROTECT_REG + 17, 0x08e00, 0x08e00, 1 },
{ A6XX_CP_PROTECT_REG + 18, 0x08e08, 0x08e08, 1 },
{ A6XX_CP_PROTECT_REG + 19, 0x08e50, 0x08e6f, 1 },
{ A6XX_CP_PROTECT_REG + 20, 0x09624, 0x097ff, 1 },
{ A6XX_CP_PROTECT_REG + 21, 0x09e70, 0x09e71, 1 },
{ A6XX_CP_PROTECT_REG + 22, 0x09e78, 0x09fff, 1 },
{ A6XX_CP_PROTECT_REG + 23, 0x0a630, 0x0a7ff, 1 },
{ A6XX_CP_PROTECT_REG + 24, 0x0ae02, 0x0ae02, 1 },
{ A6XX_CP_PROTECT_REG + 25, 0x0ae50, 0x0b17f, 1 },
{ A6XX_CP_PROTECT_REG + 26, 0x0b604, 0x0b604, 1 },
{ A6XX_CP_PROTECT_REG + 27, 0x0be02, 0x0be03, 1 },
{ A6XX_CP_PROTECT_REG + 28, 0x0be20, 0x0d5ff, 1 },
{ A6XX_CP_PROTECT_REG + 29, 0x0f000, 0x0fbff, 1 },
{ A6XX_CP_PROTECT_REG + 30, 0x0fc00, 0x11bff, 0 },
{ A6XX_CP_PROTECT_REG + 31, 0x11c00, 0x11c00, 1 },
{ 0 },
};
static void _update_always_on_regs(struct adreno_device *adreno_dev)
{
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
@ -424,49 +444,31 @@ static void a6xx_init(struct adreno_device *adreno_dev)
static void a6xx_protect_init(struct adreno_device *adreno_dev)
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct kgsl_protected_registers *mmu_prot =
kgsl_mmu_get_prot_regs(&device->mmu);
int i, num_sets;
int req_sets = ARRAY_SIZE(a6xx_protected_regs_group);
int max_sets = adreno_dev->gpucore->num_protected_regs;
unsigned int mmu_base = 0, mmu_range = 0, cur_range;
const struct a6xx_protected_regs *regs = a630_protected_regs;
int i;
/* enable access protection to privileged registers */
kgsl_regwrite(device, A6XX_CP_PROTECT_CNTL, 0x00000003);
/*
* Enable access protection to privileged registers, fault on an access
* protect violation and select the last span to protect from the start
* address all the way to the end of the register address space
*/
kgsl_regwrite(device, A6XX_CP_PROTECT_CNTL,
(1 << 0) | (1 << 1) | (1 << 3));
if (mmu_prot) {
mmu_base = mmu_prot->base;
mmu_range = mmu_prot->range;
req_sets += DIV_ROUND_UP(mmu_range, 0x2000);
}
/* Program each register defined by the core definition */
for (i = 0; regs[i].reg; i++) {
u32 count;
if (req_sets > max_sets)
WARN(1, "Size exceeds the num of protection regs available\n");
/*
* This is the offset of the end register as counted from the
* start, i.e. # of registers in the range - 1
*/
count = regs[i].end - regs[i].start;
/* Protect GPU registers */
num_sets = min_t(unsigned int,
ARRAY_SIZE(a6xx_protected_regs_group), max_sets);
for (i = 0; i < num_sets; i++) {
struct a6xx_protected_regs *regs =
&a6xx_protected_regs_group[i];
kgsl_regwrite(device, A6XX_CP_PROTECT_REG + i,
regs->base | (regs->count << 18) |
(regs->read_protect << 31));
}
/* Protect MMU registers */
if (mmu_prot) {
while ((i < max_sets) && (mmu_range > 0)) {
cur_range = min_t(unsigned int, mmu_range,
0x2000);
kgsl_regwrite(device, A6XX_CP_PROTECT_REG + i,
mmu_base | ((cur_range - 1) << 18) | (1 << 31));
mmu_base += cur_range;
mmu_range -= cur_range;
i++;
}
kgsl_regwrite(device, regs[i].reg,
(regs[i].start & 0x3ffff) |
((count & 0x1fff) << 18) |
(regs[i].noaccess << 31));
}
}
@ -721,6 +723,11 @@ static void a6xx_start(struct adreno_device *adreno_dev)
/* Turn on performance counters */
kgsl_regwrite(device, A6XX_RBBM_PERFCTR_CNTL, 0x1);
/* Turn on the IFPC counter (countable 4 on XOCLK4) */
if (kgsl_gmu_isenabled(device))
kgsl_regrmw(device, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1,
0xff, 0x4);
if (of_property_read_u32(device->pdev->dev.of_node,
"qcom,highest-bank-bit", &bit))
bit = MIN_HBB;
@ -782,6 +789,13 @@ static void a6xx_start(struct adreno_device *adreno_dev)
if (adreno_is_preemption_enabled(adreno_dev))
kgsl_regwrite(device, A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE,
0x1);
/*
* Enable GMU power counter 0 to count GPU busy. This is applicable to
* all a6xx targets
*/
kgsl_regwrite(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0xff000000);
kgsl_regrmw(device, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, 0xff, 0x20);
kgsl_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0x1);
a6xx_protect_init(adreno_dev);
@ -3455,50 +3469,11 @@ static struct adreno_perfcount_register a6xx_perfcounters_gbif_pwr[] = {
A6XX_GBIF_PWR_CNT_HIGH2, -1, A6XX_GBIF_PERF_PWR_CNT_EN },
};
static struct adreno_perfcount_register a6xx_perfcounters_pwr[] = {
{ KGSL_PERFCOUNTER_BROKEN, 0, 0, 0, 0, -1, 0 },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H, -1, 0 },
};
static struct adreno_perfcount_register a6xx_perfcounters_alwayson[] = {
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_CP_ALWAYS_ON_COUNTER_LO,
A6XX_CP_ALWAYS_ON_COUNTER_HI, -1 },
};
static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = {
/*
* A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0 is used for the GPU
* busy count (see the PWR group above). Mark it as broken
* so it's not re-used.
*/
{ KGSL_PERFCOUNTER_BROKEN, 0, 0,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H, -1,
A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_L,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_H, -1,
A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_L,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_H, -1,
A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_L,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_H, -1,
A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_H, -1,
A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_L,
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_H, -1,
A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, },
};
/*
* ADRENO_PERFCOUNTER_GROUP_RESTORE flag is enabled by default
* because most of the perfcounter groups need to be restored
@ -3537,11 +3512,8 @@ static struct adreno_perfcount_group a6xx_perfcounter_groups
A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF, vbif, 0),
A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF_PWR, vbif_pwr,
ADRENO_PERFCOUNTER_GROUP_FIXED),
A6XX_PERFCOUNTER_GROUP_FLAGS(PWR, pwr,
ADRENO_PERFCOUNTER_GROUP_FIXED),
A6XX_PERFCOUNTER_GROUP_FLAGS(ALWAYSON, alwayson,
ADRENO_PERFCOUNTER_GROUP_FIXED),
A6XX_POWER_COUNTER_GROUP(GPMU, gpmu),
};
static struct adreno_perfcounters a6xx_perfcounters = {
@ -3549,30 +3521,6 @@ static struct adreno_perfcounters a6xx_perfcounters = {
ARRAY_SIZE(a6xx_perfcounter_groups),
};
/* Program the GMU power counter to count GPU busy cycles */
static int a6xx_enable_pwr_counters(struct adreno_device *adreno_dev,
unsigned int counter)
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
/*
* We have a limited number of power counters. Since we're not using
* total GPU cycle count, return error if requested.
*/
if (counter == 0)
return -EINVAL;
if (!device->gmu.pdev)
return -ENODEV;
kgsl_regwrite(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0xFF000000);
kgsl_regrmw(device,
A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, 0xFF, 0x20);
kgsl_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0x1);
return 0;
}
static void a6xx_efuse_speed_bin(struct adreno_device *adreno_dev)
{
unsigned int val;
@ -3637,6 +3585,13 @@ static void a6xx_platform_setup(struct adreno_device *adreno_dev)
gpudev->vbif_xin_halt_ctrl0_mask =
A6XX_VBIF_XIN_HALT_CTRL0_MASK;
/* Set the counter for IFPC */
if (ADRENO_FEATURE(adreno_dev, ADRENO_IFPC))
adreno_dev->perfctr_ifpc_lo =
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L;
/* Set the GPU busy counter for frequency scaling */
adreno_dev->perfctr_pwr_lo = A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L;
/* Check efuse bits for various capabilties */
a6xx_check_features(adreno_dev);
}
@ -3876,7 +3831,6 @@ struct adreno_gpudev adreno_a6xx_gpudev = {
.regulator_enable = a6xx_sptprac_enable,
.regulator_disable = a6xx_sptprac_disable,
.perfcounters = &a6xx_perfcounters,
.enable_pwr_counters = a6xx_enable_pwr_counters,
.count_throttles = a6xx_count_throttles,
.microcode_read = a6xx_microcode_read,
.enable_64bit = a6xx_enable_64bit,

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. 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
@ -29,6 +29,7 @@
#include "adreno_trace.h"
#include "a3xx_reg.h"
#include "a6xx_reg.h"
#include "adreno_a5xx.h"
#define RB_HOSTPTR(_rb, _pos) \
@ -877,6 +878,8 @@ static inline int _get_alwayson_counter(struct adreno_device *adreno_dev,
ADRENO_GPUREV(adreno_dev) <= ADRENO_REV_A530)
*p++ = adreno_getreg(adreno_dev,
ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO);
else if (adreno_is_a6xx(adreno_dev))
*p++ = A6XX_CP_ALWAYS_ON_COUNTER_LO | (1 << 30) | (2 << 18);
else
*p++ = adreno_getreg(adreno_dev,
ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO) |

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2008-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. 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
@ -276,6 +276,9 @@ static void kgsl_destroy_ion(struct kgsl_memdesc *memdesc)
struct kgsl_mem_entry, memdesc);
struct kgsl_dma_buf_meta *meta = entry->priv_data;
if (memdesc->priv & KGSL_MEMDESC_MAPPED)
return;
if (meta != NULL) {
dma_buf_unmap_attachment(meta->attach, meta->table,
DMA_FROM_DEVICE);
@ -303,6 +306,9 @@ static void kgsl_destroy_anon(struct kgsl_memdesc *memdesc)
struct scatterlist *sg;
struct page *page;
if (memdesc->priv & KGSL_MEMDESC_MAPPED)
return;
for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) {
page = sg_page(sg);
for (j = 0; j < (sg->length >> PAGE_SHIFT); j++) {

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2002,2007-2017,2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. 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
@ -505,6 +505,8 @@ kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
size = kgsl_memdesc_footprint(memdesc);
ret = pagetable->pt_ops->mmu_unmap(pagetable, memdesc);
if (ret)
return ret;
atomic_dec(&pagetable->stats.entries);
atomic_long_sub(size, &pagetable->stats.mapped);

View file

@ -1,4 +1,5 @@
/* Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. 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
@ -479,6 +480,9 @@ done:
static void kgsl_page_alloc_free(struct kgsl_memdesc *memdesc)
{
if (memdesc->priv & KGSL_MEMDESC_MAPPED)
return;
kgsl_page_alloc_unmap_kernel(memdesc);
/* we certainly do not expect the hostptr to still be mapped */
BUG_ON(memdesc->hostptr);
@ -582,6 +586,9 @@ static void kgsl_cma_coherent_free(struct kgsl_memdesc *memdesc)
{
unsigned long attrs = 0;
if (memdesc->priv & KGSL_MEMDESC_MAPPED)
return;
if (memdesc->hostptr) {
if (memdesc->priv & KGSL_MEMDESC_SECURE) {
atomic_long_sub(memdesc->size,

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2015, Sony Mobile Communications AB.
* Copyright (c) 2012-2013, 2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2024, Qualcomm Innovation Center, Inc. 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
@ -85,6 +86,17 @@
/* Max number of processors/hosts in a system */
#define SMEM_HOST_COUNT 9
/* Entry range check
* ptr >= start : Checks if ptr is greater than the start of access region
* ptr + size >= ptr: Check for integer overflow (On 32bit system where ptr
* and size are 32bits, ptr + size can wrap around to be a small integer)
* ptr + size <= end: Checks if ptr+size is less than the end of access region
*/
#define IN_PARTITION_RANGE(ptr, size, start, end) \
(((void *)(ptr) >= (void *)(start)) && \
(((void *)(ptr) + (size)) >= (void *)(ptr)) && \
(((void *)(ptr) + (size)) <= (void *)(end)))
/**
* struct smem_proc_comm - proc_comm communication struct (legacy)
* @command: current command to be executed
@ -313,7 +325,8 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
end = phdr_to_last_private_entry(phdr);
cached = phdr_to_first_cached_entry(phdr);
if (WARN_ON((void *)end > p_end || (void *)cached > p_end))
if (WARN_ON(!IN_PARTITION_RANGE(end, 0, phdr, cached) ||
cached > p_end))
return -EINVAL;
while (hdr < end) {
@ -482,8 +495,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
unsigned item,
size_t *size)
{
struct smem_partition_header *phdr;
struct smem_private_entry *e, *end;
struct smem_private_entry *e, *uncached_end, *cached_end;
void *item_ptr, *p_end;
u32 partition_size;
u32 padding_data;
@ -494,35 +508,36 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
p_end = (void *)phdr + partition_size;
e = phdr_to_first_private_entry(phdr);
end = phdr_to_last_private_entry(phdr);
uncached_end = phdr_to_last_private_entry(phdr);
cached_end = phdr_to_first_cached_entry(phdr);
if (WARN_ON((void *)end > p_end))
if (WARN_ON(!IN_PARTITION_RANGE(uncached_end, 0, phdr, uncached_end)
|| (void *)cached_end > p_end))
return ERR_PTR(-EINVAL);
while (e < end) {
if (e->canary != SMEM_PRIVATE_CANARY) {
dev_err(smem->dev,
"Found invalid canary in host %d:%d partition\n",
phdr->host0, phdr->host1);
return ERR_PTR(-EINVAL);
}
while ((e < uncached_end) && ((e + 1) < uncached_end)) {
if (e->canary != SMEM_PRIVATE_CANARY)
goto invalid_canary;
if (le16_to_cpu(e->item) == item) {
if (size != NULL) {
e_size = le32_to_cpu(e->size);
padding_data = le16_to_cpu(e->padding_data);
e_size = le32_to_cpu(e->size);
padding_data = le16_to_cpu(e->padding_data);
if (e_size < partition_size
&& padding_data < e_size)
*size = e_size - padding_data;
else
return ERR_PTR(-EINVAL);
}
item_ptr = entry_to_item(e);
if (WARN_ON(item_ptr > p_end))
if (e_size < partition_size && padding_data < e_size)
entry_size = e_size - padding_data;
else
return ERR_PTR(-EINVAL);
item_ptr = entry_to_item(e);
if (WARN_ON(!IN_PARTITION_RANGE(item_ptr, entry_size, e,
uncached_end)))
return ERR_PTR(-EINVAL);
if (size != NULL)
*size = entry_size;
return item_ptr;
}