1 // SPDX-License-Identifier: GPL-2.0-only
4 * Copyright © 2022-2024 Rivos Inc.
5 * Copyright © 2023 FORTH-ICS/CARV
7 * RISCV IOMMU as a PCIe device
10 * Tomasz Jeznach <tjeznach@rivosinc.com>
11 * Nick Kossifidis <mick@ics.forth.gr>
14 #include <linux/compiler.h>
15 #include <linux/init.h>
16 #include <linux/iommu.h>
17 #include <linux/kernel.h>
18 #include <linux/pci.h>
20 #include "iommu-bits.h"
23 /* QEMU RISC-V IOMMU implementation */
24 #define PCI_DEVICE_ID_REDHAT_RISCV_IOMMU 0x0014
26 /* Rivos Inc. assigned PCI Vendor and Device IDs */
27 #ifndef PCI_VENDOR_ID_RIVOS
28 #define PCI_VENDOR_ID_RIVOS 0x1efd
31 #define PCI_DEVICE_ID_RIVOS_RISCV_IOMMU_GA 0x0008
33 static int riscv_iommu_pci_probe(struct pci_dev
*pdev
, const struct pci_device_id
*ent
)
35 struct device
*dev
= &pdev
->dev
;
36 struct riscv_iommu_device
*iommu
;
39 rc
= pcim_enable_device(pdev
);
43 if (!(pci_resource_flags(pdev
, 0) & IORESOURCE_MEM
))
46 if (pci_resource_len(pdev
, 0) < RISCV_IOMMU_REG_SIZE
)
49 rc
= pcim_iomap_regions(pdev
, BIT(0), pci_name(pdev
));
51 return dev_err_probe(dev
, rc
, "pcim_iomap_regions failed\n");
53 iommu
= devm_kzalloc(dev
, sizeof(*iommu
), GFP_KERNEL
);
58 iommu
->reg
= pcim_iomap_table(pdev
)[0];
61 dev_set_drvdata(dev
, iommu
);
63 /* Check device reported capabilities / features. */
64 iommu
->caps
= riscv_iommu_readq(iommu
, RISCV_IOMMU_REG_CAPABILITIES
);
65 iommu
->fctl
= riscv_iommu_readl(iommu
, RISCV_IOMMU_REG_FCTL
);
67 /* The PCI driver only uses MSIs, make sure the IOMMU supports this */
68 switch (FIELD_GET(RISCV_IOMMU_CAPABILITIES_IGS
, iommu
->caps
)) {
69 case RISCV_IOMMU_CAPABILITIES_IGS_MSI
:
70 case RISCV_IOMMU_CAPABILITIES_IGS_BOTH
:
73 return dev_err_probe(dev
, -ENODEV
,
74 "unable to use message-signaled interrupts\n");
77 /* Allocate and assign IRQ vectors for the various events */
78 rc
= pci_alloc_irq_vectors(pdev
, 1, RISCV_IOMMU_INTR_COUNT
,
79 PCI_IRQ_MSIX
| PCI_IRQ_MSI
);
81 return dev_err_probe(dev
, -ENODEV
,
82 "unable to allocate irq vectors\n");
84 iommu
->irqs_count
= rc
;
85 for (vec
= 0; vec
< iommu
->irqs_count
; vec
++)
86 iommu
->irqs
[vec
] = msi_get_virq(dev
, vec
);
88 /* Enable message-signaled interrupts, fctl.WSI */
89 if (iommu
->fctl
& RISCV_IOMMU_FCTL_WSI
) {
90 iommu
->fctl
^= RISCV_IOMMU_FCTL_WSI
;
91 riscv_iommu_writel(iommu
, RISCV_IOMMU_REG_FCTL
, iommu
->fctl
);
94 return riscv_iommu_init(iommu
);
97 static void riscv_iommu_pci_remove(struct pci_dev
*pdev
)
99 struct riscv_iommu_device
*iommu
= dev_get_drvdata(&pdev
->dev
);
101 riscv_iommu_remove(iommu
);
104 static const struct pci_device_id riscv_iommu_pci_tbl
[] = {
105 {PCI_VDEVICE(REDHAT
, PCI_DEVICE_ID_REDHAT_RISCV_IOMMU
), 0},
106 {PCI_VDEVICE(RIVOS
, PCI_DEVICE_ID_RIVOS_RISCV_IOMMU_GA
), 0},
110 static struct pci_driver riscv_iommu_pci_driver
= {
111 .name
= KBUILD_MODNAME
,
112 .id_table
= riscv_iommu_pci_tbl
,
113 .probe
= riscv_iommu_pci_probe
,
114 .remove
= riscv_iommu_pci_remove
,
116 .suppress_bind_attrs
= true,
120 builtin_pci_driver(riscv_iommu_pci_driver
);