IOMMU Updates for Linux v4.17

These updates come with:
 
 	- OF_IOMMU support for the Rockchip iommu driver so that it can
 	  use generic DT bindings
 
 	- Rework of locking in the AMD IOMMU interrupt remapping code to
 	  make it work better in RT kernels
 
 	- Support for improved iotlb flushing in the AMD IOMMU driver
 
 	- Support for 52-bit physical and virtual addressing in the
 	  ARM-SMMU
 
 	- Various other small fixes and cleanups
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABAgAGBQJazi2BAAoJECvwRC2XARrjYVwP/AyXK7CjRvaiHFopIUO0WpwY
 V3GiKrODtSNHqPSKuFnqIssIhxZPw/SKFz6E/pe08pZ/pxHYTxeTL78Wz7D1+4Sp
 n0YokSM5qLb660OTQVnyKNCku8cEMCb9hkQ/75SFgwcILQYF93cZBDIdBn93OKVO
 6xAOE+tqd8Daulnk0YpdiCTFTJPzYHPl6B7scoUav26uaKxWeMJxeYe+EXC+4WQG
 U1u/jDiVXyllzGgRqqfrmO4L2acmsK8HL97hD4+m1URJKDlb8ho6xwaRThFZWqXS
 SbrYnvH0ruWGrLiQKmVUssw8FqbcXCzq3236g2O8jE4jqWSm70twg+q31iMjwD7v
 bwsJGMkk7aLrquv9Zpaylpf8tRECk5bjhTFC2zB0pdum5XLx47j0IHKWMLPYhkCz
 E0pBefvuhoSTbt/5X0urSRzH2Hk4ljEsM+QjlfH8SN3ALTljFjay607wbxC7t35M
 LEL5AuNsDDBddoJIi9D13CdJEZa4lps8dbpB8m40lQVvmiLPLcKraaG0RfKQ397T
 wsxhsDOQYM2FCwfUP3n8RTsMKRIp/UVkKY+2G7AsKofciSeulK6nDbrV7jFnitx4
 vTxbRgpNejJpqzKZG/W9lCGWk1BhmQK/Cbu6JW5IA4+ew9omWkFp61U6rtc645Te
 6cNEYBiMz/RZIiC2b18J
 =kte5
 -----END PGP SIGNATURE-----

Merge tag 'iommu-updates-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

Pull IOMMU updates from Joerg Roedel:

 - OF_IOMMU support for the Rockchip iommu driver so that it can use
   generic DT bindings

 - rework of locking in the AMD IOMMU interrupt remapping code to make
   it work better in RT kernels

 - support for improved iotlb flushing in the AMD IOMMU driver

 - support for 52-bit physical and virtual addressing in the ARM-SMMU

 - various other small fixes and cleanups

* tag 'iommu-updates-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (53 commits)
  iommu/io-pgtable-arm: Avoid warning with 32-bit phys_addr_t
  iommu/rockchip: Support sharing IOMMU between masters
  iommu/rockchip: Add runtime PM support
  iommu/rockchip: Fix error handling in init
  iommu/rockchip: Use OF_IOMMU to attach devices automatically
  iommu/rockchip: Use IOMMU device for dma mapping operations
  dt-bindings: iommu/rockchip: Add clock property
  iommu/rockchip: Control clocks needed to access the IOMMU
  iommu/rockchip: Fix TLB flush of secondary IOMMUs
  iommu/rockchip: Use iopoll helpers to wait for hardware
  iommu/rockchip: Fix error handling in attach
  iommu/rockchip: Request irqs in rk_iommu_probe()
  iommu/rockchip: Fix error handling in probe
  iommu/rockchip: Prohibit unbind and remove
  iommu/amd: Return proper error code in irq_remapping_alloc()
  iommu/amd: Make amd_iommu_devtable_lock a spin_lock
  iommu/amd: Drop the lock while allocating new irq remap table
  iommu/amd: Factor out setting the remap table for a devid
  iommu/amd: Use `table' instead `irt' as variable name in amd_iommu_update_ga()
  iommu/amd: Remove the special case from alloc_irq_table()
  ...
This commit is contained in:
Linus Torvalds 2018-04-11 18:50:41 -07:00
commit e5c372280b
25 changed files with 1011 additions and 856 deletions

View File

@ -11,6 +11,8 @@ Required Properties:
the device is compatible with the R-Car Gen2 VMSA-compatible IPMMU. the device is compatible with the R-Car Gen2 VMSA-compatible IPMMU.
- "renesas,ipmmu-r8a73a4" for the R8A73A4 (R-Mobile APE6) IPMMU. - "renesas,ipmmu-r8a73a4" for the R8A73A4 (R-Mobile APE6) IPMMU.
- "renesas,ipmmu-r8a7743" for the R8A7743 (RZ/G1M) IPMMU.
- "renesas,ipmmu-r8a7745" for the R8A7745 (RZ/G1E) IPMMU.
- "renesas,ipmmu-r8a7790" for the R8A7790 (R-Car H2) IPMMU. - "renesas,ipmmu-r8a7790" for the R8A7790 (R-Car H2) IPMMU.
- "renesas,ipmmu-r8a7791" for the R8A7791 (R-Car M2-W) IPMMU. - "renesas,ipmmu-r8a7791" for the R8A7791 (R-Car M2-W) IPMMU.
- "renesas,ipmmu-r8a7793" for the R8A7793 (R-Car M2-N) IPMMU. - "renesas,ipmmu-r8a7793" for the R8A7793 (R-Car M2-N) IPMMU.
@ -19,7 +21,8 @@ Required Properties:
- "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU. - "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU.
- "renesas,ipmmu-r8a77970" for the R8A77970 (R-Car V3M) IPMMU. - "renesas,ipmmu-r8a77970" for the R8A77970 (R-Car V3M) IPMMU.
- "renesas,ipmmu-r8a77995" for the R8A77995 (R-Car D3) IPMMU. - "renesas,ipmmu-r8a77995" for the R8A77995 (R-Car D3) IPMMU.
- "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU. - "renesas,ipmmu-vmsa" for generic R-Car Gen2 or RZ/G1 VMSA-compatible
IPMMU.
- reg: Base address and size of the IPMMU registers. - reg: Base address and size of the IPMMU registers.
- interrupts: Specifiers for the MMU fault interrupts. For instances that - interrupts: Specifiers for the MMU fault interrupts. For instances that

View File

@ -14,6 +14,11 @@ Required properties:
"single-master" device, and needs no additional information "single-master" device, and needs no additional information
to associate with its master device. See: to associate with its master device. See:
Documentation/devicetree/bindings/iommu/iommu.txt Documentation/devicetree/bindings/iommu/iommu.txt
- clocks : A list of clocks required for the IOMMU to be accessible by
the host CPU.
- clock-names : Should contain the following:
"iface" - Main peripheral bus clock (PCLK/HCL) (required)
"aclk" - AXI bus clock (required)
Optional properties: Optional properties:
- rockchip,disable-mmu-reset : Don't use the mmu reset operation. - rockchip,disable-mmu-reset : Don't use the mmu reset operation.
@ -27,5 +32,7 @@ Example:
reg = <0xff940300 0x100>; reg = <0xff940300 0x100>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "vopl_mmu"; interrupt-names = "vopl_mmu";
clocks = <&cru ACLK_VOP1>, <&cru HCLK_VOP1>;
clock-names = "aclk", "iface";
#iommu-cells = <0>; #iommu-cells = <0>;
}; };

View File

