Commit f8d5e706 authored by Will Deacon's avatar Will Deacon
Browse files

Merge branches 'fixes', 'arm/smmu/updates', 'arm/smmu/bindings', 'riscv',...

Merge branches 'fixes', 'arm/smmu/updates', 'arm/smmu/bindings', 'riscv', 'intel/vt-d', 'amd/amd-vi' and 'core' into next
Loading
+7 −1
Original line number Diff line number Diff line
@@ -207,8 +207,14 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM            | MMU-600         | #1076982,1209401| N/A                         |
+----------------+-----------------+-----------------+-----------------------------+
| ARM            | MMU-700         | #2268618,2812531| N/A                         |
| ARM            | MMU-700         | #2133013,       | N/A                         |
|                |                 | #2268618,       |                             |
|                |                 | #2812531,       |                             |
|                |                 | #3777127        |                             |
+----------------+-----------------+-----------------+-----------------------------+
| ARM            | MMU L1          | #3878312        | N/A                         |
+----------------+-----------------+-----------------+-----------------------------+
| ARM            | MMU S3          | #3995052        | N/A                         |
+----------------+-----------------+-----------------+-----------------------------+
| ARM            | GIC-700         | #2941627        | ARM64_ERRATUM_2941627       |
+----------------+-----------------+-----------------+-----------------------------+
+2 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ properties:
      - description: Qcom SoCs implementing "qcom,smmu-500" and "arm,mmu-500"
        items:
          - enum:
              - qcom,eliza-smmu-500
              - qcom,glymur-smmu-500
              - qcom,kaanapali-smmu-500
              - qcom,milos-smmu-500
@@ -92,6 +93,7 @@ properties:
        items:
          - enum:
              - qcom,glymur-smmu-500
              - qcom,hawi-smmu-500
              - qcom,kaanapali-smmu-500
              - qcom,milos-smmu-500
              - qcom,qcm2290-smmu-500
+31 −32
Original line number Diff line number Diff line
@@ -26,22 +26,19 @@ static ssize_t iommu_mmio_write(struct file *filp, const char __user *ubuf,
{
	struct seq_file *m = filp->private_data;
	struct amd_iommu *iommu = m->private;
	int ret;

	iommu->dbg_mmio_offset = -1;
	int ret, dbg_mmio_offset = iommu->dbg_mmio_offset = -1;

	if (cnt > OFS_IN_SZ)
		return -EINVAL;

	ret = kstrtou32_from_user(ubuf, cnt, 0, &iommu->dbg_mmio_offset);
	ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_mmio_offset);
	if (ret)
		return ret;

	if (iommu->dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64)) {
		iommu->dbg_mmio_offset = -1;
	if (dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64))
		return -EINVAL;
	}

	iommu->dbg_mmio_offset = dbg_mmio_offset;
	return cnt;
}

