Skip to contentSkip to conversation

ARM: omap: edma: add suspend resume hook

PATCH New Daniel Mack 4 participants 9 messages Aug 26, 2014 – Nov 17, 2014 Arm (32-bit)

lore
Share & tools
lore
#0 lore raw

PATCH v9 1/1 ARM: omap: edma: add suspend resume hook

This patch makes the edma driver resume correctly after suspend. Tested on an AM33xx platform with cyclic audio streams and omap_hsmmc.

All information can be reconstructed by already known runtime information.

As we now use some functions that were previously only used from __init context, annotations had to be dropped.

[nm at ti.com: added error handling for runtime + suspend_late/early_resume]

---
Changes from v8:

* Drop the edma_suspend hook altogether. Even though back then when I wrote the code I was sure disabling the interrupts during suspend is necessary, tests now show it in fact isn't. My test setup still works if that code is omitted.
* Use SET_LATE_SYSTEM_SLEEP_PM_OPS in the dev_pm_ops declaration.

Thanks to Sekhar for pointing out the above.

 arch/arm/common/edma.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)
arch/arm/common/edma.c +58 -2
index 485be42..c623dd0 100644
@@ -244,6 +244,8 @@ struct edma {
 	/* list of channels with no even trigger; terminated by "-1" */
 	const s8	*noevent;
 
+	struct edma_soc_info *info;
+
 	/* The edma_inuse bit for each PaRAM slot is clear unless the
 	 * channel is in use ... by ARM or DSP, for QDMA, or whatever.
 	 */
@@ -295,7 +297,7 @@ static void map_dmach_queue(unsigned ctlr, unsigned ch_no,
 			~(0x7 << bit), queue_no << bit);
 }
 
-static void __init assign_priority_to_queue(unsigned ctlr, int queue_no,
+static void assign_priority_to_queue(unsigned ctlr, int queue_no,
 		int priority)
 {
 	int bit = queue_no * 4;
@@ -314,7 +316,7 @@ static void __init assign_priority_to_queue(unsigned ctlr, int queue_no,
  * included in that particular EDMA variant (Eg : dm646x)
  *
  */
-static void __init map_dmach_param(unsigned ctlr)
+static void map_dmach_param(unsigned ctlr)
 {
 	int i;
 	for (i = 0; i < EDMA_MAX_DMACH; i++)
@@ -1762,15 +1764,69 @@ static int edma_probe(struct platform_device *pdev)
 			edma_write_array2(j, EDMA_DRAE, i, 1, 0x0);
 			edma_write_array(j, EDMA_QRAE, i, 0x0);
 		}
+		edma_cc[j]->info = info[j];
 		arch_num_cc++;
 	}
 
 	return 0;
 }
 
+static int edma_pm_resume(struct device *dev)
+{
+	int i, j, r;
+
+	r = pm_runtime_get_sync(dev);
+	if (r < 0) {
+		dev_err(dev, "%s: get_sync returned %d\n", __func__, r);
+		return r;
+	}
+
+	for (j = 0; j < arch_num_cc; j++) {
+		struct edma *cc = edma_cc[j];
+
+		s8 (*queue_priority_mapping)[2];
+
+		queue_priority_mapping = cc->info->queue_priority_mapping;
+
+		/* Event queue priority mapping */
+		for (i = 0; queue_priority_mapping[i][0] != -1; i++)
+			assign_priority_to_queue(j,
+						 queue_priority_mapping[i][0],
+						 queue_priority_mapping[i][1]);
+
+		/*
+		 * Map the channel to param entry if channel mapping logic
+		 * exist
+		 */
+		if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST)
+			map_dmach_param(j);
+
+		for (i = 0; i < cc->num_channels; i++) {
+			if (test_bit(i, cc->edma_inuse)) {
+				/* ensure access through shadow region 0 */
+				edma_or_array2(j, EDMA_DRAE, 0, i >> 5,
+					       BIT(i & 0x1f));
+
+				setup_dma_interrupt(i,
+						    cc->intr_data[i].callback,
+						    cc->intr_data[i].data);
+			}
+		}
+	}
+
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops edma_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, edma_pm_resume)
+};
+
 static struct platform_driver edma_driver = {
 	.driver = {
 		.name	= "edma",
+		.pm	= &edma_pm_ops,
 		.of_match_table = edma_of_ids,
 	},
 	.probe = edma_probe,
Signature · 1 line
2.1.0
#1 lore raw

PATCH v9 1/1 ARM: omap: edma: add suspend resume hook

Quoted 24 lines · Daniel Mack

This patch makes the edma driver resume correctly after suspend. Tested on an AM33xx platform with cyclic audio streams and omap_hsmmc.

All information can be reconstructed by already known runtime information.

As we now use some functions that were previously only used from __init context, annotations had to be dropped.

[nm at ti.com: added error handling for runtime + suspend_late/early_resume]

---
Changes from v8:

* Drop the edma_suspend hook altogether. Even though back then when I wrote the code I was sure disabling the interrupts during suspend is necessary, tests now show it in fact isn't. My test setup still works if that code is omitted.
* Use SET_LATE_SYSTEM_SLEEP_PM_OPS in the dev_pm_ops declaration.

Quoted 4 lines

Thanks to Sekhar for pointing out the above.

 arch/arm/common/edma.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)