@ -34,6 +34,7 @@
struct iort_its_msi_chip { struct iort_its_msi_chip {
struct list_head list; struct list_head list;
struct fwnode_handle *fw_node; struct fwnode_handle *fw_node;
phys_addr_t base_addr;
u32 translation_id; u32 translation_id;
}; };
@ -156,14 +157,16 @@ static LIST_HEAD(iort_msi_chip_list);
static DEFINE_SPINLOCK(iort_msi_chip_lock); static DEFINE_SPINLOCK(iort_msi_chip_lock);
/** /**
* iort_register_domain_token() - register domain token and related ITS ID * iort_register_domain_token() - register domain token along with related
* to the list from where we can get it back later on. * ITS ID and base address to the list from where we can get it back later on.
* @trans_id: ITS ID. * @trans_id: ITS ID.
* @base: ITS base address.
* @fw_node: Domain token. * @fw_node: Domain token.
* *
* Returns: 0 on success, -ENOMEM if no memory when allocating list element * Returns: 0 on success, -ENOMEM if no memory when allocating list element
*/ */
int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node) int iort_register_domain_token(int trans_id, phys_addr_t base,
struct fwnode_handle *fw_node)
{ {
struct iort_its_msi_chip *its_msi_chip; struct iort_its_msi_chip *its_msi_chip;
@ -173,6 +176,7 @@ int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
its_msi_chip->fw_node = fw_node; its_msi_chip->fw_node = fw_node;
its_msi_chip->translation_id = trans_id; its_msi_chip->translation_id = trans_id;
its_msi_chip->base_addr = base;
spin_lock(&iort_msi_chip_lock); spin_lock(&iort_msi_chip_lock);
list_add(&its_msi_chip->list, &iort_msi_chip_list); list_add(&its_msi_chip->list, &iort_msi_chip_list);
@ -569,6 +573,24 @@ int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
return -ENODEV; return -ENODEV;
} }
static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base)
{
struct iort_its_msi_chip *its_msi_chip;
int ret = -ENODEV;
spin_lock(&iort_msi_chip_lock);
list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
if (its_msi_chip->translation_id == its_id) {
*base = its_msi_chip->base_addr;
ret = 0;
break;
}
}
spin_unlock(&iort_msi_chip_lock);
return ret;
}
/** /**
* iort_dev_find_its_id() - Find the ITS identifier for a device * iort_dev_find_its_id() - Find the ITS identifier for a device
* @dev: The device. * @dev: The device.
@ -754,6 +776,24 @@ static inline bool iort_iommu_driver_enabled(u8 type)
} }
#ifdef CONFIG_IOMMU_API #ifdef CONFIG_IOMMU_API
static struct acpi_iort_node *iort_get_msi_resv_iommu(struct device *dev)
{
struct acpi_iort_node *iommu;
struct iommu_fwspec *fwspec = dev->iommu_fwspec;
iommu = iort_get_iort_node(fwspec->iommu_fwnode);
if (iommu && (iommu->type == ACPI_IORT_NODE_SMMU_V3)) {
struct acpi_iort_smmu_v3 *smmu;
smmu = (struct acpi_iort_smmu_v3 *)iommu->node_data;
if (smmu->model == ACPI_IORT_SMMU_V3_HISILICON_HI161X)
return iommu;
}
return NULL;
}
static inline const struct iommu_ops *iort_fwspec_iommu_ops( static inline const struct iommu_ops *iort_fwspec_iommu_ops(
struct iommu_fwspec *fwspec) struct iommu_fwspec *fwspec)
{ {
@ -770,6 +810,69 @@ static inline int iort_add_device_replay(const struct iommu_ops *ops,
return err; return err;
} }
/**
* iort_iommu_msi_get_resv_regions - Reserved region driver helper
* @dev: Device from iommu_get_resv_regions()
* @head: Reserved region list from iommu_get_resv_regions()
*
* Returns: Number of msi reserved regions on success (0 if platform
* doesn't require the reservation or no associated msi regions),
* appropriate error value otherwise. The ITS interrupt translation
* spaces (ITS_base + SZ_64K, SZ_64K) associated with the device
* are the msi reserved regions.
*/
int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
{
struct acpi_iort_its_group *its;
struct acpi_iort_node *iommu_node, *its_node = NULL;
int i, resv = 0;
iommu_node = iort_get_msi_resv_iommu(dev);
if (!iommu_node)
return 0;
/*
* Current logic to reserve ITS regions relies on HW topologies
* where a given PCI or named component maps its IDs to only one
* ITS group; if a PCI or named component can map its IDs to
* different ITS groups through IORT mappings this function has
* to be reworked to ensure we reserve regions for all ITS groups
* a given PCI or named component may map IDs to.
*/
for (i = 0; i < dev->iommu_fwspec->num_ids; i++) {
its_node = iort_node_map_id(iommu_node,
dev->iommu_fwspec->ids[i],
NULL, IORT_MSI_TYPE);
if (its_node)
break;
}
if (!its_node)
return 0;
/* Move to ITS specific data */
its = (struct acpi_iort_its_group *)its_node->node_data;
for (i = 0; i < its->its_count; i++) {
phys_addr_t base;
if (!iort_find_its_base(its->identifiers[i], &base)) {
int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
struct iommu_resv_region *region;
region = iommu_alloc_resv_region(base + SZ_64K, SZ_64K,
prot, IOMMU_RESV_MSI);
if (region) {
list_add_tail(&region->list, head);
resv++;
}
}
}
return (resv == its->its_count) ? resv : -ENODEV;
}
#else #else
static inline const struct iommu_ops *iort_fwspec_iommu_ops( static inline const struct iommu_ops *iort_fwspec_iommu_ops(
struct iommu_fwspec *fwspec) struct iommu_fwspec *fwspec)
@ -777,6 +880,8 @@ static inline const struct iommu_ops *iort_fwspec_iommu_ops(
static inline int iort_add_device_replay(const struct iommu_ops *ops, static inline int iort_add_device_replay(const struct iommu_ops *ops,
struct device *dev) struct device *dev)
{ return 0; } { return 0; }
int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
{ return 0; }
#endif #endif
static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node, static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node,

View File

@ -81,11 +81,12 @@
*/ */
#define AMD_IOMMU_PGSIZES ((~0xFFFUL) & ~(2ULL << 38)) #define AMD_IOMMU_PGSIZES ((~0xFFFUL) & ~(2ULL << 38))
static DEFINE_RWLOCK(amd_iommu_devtable_lock); static DEFINE_SPINLOCK(amd_iommu_devtable_lock);
static DEFINE_SPINLOCK(pd_bitmap_lock);
static DEFINE_SPINLOCK(iommu_table_lock);
/* List of all available dev_data structures */ /* List of all available dev_data structures */
static LIST_HEAD(dev_data_list); static LLIST_HEAD(dev_data_list);
static DEFINE_SPINLOCK(dev_data_list_lock);
LIST_HEAD(ioapic_map); LIST_HEAD(ioapic_map);
LIST_HEAD(hpet_map); LIST_HEAD(hpet_map);
@ -204,40 +205,33 @@ static struct dma_ops_domain* to_dma_ops_domain(struct protection_domain *domain
static struct iommu_dev_data *alloc_dev_data(u16 devid) static struct iommu_dev_data *alloc_dev_data(u16 devid)
{ {
struct iommu_dev_data *dev_data; struct iommu_dev_data *dev_data;
unsigned long flags;
dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL); dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
if (!dev_data) if (!dev_data)
return NULL; return NULL;
dev_data->devid = devid; dev_data->devid = devid;
spin_lock_irqsave(&dev_data_list_lock, flags);
list_add_tail(&dev_data->dev_data_list, &dev_data_list);
spin_unlock_irqrestore(&dev_data_list_lock, flags);
ratelimit_default_init(&dev_data->rs); ratelimit_default_init(&dev_data->rs);
llist_add(&dev_data->dev_data_list, &dev_data_list);
return dev_data; return dev_data;
} }
static struct iommu_dev_data *search_dev_data(u16 devid) static struct iommu_dev_data *search_dev_data(u16 devid)
{ {
struct iommu_dev_data *dev_data; struct iommu_dev_data *dev_data;
unsigned long flags; struct llist_node *node;
spin_lock_irqsave(&dev_data_list_lock, flags); if (llist_empty(&dev_data_list))
list_for_each_entry(dev_data, &dev_data_list, dev_data_list) { return NULL;
node = dev_data_list.first;
llist_for_each_entry(dev_data, node, dev_data_list) {
if (dev_data->devid == devid) if (dev_data->devid == devid)
goto out_unlock; return dev_data;
} }
dev_data = NULL; return NULL;
out_unlock:
spin_unlock_irqrestore(&dev_data_list_lock, flags);
return dev_data;
} }
static int __last_alias(struct pci_dev *pdev, u16 alias, void *data) static int __last_alias(struct pci_dev *pdev, u16 alias, void *data)
@ -311,6 +305,8 @@ static struct iommu_dev_data *find_dev_data(u16 devid)
if (dev_data == NULL) { if (dev_data == NULL) {
dev_data = alloc_dev_data(devid); dev_data = alloc_dev_data(devid);
if (!dev_data)
return NULL;
if (translation_pre_enabled(iommu)) if (translation_pre_enabled(iommu))
dev_data->defer_attach = true; dev_data->defer_attach = true;
@ -548,6 +544,7 @@ static void amd_iommu_report_page_fault(u16 devid, u16 domain_id,
static void iommu_print_event(struct amd_iommu *iommu, void *__evt) static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
{ {
struct device *dev = iommu->iommu.dev;
int type, devid, domid, flags; int type, devid, domid, flags;
volatile u32 *event = __evt; volatile u32 *event = __evt;
int count = 0; int count = 0;
@ -574,53 +571,53 @@ retry:
amd_iommu_report_page_fault(devid, domid, address, flags); amd_iommu_report_page_fault(devid, domid, address, flags);
return; return;
} else { } else {
printk(KERN_ERR "AMD-Vi: Event logged ["); dev_err(dev, "AMD-Vi: Event logged [");
} }
switch (type) { switch (type) {
case EVENT_TYPE_ILL_DEV: case EVENT_TYPE_ILL_DEV:
printk("ILLEGAL_DEV_TABLE_ENTRY device=%02x:%02x.%x " dev_err(dev, "ILLEGAL_DEV_TABLE_ENTRY device=%02x:%02x.%x "
"address=0x%016llx flags=0x%04x]\n", "address=0x%016llx flags=0x%04x]\n",
PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid), PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
address, flags); address, flags);
dump_dte_entry(devid); dump_dte_entry(devid);
break; break;
case EVENT_TYPE_DEV_TAB_ERR: case EVENT_TYPE_DEV_TAB_ERR:
printk("DEV_TAB_HARDWARE_ERROR device=%02x:%02x.%x " dev_err(dev, "DEV_TAB_HARDWARE_ERROR device=%02x:%02x.%x "
"address=0x%016llx flags=0x%04x]\n", "address=0x%016llx flags=0x%04x]\n",
PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid), PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
address, flags); address, flags);
break; break;
case EVENT_TYPE_PAGE_TAB_ERR: case EVENT_TYPE_PAGE_TAB_ERR:
printk("PAGE_TAB_HARDWARE_ERROR device=%02x:%02x.%x " dev_err(dev, "PAGE_TAB_HARDWARE_ERROR device=%02x:%02x.%x "
"domain=0x%04x address=0x%016llx flags=0x%04x]\n", "domain=0x%04x address=0x%016llx flags=0x%04x]\n",
PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid), PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
domid, address, flags); domid, address, flags);
break; break;
case EVENT_TYPE_ILL_CMD: case EVENT_TYPE_ILL_CMD:
printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); dev_err(dev, "ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address);
dump_command(address); dump_command(address);
break; break;
case EVENT_TYPE_CMD_HARD_ERR: case EVENT_TYPE_CMD_HARD_ERR:
printk("COMMAND_HARDWARE_ERROR address=0x%016llx " dev_err(dev, "COMMAND_HARDWARE_ERROR address=0x%016llx "
"flags=0x%04x]\n", address, flags); "flags=0x%04x]\n", address, flags);
break; break;
case EVENT_TYPE_IOTLB_INV_TO: case EVENT_TYPE_IOTLB_INV_TO:
printk("IOTLB_INV_TIMEOUT device=%02x:%02x.%x " dev_err(dev, "IOTLB_INV_TIMEOUT device=%02x:%02x.%x "
"address=0x%016llx]\n", "address=0x%016llx]\n",
PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid), PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
address); address);
break; break;
case EVENT_TYPE_INV_DEV_REQ: case EVENT_TYPE_INV_DEV_REQ:
printk("INVALID_DEVICE_REQUEST device=%02x:%02x.%x " dev_err(dev, "INVALID_DEVICE_REQUEST device=%02x:%02x.%x "
"address=0x%016llx flags=0x%04x]\n", "address=0x%016llx flags=0x%04x]\n",
PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid), PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
address, flags); address, flags);
break; break;
default: default:
printk(KERN_ERR "UNKNOWN type=0x%02x event[0]=0x%08x " dev_err(dev, KERN_ERR "UNKNOWN event[0]=0x%08x event[1]=0x%08x "
"event[1]=0x%08x event[2]=0x%08x event[3]=0x%08x\n", "event[2]=0x%08x event[3]=0x%08x\n",
type, event[0], event[1], event[2], event[3]); event[0], event[1], event[2], event[3]);
} }
memset(__evt, 0, 4 * sizeof(u32)); memset(__evt, 0, 4 * sizeof(u32));
@ -1057,9 +1054,9 @@ static int iommu_queue_command_sync(struct amd_iommu *iommu,
unsigned long flags; unsigned long flags;
int ret; int ret;
spin_lock_irqsave(&iommu->lock, flags); raw_spin_lock_irqsave(&iommu->lock, flags);
ret = __iommu_queue_command_sync(iommu, cmd, sync); ret = __iommu_queue_command_sync(iommu, cmd, sync);
spin_unlock_irqrestore(&iommu->lock, flags); raw_spin_unlock_irqrestore(&iommu->lock, flags);
return ret; return ret;
} }
@ -1085,7 +1082,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
build_completion_wait(&cmd, (u64)&iommu->cmd_sem); build_completion_wait(&cmd, (u64)&iommu->cmd_sem);
spin_lock_irqsave(&iommu->lock, flags); raw_spin_lock_irqsave(&iommu->lock, flags);
iommu->cmd_sem = 0; iommu->cmd_sem = 0;
@ -1096,7 +1093,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
ret = wait_on_sem(&iommu->cmd_sem); ret = wait_on_sem(&iommu->cmd_sem);
out_unlock: out_unlock:
spin_unlock_irqrestore(&iommu->lock, flags); raw_spin_unlock_irqrestore(&iommu->lock, flags);
return ret; return ret;
} }
@ -1606,29 +1603,26 @@ static void del_domain_from_list(struct protection_domain *domain)
static u16 domain_id_alloc(void) static u16 domain_id_alloc(void)
{ {
unsigned long flags;
int id; int id;
write_lock_irqsave(&amd_iommu_devtable_lock, flags); spin_lock(&pd_bitmap_lock);
id = find_first_zero_bit(amd_iommu_pd_alloc_bitmap, MAX_DOMAIN_ID); id = find_first_zero_bit(amd_iommu_pd_alloc_bitmap, MAX_DOMAIN_ID);
BUG_ON(id == 0); BUG_ON(id == 0);
if (id > 0 && id < MAX_DOMAIN_ID) if (id > 0 && id < MAX_DOMAIN_ID)
__set_bit(id, amd_iommu_pd_alloc_bitmap); __set_bit(id, amd_iommu_pd_alloc_bitmap);
else else
id = 0; id = 0;
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); spin_unlock(&pd_bitmap_lock);
return id; return id;
} }
static void domain_id_free(int id) static void domain_id_free(int id)
{ {
unsigned long flags; spin_lock(&pd_bitmap_lock);
write_lock_irqsave(&amd_iommu_devtable_lock, flags);
if (id > 0 && id < MAX_DOMAIN_ID) if (id > 0 && id < MAX_DOMAIN_ID)
__clear_bit(id, amd_iommu_pd_alloc_bitmap); __clear_bit(id, amd_iommu_pd_alloc_bitmap);
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); spin_unlock(&pd_bitmap_lock);
} }
#define DEFINE_FREE_PT_FN(LVL, FN) \ #define DEFINE_FREE_PT_FN(LVL, FN) \
@ -2104,9 +2098,9 @@ static int attach_device(struct device *dev,
} }
skip_ats_check: skip_ats_check:
write_lock_irqsave(&amd_iommu_devtable_lock, flags); spin_lock_irqsave(&amd_iommu_devtable_lock, flags);
ret = __attach_device(dev_data, domain); ret = __attach_device(dev_data, domain);
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); spin_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
/* /*
* We might boot into a crash-kernel here. The crashed kernel * We might boot into a crash-kernel here. The crashed kernel
@ -2156,9 +2150,9 @@ static void detach_device(struct device *dev)
domain = dev_data->domain; domain = dev_data->domain;
/* lock device table */ /* lock device table */
write_lock_irqsave(&amd_iommu_devtable_lock, flags); spin_lock_irqsave(&amd_iommu_devtable_lock, flags);
__detach_device(dev_data); __detach_device(dev_data);
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); spin_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
if (!dev_is_pci(dev)) if (!dev_is_pci(dev))
return; return;
@ -2795,7 +2789,7 @@ static void cleanup_domain(struct protection_domain *domain)
struct iommu_dev_data *entry; struct iommu_dev_data *entry;
unsigned long flags; unsigned long flags;
write_lock_irqsave(&amd_iommu_devtable_lock, flags); spin_lock_irqsave(&amd_iommu_devtable_lock, flags);
while (!list_empty(&domain->dev_list)) { while (!list_empty(&domain->dev_list)) {
entry = list_first_entry(&domain->dev_list, entry = list_first_entry(&domain->dev_list,
@ -2803,7 +2797,7 @@ static void cleanup_domain(struct protection_domain *domain)
__detach_device(entry); __detach_device(entry);
} }
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); spin_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
} }
static void protection_domain_free(struct protection_domain *domain) static void protection_domain_free(struct protection_domain *domain)
@ -3025,15 +3019,12 @@ static size_t amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
size_t unmap_size; size_t unmap_size;
if (domain->mode == PAGE_MODE_NONE) if (domain->mode == PAGE_MODE_NONE)
return -EINVAL; return 0;
mutex_lock(&domain->api_lock); mutex_lock(&domain->api_lock);
unmap_size = iommu_unmap_page(domain, iova, page_size); unmap_size = iommu_unmap_page(domain, iova, page_size);
mutex_unlock(&domain->api_lock); mutex_unlock(&domain->api_lock);
domain_flush_tlb_pde(domain);
domain_flush_complete(domain);
return unmap_size; return unmap_size;
} }
@ -3151,6 +3142,19 @@ static bool amd_iommu_is_attach_deferred(struct iommu_domain *domain,
return dev_data->defer_attach; return dev_data->defer_attach;
} }
static void amd_iommu_flush_iotlb_all(struct iommu_domain *domain)
{
struct protection_domain *dom = to_pdomain(domain);
domain_flush_tlb_pde(dom);
domain_flush_complete(dom);
}
static void amd_iommu_iotlb_range_add(struct iommu_domain *domain,
unsigned long iova, size_t size)
{
}
const struct iommu_ops amd_iommu_ops = { const struct iommu_ops amd_iommu_ops = {
.capable = amd_iommu_capable, .capable = amd_iommu_capable,
.domain_alloc = amd_iommu_domain_alloc, .domain_alloc = amd_iommu_domain_alloc,
@ -3169,6 +3173,9 @@ const struct iommu_ops amd_iommu_ops = {
.apply_resv_region = amd_iommu_apply_resv_region, .apply_resv_region = amd_iommu_apply_resv_region,
.is_attach_deferred = amd_iommu_is_attach_deferred, .is_attach_deferred = amd_iommu_is_attach_deferred,
.pgsize_bitmap = AMD_IOMMU_PGSIZES, .pgsize_bitmap = AMD_IOMMU_PGSIZES,
.flush_iotlb_all = amd_iommu_flush_iotlb_all,
.iotlb_range_add = amd_iommu_iotlb_range_add,
.iotlb_sync = amd_iommu_flush_iotlb_all,
}; };
/***************************************************************************** /*****************************************************************************
@ -3570,14 +3577,62 @@ static void set_dte_irq_entry(u16 devid, struct irq_remap_table *table)
amd_iommu_dev_table[devid].data[2] = dte; amd_iommu_dev_table[devid].data[2] = dte;
} }
static struct irq_remap_table *get_irq_table(u16 devid, bool ioapic) static struct irq_remap_table *get_irq_table(u16 devid)
{
struct irq_remap_table *table;
if (WARN_ONCE(!amd_iommu_rlookup_table[devid],
"%s: no iommu for devid %x\n", __func__, devid))
return NULL;
table = irq_lookup_table[devid];
if (WARN_ONCE(!table, "%s: no table for devid %x\n", __func__, devid))
return NULL;
return table;
}
static struct irq_remap_table *__alloc_irq_table(void)
{
struct irq_remap_table *table;
table = kzalloc(sizeof(*table), GFP_KERNEL);
if (!table)
return NULL;
table->table = kmem_cache_alloc(amd_iommu_irq_cache, GFP_KERNEL);
if (!table->table) {
kfree(table);
return NULL;
}
raw_spin_lock_init(&table->lock);
if (!AMD_IOMMU_GUEST_IR_GA(amd_iommu_guest_ir))
memset(table->table, 0,
MAX_IRQS_PER_TABLE * sizeof(u32));
else
memset(table->table, 0,
(MAX_IRQS_PER_TABLE * (sizeof(u64) * 2)));
return table;
}
static void set_remap_table_entry(struct amd_iommu *iommu, u16 devid,
struct irq_remap_table *table)
{
irq_lookup_table[devid] = table;
set_dte_irq_entry(devid, table);
iommu_flush_dte(iommu, devid);
}
static struct irq_remap_table *alloc_irq_table(u16 devid)
{ {
struct irq_remap_table *table = NULL; struct irq_remap_table *table = NULL;
struct irq_remap_table *new_table = NULL;
struct amd_iommu *iommu; struct amd_iommu *iommu;
unsigned long flags; unsigned long flags;
u16 alias; u16 alias;
write_lock_irqsave(&amd_iommu_devtable_lock, flags); spin_lock_irqsave(&iommu_table_lock, flags);
iommu = amd_iommu_rlookup_table[devid]; iommu = amd_iommu_rlookup_table[devid];
if (!iommu) if (!iommu)
@ -3590,60 +3645,45 @@ static struct irq_remap_table *get_irq_table(u16 devid, bool ioapic)
alias = amd_iommu_alias_table[devid]; alias = amd_iommu_alias_table[devid];
table = irq_lookup_table[alias]; table = irq_lookup_table[alias];
if (table) { if (table) {
irq_lookup_table[devid] = table; set_remap_table_entry(iommu, devid, table);
set_dte_irq_entry(devid, table); goto out_wait;
iommu_flush_dte(iommu, devid);
goto out;
} }
spin_unlock_irqrestore(&iommu_table_lock, flags);
/* Nothing there yet, allocate new irq remapping table */ /* Nothing there yet, allocate new irq remapping table */
table = kzalloc(sizeof(*table), GFP_ATOMIC); new_table = __alloc_irq_table();
if (!table) if (!new_table)
return NULL;
spin_lock_irqsave(&iommu_table_lock, flags);
table = irq_lookup_table[devid];
if (table)
goto out_unlock; goto out_unlock;
/* Initialize table spin-lock */ table = irq_lookup_table[alias];
spin_lock_init(&table->lock); if (table) {
set_remap_table_entry(iommu, devid, table);
if (ioapic) goto out_wait;
/* Keep the first 32 indexes free for IOAPIC interrupts */
table->min_index = 32;
table->table = kmem_cache_alloc(amd_iommu_irq_cache, GFP_ATOMIC);
if (!table->table) {
kfree(table);
table = NULL;
goto out_unlock;
} }
if (!AMD_IOMMU_GUEST_IR_GA(amd_iommu_guest_ir)) table = new_table;
memset(table->table, 0, new_table = NULL;
MAX_IRQS_PER_TABLE * sizeof(u32));
else
memset(table->table, 0,
(MAX_IRQS_PER_TABLE * (sizeof(u64) * 2)));
if (ioapic) { set_remap_table_entry(iommu, devid, table);
int i; if (devid != alias)
set_remap_table_entry(iommu, alias, table);
for (i = 0; i < 32; ++i) out_wait:
iommu->irte_ops->set_allocated(table, i);
}
irq_lookup_table[devid] = table;
set_dte_irq_entry(devid, table);
iommu_flush_dte(iommu, devid);
if (devid != alias) {
irq_lookup_table[alias] = table;
set_dte_irq_entry(alias, table);
iommu_flush_dte(iommu, alias);
}
out:
iommu_completion_wait(iommu); iommu_completion_wait(iommu);
out_unlock: out_unlock:
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); spin_unlock_irqrestore(&iommu_table_lock, flags);
if (new_table) {
kmem_cache_free(amd_iommu_irq_cache, new_table->table);
kfree(new_table);
}
return table; return table;
} }
@ -3657,14 +3697,14 @@ static int alloc_irq_index(u16 devid, int count, bool align)
if (!iommu) if (!iommu)
return -ENODEV; return -ENODEV;
table = get_irq_table(devid, false); table = alloc_irq_table(devid);
if (!table) if (!table)
return -ENODEV; return -ENODEV;
if (align) if (align)
alignment = roundup_pow_of_two(count); alignment = roundup_pow_of_two(count);
spin_lock_irqsave(&table->lock, flags); raw_spin_lock_irqsave(&table->lock, flags);
/* Scan table for free entries */ /* Scan table for free entries */
for (index = ALIGN(table->min_index, alignment), c = 0; for (index = ALIGN(table->min_index, alignment), c = 0;
@ -3691,7 +3731,7 @@ static int alloc_irq_index(u16 devid, int count, bool align)
index = -ENOSPC; index = -ENOSPC;
out: out:
spin_unlock_irqrestore(&table->lock, flags); raw_spin_unlock_irqrestore(&table->lock, flags);
return index; return index;
} }
@ -3708,11 +3748,11 @@ static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
if (iommu == NULL) if (iommu == NULL)
return -EINVAL; return -EINVAL;
table = get_irq_table(devid, false); table = get_irq_table(devid);
if (!table) if (!table)
return -ENOMEM; return -ENOMEM;
spin_lock_irqsave(&table->lock, flags); raw_spin_lock_irqsave(&table->lock, flags);
entry = (struct irte_ga *)table->table; entry = (struct irte_ga *)table->table;
entry = &entry[index]; entry = &entry[index];
@ -3723,7 +3763,7 @@ static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
if (data) if (data)
data->ref = entry; data->ref = entry;
spin_unlock_irqrestore(&table->lock, flags); raw_spin_unlock_irqrestore(&table->lock, flags);
iommu_flush_irt(iommu, devid); iommu_flush_irt(iommu, devid);
iommu_completion_wait(iommu); iommu_completion_wait(iommu);
@ -3741,13 +3781,13 @@ static int modify_irte(u16 devid, int index, union irte *irte)
if (iommu == NULL) if (iommu == NULL)
return -EINVAL; return -EINVAL;
table = get_irq_table(devid, false); table = get_irq_table(devid);
if (!table) if (!table)
return -ENOMEM; return -ENOMEM;
spin_lock_irqsave(&table->lock, flags); raw_spin_lock_irqsave(&table->lock, flags);
table->table[index] = irte->val; table->table[index] = irte->val;
spin_unlock_irqrestore(&table->lock, flags); raw_spin_unlock_irqrestore(&table->lock, flags);
iommu_flush_irt(iommu, devid); iommu_flush_irt(iommu, devid);
iommu_completion_wait(iommu); iommu_completion_wait(iommu);
@ -3765,13 +3805,13 @@ static void free_irte(u16 devid, int index)
if (iommu == NULL) if (iommu == NULL)
return; return;
table = get_irq_table(devid, false); table = get_irq_table(devid);
if (!table) if (!table)
return; return;
spin_lock_irqsave(&table->lock, flags); raw_spin_lock_irqsave(&table->lock, flags);
iommu->irte_ops->clear_allocated(table, index); iommu->irte_ops->clear_allocated(table, index);
spin_unlock_irqrestore(&table->lock, flags); raw_spin_unlock_irqrestore(&table->lock, flags);
iommu_flush_irt(iommu, devid); iommu_flush_irt(iommu, devid);
iommu_completion_wait(iommu); iommu_completion_wait(iommu);
@ -3852,10 +3892,8 @@ static void irte_ga_set_affinity(void *entry, u16 devid, u16 index,
u8 vector, u32 dest_apicid) u8 vector, u32 dest_apicid)
{ {
struct irte_ga *irte = (struct irte_ga *) entry; struct irte_ga *irte = (struct irte_ga *) entry;
struct iommu_dev_data *dev_data = search_dev_data(devid);
if (!dev_data || !dev_data->use_vapic || if (!irte->lo.fields_remap.guest_mode) {
!irte->lo.fields_remap.guest_mode) {
irte->hi.fields.vector = vector; irte->hi.fields.vector = vector;
irte->lo.fields_remap.destination = dest_apicid; irte->lo.fields_remap.destination = dest_apicid;
modify_irte_ga(devid, index, irte, NULL); modify_irte_ga(devid, index, irte, NULL);
@ -4061,7 +4099,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
struct amd_ir_data *data = NULL; struct amd_ir_data *data = NULL;
struct irq_cfg *cfg; struct irq_cfg *cfg;
int i, ret, devid; int i, ret, devid;
int index = -1; int index;
if (!info) if (!info)
return -EINVAL; return -EINVAL;
@ -4085,10 +4123,26 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
return ret; return ret;
if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC) { if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC) {
if (get_irq_table(devid, true)) struct irq_remap_table *table;
struct amd_iommu *iommu;
table = alloc_irq_table(devid);
if (table) {
if (!table->min_index) {
/*
* Keep the first 32 indexes free for IOAPIC
* interrupts.
*/
table->min_index = 32;
iommu = amd_iommu_rlookup_table[devid];
for (i = 0; i < 32; ++i)
iommu->irte_ops->set_allocated(table, i);
}
WARN_ON(table->min_index != 32);
index = info->ioapic_pin; index = info->ioapic_pin;
else } else {
ret = -ENOMEM; index = -ENOMEM;
}
} else { } else {
bool align = (info->type == X86_IRQ_ALLOC_TYPE_MSI); bool align = (info->type == X86_IRQ_ALLOC_TYPE_MSI);
@ -4354,7 +4408,7 @@ int amd_iommu_update_ga(int cpu, bool is_run, void *data)
{ {
unsigned long flags; unsigned long flags;
struct amd_iommu *iommu; struct amd_iommu *iommu;
struct irq_remap_table *irt; struct irq_remap_table *table;
struct amd_ir_data *ir_data = (struct amd_ir_data *)data; struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
int devid = ir_data->irq_2_irte.devid; int devid = ir_data->irq_2_irte.devid;
struct irte_ga *entry = (struct irte_ga *) ir_data->entry; struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
@ -4368,11 +4422,11 @@ int amd_iommu_update_ga(int cpu, bool is_run, void *data)
if (!iommu) if (!iommu)
return -ENODEV; return -ENODEV;
irt = get_irq_table(devid, false); table = get_irq_table(devid);
if (!irt) if (!table)
return -ENODEV; return -ENODEV;
spin_lock_irqsave(&irt->lock, flags); raw_spin_lock_irqsave(&table->lock, flags);
if (ref->lo.fields_vapic.guest_mode) { if (ref->lo.fields_vapic.guest_mode) {
if (cpu >= 0) if (cpu >= 0)
@ -4381,7 +4435,7 @@ int amd_iommu_update_ga(int cpu, bool is_run, void *data)
barrier(); barrier();
} }
spin_unlock_irqrestore(&irt->lock, flags); raw_spin_unlock_irqrestore(&table->lock, flags);
iommu_flush_irt(iommu, devid); iommu_flush_irt(iommu, devid);
iommu_completion_wait(iommu); iommu_completion_wait(iommu);

View File

@ -1474,7 +1474,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
{ {
int ret; int ret;
spin_lock_init(&iommu->lock); raw_spin_lock_init(&iommu->lock);
/* Add IOMMU to internal data structures */ /* Add IOMMU to internal data structures */
list_add_tail(&iommu->list, &amd_iommu_list); list_add_tail(&iommu->list, &amd_iommu_list);

View File

@ -408,7 +408,7 @@ extern bool amd_iommu_iotlb_sup;
#define IRQ_TABLE_ALIGNMENT 128 #define IRQ_TABLE_ALIGNMENT 128
struct irq_remap_table { struct irq_remap_table {
spinlock_t lock; raw_spinlock_t lock;
unsigned min_index; unsigned min_index;
u32 *table; u32 *table;
}; };
@ -490,7 +490,7 @@ struct amd_iommu {
int index; int index;
/* locks the accesses to the hardware */ /* locks the accesses to the hardware */
spinlock_t lock; raw_spinlock_t lock;
/* Pointer to PCI device of this IOMMU */ /* Pointer to PCI device of this IOMMU */
struct pci_dev *dev; struct pci_dev *dev;
@ -627,7 +627,7 @@ struct devid_map {
*/ */
struct iommu_dev_data { struct iommu_dev_data {
struct list_head list; /* For domain->dev_list */ struct list_head list; /* For domain->dev_list */
struct list_head dev_data_list; /* For global dev_data_list */ struct llist_node dev_data_list; /* For global dev_data_list */
struct protection_domain *domain; /* Domain the device is bound to */ struct protection_domain *domain; /* Domain the device is bound to */
u16 devid; /* PCI Device ID */ u16 devid; /* PCI Device ID */
u16 alias; /* Alias Device ID */ u16 alias; /* Alias Device ID */

View File

@ -22,6 +22,8 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/acpi_iort.h> #include <linux/acpi_iort.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dma-iommu.h> #include <linux/dma-iommu.h>
#include <linux/err.h> #include <linux/err.h>
@ -43,18 +45,15 @@
/* MMIO registers */ /* MMIO registers */
#define ARM_SMMU_IDR0 0x0 #define ARM_SMMU_IDR0 0x0
#define IDR0_ST_LVL_SHIFT 27 #define IDR0_ST_LVL GENMASK(28, 27)
#define IDR0_ST_LVL_MASK 0x3 #define IDR0_ST_LVL_2LVL 1
#define IDR0_ST_LVL_2LVL (1 << IDR0_ST_LVL_SHIFT) #define IDR0_STALL_MODEL GENMASK(25, 24)
#define IDR0_STALL_MODEL_SHIFT 24 #define IDR0_STALL_MODEL_STALL 0
#define IDR0_STALL_MODEL_MASK 0x3 #define IDR0_STALL_MODEL_FORCE 2
#define IDR0_STALL_MODEL_STALL (0 << IDR0_STALL_MODEL_SHIFT) #define IDR0_TTENDIAN GENMASK(22, 21)
#define IDR0_STALL_MODEL_FORCE (2 << IDR0_STALL_MODEL_SHIFT) #define IDR0_TTENDIAN_MIXED 0
#define IDR0_TTENDIAN_SHIFT 21 #define IDR0_TTENDIAN_LE 2
#define IDR0_TTENDIAN_MASK 0x3 #define IDR0_TTENDIAN_BE 3
#define IDR0_TTENDIAN_LE (2 << IDR0_TTENDIAN_SHIFT)
#define IDR0_TTENDIAN_BE (3 << IDR0_TTENDIAN_SHIFT)
#define IDR0_TTENDIAN_MIXED (0 << IDR0_TTENDIAN_SHIFT)
#define IDR0_CD2L (1 << 19) #define IDR0_CD2L (1 << 19)
#define IDR0_VMID16 (1 << 18) #define IDR0_VMID16 (1 << 18)
#define IDR0_PRI (1 << 16) #define IDR0_PRI (1 << 16)
@ -64,10 +63,9 @@
#define IDR0_ATS (1 << 10) #define IDR0_ATS (1 << 10)
#define IDR0_HYP (1 << 9) #define IDR0_HYP (1 << 9)
#define IDR0_COHACC (1 << 4) #define IDR0_COHACC (1 << 4)
#define IDR0_TTF_SHIFT 2 #define IDR0_TTF GENMASK(3, 2)
#define IDR0_TTF_MASK 0x3 #define IDR0_TTF_AARCH64 2
#define IDR0_TTF_AARCH64 (2 << IDR0_TTF_SHIFT) #define IDR0_TTF_AARCH32_64 3
#define IDR0_TTF_AARCH32_64 (3 << IDR0_TTF_SHIFT)
#define IDR0_S1P (1 << 1) #define IDR0_S1P (1 << 1)
#define IDR0_S2P (1 << 0) #define IDR0_S2P (1 << 0)
@ -75,31 +73,27 @@
#define IDR1_TABLES_PRESET (1 << 30) #define IDR1_TABLES_PRESET (1 << 30)
#define IDR1_QUEUES_PRESET (1 << 29) #define IDR1_QUEUES_PRESET (1 << 29)
#define IDR1_REL (1 << 28) #define IDR1_REL (1 << 28)
#define IDR1_CMDQ_SHIFT 21 #define IDR1_CMDQS GENMASK(25, 21)
#define IDR1_CMDQ_MASK 0x1f #define IDR1_EVTQS GENMASK(20, 16)
#define IDR1_EVTQ_SHIFT 16 #define IDR1_PRIQS GENMASK(15, 11)
#define IDR1_EVTQ_MASK 0x1f #define IDR1_SSIDSIZE GENMASK(10, 6)
#define IDR1_PRIQ_SHIFT 11 #define IDR1_SIDSIZE GENMASK(5, 0)
#define IDR1_PRIQ_MASK 0x1f
#define IDR1_SSID_SHIFT 6
#define IDR1_SSID_MASK 0x1f
#define IDR1_SID_SHIFT 0
#define IDR1_SID_MASK 0x3f
#define ARM_SMMU_IDR5 0x14 #define ARM_SMMU_IDR5 0x14
#define IDR5_STALL_MAX_SHIFT 16 #define IDR5_STALL_MAX GENMASK(31, 16)
#define IDR5_STALL_MAX_MASK 0xffff
#define IDR5_GRAN64K (1 << 6) #define IDR5_GRAN64K (1 << 6)
#define IDR5_GRAN16K (1 << 5) #define IDR5_GRAN16K (1 << 5)
#define IDR5_GRAN4K (1 << 4) #define IDR5_GRAN4K (1 << 4)
#define IDR5_OAS_SHIFT 0 #define IDR5_OAS GENMASK(2, 0)
#define IDR5_OAS_MASK 0x7 #define IDR5_OAS_32_BIT 0
#define IDR5_OAS_32_BIT (0 << IDR5_OAS_SHIFT) #define IDR5_OAS_36_BIT 1
#define IDR5_OAS_36_BIT (1 << IDR5_OAS_SHIFT) #define IDR5_OAS_40_BIT 2
#define IDR5_OAS_40_BIT (2 << IDR5_OAS_SHIFT) #define IDR5_OAS_42_BIT 3
#define IDR5_OAS_42_BIT (3 << IDR5_OAS_SHIFT) #define IDR5_OAS_44_BIT 4
#define IDR5_OAS_44_BIT (4 << IDR5_OAS_SHIFT) #define IDR5_OAS_48_BIT 5
#define IDR5_OAS_48_BIT (5 << IDR5_OAS_SHIFT) #define IDR5_OAS_52_BIT 6
#define IDR5_VAX GENMASK(11, 10)
#define IDR5_VAX_52_BIT 1
#define ARM_SMMU_CR0 0x20 #define ARM_SMMU_CR0 0x20
#define CR0_CMDQEN (1 << 3) #define CR0_CMDQEN (1 << 3)
@ -110,18 +104,16 @@
#define ARM_SMMU_CR0ACK 0x24 #define ARM_SMMU_CR0ACK 0x24
#define ARM_SMMU_CR1 0x28 #define ARM_SMMU_CR1 0x28
#define CR1_SH_NSH 0 #define CR1_TABLE_SH GENMASK(11, 10)
#define CR1_SH_OSH 2 #define CR1_TABLE_OC GENMASK(9, 8)
#define CR1_SH_ISH 3 #define CR1_TABLE_IC GENMASK(7, 6)
#define CR1_QUEUE_SH GENMASK(5, 4)
#define CR1_QUEUE_OC GENMASK(3, 2)
#define CR1_QUEUE_IC GENMASK(1, 0)
/* CR1 cacheability fields don't quite follow the usual TCR-style encoding */
#define CR1_CACHE_NC 0 #define CR1_CACHE_NC 0
#define CR1_CACHE_WB 1 #define CR1_CACHE_WB 1
#define CR1_CACHE_WT 2 #define CR1_CACHE_WT 2
#define CR1_TABLE_SH_SHIFT 10
#define CR1_TABLE_OC_SHIFT 8
#define CR1_TABLE_IC_SHIFT 6
#define CR1_QUEUE_SH_SHIFT 4
#define CR1_QUEUE_OC_SHIFT 2
#define CR1_QUEUE_IC_SHIFT 0
#define ARM_SMMU_CR2 0x2c #define ARM_SMMU_CR2 0x2c
#define CR2_PTM (1 << 2) #define CR2_PTM (1 << 2)
@ -129,8 +121,8 @@
#define CR2_E2H (1 << 0) #define CR2_E2H (1 << 0)
#define ARM_SMMU_GBPA 0x44 #define ARM_SMMU_GBPA 0x44
#define GBPA_ABORT (1 << 20)
#define GBPA_UPDATE (1 << 31) #define GBPA_UPDATE (1 << 31)
#define GBPA_ABORT (1 << 20)
#define ARM_SMMU_IRQ_CTRL 0x50 #define ARM_SMMU_IRQ_CTRL 0x50
#define IRQ_CTRL_EVTQ_IRQEN (1 << 2) #define IRQ_CTRL_EVTQ_IRQEN (1 << 2)
@ -158,18 +150,14 @@
#define ARM_SMMU_STRTAB_BASE 0x80 #define ARM_SMMU_STRTAB_BASE 0x80
#define STRTAB_BASE_RA (1UL << 62) #define STRTAB_BASE_RA (1UL << 62)
#define STRTAB_BASE_ADDR_SHIFT 6 #define STRTAB_BASE_ADDR_MASK GENMASK_ULL(51, 6)
#define STRTAB_BASE_ADDR_MASK 0x3ffffffffffUL
#define ARM_SMMU_STRTAB_BASE_CFG 0x88 #define ARM_SMMU_STRTAB_BASE_CFG 0x88
#define STRTAB_BASE_CFG_LOG2SIZE_SHIFT 0 #define STRTAB_BASE_CFG_FMT GENMASK(17, 16)
#define STRTAB_BASE_CFG_LOG2SIZE_MASK 0x3f #define STRTAB_BASE_CFG_FMT_LINEAR 0
#define STRTAB_BASE_CFG_SPLIT_SHIFT 6 #define STRTAB_BASE_CFG_FMT_2LVL 1
#define STRTAB_BASE_CFG_SPLIT_MASK 0x1f #define STRTAB_BASE_CFG_SPLIT GENMASK(10, 6)
#define STRTAB_BASE_CFG_FMT_SHIFT 16 #define STRTAB_BASE_CFG_LOG2SIZE GENMASK(5, 0)
#define STRTAB_BASE_CFG_FMT_MASK 0x3
#define STRTAB_BASE_CFG_FMT_LINEAR (0 << STRTAB_BASE_CFG_FMT_SHIFT)
#define STRTAB_BASE_CFG_FMT_2LVL (1 << STRTAB_BASE_CFG_FMT_SHIFT)
#define ARM_SMMU_CMDQ_BASE 0x90 #define ARM_SMMU_CMDQ_BASE 0x90
#define ARM_SMMU_CMDQ_PROD 0x98 #define ARM_SMMU_CMDQ_PROD 0x98
@ -190,14 +178,16 @@
#define ARM_SMMU_PRIQ_IRQ_CFG2 0xdc #define ARM_SMMU_PRIQ_IRQ_CFG2 0xdc
/* Common MSI config fields */ /* Common MSI config fields */
#define MSI_CFG0_ADDR_SHIFT 2 #define MSI_CFG0_ADDR_MASK GENMASK_ULL(51, 2)
#define MSI_CFG0_ADDR_MASK 0x3fffffffffffUL #define MSI_CFG2_SH GENMASK(5, 4)
#define MSI_CFG2_SH_SHIFT 4 #define MSI_CFG2_MEMATTR GENMASK(3, 0)
#define MSI_CFG2_SH_NSH (0UL << MSI_CFG2_SH_SHIFT)
#define MSI_CFG2_SH_OSH (2UL << MSI_CFG2_SH_SHIFT) /* Common memory attribute values */
#define MSI_CFG2_SH_ISH (3UL << MSI_CFG2_SH_SHIFT) #define ARM_SMMU_SH_NSH 0
#define MSI_CFG2_MEMATTR_SHIFT 0 #define ARM_SMMU_SH_OSH 2
#define MSI_CFG2_MEMATTR_DEVICE_nGnRE (0x1 << MSI_CFG2_MEMATTR_SHIFT) #define ARM_SMMU_SH_ISH 3
#define ARM_SMMU_MEMATTR_DEVICE_nGnRE 0x1
#define ARM_SMMU_MEMATTR_OIWB 0xf
#define Q_IDX(q, p) ((p) & ((1 << (q)->max_n_shift) - 1)) #define Q_IDX(q, p) ((p) & ((1 << (q)->max_n_shift) - 1))
#define Q_WRP(q, p) ((p) & (1 << (q)->max_n_shift)) #define Q_WRP(q, p) ((p) & (1 << (q)->max_n_shift))
@ -207,10 +197,8 @@
Q_IDX(q, p) * (q)->ent_dwords) Q_IDX(q, p) * (q)->ent_dwords)
#define Q_BASE_RWA (1UL << 62) #define Q_BASE_RWA (1UL << 62)
#define Q_BASE_ADDR_SHIFT 5 #define Q_BASE_ADDR_MASK GENMASK_ULL(51, 5)
#define Q_BASE_ADDR_MASK 0xfffffffffffUL #define Q_BASE_LOG2SIZE GENMASK(4, 0)
#define Q_BASE_LOG2SIZE_SHIFT 0
#define Q_BASE_LOG2SIZE_MASK 0x1fUL
/* /*
* Stream table. * Stream table.
@ -223,187 +211,143 @@
#define STRTAB_SPLIT 8 #define STRTAB_SPLIT 8
#define STRTAB_L1_DESC_DWORDS 1 #define STRTAB_L1_DESC_DWORDS 1
#define STRTAB_L1_DESC_SPAN_SHIFT 0 #define STRTAB_L1_DESC_SPAN GENMASK_ULL(4, 0)
#define STRTAB_L1_DESC_SPAN_MASK 0x1fUL #define STRTAB_L1_DESC_L2PTR_MASK GENMASK_ULL(51, 6)
#define STRTAB_L1_DESC_L2PTR_SHIFT 6
#define STRTAB_L1_DESC_L2PTR_MASK 0x3ffffffffffUL
#define STRTAB_STE_DWORDS 8 #define STRTAB_STE_DWORDS 8
#define STRTAB_STE_0_V (1UL << 0) #define STRTAB_STE_0_V (1UL << 0)
#define STRTAB_STE_0_CFG_SHIFT 1 #define STRTAB_STE_0_CFG GENMASK_ULL(3, 1)
#define STRTAB_STE_0_CFG_MASK 0x7UL #define STRTAB_STE_0_CFG_ABORT 0
#define STRTAB_STE_0_CFG_ABORT (0UL << STRTAB_STE_0_CFG_SHIFT) #define STRTAB_STE_0_CFG_BYPASS 4
#define STRTAB_STE_0_CFG_BYPASS (4UL << STRTAB_STE_0_CFG_SHIFT) #define STRTAB_STE_0_CFG_S1_TRANS 5
#define STRTAB_STE_0_CFG_S1_TRANS (5UL << STRTAB_STE_0_CFG_SHIFT) #define STRTAB_STE_0_CFG_S2_TRANS 6
#define STRTAB_STE_0_CFG_S2_TRANS (6UL << STRTAB_STE_0_CFG_SHIFT)
#define STRTAB_STE_0_S1FMT_SHIFT 4 #define STRTAB_STE_0_S1FMT GENMASK_ULL(5, 4)
#define STRTAB_STE_0_S1FMT_LINEAR (0UL << STRTAB_STE_0_S1FMT_SHIFT) #define STRTAB_STE_0_S1FMT_LINEAR 0
#define STRTAB_STE_0_S1CTXPTR_SHIFT 6 #define STRTAB_STE_0_S1CTXPTR_MASK GENMASK_ULL(51, 6)
#define STRTAB_STE_0_S1CTXPTR_MASK 0x3ffffffffffUL #define STRTAB_STE_0_S1CDMAX GENMASK_ULL(63, 59)
#define STRTAB_STE_0_S1CDMAX_SHIFT 59
#define STRTAB_STE_0_S1CDMAX_MASK 0x1fUL
#define STRTAB_STE_1_S1C_CACHE_NC 0UL #define STRTAB_STE_1_S1C_CACHE_NC 0UL
#define STRTAB_STE_1_S1C_CACHE_WBRA 1UL #define STRTAB_STE_1_S1C_CACHE_WBRA 1UL
#define STRTAB_STE_1_S1C_CACHE_WT 2UL #define STRTAB_STE_1_S1C_CACHE_WT 2UL
#define STRTAB_STE_1_S1C_CACHE_WB 3UL #define STRTAB_STE_1_S1C_CACHE_WB 3UL
#define STRTAB_STE_1_S1C_SH_NSH 0UL #define STRTAB_STE_1_S1CIR GENMASK_ULL(3, 2)
#define STRTAB_STE_1_S1C_SH_OSH 2UL #define STRTAB_STE_1_S1COR GENMASK_ULL(5, 4)
#define STRTAB_STE_1_S1C_SH_ISH 3UL #define STRTAB_STE_1_S1CSH GENMASK_ULL(7, 6)
#define STRTAB_STE_1_S1CIR_SHIFT 2
#define STRTAB_STE_1_S1COR_SHIFT 4
#define STRTAB_STE_1_S1CSH_SHIFT 6
#define STRTAB_STE_1_S1STALLD (1UL << 27) #define STRTAB_STE_1_S1STALLD (1UL << 27)
#define STRTAB_STE_1_EATS GENMASK_ULL(29, 28)
#define STRTAB_STE_1_EATS_ABT 0UL #define STRTAB_STE_1_EATS_ABT 0UL
#define STRTAB_STE_1_EATS_TRANS 1UL #define STRTAB_STE_1_EATS_TRANS 1UL
#define STRTAB_STE_1_EATS_S1CHK 2UL #define STRTAB_STE_1_EATS_S1CHK 2UL
#define STRTAB_STE_1_EATS_SHIFT 28
#define STRTAB_STE_1_STRW GENMASK_ULL(31, 30)
#define STRTAB_STE_1_STRW_NSEL1 0UL #define STRTAB_STE_1_STRW_NSEL1 0UL
#define STRTAB_STE_1_STRW_EL2 2UL #define STRTAB_STE_1_STRW_EL2 2UL
#define STRTAB_STE_1_STRW_SHIFT 30
#define STRTAB_STE_1_SHCFG GENMASK_ULL(45, 44)
#define STRTAB_STE_1_SHCFG_INCOMING 1UL #define STRTAB_STE_1_SHCFG_INCOMING 1UL
#define STRTAB_STE_1_SHCFG_SHIFT 44
#define STRTAB_STE_2_S2VMID_SHIFT 0 #define STRTAB_STE_2_S2VMID GENMASK_ULL(15, 0)
#define STRTAB_STE_2_S2VMID_MASK 0xffffUL #define STRTAB_STE_2_VTCR GENMASK_ULL(50, 32)
#define STRTAB_STE_2_VTCR_SHIFT 32
#define STRTAB_STE_2_VTCR_MASK 0x7ffffUL
#define STRTAB_STE_2_S2AA64 (1UL << 51) #define STRTAB_STE_2_S2AA64 (1UL << 51)
#define STRTAB_STE_2_S2ENDI (1UL << 52) #define STRTAB_STE_2_S2ENDI (1UL << 52)
#define STRTAB_STE_2_S2PTW (1UL << 54) #define STRTAB_STE_2_S2PTW (1UL << 54)
#define STRTAB_STE_2_S2R (1UL << 58) #define STRTAB_STE_2_S2R (1UL << 58)
#define STRTAB_STE_3_S2TTB_SHIFT 4 #define STRTAB_STE_3_S2TTB_MASK GENMASK_ULL(51, 4)
#define STRTAB_STE_3_S2TTB_MASK 0xfffffffffffUL
/* Context descriptor (stage-1 only) */ /* Context descriptor (stage-1 only) */
#define CTXDESC_CD_DWORDS 8 #define CTXDESC_CD_DWORDS 8
#define CTXDESC_CD_0_TCR_T0SZ_SHIFT 0 #define CTXDESC_CD_0_TCR_T0SZ GENMASK_ULL(5, 0)
#define ARM64_TCR_T0SZ_SHIFT 0 #define ARM64_TCR_T0SZ GENMASK_ULL(5, 0)
#define ARM64_TCR_T0SZ_MASK 0x1fUL #define CTXDESC_CD_0_TCR_TG0 GENMASK_ULL(7, 6)
#define CTXDESC_CD_0_TCR_TG0_SHIFT 6 #define ARM64_TCR_TG0 GENMASK_ULL(15, 14)
#define ARM64_TCR_TG0_SHIFT 14 #define CTXDESC_CD_0_TCR_IRGN0 GENMASK_ULL(9, 8)
#define ARM64_TCR_TG0_MASK 0x3UL #define ARM64_TCR_IRGN0 GENMASK_ULL(9, 8)
#define CTXDESC_CD_0_TCR_IRGN0_SHIFT 8 #define CTXDESC_CD_0_TCR_ORGN0 GENMASK_ULL(11, 10)
#define ARM64_TCR_IRGN0_SHIFT 8 #define ARM64_TCR_ORGN0 GENMASK_ULL(11, 10)
#define ARM64_TCR_IRGN0_MASK 0x3UL #define CTXDESC_CD_0_TCR_SH0 GENMASK_ULL(13, 12)
#define CTXDESC_CD_0_TCR_ORGN0_SHIFT 10 #define ARM64_TCR_SH0 GENMASK_ULL(13, 12)
#define ARM64_TCR_ORGN0_SHIFT 10 #define CTXDESC_CD_0_TCR_EPD0 (1ULL << 14)
#define ARM64_TCR_ORGN0_MASK 0x3UL #define ARM64_TCR_EPD0 (1ULL << 7)
#define CTXDESC_CD_0_TCR_SH0_SHIFT 12 #define CTXDESC_CD_0_TCR_EPD1 (1ULL << 30)
#define ARM64_TCR_SH0_SHIFT 12 #define ARM64_TCR_EPD1 (1ULL << 23)
#define ARM64_TCR_SH0_MASK 0x3UL
#define CTXDESC_CD_0_TCR_EPD0_SHIFT 14
#define ARM64_TCR_EPD0_SHIFT 7
#define ARM64_TCR_EPD0_MASK 0x1UL
#define CTXDESC_CD_0_TCR_EPD1_SHIFT 30
#define ARM64_TCR_EPD1_SHIFT 23
#define ARM64_TCR_EPD1_MASK 0x1UL
#define CTXDESC_CD_0_ENDI (1UL << 15) #define CTXDESC_CD_0_ENDI (1UL << 15)
#define CTXDESC_CD_0_V (1UL << 31) #define CTXDESC_CD_0_V (1UL << 31)
#define CTXDESC_CD_0_TCR_IPS_SHIFT 32 #define CTXDESC_CD_0_TCR_IPS GENMASK_ULL(34, 32)
#define ARM64_TCR_IPS_SHIFT 32 #define ARM64_TCR_IPS GENMASK_ULL(34, 32)
#define ARM64_TCR_IPS_MASK 0x7UL #define CTXDESC_CD_0_TCR_TBI0 (1ULL << 38)
#define CTXDESC_CD_0_TCR_TBI0_SHIFT 38 #define ARM64_TCR_TBI0 (1ULL << 37)
#define ARM64_TCR_TBI0_SHIFT 37
#define ARM64_TCR_TBI0_MASK 0x1UL
#define CTXDESC_CD_0_AA64 (1UL << 41) #define CTXDESC_CD_0_AA64 (1UL << 41)
#define CTXDESC_CD_0_S (1UL << 44) #define CTXDESC_CD_0_S (1UL << 44)
#define CTXDESC_CD_0_R (1UL << 45) #define CTXDESC_CD_0_R (1UL << 45)
#define CTXDESC_CD_0_A (1UL << 46) #define CTXDESC_CD_0_A (1UL << 46)
#define CTXDESC_CD_0_ASET_SHIFT 47 #define CTXDESC_CD_0_ASET (1UL << 47)
#define CTXDESC_CD_0_ASET_SHARED (0UL << CTXDESC_CD_0_ASET_SHIFT) #define CTXDESC_CD_0_ASID GENMASK_ULL(63, 48)
#define CTXDESC_CD_0_ASET_PRIVATE (1UL << CTXDESC_CD_0_ASET_SHIFT)
#define CTXDESC_CD_0_ASID_SHIFT 48
#define CTXDESC_CD_0_ASID_MASK 0xffffUL
#define CTXDESC_CD_1_TTB0_SHIFT 4 #define CTXDESC_CD_1_TTB0_MASK GENMASK_ULL(51, 4)
#define CTXDESC_CD_1_TTB0_MASK 0xfffffffffffUL
#define CTXDESC_CD_3_MAIR_SHIFT 0
/* Convert between AArch64 (CPU) TCR format and SMMU CD format */ /* Convert between AArch64 (CPU) TCR format and SMMU CD format */
#define ARM_SMMU_TCR2CD(tcr, fld) \ #define ARM_SMMU_TCR2CD(tcr, fld) FIELD_PREP(CTXDESC_CD_0_TCR_##fld, \
(((tcr) >> ARM64_TCR_##fld##_SHIFT & ARM64_TCR_##fld##_MASK) \ FIELD_GET(ARM64_TCR_##fld, tcr))
<< CTXDESC_CD_0_TCR_##fld##_SHIFT)
/* Command queue */ /* Command queue */
#define CMDQ_ENT_DWORDS 2 #define CMDQ_ENT_DWORDS 2
#define CMDQ_MAX_SZ_SHIFT 8 #define CMDQ_MAX_SZ_SHIFT 8
#define CMDQ_ERR_SHIFT 24 #define CMDQ_CONS_ERR GENMASK(30, 24)
#define CMDQ_ERR_MASK 0x7f
#define CMDQ_ERR_CERROR_NONE_IDX 0 #define CMDQ_ERR_CERROR_NONE_IDX 0
#define CMDQ_ERR_CERROR_ILL_IDX 1 #define CMDQ_ERR_CERROR_ILL_IDX 1
#define CMDQ_ERR_CERROR_ABT_IDX 2 #define CMDQ_ERR_CERROR_ABT_IDX 2
#define CMDQ_0_OP_SHIFT 0 #define CMDQ_0_OP GENMASK_ULL(7, 0)
#define CMDQ_0_OP_MASK 0xffUL
#define CMDQ_0_SSV (1UL << 11) #define CMDQ_0_SSV (1UL << 11)
#define CMDQ_PREFETCH_0_SID_SHIFT 32 #define CMDQ_PREFETCH_0_SID GENMASK_ULL(63, 32)
#define CMDQ_PREFETCH_1_SIZE_SHIFT 0 #define CMDQ_PREFETCH_1_SIZE GENMASK_ULL(4, 0)
#define CMDQ_PREFETCH_1_ADDR_MASK ~0xfffUL #define CMDQ_PREFETCH_1_ADDR_MASK GENMASK_ULL(63, 12)
#define CMDQ_CFGI_0_SID_SHIFT 32 #define CMDQ_CFGI_0_SID GENMASK_ULL(63, 32)
#define CMDQ_CFGI_0_SID_MASK 0xffffffffUL
#define CMDQ_CFGI_1_LEAF (1UL << 0) #define CMDQ_CFGI_1_LEAF (1UL << 0)
#define CMDQ_CFGI_1_RANGE_SHIFT 0 #define CMDQ_CFGI_1_RANGE GENMASK_ULL(4, 0)
#define CMDQ_CFGI_1_RANGE_MASK 0x1fUL
#define CMDQ_TLBI_0_VMID_SHIFT 32 #define CMDQ_TLBI_0_VMID GENMASK_ULL(47, 32)
#define CMDQ_TLBI_0_ASID_SHIFT 48 #define CMDQ_TLBI_0_ASID GENMASK_ULL(63, 48)
#define CMDQ_TLBI_1_LEAF (1UL << 0) #define CMDQ_TLBI_1_LEAF (1UL << 0)
#define CMDQ_TLBI_1_VA_MASK ~0xfffUL #define CMDQ_TLBI_1_VA_MASK GENMASK_ULL(63, 12)
#define CMDQ_TLBI_1_IPA_MASK 0xfffffffff000UL #define CMDQ_TLBI_1_IPA_MASK GENMASK_ULL(51, 12)
#define CMDQ_PRI_0_SSID_SHIFT 12 #define CMDQ_PRI_0_SSID GENMASK_ULL(31, 12)
#define CMDQ_PRI_0_SSID_MASK 0xfffffUL #define CMDQ_PRI_0_SID GENMASK_ULL(63, 32)
#define CMDQ_PRI_0_SID_SHIFT 32 #define CMDQ_PRI_1_GRPID GENMASK_ULL(8, 0)
#define CMDQ_PRI_0_SID_MASK 0xffffffffUL #define CMDQ_PRI_1_RESP GENMASK_ULL(13, 12)
#define CMDQ_PRI_1_GRPID_SHIFT 0
#define CMDQ_PRI_1_GRPID_MASK 0x1ffUL
#define CMDQ_PRI_1_RESP_SHIFT 12
#define CMDQ_PRI_1_RESP_DENY (0UL << CMDQ_PRI_1_RESP_SHIFT)
#define CMDQ_PRI_1_RESP_FAIL (1UL << CMDQ_PRI_1_RESP_SHIFT)
#define CMDQ_PRI_1_RESP_SUCC (2UL << CMDQ_PRI_1_RESP_SHIFT)
#define CMDQ_SYNC_0_CS_SHIFT 12 #define CMDQ_SYNC_0_CS GENMASK_ULL(13, 12)
#define CMDQ_SYNC_0_CS_NONE (0UL << CMDQ_SYNC_0_CS_SHIFT) #define CMDQ_SYNC_0_CS_NONE 0
#define CMDQ_SYNC_0_CS_IRQ (1UL << CMDQ_SYNC_0_CS_SHIFT) #define CMDQ_SYNC_0_CS_IRQ 1
#define CMDQ_SYNC_0_CS_SEV (2UL << CMDQ_SYNC_0_CS_SHIFT) #define CMDQ_SYNC_0_CS_SEV 2
#define CMDQ_SYNC_0_MSH_SHIFT 22 #define CMDQ_SYNC_0_MSH GENMASK_ULL(23, 22)
#define CMDQ_SYNC_0_MSH_ISH (3UL << CMDQ_SYNC_0_MSH_SHIFT) #define CMDQ_SYNC_0_MSIATTR GENMASK_ULL(27, 24)
#define CMDQ_SYNC_0_MSIATTR_SHIFT 24 #define CMDQ_SYNC_0_MSIDATA GENMASK_ULL(63, 32)
#define CMDQ_SYNC_0_MSIATTR_OIWB (0xfUL << CMDQ_SYNC_0_MSIATTR_SHIFT) #define CMDQ_SYNC_1_MSIADDR_MASK GENMASK_ULL(51, 2)
#define CMDQ_SYNC_0_MSIDATA_SHIFT 32
#define CMDQ_SYNC_0_MSIDATA_MASK 0xffffffffUL
#define CMDQ_SYNC_1_MSIADDR_SHIFT 0
#define CMDQ_SYNC_1_MSIADDR_MASK 0xffffffffffffcUL
/* Event queue */ /* Event queue */
#define EVTQ_ENT_DWORDS 4 #define EVTQ_ENT_DWORDS 4
#define EVTQ_MAX_SZ_SHIFT 7 #define EVTQ_MAX_SZ_SHIFT 7
#define EVTQ_0_ID_SHIFT 0 #define EVTQ_0_ID GENMASK_ULL(7, 0)
#define EVTQ_0_ID_MASK 0xffUL
/* PRI queue */ /* PRI queue */
#define PRIQ_ENT_DWORDS 2 #define PRIQ_ENT_DWORDS 2
#define PRIQ_MAX_SZ_SHIFT 8 #define PRIQ_MAX_SZ_SHIFT 8
#define PRIQ_0_SID_SHIFT 0 #define PRIQ_0_SID GENMASK_ULL(31, 0)
#define PRIQ_0_SID_MASK 0xffffffffUL #define PRIQ_0_SSID GENMASK_ULL(51, 32)
#define PRIQ_0_SSID_SHIFT 32
#define PRIQ_0_SSID_MASK 0xfffffUL
#define PRIQ_0_PERM_PRIV (1UL << 58) #define PRIQ_0_PERM_PRIV (1UL << 58)
#define PRIQ_0_PERM_EXEC (1UL << 59) #define PRIQ_0_PERM_EXEC (1UL << 59)
#define PRIQ_0_PERM_READ (1UL << 60) #define PRIQ_0_PERM_READ (1UL << 60)
@ -411,10 +355,8 @@
#define PRIQ_0_PRG_LAST (1UL << 62) #define PRIQ_0_PRG_LAST (1UL << 62)
#define PRIQ_0_SSID_V (1UL << 63) #define PRIQ_0_SSID_V (1UL << 63)
#define PRIQ_1_PRG_IDX_SHIFT 0 #define PRIQ_1_PRG_IDX GENMASK_ULL(8, 0)
#define PRIQ_1_PRG_IDX_MASK 0x1ffUL #define PRIQ_1_ADDR_MASK GENMASK_ULL(63, 12)
#define PRIQ_1_ADDR_SHIFT 12
#define PRIQ_1_ADDR_MASK 0xfffffffffffffUL
/* High-level queue structures */ /* High-level queue structures */
#define ARM_SMMU_POLL_TIMEOUT_US 100 #define ARM_SMMU_POLL_TIMEOUT_US 100
@ -430,9 +372,9 @@ MODULE_PARM_DESC(disable_bypass,
"Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU."); "Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
enum pri_resp { enum pri_resp {
PRI_RESP_DENY, PRI_RESP_DENY = 0,
PRI_RESP_FAIL, PRI_RESP_FAIL = 1,
PRI_RESP_SUCC, PRI_RESP_SUCC = 2,
}; };
enum arm_smmu_msi_index { enum arm_smmu_msi_index {
@ -611,6 +553,7 @@ struct arm_smmu_device {
#define ARM_SMMU_FEAT_STALLS (1 << 11) #define ARM_SMMU_FEAT_STALLS (1 << 11)
#define ARM_SMMU_FEAT_HYP (1 << 12) #define ARM_SMMU_FEAT_HYP (1 << 12)
#define ARM_SMMU_FEAT_STALL_FORCE (1 << 13) #define ARM_SMMU_FEAT_STALL_FORCE (1 << 13)
#define ARM_SMMU_FEAT_VAX (1 << 14)
u32 features; u32 features;
#define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0) #define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0)
@ -836,67 +779,64 @@ static int queue_remove_raw(struct arm_smmu_queue *q, u64 *ent)
static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent) static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
{ {
memset(cmd, 0, CMDQ_ENT_DWORDS << 3); memset(cmd, 0, CMDQ_ENT_DWORDS << 3);
cmd[0] |= (ent->opcode & CMDQ_0_OP_MASK) << CMDQ_0_OP_SHIFT; cmd[0] |= FIELD_PREP(CMDQ_0_OP, ent->opcode);
switch (ent->opcode) { switch (ent->opcode) {
case CMDQ_OP_TLBI_EL2_ALL: case CMDQ_OP_TLBI_EL2_ALL:
case CMDQ_OP_TLBI_NSNH_ALL: case CMDQ_OP_TLBI_NSNH_ALL:
break; break;
case CMDQ_OP_PREFETCH_CFG: case CMDQ_OP_PREFETCH_CFG:
cmd[0] |= (u64)ent->prefetch.sid << CMDQ_PREFETCH_0_SID_SHIFT; cmd[0] |= FIELD_PREP(CMDQ_PREFETCH_0_SID, ent->prefetch.sid);
cmd[1] |= ent->prefetch.size << CMDQ_PREFETCH_1_SIZE_SHIFT; cmd[1] |= FIELD_PREP(CMDQ_PREFETCH_1_SIZE, ent->prefetch.size);
cmd[1] |= ent->prefetch.addr & CMDQ_PREFETCH_1_ADDR_MASK; cmd[1] |= ent->prefetch.addr & CMDQ_PREFETCH_1_ADDR_MASK;
break; break;
case CMDQ_OP_CFGI_STE: case CMDQ_OP_CFGI_STE:
cmd[0] |= (u64)ent->cfgi.sid << CMDQ_CFGI_0_SID_SHIFT; cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SID, ent->cfgi.sid);
cmd[1] |= ent->cfgi.leaf ? CMDQ_CFGI_1_LEAF : 0; cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_LEAF, ent->cfgi.leaf);
break; break;
case CMDQ_OP_CFGI_ALL: case CMDQ_OP_CFGI_ALL:
/* Cover the entire SID range */ /* Cover the entire SID range */
cmd[1] |= CMDQ_CFGI_1_RANGE_MASK << CMDQ_CFGI_1_RANGE_SHIFT; cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_RANGE, 31);
break; break;
case CMDQ_OP_TLBI_NH_VA: case CMDQ_OP_TLBI_NH_VA:
cmd[0] |= (u64)ent->tlbi.asid << CMDQ_TLBI_0_ASID_SHIFT; cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid);
cmd[1] |= ent->tlbi.leaf ? CMDQ_TLBI_1_LEAF : 0; cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf);
cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_VA_MASK; cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_VA_MASK;
break; break;
case CMDQ_OP_TLBI_S2_IPA: case CMDQ_OP_TLBI_S2_IPA:
cmd[0] |= (u64)ent->tlbi.vmid << CMDQ_TLBI_0_VMID_SHIFT; cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
cmd[1] |= ent->tlbi.leaf ? CMDQ_TLBI_1_LEAF : 0; cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf);
cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_IPA_MASK; cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_IPA_MASK;
break; break;
case CMDQ_OP_TLBI_NH_ASID: case CMDQ_OP_TLBI_NH_ASID:
cmd[0] |= (u64)ent->tlbi.asid << CMDQ_TLBI_0_ASID_SHIFT; cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid);
/* Fallthrough */ /* Fallthrough */
case CMDQ_OP_TLBI_S12_VMALL: case CMDQ_OP_TLBI_S12_VMALL:
cmd[0] |= (u64)ent->tlbi.vmid << CMDQ_TLBI_0_VMID_SHIFT; cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
break; break;
case CMDQ_OP_PRI_RESP: case CMDQ_OP_PRI_RESP:
cmd[0] |= ent->substream_valid ? CMDQ_0_SSV : 0; cmd[0] |= FIELD_PREP(CMDQ_0_SSV, ent->substream_valid);
cmd[0] |= ent->pri.ssid << CMDQ_PRI_0_SSID_SHIFT; cmd[0] |= FIELD_PREP(CMDQ_PRI_0_SSID, ent->pri.ssid);
cmd[0] |= (u64)ent->pri.sid << CMDQ_PRI_0_SID_SHIFT; cmd[0] |= FIELD_PREP(CMDQ_PRI_0_SID, ent->pri.sid);
cmd[1] |= ent->pri.grpid << CMDQ_PRI_1_GRPID_SHIFT; cmd[1] |= FIELD_PREP(CMDQ_PRI_1_GRPID, ent->pri.grpid);
switch (ent->pri.resp) { switch (ent->pri.resp) {
case PRI_RESP_DENY: case PRI_RESP_DENY:
cmd[1] |= CMDQ_PRI_1_RESP_DENY;
break;
case PRI_RESP_FAIL: case PRI_RESP_FAIL:
cmd[1] |= CMDQ_PRI_1_RESP_FAIL;
break;
case PRI_RESP_SUCC: case PRI_RESP_SUCC:
cmd[1] |= CMDQ_PRI_1_RESP_SUCC;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
cmd[1] |= FIELD_PREP(CMDQ_PRI_1_RESP, ent->pri.resp);
break; break;
case CMDQ_OP_CMD_SYNC: case CMDQ_OP_CMD_SYNC:
if (ent->sync.msiaddr) if (ent->sync.msiaddr)
cmd[0] |= CMDQ_SYNC_0_CS_IRQ; cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_IRQ);
else else
cmd[0] |= CMDQ_SYNC_0_CS_SEV; cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV);
cmd[0] |= CMDQ_SYNC_0_MSH_ISH | CMDQ_SYNC_0_MSIATTR_OIWB; cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_ISH);
cmd[0] |= (u64)ent->sync.msidata << CMDQ_SYNC_0_MSIDATA_SHIFT; cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OIWB);
cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIDATA, ent->sync.msidata);
cmd[1] |= ent->sync.msiaddr & CMDQ_SYNC_1_MSIADDR_MASK; cmd[1] |= ent->sync.msiaddr & CMDQ_SYNC_1_MSIADDR_MASK;
break; break;
default: default:
@ -918,7 +858,7 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
u64 cmd[CMDQ_ENT_DWORDS]; u64 cmd[CMDQ_ENT_DWORDS];
struct arm_smmu_queue *q = &smmu->cmdq.q; struct arm_smmu_queue *q = &smmu->cmdq.q;
u32 cons = readl_relaxed(q->cons_reg); u32 cons = readl_relaxed(q->cons_reg);
u32 idx = cons >> CMDQ_ERR_SHIFT & CMDQ_ERR_MASK; u32 idx = FIELD_GET(CMDQ_CONS_ERR, cons);
struct arm_smmu_cmdq_ent cmd_sync = { struct arm_smmu_cmdq_ent cmd_sync = {
.opcode = CMDQ_OP_CMD_SYNC, .opcode = CMDQ_OP_CMD_SYNC,
}; };
@ -1083,8 +1023,8 @@ static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
#ifdef __BIG_ENDIAN #ifdef __BIG_ENDIAN
CTXDESC_CD_0_ENDI | CTXDESC_CD_0_ENDI |
#endif #endif
CTXDESC_CD_0_R | CTXDESC_CD_0_A | CTXDESC_CD_0_ASET_PRIVATE | CTXDESC_CD_0_R | CTXDESC_CD_0_A | CTXDESC_CD_0_ASET |
CTXDESC_CD_0_AA64 | (u64)cfg->cd.asid << CTXDESC_CD_0_ASID_SHIFT | CTXDESC_CD_0_AA64 | FIELD_PREP(CTXDESC_CD_0_ASID, cfg->cd.asid) |
CTXDESC_CD_0_V; CTXDESC_CD_0_V;
/* STALL_MODEL==0b10 && CD.S==0 is ILLEGAL */ /* STALL_MODEL==0b10 && CD.S==0 is ILLEGAL */
@ -1093,10 +1033,10 @@ static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
cfg->cdptr[0] = cpu_to_le64(val); cfg->cdptr[0] = cpu_to_le64(val);
val = cfg->cd.ttbr & CTXDESC_CD_1_TTB0_MASK << CTXDESC_CD_1_TTB0_SHIFT; val = cfg->cd.ttbr & CTXDESC_CD_1_TTB0_MASK;
cfg->cdptr[1] = cpu_to_le64(val); cfg->cdptr[1] = cpu_to_le64(val);
cfg->cdptr[3] = cpu_to_le64(cfg->cd.mair << CTXDESC_CD_3_MAIR_SHIFT); cfg->cdptr[3] = cpu_to_le64(cfg->cd.mair);
} }
/* Stream table manipulation functions */ /* Stream table manipulation functions */
@ -1105,10 +1045,8 @@ arm_smmu_write_strtab_l1_desc(__le64 *dst, struct arm_smmu_strtab_l1_desc *desc)
{ {
u64 val = 0; u64 val = 0;
val |= (desc->span & STRTAB_L1_DESC_SPAN_MASK) val |= FIELD_PREP(STRTAB_L1_DESC_SPAN, desc->span);
<< STRTAB_L1_DESC_SPAN_SHIFT; val |= desc->l2ptr_dma & STRTAB_L1_DESC_L2PTR_MASK;
val |= desc->l2ptr_dma &
STRTAB_L1_DESC_L2PTR_MASK << STRTAB_L1_DESC_L2PTR_SHIFT;
*dst = cpu_to_le64(val); *dst = cpu_to_le64(val);
} }
@ -1156,10 +1094,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
}; };
if (val & STRTAB_STE_0_V) { if (val & STRTAB_STE_0_V) {
u64 cfg; switch (FIELD_GET(STRTAB_STE_0_CFG, val)) {
cfg = val & STRTAB_STE_0_CFG_MASK << STRTAB_STE_0_CFG_SHIFT;
switch (cfg) {
case STRTAB_STE_0_CFG_BYPASS: case STRTAB_STE_0_CFG_BYPASS:
break; break;
case STRTAB_STE_0_CFG_S1_TRANS: case STRTAB_STE_0_CFG_S1_TRANS:
@ -1180,13 +1115,13 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
/* Bypass/fault */ /* Bypass/fault */
if (!ste->assigned || !(ste->s1_cfg || ste->s2_cfg)) { if (!ste->assigned || !(ste->s1_cfg || ste->s2_cfg)) {
if (!ste->assigned && disable_bypass) if (!ste->assigned && disable_bypass)
val |= STRTAB_STE_0_CFG_ABORT; val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_ABORT);
else else
val |= STRTAB_STE_0_CFG_BYPASS; val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_BYPASS);
dst[0] = cpu_to_le64(val); dst[0] = cpu_to_le64(val);
dst[1] = cpu_to_le64(STRTAB_STE_1_SHCFG_INCOMING dst[1] = cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG,
<< STRTAB_STE_1_SHCFG_SHIFT); STRTAB_STE_1_SHCFG_INCOMING));
dst[2] = 0; /* Nuke the VMID */ dst[2] = 0; /* Nuke the VMID */
/* /*
* The SMMU can perform negative caching, so we must sync * The SMMU can perform negative caching, so we must sync
@ -1200,41 +1135,36 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
if (ste->s1_cfg) { if (ste->s1_cfg) {
BUG_ON(ste_live); BUG_ON(ste_live);
dst[1] = cpu_to_le64( dst[1] = cpu_to_le64(
STRTAB_STE_1_S1C_CACHE_WBRA FIELD_PREP(STRTAB_STE_1_S1CIR, STRTAB_STE_1_S1C_CACHE_WBRA) |
<< STRTAB_STE_1_S1CIR_SHIFT | FIELD_PREP(STRTAB_STE_1_S1COR, STRTAB_STE_1_S1C_CACHE_WBRA) |
STRTAB_STE_1_S1C_CACHE_WBRA FIELD_PREP(STRTAB_STE_1_S1CSH, ARM_SMMU_SH_ISH) |
<< STRTAB_STE_1_S1COR_SHIFT |
STRTAB_STE_1_S1C_SH_ISH << STRTAB_STE_1_S1CSH_SHIFT |
#ifdef CONFIG_PCI_ATS #ifdef CONFIG_PCI_ATS
STRTAB_STE_1_EATS_TRANS << STRTAB_STE_1_EATS_SHIFT | FIELD_PREP(STRTAB_STE_1_EATS, STRTAB_STE_1_EATS_TRANS) |
#endif #endif
STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT); FIELD_PREP(STRTAB_STE_1_STRW, STRTAB_STE_1_STRW_NSEL1));
if (smmu->features & ARM_SMMU_FEAT_STALLS && if (smmu->features & ARM_SMMU_FEAT_STALLS &&
!(smmu->features & ARM_SMMU_FEAT_STALL_FORCE)) !(smmu->features & ARM_SMMU_FEAT_STALL_FORCE))
dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD); dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
val |= (ste->s1_cfg->cdptr_dma & STRTAB_STE_0_S1CTXPTR_MASK val |= (ste->s1_cfg->cdptr_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
<< STRTAB_STE_0_S1CTXPTR_SHIFT) | FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S1_TRANS);
STRTAB_STE_0_CFG_S1_TRANS;
} }
if (ste->s2_cfg) { if (ste->s2_cfg) {
BUG_ON(ste_live); BUG_ON(ste_live);
dst[2] = cpu_to_le64( dst[2] = cpu_to_le64(
ste->s2_cfg->vmid << STRTAB_STE_2_S2VMID_SHIFT | FIELD_PREP(STRTAB_STE_2_S2VMID, ste->s2_cfg->vmid) |
(ste->s2_cfg->vtcr & STRTAB_STE_2_VTCR_MASK) FIELD_PREP(STRTAB_STE_2_VTCR, ste->s2_cfg->vtcr) |
<< STRTAB_STE_2_VTCR_SHIFT |
#ifdef __BIG_ENDIAN #ifdef __BIG_ENDIAN
STRTAB_STE_2_S2ENDI | STRTAB_STE_2_S2ENDI |
#endif #endif
STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2AA64 | STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2AA64 |
STRTAB_STE_2_S2R); STRTAB_STE_2_S2R);
dst[3] = cpu_to_le64(ste->s2_cfg->vttbr & dst[3] = cpu_to_le64(ste->s2_cfg->vttbr & STRTAB_STE_3_S2TTB_MASK);
STRTAB_STE_3_S2TTB_MASK << STRTAB_STE_3_S2TTB_SHIFT);
val |= STRTAB_STE_0_CFG_S2_TRANS; val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S2_TRANS);
} }
arm_smmu_sync_ste_for_sid(smmu, sid); arm_smmu_sync_ste_for_sid(smmu, sid);
@ -1295,7 +1225,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
do { do {
while (!queue_remove_raw(q, evt)) { while (!queue_remove_raw(q, evt)) {
u8 id = evt[0] >> EVTQ_0_ID_SHIFT & EVTQ_0_ID_MASK; u8 id = FIELD_GET(EVTQ_0_ID, evt[0]);
dev_info(smmu->dev, "event 0x%02x received:\n", id); dev_info(smmu->dev, "event 0x%02x received:\n", id);
for (i = 0; i < ARRAY_SIZE(evt); ++i) for (i = 0; i < ARRAY_SIZE(evt); ++i)
@ -1323,11 +1253,11 @@ static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
u16 grpid; u16 grpid;
bool ssv, last; bool ssv, last;
sid = evt[0] >> PRIQ_0_SID_SHIFT & PRIQ_0_SID_MASK; sid = FIELD_GET(PRIQ_0_SID, evt[0]);
ssv = evt[0] & PRIQ_0_SSID_V; ssv = FIELD_GET(PRIQ_0_SSID_V, evt[0]);
ssid = ssv ? evt[0] >> PRIQ_0_SSID_SHIFT & PRIQ_0_SSID_MASK : 0; ssid = ssv ? FIELD_GET(PRIQ_0_SSID, evt[0]) : 0;
last = evt[0] & PRIQ_0_PRG_LAST; last = FIELD_GET(PRIQ_0_PRG_LAST, evt[0]);
grpid = evt[1] >> PRIQ_1_PRG_IDX_SHIFT & PRIQ_1_PRG_IDX_MASK; grpid = FIELD_GET(PRIQ_1_PRG_IDX, evt[1]);
dev_info(smmu->dev, "unexpected PRI request received:\n"); dev_info(smmu->dev, "unexpected PRI request received:\n");
dev_info(smmu->dev, dev_info(smmu->dev,
@ -1337,7 +1267,7 @@ static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
evt[0] & PRIQ_0_PERM_READ ? "R" : "", evt[0] & PRIQ_0_PERM_READ ? "R" : "",
evt[0] & PRIQ_0_PERM_WRITE ? "W" : "", evt[0] & PRIQ_0_PERM_WRITE ? "W" : "",
evt[0] & PRIQ_0_PERM_EXEC ? "X" : "", evt[0] & PRIQ_0_PERM_EXEC ? "X" : "",
evt[1] & PRIQ_1_ADDR_MASK << PRIQ_1_ADDR_SHIFT); evt[1] & PRIQ_1_ADDR_MASK);
if (last) { if (last) {
struct arm_smmu_cmdq_ent cmd = { struct arm_smmu_cmdq_ent cmd = {
@ -1664,7 +1594,8 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
switch (smmu_domain->stage) { switch (smmu_domain->stage) {
case ARM_SMMU_DOMAIN_S1: case ARM_SMMU_DOMAIN_S1:
ias = VA_BITS; ias = (smmu->features & ARM_SMMU_FEAT_VAX) ? 52 : 48;
ias = min_t(unsigned long, ias, VA_BITS);
oas = smmu->ias; oas = smmu->ias;
fmt = ARM_64_LPAE_S1; fmt = ARM_64_LPAE_S1;
finalise_stage_fn = arm_smmu_domain_finalise_s1; finalise_stage_fn = arm_smmu_domain_finalise_s1;
@ -1696,7 +1627,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
return -ENOMEM; return -ENOMEM;
domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap; domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
domain->geometry.aperture_end = (1UL << ias) - 1; domain->geometry.aperture_end = (1UL << pgtbl_cfg.ias) - 1;
domain->geometry.force_aperture = true; domain->geometry.force_aperture = true;
ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg); ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg);
@ -2102,9 +2033,8 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
q->ent_dwords = dwords; q->ent_dwords = dwords;
q->q_base = Q_BASE_RWA; q->q_base = Q_BASE_RWA;
q->q_base |= q->base_dma & Q_BASE_ADDR_MASK << Q_BASE_ADDR_SHIFT; q->q_base |= q->base_dma & Q_BASE_ADDR_MASK;
q->q_base |= (q->max_n_shift & Q_BASE_LOG2SIZE_MASK) q->q_base |= FIELD_PREP(Q_BASE_LOG2SIZE, q->max_n_shift);
<< Q_BASE_LOG2SIZE_SHIFT;
q->prod = q->cons = 0; q->prod = q->cons = 0;
return 0; return 0;
@ -2186,11 +2116,9 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
cfg->strtab = strtab; cfg->strtab = strtab;
/* Configure strtab_base_cfg for 2 levels */ /* Configure strtab_base_cfg for 2 levels */
reg = STRTAB_BASE_CFG_FMT_2LVL; reg = FIELD_PREP(STRTAB_BASE_CFG_FMT, STRTAB_BASE_CFG_FMT_2LVL);
reg |= (size & STRTAB_BASE_CFG_LOG2SIZE_MASK) reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, size);
<< STRTAB_BASE_CFG_LOG2SIZE_SHIFT; reg |= FIELD_PREP(STRTAB_BASE_CFG_SPLIT, STRTAB_SPLIT);
reg |= (STRTAB_SPLIT & STRTAB_BASE_CFG_SPLIT_MASK)
<< STRTAB_BASE_CFG_SPLIT_SHIFT;
cfg->strtab_base_cfg = reg; cfg->strtab_base_cfg = reg;
return arm_smmu_init_l1_strtab(smmu); return arm_smmu_init_l1_strtab(smmu);
@ -2216,9 +2144,8 @@ static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
cfg->num_l1_ents = 1 << smmu->sid_bits; cfg->num_l1_ents = 1 << smmu->sid_bits;
/* Configure strtab_base_cfg for a linear table covering all SIDs */ /* Configure strtab_base_cfg for a linear table covering all SIDs */
reg = STRTAB_BASE_CFG_FMT_LINEAR; reg = FIELD_PREP(STRTAB_BASE_CFG_FMT, STRTAB_BASE_CFG_FMT_LINEAR);
reg |= (smmu->sid_bits & STRTAB_BASE_CFG_LOG2SIZE_MASK) reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, smmu->sid_bits);
<< STRTAB_BASE_CFG_LOG2SIZE_SHIFT;
cfg->strtab_base_cfg = reg; cfg->strtab_base_cfg = reg;
arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents); arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents);
@ -2239,8 +2166,7 @@ static int arm_smmu_init_strtab(struct arm_smmu_device *smmu)
return ret; return ret;
/* Set the strtab base address */ /* Set the strtab base address */
reg = smmu->strtab_cfg.strtab_dma & reg = smmu->strtab_cfg.strtab_dma & STRTAB_BASE_ADDR_MASK;
STRTAB_BASE_ADDR_MASK << STRTAB_BASE_ADDR_SHIFT;
reg |= STRTAB_BASE_RA; reg |= STRTAB_BASE_RA;
smmu->strtab_cfg.strtab_base = reg; smmu->strtab_cfg.strtab_base = reg;
@ -2303,11 +2229,11 @@ static void arm_smmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
phys_addr_t *cfg = arm_smmu_msi_cfg[desc->platform.msi_index]; phys_addr_t *cfg = arm_smmu_msi_cfg[desc->platform.msi_index];
doorbell = (((u64)msg->address_hi) << 32) | msg->address_lo; doorbell = (((u64)msg->address_hi) << 32) | msg->address_lo;
doorbell &= MSI_CFG0_ADDR_MASK << MSI_CFG0_ADDR_SHIFT; doorbell &= MSI_CFG0_ADDR_MASK;
writeq_relaxed(doorbell, smmu->base + cfg[0]); writeq_relaxed(doorbell, smmu->base + cfg[0]);
writel_relaxed(msg->data, smmu->base + cfg[1]); writel_relaxed(msg->data, smmu->base + cfg[1]);
writel_relaxed(MSI_CFG2_MEMATTR_DEVICE_nGnRE, smmu->base + cfg[2]); writel_relaxed(ARM_SMMU_MEMATTR_DEVICE_nGnRE, smmu->base + cfg[2]);
} }
static void arm_smmu_setup_msis(struct arm_smmu_device *smmu) static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
@ -2328,10 +2254,15 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
if (!(smmu->features & ARM_SMMU_FEAT_MSI)) if (!(smmu->features & ARM_SMMU_FEAT_MSI))
return; return;
if (!dev->msi_domain) {
dev_info(smmu->dev, "msi_domain absent - falling back to wired irqs\n");
return;
}
/* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */ /* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */
ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg); ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
if (ret) { if (ret) {
dev_warn(dev, "failed to allocate MSIs\n"); dev_warn(dev, "failed to allocate MSIs - falling back to wired irqs\n");
return; return;
} }
@ -2370,6 +2301,8 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
"arm-smmu-v3-evtq", smmu); "arm-smmu-v3-evtq", smmu);
if (ret < 0) if (ret < 0)
dev_warn(smmu->dev, "failed to enable evtq irq\n"); dev_warn(smmu->dev, "failed to enable evtq irq\n");
} else {
dev_warn(smmu->dev, "no evtq irq - events will not be reported!\n");
} }
irq = smmu->gerr_irq; irq = smmu->gerr_irq;
@ -2378,6 +2311,8 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
0, "arm-smmu-v3-gerror", smmu); 0, "arm-smmu-v3-gerror", smmu);
if (ret < 0) if (ret < 0)
dev_warn(smmu->dev, "failed to enable gerror irq\n"); dev_warn(smmu->dev, "failed to enable gerror irq\n");
} else {
dev_warn(smmu->dev, "no gerr irq - errors will not be reported!\n");
} }
if (smmu->features & ARM_SMMU_FEAT_PRI) { if (smmu->features & ARM_SMMU_FEAT_PRI) {
@ -2391,6 +2326,8 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
if (ret < 0) if (ret < 0)
dev_warn(smmu->dev, dev_warn(smmu->dev,
"failed to enable priq irq\n"); "failed to enable priq irq\n");
} else {
dev_warn(smmu->dev, "no priq irq - PRI will be broken\n");
} }
} }
} }
@ -2463,12 +2400,12 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
return ret; return ret;
/* CR1 (table and queue memory attributes) */ /* CR1 (table and queue memory attributes) */
reg = (CR1_SH_ISH << CR1_TABLE_SH_SHIFT) | reg = FIELD_PREP(CR1_TABLE_SH, ARM_SMMU_SH_ISH) |
(CR1_CACHE_WB << CR1_TABLE_OC_SHIFT) | FIELD_PREP(CR1_TABLE_OC, CR1_CACHE_WB) |
(CR1_CACHE_WB << CR1_TABLE_IC_SHIFT) | FIELD_PREP(CR1_TABLE_IC, CR1_CACHE_WB) |
(CR1_SH_ISH << CR1_QUEUE_SH_SHIFT) | FIELD_PREP(CR1_QUEUE_SH, ARM_SMMU_SH_ISH) |
(CR1_CACHE_WB << CR1_QUEUE_OC_SHIFT) | FIELD_PREP(CR1_QUEUE_OC, CR1_CACHE_WB) |
(CR1_CACHE_WB << CR1_QUEUE_IC_SHIFT); FIELD_PREP(CR1_QUEUE_IC, CR1_CACHE_WB);
writel_relaxed(reg, smmu->base + ARM_SMMU_CR1); writel_relaxed(reg, smmu->base + ARM_SMMU_CR1);
/* CR2 (random crap) */ /* CR2 (random crap) */
@ -2578,7 +2515,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0); reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0);
/* 2-level structures */ /* 2-level structures */
if ((reg & IDR0_ST_LVL_MASK << IDR0_ST_LVL_SHIFT) == IDR0_ST_LVL_2LVL) if (FIELD_GET(IDR0_ST_LVL, reg) == IDR0_ST_LVL_2LVL)
smmu->features |= ARM_SMMU_FEAT_2_LVL_STRTAB; smmu->features |= ARM_SMMU_FEAT_2_LVL_STRTAB;
if (reg & IDR0_CD2L) if (reg & IDR0_CD2L)
@ -2589,7 +2526,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
* We currently require the same endianness as the CPU, but this * We currently require the same endianness as the CPU, but this
* could be changed later by adding a new IO_PGTABLE_QUIRK. * could be changed later by adding a new IO_PGTABLE_QUIRK.
*/ */
switch (reg & IDR0_TTENDIAN_MASK << IDR0_TTENDIAN_SHIFT) { switch (FIELD_GET(IDR0_TTENDIAN, reg)) {
case IDR0_TTENDIAN_MIXED: case IDR0_TTENDIAN_MIXED:
smmu->features |= ARM_SMMU_FEAT_TT_LE | ARM_SMMU_FEAT_TT_BE; smmu->features |= ARM_SMMU_FEAT_TT_LE | ARM_SMMU_FEAT_TT_BE;
break; break;
@ -2631,7 +2568,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
dev_warn(smmu->dev, "IDR0.COHACC overridden by FW configuration (%s)\n", dev_warn(smmu->dev, "IDR0.COHACC overridden by FW configuration (%s)\n",
coherent ? "true" : "false"); coherent ? "true" : "false");
switch (reg & IDR0_STALL_MODEL_MASK << IDR0_STALL_MODEL_SHIFT) { switch (FIELD_GET(IDR0_STALL_MODEL, reg)) {
case IDR0_STALL_MODEL_FORCE: case IDR0_STALL_MODEL_FORCE:
smmu->features |= ARM_SMMU_FEAT_STALL_FORCE; smmu->features |= ARM_SMMU_FEAT_STALL_FORCE;
/* Fallthrough */ /* Fallthrough */
@ -2651,7 +2588,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
} }
/* We only support the AArch64 table format at present */ /* We only support the AArch64 table format at present */
switch (reg & IDR0_TTF_MASK << IDR0_TTF_SHIFT) { switch (FIELD_GET(IDR0_TTF, reg)) {
case IDR0_TTF_AARCH32_64: case IDR0_TTF_AARCH32_64:
smmu->ias = 40; smmu->ias = 40;
/* Fallthrough */ /* Fallthrough */
@ -2674,22 +2611,22 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
} }
/* Queue sizes, capped at 4k */ /* Queue sizes, capped at 4k */
smmu->cmdq.q.max_n_shift = min((u32)CMDQ_MAX_SZ_SHIFT, smmu->cmdq.q.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT,
reg >> IDR1_CMDQ_SHIFT & IDR1_CMDQ_MASK); FIELD_GET(IDR1_CMDQS, reg));
if (!smmu->cmdq.q.max_n_shift) { if (!smmu->cmdq.q.max_n_shift) {
/* Odd alignment restrictions on the base, so ignore for now */ /* Odd alignment restrictions on the base, so ignore for now */
dev_err(smmu->dev, "unit-length command queue not supported\n"); dev_err(smmu->dev, "unit-length command queue not supported\n");
return -ENXIO; return -ENXIO;
} }
smmu->evtq.q.max_n_shift = min((u32)EVTQ_MAX_SZ_SHIFT, smmu->evtq.q.max_n_shift = min_t(u32, EVTQ_MAX_SZ_SHIFT,
reg >> IDR1_EVTQ_SHIFT & IDR1_EVTQ_MASK); FIELD_GET(IDR1_EVTQS, reg));
smmu->priq.q.max_n_shift = min((u32)PRIQ_MAX_SZ_SHIFT, smmu->priq.q.max_n_shift = min_t(u32, PRIQ_MAX_SZ_SHIFT,
reg >> IDR1_PRIQ_SHIFT & IDR1_PRIQ_MASK); FIELD_GET(IDR1_PRIQS, reg));
/* SID/SSID sizes */ /* SID/SSID sizes */
smmu->ssid_bits = reg >> IDR1_SSID_SHIFT & IDR1_SSID_MASK; smmu->ssid_bits = FIELD_GET(IDR1_SSIDSIZE, reg);
smmu->sid_bits = reg >> IDR1_SID_SHIFT & IDR1_SID_MASK; smmu->sid_bits = FIELD_GET(IDR1_SIDSIZE, reg);
/* /*
* If the SMMU supports fewer bits than would fill a single L2 stream * If the SMMU supports fewer bits than would fill a single L2 stream
@ -2702,8 +2639,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5); reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5);
/* Maximum number of outstanding stalls */ /* Maximum number of outstanding stalls */
smmu->evtq.max_stalls = reg >> IDR5_STALL_MAX_SHIFT smmu->evtq.max_stalls = FIELD_GET(IDR5_STALL_MAX, reg);
& IDR5_STALL_MAX_MASK;
/* Page sizes */ /* Page sizes */
if (reg & IDR5_GRAN64K) if (reg & IDR5_GRAN64K)
@ -2713,13 +2649,12 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
if (reg & IDR5_GRAN4K) if (reg & IDR5_GRAN4K)
smmu->pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G; smmu->pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G;
if (arm_smmu_ops.pgsize_bitmap == -1UL) /* Input address size */
arm_smmu_ops.pgsize_bitmap = smmu->pgsize_bitmap; if (FIELD_GET(IDR5_VAX, reg) == IDR5_VAX_52_BIT)
else smmu->features |= ARM_SMMU_FEAT_VAX;
arm_smmu_ops.pgsize_bitmap |= smmu->pgsize_bitmap;
/* Output address size */ /* Output address size */
switch (reg & IDR5_OAS_MASK << IDR5_OAS_SHIFT) { switch (FIELD_GET(IDR5_OAS, reg)) {
case IDR5_OAS_32_BIT: case IDR5_OAS_32_BIT:
smmu->oas = 32; smmu->oas = 32;
break; break;
@ -2735,6 +2670,10 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
case IDR5_OAS_44_BIT: case IDR5_OAS_44_BIT:
smmu->oas = 44; smmu->oas = 44;
break; break;
case IDR5_OAS_52_BIT:
smmu->oas = 52;
smmu->pgsize_bitmap |= 1ULL << 42; /* 4TB */
break;
default: default:
dev_info(smmu->dev, dev_info(smmu->dev,
"unknown output address size. Truncating to 48-bit\n"); "unknown output address size. Truncating to 48-bit\n");
@ -2743,6 +2682,11 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
smmu->oas = 48; smmu->oas = 48;
} }
if (arm_smmu_ops.pgsize_bitmap == -1UL)
arm_smmu_ops.pgsize_bitmap = smmu->pgsize_bitmap;
else
arm_smmu_ops.pgsize_bitmap |= smmu->pgsize_bitmap;
/* Set the DMA mask for our table walker */ /* Set the DMA mask for our table walker */
if (dma_set_mask_and_coherent(smmu->dev, DMA_BIT_MASK(smmu->oas))) if (dma_set_mask_and_coherent(smmu->dev, DMA_BIT_MASK(smmu->oas)))
dev_warn(smmu->dev, dev_warn(smmu->dev,

View File

@ -19,6 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <linux/acpi_iort.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-iommu.h> #include <linux/dma-iommu.h>
#include <linux/gfp.h> #include <linux/gfp.h>
@ -167,13 +168,18 @@ EXPORT_SYMBOL(iommu_put_dma_cookie);
* *
* IOMMU drivers can use this to implement their .get_resv_regions callback * IOMMU drivers can use this to implement their .get_resv_regions callback
* for general non-IOMMU-specific reservations. Currently, this covers host * for general non-IOMMU-specific reservations. Currently, this covers host
* bridge windows for PCI devices. * bridge windows for PCI devices and GICv3 ITS region reservation on ACPI
* based ARM platforms that may require HW MSI reservation.
*/ */
void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list) void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list)
{ {
struct pci_host_bridge *bridge; struct pci_host_bridge *bridge;
struct resource_entry *window; struct resource_entry *window;
if (!is_of_node(dev->iommu_fwspec->iommu_fwnode) &&
iort_iommu_msi_get_resv_regions(dev, list) < 0)
return;
if (!dev_is_pci(dev)) if (!dev_is_pci(dev))
return; return;

View File

@ -806,7 +806,7 @@ int __init dmar_dev_scope_init(void)
return dmar_dev_scope_status; return dmar_dev_scope_status;
} }
void dmar_register_bus_notifier(void) void __init dmar_register_bus_notifier(void)
{ {
bus_register_notifier(&pci_bus_type, &dmar_pci_bus_nb); bus_register_notifier(&pci_bus_type, &dmar_pci_bus_nb);
} }

View File

@ -1239,17 +1239,6 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *iommu_domain,
return phys; return phys;
} }
static struct iommu_group *get_device_iommu_group(struct device *dev)
{
struct iommu_group *group;
group = iommu_group_get(dev);
if (!group)
group = iommu_group_alloc();
return group;
}
static int exynos_iommu_add_device(struct device *dev) static int exynos_iommu_add_device(struct device *dev)
{ {
struct exynos_iommu_owner *owner = dev->archdata.iommu; struct exynos_iommu_owner *owner = dev->archdata.iommu;
@ -1345,7 +1334,7 @@ static const struct iommu_ops exynos_iommu_ops = {
.unmap = exynos_iommu_unmap, .unmap = exynos_iommu_unmap,
.map_sg = default_iommu_map_sg, .map_sg = default_iommu_map_sg,
.iova_to_phys = exynos_iommu_iova_to_phys, .iova_to_phys = exynos_iommu_iova_to_phys,
.device_group = get_device_iommu_group, .device_group = generic_device_group,
.add_device = exynos_iommu_add_device, .add_device = exynos_iommu_add_device,
.remove_device = exynos_iommu_remove_device, .remove_device = exynos_iommu_remove_device,
.pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE, .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,

View File

@ -5043,7 +5043,6 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain,
{ {
struct dmar_domain *dmar_domain = to_dmar_domain(domain); struct dmar_domain *dmar_domain = to_dmar_domain(domain);
struct page *freelist = NULL; struct page *freelist = NULL;
struct intel_iommu *iommu;
unsigned long start_pfn, last_pfn; unsigned long start_pfn, last_pfn;
unsigned int npages; unsigned int npages;
int iommu_id, level = 0; int iommu_id, level = 0;
@ -5062,12 +5061,9 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain,
npages = last_pfn - start_pfn + 1; npages = last_pfn - start_pfn + 1;
for_each_domain_iommu(iommu_id, dmar_domain) { for_each_domain_iommu(iommu_id, dmar_domain)
iommu = g_iommus[iommu_id];
iommu_flush_iotlb_psi(g_iommus[iommu_id], dmar_domain, iommu_flush_iotlb_psi(g_iommus[iommu_id], dmar_domain,
start_pfn, npages, !freelist, 0); start_pfn, npages, !freelist, 0);
}
dma_free_pagelist(freelist); dma_free_pagelist(freelist);

View File

@ -396,6 +396,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
pasid_max - 1, GFP_KERNEL); pasid_max - 1, GFP_KERNEL);
if (ret < 0) { if (ret < 0) {
kfree(svm); kfree(svm);
kfree(sdev);
goto out; goto out;
} }
svm->pasid = ret; svm->pasid = ret;
@ -422,17 +423,13 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
iommu->pasid_table[svm->pasid].val = pasid_entry_val; iommu->pasid_table[svm->pasid].val = pasid_entry_val;
wmb(); wmb();
/* In caching mode, we still have to flush with PASID 0 when
* a PASID table entry becomes present. Not entirely clear /*
* *why* that would be the case surely we could just issue * Flush PASID cache when a PASID table entry becomes
* a flush with the PASID value that we've changed? The PASID * present.
* is the index into the table, after all. It's not like domain */
* IDs in the case of the equivalent context-entry change in
* caching mode. And for that matter it's not entirely clear why
* a VMM would be in the business of caching the PASID table
* anyway. Surely that can be left entirely to the guest? */
if (cap_caching_mode(iommu->cap)) if (cap_caching_mode(iommu->cap))
intel_flush_pasid_dev(svm, sdev, 0); intel_flush_pasid_dev(svm, sdev, svm->pasid);
} }
list_add_rcu(&sdev->list, &svm->devs); list_add_rcu(&sdev->list, &svm->devs);

View File

@ -357,8 +357,8 @@ static bool arm_v7s_pte_is_cont(arm_v7s_iopte pte, int lvl)
return false; return false;
} }
static int __arm_v7s_unmap(struct arm_v7s_io_pgtable *, unsigned long, static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *, unsigned long,
size_t, int, arm_v7s_iopte *); size_t, int, arm_v7s_iopte *);
static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data, static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data,
unsigned long iova, phys_addr_t paddr, int prot, unsigned long iova, phys_addr_t paddr, int prot,
@ -541,9 +541,10 @@ static arm_v7s_iopte arm_v7s_split_cont(struct arm_v7s_io_pgtable *data,
return pte; return pte;
} }
static int arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data, static size_t arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data,
unsigned long iova, size_t size, unsigned long iova, size_t size,
arm_v7s_iopte blk_pte, arm_v7s_iopte *ptep) arm_v7s_iopte blk_pte,
arm_v7s_iopte *ptep)
{ {
struct io_pgtable_cfg *cfg = &data->iop.cfg; struct io_pgtable_cfg *cfg = &data->iop.cfg;
arm_v7s_iopte pte, *tablep; arm_v7s_iopte pte, *tablep;
@ -584,9 +585,9 @@ static int arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data,
return size; return size;
} }
static int __arm_v7s_unmap(struct arm_v7s_io_pgtable *data, static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
unsigned long iova, size_t size, int lvl, unsigned long iova, size_t size, int lvl,
arm_v7s_iopte *ptep) arm_v7s_iopte *ptep)
{ {
arm_v7s_iopte pte[ARM_V7S_CONT_PAGES]; arm_v7s_iopte pte[ARM_V7S_CONT_PAGES];
struct io_pgtable *iop = &data->iop; struct io_pgtable *iop = &data->iop;
@ -656,8 +657,8 @@ static int __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
return __arm_v7s_unmap(data, iova, size, lvl + 1, ptep); return __arm_v7s_unmap(data, iova, size, lvl + 1, ptep);
} }
static int arm_v7s_unmap(struct io_pgtable_ops *ops, unsigned long iova, static size_t arm_v7s_unmap(struct io_pgtable_ops *ops, unsigned long iova,
size_t size) size_t size)
{ {
struct arm_v7s_io_pgtable *data = io_pgtable_ops_to_data(ops); struct arm_v7s_io_pgtable *data = io_pgtable_ops_to_data(ops);

View File

@ -21,6 +21,7 @@
#define pr_fmt(fmt) "arm-lpae io-pgtable: " fmt #define pr_fmt(fmt) "arm-lpae io-pgtable: " fmt
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sizes.h> #include <linux/sizes.h>
@ -32,7 +33,7 @@
#include "io-pgtable.h" #include "io-pgtable.h"
#define ARM_LPAE_MAX_ADDR_BITS 48 #define ARM_LPAE_MAX_ADDR_BITS 52
#define ARM_LPAE_S2_MAX_CONCAT_PAGES 16 #define ARM_LPAE_S2_MAX_CONCAT_PAGES 16
#define ARM_LPAE_MAX_LEVELS 4 #define ARM_LPAE_MAX_LEVELS 4
@ -86,6 +87,8 @@
#define ARM_LPAE_PTE_TYPE_TABLE 3 #define ARM_LPAE_PTE_TYPE_TABLE 3
#define ARM_LPAE_PTE_TYPE_PAGE 3 #define ARM_LPAE_PTE_TYPE_PAGE 3
#define ARM_LPAE_PTE_ADDR_MASK GENMASK_ULL(47,12)
#define ARM_LPAE_PTE_NSTABLE (((arm_lpae_iopte)1) << 63) #define ARM_LPAE_PTE_NSTABLE (((arm_lpae_iopte)1) << 63)
#define ARM_LPAE_PTE_XN (((arm_lpae_iopte)3) << 53) #define ARM_LPAE_PTE_XN (((arm_lpae_iopte)3) << 53)
#define ARM_LPAE_PTE_AF (((arm_lpae_iopte)1) << 10) #define ARM_LPAE_PTE_AF (((arm_lpae_iopte)1) << 10)
@ -159,6 +162,7 @@
#define ARM_LPAE_TCR_PS_42_BIT 0x3ULL #define ARM_LPAE_TCR_PS_42_BIT 0x3ULL
#define ARM_LPAE_TCR_PS_44_BIT 0x4ULL #define ARM_LPAE_TCR_PS_44_BIT 0x4ULL
#define ARM_LPAE_TCR_PS_48_BIT 0x5ULL #define ARM_LPAE_TCR_PS_48_BIT 0x5ULL
#define ARM_LPAE_TCR_PS_52_BIT 0x6ULL
#define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3) #define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3)
#define ARM_LPAE_MAIR_ATTR_MASK 0xff #define ARM_LPAE_MAIR_ATTR_MASK 0xff
@ -170,9 +174,7 @@
#define ARM_LPAE_MAIR_ATTR_IDX_DEV 2 #define ARM_LPAE_MAIR_ATTR_IDX_DEV 2
/* IOPTE accessors */ /* IOPTE accessors */
#define iopte_deref(pte,d) \ #define iopte_deref(pte,d) __va(iopte_to_paddr(pte, d))
(__va((pte) & ((1ULL << ARM_LPAE_MAX_ADDR_BITS) - 1) \
& ~(ARM_LPAE_GRANULE(d) - 1ULL)))
#define iopte_type(pte,l) \ #define iopte_type(pte,l) \
(((pte) >> ARM_LPAE_PTE_TYPE_SHIFT) & ARM_LPAE_PTE_TYPE_MASK) (((pte) >> ARM_LPAE_PTE_TYPE_SHIFT) & ARM_LPAE_PTE_TYPE_MASK)
@ -184,12 +186,6 @@
(iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_PAGE) : \ (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_PAGE) : \
(iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_BLOCK)) (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_BLOCK))
#define iopte_to_pfn(pte,d) \
(((pte) & ((1ULL << ARM_LPAE_MAX_ADDR_BITS) - 1)) >> (d)->pg_shift)
#define pfn_to_iopte(pfn,d) \
(((pfn) << (d)->pg_shift) & ((1ULL << ARM_LPAE_MAX_ADDR_BITS) - 1))
struct arm_lpae_io_pgtable { struct arm_lpae_io_pgtable {
struct io_pgtable iop; struct io_pgtable iop;
@ -203,6 +199,27 @@ struct arm_lpae_io_pgtable {
typedef u64 arm_lpae_iopte; typedef u64 arm_lpae_iopte;
static arm_lpae_iopte paddr_to_iopte(phys_addr_t paddr,
struct arm_lpae_io_pgtable *data)
{
arm_lpae_iopte pte = paddr;
/* Of the bits which overlap, either 51:48 or 15:12 are always RES0 */
return (pte | (pte >> (48 - 12))) & ARM_LPAE_PTE_ADDR_MASK;
}
static phys_addr_t iopte_to_paddr(arm_lpae_iopte pte,
struct arm_lpae_io_pgtable *data)
{
u64 paddr = pte & ARM_LPAE_PTE_ADDR_MASK;
if (data->pg_shift < 16)
return paddr;
/* Rotate the packed high-order bits back to the top */
return (paddr | (paddr << (48 - 12))) & (ARM_LPAE_PTE_ADDR_MASK << 4);
}
static bool selftest_running = false; static bool selftest_running = false;
static dma_addr_t __arm_lpae_dma_addr(void *pages) static dma_addr_t __arm_lpae_dma_addr(void *pages)
@ -268,9 +285,9 @@ static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, arm_lpae_iopte pte,
__arm_lpae_sync_pte(ptep, cfg); __arm_lpae_sync_pte(ptep, cfg);
} }
static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
unsigned long iova, size_t size, int lvl, unsigned long iova, size_t size, int lvl,
arm_lpae_iopte *ptep); arm_lpae_iopte *ptep);
static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data,
phys_addr_t paddr, arm_lpae_iopte prot, phys_addr_t paddr, arm_lpae_iopte prot,
@ -287,7 +304,7 @@ static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data,
pte |= ARM_LPAE_PTE_TYPE_BLOCK; pte |= ARM_LPAE_PTE_TYPE_BLOCK;
pte |= ARM_LPAE_PTE_AF | ARM_LPAE_PTE_SH_IS; pte |= ARM_LPAE_PTE_AF | ARM_LPAE_PTE_SH_IS;
pte |= pfn_to_iopte(paddr >> data->pg_shift, data); pte |= paddr_to_iopte(paddr, data);
__arm_lpae_set_pte(ptep, pte, &data->iop.cfg); __arm_lpae_set_pte(ptep, pte, &data->iop.cfg);
} }
@ -506,10 +523,10 @@ static void arm_lpae_free_pgtable(struct io_pgtable *iop)
kfree(data); kfree(data);
} }
static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
unsigned long iova, size_t size, unsigned long iova, size_t size,
arm_lpae_iopte blk_pte, int lvl, arm_lpae_iopte blk_pte, int lvl,
arm_lpae_iopte *ptep) arm_lpae_iopte *ptep)
{ {
struct io_pgtable_cfg *cfg = &data->iop.cfg; struct io_pgtable_cfg *cfg = &data->iop.cfg;
arm_lpae_iopte pte, *tablep; arm_lpae_iopte pte, *tablep;
@ -528,7 +545,7 @@ static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
if (size == split_sz) if (size == split_sz)
unmap_idx = ARM_LPAE_LVL_IDX(iova, lvl, data); unmap_idx = ARM_LPAE_LVL_IDX(iova, lvl, data);
blk_paddr = iopte_to_pfn(blk_pte, data) << data->pg_shift; blk_paddr = iopte_to_paddr(blk_pte, data);
pte = iopte_prot(blk_pte); pte = iopte_prot(blk_pte);
for (i = 0; i < tablesz / sizeof(pte); i++, blk_paddr += split_sz) { for (i = 0; i < tablesz / sizeof(pte); i++, blk_paddr += split_sz) {
@ -560,9 +577,9 @@ static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
return size; return size;
} }
static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
unsigned long iova, size_t size, int lvl, unsigned long iova, size_t size, int lvl,
arm_lpae_iopte *ptep) arm_lpae_iopte *ptep)
{ {
arm_lpae_iopte pte; arm_lpae_iopte pte;
struct io_pgtable *iop = &data->iop; struct io_pgtable *iop = &data->iop;
@ -606,8 +623,8 @@ static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
return __arm_lpae_unmap(data, iova, size, lvl + 1, ptep); return __arm_lpae_unmap(data, iova, size, lvl + 1, ptep);
} }
static int arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova, static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
size_t size) size_t size)
{ {
struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
arm_lpae_iopte *ptep = data->pgd; arm_lpae_iopte *ptep = data->pgd;
@ -652,12 +669,13 @@ static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
found_translation: found_translation:
iova &= (ARM_LPAE_BLOCK_SIZE(lvl, data) - 1); iova &= (ARM_LPAE_BLOCK_SIZE(lvl, data) - 1);
return ((phys_addr_t)iopte_to_pfn(pte,data) << data->pg_shift) | iova; return iopte_to_paddr(pte, data) | iova;
} }
static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg) static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg)
{ {
unsigned long granule; unsigned long granule, page_sizes;
unsigned int max_addr_bits = 48;
/* /*
* We need to restrict the supported page sizes to match the * We need to restrict the supported page sizes to match the
@ -677,17 +695,24 @@ static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg)
switch (granule) { switch (granule) {
case SZ_4K: case SZ_4K:
cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G); page_sizes = (SZ_4K | SZ_2M | SZ_1G);
break; break;
case SZ_16K: case SZ_16K:
cfg->pgsize_bitmap &= (SZ_16K | SZ_32M); page_sizes = (SZ_16K | SZ_32M);
break; break;
case SZ_64K: case SZ_64K:
cfg->pgsize_bitmap &= (SZ_64K | SZ_512M); max_addr_bits = 52;
page_sizes = (SZ_64K | SZ_512M);
if (cfg->oas > 48)
page_sizes |= 1ULL << 42; /* 4TB */
break; break;
default: default:
cfg->pgsize_bitmap = 0; page_sizes = 0;
} }
cfg->pgsize_bitmap &= page_sizes;
cfg->ias = min(cfg->ias, max_addr_bits);
cfg->oas = min(cfg->oas, max_addr_bits);
} }
static struct arm_lpae_io_pgtable * static struct arm_lpae_io_pgtable *
@ -784,6 +809,9 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
case 48: case 48:
reg |= (ARM_LPAE_TCR_PS_48_BIT << ARM_LPAE_TCR_IPS_SHIFT); reg |= (ARM_LPAE_TCR_PS_48_BIT << ARM_LPAE_TCR_IPS_SHIFT);
break; break;
case 52:
reg |= (ARM_LPAE_TCR_PS_52_BIT << ARM_LPAE_TCR_IPS_SHIFT);
break;
default: default:
goto out_free_data; goto out_free_data;
} }
@ -891,6 +919,9 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
case 48: case 48:
reg |= (ARM_LPAE_TCR_PS_48_BIT << ARM_LPAE_TCR_PS_SHIFT); reg |= (ARM_LPAE_TCR_PS_48_BIT << ARM_LPAE_TCR_PS_SHIFT);
break; break;
case 52:
reg |= (ARM_LPAE_TCR_PS_52_BIT << ARM_LPAE_TCR_PS_SHIFT);
break;
default: default:
goto out_free_data; goto out_free_data;
} }

