diff mbox series

[v2,3/4] dmaengine: sun6i: Add support for 34-bit physical addresses

Message ID 20220411044633.39014-4-samuel@sholland.org (mailing list archive)
State New, archived
Headers show
Series dmaengine: sun6i: Allwinner D1 support | expand

Commit Message

Samuel Holland April 11, 2022, 4:46 a.m. UTC
Recent Allwinner SoCs support >4 GiB of DRAM, so those variants of the
DMA engine support >32 bit physical addresses. This is accomplished by
placing the high bits in the "para" word in the DMA descriptor.

DMA descriptors themselves can be located at >32 bit addresses by
putting the high bits in the LSBs of the descriptor address register,
taking advantage of the required DMA descriptor alignment. However,
support for this is not really necessary, so we can avoid the
complication by allocating them from the DMA_32 zone.

Acked-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Samuel Holland <samuel@sholland.org>
---

Changes in v2:
 - Fix `checkpatch.pl --strict` style issues (missing spaces)

 drivers/dma/sun6i-dma.c | 39 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 5 deletions(-)

Comments

kernel test robot April 11, 2022, 12:03 p.m. UTC | #1
Hi Samuel,

I love your patch! Perhaps something to improve:

[auto build test WARNING on vkoul-dmaengine/next]
[also build test WARNING on sunxi/sunxi/for-next v5.18-rc2 next-20220411]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Samuel-Holland/dmaengine-sun6i-Allwinner-D1-support/20220411-124826
base:   https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git next
config: nios2-randconfig-r011-20220410 (https://download.01.org/0day-ci/archive/20220411/202204111937.ZQ1e600D-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/2e9c7977b871d504bca4e9ee88d3b322a21f3fb7
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Samuel-Holland/dmaengine-sun6i-Allwinner-D1-support/20220411-124826
        git checkout 2e9c7977b871d504bca4e9ee88d3b322a21f3fb7
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=nios2 SHELL=/bin/bash drivers/dma/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from include/linux/device.h:15,
                    from include/linux/dmaengine.h:8,
                    from drivers/dma/sun6i-dma.c:12:
   drivers/dma/sun6i-dma.c: In function 'sun6i_dma_dump_chan_regs':
   drivers/dma/sun6i-dma.c:259:34: warning: format '%lx' expects argument of type 'long unsigned int', but argument 5 has type 'int' [-Wformat=]
     259 |         dev_dbg(sdev->slave.dev, "Chan %d reg: 0x%lx\n"
         |                                  ^~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:129:41: note: in definition of macro 'dev_printk'
     129 |                 _dev_printk(level, dev, fmt, ##__VA_ARGS__);            \
         |                                         ^~~
   include/linux/dev_printk.h:158:37: note: in expansion of macro 'dev_fmt'
     158 |         dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                     ^~~~~~~
   drivers/dma/sun6i-dma.c:259:9: note: in expansion of macro 'dev_dbg'
     259 |         dev_dbg(sdev->slave.dev, "Chan %d reg: 0x%lx\n"
         |         ^~~~~~~
   drivers/dma/sun6i-dma.c:259:52: note: format string is defined here
     259 |         dev_dbg(sdev->slave.dev, "Chan %d reg: 0x%lx\n"
         |                                                  ~~^
         |                                                    |
         |                                                    long unsigned int
         |                                                  %x
   drivers/dma/sun6i-dma.c: In function 'sun6i_dma_prep_dma_memcpy':
>> drivers/dma/sun6i-dma.c:99:48: warning: right shift count >= width of type [-Wshift-count-overflow]
      99 | #define SET_SRC_HIGH_ADDR(x)            ((((x) >> 32) & 0x3U) << 16)
         |                                                ^~
   drivers/dma/sun6i-dma.c:674:32: note: in expansion of macro 'SET_SRC_HIGH_ADDR'
     674 |                 v_lli->para |= SET_SRC_HIGH_ADDR(src) |
         |                                ^~~~~~~~~~~~~~~~~
   drivers/dma/sun6i-dma.c:100:48: warning: right shift count >= width of type [-Wshift-count-overflow]
     100 | #define SET_DST_HIGH_ADDR(x)            ((((x) >> 32) & 0x3U) << 18)
         |                                                ^~
   drivers/dma/sun6i-dma.c:675:32: note: in expansion of macro 'SET_DST_HIGH_ADDR'
     675 |                                SET_DST_HIGH_ADDR(dest);
         |                                ^~~~~~~~~~~~~~~~~
   drivers/dma/sun6i-dma.c: In function 'sun6i_dma_prep_slave_sg':
>> drivers/dma/sun6i-dma.c:99:48: warning: right shift count >= width of type [-Wshift-count-overflow]
      99 | #define SET_SRC_HIGH_ADDR(x)            ((((x) >> 32) & 0x3U) << 16)
         |                                                ^~
   drivers/dma/sun6i-dma.c:737:48: note: in expansion of macro 'SET_SRC_HIGH_ADDR'
     737 |                                 v_lli->para |= SET_SRC_HIGH_ADDR(sg_dma_address(sg)) |
         |                                                ^~~~~~~~~~~~~~~~~
   drivers/dma/sun6i-dma.c:100:48: warning: right shift count >= width of type [-Wshift-count-overflow]
     100 | #define SET_DST_HIGH_ADDR(x)            ((((x) >> 32) & 0x3U) << 18)
         |                                                ^~
   drivers/dma/sun6i-dma.c:738:48: note: in expansion of macro 'SET_DST_HIGH_ADDR'
     738 |                                                SET_DST_HIGH_ADDR(sconfig->dst_addr);
         |                                                ^~~~~~~~~~~~~~~~~
>> drivers/dma/sun6i-dma.c:99:48: warning: right shift count >= width of type [-Wshift-count-overflow]
      99 | #define SET_SRC_HIGH_ADDR(x)            ((((x) >> 32) & 0x3U) << 16)
         |                                                ^~
   drivers/dma/sun6i-dma.c:753:48: note: in expansion of macro 'SET_SRC_HIGH_ADDR'
     753 |                                 v_lli->para |= SET_SRC_HIGH_ADDR(sconfig->src_addr) |
         |                                                ^~~~~~~~~~~~~~~~~
   drivers/dma/sun6i-dma.c:100:48: warning: right shift count >= width of type [-Wshift-count-overflow]
     100 | #define SET_DST_HIGH_ADDR(x)            ((((x) >> 32) & 0x3U) << 18)
         |                                                ^~
   drivers/dma/sun6i-dma.c:754:48: note: in expansion of macro 'SET_DST_HIGH_ADDR'
     754 |                                                SET_DST_HIGH_ADDR(sg_dma_address(sg));
         |                                                ^~~~~~~~~~~~~~~~~
   drivers/dma/sun6i-dma.c: In function 'sun6i_dma_prep_dma_cyclic':
>> drivers/dma/sun6i-dma.c:99:48: warning: right shift count >= width of type [-Wshift-count-overflow]
      99 | #define SET_SRC_HIGH_ADDR(x)            ((((x) >> 32) & 0x3U) << 16)
         |                                                ^~
   drivers/dma/sun6i-dma.c:826:48: note: in expansion of macro 'SET_SRC_HIGH_ADDR'
     826 |                                 v_lli->para |= SET_SRC_HIGH_ADDR(buf_addr + period_len * i) |
         |                                                ^~~~~~~~~~~~~~~~~
   drivers/dma/sun6i-dma.c:100:48: warning: right shift count >= width of type [-Wshift-count-overflow]
     100 | #define SET_DST_HIGH_ADDR(x)            ((((x) >> 32) & 0x3U) << 18)
         |                                                ^~
   drivers/dma/sun6i-dma.c:827:48: note: in expansion of macro 'SET_DST_HIGH_ADDR'
     827 |                                                SET_DST_HIGH_ADDR(sconfig->dst_addr);
         |                                                ^~~~~~~~~~~~~~~~~
>> drivers/dma/sun6i-dma.c:99:48: warning: right shift count >= width of type [-Wshift-count-overflow]
      99 | #define SET_SRC_HIGH_ADDR(x)            ((((x) >> 32) & 0x3U) << 16)
         |                                                ^~
   drivers/dma/sun6i-dma.c:835:48: note: in expansion of macro 'SET_SRC_HIGH_ADDR'
     835 |                                 v_lli->para |= SET_SRC_HIGH_ADDR(sconfig->src_addr) |
         |                                                ^~~~~~~~~~~~~~~~~
   drivers/dma/sun6i-dma.c:100:48: warning: right shift count >= width of type [-Wshift-count-overflow]
     100 | #define SET_DST_HIGH_ADDR(x)            ((((x) >> 32) & 0x3U) << 18)
         |                                                ^~
   drivers/dma/sun6i-dma.c:836:48: note: in expansion of macro 'SET_DST_HIGH_ADDR'
     836 |                                                SET_DST_HIGH_ADDR(buf_addr + period_len * i);
         |                                                ^~~~~~~~~~~~~~~~~


vim +99 drivers/dma/sun6i-dma.c

    92	
    93	/*
    94	 * LLI address mangling
    95	 *
    96	 * The LLI link physical address is also mangled, but we avoid dealing
    97	 * with that by allocating LLIs from the DMA32 zone.
    98	 */
  > 99	#define SET_SRC_HIGH_ADDR(x)		((((x) >> 32) & 0x3U) << 16)
   100	#define SET_DST_HIGH_ADDR(x)		((((x) >> 32) & 0x3U) << 18)
   101
diff mbox series

Patch

diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index a9334f969b28..bd5958185ed1 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -90,6 +90,14 @@ 
 
 #define DMA_CHAN_CUR_PARA	0x1c
 
+/*
+ * LLI address mangling
+ *
+ * The LLI link physical address is also mangled, but we avoid dealing
+ * with that by allocating LLIs from the DMA32 zone.
+ */
+#define SET_SRC_HIGH_ADDR(x)		((((x) >> 32) & 0x3U) << 16)
+#define SET_DST_HIGH_ADDR(x)		((((x) >> 32) & 0x3U) << 18)
 
 /*
  * Various hardware related defines
@@ -132,6 +140,7 @@  struct sun6i_dma_config {
 	u32 dst_burst_lengths;
 	u32 src_addr_widths;
 	u32 dst_addr_widths;
+	bool has_high_addr;
 	bool has_mbus_clk;
 };
 
@@ -223,6 +232,12 @@  to_sun6i_desc(struct dma_async_tx_descriptor *tx)
 	return container_of(tx, struct sun6i_desc, vd.tx);
 }
 
+static inline bool sun6i_dma_has_high_addr(struct sun6i_dma_dev *sdev)
+{
+	return IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) &&
+		sdev->cfg->has_high_addr;
+}
+
 static inline void sun6i_dma_dump_com_regs(struct sun6i_dma_dev *sdev)
 {
 	dev_dbg(sdev->slave.dev, "Common register:\n"
@@ -645,7 +660,7 @@  static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
 	if (!txd)
 		return NULL;
 
-	v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
+	v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32 | GFP_NOWAIT, &p_lli);
 	if (!v_lli) {
 		dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
 		goto err_txd_free;
@@ -655,6 +670,9 @@  static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
 	v_lli->dst = dest;
 	v_lli->len = len;
 	v_lli->para = NORMAL_WAIT;
+	if (sun6i_dma_has_high_addr(sdev))
+		v_lli->para |= SET_SRC_HIGH_ADDR(src) |
+			       SET_DST_HIGH_ADDR(dest);
 
 	burst = convert_burst(8);
 	width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
@@ -705,7 +723,7 @@  static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
 		return NULL;
 
 	for_each_sg(sgl, sg, sg_len, i) {
-		v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
+		v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32 | GFP_NOWAIT, &p_lli);
 		if (!v_lli)
 			goto err_lli_free;
 
@@ -715,6 +733,9 @@  static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
 		if (dir == DMA_MEM_TO_DEV) {
 			v_lli->src = sg_dma_address(sg);
 			v_lli->dst = sconfig->dst_addr;
+			if (sun6i_dma_has_high_addr(sdev))
+				v_lli->para |= SET_SRC_HIGH_ADDR(sg_dma_address(sg)) |
+					       SET_DST_HIGH_ADDR(sconfig->dst_addr);
 			v_lli->cfg = lli_cfg;
 			sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
 			sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
@@ -728,6 +749,9 @@  static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
 		} else {
 			v_lli->src = sconfig->src_addr;
 			v_lli->dst = sg_dma_address(sg);
+			if (sun6i_dma_has_high_addr(sdev))
+				v_lli->para |= SET_SRC_HIGH_ADDR(sconfig->src_addr) |
+					       SET_DST_HIGH_ADDR(sg_dma_address(sg));
 			v_lli->cfg = lli_cfg;
 			sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
 			sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
@@ -786,7 +810,7 @@  static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
 		return NULL;
 
 	for (i = 0; i < periods; i++) {
-		v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
+		v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32 | GFP_NOWAIT, &p_lli);
 		if (!v_lli) {
 			dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
 			goto err_lli_free;
@@ -798,12 +822,18 @@  static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
 		if (dir == DMA_MEM_TO_DEV) {
 			v_lli->src = buf_addr + period_len * i;
 			v_lli->dst = sconfig->dst_addr;
+			if (sun6i_dma_has_high_addr(sdev))
+				v_lli->para |= SET_SRC_HIGH_ADDR(buf_addr + period_len * i) |
+					       SET_DST_HIGH_ADDR(sconfig->dst_addr);
 			v_lli->cfg = lli_cfg;
 			sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
 			sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
 		} else {
 			v_lli->src = sconfig->src_addr;
 			v_lli->dst = buf_addr + period_len * i;
+			if (sun6i_dma_has_high_addr(sdev))
+				v_lli->para |= SET_SRC_HIGH_ADDR(sconfig->src_addr) |
+					       SET_DST_HIGH_ADDR(buf_addr + period_len * i);
 			v_lli->cfg = lli_cfg;
 			sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
 			sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
@@ -1174,8 +1204,6 @@  static struct sun6i_dma_config sun50i_a64_dma_cfg = {
 };
 
 /*
- * TODO: Add support for more than 4g physical addressing.
- *
  * The A100 binding uses the number of dma channels from the
  * device tree node.
  */
@@ -1194,6 +1222,7 @@  static struct sun6i_dma_config sun50i_a100_dma_cfg = {
 			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
 			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
 			     BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+	.has_high_addr = true,
 	.has_mbus_clk = true,
 };