Doesn't seem to be any comments here, any chance this can be picked up? This patch always seems to get missed but will be needed for suspend/resume on both AM335x and AM437x.

Regards,
Dave

Quoted 103 lines
arch/arm/common/edma.c +58 -2
index 485be42..c623dd0 100644
@@ -244,6 +244,8 @@ struct edma {
 	/* list of channels with no even trigger; terminated by "-1" */
 	const s8	*noevent;
 
+	struct edma_soc_info *info;
+
 	/* The edma_inuse bit for each PaRAM slot is clear unless the
 	 * channel is in use ... by ARM or DSP, for QDMA, or whatever.
 	 */
@@ -295,7 +297,7 @@ static void map_dmach_queue(unsigned ctlr, unsigned ch_no,
 			~(0x7 << bit), queue_no << bit);
 }
 
-static void __init assign_priority_to_queue(unsigned ctlr, int queue_no,
+static void assign_priority_to_queue(unsigned ctlr, int queue_no,
 		int priority)
 {
 	int bit = queue_no * 4;
@@ -314,7 +316,7 @@ static void __init assign_priority_to_queue(unsigned ctlr, int queue_no,
  * included in that particular EDMA variant (Eg : dm646x)
  *
  */
-static void __init map_dmach_param(unsigned ctlr)
+static void map_dmach_param(unsigned ctlr)
 {
 	int i;
 	for (i = 0; i < EDMA_MAX_DMACH; i++)
@@ -1762,15 +1764,69 @@ static int edma_probe(struct platform_device *pdev)
 			edma_write_array2(j, EDMA_DRAE, i, 1, 0x0);
 			edma_write_array(j, EDMA_QRAE, i, 0x0);
 		}
+		edma_cc[j]->info = info[j];
 		arch_num_cc++;
 	}
 
 	return 0;
 }
 
+static int edma_pm_resume(struct device *dev)
+{
+	int i, j, r;
+
+	r = pm_runtime_get_sync(dev);
+	if (r < 0) {
+		dev_err(dev, "%s: get_sync returned %d\n", __func__, r);
+		return r;
+	}
+
+	for (j = 0; j < arch_num_cc; j++) {
+		struct edma *cc = edma_cc[j];
+
+		s8 (*queue_priority_mapping)[2];
+
+		queue_priority_mapping = cc->info->queue_priority_mapping;
+
+		/* Event queue priority mapping */
+		for (i = 0; queue_priority_mapping[i][0] != -1; i++)
+			assign_priority_to_queue(j,
+						 queue_priority_mapping[i][0],
+						 queue_priority_mapping[i][1]);
+
+		/*
+		 * Map the channel to param entry if channel mapping logic
+		 * exist
+		 */
+		if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST)
+			map_dmach_param(j);
+
+		for (i = 0; i < cc->num_channels; i++) {
+			if (test_bit(i, cc->edma_inuse)) {
+				/* ensure access through shadow region 0 */
+				edma_or_array2(j, EDMA_DRAE, 0, i >> 5,
+					       BIT(i & 0x1f));
+
+				setup_dma_interrupt(i,
+						    cc->intr_data[i].callback,
+						    cc->intr_data[i].data);
+			}
+		}
+	}
+
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops edma_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, edma_pm_resume)
+};
+
 static struct platform_driver edma_driver = {
 	.driver = {
 		.name	= "edma",
+		.pm	= &edma_pm_ops,
 		.of_match_table = edma_of_ids,
 	},
 	.probe = edma_probe,
#2 lore raw

PATCH v9 1/1 ARM: omap: edma: add suspend resume hook

Quoted 25 lines · Dave Gerlach
Quoted 24 lines · Daniel Mack

This patch makes the edma driver resume correctly after suspend. Tested on an AM33xx platform with cyclic audio streams and omap_hsmmc.

All information can be reconstructed by already known runtime information.

As we now use some functions that were previously only used from __init context, annotations had to be dropped.

[nm at ti.com: added error handling for runtime + suspend_late/early_resume]

---
Changes from v8:

* Drop the edma_suspend hook altogether. Even though back then when I wrote the code I was sure disabling the interrupts during suspend is necessary, tests now show it in fact isn't. My test setup still works if that code is omitted.
* Use SET_LATE_SYSTEM_SLEEP_PM_OPS in the dev_pm_ops declaration.

Quoted 8 lines
Quoted 4 lines

Thanks to Sekhar for pointing out the above.

 arch/arm/common/edma.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)