View File

@ -119,8 +119,8 @@ struct io_pgtable_cfg {
struct io_pgtable_ops { struct io_pgtable_ops {
int (*map)(struct io_pgtable_ops *ops, unsigned long iova, int (*map)(struct io_pgtable_ops *ops, unsigned long iova,
phys_addr_t paddr, size_t size, int prot); phys_addr_t paddr, size_t size, int prot);
int (*unmap)(struct io_pgtable_ops *ops, unsigned long iova, size_t (*unmap)(struct io_pgtable_ops *ops, unsigned long iova,
size_t size); size_t size);
phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops, phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops,
unsigned long iova); unsigned long iova);
}; };

View File

@ -1573,10 +1573,10 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
if (unlikely(ops->unmap == NULL || if (unlikely(ops->unmap == NULL ||
domain->pgsize_bitmap == 0UL)) domain->pgsize_bitmap == 0UL))
return -ENODEV; return 0;
if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING))) if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING)))
return -EINVAL; return 0;
/* find out the minimum page size supported */ /* find out the minimum page size supported */
min_pagesz = 1 << __ffs(domain->pgsize_bitmap); min_pagesz = 1 << __ffs(domain->pgsize_bitmap);
@ -1589,7 +1589,7 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
if (!IS_ALIGNED(iova | size, min_pagesz)) { if (!IS_ALIGNED(iova | size, min_pagesz)) {
pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n", pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
iova, size, min_pagesz); iova, size, min_pagesz);
return -EINVAL; return 0;
} }
pr_debug("unmap this: iova 0x%lx size 0x%zx\n", iova, size); pr_debug("unmap this: iova 0x%lx size 0x%zx\n", iova, size);

