drivers/spi/spi-cadence-xspi.c | 53 +++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-)
The cdns xspi controller slave dma interface may support wider data
width. Wider I/O width can benefit performance. We can know the width
by checking the CTRL_FEATURES_REG's DMA_DATA_WIDTH bit, 0 means 32bit
1 means 64bit.
A simple test with QSPI nor flash on one arm64 platform:
Use 8bit slave dma data width (now):
# dd if=/dev/mtdblock0 of=/dev/null bs=8192 count=1000
1000+0 records in
1000+0 records out
8192000 bytes (7.8MB) copied, 1.368735 seconds, 5.7MB/s
Use 32bit slave dma data width:
# dd if=/dev/mtdblock0 of=/dev/null bs=8192 count=1000
1000+0 records in
1000+0 records out
8192000 bytes (7.8MB) copied, 1.088787 seconds, 7.2MB/s
Improved by 26.3%!
Use 64bit slave dma data width:
# dd if=/dev/mtdblock0 of=/dev/null bs=8192 count=1000
1000+0 records in
1000+0 records out
8192000 bytes (7.8MB) copied, 0.831104 seconds, 9.4MB/s
Improved by 64.9%!
Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
Since v1:
- the hw capability(slave dma data width) can be found by checking the
CTRL_FEATURES_REG's DMA_DATA_WIDTH, so no need dt property any more.
drivers/spi/spi-cadence-xspi.c | 53 +++++++++++++++++++++++++++++++---
1 file changed, 49 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c
index 895b4b3276a5..ab6f1c68a2eb 100644
--- a/drivers/spi/spi-cadence-xspi.c
+++ b/drivers/spi/spi-cadence-xspi.c
@@ -369,6 +369,8 @@ struct cdns_xspi_dev {
void *in_buffer;
const void *out_buffer;
+ /* Slave DMA data width in bytes (4 or 8). */
+ u8 dma_data_width;
u8 hw_num_banks;
@@ -573,11 +575,56 @@ static int cdns_xspi_controller_init(struct cdns_xspi_dev *cdns_xspi)
ctrl_features = readl(cdns_xspi->iobase + CDNS_XSPI_CTRL_FEATURES_REG);
cdns_xspi->hw_num_banks = FIELD_GET(CDNS_XSPI_NUM_BANKS, ctrl_features);
+ cdns_xspi->dma_data_width = (ctrl_features & CDNS_XSPI_DMA_DATA_WIDTH) ? 8 : 4;
cdns_xspi->set_interrupts_handler(cdns_xspi, false);
return 0;
}
+static inline void cdns_xspi_sdma_read(struct cdns_xspi_dev *cdns_xspi, size_t len)
+{
+ void __iomem *src = cdns_xspi->sdmabase;
+ void *buf = cdns_xspi->in_buffer;
+ size_t offset = 0;
+
+ if (cdns_xspi->dma_data_width == 4) {
+ if (IS_ALIGNED((uintptr_t)src, 4) && IS_ALIGNED((uintptr_t)buf, 4)) {
+ ioread32_rep(src, buf, len >> 2);
+ offset = len & ~0x3;
+ len -= offset;
+ }
+ } else {
+ if (IS_ALIGNED((uintptr_t)src, 8) && IS_ALIGNED((uintptr_t)buf, 8)) {
+ ioread64_rep(src, buf, len >> 3);
+ offset = len & ~0x7;
+ len -= offset;
+ }
+ }
+ ioread8_rep(src, (u8 *)buf + offset, len);
+}
+
+static inline void cdns_xspi_sdma_write(struct cdns_xspi_dev *cdns_xspi, size_t len)
+{
+ void __iomem *dst = cdns_xspi->sdmabase;
+ const void *buf = cdns_xspi->out_buffer;
+ size_t offset = 0;
+
+ if (cdns_xspi->dma_data_width == 4) {
+ if (IS_ALIGNED((uintptr_t)dst, 4) && IS_ALIGNED((uintptr_t)buf, 4)) {
+ iowrite32_rep(dst, buf, len >> 2);
+ offset = len & ~0x3;
+ len -= offset;
+ }
+ } else {
+ if (IS_ALIGNED((uintptr_t)dst, 8) && IS_ALIGNED((uintptr_t)buf, 8)) {
+ iowrite64_rep(dst, buf, len >> 3);
+ offset = len & ~0x7;
+ len -= offset;
+ }
+ }
+ iowrite8_rep(dst, (const u8 *)buf + offset, len);
+}
+
static void cdns_xspi_sdma_handle(struct cdns_xspi_dev *cdns_xspi)
{
u32 sdma_size, sdma_trd_info;
@@ -589,13 +636,11 @@ static void cdns_xspi_sdma_handle(struct cdns_xspi_dev *cdns_xspi)
switch (sdma_dir) {
case CDNS_XSPI_SDMA_DIR_READ:
- ioread8_rep(cdns_xspi->sdmabase,
- cdns_xspi->in_buffer, sdma_size);
+ cdns_xspi_sdma_read(cdns_xspi, sdma_size);
break;
case CDNS_XSPI_SDMA_DIR_WRITE:
- iowrite8_rep(cdns_xspi->sdmabase,
- cdns_xspi->out_buffer, sdma_size);
+ cdns_xspi_sdma_write(cdns_xspi, sdma_size);
break;
}
}
--
2.53.0
Hi Jisheng,
kernel test robot noticed the following build errors:
[auto build test ERROR on broonie-spi/for-next]
[also build test ERROR on linus/master v7.1-rc5 next-20260529]
[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#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Jisheng-Zhang/spi-cadence-xspi-Support-32bit-and-64bit-slave-dma-interface/20260530-205805
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
patch link: https://lore.kernel.org/r/20260530123715.25899-1-jszhang%40kernel.org
patch subject: [PATCH v2] spi: cadence-xspi: Support 32bit and 64bit slave dma interface
config: x86_64-randconfig-005-20260531 (https://download.01.org/0day-ci/archive/20260531/202605310818.A7laSi0h-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260531/202605310818.A7laSi0h-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605310818.A7laSi0h-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/spi/spi-cadence-xspi.c:601:4: error: call to undeclared function 'ioread64_rep'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
601 | ioread64_rep(src, buf, len >> 3);
| ^
>> drivers/spi/spi-cadence-xspi.c:623:4: error: call to undeclared function 'iowrite64_rep'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
623 | iowrite64_rep(dst, buf, len >> 3);
| ^
2 errors generated.
vim +/ioread64_rep +601 drivers/spi/spi-cadence-xspi.c
586
587 static inline void cdns_xspi_sdma_read(struct cdns_xspi_dev *cdns_xspi, size_t len)
588 {
589 void __iomem *src = cdns_xspi->sdmabase;
590 void *buf = cdns_xspi->in_buffer;
591 size_t offset = 0;
592
593 if (cdns_xspi->dma_data_width == 4) {
594 if (IS_ALIGNED((uintptr_t)src, 4) && IS_ALIGNED((uintptr_t)buf, 4)) {
595 ioread32_rep(src, buf, len >> 2);
596 offset = len & ~0x3;
597 len -= offset;
598 }
599 } else {
600 if (IS_ALIGNED((uintptr_t)src, 8) && IS_ALIGNED((uintptr_t)buf, 8)) {
> 601 ioread64_rep(src, buf, len >> 3);
602 offset = len & ~0x7;
603 len -= offset;
604 }
605 }
606 ioread8_rep(src, (u8 *)buf + offset, len);
607 }
608
609 static inline void cdns_xspi_sdma_write(struct cdns_xspi_dev *cdns_xspi, size_t len)
610 {
611 void __iomem *dst = cdns_xspi->sdmabase;
612 const void *buf = cdns_xspi->out_buffer;
613 size_t offset = 0;
614
615 if (cdns_xspi->dma_data_width == 4) {
616 if (IS_ALIGNED((uintptr_t)dst, 4) && IS_ALIGNED((uintptr_t)buf, 4)) {
617 iowrite32_rep(dst, buf, len >> 2);
618 offset = len & ~0x3;
619 len -= offset;
620 }
621 } else {
622 if (IS_ALIGNED((uintptr_t)dst, 8) && IS_ALIGNED((uintptr_t)buf, 8)) {
> 623 iowrite64_rep(dst, buf, len >> 3);
624 offset = len & ~0x7;
625 len -= offset;
626 }
627 }
628 iowrite8_rep(dst, (const u8 *)buf + offset, len);
629 }
630
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.