diff options
Diffstat (limited to 'drivers/gpu/msm')
| -rw-r--r-- | drivers/gpu/msm/adreno.c | 12 | ||||
| -rw-r--r-- | drivers/gpu/msm/adreno_a4xx_snapshot.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/msm/adreno_ringbuffer.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_iommu.c | 133 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_iommu.h | 24 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_mmu.h | 14 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_pwrctrl.c | 5 |
7 files changed, 109 insertions, 90 deletions
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 46ac589c78b..35ab19c634c 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1162,9 +1162,11 @@ static int adreno_iommu_setstate(struct kgsl_device *device, * after the command has been retired */ if (result) - kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false); + kgsl_mmu_disable_clk(&device->mmu, + KGSL_IOMMU_CONTEXT_USER); else - kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, true); + kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, + KGSL_IOMMU_CONTEXT_USER); done: kgsl_context_put(context); @@ -1449,6 +1451,12 @@ static int adreno_of_get_pdata(struct platform_device *pdev) if (ret) goto err; + /* get pm_qos from target, set it to default if not found */ + if (adreno_of_read_property(pdev->dev.of_node, "qcom,pm_qos_latency", + &pdata->pm_qos_latency)) + pdata->pm_qos_latency = 501; + + if (adreno_of_read_property(pdev->dev.of_node, "qcom,idle-timeout", &pdata->idle_timeout)) pdata->idle_timeout = HZ/12; diff --git a/drivers/gpu/msm/adreno_a4xx_snapshot.c b/drivers/gpu/msm/adreno_a4xx_snapshot.c index 3655325305f..cc6a37b8c1e 100644 --- a/drivers/gpu/msm/adreno_a4xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a4xx_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, The Linux Foundation. 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 @@ -326,6 +326,7 @@ void *a4xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, goto skip_regs; } if (kgsl_mmu_enable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_PRIV)) { + kgsl_mmu_disable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER); KGSL_CORE_ERR("Failed to turn on iommu priv context clocks\n"); goto skip_regs; } @@ -333,6 +334,9 @@ void *a4xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain, kgsl_snapshot_dump_regs, &list); + + kgsl_mmu_disable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER); + kgsl_mmu_disable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_PRIV); skip_regs: snapshot = kgsl_snapshot_indexed_registers(device, snapshot, remain, @@ -399,7 +403,5 @@ skip_regs: kgsl_regwrite(device, A4XX_RBBM_CLOCK_CTL2, clock_ctl2); - /* This will only disable the clock if no one else turned on */ - kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, 0); return snapshot; } diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 68d766ae716..aac609f3a06 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -652,7 +652,8 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, total_sizedwords += (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) ? 2 : 0; /* Add two dwords for the CP_INTERRUPT */ - total_sizedwords += drawctxt ? 2 : 0; + total_sizedwords += + (drawctxt || (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) ? 2 : 0; /* context rollover */ if (adreno_is_a3xx(adreno_dev)) diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index a791d67c8e0..5454498f6db 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -457,7 +457,7 @@ done: * Disables iommu clocks * Return - void */ -static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu) +static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu, int ctx_id) { struct kgsl_iommu *iommu = mmu->priv; struct msm_iommu_drvdata *iommu_drvdata; @@ -466,8 +466,15 @@ static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu) 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].clk_enabled) + if (ctx_id != iommu_unit->dev[j].ctx_id) continue; + atomic_dec(&iommu_unit->dev[j].clk_enable_count); + BUG_ON( + atomic_read(&iommu_unit->dev[j].clk_enable_count) < 0); + /* + * the clock calls have a refcount so call them on every + * enable/disable call + */ iommu_drvdata = dev_get_drvdata( iommu_unit->dev[j].dev->parent); if (iommu_drvdata->aclk) @@ -475,7 +482,6 @@ static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu) if (iommu_drvdata->clk) clk_disable_unprepare(iommu_drvdata->clk); clk_disable_unprepare(iommu_drvdata->pclk); - iommu_unit->dev[j].clk_enabled = false; } } } @@ -496,32 +502,14 @@ static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data, unsigned int id, unsigned int ts, u32 type) { - struct kgsl_mmu *mmu = data; - struct kgsl_iommu *iommu = mmu->priv; - - if (!iommu->clk_event_queued) { - if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) - KGSL_DRV_ERR(device, - "IOMMU disable clock event being cancelled, " - "iommu_last_cmd_ts: %x, retired ts: %x\n", - iommu->iommu_last_cmd_ts, ts); - return; - } + struct kgsl_iommu_disable_clk_param *param = data; - if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) { - kgsl_iommu_disable_clk(mmu); - iommu->clk_event_queued = false; - } else { - /* add new event to fire when ts is reached, this can happen - * if we queued an event and someone requested the clocks to - * be disbaled on a later timestamp */ - if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts, - kgsl_iommu_clk_disable_event, mmu, mmu)) { - KGSL_DRV_ERR(device, - "Failed to add IOMMU disable clk event\n"); - iommu->clk_event_queued = false; - } - } + if ((0 <= timestamp_cmp(ts, param->ts)) || + (KGSL_EVENT_CANCELLED == type)) + kgsl_iommu_disable_clk(param->mmu, param->ctx_id); + else + /* something went wrong with the event handling mechanism */ + BUG_ON(1); } /* @@ -531,6 +519,8 @@ static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data, * @ts_valid - Indicates whether ts parameter is valid, if this parameter * is false then it means that the calling function wants to disable the * IOMMU clocks immediately without waiting for any timestamp + * @ctx_id: Context id of the IOMMU context for which clocks are to be + * turned off * * Creates an event to disable the IOMMU clocks on timestamp and if event * already exists then updates the timestamp of disabling the IOMMU clocks @@ -539,28 +529,25 @@ static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data, * Return - void */ static void -kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts, - bool ts_valid) +kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, + unsigned int ts, int ctx_id) { - struct kgsl_iommu *iommu = mmu->priv; + struct kgsl_iommu_disable_clk_param *param; - if (iommu->clk_event_queued) { - if (ts_valid && (0 < - timestamp_cmp(ts, iommu->iommu_last_cmd_ts))) - iommu->iommu_last_cmd_ts = ts; - } else { - if (ts_valid) { - iommu->iommu_last_cmd_ts = ts; - iommu->clk_event_queued = true; - if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL, - ts, kgsl_iommu_clk_disable_event, mmu, mmu)) { - KGSL_DRV_ERR(mmu->device, - "Failed to add IOMMU disable clk event\n"); - iommu->clk_event_queued = false; - } - } else { - kgsl_iommu_disable_clk(mmu); - } + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*param)); + return; + } + param->mmu = mmu; + param->ctx_id = ctx_id; + param->ts = ts; + + if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL, + ts, kgsl_iommu_clk_disable_event, param, mmu)) { + KGSL_DRV_ERR(mmu->device, + "Failed to add IOMMU disable clk event\n"); + kfree(param); } } @@ -583,8 +570,7 @@ static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu, 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].clk_enabled || - ctx_id != iommu_unit->dev[j].ctx_id) + if (ctx_id != iommu_unit->dev[j].ctx_id) continue; iommu_drvdata = dev_get_drvdata(iommu_unit->dev[j].dev->parent); @@ -610,12 +596,25 @@ static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu, goto done; } } - iommu_unit->dev[j].clk_enabled = true; + atomic_inc(&iommu_unit->dev[j].clk_enable_count); } } done: - if (ret) - kgsl_iommu_disable_clk(mmu); + if (ret) { + struct kgsl_iommu_unit *iommu_unit; + if (iommu->unit_count == i) + i--; + iommu_unit = &iommu->iommu_units[i]; + do { + for (j--; j >= 0; j--) + kgsl_iommu_disable_clk(mmu, ctx_id); + i--; + if (i >= 0) { + iommu_unit = &iommu->iommu_units[i]; + j = iommu_unit->dev_count; + } + } while (i >= 0); + } return ret; } @@ -842,6 +841,9 @@ static int _get_iommu_ctxs(struct kgsl_mmu *mmu, ret = -EINVAL; goto done; } + atomic_set( + &(iommu_unit->dev[iommu_unit->dev_count].clk_enable_count), + 0); iommu_unit->dev[iommu_unit->dev_count].dev = msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name); @@ -1625,6 +1627,7 @@ static int kgsl_iommu_start(struct kgsl_mmu *mmu) } status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); if (status) { + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); KGSL_CORE_ERR("clk enable failed\n"); goto done; } @@ -1670,14 +1673,11 @@ static int kgsl_iommu_start(struct kgsl_mmu *mmu) KGSL_IOMMU_SETSTATE_NOP_OFFSET, cp_nop_packet(1), sizeof(unsigned int)); - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); 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; } @@ -1800,6 +1800,7 @@ static void kgsl_iommu_pagefault_resume(struct kgsl_mmu *mmu) iommu_unit, iommu_unit->dev[j].ctx_id, FSR, 0); + kgsl_iommu_disable_clk(mmu, j); _iommu_unlock(iommu); iommu_unit->dev[j].fault = 0; } @@ -1812,7 +1813,6 @@ static void kgsl_iommu_pagefault_resume(struct kgsl_mmu *mmu) static void kgsl_iommu_stop(struct kgsl_mmu *mmu) { - struct kgsl_iommu *iommu = mmu->priv; /* * stop device mmu * @@ -1828,9 +1828,7 @@ static void kgsl_iommu_stop(struct kgsl_mmu *mmu) kgsl_iommu_pagefault_resume(mmu); } /* 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_close(struct kgsl_mmu *mmu) @@ -1883,7 +1881,7 @@ kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu) pt_base = KGSL_IOMMU_GET_CTX_REG_TTBR0(iommu, (&iommu->iommu_units[0]), KGSL_IOMMU_CONTEXT_USER); - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); return pt_base & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK; } @@ -1911,7 +1909,6 @@ static int kgsl_iommu_default_setstate(struct kgsl_mmu *mmu, phys_addr_t pt_val; ret = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); - if (ret) { KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n"); return ret; @@ -1992,7 +1989,7 @@ unlock: _iommu_unlock(iommu); /* Disable smmu clock */ - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); return ret; } @@ -2072,13 +2069,14 @@ static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu, if (ret) { KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n"); - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); return ret; } /* Need to idle device before changing options */ ret = mmu->device->ftbl->idle(mmu->device); if (ret) { - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); return ret; } @@ -2101,7 +2099,8 @@ static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu, SCTLR, sctlr_val); } } - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); return ret; } diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h index 3b900dea663..85ab7dbee94 100644 --- a/drivers/gpu/msm/kgsl_iommu.h +++ b/drivers/gpu/msm/kgsl_iommu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. 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 @@ -155,6 +155,7 @@ struct kgsl_iommu_register_list { * are on, else the clocks are off * fault: Flag when set indicates that this iommu device has caused a page * fault + * @clk_enable_count: The ref count of clock enable calls */ struct kgsl_iommu_device { struct device *dev; @@ -164,6 +165,7 @@ struct kgsl_iommu_device { bool clk_enabled; struct kgsl_device *kgsldev; int fault; + atomic_t clk_enable_count; }; /* @@ -194,10 +196,6 @@ struct kgsl_iommu_unit { * iommu contexts owned by graphics cores * @unit_count: Number of IOMMU units that are available for this * instance of the IOMMU driver - * @iommu_last_cmd_ts: The timestamp of last command submitted that - * aceeses iommu registers - * @clk_event_queued: Indicates whether an event to disable clocks - * is already queued or not * @device: Pointer to kgsl device * @ctx_offset: The context offset to be added to base address when * accessing IOMMU registers @@ -213,8 +211,6 @@ struct kgsl_iommu_unit { struct kgsl_iommu { struct kgsl_iommu_unit iommu_units[KGSL_IOMMU_MAX_UNITS]; unsigned int unit_count; - unsigned int iommu_last_cmd_ts; - bool clk_event_queued; struct kgsl_device *device; unsigned int ctx_offset; struct kgsl_iommu_register_list *iommu_reg_list; @@ -234,4 +230,18 @@ struct kgsl_iommu_pt { struct kgsl_iommu *iommu; }; +/* + * struct kgsl_iommu_disable_clk_param - Parameter struct for disble clk event + * @mmu: The mmu pointer + * @rb_level: the rb level in which the timestamp of the event belongs to + * @ctx_id: The IOMMU context whose clock is to be turned off + * @ts: Timestamp on which clock is to be disabled + */ +struct kgsl_iommu_disable_clk_param { + struct kgsl_mmu *mmu; + int rb_level; + int ctx_id; + unsigned int ts; +}; + #endif diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 0d5f46454c1..8fb3a23e33f 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -99,11 +99,12 @@ struct kgsl_mmu_ops { void (*mmu_pagefault_resume) (struct kgsl_mmu *mmu); void (*mmu_disable_clk_on_ts) - (struct kgsl_mmu *mmu, uint32_t ts, bool ts_valid); + (struct kgsl_mmu *mmu, + uint32_t ts, int ctx_id); int (*mmu_enable_clk) (struct kgsl_mmu *mmu, int ctx_id); void (*mmu_disable_clk) - (struct kgsl_mmu *mmu); + (struct kgsl_mmu *mmu, int ctx_id); phys_addr_t (*mmu_get_default_ttbr0)(struct kgsl_mmu *mmu, unsigned int unit_id, enum kgsl_iommu_context_id ctx_id); @@ -275,17 +276,18 @@ static inline int kgsl_mmu_enable_clk(struct kgsl_mmu *mmu, return 0; } -static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu) +static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu, int ctx_id) { if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk) - mmu->mmu_ops->mmu_disable_clk(mmu); + mmu->mmu_ops->mmu_disable_clk(mmu, ctx_id); } static inline void kgsl_mmu_disable_clk_on_ts(struct kgsl_mmu *mmu, - unsigned int ts, bool ts_valid) + unsigned int ts, + int ctx_id) { if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk_on_ts) - mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ts_valid); + mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ctx_id); } static inline unsigned int kgsl_mmu_get_reg_gpuaddr(struct kgsl_mmu *mmu, diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 44c0a331430..7271e402e74 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1085,8 +1085,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) pwr->interval_timeout = pdata->idle_timeout; pwr->strtstp_sleepwake = pdata->strtstp_sleepwake; - /* Set the CPU latency to 501usec to allow low latency PC modes */ - pwr->pm_qos_latency = 501; + pwr->pm_qos_latency = pdata->pm_qos_latency; pm_runtime_enable(device->parentdev); @@ -1366,8 +1365,6 @@ _sleep(struct kgsl_device *device) break; } - kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false); - return 0; } |
