This patch adds a new device-tree property that allows to specify the dma protection control bits for the all of the DMA controller's channel uniformly. Setting the "correct" bits can have a huge impact on the PPC460EX and APM82181 that use this DMA engine in combination with a DesignWare' SATA-II core (sata_dwc_460ex driver). In the OpenWrt Forum, the user takimata reported that: |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. Another user And.short reported: |I can report that your fix worked! Boots up fine with two |drives even with more partitions, and no more reboot on |concurrent disk access! A closer look into the sata_dwc_460ex code revealed that the driver did initally set the correct protection control bits. However, this feature was lost when the sata_dwc_460ex driver was converted to the generic DMA driver framework.
Showing the changes to include/linux/platform_data (1 of 4 files). Show all
Unified · Split
| @@ -49,6 +49,7 @@ struct dw_dma_slave { · 48 unmodified lines | ||
| 49 | 49 | * @data_width: Maximum data width supported by hardware per AHB master |
| 50 | 50 | * (in bytes, power of 2) |
| 51 | 51 | * @multi_block: Multi block transfers supported by hardware per channel. |
| 52 | + * @protctl: Protection control signals setting per channel. | |
| 52 | 53 | */ |
| 53 | 54 | struct dw_dma_platform_data { |
| 54 | 55 | unsigned int nr_channels; |
| @@ -65,6 +66,11 @@ struct dw_dma_platform_data { · 10 unmodified lines | ||
| 65 | 66 | unsigned char nr_masters; |
| 66 | 67 | unsigned char data_width[DW_DMA_MAX_NR_MASTERS]; |
| 67 | 68 | unsigned char multi_block[DW_DMA_MAX_NR_CHANNELS]; |
| 69 | +#define CHAN_PROTCTL_PRIVILEGED BIT(0) | |
| 70 | +#define CHAN_PROTCTL_BUFFERABLE BIT(1) | |
| 71 | +#define CHAN_PROTCTL_CACHEABLE BIT(2) | |
| 72 | +#define CHAN_PROTCTL_MASK GENMASK(2, 0) | |
| 73 | + unsigned char protctl; | |
| 68 | 74 | }; |
| 69 | 75 | |
| 70 | 76 | #endif /* _PLATFORM_DATA_DMA_DW_H */ |