diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 8900ac4b3133..39126ba9f4df 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1368,6 +1368,8 @@ static const struct kgsl_functable adreno_functable; static void adreno_setup_device(struct adreno_device *adreno_dev) { + u32 i; + memset(adreno_dev, 0, sizeof(*adreno_dev)); adreno_dev->dev.name = "kgsl-3d0"; @@ -1403,6 +1405,12 @@ static void adreno_setup_device(struct adreno_device *adreno_dev) /* Enable use of the LLC slices where applicable */ adreno_dev->gpu_llc_slice_enable = true; adreno_dev->gpuhtw_llc_slice_enable = true; + + for (i = 0; i < ARRAY_SIZE(adreno_dev->ringbuffers); i++) { + struct adreno_ringbuffer *rb = &adreno_dev->ringbuffers[i]; + + INIT_LIST_HEAD(&rb->events.group); + } } static int adreno_probe(struct platform_device *pdev) @@ -1525,10 +1533,6 @@ static int adreno_probe(struct platform_device *pdev) kgsl_device_snapshot_probe(device, size); - status = adreno_ringbuffer_probe(adreno_dev); - if (status) - goto out; - status = adreno_dispatcher_init(adreno_dev); if (status) goto out; @@ -1575,7 +1579,6 @@ static int adreno_probe(struct platform_device *pdev) #endif out: if (status) { - adreno_ringbuffer_close(adreno_dev); kgsl_device_platform_remove(device); device->pdev = NULL; } @@ -1813,6 +1816,10 @@ static int adreno_init(struct kgsl_device *device) if (test_bit(ADRENO_DEVICE_INITIALIZED, &adreno_dev->priv)) return 0; + ret = adreno_ringbuffer_init(adreno_dev); + if (ret) + return ret; + /* * Either the microcode read failed because the usermodehelper isn't * available or the microcode was corrupted. Fail the init and force @@ -1953,6 +1960,60 @@ static void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev) } } +static int adreno_first_open(struct kgsl_device *device) +{ + int ret; + + /* + * active_cnt special case: we are starting up for the first + * time, so use this sequence instead of the kgsl_pwrctrl_wake() + * which will be called by kgsl_active_count_get(). + */ + atomic_inc(&device->active_cnt); + + kgsl_sharedmem_set(device, device->memstore, 0, 0, + device->memstore->size); + + ret = adreno_init(device); + if (ret) + goto err; + + ret = adreno_start(device, 0); + if (ret) + goto err; + + timer_setup(&device->idle_timer, kgsl_timer, 0); + + complete_all(&device->hwaccess_gate); + kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); + kgsl_active_count_put(device); + + return 0; +err: + kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); + atomic_dec(&device->active_cnt); + + return ret; +} + +static int adreno_last_close(struct kgsl_device *device) +{ + /* + * Wait up to 1 second for the active count to go low + * and then start complaining about it + */ + if (kgsl_active_count_wait(device, 0)) { + dev_err(device->dev, + "Waiting for the active count to become 0\n"); + + while (kgsl_active_count_wait(device, 0)) + dev_err(device->dev, + "Still waiting for the active count\n"); + } + + return kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); +} + /** * _adreno_start - Power up the GPU and prepare to accept commands * @adreno_dev: Pointer to an adreno_device structure @@ -3791,9 +3852,10 @@ static const struct kgsl_functable adreno_functable = { .idle = adreno_idle, .isidle = adreno_isidle, .suspend_context = adreno_suspend_context, - .init = adreno_init, + .first_open = adreno_first_open, .start = adreno_start, .stop = adreno_stop, + .last_close = adreno_last_close, .getproperty = adreno_getproperty, .getproperty_compat = adreno_getproperty_compat, .waittimestamp = adreno_waittimestamp, diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index aa66683f132e..f1d23473d23c 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -111,8 +111,10 @@ static void a6xx_init(struct adreno_device *adreno_dev) a6xx_crashdump_init(adreno_dev); - adreno_dev->pwrup_reglist = kgsl_allocate_global(device, - PAGE_SIZE, 0, KGSL_MEMDESC_PRIVILEGED, "powerup_register_list"); + if (IS_ERR_OR_NULL(adreno_dev->pwrup_reglist)) + adreno_dev->pwrup_reglist = kgsl_allocate_global(device, + PAGE_SIZE, 0, KGSL_MEMDESC_PRIVILEGED, + "powerup_register_list"); } static void a6xx_protect_init(struct adreno_device *adreno_dev) @@ -322,6 +324,20 @@ static void a6xx_llc_configure_gpu_scid(struct adreno_device *adreno_dev); static void a6xx_llc_configure_gpuhtw_scid(struct adreno_device *adreno_dev); static void a6xx_llc_enable_overrides(struct adreno_device *adreno_dev); +/* + * Some targets support marking certain transactions as always privileged which + * allows us to mark more memory as privileged without having to explicitly set + * the APRIV bit. For those targets, choose the following transactions to be + * privileged by default: + * CDWRITE [6:6] - Crashdumper writes + * CDREAD [5:5] - Crashdumper reads + * RBRPWB [3:3] - RPTR shadow writes + * RBPRIVLEVEL [2:2] - Memory accesses from PM4 packets in the ringbuffer + * RBFETCH [1:1] - Ringbuffer reads + */ +#define A6XX_APRIV_DEFAULT \ + ((1 << 6) | (1 << 5) | (1 << 3) | (1 << 2) | (1 << 1)) + /* * a6xx_start() - Device start * @adreno_dev: Pointer to adreno device @@ -537,8 +553,6 @@ static void a6xx_start(struct adreno_device *adreno_dev) patch_reglist = true; } - a6xx_preemption_start(adreno_dev); - /* * We start LM here because we want all the following to be up * 1. GX HS @@ -559,6 +573,9 @@ static void a6xx_start(struct adreno_device *adreno_dev) if (adreno_is_a660v1(adreno_dev)) kgsl_regwrite(device, A6XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x0); + + if (ADRENO_FEATURE(adreno_dev, ADRENO_APRIV)) + kgsl_regwrite(device, A6XX_CP_APRIV_CNTL, A6XX_APRIV_DEFAULT); } /* @@ -767,20 +784,6 @@ static int a6xx_post_start(struct adreno_device *adreno_dev) return ret; } -/* - * Some targets support marking certain transactions as always privileged which - * allows us to mark more memory as privileged without having to explicitly set - * the APRIV bit. For those targets, choose the following transactions to be - * privileged by default: - * CDWRITE [6:6] - Crashdumper writes - * CDREAD [5:5] - Crashdumper reads - * RBRPWB [3:3] - RPTR shadow writes - * RBPRIVLEVEL [2:2] - Memory accesses from PM4 packets in the ringbuffer - * RBFETCH [1:1] - Ringbuffer reads - */ -#define A6XX_APRIV_DEFAULT \ - ((1 << 6) | (1 << 5) | (1 << 3) | (1 << 2) | (1 << 1)) - /* * a6xx_rb_start() - Start the ringbuffer * @adreno_dev: Pointer to adreno device @@ -792,6 +795,8 @@ static int a6xx_rb_start(struct adreno_device *adreno_dev) uint64_t addr; int ret; + a6xx_preemption_start(adreno_dev); + addr = SCRATCH_RPTR_GPU_ADDR(device, rb->id); adreno_writereg64(adreno_dev, ADRENO_REG_CP_RB_RPTR_ADDR_LO, @@ -811,9 +816,6 @@ static int a6xx_rb_start(struct adreno_device *adreno_dev) if (ret) return ret; - if (ADRENO_FEATURE(adreno_dev, ADRENO_APRIV)) - kgsl_regwrite(device, A6XX_CP_APRIV_CNTL, A6XX_APRIV_DEFAULT); - /* Clear the SQE_HALT to start the CP engine */ kgsl_regwrite(device, A6XX_CP_SQE_CNTL, 1); diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 26fc4796622c..70cd36b16e3a 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -255,13 +255,42 @@ static int _rb_readtimestamp(struct kgsl_device *device, timestamp); } -static int _adreno_ringbuffer_probe(struct adreno_device *adreno_dev, +static int _adreno_ringbuffer_init(struct adreno_device *adreno_dev, int id) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_ringbuffer *rb = &adreno_dev->ringbuffers[id]; unsigned int priv = 0; + /* + * Allocate mem for storing RB pagetables and commands to + * switch pagetable + */ + if (IS_ERR_OR_NULL(rb->pagetable_desc)) { + rb->pagetable_desc = kgsl_allocate_global(device, PAGE_SIZE, + 0, KGSL_MEMDESC_PRIVILEGED, "pagetable_desc"); + if (IS_ERR(rb->pagetable_desc)) + return PTR_ERR(rb->pagetable_desc); + } + + /* allocate a chunk of memory to create user profiling IB1s */ + if (IS_ERR_OR_NULL(rb->profile_desc)) + rb->profile_desc = kgsl_allocate_global(device, PAGE_SIZE, + KGSL_MEMFLAGS_GPUREADONLY, 0, "profile_desc"); + + if (ADRENO_FEATURE(adreno_dev, ADRENO_APRIV)) + priv |= KGSL_MEMDESC_PRIVILEGED; + + if (IS_ERR_OR_NULL(rb->buffer_desc)) { + rb->buffer_desc = kgsl_allocate_global(device, KGSL_RB_SIZE, + KGSL_MEMFLAGS_GPUREADONLY, priv, "ringbuffer"); + if (IS_ERR(rb->buffer_desc)) + return PTR_ERR(rb->buffer_desc); + } + + if (!list_empty(&rb->events.group)) + return 0; + rb->id = id; kgsl_add_event_group(&rb->events, NULL, _rb_readtimestamp, rb, "rb_events-%d", id); @@ -271,26 +300,7 @@ static int _adreno_ringbuffer_probe(struct adreno_device *adreno_dev, spin_lock_init(&rb->preempt_lock); - /* - * Allocate mem for storing RB pagetables and commands to - * switch pagetable - */ - rb->pagetable_desc = kgsl_allocate_global(device, PAGE_SIZE, - 0, KGSL_MEMDESC_PRIVILEGED, "pagetable_desc"); - if (IS_ERR(rb->pagetable_desc)) - return PTR_ERR(rb->pagetable_desc); - - /* allocate a chunk of memory to create user profiling IB1s */ - rb->profile_desc = kgsl_allocate_global(device, PAGE_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, 0, "profile_desc"); - - if (ADRENO_FEATURE(adreno_dev, ADRENO_APRIV)) - priv |= KGSL_MEMDESC_PRIVILEGED; - - rb->buffer_desc = kgsl_allocate_global(device, KGSL_RB_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, priv, "ringbuffer"); - - return PTR_ERR_OR_ZERO(rb->buffer_desc); + return 0; } static void adreno_preemption_timer(struct timer_list *t) @@ -334,7 +344,7 @@ static void adreno_preemption_close(struct adreno_device *adreno_dev) del_timer(&preempt->timer); } -int adreno_ringbuffer_probe(struct adreno_device *adreno_dev) +int adreno_ringbuffer_init(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); int i; @@ -347,11 +357,13 @@ int adreno_ringbuffer_probe(struct adreno_device *adreno_dev) if (ADRENO_FEATURE(adreno_dev, ADRENO_APRIV)) priv |= KGSL_MEMDESC_PRIVILEGED; - device->scratch = kgsl_allocate_global(device, + if (IS_ERR_OR_NULL(device->scratch)) { + device->scratch = kgsl_allocate_global(device, PAGE_SIZE, 0, KGSL_MEMDESC_RANDOM, "scratch"); - if (IS_ERR(device->scratch)) - return PTR_ERR(device->scratch); + if (IS_ERR(device->scratch)) + return PTR_ERR(device->scratch); + } } if (ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) @@ -361,7 +373,7 @@ int adreno_ringbuffer_probe(struct adreno_device *adreno_dev) adreno_dev->num_ringbuffers = 1; for (i = 0; i < adreno_dev->num_ringbuffers; i++) { - status = _adreno_ringbuffer_probe(adreno_dev, i); + status = _adreno_ringbuffer_init(adreno_dev, i); if (status) { adreno_ringbuffer_close(adreno_dev); return status; @@ -379,10 +391,8 @@ void adreno_ringbuffer_close(struct adreno_device *adreno_dev) struct adreno_ringbuffer *rb; int i; - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) kgsl_del_event_group(&rb->events); - memset(rb, 0, sizeof(*rb)); - } adreno_preemption_close(adreno_dev); } diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h index a01cbd7a2d5e..52f58f116b57 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.h +++ b/drivers/gpu/msm/adreno_ringbuffer.h @@ -149,7 +149,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, struct kgsl_drawobj_cmd *cmdobj, struct adreno_submit_time *time); -int adreno_ringbuffer_probe(struct adreno_device *adreno_dev); +int adreno_ringbuffer_init(struct adreno_device *adreno_dev); int adreno_ringbuffer_start(struct adreno_device *adreno_dev); diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 26f50a79dc68..c24713fc3833 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1008,23 +1008,9 @@ static int kgsl_close_device(struct kgsl_device *device) mutex_lock(&device->mutex); device->open_count--; - if (device->open_count == 0) { + if (device->open_count == 0) + result = device->ftbl->last_close(device); - /* - * Wait up to 1 second for the active count to go low - * and then start complaining about it - */ - if (kgsl_active_count_wait(device, 0)) { - dev_err(device->dev, - "Waiting for the active count to become 0\n"); - - while (kgsl_active_count_wait(device, 0)) - dev_err(device->dev, - "Still waiting for the active count\n"); - } - - result = kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); - } mutex_unlock(&device->mutex); return result; @@ -1092,37 +1078,12 @@ static int kgsl_open_device(struct kgsl_device *device) mutex_lock(&device->mutex); if (device->open_count == 0) { - /* - * active_cnt special case: we are starting up for the first - * time, so use this sequence instead of the kgsl_pwrctrl_wake() - * which will be called by kgsl_active_count_get(). - */ - atomic_inc(&device->active_cnt); - kgsl_sharedmem_set(device, device->memstore, 0, 0, - device->memstore->size); - - result = device->ftbl->init(device); + result = device->ftbl->first_open(device); if (result) - goto err; - - result = device->ftbl->start(device, 0); - if (result) - goto err; - /* - * Make sure the gates are open, so they don't block until - * we start suspend or FT. - */ - complete_all(&device->hwaccess_gate); - kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); - kgsl_active_count_put(device); + goto out; } device->open_count++; -err: - if (result) { - kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); - atomic_dec(&device->active_cnt); - } - +out: mutex_unlock(&device->mutex); return result; } @@ -4908,8 +4869,6 @@ int kgsl_device_platform_probe(struct kgsl_device *device) rwlock_init(&device->context_lock); spin_lock_init(&device->submit_lock); - timer_setup(&device->idle_timer, kgsl_timer, 0); - status = kgsl_mmu_probe(device); if (status != 0) goto error_pwrctrl_close; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index e35e373d4994..490c92279238 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -99,7 +99,8 @@ struct kgsl_functable { int (*idle)(struct kgsl_device *device); bool (*isidle)(struct kgsl_device *device); int (*suspend_context)(struct kgsl_device *device); - int (*init)(struct kgsl_device *device); + int (*first_open)(struct kgsl_device *device); + int (*last_close)(struct kgsl_device *device); int (*start)(struct kgsl_device *device, int priority); int (*stop)(struct kgsl_device *device); int (*getproperty)(struct kgsl_device *device, diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index adee3f6063e6..3c7e4ba64e63 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -833,6 +833,25 @@ static u32 kgsl_iommu_get_contextidr(struct kgsl_pagetable *pt) return iommu_pt->contextidr; } +static int kgsl_iommu_get_context_bank(struct kgsl_pagetable *pt) +{ + struct kgsl_iommu_pt *iommu_pt; + u32 cb_num; + int ret; + + if (!pt) + return -EINVAL; + + iommu_pt = pt->priv; + + ret = iommu_domain_get_attr(iommu_pt->domain, + DOMAIN_ATTR_CONTEXT_BANK, &cb_num); + if (ret) + return ret; + + return (int) cb_num; +} + /* * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable * @mmu_specific_pt - Pointer to pagetable which is to be freed @@ -2622,6 +2641,7 @@ static struct kgsl_mmu_pt_ops iommu_pt_ops = { .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable, .get_ttbr0 = kgsl_iommu_get_ttbr0, .get_contextidr = kgsl_iommu_get_contextidr, + .get_context_bank = kgsl_iommu_get_context_bank, .get_gpuaddr = kgsl_iommu_get_gpuaddr, .put_gpuaddr = kgsl_iommu_put_gpuaddr, .set_svm_region = kgsl_iommu_set_svm_region, diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index d30d745a18f6..d082e6cc321e 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -544,6 +544,14 @@ void kgsl_mmu_close(struct kgsl_device *device) mmu->mmu_ops->mmu_close(mmu); } +int kgsl_mmu_pagetable_get_context_bank(struct kgsl_pagetable *pagetable) +{ + if (PT_OP_VALID(pagetable, get_context_bank)) + return pagetable->pt_ops->get_context_bank(pagetable); + + return -ENOENT; +} + enum kgsl_mmutype kgsl_mmu_get_mmutype(struct kgsl_device *device) { return device ? device->mmu.type : KGSL_MMU_TYPE_NONE; diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 04d3878c6899..dd38829c172d 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -83,6 +83,7 @@ struct kgsl_mmu_pt_ops { void (*mmu_destroy_pagetable)(struct kgsl_pagetable *pt); u64 (*get_ttbr0)(struct kgsl_pagetable *pt); u32 (*get_contextidr)(struct kgsl_pagetable *pt); + int (*get_context_bank)(struct kgsl_pagetable *pt); int (*get_gpuaddr)(struct kgsl_pagetable *pt, struct kgsl_memdesc *memdesc); void (*put_gpuaddr)(struct kgsl_memdesc *memdesc); @@ -346,4 +347,14 @@ kgsl_mmu_pagetable_get_contextidr(struct kgsl_pagetable *pagetable) void kgsl_mmu_map_global(struct kgsl_device *device, struct kgsl_memdesc *memdesc); +/** + * kgsl_mmu_pagetable_get_context_bank - Return the context bank number + * @pagetable: A handle to a given pagetable + * + * This function will find the context number of the given pagetable + + * Return: The context bank number the pagetable is attached to or + * negative error on failure. + */ +int kgsl_mmu_pagetable_get_context_bank(struct kgsl_pagetable *pagetable); #endif /* __KGSL_MMU_H */