aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/msm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/msm')
-rw-r--r--drivers/gpu/msm/adreno.c12
-rw-r--r--drivers/gpu/msm/adreno_a4xx_snapshot.c8
-rw-r--r--drivers/gpu/msm/adreno_ringbuffer.c3
-rw-r--r--drivers/gpu/msm/kgsl_iommu.c133
-rw-r--r--drivers/gpu/msm/kgsl_iommu.h24
-rw-r--r--drivers/gpu/msm/kgsl_mmu.h14
-rw-r--r--drivers/gpu/msm/kgsl_pwrctrl.c5
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;
}