Doesn't seem to be any comments here, any chance this can be picked up? This patch always seems to get missed but will be needed for suspend/resume on both AM335x and AM437x.

Dave, do you have a branch against mainline with suspend working on any of these SoCs using which I can test this patch?

Thanks,
Sekhar

#3 lore raw

PATCH v9 1/1 ARM: omap: edma: add suspend resume hook

Sekhar,

Quoted 31 lines · Sekhar Nori
Quoted 30 lines · Dave Gerlach
Quoted 28 lines · Daniel Mack

This patch makes the edma driver resume correctly after suspend. Tested on an AM33xx platform with cyclic audio streams and omap_hsmmc.

All information can be reconstructed by already known runtime information.

As we now use some functions that were previously only used from __init context, annotations had to be dropped.

[nm at ti.com: added error handling for runtime + suspend_late/early_resume]

---
Changes from v8:

* Drop the edma_suspend hook altogether. Even though back then when I wrote the code I was sure disabling the interrupts during suspend is necessary, tests now show it in fact isn't. My test setup still works if that code is omitted.
* Use SET_LATE_SYSTEM_SLEEP_PM_OPS in the dev_pm_ops declaration.

Thanks to Sekhar for pointing out the above.

 arch/arm/common/edma.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)
Quoted 6 lines
Quoted 3 lines

Doesn't seem to be any comments here, any chance this can be picked up? This patch always seems to get missed but will be needed for suspend/resume on both AM335x and AM437x.

Dave, do you have a branch against mainline with suspend working on any of these SoCs using which I can test this patch?

Yes, here is WIP of next version with all required patches + this one.
https://github.com/dgerlach/linux-pm/tree/pm-ds0-v3.18-rc3-WIP

For suspend to work you need to select:

CONFIG_WKUP_M3_IPC=y
CONFIG_WKUP_M3_RPROC=y

And you need to enable USB for multiple suspends to work.

You can get am335x-pm-firmware.elf FW here from HEAD:
https://git.ti.com/ti-cm3-pm-firmware/amx3-cm3/commits/next

You can place in /lib/firmware and select CONFIG_FW_LOADER_USER_HELPER_FALLBACK or build into kernel.