View File

@ -60,7 +60,7 @@
(((prot) & 0x3) << F_MMU_TF_PROTECT_SEL_SHIFT(data)) (((prot) & 0x3) << F_MMU_TF_PROTECT_SEL_SHIFT(data))
#define REG_MMU_IVRP_PADDR 0x114 #define REG_MMU_IVRP_PADDR 0x114
#define F_MMU_IVRP_PA_SET(pa, ext) (((pa) >> 1) | ((!!(ext)) << 31))
#define REG_MMU_VLD_PA_RNG 0x118 #define REG_MMU_VLD_PA_RNG 0x118
#define F_MMU_VLD_PA_RNG(EA, SA) (((EA) << 8) | (SA)) #define F_MMU_VLD_PA_RNG(EA, SA) (((EA) << 8) | (SA))
@ -539,8 +539,13 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
F_INT_PRETETCH_TRANSATION_FIFO_FAULT; F_INT_PRETETCH_TRANSATION_FIFO_FAULT;
writel_relaxed(regval, data->base + REG_MMU_INT_MAIN_CONTROL); writel_relaxed(regval, data->base + REG_MMU_INT_MAIN_CONTROL);
writel_relaxed(F_MMU_IVRP_PA_SET(data->protect_base, data->enable_4GB), if (data->m4u_plat == M4U_MT8173)
data->base + REG_MMU_IVRP_PADDR); regval = (data->protect_base >> 1) | (data->enable_4GB << 31);
else
regval = lower_32_bits(data->protect_base) |
upper_32_bits(data->protect_base);
writel_relaxed(regval, data->base + REG_MMU_IVRP_PADDR);
if (data->enable_4GB && data->m4u_plat != M4U_MT8173) { if (data->enable_4GB && data->m4u_plat != M4U_MT8173) {
/* /*
* If 4GB mode is enabled, the validate PA range is from * If 4GB mode is enabled, the validate PA range is from
@ -695,6 +700,7 @@ static int __maybe_unused mtk_iommu_suspend(struct device *dev)
reg->ctrl_reg = readl_relaxed(base + REG_MMU_CTRL_REG); reg->ctrl_reg = readl_relaxed(base + REG_MMU_CTRL_REG);
reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL0); reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL0);
reg->int_main_control = readl_relaxed(base + REG_MMU_INT_MAIN_CONTROL); reg->int_main_control = readl_relaxed(base + REG_MMU_INT_MAIN_CONTROL);
reg->ivrp_paddr = readl_relaxed(base + REG_MMU_IVRP_PADDR);
clk_disable_unprepare(data->bclk); clk_disable_unprepare(data->bclk);
return 0; return 0;
} }
@ -717,8 +723,7 @@ static int __maybe_unused mtk_iommu_resume(struct device *dev)
writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG); writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL0); writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL0);
writel_relaxed(reg->int_main_control, base + REG_MMU_INT_MAIN_CONTROL); writel_relaxed(reg->int_main_control, base + REG_MMU_INT_MAIN_CONTROL);
writel_relaxed(F_MMU_IVRP_PA_SET(data->protect_base, data->enable_4GB), writel_relaxed(reg->ivrp_paddr, base + REG_MMU_IVRP_PADDR);
base + REG_MMU_IVRP_PADDR);
if (data->m4u_dom) if (data->m4u_dom)
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0], writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
base + REG_MMU_PT_BASE_ADDR); base + REG_MMU_PT_BASE_ADDR);

View File

@ -32,6 +32,7 @@ struct mtk_iommu_suspend_reg {
u32 ctrl_reg; u32 ctrl_reg;
u32 int_control0; u32 int_control0;
u32 int_main_control; u32 int_main_control;
u32 ivrp_paddr;
}; };
enum mtk_iommu_plat { enum mtk_iommu_plat {

View File

@ -417,20 +417,12 @@ static int mtk_iommu_create_mapping(struct device *dev,
m4udev->archdata.iommu = mtk_mapping; m4udev->archdata.iommu = mtk_mapping;
} }
ret = arm_iommu_attach_device(dev, mtk_mapping);
if (ret)
goto err_release_mapping;
return 0; return 0;
err_release_mapping:
arm_iommu_release_mapping(mtk_mapping);
m4udev->archdata.iommu = NULL;
return ret;
} }
static int mtk_iommu_add_device(struct device *dev) static int mtk_iommu_add_device(struct device *dev)
{ {
struct dma_iommu_mapping *mtk_mapping;
struct of_phandle_args iommu_spec; struct of_phandle_args iommu_spec;
struct of_phandle_iterator it; struct of_phandle_iterator it;
struct mtk_iommu_data *data; struct mtk_iommu_data *data;
@ -451,15 +443,30 @@ static int mtk_iommu_add_device(struct device *dev)
if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops)
return -ENODEV; /* Not a iommu client device */ return -ENODEV; /* Not a iommu client device */
data = dev->iommu_fwspec->iommu_priv; /*
iommu_device_link(&data->iommu, dev); * This is a short-term bodge because the ARM DMA code doesn't
* understand multi-device groups, but we have to call into it
group = iommu_group_get_for_dev(dev); * successfully (and not just rely on a normal IOMMU API attach
* here) in order to set the correct DMA API ops on @dev.
*/
group = iommu_group_alloc();
if (IS_ERR(group)) if (IS_ERR(group))
return PTR_ERR(group); return PTR_ERR(group);
err = iommu_group_add_device(group, dev);
iommu_group_put(group); iommu_group_put(group);
return 0; if (err)
return err;
data = dev->iommu_fwspec->iommu_priv;
mtk_mapping = data->dev->archdata.iommu;
err = arm_iommu_attach_device(dev, mtk_mapping);
if (err) {
iommu_group_remove_device(dev);
return err;
}
return iommu_device_link(&data->iommu, dev);;
} }
static void mtk_iommu_remove_device(struct device *dev) static void mtk_iommu_remove_device(struct device *dev)
@ -476,24 +483,6 @@ static void mtk_iommu_remove_device(struct device *dev)
iommu_fwspec_free(dev); iommu_fwspec_free(dev);
} }
static struct iommu_group *mtk_iommu_device_group(struct device *dev)
{
struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv;
if (!data)
return ERR_PTR(-ENODEV);
/* All the client devices are in the same m4u iommu-group */
if (!data->m4u_group) {
data->m4u_group = iommu_group_alloc();
if (IS_ERR(data->m4u_group))
dev_err(dev, "Failed to allocate M4U IOMMU group\n");
} else {
iommu_group_ref_get(data->m4u_group);
}
return data->m4u_group;
}
static int mtk_iommu_hw_init(const struct mtk_iommu_data *data) static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
{ {
u32 regval; u32 regval;
@ -546,7 +535,6 @@ static struct iommu_ops mtk_iommu_ops = {
.iova_to_phys = mtk_iommu_iova_to_phys, .iova_to_phys = mtk_iommu_iova_to_phys,
.add_device = mtk_iommu_add_device, .add_device = mtk_iommu_add_device,
.remove_device = mtk_iommu_remove_device, .remove_device = mtk_iommu_remove_device,
.device_group = mtk_iommu_device_group,
.pgsize_bitmap = ~0UL << MT2701_IOMMU_PAGE_SHIFT, .pgsize_bitmap = ~0UL << MT2701_IOMMU_PAGE_SHIFT,
}; };

View File

@ -1536,7 +1536,7 @@ static struct iommu_group *omap_iommu_device_group(struct device *dev)
struct iommu_group *group = ERR_PTR(-EINVAL); struct iommu_group *group = ERR_PTR(-EINVAL);
if (arch_data->iommu_dev) if (arch_data->iommu_dev)
group = arch_data->iommu_dev->group; group = iommu_group_ref_get(arch_data->iommu_dev->group);
return group; return group;
} }

