| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * ARM SMMU Support | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2015-2016 Broadcom Corporation | 
					
						
							|  |  |  |  * Copyright (c) 2017 Red Hat, Inc. | 
					
						
							|  |  |  |  * Written by Prem Mallappa, Eric Auger | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License version 2 as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef HW_ARM_SMMU_COMMON_H
 | 
					
						
							|  |  |  | #define HW_ARM_SMMU_COMMON_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "hw/sysbus.h"
 | 
					
						
							|  |  |  | #include "hw/pci/pci.h"
 | 
					
						
							| 
									
										
										
										
											2020-09-03 16:43:22 -04:00
										 |  |  | #include "qom/object.h"
 | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define SMMU_PCI_BUS_MAX      256
 | 
					
						
							|  |  |  | #define SMMU_PCI_DEVFN_MAX    256
 | 
					
						
							| 
									
										
										
										
											2018-07-09 14:51:34 +01:00
										 |  |  | #define SMMU_PCI_DEVFN(sid)   (sid & 0xFF)
 | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define SMMU_MAX_VA_BITS      48
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Page table walk error types | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | typedef enum { | 
					
						
							|  |  |  |     SMMU_PTW_ERR_NONE, | 
					
						
							|  |  |  |     SMMU_PTW_ERR_WALK_EABT,   /* Translation walk external abort */ | 
					
						
							|  |  |  |     SMMU_PTW_ERR_TRANSLATION, /* Translation fault */ | 
					
						
							|  |  |  |     SMMU_PTW_ERR_ADDR_SIZE,   /* Address Size fault */ | 
					
						
							|  |  |  |     SMMU_PTW_ERR_ACCESS,      /* Access fault */ | 
					
						
							|  |  |  |     SMMU_PTW_ERR_PERMISSION,  /* Permission fault */ | 
					
						
							|  |  |  | } SMMUPTWEventType; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct SMMUPTWEventInfo { | 
					
						
							|  |  |  |     SMMUPTWEventType type; | 
					
						
							|  |  |  |     dma_addr_t addr; /* fetched address that induced an abort, if any */ | 
					
						
							|  |  |  | } SMMUPTWEventInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct SMMUTransTableInfo { | 
					
						
							|  |  |  |     bool disabled;             /* is the translation table disabled? */ | 
					
						
							|  |  |  |     uint64_t ttb;              /* TT base address */ | 
					
						
							|  |  |  |     uint8_t tsz;               /* input range, ie. 2^(64 -tsz)*/ | 
					
						
							|  |  |  |     uint8_t granule_sz;        /* granule page shift */ | 
					
						
							| 
									
										
										
										
											2020-07-28 17:08:14 +02:00
										 |  |  |     bool had;                  /* hierarchical attribute disable */ | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | } SMMUTransTableInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-28 17:08:08 +02:00
										 |  |  | typedef struct SMMUTLBEntry { | 
					
						
							|  |  |  |     IOMMUTLBEntry entry; | 
					
						
							|  |  |  |     uint8_t level; | 
					
						
							|  |  |  |     uint8_t granule; | 
					
						
							|  |  |  | } SMMUTLBEntry; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Generic structure populated by derived SMMU devices | 
					
						
							|  |  |  |  * after decoding the configuration information and used as | 
					
						
							|  |  |  |  * input to the page table walk | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | typedef struct SMMUTransCfg { | 
					
						
							|  |  |  |     int stage;                 /* translation stage */ | 
					
						
							|  |  |  |     bool aa64;                 /* arch64 or aarch32 translation table */ | 
					
						
							|  |  |  |     bool disabled;             /* smmu is disabled */ | 
					
						
							|  |  |  |     bool bypassed;             /* translation is bypassed */ | 
					
						
							|  |  |  |     bool aborted;              /* translation is aborted */ | 
					
						
							| 
									
										
										
										
											2022-04-27 12:15:43 +01:00
										 |  |  |     bool record_faults;        /* record fault events */ | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  |     uint64_t ttb;              /* TT base address */ | 
					
						
							|  |  |  |     uint8_t oas;               /* output address width */ | 
					
						
							|  |  |  |     uint8_t tbi;               /* Top Byte Ignore */ | 
					
						
							|  |  |  |     uint16_t asid; | 
					
						
							|  |  |  |     SMMUTransTableInfo tt[2]; | 
					
						
							| 
									
										
										
										
											2018-06-26 17:50:42 +01:00
										 |  |  |     uint32_t iotlb_hits;       /* counts IOTLB hits for this asid */ | 
					
						
							|  |  |  |     uint32_t iotlb_misses;     /* counts IOTLB misses for this asid */ | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | } SMMUTransCfg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct SMMUDevice { | 
					
						
							|  |  |  |     void               *smmu; | 
					
						
							|  |  |  |     PCIBus             *bus; | 
					
						
							|  |  |  |     int                devfn; | 
					
						
							|  |  |  |     IOMMUMemoryRegion  iommu; | 
					
						
							|  |  |  |     AddressSpace       as; | 
					
						
							| 
									
										
										
										
											2018-06-26 17:50:42 +01:00
										 |  |  |     uint32_t           cfg_cache_hits; | 
					
						
							|  |  |  |     uint32_t           cfg_cache_misses; | 
					
						
							| 
									
										
										
										
											2019-04-29 17:35:57 +01:00
										 |  |  |     QLIST_ENTRY(SMMUDevice) next; | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | } SMMUDevice; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct SMMUPciBus { | 
					
						
							|  |  |  |     PCIBus       *bus; | 
					
						
							| 
									
										
											  
											
												misc: Replace zero-length arrays with flexible array member (automatic)
Description copied from Linux kernel commit from Gustavo A. R. Silva
(see [3]):
--v-- description start --v--
  The current codebase makes use of the zero-length array language
  extension to the C90 standard, but the preferred mechanism to
  declare variable-length types such as these ones is a flexible
  array member [1], introduced in C99:
  struct foo {
      int stuff;
      struct boo array[];
  };
  By making use of the mechanism above, we will get a compiler
  warning in case the flexible array does not occur last in the
  structure, which will help us prevent some kind of undefined
  behavior bugs from being unadvertenly introduced [2] to the
  Linux codebase from now on.
--^-- description end --^--
Do the similar housekeeping in the QEMU codebase (which uses
C99 since commit 7be41675f7cb).
All these instances of code were found with the help of the
following Coccinelle script:
  @@
  identifier s, m, a;
  type t, T;
  @@
   struct s {
      ...
      t m;
  -   T a[0];
  +   T a[];
  };
  @@
  identifier s, m, a;
  type t, T;
  @@
   struct s {
      ...
      t m;
  -   T a[0];
  +   T a[];
   } QEMU_PACKED;
[1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=76497732932f
[3] https://git.kernel.org/pub/scm/linux/kernel/git/gustavoars/linux.git/commit/?id=17642a2fbd2c1
Inspired-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
											
										 
											2020-03-04 16:38:15 +01:00
										 |  |  |     SMMUDevice   *pbdev[]; /* Parent array is sparse, so dynamically alloc */ | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | } SMMUPciBus; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 17:50:42 +01:00
										 |  |  | typedef struct SMMUIOTLBKey { | 
					
						
							|  |  |  |     uint64_t iova; | 
					
						
							|  |  |  |     uint16_t asid; | 
					
						
							| 
									
										
										
										
											2020-07-28 17:08:09 +02:00
										 |  |  |     uint8_t tg; | 
					
						
							|  |  |  |     uint8_t level; | 
					
						
							| 
									
										
										
										
											2018-06-26 17:50:42 +01:00
										 |  |  | } SMMUIOTLBKey; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 16:43:22 -04:00
										 |  |  | struct SMMUState { | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  |     /* <private> */ | 
					
						
							|  |  |  |     SysBusDevice  dev; | 
					
						
							|  |  |  |     const char *mrtypename; | 
					
						
							|  |  |  |     MemoryRegion iomem; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     GHashTable *smmu_pcibus_by_busptr; | 
					
						
							|  |  |  |     GHashTable *configs; /* cache for configuration data */ | 
					
						
							|  |  |  |     GHashTable *iotlb; | 
					
						
							|  |  |  |     SMMUPciBus *smmu_pcibus_by_bus_num[SMMU_PCI_BUS_MAX]; | 
					
						
							|  |  |  |     PCIBus *pci_bus; | 
					
						
							| 
									
										
										
										
											2019-04-29 17:35:57 +01:00
										 |  |  |     QLIST_HEAD(, SMMUDevice) devices_with_notifiers; | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  |     uint8_t bus_num; | 
					
						
							|  |  |  |     PCIBus *primary_bus; | 
					
						
							| 
									
										
										
										
											2020-09-03 16:43:22 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 16:43:22 -04:00
										 |  |  | struct SMMUBaseClass { | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  |     /* <private> */ | 
					
						
							|  |  |  |     SysBusDeviceClass parent_class; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*< public >*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     DeviceRealize parent_realize; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 16:43:22 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define TYPE_ARM_SMMU "arm-smmu"
 | 
					
						
							| 
									
										
										
										
											2020-09-16 14:25:18 -04:00
										 |  |  | OBJECT_DECLARE_TYPE(SMMUState, SMMUBaseClass, ARM_SMMU) | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | /* Return the SMMUPciBus handle associated to a PCI bus number */ | 
					
						
							|  |  |  | SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Return the stream ID of an SMMU device */ | 
					
						
							|  |  |  | static inline uint16_t smmu_get_sid(SMMUDevice *sdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return PCI_BUILD_BDF(pci_bus_num(sdev->bus), sdev->devfn); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * smmu_ptw - Perform the page table walk for a given iova / access flags | 
					
						
							|  |  |  |  * pair, according to @cfg translation config | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm, | 
					
						
							| 
									
										
										
										
											2020-07-28 17:08:08 +02:00
										 |  |  |              SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info); | 
					
						
							| 
									
										
										
										
											2018-05-04 18:05:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * select_tt - compute which translation table shall be used according to | 
					
						
							|  |  |  |  * the input iova and translation config and return the TT specific info | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 17:50:42 +01:00
										 |  |  | /* Return the iommu mr associated to @sid, or NULL if none */ | 
					
						
							|  |  |  | IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 17:50:42 +01:00
										 |  |  | #define SMMU_IOTLB_MAX_SIZE 256
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-28 17:08:09 +02:00
										 |  |  | SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg, | 
					
						
							|  |  |  |                                 SMMUTransTableInfo *tt, hwaddr iova); | 
					
						
							| 
									
										
										
										
											2020-07-28 17:08:08 +02:00
										 |  |  | void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry); | 
					
						
							| 
									
										
										
										
											2020-07-28 17:08:09 +02:00
										 |  |  | SMMUIOTLBKey smmu_get_iotlb_key(uint16_t asid, uint64_t iova, | 
					
						
							|  |  |  |                                 uint8_t tg, uint8_t level); | 
					
						
							| 
									
										
										
										
											2018-06-26 17:50:42 +01:00
										 |  |  | void smmu_iotlb_inv_all(SMMUState *s); | 
					
						
							|  |  |  | void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid); | 
					
						
							| 
									
										
										
										
											2020-07-28 17:08:11 +02:00
										 |  |  | void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova, | 
					
						
							|  |  |  |                          uint8_t tg, uint64_t num_pages, uint8_t ttl); | 
					
						
							| 
									
										
										
										
											2018-06-26 17:50:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 17:50:42 +01:00
										 |  |  | /* Unmap the range of all the notifiers registered to any IOMMU mr */ | 
					
						
							|  |  |  | void smmu_inv_notifiers_all(SMMUState *s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Unmap the range of all the notifiers registered to @mr */ | 
					
						
							|  |  |  | void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-15 15:51:23 +01:00
										 |  |  | #endif /* HW_ARM_SMMU_COMMON_H */
 |