Also for what it's worth you can have my tested by:

I have tested on am335x-boneblack, am335x-evm, and am335x-evmsk, multiple suspend cycles work with no issue.

Regards,
Dave

Quoted 4 lines

Thanks,
Sekhar

#4 lore raw

PATCH v9 1/1 ARM: omap: edma: add suspend resume hook

Quoted 40 lines · Dave Gerlach

Sekhar,

Quoted 31 lines · Sekhar Nori
Quoted 30 lines · Dave Gerlach
Quoted 28 lines · Daniel Mack

This patch makes the edma driver resume correctly after suspend. Tested on an AM33xx platform with cyclic audio streams and omap_hsmmc.

All information can be reconstructed by already known runtime information.

As we now use some functions that were previously only used from __init context, annotations had to be dropped.

[nm at ti.com: added error handling for runtime + suspend_late/early_resume]

---
Changes from v8:

* Drop the edma_suspend hook altogether. Even though back then when I wrote the code I was sure disabling the interrupts during suspend is necessary, tests now show it in fact isn't. My test setup still works if that code is omitted.
* Use SET_LATE_SYSTEM_SLEEP_PM_OPS in the dev_pm_ops declaration.

Thanks to Sekhar for pointing out the above.

 arch/arm/common/edma.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)
Quoted 6 lines
Quoted 3 lines

Doesn't seem to be any comments here, any chance this can be picked up? This patch always seems to get missed but will be needed for suspend/resume on both AM335x and AM437x.

Dave, do you have a branch against mainline with suspend working on any of these SoCs using which I can test this patch?

Quoted 7 lines

Yes, here is WIP of next version with all required patches + this one.
https://github.com/dgerlach/linux-pm/tree/pm-ds0-v3.18-rc3-WIP

For suspend to work you need to select:

CONFIG_WKUP_M3_IPC=y
CONFIG_WKUP_M3_RPROC=y

I get this:

arch/arm/mach-omap2/pm33xx.c:28:31: fatal error: linux/wkup_m3_ipc.h: No such file or directory

 #include <linux/wkup_m3_ipc.h>
                               ^

compilation terminated.
make[1]: *** [arch/arm/mach-omap2/pm33xx.o] Error 1

Forgot to commit wkup_m3_ipc.h?

Thanks,
Sekhar

#5 lore raw

PATCH v9 1/1 ARM: omap: edma: add suspend resume hook

Sekhar,

Quoted 51 lines · Sekhar Nori
Quoted 40 lines · Dave Gerlach

Sekhar,

Quoted 31 lines · Sekhar Nori
Quoted 30 lines · Dave Gerlach
Quoted 28 lines · Daniel Mack

This patch makes the edma driver resume correctly after suspend. Tested on an AM33xx platform with cyclic audio streams and omap_hsmmc.

All information can be reconstructed by already known runtime information.

As we now use some functions that were previously only used from __init context, annotations had to be dropped.

[nm at ti.com: added error handling for runtime + suspend_late/early_resume]

---
Changes from v8:

* Drop the edma_suspend hook altogether. Even though back then when I wrote the code I was sure disabling the interrupts during suspend is necessary, tests now show it in fact isn't. My test setup still works if that code is omitted.
* Use SET_LATE_SYSTEM_SLEEP_PM_OPS in the dev_pm_ops declaration.

Thanks to Sekhar for pointing out the above.

 arch/arm/common/edma.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)
Quoted 6 lines
Quoted 3 lines

Doesn't seem to be any comments here, any chance this can be picked up? This patch always seems to get missed but will be needed for suspend/resume on both AM335x and AM437x.

Dave, do you have a branch against mainline with suspend working on any of these SoCs using which I can test this patch?

Quoted 7 lines

Yes, here is WIP of next version with all required patches + this one.
https://github.com/dgerlach/linux-pm/tree/pm-ds0-v3.18-rc3-WIP

For suspend to work you need to select:

