mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
iommu: msm: check range before mapping for IOMMU-v1
Make sure iommu_map_range() does not leave a partial mapping on error if part of the range is already mapped. Change-Id: I108b45ce8935b73ecb65f375930fe5e00b8d91eb Signed-off-by: Jeremy Gebben <jgebben@codeaurora.org>
This commit is contained in:
parent
962d00eb87
commit
6b44ed1956
1 changed files with 53 additions and 0 deletions
|
@ -370,6 +370,55 @@ static phys_addr_t get_phys_addr(struct scatterlist *sg)
|
|||
return pa;
|
||||
}
|
||||
|
||||
static int check_range(unsigned long *fl_table, unsigned int va,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
unsigned long *fl_pte;
|
||||
unsigned long fl_offset;
|
||||
unsigned long *sl_table;
|
||||
unsigned long sl_start, sl_end;
|
||||
int i;
|
||||
|
||||
fl_offset = FL_OFFSET(va); /* Upper 12 bits */
|
||||
fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */
|
||||
|
||||
while (offset < len) {
|
||||
if (*fl_pte & FL_TYPE_TABLE) {
|
||||
sl_start = SL_OFFSET(va);
|
||||
sl_table = __va(((*fl_pte) & FL_BASE_MASK));
|
||||
sl_end = ((len - offset) / SZ_4K) + sl_start;
|
||||
|
||||
if (sl_end > NUM_SL_PTE)
|
||||
sl_end = NUM_SL_PTE;
|
||||
|
||||
for (i = sl_start; i < sl_end; i++) {
|
||||
if (sl_table[i] != 0) {
|
||||
pr_err("%08x - %08x already mapped\n",
|
||||
va, va + SZ_4K);
|
||||
return -EBUSY;
|
||||
}
|
||||
offset += SZ_4K;
|
||||
va += SZ_4K;
|
||||
}
|
||||
|
||||
|
||||
sl_start = 0;
|
||||
} else {
|
||||
if (*fl_pte != 0) {
|
||||
pr_err("%08x - %08x already mapped\n",
|
||||
va, va + SZ_1M);
|
||||
return -EBUSY;
|
||||
}
|
||||
va += SZ_1M;
|
||||
offset += SZ_1M;
|
||||
sl_start = 0;
|
||||
}
|
||||
fl_pte++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int is_fully_aligned(unsigned int va, phys_addr_t pa, size_t len,
|
||||
int align)
|
||||
{
|
||||
|
@ -405,6 +454,10 @@ int msm_iommu_pagetable_map_range(struct iommu_pt *pt, unsigned int va,
|
|||
fl_pte = pt->fl_table + fl_offset; /* int pointers, 4 bytes */
|
||||
pa = get_phys_addr(sg);
|
||||
|
||||
ret = check_range(pt->fl_table, va, len);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
while (offset < len) {
|
||||
chunk_size = SZ_4K;
|
||||
|
||||
|
|
Loading…
Reference in a new issue