View File

@ -4,6 +4,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/clk.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
@ -13,13 +14,15 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/jiffies.h> #include <linux/iopoll.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_iommu.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
@ -36,7 +39,10 @@
#define RK_MMU_AUTO_GATING 0x24 #define RK_MMU_AUTO_GATING 0x24
#define DTE_ADDR_DUMMY 0xCAFEBABE #define DTE_ADDR_DUMMY 0xCAFEBABE
#define FORCE_RESET_TIMEOUT 100 /* ms */
#define RK_MMU_POLL_PERIOD_US 100
#define RK_MMU_FORCE_RESET_TIMEOUT_US 100000
#define RK_MMU_POLL_TIMEOUT_US 1000
/* RK_MMU_STATUS fields */ /* RK_MMU_STATUS fields */
#define RK_MMU_STATUS_PAGING_ENABLED BIT(0) #define RK_MMU_STATUS_PAGING_ENABLED BIT(0)
@ -73,11 +79,8 @@
*/ */
#define RK_IOMMU_PGSIZE_BITMAP 0x007ff000 #define RK_IOMMU_PGSIZE_BITMAP 0x007ff000
#define IOMMU_REG_POLL_COUNT_FAST 1000
struct rk_iommu_domain { struct rk_iommu_domain {
struct list_head iommus; struct list_head iommus;
struct platform_device *pdev;
u32 *dt; /* page directory table */ u32 *dt; /* page directory table */
dma_addr_t dt_dma; dma_addr_t dt_dma;
spinlock_t iommus_lock; /* lock for iommus list */ spinlock_t iommus_lock; /* lock for iommus list */
@ -86,24 +89,37 @@ struct rk_iommu_domain {
struct iommu_domain domain; struct iommu_domain domain;
}; };
/* list of clocks required by IOMMU */
static const char * const rk_iommu_clocks[] = {
"aclk", "iface",
};
struct rk_iommu { struct rk_iommu {
struct device *dev; struct device *dev;
void __iomem **bases; void __iomem **bases;
int num_mmu; int num_mmu;
int *irq; struct clk_bulk_data *clocks;
int num_irq; int num_clocks;
bool reset_disabled; bool reset_disabled;
struct iommu_device iommu; struct iommu_device iommu;
struct list_head node; /* entry in rk_iommu_domain.iommus */ struct list_head node; /* entry in rk_iommu_domain.iommus */
struct iommu_domain *domain; /* domain to which iommu is attached */ struct iommu_domain *domain; /* domain to which iommu is attached */
struct iommu_group *group;
}; };
struct rk_iommudata {
struct device_link *link; /* runtime PM link from IOMMU to master */
struct rk_iommu *iommu;
};
static struct device *dma_dev;
static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma, static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma,
unsigned int count) unsigned int count)
{ {
size_t size = count * sizeof(u32); /* count of u32 entry */ size_t size = count * sizeof(u32); /* count of u32 entry */
dma_sync_single_for_device(&dom->pdev->dev, dma, size, DMA_TO_DEVICE); dma_sync_single_for_device(dma_dev, dma, size, DMA_TO_DEVICE);
} }
static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom) static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom)
@ -111,27 +127,6 @@ static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom)
return container_of(dom, struct rk_iommu_domain, domain); return container_of(dom, struct rk_iommu_domain, domain);
} }
/**
* Inspired by _wait_for in intel_drv.h
* This is NOT safe for use in interrupt context.
*
* Note that it's important that we check the condition again after having
* timed out, since the timeout could be due to preemption or similar and
* we've never had a chance to check the condition before the timeout.
*/
#define rk_wait_for(COND, MS) ({ \
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1; \
int ret__ = 0; \
while (!(COND)) { \
if (time_after(jiffies, timeout__)) { \
ret__ = (COND) ? 0 : -ETIMEDOUT; \
break; \
} \
usleep_range(50, 100); \
} \
ret__; \
})
/* /*
* The Rockchip rk3288 iommu uses a 2-level page table. * The Rockchip rk3288 iommu uses a 2-level page table.
* The first level is the "Directory Table" (DT). * The first level is the "Directory Table" (DT).
@ -296,19 +291,21 @@ static void rk_iommu_base_command(void __iomem *base, u32 command)
{ {
writel(command, base + RK_MMU_COMMAND); writel(command, base + RK_MMU_COMMAND);
} }
static void rk_iommu_zap_lines(struct rk_iommu *iommu, dma_addr_t iova, static void rk_iommu_zap_lines(struct rk_iommu *iommu, dma_addr_t iova_start,
size_t size) size_t size)
{ {
int i; int i;
dma_addr_t iova_end = iova_start + size;
dma_addr_t iova_end = iova + size;
/* /*
* TODO(djkurtz): Figure out when it is more efficient to shootdown the * TODO(djkurtz): Figure out when it is more efficient to shootdown the
* entire iotlb rather than iterate over individual iovas. * entire iotlb rather than iterate over individual iovas.
*/ */
for (i = 0; i < iommu->num_mmu; i++) for (i = 0; i < iommu->num_mmu; i++) {
for (; iova < iova_end; iova += SPAGE_SIZE) dma_addr_t iova;
for (iova = iova_start; iova < iova_end; iova += SPAGE_SIZE)
rk_iommu_write(iommu->bases[i], RK_MMU_ZAP_ONE_LINE, iova); rk_iommu_write(iommu->bases[i], RK_MMU_ZAP_ONE_LINE, iova);
}
} }
static bool rk_iommu_is_stall_active(struct rk_iommu *iommu) static bool rk_iommu_is_stall_active(struct rk_iommu *iommu)
@ -335,9 +332,21 @@ static bool rk_iommu_is_paging_enabled(struct rk_iommu *iommu)
return enable; return enable;
} }
static bool rk_iommu_is_reset_done(struct rk_iommu *iommu)
{
bool done = true;
int i;
for (i = 0; i < iommu->num_mmu; i++)
done &= rk_iommu_read(iommu->bases[i], RK_MMU_DTE_ADDR) == 0;
return done;
}
static int rk_iommu_enable_stall(struct rk_iommu *iommu) static int rk_iommu_enable_stall(struct rk_iommu *iommu)
{ {
int ret, i; int ret, i;
bool val;
if (rk_iommu_is_stall_active(iommu)) if (rk_iommu_is_stall_active(iommu))
return 0; return 0;
@ -348,7 +357,9 @@ static int rk_iommu_enable_stall(struct rk_iommu *iommu)
rk_iommu_command(iommu, RK_MMU_CMD_ENABLE_STALL); rk_iommu_command(iommu, RK_MMU_CMD_ENABLE_STALL);
ret = rk_wait_for(rk_iommu_is_stall_active(iommu), 1); ret = readx_poll_timeout(rk_iommu_is_stall_active, iommu, val,
val, RK_MMU_POLL_PERIOD_US,
RK_MMU_POLL_TIMEOUT_US);
if (ret) if (ret)
for (i = 0; i < iommu->num_mmu; i++) for (i = 0; i < iommu->num_mmu; i++)
dev_err(iommu->dev, "Enable stall request timed out, status: %#08x\n", dev_err(iommu->dev, "Enable stall request timed out, status: %#08x\n",
@ -360,13 +371,16 @@ static int rk_iommu_enable_stall(struct rk_iommu *iommu)
static int rk_iommu_disable_stall(struct rk_iommu *iommu) static int rk_iommu_disable_stall(struct rk_iommu *iommu)
{ {
int ret, i; int ret, i;
bool val;
if (!rk_iommu_is_stall_active(iommu)) if (!rk_iommu_is_stall_active(iommu))
return 0; return 0;
rk_iommu_command(iommu, RK_MMU_CMD_DISABLE_STALL); rk_iommu_command(iommu, RK_MMU_CMD_DISABLE_STALL);
ret = rk_wait_for(!rk_iommu_is_stall_active(iommu), 1); ret = readx_poll_timeout(rk_iommu_is_stall_active, iommu, val,
!val, RK_MMU_POLL_PERIOD_US,
RK_MMU_POLL_TIMEOUT_US);
if (ret) if (ret)
for (i = 0; i < iommu->num_mmu; i++) for (i = 0; i < iommu->num_mmu; i++)
dev_err(iommu->dev, "Disable stall request timed out, status: %#08x\n", dev_err(iommu->dev, "Disable stall request timed out, status: %#08x\n",
@ -378,13 +392,16 @@ static int rk_iommu_disable_stall(struct rk_iommu *iommu)
static int rk_iommu_enable_paging(struct rk_iommu *iommu) static int rk_iommu_enable_paging(struct rk_iommu *iommu)
{ {
int ret, i; int ret, i;
bool val;
if (rk_iommu_is_paging_enabled(iommu)) if (rk_iommu_is_paging_enabled(iommu))
return 0; return 0;
rk_iommu_command(iommu, RK_MMU_CMD_ENABLE_PAGING); rk_iommu_command(iommu, RK_MMU_CMD_ENABLE_PAGING);
ret = rk_wait_for(rk_iommu_is_paging_enabled(iommu), 1); ret = readx_poll_timeout(rk_iommu_is_paging_enabled, iommu, val,
val, RK_MMU_POLL_PERIOD_US,
RK_MMU_POLL_TIMEOUT_US);
if (ret) if (ret)
for (i = 0; i < iommu->num_mmu; i++) for (i = 0; i < iommu->num_mmu; i++)
dev_err(iommu->dev, "Enable paging request timed out, status: %#08x\n", dev_err(iommu->dev, "Enable paging request timed out, status: %#08x\n",
@ -396,13 +413,16 @@ static int rk_iommu_enable_paging(struct rk_iommu *iommu)
static int rk_iommu_disable_paging(struct rk_iommu *iommu) static int rk_iommu_disable_paging(struct rk_iommu *iommu)
{ {
int ret, i; int ret, i;
bool val;
if (!rk_iommu_is_paging_enabled(iommu)) if (!rk_iommu_is_paging_enabled(iommu))
return 0; return 0;
rk_iommu_command(iommu, RK_MMU_CMD_DISABLE_PAGING); rk_iommu_command(iommu, RK_MMU_CMD_DISABLE_PAGING);
ret = rk_wait_for(!rk_iommu_is_paging_enabled(iommu), 1); ret = readx_poll_timeout(rk_iommu_is_paging_enabled, iommu, val,
!val, RK_MMU_POLL_PERIOD_US,
RK_MMU_POLL_TIMEOUT_US);
if (ret) if (ret)
for (i = 0; i < iommu->num_mmu; i++) for (i = 0; i < iommu->num_mmu; i++)
dev_err(iommu->dev, "Disable paging request timed out, status: %#08x\n", dev_err(iommu->dev, "Disable paging request timed out, status: %#08x\n",
@ -415,6 +435,7 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
{ {
int ret, i; int ret, i;
u32 dte_addr; u32 dte_addr;
bool val;
if (iommu->reset_disabled) if (iommu->reset_disabled)
return 0; return 0;
@ -435,13 +456,12 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
rk_iommu_command(iommu, RK_MMU_CMD_FORCE_RESET); rk_iommu_command(iommu, RK_MMU_CMD_FORCE_RESET);
for (i = 0; i < iommu->num_mmu; i++) { ret = readx_poll_timeout(rk_iommu_is_reset_done, iommu, val,
ret = rk_wait_for(rk_iommu_read(iommu->bases[i], RK_MMU_DTE_ADDR) == 0x00000000, val, RK_MMU_FORCE_RESET_TIMEOUT_US,
FORCE_RESET_TIMEOUT); RK_MMU_POLL_TIMEOUT_US);
if (ret) { if (ret) {
dev_err(iommu->dev, "FORCE_RESET command timed out\n"); dev_err(iommu->dev, "FORCE_RESET command timed out\n");
return ret; return ret;
}
} }
return 0; return 0;
@ -503,6 +523,12 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
int i; int i;
if (WARN_ON(!pm_runtime_get_if_in_use(iommu->dev)))
return 0;
if (WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)))
goto out;
for (i = 0; i < iommu->num_mmu; i++) { for (i = 0; i < iommu->num_mmu; i++) {
int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS); int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS);
if (int_status == 0) if (int_status == 0)
@ -549,6 +575,10 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status); rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status);
} }
clk_bulk_disable(iommu->num_clocks, iommu->clocks);
out:
pm_runtime_put(iommu->dev);
return ret; return ret;
} }
@ -590,8 +620,17 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
spin_lock_irqsave(&rk_domain->iommus_lock, flags); spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_for_each(pos, &rk_domain->iommus) { list_for_each(pos, &rk_domain->iommus) {
struct rk_iommu *iommu; struct rk_iommu *iommu;
iommu = list_entry(pos, struct rk_iommu, node); iommu = list_entry(pos, struct rk_iommu, node);
rk_iommu_zap_lines(iommu, iova, size);
/* Only zap TLBs of IOMMUs that are powered on. */
if (pm_runtime_get_if_in_use(iommu->dev)) {
WARN_ON(clk_bulk_enable(iommu->num_clocks,
iommu->clocks));
rk_iommu_zap_lines(iommu, iova, size);
clk_bulk_disable(iommu->num_clocks, iommu->clocks);
pm_runtime_put(iommu->dev);
}
} }
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags); spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
} }
@ -608,7 +647,6 @@ static void rk_iommu_zap_iova_first_last(struct rk_iommu_domain *rk_domain,
static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain, static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
dma_addr_t iova) dma_addr_t iova)
{ {
struct device *dev = &rk_domain->pdev->dev;
u32 *page_table, *dte_addr; u32 *page_table, *dte_addr;
u32 dte_index, dte; u32 dte_index, dte;
phys_addr_t pt_phys; phys_addr_t pt_phys;
@ -626,9 +664,9 @@ static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
if (!page_table) if (!page_table)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
pt_dma = dma_map_single(dev, page_table, SPAGE_SIZE, DMA_TO_DEVICE); pt_dma = dma_map_single(dma_dev, page_table, SPAGE_SIZE, DMA_TO_DEVICE);
if (dma_mapping_error(dev, pt_dma)) { if (dma_mapping_error(dma_dev, pt_dma)) {
dev_err(dev, "DMA mapping error while allocating page table\n"); dev_err(dma_dev, "DMA mapping error while allocating page table\n");
free_page((unsigned long)page_table); free_page((unsigned long)page_table);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
@ -790,52 +828,46 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
static struct rk_iommu *rk_iommu_from_dev(struct device *dev) static struct rk_iommu *rk_iommu_from_dev(struct device *dev)
{ {
struct iommu_group *group; struct rk_iommudata *data = dev->archdata.iommu;
struct device *iommu_dev;
struct rk_iommu *rk_iommu;
group = iommu_group_get(dev); return data ? data->iommu : NULL;
if (!group)
return NULL;
iommu_dev = iommu_group_get_iommudata(group);
rk_iommu = dev_get_drvdata(iommu_dev);
iommu_group_put(group);
return rk_iommu;
} }
static int rk_iommu_attach_device(struct iommu_domain *domain, /* Must be called with iommu powered on and attached */
struct device *dev) static void rk_iommu_disable(struct rk_iommu *iommu)
{ {
struct rk_iommu *iommu; int i;
/* Ignore error while disabling, just keep going */
WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
rk_iommu_enable_stall(iommu);
rk_iommu_disable_paging(iommu);
for (i = 0; i < iommu->num_mmu; i++) {
rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0);
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0);
}
rk_iommu_disable_stall(iommu);
clk_bulk_disable(iommu->num_clocks, iommu->clocks);
}
/* Must be called with iommu powered on and attached */
static int rk_iommu_enable(struct rk_iommu *iommu)
{
struct iommu_domain *domain = iommu->domain;
struct rk_iommu_domain *rk_domain = to_rk_domain(domain); struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
unsigned long flags;
int ret, i; int ret, i;
/* ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks);
* Allow 'virtual devices' (e.g., drm) to attach to domain. if (ret)
* Such a device does not belong to an iommu group. return ret;
*/
iommu = rk_iommu_from_dev(dev);
if (!iommu)
return 0;
ret = rk_iommu_enable_stall(iommu); ret = rk_iommu_enable_stall(iommu);
if (ret) if (ret)
return ret; goto out_disable_clocks;
ret = rk_iommu_force_reset(iommu); ret = rk_iommu_force_reset(iommu);
if (ret) if (ret)
return ret; goto out_disable_stall;
iommu->domain = domain;
for (i = 0; i < iommu->num_irq; i++) {
ret = devm_request_irq(iommu->dev, iommu->irq[i], rk_iommu_irq,
IRQF_SHARED, dev_name(dev), iommu);
if (ret)
return ret;
}
for (i = 0; i < iommu->num_mmu; i++) { for (i = 0; i < iommu->num_mmu; i++) {
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR,
@ -845,18 +877,12 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
} }
ret = rk_iommu_enable_paging(iommu); ret = rk_iommu_enable_paging(iommu);
if (ret)
return ret;
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_add_tail(&iommu->node, &rk_domain->iommus);
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
dev_dbg(dev, "Attached to iommu domain\n");
out_disable_stall:
rk_iommu_disable_stall(iommu); rk_iommu_disable_stall(iommu);
out_disable_clocks:
return 0; clk_bulk_disable(iommu->num_clocks, iommu->clocks);
return ret;
} }
static void rk_iommu_detach_device(struct iommu_domain *domain, static void rk_iommu_detach_device(struct iommu_domain *domain,
@ -865,60 +891,90 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
struct rk_iommu *iommu; struct rk_iommu *iommu;
struct rk_iommu_domain *rk_domain = to_rk_domain(domain); struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
unsigned long flags; unsigned long flags;
int i;
/* Allow 'virtual devices' (eg drm) to detach from domain */ /* Allow 'virtual devices' (eg drm) to detach from domain */
iommu = rk_iommu_from_dev(dev); iommu = rk_iommu_from_dev(dev);
if (!iommu) if (!iommu)
return; return;
dev_dbg(dev, "Detaching from iommu domain\n");
/* iommu already detached */
if (iommu->domain != domain)
return;
iommu->domain = NULL;
spin_lock_irqsave(&rk_domain->iommus_lock, flags); spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_del_init(&iommu->node); list_del_init(&iommu->node);
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags); spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
/* Ignore error while disabling, just keep going */ if (pm_runtime_get_if_in_use(iommu->dev)) {
rk_iommu_enable_stall(iommu); rk_iommu_disable(iommu);
rk_iommu_disable_paging(iommu); pm_runtime_put(iommu->dev);
for (i = 0; i < iommu->num_mmu; i++) {
rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0);
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0);
} }
rk_iommu_disable_stall(iommu); }
for (i = 0; i < iommu->num_irq; i++) static int rk_iommu_attach_device(struct iommu_domain *domain,
devm_free_irq(iommu->dev, iommu->irq[i], iommu); struct device *dev)
{
struct rk_iommu *iommu;
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
unsigned long flags;
int ret;
iommu->domain = NULL; /*
* Allow 'virtual devices' (e.g., drm) to attach to domain.
* Such a device does not belong to an iommu group.
*/
iommu = rk_iommu_from_dev(dev);
if (!iommu)
return 0;
dev_dbg(dev, "Detached from iommu domain\n"); dev_dbg(dev, "Attaching to iommu domain\n");
/* iommu already attached */
if (iommu->domain == domain)
return 0;
if (iommu->domain)
rk_iommu_detach_device(iommu->domain, dev);
iommu->domain = domain;
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_add_tail(&iommu->node, &rk_domain->iommus);
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
if (!pm_runtime_get_if_in_use(iommu->dev))
return 0;
ret = rk_iommu_enable(iommu);
if (ret)
rk_iommu_detach_device(iommu->domain, dev);
pm_runtime_put(iommu->dev);
return ret;
} }
static struct iommu_domain *rk_iommu_domain_alloc(unsigned type) static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
{ {
struct rk_iommu_domain *rk_domain; struct rk_iommu_domain *rk_domain;
struct platform_device *pdev;
struct device *iommu_dev;
if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
return NULL; return NULL;
/* Register a pdev per domain, so DMA API can base on this *dev if (!dma_dev)
* even some virtual master doesn't have an iommu slave
*/
pdev = platform_device_register_simple("rk_iommu_domain",
PLATFORM_DEVID_AUTO, NULL, 0);
if (IS_ERR(pdev))
return NULL; return NULL;
rk_domain = devm_kzalloc(&pdev->dev, sizeof(*rk_domain), GFP_KERNEL); rk_domain = devm_kzalloc(dma_dev, sizeof(*rk_domain), GFP_KERNEL);
if (!rk_domain) if (!rk_domain)
goto err_unreg_pdev; return NULL;
rk_domain->pdev = pdev;
if (type == IOMMU_DOMAIN_DMA && if (type == IOMMU_DOMAIN_DMA &&
iommu_get_dma_cookie(&rk_domain->domain)) iommu_get_dma_cookie(&rk_domain->domain))
goto err_unreg_pdev; return NULL;
/* /*
* rk32xx iommus use a 2 level pagetable. * rk32xx iommus use a 2 level pagetable.
@ -929,11 +985,10 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
if (!rk_domain->dt) if (!rk_domain->dt)
goto err_put_cookie; goto err_put_cookie;
iommu_dev = &pdev->dev; rk_domain->dt_dma = dma_map_single(dma_dev, rk_domain->dt,
rk_domain->dt_dma = dma_map_single(iommu_dev, rk_domain->dt,
SPAGE_SIZE, DMA_TO_DEVICE); SPAGE_SIZE, DMA_TO_DEVICE);
if (dma_mapping_error(iommu_dev, rk_domain->dt_dma)) { if (dma_mapping_error(dma_dev, rk_domain->dt_dma)) {
dev_err(iommu_dev, "DMA map error for DT\n"); dev_err(dma_dev, "DMA map error for DT\n");
goto err_free_dt; goto err_free_dt;
} }
@ -954,8 +1009,6 @@ err_free_dt:
err_put_cookie: err_put_cookie:
if (type == IOMMU_DOMAIN_DMA) if (type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(&rk_domain->domain); iommu_put_dma_cookie(&rk_domain->domain);
err_unreg_pdev:
platform_device_unregister(pdev);
return NULL; return NULL;
} }
@ -972,128 +1025,84 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
if (rk_dte_is_pt_valid(dte)) { if (rk_dte_is_pt_valid(dte)) {
phys_addr_t pt_phys = rk_dte_pt_address(dte); phys_addr_t pt_phys = rk_dte_pt_address(dte);
u32 *page_table = phys_to_virt(pt_phys); u32 *page_table = phys_to_virt(pt_phys);
dma_unmap_single(&rk_domain->pdev->dev, pt_phys, dma_unmap_single(dma_dev, pt_phys,
SPAGE_SIZE, DMA_TO_DEVICE); SPAGE_SIZE, DMA_TO_DEVICE);
free_page((unsigned long)page_table); free_page((unsigned long)page_table);
} }
} }
dma_unmap_single(&rk_domain->pdev->dev, rk_domain->dt_dma, dma_unmap_single(dma_dev, rk_domain->dt_dma,
SPAGE_SIZE, DMA_TO_DEVICE); SPAGE_SIZE, DMA_TO_DEVICE);
free_page((unsigned long)rk_domain->dt); free_page((unsigned long)rk_domain->dt);
if (domain->type == IOMMU_DOMAIN_DMA) if (domain->type == IOMMU_DOMAIN_DMA)
iommu_put_dma_cookie(&rk_domain->domain); iommu_put_dma_cookie(&rk_domain->domain);
platform_device_unregister(rk_domain->pdev);
}
static bool rk_iommu_is_dev_iommu_master(struct device *dev)
{
struct device_node *np = dev->of_node;
int ret;
/*
* An iommu master has an iommus property containing a list of phandles
* to iommu nodes, each with an #iommu-cells property with value 0.
*/
ret = of_count_phandle_with_args(np, "iommus", "#iommu-cells");
return (ret > 0);
}
static int rk_iommu_group_set_iommudata(struct iommu_group *group,
struct device *dev)
{
struct device_node *np = dev->of_node;
struct platform_device *pd;
int ret;
struct of_phandle_args args;
/*
* An iommu master has an iommus property containing a list of phandles
* to iommu nodes, each with an #iommu-cells property with value 0.
*/
ret = of_parse_phandle_with_args(np, "iommus", "#iommu-cells", 0,
&args);
if (ret) {
dev_err(dev, "of_parse_phandle_with_args(%pOF) => %d\n",
np, ret);
return ret;
}
if (args.args_count != 0) {
dev_err(dev, "incorrect number of iommu params found for %pOF (found %d, expected 0)\n",
args.np, args.args_count);
return -EINVAL;
}
pd = of_find_device_by_node(args.np);
of_node_put(args.np);
if (!pd) {
dev_err(dev, "iommu %pOF not found\n", args.np);
return -EPROBE_DEFER;
}
/* TODO(djkurtz): handle multiple slave iommus for a single master */
iommu_group_set_iommudata(group, &pd->dev, NULL);
return 0;
} }
static int rk_iommu_add_device(struct device *dev) static int rk_iommu_add_device(struct device *dev)
{ {
struct iommu_group *group; struct iommu_group *group;
struct rk_iommu *iommu; struct rk_iommu *iommu;
int ret; struct rk_iommudata *data;
if (!rk_iommu_is_dev_iommu_master(dev)) data = dev->archdata.iommu;
if (!data)
return -ENODEV; return -ENODEV;
group = iommu_group_get(dev);
if (!group) {
group = iommu_group_alloc();
if (IS_ERR(group)) {
dev_err(dev, "Failed to allocate IOMMU group\n");
return PTR_ERR(group);
}
}
ret = iommu_group_add_device(group, dev);
if (ret)
goto err_put_group;
ret = rk_iommu_group_set_iommudata(group, dev);
if (ret)
goto err_remove_device;
iommu = rk_iommu_from_dev(dev); iommu = rk_iommu_from_dev(dev);
if (iommu)
iommu_device_link(&iommu->iommu, dev);
group = iommu_group_get_for_dev(dev);
if (IS_ERR(group))
return PTR_ERR(group);
iommu_group_put(group); iommu_group_put(group);
iommu_device_link(&iommu->iommu, dev);
data->link = device_link_add(dev, iommu->dev, DL_FLAG_PM_RUNTIME);
return 0; return 0;
err_remove_device:
iommu_group_remove_device(dev);
err_put_group:
iommu_group_put(group);
return ret;
} }
static void rk_iommu_remove_device(struct device *dev) static void rk_iommu_remove_device(struct device *dev)
{ {
struct rk_iommu *iommu; struct rk_iommu *iommu;
struct rk_iommudata *data = dev->archdata.iommu;
if (!rk_iommu_is_dev_iommu_master(dev))
return;
iommu = rk_iommu_from_dev(dev); iommu = rk_iommu_from_dev(dev);
if (iommu)
iommu_device_unlink(&iommu->iommu, dev);
device_link_del(data->link);
iommu_device_unlink(&iommu->iommu, dev);
iommu_group_remove_device(dev); iommu_group_remove_device(dev);
} }
static struct iommu_group *rk_iommu_device_group(struct device *dev)
{
struct rk_iommu *iommu;
iommu = rk_iommu_from_dev(dev);
return iommu_group_ref_get(iommu->group);
}
static int rk_iommu_of_xlate(struct device *dev,
struct of_phandle_args *args)
{
struct platform_device *iommu_dev;
struct rk_iommudata *data;
data = devm_kzalloc(dma_dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
iommu_dev = of_find_device_by_node(args->np);
data->iommu = platform_get_drvdata(iommu_dev);
dev->archdata.iommu = data;
of_dev_put(iommu_dev);
return 0;
}
static const struct iommu_ops rk_iommu_ops = { static const struct iommu_ops rk_iommu_ops = {
.domain_alloc = rk_iommu_domain_alloc, .domain_alloc = rk_iommu_domain_alloc,
.domain_free = rk_iommu_domain_free, .domain_free = rk_iommu_domain_free,
@ -1105,31 +1114,9 @@ static const struct iommu_ops rk_iommu_ops = {
.add_device = rk_iommu_add_device, .add_device = rk_iommu_add_device,
.remove_device = rk_iommu_remove_device, .remove_device = rk_iommu_remove_device,
.iova_to_phys = rk_iommu_iova_to_phys, .iova_to_phys = rk_iommu_iova_to_phys,
.device_group = rk_iommu_device_group,
.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP, .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
}; .of_xlate = rk_iommu_of_xlate,
static int rk_iommu_domain_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
if (!dev->dma_parms)
return -ENOMEM;
/* Set dma_ops for dev, otherwise it would be dummy_dma_ops */
arch_setup_dma_ops(dev, 0, DMA_BIT_MASK(32), NULL, false);
dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
return 0;
}
static struct platform_driver rk_iommu_domain_driver = {
.probe = rk_iommu_domain_probe,
.driver = {
.name = "rk_iommu_domain",
},
}; };
static int rk_iommu_probe(struct platform_device *pdev) static int rk_iommu_probe(struct platform_device *pdev)
@ -1138,7 +1125,7 @@ static int rk_iommu_probe(struct platform_device *pdev)
struct rk_iommu *iommu; struct rk_iommu *iommu;
struct resource *res; struct resource *res;
int num_res = pdev->num_resources; int num_res = pdev->num_resources;
int err, i; int err, i, irq;
iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL); iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL);
if (!iommu) if (!iommu)
@ -1165,50 +1152,108 @@ static int rk_iommu_probe(struct platform_device *pdev)
if (iommu->num_mmu == 0) if (iommu->num_mmu == 0)
return PTR_ERR(iommu->bases[0]); return PTR_ERR(iommu->bases[0]);
iommu->num_irq = platform_irq_count(pdev); i = 0;
if (iommu->num_irq < 0) while ((irq = platform_get_irq(pdev, i++)) != -ENXIO) {
return iommu->num_irq; if (irq < 0)
if (iommu->num_irq == 0) return irq;
return -ENXIO;
iommu->irq = devm_kcalloc(dev, iommu->num_irq, sizeof(*iommu->irq), err = devm_request_irq(iommu->dev, irq, rk_iommu_irq,
GFP_KERNEL); IRQF_SHARED, dev_name(dev), iommu);
if (!iommu->irq) if (err)
return -ENOMEM; return err;
for (i = 0; i < iommu->num_irq; i++) {
iommu->irq[i] = platform_get_irq(pdev, i);
if (iommu->irq[i] < 0) {
dev_err(dev, "Failed to get IRQ, %d\n", iommu->irq[i]);
return -ENXIO;
}
} }
iommu->reset_disabled = device_property_read_bool(dev, iommu->reset_disabled = device_property_read_bool(dev,
"rockchip,disable-mmu-reset"); "rockchip,disable-mmu-reset");
err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev)); iommu->num_clocks = ARRAY_SIZE(rk_iommu_clocks);
iommu->clocks = devm_kcalloc(iommu->dev, iommu->num_clocks,
sizeof(*iommu->clocks), GFP_KERNEL);
if (!iommu->clocks)
return -ENOMEM;
for (i = 0; i < iommu->num_clocks; ++i)
iommu->clocks[i].id = rk_iommu_clocks[i];
err = devm_clk_bulk_get(iommu->dev, iommu->num_clocks, iommu->clocks);
if (err) if (err)
return err; return err;
iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops); err = clk_bulk_prepare(iommu->num_clocks, iommu->clocks);
err = iommu_device_register(&iommu->iommu); if (err)
return err;
iommu->group = iommu_group_alloc();
if (IS_ERR(iommu->group)) {
err = PTR_ERR(iommu->group);
goto err_unprepare_clocks;
}
err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev));
if (err)
goto err_put_group;
iommu_device_set_ops(&iommu->iommu, &rk_iommu_ops);
iommu_device_set_fwnode(&iommu->iommu, &dev->of_node->fwnode);
err = iommu_device_register(&iommu->iommu);
if (err)
goto err_remove_sysfs;
/*
* Use the first registered IOMMU device for domain to use with DMA
* API, since a domain might not physically correspond to a single
* IOMMU device..
*/
if (!dma_dev)
dma_dev = &pdev->dev;
bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
pm_runtime_enable(dev);
return 0;
err_remove_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
err_put_group:
iommu_group_put(iommu->group);
err_unprepare_clocks:
clk_bulk_unprepare(iommu->num_clocks, iommu->clocks);
return err; return err;
} }
static int rk_iommu_remove(struct platform_device *pdev) static void rk_iommu_shutdown(struct platform_device *pdev)
{ {
struct rk_iommu *iommu = platform_get_drvdata(pdev); pm_runtime_force_suspend(&pdev->dev);
}
if (iommu) { static int __maybe_unused rk_iommu_suspend(struct device *dev)
iommu_device_sysfs_remove(&iommu->iommu); {
iommu_device_unregister(&iommu->iommu); struct rk_iommu *iommu = dev_get_drvdata(dev);
}
if (!iommu->domain)
return 0;
rk_iommu_disable(iommu);
return 0; return 0;
} }
static int __maybe_unused rk_iommu_resume(struct device *dev)
{
struct rk_iommu *iommu = dev_get_drvdata(dev);
if (!iommu->domain)
return 0;
return rk_iommu_enable(iommu);
}
static const struct dev_pm_ops rk_iommu_pm_ops = {
SET_RUNTIME_PM_OPS(rk_iommu_suspend, rk_iommu_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static const struct of_device_id rk_iommu_dt_ids[] = { static const struct of_device_id rk_iommu_dt_ids[] = {
{ .compatible = "rockchip,iommu" }, { .compatible = "rockchip,iommu" },
{ /* sentinel */ } { /* sentinel */ }
@ -1217,45 +1262,22 @@ MODULE_DEVICE_TABLE(of, rk_iommu_dt_ids);
static struct platform_driver rk_iommu_driver = { static struct platform_driver rk_iommu_driver = {
.probe = rk_iommu_probe, .probe = rk_iommu_probe,
.remove = rk_iommu_remove, .shutdown = rk_iommu_shutdown,
.driver = { .driver = {
.name = "rk_iommu", .name = "rk_iommu",
.of_match_table = rk_iommu_dt_ids, .of_match_table = rk_iommu_dt_ids,
.pm = &rk_iommu_pm_ops,
.suppress_bind_attrs = true,
}, },
}; };
static int __init rk_iommu_init(void) static int __init rk_iommu_init(void)
{ {
struct device_node *np; return platform_driver_register(&rk_iommu_driver);
int ret;
np = of_find_matching_node(NULL, rk_iommu_dt_ids);
if (!np)
return 0;
of_node_put(np);
ret = bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
if (ret)
return ret;
ret = platform_driver_register(&rk_iommu_domain_driver);
if (ret)
return ret;
ret = platform_driver_register(&rk_iommu_driver);
if (ret)
platform_driver_unregister(&rk_iommu_domain_driver);
return ret;
} }
static void __exit rk_iommu_exit(void)
{
platform_driver_unregister(&rk_iommu_driver);
platform_driver_unregister(&rk_iommu_domain_driver);
}
subsys_initcall(rk_iommu_init); subsys_initcall(rk_iommu_init);
module_exit(rk_iommu_exit);
IOMMU_OF_DECLARE(rk_iommu_of, "rockchip,iommu");
MODULE_DESCRIPTION("IOMMU API for Rockchip"); MODULE_DESCRIPTION("IOMMU API for Rockchip");
MODULE_AUTHOR("Simon Xue <xxm@rock-chips.com> and Daniel Kurtz <djkurtz@chromium.org>"); MODULE_AUTHOR("Simon Xue <xxm@rock-chips.com> and Daniel Kurtz <djkurtz@chromium.org>");

View File

@ -3612,7 +3612,8 @@ static int __init gic_acpi_parse_madt_its(struct acpi_subtable_header *header,
return -ENOMEM; return -ENOMEM;
} }
err = iort_register_domain_token(its_entry->translation_id, dom_handle); err = iort_register_domain_token(its_entry->translation_id, res.start,
dom_handle);
if (err) { if (err) {
pr_err("ITS@%pa: Unable to register GICv3 ITS domain token (ITS ID %d) to IORT\n", pr_err("ITS@%pa: Unable to register GICv3 ITS domain token (ITS ID %d) to IORT\n",
&res.start, its_entry->translation_id); &res.start, its_entry->translation_id);

View File

@ -26,7 +26,8 @@
#define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL) #define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL)
#define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL) #define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL)
int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node); int iort_register_domain_token(int trans_id, phys_addr_t base,
struct fwnode_handle *fw_node);
void iort_deregister_domain_token(int trans_id); void iort_deregister_domain_token(int trans_id);
struct fwnode_handle *iort_find_domain_token(int trans_id); struct fwnode_handle *iort_find_domain_token(int trans_id);
#ifdef CONFIG_ACPI_IORT #ifdef CONFIG_ACPI_IORT
@ -38,6 +39,7 @@ int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
/* IOMMU interface */ /* IOMMU interface */
void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *size); void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *size);
const struct iommu_ops *iort_iommu_configure(struct device *dev); const struct iommu_ops *iort_iommu_configure(struct device *dev);
int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head);
#else #else
static inline void acpi_iort_init(void) { } static inline void acpi_iort_init(void) { }
static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id) static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
@ -52,6 +54,9 @@ static inline void iort_dma_setup(struct device *dev, u64 *dma_addr,
static inline const struct iommu_ops *iort_iommu_configure( static inline const struct iommu_ops *iort_iommu_configure(
struct device *dev) struct device *dev)
{ return NULL; } { return NULL; }
static inline
int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
{ return 0; }
#endif #endif
#endif /* __ACPI_IORT_H__ */ #endif /* __ACPI_IORT_H__ */

View File

@ -209,12 +209,12 @@
#define DMA_FECTL_IM (((u32)1) << 31) #define DMA_FECTL_IM (((u32)1) << 31)
/* FSTS_REG */ /* FSTS_REG */
#define DMA_FSTS_PPF ((u32)2) #define DMA_FSTS_PFO (1 << 0) /* Primary Fault Overflow */
#define DMA_FSTS_PFO ((u32)1) #define DMA_FSTS_PPF (1 << 1) /* Primary Pending Fault */
#define DMA_FSTS_IQE (1 << 4) #define DMA_FSTS_IQE (1 << 4) /* Invalidation Queue Error */
#define DMA_FSTS_ICE (1 << 5) #define DMA_FSTS_ICE (1 << 5) /* Invalidation Completion Error */
#define DMA_FSTS_ITE (1 << 6) #define DMA_FSTS_ITE (1 << 6) /* Invalidation Time-out Error */
#define DMA_FSTS_PRO (1 << 7) #define DMA_FSTS_PRO (1 << 7) /* Page Request Overflow */
#define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff) #define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff)
/* FRCD_REG, 32 bits access */ /* FRCD_REG, 32 bits access */

View File

@ -465,23 +465,23 @@ static inline int iommu_map(struct iommu_domain *domain, unsigned long iova,
return -ENODEV; return -ENODEV;
} }
static inline int iommu_unmap(struct iommu_domain *domain, unsigned long iova, static inline size_t iommu_unmap(struct iommu_domain *domain,
size_t size) unsigned long iova, size_t size)
{ {
return -ENODEV; return 0;
} }
static inline int iommu_unmap_fast(struct iommu_domain *domain, unsigned long iova, static inline size_t iommu_unmap_fast(struct iommu_domain *domain,
int gfp_order) unsigned long iova, int gfp_order)
{ {
return -ENODEV; return 0;
} }
static inline size_t iommu_map_sg(struct iommu_domain *domain, static inline size_t iommu_map_sg(struct iommu_domain *domain,
unsigned long iova, struct scatterlist *sg, unsigned long iova, struct scatterlist *sg,
unsigned int nents, int prot) unsigned int nents, int prot)
{ {
return -ENODEV; return 0;
} }
static inline void iommu_flush_tlb_all(struct iommu_domain *domain) static inline void iommu_flush_tlb_all(struct iommu_domain *domain)