CONFIG_WKUP_M3_IPC=y
CONFIG_WKUP_M3_RPROC=y

I get this:

Quoted 8 lines

arch/arm/mach-omap2/pm33xx.c:28:31: fatal error: linux/wkup_m3_ipc.h: No such file or directory

 #include <linux/wkup_m3_ipc.h>
                               ^

compilation terminated.
make[1]: *** [arch/arm/mach-omap2/pm33xx.o] Error 1

Forgot to commit wkup_m3_ipc.h?

Ahhh sorry about that, looks like I dropped it during a rebase. Added it in a patch and pushed that on top of the tree from yesterday. Sorry again!.

Regards,
Dave

Quoted 4 lines

Thanks,
Sekhar

#6 lore raw

PATCH v9 1/1 ARM: omap: edma: add suspend resume hook

In reply to Daniel Mack
Quoted 66 lines · Daniel Mack

This patch makes the edma driver resume correctly after suspend. Tested on an AM33xx platform with cyclic audio streams and omap_hsmmc.

All information can be reconstructed by already known runtime information.

As we now use some functions that were previously only used from __init context, annotations had to be dropped.

[nm at ti.com: added error handling for runtime + suspend_late/early_resume]

---
Changes from v8:

* Drop the edma_suspend hook altogether. Even though back then when I wrote the code I was sure disabling the interrupts during suspend is necessary, tests now show it in fact isn't. My test setup still works if that code is omitted.
* Use SET_LATE_SYSTEM_SLEEP_PM_OPS in the dev_pm_ops declaration.

Thanks to Sekhar for pointing out the above.

 arch/arm/common/edma.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)
arch/arm/common/edma.c +5 -2
index 485be42..c623dd0 100644
@@ -244,6 +244,8 @@ struct edma {
 	/* list of channels with no even trigger; terminated by "-1" */
 	const s8	*noevent;
 
+	struct edma_soc_info *info;
+
 	/* The edma_inuse bit for each PaRAM slot is clear unless the
 	 * channel is in use ... by ARM or DSP, for QDMA, or whatever.
 	 */
@@ -295,7 +297,7 @@ static void map_dmach_queue(unsigned ctlr, unsigned ch_no,
 			~(0x7 << bit), queue_no << bit);
 }
 