@@ -49,14 +46,16 @@ static int iommu_mmio_show(struct seq_file *m, void *unused)
{
	struct amd_iommu *iommu = m->private;
	u64 value;
	int dbg_mmio_offset = iommu->dbg_mmio_offset;

	if (iommu->dbg_mmio_offset < 0) {
	if (dbg_mmio_offset < 0 || dbg_mmio_offset >
			iommu->mmio_phys_end - sizeof(u64)) {
		seq_puts(m, "Please provide mmio register's offset\n");
		return 0;
	}

	value = readq(iommu->mmio_base + iommu->dbg_mmio_offset);
	seq_printf(m, "Offset:0x%x Value:0x%016llx\n", iommu->dbg_mmio_offset, value);
	value = readq(iommu->mmio_base + dbg_mmio_offset);
	seq_printf(m, "Offset:0x%x Value:0x%016llx\n", dbg_mmio_offset, value);

	return 0;
}
@@ -67,23 +66,20 @@ static ssize_t iommu_capability_write(struct file *filp, const char __user *ubuf
{
	struct seq_file *m = filp->private_data;
	struct amd_iommu *iommu = m->private;
	int ret;

	iommu->dbg_cap_offset = -1;
	int ret, dbg_cap_offset = iommu->dbg_cap_offset = -1;

	if (cnt > OFS_IN_SZ)
		return -EINVAL;

	ret = kstrtou32_from_user(ubuf, cnt, 0, &iommu->dbg_cap_offset);
	ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_cap_offset);
	if (ret)
		return ret;

	/* Capability register at offset 0x14 is the last IOMMU capability register. */
	if (iommu->dbg_cap_offset > 0x14) {
		iommu->dbg_cap_offset = -1;
	if (dbg_cap_offset > 0x14)
		return -EINVAL;
	}

	iommu->dbg_cap_offset = dbg_cap_offset;
	return cnt;
}

@@ -91,21 +87,21 @@ static int iommu_capability_show(struct seq_file *m, void *unused)
{
	struct amd_iommu *iommu = m->private;
	u32 value;
	int err;
	int err, dbg_cap_offset = iommu->dbg_cap_offset;

	if (iommu->dbg_cap_offset < 0) {
	if (dbg_cap_offset < 0 || dbg_cap_offset > 0x14) {
		seq_puts(m, "Please provide capability register's offset in the range [0x00 - 0x14]\n");
		return 0;
	}

	err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + iommu->dbg_cap_offset, &value);
	err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + dbg_cap_offset, &value);
	if (err) {
		seq_printf(m, "Not able to read capability register at 0x%x\n",
			   iommu->dbg_cap_offset);
			   dbg_cap_offset);
		return 0;
	}

	seq_printf(m, "Offset:0x%x Value:0x%08x\n", iommu->dbg_cap_offset, value);
	seq_printf(m, "Offset:0x%x Value:0x%08x\n", dbg_cap_offset, value);

	return 0;
}
@@ -197,10 +193,11 @@ static ssize_t devid_write(struct file *filp, const char __user *ubuf,
static int devid_show(struct seq_file *m, void *unused)
{
	u16 devid;
	int sbdf_shadow = sbdf;

	if (sbdf >= 0) {
		devid = PCI_SBDF_TO_DEVID(sbdf);
		seq_printf(m, "%04x:%02x:%02x.%x\n", PCI_SBDF_TO_SEGID(sbdf),
	if (sbdf_shadow >= 0) {
		devid = PCI_SBDF_TO_DEVID(sbdf_shadow);
		seq_printf(m, "%04x:%02x:%02x.%x\n", PCI_SBDF_TO_SEGID(sbdf_shadow),
			   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid));
	} else
		seq_puts(m, "No or Invalid input provided\n");
@@ -237,13 +234,14 @@ static int iommu_devtbl_show(struct seq_file *m, void *unused)
{
	struct amd_iommu_pci_seg *pci_seg;
	u16 seg, devid;
	int sbdf_shadow = sbdf;

	if (sbdf < 0) {
	if (sbdf_shadow < 0) {
		seq_puts(m, "Enter a valid device ID to 'devid' file\n");
		return 0;
	}
	seg = PCI_SBDF_TO_SEGID(sbdf);
	devid = PCI_SBDF_TO_DEVID(sbdf);
	seg = PCI_SBDF_TO_SEGID(sbdf_shadow);
	devid = PCI_SBDF_TO_DEVID(sbdf_shadow);

	for_each_pci_segment(pci_seg) {
		if (pci_seg->id != seg)
@@ -336,19 +334,20 @@ static int iommu_irqtbl_show(struct seq_file *m, void *unused)
{
	struct amd_iommu_pci_seg *pci_seg;
	u16 devid, seg;
	int sbdf_shadow = sbdf;

	if (!irq_remapping_enabled) {
		seq_puts(m, "Interrupt remapping is disabled\n");
		return 0;
	}

	if (sbdf < 0) {
	if (sbdf_shadow < 0) {
		seq_puts(m, "Enter a valid device ID to 'devid' file\n");
		return 0;
	}

	seg = PCI_SBDF_TO_SEGID(sbdf);
	devid = PCI_SBDF_TO_DEVID(sbdf);
	seg = PCI_SBDF_TO_SEGID(sbdf_shadow);
	devid = PCI_SBDF_TO_DEVID(sbdf_shadow);

	for_each_pci_segment(pci_seg) {
		if (pci_seg->id != seg)
+6 −3
Original line number Diff line number Diff line
@@ -848,10 +848,11 @@ static void __init free_command_buffer(struct amd_iommu *iommu)
void *__init iommu_alloc_4k_pages(struct amd_iommu *iommu, gfp_t gfp,
				  size_t size)
{
	int nid = iommu->dev ? dev_to_node(&iommu->dev->dev) : NUMA_NO_NODE;
	void *buf;

	size = PAGE_ALIGN(size);
	buf = iommu_alloc_pages_sz(gfp, size);
	buf = iommu_alloc_pages_node_sz(nid, gfp, size);
	if (!buf)
		return NULL;
	if (check_feature(FEATURE_SNP) &&
@@ -954,14 +955,16 @@ static int iommu_ga_log_enable(struct amd_iommu *iommu)

static int iommu_init_ga_log(struct amd_iommu *iommu)
{
	int nid = iommu->dev ? dev_to_node(&iommu->dev->dev) : NUMA_NO_NODE;

	if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))
		return 0;

	iommu->ga_log = iommu_alloc_pages_sz(GFP_KERNEL, GA_LOG_SIZE);
	iommu->ga_log = iommu_alloc_pages_node_sz(nid, GFP_KERNEL, GA_LOG_SIZE);
	if (!iommu->ga_log)
		goto err_out;

	iommu->ga_log_tail = iommu_alloc_pages_sz(GFP_KERNEL, 8);
	iommu->ga_log_tail = iommu_alloc_pages_node_sz(nid, GFP_KERNEL, 8);
	if (!iommu->ga_log_tail)
		goto err_out;

+33 −10
Original line number Diff line number Diff line
@@ -403,11 +403,12 @@ struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 devid)
	return NULL;
}

static int clone_alias(struct pci_dev *pdev, u16 alias, void *data)
static int clone_alias(struct pci_dev *pdev_origin, u16 alias, void *data)
{
	struct dev_table_entry new;
	struct amd_iommu *iommu;
	struct iommu_dev_data *dev_data, *alias_data;
	struct pci_dev *pdev = data;
	u16 devid = pci_dev_id(pdev);
	int ret = 0;

@@ -454,9 +455,9 @@ static void clone_aliases(struct amd_iommu *iommu, struct device *dev)
	 * part of the PCI DMA aliases if it's bus differs
	 * from the original device.
	 */
	clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], NULL);
	clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], pdev);

	pci_for_each_dma_alias(pdev, clone_alias, NULL);
	pci_for_each_dma_alias(pdev, clone_alias, pdev);
}

static void setup_aliases(struct amd_iommu *iommu, struct device *dev)
@@ -2991,13 +2992,17 @@ static bool amd_iommu_capable(struct device *dev, enum iommu_cap cap)
		return amdr_ivrs_remap_support;
	case IOMMU_CAP_ENFORCE_CACHE_COHERENCY:
		return true;
	case IOMMU_CAP_DEFERRED_FLUSH:
		return true;
	case IOMMU_CAP_DIRTY_TRACKING: {
		struct amd_iommu *iommu = get_amd_iommu_from_dev(dev);

		return amd_iommu_hd_support(iommu);
	}
	case IOMMU_CAP_PCI_ATS_SUPPORTED: {
		struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev);

		return amd_iommu_iotlb_sup &&
			 (dev_data->flags & AMD_IOMMU_DEVICE_FLAG_ATS_SUP);
	}
	default:
		break;
	}
@@ -3179,26 +3184,44 @@ const struct iommu_ops amd_iommu_ops = {
static struct irq_chip amd_ir_chip;
static DEFINE_SPINLOCK(iommu_table_lock);

static int iommu_flush_dev_irt(struct pci_dev *unused, u16 devid, void *data)
{
	int ret;
	struct iommu_cmd cmd;
	struct amd_iommu *iommu = data;

	build_inv_irt(&cmd, devid);
	ret = __iommu_queue_command_sync(iommu, &cmd, true);
	return ret;
}

static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid)
{
	int ret;
	u64 data;
	unsigned long flags;
	struct iommu_cmd cmd, cmd2;
	struct iommu_cmd cmd;
	struct pci_dev *pdev = NULL;
	struct iommu_dev_data *dev_data = search_dev_data(iommu, devid);

	if (iommu->irtcachedis_enabled)
		return;

	build_inv_irt(&cmd, devid);
	if (dev_data && dev_data->dev && dev_is_pci(dev_data->dev))
		pdev = to_pci_dev(dev_data->dev);

	raw_spin_lock_irqsave(&iommu->lock, flags);
	data = get_cmdsem_val(iommu);
	build_completion_wait(&cmd2, iommu, data);
	build_completion_wait(&cmd, iommu, data);

	ret = __iommu_queue_command_sync(iommu, &cmd, true);
	if (pdev)
		ret = pci_for_each_dma_alias(pdev, iommu_flush_dev_irt, iommu);
	else
		ret = iommu_flush_dev_irt(NULL, devid, iommu);
	if (ret)
		goto out_err;
	ret = __iommu_queue_command_sync(iommu, &cmd2, false);

	ret = __iommu_queue_command_sync(iommu, &cmd, false);
	if (ret)
		goto out_err;
	raw_spin_unlock_irqrestore(&iommu->lock, flags);
Loading