apm821xx: fix sata access freezes
authorChristian Lamparter <chunkeey@gmail.com>
Mon, 16 Jul 2018 20:56:34 +0000 (22:56 +0200)
committerMathias Kresin <dev@kresin.me>
Thu, 19 Jul 2018 16:54:40 +0000 (18:54 +0200)
The original vendor's driver programmed the dma controller's
AHB HPROT values to enable bufferable, privileged mode. This
along with the "same priorty for both channels" fixes the
freezes according to @takimata, @And.short, that have been
reported on the forum by @ticerex.

Furtheremore, @takimata reported that the patch also improved
the performance of the HDDs considerably:
|<https://forum.lede-project.org/t/wd-mybook-live-duo-two-disks/16195/55>
|It seems your patch unleashed the full power of the SATA port.
|Where I was previously hitting a really hard limit at around
|82 MB/s for reading and 27 MB/s for writing, I am now getting this:
|
|root@OpenWrt:/mnt# time dd if=/dev/zero of=tempfile bs=1M count=1024
|1024+0 records in
|1024+0 records out
|real    0m 13.65s
|user    0m 0.01s
|sys     0m 11.89s
|
|root@OpenWrt:/mnt# time dd if=tempfile of=/dev/null bs=1M count=1024
|1024+0 records in
|1024+0 records out
|real    0m 8.41s
|user    0m 0.01s
|sys     0m 4.70s
|
|This means: 121 MB/s reading and 75 MB/s writing!
|
|[...]
|
|The drive is a WD Green WD10EARX taken from an older MBL Single.
|I repeated the test a few times with even larger files to rule out
|any caching, I'm still seeing the same great performance. OpenWrt is
|now completely on par with the original MBL firmware's performance.

Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
target/linux/apm821xx/patches-4.14/302-dw-dma-hprot-fix-and-equal-priortiy.patch [new file with mode: 0644]

diff --git a/target/linux/apm821xx/patches-4.14/302-dw-dma-hprot-fix-and-equal-priortiy.patch b/target/linux/apm821xx/patches-4.14/302-dw-dma-hprot-fix-and-equal-priortiy.patch
new file mode 100644 (file)
index 0000000..c6e4331
--- /dev/null
@@ -0,0 +1,25 @@
+--- a/drivers/dma/dw/core.c
++++ b/drivers/dma/dw/core.c
+@@ -167,6 +167,8 @@ static void dwc_initialize_chan_dw(struc
+       cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
+       cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
++      cfghi |= DWC_CFGH_PROTCTL(3); /* bufferable + privileged access */
++
+       /* Set polarity of handshake interface */
+       cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0;
+@@ -1293,11 +1295,8 @@ int dw_dma_probe(struct dw_dma_chip *chi
+               else
+                       list_add(&dwc->chan.device_node, &dw->dma.channels);
+-              /* 7 is highest priority & 0 is lowest. */
+-              if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
+-                      dwc->priority = pdata->nr_channels - i - 1;
+-              else
+-                      dwc->priority = i;
++              /* set all channels to the same priority */
++              dwc->priority = pdata->nr_channels - 1;
+               dwc->ch_regs = &__dw_regs(dw)->CHAN[i];
+               spin_lock_init(&dwc->lock);