static int kgsl_iommu_start(struct kgsl_mmu *mmu) { int status; if (mmu->flags & KGSL_FLAGS_STARTED) return 0; kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000); if (mmu->defaultpagetable == NULL) mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT); /* Return error if the default pagetable doesn't exist */ if (mmu->defaultpagetable == NULL) return -ENOMEM; mmu->hwpagetable = mmu->defaultpagetable; status = kgsl_attach_pagetable_iommu_domain(mmu); if (!status) { mmu->flags |= KGSL_FLAGS_STARTED; } else { kgsl_detach_pagetable_iommu_domain(mmu); mmu->hwpagetable = NULL; } return status; }
static void kgsl_iommu_stop(struct kgsl_mmu *mmu) { /* * stop device mmu * * call this with the global lock held */ if (mmu->flags & KGSL_FLAGS_STARTED) { /* detach iommu attachment */ kgsl_detach_pagetable_iommu_domain(mmu); mmu->hwpagetable = NULL; mmu->flags &= ~KGSL_FLAGS_STARTED; } }
static void kgsl_iommu_setstate(struct kgsl_mmu *mmu, struct kgsl_pagetable *pagetable) { if (mmu->flags & KGSL_FLAGS_STARTED) { /* page table not current, then setup mmu to use new * specified page table */ if (mmu->hwpagetable != pagetable) { kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT); kgsl_detach_pagetable_iommu_domain(mmu); mmu->hwpagetable = pagetable; if (mmu->hwpagetable) kgsl_attach_pagetable_iommu_domain(mmu); } } }
static int kgsl_iommu_stop(struct kgsl_device *device) { /* * stop device mmu * * call this with the global lock held */ struct kgsl_mmu *mmu = &device->mmu; if (mmu->flags & KGSL_FLAGS_STARTED) { /* detach iommu attachment */ kgsl_detach_pagetable_iommu_domain(mmu); mmu->flags &= ~KGSL_FLAGS_STARTED; } return 0; }
static void kgsl_iommu_stop(struct kgsl_mmu *mmu) { struct kgsl_iommu *iommu = mmu->priv; if (mmu->flags & KGSL_FLAGS_STARTED) { kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000); kgsl_detach_pagetable_iommu_domain(mmu); mmu->hwpagetable = NULL; mmu->flags &= ~KGSL_FLAGS_STARTED; } iommu->clk_event_queued = false; kgsl_cancel_events(mmu->device, mmu); kgsl_iommu_disable_clk(mmu); }
static void kgsl_iommu_stop(struct kgsl_mmu *mmu) { struct kgsl_iommu *iommu = mmu->priv; int i, j; /* * stop device mmu * * call this with the global lock held */ if (mmu->flags & KGSL_FLAGS_STARTED) { /* detach iommu attachment */ kgsl_detach_pagetable_iommu_domain(mmu); mmu->hwpagetable = NULL; mmu->flags &= ~KGSL_FLAGS_STARTED; if (mmu->fault) { for (i = 0; i < iommu->unit_count; i++) { struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i]; for (j = 0; j < iommu_unit->dev_count; j++) { if (iommu_unit->dev[j].fault) { kgsl_iommu_enable_clk(mmu, j); KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit, iommu_unit->dev[j].ctx_id, RESUME, 1); iommu_unit->dev[j].fault = 0; } } } mmu->fault = 0; } } /* switch off MMU clocks and cancel any events it has queued */ iommu->clk_event_queued = false; kgsl_cancel_events(mmu->device, mmu); kgsl_iommu_disable_clk(mmu); }
static void kgsl_iommu_stop(struct kgsl_mmu *mmu) { struct kgsl_iommu *iommu = mmu->priv; /* * stop device mmu * * call this with the global lock held */ if (mmu->flags & KGSL_FLAGS_STARTED) { /* detach iommu attachment */ kgsl_detach_pagetable_iommu_domain(mmu); mmu->hwpagetable = NULL; mmu->flags &= ~KGSL_FLAGS_STARTED; } /* switch off MMU clocks and cancel any events it has queued */ iommu->clk_event_queued = false; kgsl_cancel_events(mmu->device, mmu); kgsl_iommu_disable_clk(mmu); }
static int kgsl_iommu_start(struct kgsl_mmu *mmu) { struct kgsl_device *device = mmu->device; int status; struct kgsl_iommu *iommu = mmu->priv; int i, j; if (mmu->flags & KGSL_FLAGS_STARTED) return 0; if (mmu->defaultpagetable == NULL) { status = kgsl_iommu_setup_defaultpagetable(mmu); if (status) return -ENOMEM; /* Initialize the sync lock between GPU and CPU */ if (msm_soc_version_supports_iommu_v1() && (device->id == KGSL_DEVICE_3D0)) kgsl_iommu_init_sync_lock(mmu); } /* We use the GPU MMU to control access to IOMMU registers on 8960 with * a225, hence we still keep the MMU active on 8960 */ if (cpu_is_msm8960()) { struct kgsl_mh *mh = &(mmu->device->mh); kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001); kgsl_regwrite(mmu->device, MH_MMU_MPU_END, mh->mpu_base + iommu->iommu_units[0].reg_map.gpuaddr); } else { kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000); } mmu->hwpagetable = mmu->defaultpagetable; status = kgsl_attach_pagetable_iommu_domain(mmu); if (status) { mmu->hwpagetable = NULL; goto done; } status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); if (status) { KGSL_CORE_ERR("clk enable failed\n"); goto done; } status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); if (status) { KGSL_CORE_ERR("clk enable failed\n"); goto done; } /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as * that value should not change when we change pagetables, so while * changing pagetables we can use this lsb value of the pagetable w/o * having to read it again */ for (i = 0; i < iommu->unit_count; i++) { struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i]; for (j = 0; j < iommu_unit->dev_count; j++) iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu, KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit, iommu_unit->dev[j].ctx_id, TTBR0)); } kgsl_iommu_disable_clk_on_ts(mmu, 0, false); mmu->flags |= KGSL_FLAGS_STARTED; done: if (status) { kgsl_iommu_disable_clk_on_ts(mmu, 0, false); kgsl_detach_pagetable_iommu_domain(mmu); } return status; }
static int kgsl_iommu_start(struct kgsl_mmu *mmu) { int status; struct kgsl_iommu *iommu = mmu->priv; int i, j; if (mmu->flags & KGSL_FLAGS_STARTED) return 0; if (mmu->defaultpagetable == NULL) { status = kgsl_iommu_setup_defaultpagetable(mmu); if (status) return -ENOMEM; } /* We use the GPU MMU to control access to IOMMU registers on 8960 with * a225, hence we still keep the MMU active on 8960 */ if (cpu_is_msm8960()) { struct kgsl_mh *mh = &(mmu->device->mh); kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001); kgsl_regwrite(mmu->device, MH_MMU_MPU_END, mh->mpu_base + iommu->iommu_units [iommu->unit_count - 1].reg_map.gpuaddr - PAGE_SIZE); } else { kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000); } mmu->hwpagetable = mmu->defaultpagetable; status = kgsl_attach_pagetable_iommu_domain(mmu); if (status) { mmu->hwpagetable = NULL; goto done; } status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); if (status) { KGSL_CORE_ERR("clk enable failed\n"); goto done; } status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); if (status) { KGSL_CORE_ERR("clk enable failed\n"); goto done; } /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as * that value should not change when we change pagetables, so while * changing pagetables we can use this lsb value of the pagetable w/o * having to read it again */ for (i = 0; i < iommu->unit_count; i++) { struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i]; /* Make sure that the ASID of the priv bank is set to 1. * When we a different pagetable for the priv bank then the * iommu driver sets the ASID to 0 instead of 1 */ KGSL_IOMMU_SET_IOMMU_REG(iommu->iommu_units[i].reg_map.hostptr, KGSL_IOMMU_CONTEXT_PRIV, CONTEXTIDR, 1); for (j = 0; j < iommu_unit->dev_count; j++) iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB( KGSL_IOMMU_GET_IOMMU_REG( iommu_unit->reg_map.hostptr, iommu_unit->dev[j].ctx_id, TTBR0)); } iommu->asid = KGSL_IOMMU_GET_IOMMU_REG( iommu->iommu_units[0].reg_map.hostptr, KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR); kgsl_iommu_disable_clk_on_ts(mmu, 0, false); mmu->flags |= KGSL_FLAGS_STARTED; done: if (status) { kgsl_iommu_disable_clk_on_ts(mmu, 0, false); kgsl_detach_pagetable_iommu_domain(mmu); } return status; }
static int kgsl_iommu_start(struct kgsl_mmu *mmu) { struct kgsl_device *device = mmu->device; int status; struct kgsl_iommu *iommu = mmu->priv; int i, j; if (mmu->flags & KGSL_FLAGS_STARTED) return 0; if (mmu->defaultpagetable == NULL) { status = kgsl_iommu_setup_defaultpagetable(mmu); if (status) return -ENOMEM; if (msm_soc_version_supports_iommu_v1() && (device->id == KGSL_DEVICE_3D0)) kgsl_iommu_init_sync_lock(mmu); } if (cpu_is_msm8960()) { struct kgsl_mh *mh = &(mmu->device->mh); kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001); kgsl_regwrite(mmu->device, MH_MMU_MPU_END, mh->mpu_base + iommu->iommu_units [iommu->unit_count - 1].reg_map.gpuaddr - PAGE_SIZE); } else { kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000); } mmu->hwpagetable = mmu->defaultpagetable; status = kgsl_attach_pagetable_iommu_domain(mmu); if (status) { mmu->hwpagetable = NULL; goto done; } status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); if (status) { KGSL_CORE_ERR("clk enable failed\n"); goto done; } status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); if (status) { KGSL_CORE_ERR("clk enable failed\n"); goto done; } for (i = 0; i < iommu->unit_count; i++) { struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i]; for (j = 0; j < iommu_unit->dev_count; j++) iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB( KGSL_IOMMU_GET_IOMMU_REG( iommu_unit->reg_map.hostptr, iommu_unit->dev[j].ctx_id, TTBR0)); } kgsl_iommu_disable_clk_on_ts(mmu, 0, false); mmu->flags |= KGSL_FLAGS_STARTED; done: if (status) { kgsl_iommu_disable_clk_on_ts(mmu, 0, false); kgsl_detach_pagetable_iommu_domain(mmu); } return status; }