-static void __init assign_priority_to_queue(unsigned ctlr, int queue_no,
+static void assign_priority_to_queue(unsigned ctlr, int queue_no,
 		int priority)
 {
 	int bit = queue_no * 4;
@@ -314,7 +316,7 @@ static void __init assign_priority_to_queue(unsigned ctlr, int queue_no,
  * included in that particular EDMA variant (Eg : dm646x)
  *
  */
-static void __init map_dmach_param(unsigned ctlr)
+static void map_dmach_param(unsigned ctlr)
 {
 	int i;
 	for (i = 0; i < EDMA_MAX_DMACH; i++)
@@ -1762,15 +1764,69 @@ static int edma_probe(struct platform_device *pdev)
 			edma_write_array2(j, EDMA_DRAE, i, 1, 0x0);
 			edma_write_array(j, EDMA_QRAE, i, 0x0);
 		}
+		edma_cc[j]->info = info[j];
 		arch_num_cc++;

arch/arm/common/edma.c static int edma_probe(struct platform_device *pdev) · line 1778

Quoted 10 lines
arch/arm/common/edma.c +5 -0
 	}
 
 	return 0;
 }
 
+static int edma_pm_resume(struct device *dev)
+{
+	int i, j, r;
+
+	r = pm_runtime_get_sync(dev);

I think I have asked this before, and I am still not sure why this call to pm_runtime_get_sync() is needed here. From my testing today, this does seem to be a a no-op and this call returns from rpm_resume() because of this check:

	else if (dev->power.disable_depth == 1 && dev->power.is_suspended
	    && dev->power.runtime_status == RPM_ACTIVE)
		retval = 1;

So, AFAICS, the net effect is an increment of dev->power.usage_count (which is already greater than 0) and its subsequent decrement at the end of the function.

After removing this call I did not see any EDMA malfunction as well (can access MMC/SD just fine after suspend/resume cycle).

So, any objections to merging this patch with the attached hunk applied?

Thanks,
Sekhar

---8<---

arch/arm/common/edma.c +1 -9
index 1f492d5be9c0..79de6a23047b 100644
@@ -1803,13 +1803,7 @@ static int edma_probe(struct platform_device *pdev)
 
 static int edma_pm_resume(struct device *dev)
 {
-       int i, j, r;
-
-       r = pm_runtime_get_sync(dev);
-       if (r < 0) {
-               dev_err(dev, "%s: get_sync returned %d\n", __func__, r);
-               return r;
-       }
+       int i, j;
 
        for (j = 0; j < arch_num_cc; j++) {
                struct edma *cc = edma_cc[j];
@@ -1844,8 +1838,6 @@ static int edma_pm_resume(struct device *dev)
                }
        }
 
-       pm_runtime_put_sync(dev);
-
        return 0;
 }
#7 lore raw

PATCH v9 1/1 ARM: omap: edma: add suspend resume hook

Hi Sekhar,

Quoted 8 lines · Sekhar Nori

I think I have asked this before, and I am still not sure why this call to pm_runtime_get_sync() is needed here. From my testing today, this does seem to be a a no-op and this call returns from rpm_resume() because of this check:

	else if (dev->power.disable_depth == 1 && dev->power.is_suspended
	    && dev->power.runtime_status == RPM_ACTIVE)
		retval = 1;

Yes. IIRC, it was in fact not needed.

Quoted 9 lines

So, AFAICS, the net effect is an increment of dev->power.usage_count (which is already greater than 0) and its subsequent decrement at the end of the function.

After removing this call I did not see any EDMA malfunction as well (can access MMC/SD just fine after suspend/resume cycle).

So, any objections to merging this patch with the attached hunk applied?

Looks good to me, we can still add it back later if it turns out to be needed.

Thanks,
Daniel

Quoted 33 lines

Thanks,
Sekhar

---8<---

arch/arm/common/edma.c +1 -9
index 1f492d5be9c0..79de6a23047b 100644
@@ -1803,13 +1803,7 @@ static int edma_probe(struct platform_device *pdev)
 
 static int edma_pm_resume(struct device *dev)
 {
-       int i, j, r;
-
-       r = pm_runtime_get_sync(dev);
-       if (r < 0) {
-               dev_err(dev, "%s: get_sync returned %d\n", __func__, r);
-               return r;
-       }
+       int i, j;
 
        for (j = 0; j < arch_num_cc; j++) {
                struct edma *cc = edma_cc[j];
@@ -1844,8 +1838,6 @@ static int edma_pm_resume(struct device *dev)
                }
        }
 
-       pm_runtime_put_sync(dev);
-
        return 0;
 }
 
#8 lore raw

PATCH v9 1/1 ARM: omap: edma: add suspend resume hook

Quoted 18 lines · Daniel Mack

Hi Sekhar,

Quoted 8 lines · Sekhar Nori

I think I have asked this before, and I am still not sure why this call to pm_runtime_get_sync() is needed here. From my testing today, this does seem to be a a no-op and this call returns from rpm_resume() because of this check:

	else if (dev->power.disable_depth == 1 && dev->power.is_suspended
	    && dev->power.runtime_status == RPM_ACTIVE)
		retval = 1;

Yes. IIRC, it was in fact not needed.

Quoted 4 lines

So, AFAICS, the net effect is an increment of dev->power.usage_count (which is already greater than 0) and its subsequent decrement at the end of the function.

Quoted 8 lines
Quoted 5 lines

After removing this call I did not see any EDMA malfunction as well (can access MMC/SD just fine after suspend/resume cycle).

So, any objections to merging this patch with the attached hunk applied?

Looks good to me, we can still add it back later if it turns out to be needed.

Okay, thanks for the confirmation.

Regards,
Sekhar