diff mbox series

[1/3] iommu: Add Visconti5 IOMMU driver

Message ID 20220525013147.2215355-2-nobuhiro1.iwamatsu@toshiba.co.jp (mailing list archive)
State New, archived
Headers show
Series Add Visconti5 IOMMU driver | expand

Commit Message

Nobuhiro Iwamatsu May 25, 2022, 1:31 a.m. UTC
Add IOMMU (ATU) driver can bse used for Visconti5's multimedia IPs, such as
DCNN (Deep Convolutional Neural Network), VIIF(Video Input), VOIF(Video
output), and others.

Signed-off-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
---
 drivers/iommu/Kconfig        |   7 +
 drivers/iommu/Makefile       |   1 +
 drivers/iommu/visconti-atu.c | 426 +++++++++++++++++++++++++++++++++++
 3 files changed, 434 insertions(+)
 create mode 100644 drivers/iommu/visconti-atu.c

Comments

kernel test robot May 25, 2022, 4:45 a.m. UTC | #1
Hi Nobuhiro,

I love your patch! Perhaps something to improve:

[auto build test WARNING on joro-iommu/next]
[also build test WARNING on arm-perf/for-next/perf soc/for-next linus/master v5.18 next-20220524]
[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/Nobuhiro-Iwamatsu/Add-Visconti5-IOMMU-driver/20220525-093326
base:   https://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git next
config: nios2-allyesconfig (https://download.01.org/0day-ci/archive/20220525/202205251205.PHq3cWj3-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 11.3.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/69bb4f3c2ef0bb1f65922bc72bb31109897a6393
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Nobuhiro-Iwamatsu/Add-Visconti5-IOMMU-driver/20220525-093326
        git checkout 69bb4f3c2ef0bb1f65922bc72bb31109897a6393
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.3.0 make.cross W=1 O=build_dir ARCH=nios2 SHELL=/bin/bash drivers/iommu/

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

All warnings (new ones prefixed by >>):

   drivers/iommu/visconti-atu.c:47:29: error: field 'iommu' has incomplete type
      47 |         struct iommu_device iommu;
         |                             ^~~~~
   drivers/iommu/visconti-atu.c:62:29: error: field 'io_domain' has incomplete type
      62 |         struct iommu_domain io_domain;
         |                             ^~~~~~~~~
   In file included from include/linux/bits.h:22,
                    from include/linux/ratelimit_types.h:5,
                    from include/linux/ratelimit.h:5,
                    from include/linux/dev_printk.h:16,
                    from include/linux/device.h:15,
                    from include/linux/dma-mapping.h:7,
                    from drivers/iommu/visconti-atu.c:12:
   drivers/iommu/visconti-atu.c: In function 'to_atu_domain':
   include/linux/compiler_types.h:293:27: error: expression in static assertion is not an integer
     293 | #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/build_bug.h:78:56: note: in definition of macro '__static_assert'
      78 | #define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
         |                                                        ^~~~
   include/linux/container_of.h:19:9: note: in expansion of macro 'static_assert'
      19 |         static_assert(__same_type(*(ptr), ((type *)0)->member) ||       \
         |         ^~~~~~~~~~~~~
   include/linux/container_of.h:19:23: note: in expansion of macro '__same_type'
      19 |         static_assert(__same_type(*(ptr), ((type *)0)->member) ||       \
         |                       ^~~~~~~~~~~
   drivers/iommu/visconti-atu.c:70:16: note: in expansion of macro 'container_of'
      70 |         return container_of(domain, struct visconti_atu_domain, io_domain);
         |                ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_enable_entry':
>> drivers/iommu/visconti-atu.c:102:52: warning: right shift count >= width of type [-Wshift-count-overflow]
     102 |                                    (atu->iova[num] >> 32) & ATU_BGADDR_MASK);
         |                                                    ^~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_attach_device':
   drivers/iommu/visconti-atu.c:121:43: error: implicit declaration of function 'dev_iommu_priv_get' [-Werror=implicit-function-declaration]
     121 |         struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
         |                                           ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:121:43: warning: initialization of 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_detach_device':
   drivers/iommu/visconti-atu.c:150:43: warning: initialization of 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     150 |         struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
         |                                           ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: At top level:
   drivers/iommu/visconti-atu.c:196:41: warning: 'struct iommu_iotlb_gather' declared inside parameter list will not be visible outside of this definition or declaration
     196 |                                  struct iommu_iotlb_gather *iotlb_gather)
         |                                         ^~~~~~~~~~~~~~~~~~
   In file included from include/linux/printk.h:555,
                    from include/asm-generic/bug.h:22,
                    from ./arch/nios2/include/generated/asm/bug.h:1,
                    from include/linux/bug.h:5,
                    from include/linux/thread_info.h:13,
                    from include/asm-generic/current.h:5,
                    from ./arch/nios2/include/generated/asm/current.h:1,
                    from include/linux/sched.h:12,
                    from include/linux/ratelimit.h:6,
                    from include/linux/dev_printk.h:16,
                    from include/linux/device.h:15,
                    from include/linux/dma-mapping.h:7,
                    from drivers/iommu/visconti-atu.c:12:
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_iova_to_phys':
>> drivers/iommu/visconti-atu.c:251:27: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'dma_addr_t' {aka 'unsigned int'} [-Wformat=]
     251 |         dev_dbg(atu->dev, "iova_to_phys: %llx -> %llx\n", iova, paddr);
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:134:29: note: in definition of macro '__dynamic_func_call'
     134 |                 func(&id, ##__VA_ARGS__);               \
         |                             ^~~~~~~~~~~
   include/linux/dynamic_debug.h:166:9: note: in expansion of macro '_dynamic_func_call'
     166 |         _dynamic_func_call(fmt,__dynamic_dev_dbg,               \
         |         ^~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:155:9: note: in expansion of macro 'dynamic_dev_dbg'
     155 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~
   include/linux/dev_printk.h:155:30: note: in expansion of macro 'dev_fmt'
     155 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                              ^~~~~~~
   drivers/iommu/visconti-atu.c:251:9: note: in expansion of macro 'dev_dbg'
     251 |         dev_dbg(atu->dev, "iova_to_phys: %llx -> %llx\n", iova, paddr);
         |         ^~~~~~~
   drivers/iommu/visconti-atu.c:251:45: note: format string is defined here
     251 |         dev_dbg(atu->dev, "iova_to_phys: %llx -> %llx\n", iova, paddr);
         |                                          ~~~^
         |                                             |
         |                                             long long unsigned int
         |                                          %x
   In file included from include/linux/printk.h:555,
                    from include/asm-generic/bug.h:22,
                    from ./arch/nios2/include/generated/asm/bug.h:1,
                    from include/linux/bug.h:5,
                    from include/linux/thread_info.h:13,
                    from include/asm-generic/current.h:5,
                    from ./arch/nios2/include/generated/asm/current.h:1,
                    from include/linux/sched.h:12,
                    from include/linux/ratelimit.h:6,
                    from include/linux/dev_printk.h:16,
                    from include/linux/device.h:15,
                    from include/linux/dma-mapping.h:7,
                    from drivers/iommu/visconti-atu.c:12:
>> drivers/iommu/visconti-atu.c:251:27: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 5 has type 'phys_addr_t' {aka 'unsigned int'} [-Wformat=]
     251 |         dev_dbg(atu->dev, "iova_to_phys: %llx -> %llx\n", iova, paddr);
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:134:29: note: in definition of macro '__dynamic_func_call'
     134 |                 func(&id, ##__VA_ARGS__);               \
         |                             ^~~~~~~~~~~
   include/linux/dynamic_debug.h:166:9: note: in expansion of macro '_dynamic_func_call'
     166 |         _dynamic_func_call(fmt,__dynamic_dev_dbg,               \
         |         ^~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:155:9: note: in expansion of macro 'dynamic_dev_dbg'
     155 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~
   include/linux/dev_printk.h:155:30: note: in expansion of macro 'dev_fmt'
     155 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                              ^~~~~~~
   drivers/iommu/visconti-atu.c:251:9: note: in expansion of macro 'dev_dbg'
     251 |         dev_dbg(atu->dev, "iova_to_phys: %llx -> %llx\n", iova, paddr);
         |         ^~~~~~~
   drivers/iommu/visconti-atu.c:251:53: note: format string is defined here
     251 |         dev_dbg(atu->dev, "iova_to_phys: %llx -> %llx\n", iova, paddr);
         |                                                  ~~~^
         |                                                     |
         |                                                     long long unsigned int
         |                                                  %x
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_of_xlate':
   drivers/iommu/visconti-atu.c:262:17: error: implicit declaration of function 'dev_iommu_priv_set' [-Werror=implicit-function-declaration]
     262 |                 dev_iommu_priv_set(dev, platform_get_drvdata(pdev));
         |                 ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_domain_alloc':
   drivers/iommu/visconti-atu.c:273:21: error: 'IOMMU_DOMAIN_UNMANAGED' undeclared (first use in this function)
     273 |         if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
         |                     ^~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:273:21: note: each undeclared identifier is reported only once for each function it appears in
   drivers/iommu/visconti-atu.c:273:55: error: 'IOMMU_DOMAIN_DMA' undeclared (first use in this function)
     273 |         if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
         |                                                       ^~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_probe_device':
   drivers/iommu/visconti-atu.c:298:39: error: implicit declaration of function 'dev_iommu_fwspec_get' [-Werror=implicit-function-declaration]
     298 |         struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
         |                                       ^~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:298:39: warning: initialization of 'struct iommu_fwspec *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
   drivers/iommu/visconti-atu.c:301:30: error: invalid use of undefined type 'struct iommu_fwspec'
     301 |         if (!fwspec || fwspec->ops != &visconti_atu_ops)
         |                              ^~
   drivers/iommu/visconti-atu.c:304:13: warning: assignment to 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     304 |         atu = dev_iommu_priv_get(dev);
         |             ^
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_release_device':
   drivers/iommu/visconti-atu.c:310:43: warning: initialization of 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     310 |         struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
         |                                           ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:315:9: error: implicit declaration of function 'iommu_fwspec_free' [-Werror=implicit-function-declaration]
     315 |         iommu_fwspec_free(dev);
         |         ^~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: At top level:
   drivers/iommu/visconti-atu.c:318:21: error: variable 'visconti_atu_ops' has initializer but incomplete type
     318 | static const struct iommu_ops visconti_atu_ops = {
         |                     ^~~~~~~~~
   drivers/iommu/visconti-atu.c:319:10: error: 'const struct iommu_ops' has no member named 'domain_alloc'
     319 |         .domain_alloc = visconti_atu_domain_alloc,
         |          ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:319:25: warning: excess elements in struct initializer
     319 |         .domain_alloc = visconti_atu_domain_alloc,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:319:25: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c:320:10: error: 'const struct iommu_ops' has no member named 'probe_device'
     320 |         .probe_device = visconti_atu_probe_device,
         |          ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:320:25: warning: excess elements in struct initializer
     320 |         .probe_device = visconti_atu_probe_device,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:320:25: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c:321:10: error: 'const struct iommu_ops' has no member named 'release_device'
     321 |         .release_device = visconti_atu_release_device,
         |          ^~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:321:27: warning: excess elements in struct initializer
     321 |         .release_device = visconti_atu_release_device,
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:321:27: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c:322:10: error: 'const struct iommu_ops' has no member named 'device_group'
     322 |         .device_group = generic_device_group,
         |          ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:322:25: error: 'generic_device_group' undeclared here (not in a function)
     322 |         .device_group = generic_device_group,
         |                         ^~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:322:25: warning: excess elements in struct initializer
   drivers/iommu/visconti-atu.c:322:25: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c:323:10: error: 'const struct iommu_ops' has no member named 'of_xlate'
     323 |         .of_xlate = visconti_atu_of_xlate,
         |          ^~~~~~~~
   drivers/iommu/visconti-atu.c:323:21: warning: excess elements in struct initializer
     323 |         .of_xlate = visconti_atu_of_xlate,
         |                     ^~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:323:21: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c:324:10: error: 'const struct iommu_ops' has no member named 'pgsize_bitmap'
     324 |         .pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
         |          ^~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:41:33: warning: excess elements in struct initializer
      41 | #define ATU_IOMMU_PGSIZE_BITMAP 0x7ffff000 /* SZ_1G - SZ_4K */
         |                                 ^~~~~~~~~~
   drivers/iommu/visconti-atu.c:324:26: note: in expansion of macro 'ATU_IOMMU_PGSIZE_BITMAP'


vim +102 drivers/iommu/visconti-atu.c

    83	
    84	static void visconti_atu_enable_entry(struct visconti_atu_device *atu,
    85					      int num)
    86	{
    87		dev_dbg(atu->dev, "enable ATU: %d\n", atu->enable_entry);
    88	
    89		visconti_atu_write(atu, ATU_AT_EN, 0);
    90		if (atu->enable_entry & BIT(num)) {
    91			visconti_atu_write(atu,
    92					   ATU_AT_REG(num, ATU_AT_BLADDR),
    93					   atu->iova[num]);
    94			visconti_atu_write(atu,
    95					   ATU_AT_REG(num, ATU_AT_ELADDR),
    96					   atu->iova[num] + atu->size[num] - 1);
    97			visconti_atu_write(atu,
    98					   ATU_AT_REG(num, ATU_AT_BGADDR0),
    99					   atu->iova[num] & ATU_BGADDR_MASK);
   100			visconti_atu_write(atu,
   101					   ATU_AT_REG(num, ATU_AT_BGADDR1),
 > 102					   (atu->iova[num] >> 32) & ATU_BGADDR_MASK);
   103		}
   104		visconti_atu_write(atu, ATU_AT_ENTRY_EN, atu->enable_entry);
   105		visconti_atu_write(atu, ATU_AT_EN, 1);
   106	}
   107	
   108	static void visconti_atu_disable_entry(struct visconti_atu_device *atu)
   109	{
   110		dev_dbg(atu->dev, "disable ATU: %d\n", atu->enable_entry);
   111	
   112		visconti_atu_write(atu, ATU_AT_EN, 0);
   113		visconti_atu_write(atu, ATU_AT_ENTRY_EN, atu->enable_entry);
   114		visconti_atu_write(atu, ATU_AT_EN, 1);
   115	}
   116	
   117	static int visconti_atu_attach_device(struct iommu_domain *io_domain,
   118					      struct device *dev)
   119	{
   120		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
   121		struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
   122		int ret = 0;
   123	
   124		if (!atu) {
   125			dev_err(dev, "Cannot attach to ATU\n");
   126			return -ENXIO;
   127		}
   128	
   129		mutex_lock(&domain->mutex);
   130	
   131		if (!domain->atu) {
   132			domain->atu = atu;
   133		} else if (domain->atu != atu) {
   134			dev_err(dev, "Can't attach ATU %s to domain on ATU %s\n",
   135				dev_name(atu->dev), dev_name(domain->atu->dev));
   136			ret = -EINVAL;
   137		} else {
   138			dev_warn(dev, "Reusing ATU context\n");
   139		}
   140	
   141		mutex_unlock(&domain->mutex);
   142	
   143		return ret;
   144	}
   145	
   146	static void visconti_atu_detach_device(struct iommu_domain *io_domain,
   147					       struct device *dev)
   148	{
   149		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
   150		struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
   151	
   152		if (domain->atu != atu)
   153			return;
   154	
   155		domain->atu = NULL;
   156	}
   157	
   158	static int visconti_atu_map(struct iommu_domain *io_domain,
   159				    unsigned long iova,
   160				    phys_addr_t paddr,
   161				    size_t size, int prot, gfp_t gfp)
   162	{
   163		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
   164		struct visconti_atu_device *atu = domain->atu;
   165		unsigned long flags;
   166		unsigned int i;
   167	
   168		if (!domain)
   169			return -ENODEV;
   170	
   171		spin_lock_irqsave(&atu->lock, flags);
   172		for (i = 0; i < atu->num_map_entry; i++) {
   173			if (!(atu->enable_entry & BIT(i))) {
   174				atu->enable_entry |= BIT(i);
   175				atu->iova[i] = iova;
   176				atu->paddr[i] = paddr;
   177				atu->size[i] = size;
   178	
   179				visconti_atu_enable_entry(atu, i);
   180				break;
   181			}
   182		}
   183		spin_unlock_irqrestore(&atu->lock, flags);
   184	
   185		if (i == atu->num_map_entry) {
   186			dev_err(atu->dev, "map: not enough entry.\n");
   187			return -ENOMEM;
   188		}
   189	
   190		return 0;
   191	}
   192	
   193	static size_t visconti_atu_unmap(struct iommu_domain *io_domain,
   194					 unsigned long iova,
   195					 size_t size,
   196					 struct iommu_iotlb_gather *iotlb_gather)
   197	{
   198		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
   199		struct visconti_atu_device *atu = domain->atu;
   200		size_t tmp_size = size;
   201		unsigned long flags;
   202		unsigned int i;
   203	
   204		spin_lock_irqsave(&atu->lock, flags);
   205	
   206		while (tmp_size != 0) {
   207			for (i = 0; i < atu->num_map_entry; i++) {
   208				if (atu->iova[i] != iova)
   209					continue;
   210	
   211				atu->enable_entry &= ~BIT(i);
   212				iova += atu->size[i];
   213				tmp_size -= atu->size[i];
   214	
   215				visconti_atu_disable_entry(atu);
   216	
   217				break;
   218			}
   219			if (i == atu->num_map_entry) {
   220				dev_err(atu->dev, "unmap: not found entry.\n");
   221				size = 0;
   222				goto out;
   223			}
   224		}
   225	
   226		if (!atu->num_map_entry)
   227			visconti_atu_write(atu, ATU_AT_EN, 0);
   228	out:
   229		spin_unlock_irqrestore(&atu->lock, flags);
   230		return size;
   231	}
   232	
   233	static phys_addr_t visconti_atu_iova_to_phys(struct iommu_domain *io_domain,
   234						     dma_addr_t iova)
   235	{
   236		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
   237		struct visconti_atu_device *atu = domain->atu;
   238		phys_addr_t paddr = 0;
   239		unsigned int i;
   240	
   241		for (i = 0; i < atu->num_map_entry; i++) {
   242			if (!(atu->enable_entry & BIT(i)))
   243				continue;
   244			if (atu->iova[i] <= iova && iova < (atu->iova[i] + atu->size[i])) {
   245				paddr = atu->paddr[i];
   246				paddr += iova & (atu->size[i] - 1);
   247				break;
   248			}
   249		}
   250	
 > 251		dev_dbg(atu->dev, "iova_to_phys: %llx -> %llx\n", iova, paddr);
   252	
   253		return paddr;
   254	}
   255
kernel test robot May 25, 2022, 6:09 a.m. UTC | #2
Hi Nobuhiro,

I love your patch! Perhaps something to improve:

[auto build test WARNING on joro-iommu/next]
[also build test WARNING on arm-perf/for-next/perf soc/for-next linus/master v5.18 next-20220524]
[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/Nobuhiro-Iwamatsu/Add-Visconti5-IOMMU-driver/20220525-093326
base:   https://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git next
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20220525/202205251452.kFXLqhQx-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 11.3.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/69bb4f3c2ef0bb1f65922bc72bb31109897a6393
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Nobuhiro-Iwamatsu/Add-Visconti5-IOMMU-driver/20220525-093326
        git checkout 69bb4f3c2ef0bb1f65922bc72bb31109897a6393
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.3.0 make.cross W=1 O=build_dir ARCH=alpha SHELL=/bin/bash drivers/iommu/

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

All warnings (new ones prefixed by >>):

   drivers/iommu/visconti-atu.c:47:29: error: field 'iommu' has incomplete type
      47 |         struct iommu_device iommu;
         |                             ^~~~~
   drivers/iommu/visconti-atu.c:62:29: error: field 'io_domain' has incomplete type
      62 |         struct iommu_domain io_domain;
         |                             ^~~~~~~~~
   In file included from include/linux/bits.h:22,
                    from include/linux/ratelimit_types.h:5,
                    from include/linux/ratelimit.h:5,
                    from include/linux/dev_printk.h:16,
                    from include/linux/device.h:15,
                    from include/linux/dma-mapping.h:7,
                    from drivers/iommu/visconti-atu.c:12:
   drivers/iommu/visconti-atu.c: In function 'to_atu_domain':
   include/linux/compiler_types.h:293:27: error: expression in static assertion is not an integer
     293 | #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/build_bug.h:78:56: note: in definition of macro '__static_assert'
      78 | #define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
         |                                                        ^~~~
   include/linux/container_of.h:19:9: note: in expansion of macro 'static_assert'
      19 |         static_assert(__same_type(*(ptr), ((type *)0)->member) ||       \
         |         ^~~~~~~~~~~~~
   include/linux/container_of.h:19:23: note: in expansion of macro '__same_type'
      19 |         static_assert(__same_type(*(ptr), ((type *)0)->member) ||       \
         |                       ^~~~~~~~~~~
   drivers/iommu/visconti-atu.c:70:16: note: in expansion of macro 'container_of'
      70 |         return container_of(domain, struct visconti_atu_domain, io_domain);
         |                ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_attach_device':
   drivers/iommu/visconti-atu.c:121:43: error: implicit declaration of function 'dev_iommu_priv_get' [-Werror=implicit-function-declaration]
     121 |         struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
         |                                           ^~~~~~~~~~~~~~~~~~
>> drivers/iommu/visconti-atu.c:121:43: warning: initialization of 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_detach_device':
   drivers/iommu/visconti-atu.c:150:43: warning: initialization of 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     150 |         struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
         |                                           ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: At top level:
>> drivers/iommu/visconti-atu.c:196:41: warning: 'struct iommu_iotlb_gather' declared inside parameter list will not be visible outside of this definition or declaration
     196 |                                  struct iommu_iotlb_gather *iotlb_gather)
         |                                         ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_of_xlate':
   drivers/iommu/visconti-atu.c:262:17: error: implicit declaration of function 'dev_iommu_priv_set' [-Werror=implicit-function-declaration]
     262 |                 dev_iommu_priv_set(dev, platform_get_drvdata(pdev));
         |                 ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_domain_alloc':
   drivers/iommu/visconti-atu.c:273:21: error: 'IOMMU_DOMAIN_UNMANAGED' undeclared (first use in this function)
     273 |         if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
         |                     ^~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:273:21: note: each undeclared identifier is reported only once for each function it appears in
   drivers/iommu/visconti-atu.c:273:55: error: 'IOMMU_DOMAIN_DMA' undeclared (first use in this function)
     273 |         if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
         |                                                       ^~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_probe_device':
   drivers/iommu/visconti-atu.c:298:39: error: implicit declaration of function 'dev_iommu_fwspec_get' [-Werror=implicit-function-declaration]
     298 |         struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
         |                                       ^~~~~~~~~~~~~~~~~~~~
>> drivers/iommu/visconti-atu.c:298:39: warning: initialization of 'struct iommu_fwspec *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
   drivers/iommu/visconti-atu.c:301:30: error: invalid use of undefined type 'struct iommu_fwspec'
     301 |         if (!fwspec || fwspec->ops != &visconti_atu_ops)
         |                              ^~
>> drivers/iommu/visconti-atu.c:304:13: warning: assignment to 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     304 |         atu = dev_iommu_priv_get(dev);
         |             ^
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_release_device':
   drivers/iommu/visconti-atu.c:310:43: warning: initialization of 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     310 |         struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
         |                                           ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:315:9: error: implicit declaration of function 'iommu_fwspec_free' [-Werror=implicit-function-declaration]
     315 |         iommu_fwspec_free(dev);
         |         ^~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: At top level:
   drivers/iommu/visconti-atu.c:318:21: error: variable 'visconti_atu_ops' has initializer but incomplete type
     318 | static const struct iommu_ops visconti_atu_ops = {
         |                     ^~~~~~~~~
   drivers/iommu/visconti-atu.c:319:10: error: 'const struct iommu_ops' has no member named 'domain_alloc'
     319 |         .domain_alloc = visconti_atu_domain_alloc,
         |          ^~~~~~~~~~~~
>> drivers/iommu/visconti-atu.c:319:25: warning: excess elements in struct initializer
     319 |         .domain_alloc = visconti_atu_domain_alloc,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:319:25: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c:320:10: error: 'const struct iommu_ops' has no member named 'probe_device'
     320 |         .probe_device = visconti_atu_probe_device,
         |          ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:320:25: warning: excess elements in struct initializer
     320 |         .probe_device = visconti_atu_probe_device,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:320:25: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c:321:10: error: 'const struct iommu_ops' has no member named 'release_device'
     321 |         .release_device = visconti_atu_release_device,
         |          ^~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:321:27: warning: excess elements in struct initializer
     321 |         .release_device = visconti_atu_release_device,
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:321:27: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c:322:10: error: 'const struct iommu_ops' has no member named 'device_group'
     322 |         .device_group = generic_device_group,
         |          ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:322:25: error: 'generic_device_group' undeclared here (not in a function)
     322 |         .device_group = generic_device_group,
         |                         ^~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:322:25: warning: excess elements in struct initializer
   drivers/iommu/visconti-atu.c:322:25: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c:323:10: error: 'const struct iommu_ops' has no member named 'of_xlate'
     323 |         .of_xlate = visconti_atu_of_xlate,
         |          ^~~~~~~~
   drivers/iommu/visconti-atu.c:323:21: warning: excess elements in struct initializer
     323 |         .of_xlate = visconti_atu_of_xlate,
         |                     ^~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:323:21: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c:324:10: error: 'const struct iommu_ops' has no member named 'pgsize_bitmap'
     324 |         .pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
         |          ^~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:41:33: warning: excess elements in struct initializer
      41 | #define ATU_IOMMU_PGSIZE_BITMAP 0x7ffff000 /* SZ_1G - SZ_4K */
         |                                 ^~~~~~~~~~
   drivers/iommu/visconti-atu.c:324:26: note: in expansion of macro 'ATU_IOMMU_PGSIZE_BITMAP'
     324 |         .pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:41:33: note: (near initialization for 'visconti_atu_ops')
      41 | #define ATU_IOMMU_PGSIZE_BITMAP 0x7ffff000 /* SZ_1G - SZ_4K */
         |                                 ^~~~~~~~~~
   drivers/iommu/visconti-atu.c:324:26: note: in expansion of macro 'ATU_IOMMU_PGSIZE_BITMAP'
     324 |         .pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:325:10: error: 'const struct iommu_ops' has no member named 'default_domain_ops'
     325 |         .default_domain_ops = &(const struct iommu_domain_ops) {
         |          ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:326:18: error: 'const struct iommu_domain_ops' has no member named 'attach_dev'
     326 |                 .attach_dev = visconti_atu_attach_device,
         |                  ^~~~~~~~~~
   drivers/iommu/visconti-atu.c:326:31: warning: excess elements in struct initializer
     326 |                 .attach_dev = visconti_atu_attach_device,
         |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:326:31: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:327:18: error: 'const struct iommu_domain_ops' has no member named 'detach_dev'
     327 |                 .detach_dev = visconti_atu_detach_device,
         |                  ^~~~~~~~~~
   drivers/iommu/visconti-atu.c:327:31: warning: excess elements in struct initializer
     327 |                 .detach_dev = visconti_atu_detach_device,
         |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:327:31: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:328:18: error: 'const struct iommu_domain_ops' has no member named 'map'
     328 |                 .map = visconti_atu_map,
         |                  ^~~
   drivers/iommu/visconti-atu.c:328:24: warning: excess elements in struct initializer
     328 |                 .map = visconti_atu_map,
         |                        ^~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:328:24: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:329:18: error: 'const struct iommu_domain_ops' has no member named 'unmap'
     329 |                 .unmap = visconti_atu_unmap,
         |                  ^~~~~
   drivers/iommu/visconti-atu.c:329:26: warning: excess elements in struct initializer
     329 |                 .unmap = visconti_atu_unmap,
         |                          ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:329:26: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:330:18: error: 'const struct iommu_domain_ops' has no member named 'iova_to_phys'
     330 |                 .iova_to_phys = visconti_atu_iova_to_phys,
         |                  ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:330:33: warning: excess elements in struct initializer
     330 |                 .iova_to_phys = visconti_atu_iova_to_phys,
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:330:33: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:331:18: error: 'const struct iommu_domain_ops' has no member named 'free'
     331 |                 .free = visconti_atu_domain_free,
         |                  ^~~~
   drivers/iommu/visconti-atu.c:331:25: warning: excess elements in struct initializer
     331 |                 .free = visconti_atu_domain_free,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:331:25: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:325:64: error: invalid use of undefined type 'const struct iommu_domain_ops'
     325 |         .default_domain_ops = &(const struct iommu_domain_ops) {
         |                                                                ^
   drivers/iommu/visconti-atu.c:325:31: warning: excess elements in struct initializer
     325 |         .default_domain_ops = &(const struct iommu_domain_ops) {
         |                               ^
   drivers/iommu/visconti-atu.c:325:31: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_probe':
   drivers/iommu/visconti-atu.c:366:22: error: implicit declaration of function 'iommu_group_alloc' [-Werror=implicit-function-declaration]
     366 |         atu->group = iommu_group_alloc();
         |                      ^~~~~~~~~~~~~~~~~
>> drivers/iommu/visconti-atu.c:366:20: warning: assignment to 'struct iommu_group *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     366 |         atu->group = iommu_group_alloc();
         |                    ^
   drivers/iommu/visconti-atu.c:380:15: error: implicit declaration of function 'iommu_device_sysfs_add' [-Werror=implicit-function-declaration]
     380 |         ret = iommu_device_sysfs_add(&atu->iommu, dev, NULL, dev_name(dev));
         |               ^~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:384:15: error: implicit declaration of function 'iommu_device_register'; did you mean 'of_device_register'? [-Werror=implicit-function-declaration]
     384 |         ret = iommu_device_register(&atu->iommu, &visconti_atu_ops, dev);
         |               ^~~~~~~~~~~~~~~~~~~~~
         |               of_device_register
   drivers/iommu/visconti-atu.c:388:14: error: implicit declaration of function 'iommu_present'; did you mean 'pmd_present'? [-Werror=implicit-function-declaration]
     388 |         if (!iommu_present(&platform_bus_type))
         |              ^~~~~~~~~~~~~
         |              pmd_present
   drivers/iommu/visconti-atu.c:389:17: error: implicit declaration of function 'bus_set_iommu' [-Werror=implicit-function-declaration]
     389 |                 bus_set_iommu(&platform_bus_type, &visconti_atu_ops);
         |                 ^~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:395:9: error: implicit declaration of function 'iommu_device_sysfs_remove' [-Werror=implicit-function-declaration]
     395 |         iommu_device_sysfs_remove(&atu->iommu);
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_remove':
   drivers/iommu/visconti-atu.c:405:9: error: implicit declaration of function 'iommu_device_unregister'; did you mean 'of_device_unregister'? [-Werror=implicit-function-declaration]
     405 |         iommu_device_unregister(&atu->iommu);
         |         ^~~~~~~~~~~~~~~~~~~~~~~
         |         of_device_unregister
   drivers/iommu/visconti-atu.c: At top level:
   drivers/iommu/visconti-atu.c:318:31: error: storage size of 'visconti_atu_ops' isn't known
     318 | static const struct iommu_ops visconti_atu_ops = {
         |                               ^~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:318:31: error: storage size of 'visconti_atu_ops' isn't known
   cc1: some warnings being treated as errors


vim +121 drivers/iommu/visconti-atu.c

   116	
   117	static int visconti_atu_attach_device(struct iommu_domain *io_domain,
   118					      struct device *dev)
   119	{
   120		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
 > 121		struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
   122		int ret = 0;
   123	
   124		if (!atu) {
   125			dev_err(dev, "Cannot attach to ATU\n");
   126			return -ENXIO;
   127		}
   128	
   129		mutex_lock(&domain->mutex);
   130	
   131		if (!domain->atu) {
   132			domain->atu = atu;
   133		} else if (domain->atu != atu) {
   134			dev_err(dev, "Can't attach ATU %s to domain on ATU %s\n",
   135				dev_name(atu->dev), dev_name(domain->atu->dev));
   136			ret = -EINVAL;
   137		} else {
   138			dev_warn(dev, "Reusing ATU context\n");
   139		}
   140	
   141		mutex_unlock(&domain->mutex);
   142	
   143		return ret;
   144	}
   145	
   146	static void visconti_atu_detach_device(struct iommu_domain *io_domain,
   147					       struct device *dev)
   148	{
   149		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
   150		struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
   151	
   152		if (domain->atu != atu)
   153			return;
   154	
   155		domain->atu = NULL;
   156	}
   157	
   158	static int visconti_atu_map(struct iommu_domain *io_domain,
   159				    unsigned long iova,
   160				    phys_addr_t paddr,
   161				    size_t size, int prot, gfp_t gfp)
   162	{
   163		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
   164		struct visconti_atu_device *atu = domain->atu;
   165		unsigned long flags;
   166		unsigned int i;
   167	
   168		if (!domain)
   169			return -ENODEV;
   170	
   171		spin_lock_irqsave(&atu->lock, flags);
   172		for (i = 0; i < atu->num_map_entry; i++) {
   173			if (!(atu->enable_entry & BIT(i))) {
   174				atu->enable_entry |= BIT(i);
   175				atu->iova[i] = iova;
   176				atu->paddr[i] = paddr;
   177				atu->size[i] = size;
   178	
   179				visconti_atu_enable_entry(atu, i);
   180				break;
   181			}
   182		}
   183		spin_unlock_irqrestore(&atu->lock, flags);
   184	
   185		if (i == atu->num_map_entry) {
   186			dev_err(atu->dev, "map: not enough entry.\n");
   187			return -ENOMEM;
   188		}
   189	
   190		return 0;
   191	}
   192	
   193	static size_t visconti_atu_unmap(struct iommu_domain *io_domain,
   194					 unsigned long iova,
   195					 size_t size,
 > 196					 struct iommu_iotlb_gather *iotlb_gather)
   197	{
   198		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
   199		struct visconti_atu_device *atu = domain->atu;
   200		size_t tmp_size = size;
   201		unsigned long flags;
   202		unsigned int i;
   203	
   204		spin_lock_irqsave(&atu->lock, flags);
   205	
   206		while (tmp_size != 0) {
   207			for (i = 0; i < atu->num_map_entry; i++) {
   208				if (atu->iova[i] != iova)
   209					continue;
   210	
   211				atu->enable_entry &= ~BIT(i);
   212				iova += atu->size[i];
   213				tmp_size -= atu->size[i];
   214	
   215				visconti_atu_disable_entry(atu);
   216	
   217				break;
   218			}
   219			if (i == atu->num_map_entry) {
   220				dev_err(atu->dev, "unmap: not found entry.\n");
   221				size = 0;
   222				goto out;
   223			}
   224		}
   225	
   226		if (!atu->num_map_entry)
   227			visconti_atu_write(atu, ATU_AT_EN, 0);
   228	out:
   229		spin_unlock_irqrestore(&atu->lock, flags);
   230		return size;
   231	}
   232	
   233	static phys_addr_t visconti_atu_iova_to_phys(struct iommu_domain *io_domain,
   234						     dma_addr_t iova)
   235	{
   236		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
   237		struct visconti_atu_device *atu = domain->atu;
   238		phys_addr_t paddr = 0;
   239		unsigned int i;
   240	
   241		for (i = 0; i < atu->num_map_entry; i++) {
   242			if (!(atu->enable_entry & BIT(i)))
   243				continue;
   244			if (atu->iova[i] <= iova && iova < (atu->iova[i] + atu->size[i])) {
   245				paddr = atu->paddr[i];
   246				paddr += iova & (atu->size[i] - 1);
   247				break;
   248			}
   249		}
   250	
   251		dev_dbg(atu->dev, "iova_to_phys: %llx -> %llx\n", iova, paddr);
   252	
   253		return paddr;
   254	}
   255	
   256	static int visconti_atu_of_xlate(struct device *dev, struct of_phandle_args *args)
   257	{
   258		if (!dev_iommu_priv_get(dev)) {
   259			struct platform_device *pdev;
   260	
   261			pdev = of_find_device_by_node(args->np);
   262			dev_iommu_priv_set(dev, platform_get_drvdata(pdev));
   263			platform_device_put(pdev);
   264		}
   265	
   266		return 0;
   267	}
   268	
   269	static struct iommu_domain *visconti_atu_domain_alloc(unsigned int type)
   270	{
   271		struct visconti_atu_domain *domain;
   272	
   273		if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
   274			return NULL;
   275	
   276		domain = kzalloc(sizeof(*domain), GFP_KERNEL);
   277		if (!domain)
   278			return NULL;
   279	
   280		mutex_init(&domain->mutex);
   281	
   282		domain->io_domain.geometry.aperture_start = 0;
   283		domain->io_domain.geometry.aperture_end = DMA_BIT_MASK(32);
   284		domain->io_domain.geometry.force_aperture = true;
   285	
   286		return &domain->io_domain;
   287	}
   288	
   289	static void visconti_atu_domain_free(struct iommu_domain *io_domain)
   290	{
   291		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
   292	
   293		kfree(domain);
   294	}
   295	
   296	static struct iommu_device *visconti_atu_probe_device(struct device *dev)
   297	{
 > 298		struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
   299		struct visconti_atu_device *atu;
   300	
   301		if (!fwspec || fwspec->ops != &visconti_atu_ops)
   302			return ERR_PTR(-ENODEV);
   303	
 > 304		atu = dev_iommu_priv_get(dev);
   305		return &atu->iommu;
   306	}
   307	
   308	static void visconti_atu_release_device(struct device *dev)
   309	{
   310		struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
   311	
   312		if (!atu)
   313			return;
   314	
   315		iommu_fwspec_free(dev);
   316	}
   317	
   318	static const struct iommu_ops visconti_atu_ops = {
 > 319		.domain_alloc = visconti_atu_domain_alloc,
   320		.probe_device = visconti_atu_probe_device,
   321		.release_device = visconti_atu_release_device,
   322		.device_group = generic_device_group,
   323		.of_xlate = visconti_atu_of_xlate,
   324		.pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
   325		.default_domain_ops = &(const struct iommu_domain_ops) {
   326			.attach_dev = visconti_atu_attach_device,
   327			.detach_dev = visconti_atu_detach_device,
   328			.map = visconti_atu_map,
   329			.unmap = visconti_atu_unmap,
   330			.iova_to_phys = visconti_atu_iova_to_phys,
   331			.free = visconti_atu_domain_free,
   332		}
   333	};
   334
Baolu Lu May 25, 2022, 6:26 a.m. UTC | #3
On 2022/5/25 09:31, Nobuhiro Iwamatsu wrote:
> +static const struct iommu_ops visconti_atu_ops = {
> +	.domain_alloc = visconti_atu_domain_alloc,
> +	.probe_device = visconti_atu_probe_device,
> +	.release_device = visconti_atu_release_device,
> +	.device_group = generic_device_group,
> +	.of_xlate = visconti_atu_of_xlate,
> +	.pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
> +	.default_domain_ops = &(const struct iommu_domain_ops) {
> +		.attach_dev = visconti_atu_attach_device,
> +		.detach_dev = visconti_atu_detach_device,

The detach_dev callback is about to be deprecated. The new drivers
should implement the default domain and blocking domain instead.

> +		.map = visconti_atu_map,
> +		.unmap = visconti_atu_unmap,
> +		.iova_to_phys = visconti_atu_iova_to_phys,
> +		.free = visconti_atu_domain_free,
> +	}
> +};

Best regards,
baolu
kernel test robot May 25, 2022, 9:36 a.m. UTC | #4
Hi Nobuhiro,

I love your patch! Yet something to improve:

[auto build test ERROR on joro-iommu/next]
[also build test ERROR on arm-perf/for-next/perf soc/for-next linus/master v5.18 next-20220524]
[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/Nobuhiro-Iwamatsu/Add-Visconti5-IOMMU-driver/20220525-093326
base:   https://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git next
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20220525/202205251708.q7cwjpF8-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 11.3.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/69bb4f3c2ef0bb1f65922bc72bb31109897a6393
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Nobuhiro-Iwamatsu/Add-Visconti5-IOMMU-driver/20220525-093326
        git checkout 69bb4f3c2ef0bb1f65922bc72bb31109897a6393
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.3.0 make.cross W=1 O=build_dir ARCH=alpha SHELL=/bin/bash

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

Note: the linux-review/Nobuhiro-Iwamatsu/Add-Visconti5-IOMMU-driver/20220525-093326 HEAD 07739c72b066c0781c371eec7614ed876441e8dd builds fine.
      It only hurts bisectability.

All errors (new ones prefixed by >>):

>> drivers/iommu/visconti-atu.c:47:29: error: field 'iommu' has incomplete type
      47 |         struct iommu_device iommu;
         |                             ^~~~~
>> drivers/iommu/visconti-atu.c:62:29: error: field 'io_domain' has incomplete type
      62 |         struct iommu_domain io_domain;
         |                             ^~~~~~~~~
   In file included from include/linux/bits.h:22,
                    from include/linux/ratelimit_types.h:5,
                    from include/linux/ratelimit.h:5,
                    from include/linux/dev_printk.h:16,
                    from include/linux/device.h:15,
                    from include/linux/dma-mapping.h:7,
                    from drivers/iommu/visconti-atu.c:12:
   drivers/iommu/visconti-atu.c: In function 'to_atu_domain':
   include/linux/compiler_types.h:293:27: error: expression in static assertion is not an integer
     293 | #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/build_bug.h:78:56: note: in definition of macro '__static_assert'
      78 | #define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
         |                                                        ^~~~
   include/linux/container_of.h:19:9: note: in expansion of macro 'static_assert'
      19 |         static_assert(__same_type(*(ptr), ((type *)0)->member) ||       \
         |         ^~~~~~~~~~~~~
   include/linux/container_of.h:19:23: note: in expansion of macro '__same_type'
      19 |         static_assert(__same_type(*(ptr), ((type *)0)->member) ||       \
         |                       ^~~~~~~~~~~
   drivers/iommu/visconti-atu.c:70:16: note: in expansion of macro 'container_of'
      70 |         return container_of(domain, struct visconti_atu_domain, io_domain);
         |                ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_attach_device':
>> drivers/iommu/visconti-atu.c:121:43: error: implicit declaration of function 'dev_iommu_priv_get' [-Werror=implicit-function-declaration]
     121 |         struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
         |                                           ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:121:43: warning: initialization of 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_detach_device':
   drivers/iommu/visconti-atu.c:150:43: warning: initialization of 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     150 |         struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
         |                                           ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: At top level:
   drivers/iommu/visconti-atu.c:196:41: warning: 'struct iommu_iotlb_gather' declared inside parameter list will not be visible outside of this definition or declaration
     196 |                                  struct iommu_iotlb_gather *iotlb_gather)
         |                                         ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_of_xlate':
>> drivers/iommu/visconti-atu.c:262:17: error: implicit declaration of function 'dev_iommu_priv_set' [-Werror=implicit-function-declaration]
     262 |                 dev_iommu_priv_set(dev, platform_get_drvdata(pdev));
         |                 ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_domain_alloc':
>> drivers/iommu/visconti-atu.c:273:21: error: 'IOMMU_DOMAIN_UNMANAGED' undeclared (first use in this function)
     273 |         if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
         |                     ^~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:273:21: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/iommu/visconti-atu.c:273:55: error: 'IOMMU_DOMAIN_DMA' undeclared (first use in this function)
     273 |         if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
         |                                                       ^~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_probe_device':
>> drivers/iommu/visconti-atu.c:298:39: error: implicit declaration of function 'dev_iommu_fwspec_get' [-Werror=implicit-function-declaration]
     298 |         struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
         |                                       ^~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:298:39: warning: initialization of 'struct iommu_fwspec *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
>> drivers/iommu/visconti-atu.c:301:30: error: invalid use of undefined type 'struct iommu_fwspec'
     301 |         if (!fwspec || fwspec->ops != &visconti_atu_ops)
         |                              ^~
   drivers/iommu/visconti-atu.c:304:13: warning: assignment to 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     304 |         atu = dev_iommu_priv_get(dev);
         |             ^
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_release_device':
   drivers/iommu/visconti-atu.c:310:43: warning: initialization of 'struct visconti_atu_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     310 |         struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
         |                                           ^~~~~~~~~~~~~~~~~~
>> drivers/iommu/visconti-atu.c:315:9: error: implicit declaration of function 'iommu_fwspec_free' [-Werror=implicit-function-declaration]
     315 |         iommu_fwspec_free(dev);
         |         ^~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: At top level:
>> drivers/iommu/visconti-atu.c:318:21: error: variable 'visconti_atu_ops' has initializer but incomplete type
     318 | static const struct iommu_ops visconti_atu_ops = {
         |                     ^~~~~~~~~
>> drivers/iommu/visconti-atu.c:319:10: error: 'const struct iommu_ops' has no member named 'domain_alloc'
     319 |         .domain_alloc = visconti_atu_domain_alloc,
         |          ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:319:25: warning: excess elements in struct initializer
     319 |         .domain_alloc = visconti_atu_domain_alloc,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:319:25: note: (near initialization for 'visconti_atu_ops')
>> drivers/iommu/visconti-atu.c:320:10: error: 'const struct iommu_ops' has no member named 'probe_device'
     320 |         .probe_device = visconti_atu_probe_device,
         |          ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:320:25: warning: excess elements in struct initializer
     320 |         .probe_device = visconti_atu_probe_device,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:320:25: note: (near initialization for 'visconti_atu_ops')
>> drivers/iommu/visconti-atu.c:321:10: error: 'const struct iommu_ops' has no member named 'release_device'
     321 |         .release_device = visconti_atu_release_device,
         |          ^~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:321:27: warning: excess elements in struct initializer
     321 |         .release_device = visconti_atu_release_device,
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:321:27: note: (near initialization for 'visconti_atu_ops')
>> drivers/iommu/visconti-atu.c:322:10: error: 'const struct iommu_ops' has no member named 'device_group'
     322 |         .device_group = generic_device_group,
         |          ^~~~~~~~~~~~
>> drivers/iommu/visconti-atu.c:322:25: error: 'generic_device_group' undeclared here (not in a function)
     322 |         .device_group = generic_device_group,
         |                         ^~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:322:25: warning: excess elements in struct initializer
   drivers/iommu/visconti-atu.c:322:25: note: (near initialization for 'visconti_atu_ops')
>> drivers/iommu/visconti-atu.c:323:10: error: 'const struct iommu_ops' has no member named 'of_xlate'
     323 |         .of_xlate = visconti_atu_of_xlate,
         |          ^~~~~~~~
   drivers/iommu/visconti-atu.c:323:21: warning: excess elements in struct initializer
     323 |         .of_xlate = visconti_atu_of_xlate,
         |                     ^~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:323:21: note: (near initialization for 'visconti_atu_ops')
>> drivers/iommu/visconti-atu.c:324:10: error: 'const struct iommu_ops' has no member named 'pgsize_bitmap'
     324 |         .pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
         |          ^~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:41:33: warning: excess elements in struct initializer
      41 | #define ATU_IOMMU_PGSIZE_BITMAP 0x7ffff000 /* SZ_1G - SZ_4K */
         |                                 ^~~~~~~~~~
   drivers/iommu/visconti-atu.c:324:26: note: in expansion of macro 'ATU_IOMMU_PGSIZE_BITMAP'
     324 |         .pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:41:33: note: (near initialization for 'visconti_atu_ops')
      41 | #define ATU_IOMMU_PGSIZE_BITMAP 0x7ffff000 /* SZ_1G - SZ_4K */
         |                                 ^~~~~~~~~~
   drivers/iommu/visconti-atu.c:324:26: note: in expansion of macro 'ATU_IOMMU_PGSIZE_BITMAP'
     324 |         .pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/iommu/visconti-atu.c:325:10: error: 'const struct iommu_ops' has no member named 'default_domain_ops'
     325 |         .default_domain_ops = &(const struct iommu_domain_ops) {
         |          ^~~~~~~~~~~~~~~~~~
>> drivers/iommu/visconti-atu.c:326:18: error: 'const struct iommu_domain_ops' has no member named 'attach_dev'
     326 |                 .attach_dev = visconti_atu_attach_device,
         |                  ^~~~~~~~~~
   drivers/iommu/visconti-atu.c:326:31: warning: excess elements in struct initializer
     326 |                 .attach_dev = visconti_atu_attach_device,
         |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:326:31: note: (near initialization for '(anonymous)')
>> drivers/iommu/visconti-atu.c:327:18: error: 'const struct iommu_domain_ops' has no member named 'detach_dev'
     327 |                 .detach_dev = visconti_atu_detach_device,
         |                  ^~~~~~~~~~
   drivers/iommu/visconti-atu.c:327:31: warning: excess elements in struct initializer
     327 |                 .detach_dev = visconti_atu_detach_device,
         |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:327:31: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:328:18: error: 'const struct iommu_domain_ops' has no member named 'map'
     328 |                 .map = visconti_atu_map,
         |                  ^~~
   drivers/iommu/visconti-atu.c:328:24: warning: excess elements in struct initializer
     328 |                 .map = visconti_atu_map,
         |                        ^~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:328:24: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:329:18: error: 'const struct iommu_domain_ops' has no member named 'unmap'
     329 |                 .unmap = visconti_atu_unmap,
         |                  ^~~~~
   drivers/iommu/visconti-atu.c:329:26: warning: excess elements in struct initializer
     329 |                 .unmap = visconti_atu_unmap,
         |                          ^~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:329:26: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:330:18: error: 'const struct iommu_domain_ops' has no member named 'iova_to_phys'
     330 |                 .iova_to_phys = visconti_atu_iova_to_phys,
         |                  ^~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:330:33: warning: excess elements in struct initializer
     330 |                 .iova_to_phys = visconti_atu_iova_to_phys,
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:330:33: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:331:18: error: 'const struct iommu_domain_ops' has no member named 'free'
     331 |                 .free = visconti_atu_domain_free,
         |                  ^~~~
   drivers/iommu/visconti-atu.c:331:25: warning: excess elements in struct initializer
     331 |                 .free = visconti_atu_domain_free,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:331:25: note: (near initialization for '(anonymous)')
   drivers/iommu/visconti-atu.c:325:64: error: invalid use of undefined type 'const struct iommu_domain_ops'
     325 |         .default_domain_ops = &(const struct iommu_domain_ops) {
         |                                                                ^
   drivers/iommu/visconti-atu.c:325:31: warning: excess elements in struct initializer
     325 |         .default_domain_ops = &(const struct iommu_domain_ops) {
         |                               ^
   drivers/iommu/visconti-atu.c:325:31: note: (near initialization for 'visconti_atu_ops')
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_probe':
   drivers/iommu/visconti-atu.c:366:22: error: implicit declaration of function 'iommu_group_alloc' [-Werror=implicit-function-declaration]
     366 |         atu->group = iommu_group_alloc();
         |                      ^~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:366:20: warning: assignment to 'struct iommu_group *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     366 |         atu->group = iommu_group_alloc();
         |                    ^
   drivers/iommu/visconti-atu.c:380:15: error: implicit declaration of function 'iommu_device_sysfs_add' [-Werror=implicit-function-declaration]
     380 |         ret = iommu_device_sysfs_add(&atu->iommu, dev, NULL, dev_name(dev));
         |               ^~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:384:15: error: implicit declaration of function 'iommu_device_register'; did you mean 'of_device_register'? [-Werror=implicit-function-declaration]
     384 |         ret = iommu_device_register(&atu->iommu, &visconti_atu_ops, dev);
         |               ^~~~~~~~~~~~~~~~~~~~~
         |               of_device_register
   drivers/iommu/visconti-atu.c:388:14: error: implicit declaration of function 'iommu_present'; did you mean 'pmd_present'? [-Werror=implicit-function-declaration]
     388 |         if (!iommu_present(&platform_bus_type))
         |              ^~~~~~~~~~~~~
         |              pmd_present
   drivers/iommu/visconti-atu.c:389:17: error: implicit declaration of function 'bus_set_iommu' [-Werror=implicit-function-declaration]
     389 |                 bus_set_iommu(&platform_bus_type, &visconti_atu_ops);
         |                 ^~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:395:9: error: implicit declaration of function 'iommu_device_sysfs_remove' [-Werror=implicit-function-declaration]
     395 |         iommu_device_sysfs_remove(&atu->iommu);
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c: In function 'visconti_atu_remove':
   drivers/iommu/visconti-atu.c:405:9: error: implicit declaration of function 'iommu_device_unregister'; did you mean 'of_device_unregister'? [-Werror=implicit-function-declaration]
     405 |         iommu_device_unregister(&atu->iommu);
         |         ^~~~~~~~~~~~~~~~~~~~~~~
         |         of_device_unregister
   drivers/iommu/visconti-atu.c: At top level:
   drivers/iommu/visconti-atu.c:318:31: error: storage size of 'visconti_atu_ops' isn't known
     318 | static const struct iommu_ops visconti_atu_ops = {
         |                               ^~~~~~~~~~~~~~~~
   drivers/iommu/visconti-atu.c:318:31: error: storage size of 'visconti_atu_ops' isn't known
   cc1: some warnings being treated as errors


vim +/iommu +47 drivers/iommu/visconti-atu.c

    43	
    44	struct visconti_atu_device {
    45		struct device *dev;
    46		void __iomem *base;
  > 47		struct iommu_device iommu;
    48		struct iommu_group *group;
    49	
    50		unsigned int num_entry;
    51		unsigned int num_map_entry;
    52		unsigned int enable_entry;
    53		unsigned long iova[ATU_MAX_IOMMU_ENTRY];
    54		phys_addr_t paddr[ATU_MAX_IOMMU_ENTRY];
    55		size_t size[ATU_MAX_IOMMU_ENTRY];
    56	
    57		spinlock_t lock;
    58	};
    59	
    60	struct visconti_atu_domain {
    61		struct visconti_atu_device *atu;
  > 62		struct iommu_domain io_domain;
    63		struct mutex mutex;
    64	};
    65	
    66	static const struct iommu_ops visconti_atu_ops;
    67	
    68	static struct visconti_atu_domain *to_atu_domain(struct iommu_domain *domain)
    69	{
    70		return container_of(domain, struct visconti_atu_domain, io_domain);
    71	}
    72	
    73	static inline void visconti_atu_write(struct visconti_atu_device *atu, u32 reg,
    74					      u32 val)
    75	{
    76		writel_relaxed(val, atu->base + reg);
    77	}
    78	
    79	static inline u32 visconti_atu_read(struct visconti_atu_device *atu, u32 reg)
    80	{
    81		return readl_relaxed(atu->base + reg);
    82	}
    83	
    84	static void visconti_atu_enable_entry(struct visconti_atu_device *atu,
    85					      int num)
    86	{
    87		dev_dbg(atu->dev, "enable ATU: %d\n", atu->enable_entry);
    88	
    89		visconti_atu_write(atu, ATU_AT_EN, 0);
    90		if (atu->enable_entry & BIT(num)) {
    91			visconti_atu_write(atu,
    92					   ATU_AT_REG(num, ATU_AT_BLADDR),
    93					   atu->iova[num]);
    94			visconti_atu_write(atu,
    95					   ATU_AT_REG(num, ATU_AT_ELADDR),
    96					   atu->iova[num] + atu->size[num] - 1);
    97			visconti_atu_write(atu,
    98					   ATU_AT_REG(num, ATU_AT_BGADDR0),
    99					   atu->iova[num] & ATU_BGADDR_MASK);
   100			visconti_atu_write(atu,
   101					   ATU_AT_REG(num, ATU_AT_BGADDR1),
   102					   (atu->iova[num] >> 32) & ATU_BGADDR_MASK);
   103		}
   104		visconti_atu_write(atu, ATU_AT_ENTRY_EN, atu->enable_entry);
   105		visconti_atu_write(atu, ATU_AT_EN, 1);
   106	}
   107	
   108	static void visconti_atu_disable_entry(struct visconti_atu_device *atu)
   109	{
   110		dev_dbg(atu->dev, "disable ATU: %d\n", atu->enable_entry);
   111	
   112		visconti_atu_write(atu, ATU_AT_EN, 0);
   113		visconti_atu_write(atu, ATU_AT_ENTRY_EN, atu->enable_entry);
   114		visconti_atu_write(atu, ATU_AT_EN, 1);
   115	}
   116	
   117	static int visconti_atu_attach_device(struct iommu_domain *io_domain,
   118					      struct device *dev)
   119	{
   120		struct visconti_atu_domain *domain = to_atu_domain(io_domain);
 > 121		struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
   122		int ret = 0;
   123	
   124		if (!atu) {
   125			dev_err(dev, "Cannot attach to ATU\n");
   126			return -ENXIO;
   127		}
   128	
   129		mutex_lock(&domain->mutex);
   130	
   131		if (!domain->atu) {
   132			domain->atu = atu;
   133		} else if (domain->atu != atu) {
   134			dev_err(dev, "Can't attach ATU %s to domain on ATU %s\n",
   135				dev_name(atu->dev), dev_name(domain->atu->dev));
   136			ret = -EINVAL;
   137		} else {
   138			dev_warn(dev, "Reusing ATU context\n");
   139		}
   140	
   141		mutex_unlock(&domain->mutex);
   142	
   143		return ret;
   144	}
   145
Jason Gunthorpe May 25, 2022, 6:26 p.m. UTC | #5
On Wed, May 25, 2022 at 02:26:37PM +0800, Baolu Lu wrote:
> On 2022/5/25 09:31, Nobuhiro Iwamatsu wrote:
> > +static const struct iommu_ops visconti_atu_ops = {
> > +	.domain_alloc = visconti_atu_domain_alloc,
> > +	.probe_device = visconti_atu_probe_device,
> > +	.release_device = visconti_atu_release_device,
> > +	.device_group = generic_device_group,
> > +	.of_xlate = visconti_atu_of_xlate,
> > +	.pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
> > +	.default_domain_ops = &(const struct iommu_domain_ops) {
> > +		.attach_dev = visconti_atu_attach_device,
> > +		.detach_dev = visconti_atu_detach_device,
> 
> The detach_dev callback is about to be deprecated. The new drivers
> should implement the default domain and blocking domain instead.

Yes please, new drivers need to use default_domains.

It is very strange that visconti_atu_detach_device() does nothing.  It
is not required that a domain is fully unmapped before being
destructed, I think detach should set ATU_AT_EN to 0.

What behavior does the HW have when ATU_AT_ENTRY_EN == 0? If DMA is
rejected then this driver should have a IOMMU_DOMAIN_BLOCKING and
return that from ops->def_domain_type().

Attaching a the blocking domain should set ATU_AT_ENTRY_EN = 0

Also, if I surmise how this works properly, it is not following the
iommu API to halt all DMA during map/unmap operations. Should at least
document this and explain why it is OK..

I'm feeling like these "special" drivers need some kind of handshake
with their only users because they don't work with things like VFIO..

Jason
Tian, Kevin May 26, 2022, 12:43 a.m. UTC | #6
> From: Jason Gunthorpe
> Sent: Thursday, May 26, 2022 2:27 AM
> 
> On Wed, May 25, 2022 at 02:26:37PM +0800, Baolu Lu wrote:
> > On 2022/5/25 09:31, Nobuhiro Iwamatsu wrote:
> > > +static const struct iommu_ops visconti_atu_ops = {
> > > +	.domain_alloc = visconti_atu_domain_alloc,
> > > +	.probe_device = visconti_atu_probe_device,
> > > +	.release_device = visconti_atu_release_device,
> > > +	.device_group = generic_device_group,
> > > +	.of_xlate = visconti_atu_of_xlate,
> > > +	.pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
> > > +	.default_domain_ops = &(const struct iommu_domain_ops) {
> > > +		.attach_dev = visconti_atu_attach_device,
> > > +		.detach_dev = visconti_atu_detach_device,
> >
> > The detach_dev callback is about to be deprecated. The new drivers
> > should implement the default domain and blocking domain instead.
> 
> Yes please, new drivers need to use default_domains.
> 
> It is very strange that visconti_atu_detach_device() does nothing.  It
> is not required that a domain is fully unmapped before being
> destructed, I think detach should set ATU_AT_EN to 0.

Looks the atu is shared by all devices behind and can only serve one
I/O address space. The atu registers only keep information about
iova ranges without any device notation. That is probably the reason 
why both attach/detach() don't touch hardware.

iiuc then this suggests there should be only one iommu group per atu,
instead of using generic_device_group() to create one group per
device.

> 
> What behavior does the HW have when ATU_AT_ENTRY_EN == 0? If DMA is

I guess it's a blocking behavior since that register tracks which iova range
register is valid. 

> rejected then this driver should have a IOMMU_DOMAIN_BLOCKING and
> return that from ops->def_domain_type().

BLOCKING should not be used as a default domain type for DMA API
which needs either a DMA or IDENTITY type.

> 
> Attaching a the blocking domain should set ATU_AT_ENTRY_EN = 0

Agree

> 
> Also, if I surmise how this works properly, it is not following the
> iommu API to halt all DMA during map/unmap operations. Should at least
> document this and explain why it is OK..
> 
> I'm feeling like these "special" drivers need some kind of handshake
> with their only users because they don't work with things like VFIO..
> 
> Jason
Jason Gunthorpe May 26, 2022, 1:40 a.m. UTC | #7
On Thu, May 26, 2022 at 12:43:25AM +0000, Tian, Kevin wrote:

> iiuc then this suggests there should be only one iommu group per atu,
> instead of using generic_device_group() to create one group per
> device.

Sounds like it

> > rejected then this driver should have a IOMMU_DOMAIN_BLOCKING and
> > return that from ops->def_domain_type().
> 
> BLOCKING should not be used as a default domain type for DMA API
> which needs either a DMA or IDENTITY type.

New drivers should not have a NULL group->default_domain. 

IMHO this driver does not support the DMA API so the default_domain
should be assigned to blocking and the DMA API disabled. We might need
some core changes to accommodate this.

The alternative would be to implement the identity domain, assuming
the ATU thing can store that kind of translation.

Jason
Nobuhiro Iwamatsu June 20, 2022, 2:15 a.m. UTC | #8
Hi,

> -----Original Message-----
> From: Baolu Lu <baolu.lu@linux.intel.com>
> Sent: Wednesday, May 25, 2022 3:27 PM
> To: iwamatsu nobuhiro(岩松 信洋 □SWC◯ACT)
> <nobuhiro1.iwamatsu@toshiba.co.jp>; Joerg Roedel <joro@8bytes.org>; Will
> Deacon <will@kernel.org>; Rob Herring <robh+dt@kernel.org>; Jason
> Gunthorpe <jgg@nvidia.com>
> Cc: baolu.lu@linux.intel.com; devicetree@vger.kernel.org;
> linux-kernel@vger.kernel.org; iommu@lists.linux-foundation.org; ishikawa
> yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>; linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH 1/3] iommu: Add Visconti5 IOMMU driver
> 
> On 2022/5/25 09:31, Nobuhiro Iwamatsu wrote:
> > +static const struct iommu_ops visconti_atu_ops = {
> > +	.domain_alloc = visconti_atu_domain_alloc,
> > +	.probe_device = visconti_atu_probe_device,
> > +	.release_device = visconti_atu_release_device,
> > +	.device_group = generic_device_group,
> > +	.of_xlate = visconti_atu_of_xlate,
> > +	.pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
> > +	.default_domain_ops = &(const struct iommu_domain_ops) {
> > +		.attach_dev = visconti_atu_attach_device,
> > +		.detach_dev = visconti_atu_detach_device,
> 
> The detach_dev callback is about to be deprecated. The new drivers should
> implement the default domain and blocking domain instead.

I see. I will update this with next version.

> 
> > +		.map = visconti_atu_map,
> > +		.unmap = visconti_atu_unmap,
> > +		.iova_to_phys = visconti_atu_iova_to_phys,
> > +		.free = visconti_atu_domain_free,
> > +	}
> > +};
> 
> Best regards,
> baolu

Best regards,
  Nobuhiro
Nobuhiro Iwamatsu June 20, 2022, 5:49 a.m. UTC | #9
Hi,

Thanks for your review.

> -----Original Message-----
> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Thursday, May 26, 2022 3:27 AM
> To: Baolu Lu <baolu.lu@linux.intel.com>
> Cc: iwamatsu nobuhiro(岩松 信洋 □SWC◯ACT)
> <nobuhiro1.iwamatsu@toshiba.co.jp>; Joerg Roedel <joro@8bytes.org>; Will
> Deacon <will@kernel.org>; Rob Herring <robh+dt@kernel.org>;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> iommu@lists.linux-foundation.org; ishikawa yuji(石川 悠司 ○RDC□AIT
> C○EA開) <yuji2.ishikawa@toshiba.co.jp>;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH 1/3] iommu: Add Visconti5 IOMMU driver
> 
> On Wed, May 25, 2022 at 02:26:37PM +0800, Baolu Lu wrote:
> > On 2022/5/25 09:31, Nobuhiro Iwamatsu wrote:
> > > +static const struct iommu_ops visconti_atu_ops = {
> > > +	.domain_alloc = visconti_atu_domain_alloc,
> > > +	.probe_device = visconti_atu_probe_device,
> > > +	.release_device = visconti_atu_release_device,
> > > +	.device_group = generic_device_group,
> > > +	.of_xlate = visconti_atu_of_xlate,
> > > +	.pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
> > > +	.default_domain_ops = &(const struct iommu_domain_ops) {
> > > +		.attach_dev = visconti_atu_attach_device,
> > > +		.detach_dev = visconti_atu_detach_device,
> >
> > The detach_dev callback is about to be deprecated. The new drivers
> > should implement the default domain and blocking domain instead.
> 
> Yes please, new drivers need to use default_domains.
> 
> It is very strange that visconti_atu_detach_device() does nothing.  It is not
> required that a domain is fully unmapped before being destructed, I think
> detach should set ATU_AT_EN to 0.

I see, I rethink implementation.

> 
> What behavior does the HW have when ATU_AT_ENTRY_EN == 0? If DMA is
> rejected then this driver should have a IOMMU_DOMAIN_BLOCKING and
> return that from ops->def_domain_type().

If ATU_AT_ENTRY_EN is 0, nothing happens. It does not work with IOMMU,
it works with the memory space set in device tree.
Also, I investigate about IOMMU_DOMAIN_BLOCKING.

> 
> Attaching a the blocking domain should set ATU_AT_ENTRY_EN = 0
> 
> Also, if I surmise how this works properly, it is not following the iommu API to
> halt all DMA during map/unmap operations. Should at least document this and
> explain why it is OK..

I see, I will check DMA during map and unmap operations.

> 
> I'm feeling like these "special" drivers need some kind of handshake with their
> only users because they don't work with things like VFIO..

Since the devices that utilize this IOMMU function are fixed, I do not think that a special handshake is required.
Could you you tell me where you thought you needed a handshake?

Best regards,
  Nobuhiro

> 
> Jason
Jason Gunthorpe June 24, 2022, 1:39 p.m. UTC | #10
On Mon, Jun 20, 2022 at 05:49:13AM +0000, nobuhiro1.iwamatsu@toshiba.co.jp wrote:
> Hi,
> 
> Thanks for your review.
> 
> > -----Original Message-----
> > From: Jason Gunthorpe <jgg@nvidia.com>
> > Sent: Thursday, May 26, 2022 3:27 AM
> > To: Baolu Lu <baolu.lu@linux.intel.com>
> > Cc: iwamatsu nobuhiro(岩松 信洋 □SWC◯ACT)
> > <nobuhiro1.iwamatsu@toshiba.co.jp>; Joerg Roedel <joro@8bytes.org>; Will
> > Deacon <will@kernel.org>; Rob Herring <robh+dt@kernel.org>;
> > devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> > iommu@lists.linux-foundation.org; ishikawa yuji(石川 悠司 ○RDC□AIT
> > C○EA開) <yuji2.ishikawa@toshiba.co.jp>;
> > linux-arm-kernel@lists.infradead.org
> > Subject: Re: [PATCH 1/3] iommu: Add Visconti5 IOMMU driver
> > 
> > On Wed, May 25, 2022 at 02:26:37PM +0800, Baolu Lu wrote:
> > > On 2022/5/25 09:31, Nobuhiro Iwamatsu wrote:
> > > > +static const struct iommu_ops visconti_atu_ops = {
> > > > +	.domain_alloc = visconti_atu_domain_alloc,
> > > > +	.probe_device = visconti_atu_probe_device,
> > > > +	.release_device = visconti_atu_release_device,
> > > > +	.device_group = generic_device_group,
> > > > +	.of_xlate = visconti_atu_of_xlate,
> > > > +	.pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
> > > > +	.default_domain_ops = &(const struct iommu_domain_ops) {
> > > > +		.attach_dev = visconti_atu_attach_device,
> > > > +		.detach_dev = visconti_atu_detach_device,
> > >
> > > The detach_dev callback is about to be deprecated. The new drivers
> > > should implement the default domain and blocking domain instead.
> > 
> > Yes please, new drivers need to use default_domains.
> > 
> > It is very strange that visconti_atu_detach_device() does nothing.  It is not
> > required that a domain is fully unmapped before being destructed, I think
> > detach should set ATU_AT_EN to 0.
> 
> I see, I rethink implementation.
> 
> > 
> > What behavior does the HW have when ATU_AT_ENTRY_EN == 0? If DMA is
> > rejected then this driver should have a IOMMU_DOMAIN_BLOCKING and
> > return that from ops->def_domain_type().
> 
> If ATU_AT_ENTRY_EN is 0, nothing happens. It does not work with IOMMU,
> it works with the memory space set in device tree.

So that would be an assignment to DOMAIN_IDENTITY

> > I'm feeling like these "special" drivers need some kind of handshake with their
> > only users because they don't work with things like VFIO..
> 
> Since the devices that utilize this IOMMU function are fixed, I do
> not think that a special handshake is required.  Could you you tell
> me where you thought you needed a handshake?

In this case the iommu driver is so limited that it will not work with
VFIO - it is only ment to be used with the fixed drivers that are
paired with it.

Ideally we'd prevent VFIO from connecting and only allow drivers that
know the limitations of the IOMMU to use the unmanaged domain.

Jason
diff mbox series

Patch

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index c79a0df090c0..8a4351020b7f 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -486,4 +486,11 @@  config SPRD_IOMMU
 
 	  Say Y here if you want to use the multimedia devices listed above.
 
+config VISCONTI_ATU
+	tristate "Toshiba Visconti5 IOMMU Support"
+	depends on ARCH_VISCONTI || COMPILE_TEST
+	select IOMMU_API
+	help
+	  Support for the IOMMU API for Toshiba Visconti5 ARM SoCs.
+
 endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 44475a9b3eea..077189f908ea 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -30,3 +30,4 @@  obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
 obj-$(CONFIG_IOMMU_SVA) += iommu-sva-lib.o io-pgfault.o
 obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o
 obj-$(CONFIG_APPLE_DART) += apple-dart.o
+obj-$(CONFIG_VISCONTI_ATU) += visconti-atu.o
diff --git a/drivers/iommu/visconti-atu.c b/drivers/iommu/visconti-atu.c
new file mode 100644
index 000000000000..269c912ad4c9
--- /dev/null
+++ b/drivers/iommu/visconti-atu.c
@@ -0,0 +1,426 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Toshiba Visconti5 IOMMU (ATU) driver
+ *
+ * (C) Copyright 2022 Toshiba Electronic Devices & Storage Corporation
+ * (C) Copyright 2022 Toshiba CORPORATION
+ *
+ * Author: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
+ */
+
+#include <linux/dma-iommu.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+
+/* Regsiter address */
+#define ATU_AT_EN		0x0000
+#define ATU_AT_ENTRY_EN		0x0020
+
+#define ATU_AT_BLADDR		0x0030
+#define ATU_AT_ELADDR		0x0038
+#define ATU_AT_BGADDR0		0x0040
+#define ATU_AT_BGADDR1		0x0044
+#define ATU_AT_CONF		0x0048
+#define ATU_AT_REG(n, reg)	(0x20 * n + reg)
+
+#define ATU_INT_START		0x0440
+#define ATU_INT_MASKED_STAT	0x0444
+#define ATU_INT_MASK		0x0448
+#define ATU_RP_CONF		0x0450
+#define ATU_ERR_ADDR		0x0454
+#define ATU_ERR_CLR		0x045C
+#define ATU_STAT		0x0460
+
+#define ATU_BGADDR_MASK GENMASK(31, 0)
+
+#define ATU_IOMMU_PGSIZE_BITMAP	0x7ffff000 /* SZ_1G - SZ_4K */
+#define ATU_MAX_IOMMU_ENTRY	32
+
+struct visconti_atu_device {
+	struct device *dev;
+	void __iomem *base;
+	struct iommu_device iommu;
+	struct iommu_group *group;
+
+	unsigned int num_entry;
+	unsigned int num_map_entry;
+	unsigned int enable_entry;
+	unsigned long iova[ATU_MAX_IOMMU_ENTRY];
+	phys_addr_t paddr[ATU_MAX_IOMMU_ENTRY];
+	size_t size[ATU_MAX_IOMMU_ENTRY];
+
+	spinlock_t lock;
+};
+
+struct visconti_atu_domain {
+	struct visconti_atu_device *atu;
+	struct iommu_domain io_domain;
+	struct mutex mutex;
+};
+
+static const struct iommu_ops visconti_atu_ops;
+
+static struct visconti_atu_domain *to_atu_domain(struct iommu_domain *domain)
+{
+	return container_of(domain, struct visconti_atu_domain, io_domain);
+}
+
+static inline void visconti_atu_write(struct visconti_atu_device *atu, u32 reg,
+				      u32 val)
+{
+	writel_relaxed(val, atu->base + reg);
+}
+
+static inline u32 visconti_atu_read(struct visconti_atu_device *atu, u32 reg)
+{
+	return readl_relaxed(atu->base + reg);
+}
+
+static void visconti_atu_enable_entry(struct visconti_atu_device *atu,
+				      int num)
+{
+	dev_dbg(atu->dev, "enable ATU: %d\n", atu->enable_entry);
+
+	visconti_atu_write(atu, ATU_AT_EN, 0);
+	if (atu->enable_entry & BIT(num)) {
+		visconti_atu_write(atu,
+				   ATU_AT_REG(num, ATU_AT_BLADDR),
+				   atu->iova[num]);
+		visconti_atu_write(atu,
+				   ATU_AT_REG(num, ATU_AT_ELADDR),
+				   atu->iova[num] + atu->size[num] - 1);
+		visconti_atu_write(atu,
+				   ATU_AT_REG(num, ATU_AT_BGADDR0),
+				   atu->iova[num] & ATU_BGADDR_MASK);
+		visconti_atu_write(atu,
+				   ATU_AT_REG(num, ATU_AT_BGADDR1),
+				   (atu->iova[num] >> 32) & ATU_BGADDR_MASK);
+	}
+	visconti_atu_write(atu, ATU_AT_ENTRY_EN, atu->enable_entry);
+	visconti_atu_write(atu, ATU_AT_EN, 1);
+}
+
+static void visconti_atu_disable_entry(struct visconti_atu_device *atu)
+{
+	dev_dbg(atu->dev, "disable ATU: %d\n", atu->enable_entry);
+
+	visconti_atu_write(atu, ATU_AT_EN, 0);
+	visconti_atu_write(atu, ATU_AT_ENTRY_EN, atu->enable_entry);
+	visconti_atu_write(atu, ATU_AT_EN, 1);
+}
+
+static int visconti_atu_attach_device(struct iommu_domain *io_domain,
+				      struct device *dev)
+{
+	struct visconti_atu_domain *domain = to_atu_domain(io_domain);
+	struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
+	int ret = 0;
+
+	if (!atu) {
+		dev_err(dev, "Cannot attach to ATU\n");
+		return -ENXIO;
+	}
+
+	mutex_lock(&domain->mutex);
+
+	if (!domain->atu) {
+		domain->atu = atu;
+	} else if (domain->atu != atu) {
+		dev_err(dev, "Can't attach ATU %s to domain on ATU %s\n",
+			dev_name(atu->dev), dev_name(domain->atu->dev));
+		ret = -EINVAL;
+	} else {
+		dev_warn(dev, "Reusing ATU context\n");
+	}
+
+	mutex_unlock(&domain->mutex);
+
+	return ret;
+}
+
+static void visconti_atu_detach_device(struct iommu_domain *io_domain,
+				       struct device *dev)
+{
+	struct visconti_atu_domain *domain = to_atu_domain(io_domain);
+	struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
+
+	if (domain->atu != atu)
+		return;
+
+	domain->atu = NULL;
+}
+
+static int visconti_atu_map(struct iommu_domain *io_domain,
+			    unsigned long iova,
+			    phys_addr_t paddr,
+			    size_t size, int prot, gfp_t gfp)
+{
+	struct visconti_atu_domain *domain = to_atu_domain(io_domain);
+	struct visconti_atu_device *atu = domain->atu;
+	unsigned long flags;
+	unsigned int i;
+
+	if (!domain)
+		return -ENODEV;
+
+	spin_lock_irqsave(&atu->lock, flags);
+	for (i = 0; i < atu->num_map_entry; i++) {
+		if (!(atu->enable_entry & BIT(i))) {
+			atu->enable_entry |= BIT(i);
+			atu->iova[i] = iova;
+			atu->paddr[i] = paddr;
+			atu->size[i] = size;
+
+			visconti_atu_enable_entry(atu, i);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&atu->lock, flags);
+
+	if (i == atu->num_map_entry) {
+		dev_err(atu->dev, "map: not enough entry.\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static size_t visconti_atu_unmap(struct iommu_domain *io_domain,
+				 unsigned long iova,
+				 size_t size,
+				 struct iommu_iotlb_gather *iotlb_gather)
+{
+	struct visconti_atu_domain *domain = to_atu_domain(io_domain);
+	struct visconti_atu_device *atu = domain->atu;
+	size_t tmp_size = size;
+	unsigned long flags;
+	unsigned int i;
+
+	spin_lock_irqsave(&atu->lock, flags);
+
+	while (tmp_size != 0) {
+		for (i = 0; i < atu->num_map_entry; i++) {
+			if (atu->iova[i] != iova)
+				continue;
+
+			atu->enable_entry &= ~BIT(i);
+			iova += atu->size[i];
+			tmp_size -= atu->size[i];
+
+			visconti_atu_disable_entry(atu);
+
+			break;
+		}
+		if (i == atu->num_map_entry) {
+			dev_err(atu->dev, "unmap: not found entry.\n");
+			size = 0;
+			goto out;
+		}
+	}
+
+	if (!atu->num_map_entry)
+		visconti_atu_write(atu, ATU_AT_EN, 0);
+out:
+	spin_unlock_irqrestore(&atu->lock, flags);
+	return size;
+}
+
+static phys_addr_t visconti_atu_iova_to_phys(struct iommu_domain *io_domain,
+					     dma_addr_t iova)
+{
+	struct visconti_atu_domain *domain = to_atu_domain(io_domain);
+	struct visconti_atu_device *atu = domain->atu;
+	phys_addr_t paddr = 0;
+	unsigned int i;
+
+	for (i = 0; i < atu->num_map_entry; i++) {
+		if (!(atu->enable_entry & BIT(i)))
+			continue;
+		if (atu->iova[i] <= iova && iova < (atu->iova[i] + atu->size[i])) {
+			paddr = atu->paddr[i];
+			paddr += iova & (atu->size[i] - 1);
+			break;
+		}
+	}
+
+	dev_dbg(atu->dev, "iova_to_phys: %llx -> %llx\n", iova, paddr);
+
+	return paddr;
+}
+
+static int visconti_atu_of_xlate(struct device *dev, struct of_phandle_args *args)
+{
+	if (!dev_iommu_priv_get(dev)) {
+		struct platform_device *pdev;
+
+		pdev = of_find_device_by_node(args->np);
+		dev_iommu_priv_set(dev, platform_get_drvdata(pdev));
+		platform_device_put(pdev);
+	}
+
+	return 0;
+}
+
+static struct iommu_domain *visconti_atu_domain_alloc(unsigned int type)
+{
+	struct visconti_atu_domain *domain;
+
+	if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
+		return NULL;
+
+	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+	if (!domain)
+		return NULL;
+
+	mutex_init(&domain->mutex);
+
+	domain->io_domain.geometry.aperture_start = 0;
+	domain->io_domain.geometry.aperture_end = DMA_BIT_MASK(32);
+	domain->io_domain.geometry.force_aperture = true;
+
+	return &domain->io_domain;
+}
+
+static void visconti_atu_domain_free(struct iommu_domain *io_domain)
+{
+	struct visconti_atu_domain *domain = to_atu_domain(io_domain);
+
+	kfree(domain);
+}
+
+static struct iommu_device *visconti_atu_probe_device(struct device *dev)
+{
+	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+	struct visconti_atu_device *atu;
+
+	if (!fwspec || fwspec->ops != &visconti_atu_ops)
+		return ERR_PTR(-ENODEV);
+
+	atu = dev_iommu_priv_get(dev);
+	return &atu->iommu;
+}
+
+static void visconti_atu_release_device(struct device *dev)
+{
+	struct visconti_atu_device *atu = dev_iommu_priv_get(dev);
+
+	if (!atu)
+		return;
+
+	iommu_fwspec_free(dev);
+}
+
+static const struct iommu_ops visconti_atu_ops = {
+	.domain_alloc = visconti_atu_domain_alloc,
+	.probe_device = visconti_atu_probe_device,
+	.release_device = visconti_atu_release_device,
+	.device_group = generic_device_group,
+	.of_xlate = visconti_atu_of_xlate,
+	.pgsize_bitmap = ATU_IOMMU_PGSIZE_BITMAP,
+	.default_domain_ops = &(const struct iommu_domain_ops) {
+		.attach_dev = visconti_atu_attach_device,
+		.detach_dev = visconti_atu_detach_device,
+		.map = visconti_atu_map,
+		.unmap = visconti_atu_unmap,
+		.iova_to_phys = visconti_atu_iova_to_phys,
+		.free = visconti_atu_domain_free,
+	}
+};
+
+static int visconti_atu_probe(struct platform_device *pdev)
+{
+	struct visconti_atu_device *atu;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	u32 reserved_entry;
+	int ret;
+
+	atu = devm_kzalloc(&pdev->dev, sizeof(*atu), GFP_KERNEL);
+	if (!atu)
+		return -ENOMEM;
+
+	ret = of_property_read_u32(dev->of_node, "toshiba,max-entry",
+				   &atu->num_entry);
+	if (ret < 0) {
+		dev_err(dev, "cannot get max-entry data\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "toshiba,reserved-entry",
+				   &reserved_entry);
+	if (ret < 0)
+		reserved_entry = 0;
+
+	if (atu->num_entry < reserved_entry)
+		return -EINVAL;
+
+	atu->num_map_entry = atu->num_entry - reserved_entry;
+	atu->enable_entry = 0;
+	atu->dev = dev;
+
+	atu->group = iommu_group_alloc();
+	if (IS_ERR(atu->group)) {
+		ret = PTR_ERR(atu->group);
+		goto out;
+	}
+
+	spin_lock_init(&atu->lock);
+
+	atu->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(atu->base)) {
+		ret = PTR_ERR(atu->base);
+		goto out;
+	}
+
+	ret = iommu_device_sysfs_add(&atu->iommu, dev, NULL, dev_name(dev));
+	if (ret)
+		goto out;
+
+	ret = iommu_device_register(&atu->iommu, &visconti_atu_ops, dev);
+	if (ret)
+		goto remove_sysfs;
+
+	if (!iommu_present(&platform_bus_type))
+		bus_set_iommu(&platform_bus_type, &visconti_atu_ops);
+	platform_set_drvdata(pdev, atu);
+
+	return 0;
+
+remove_sysfs:
+	iommu_device_sysfs_remove(&atu->iommu);
+out:
+	return ret;
+}
+
+static int visconti_atu_remove(struct platform_device *pdev)
+{
+	struct visconti_atu_device *atu = platform_get_drvdata(pdev);
+
+	iommu_device_sysfs_remove(&atu->iommu);
+	iommu_device_unregister(&atu->iommu);
+
+	return 0;
+}
+
+static const struct of_device_id visconti_atu_of_match[] = {
+	{ .compatible = "toshiba,visconti-atu", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, visconti_atu_of_match);
+
+static struct platform_driver visconti_atu_driver = {
+	.driver = {
+		.name = "visconti-atu",
+		.of_match_table = visconti_atu_of_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = visconti_atu_probe,
+	.remove = visconti_atu_remove,
+};
+
+builtin_platform_driver(visconti_atu_driver);