1 // SPDX-License-Identifier: GPL-2.0-only 2 3 /* 4 * Copyright © 2022-2024 Rivos Inc. 5 * Copyright © 2023 FORTH-ICS/CARV 6 * 7 * RISCV IOMMU as a PCIe device 8 * 9 * Authors 10 * Tomasz Jeznach <tjeznach@rivosinc.com> 11 * Nick Kossifidis <mick@ics.forth.gr> 12 */ 13 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> 19 20 #include "iommu-bits.h" 21 #include "iommu.h" 22 23 /* QEMU RISC-V IOMMU implementation */ 24 #define PCI_DEVICE_ID_REDHAT_RISCV_IOMMU 0x0014 25 26 /* Rivos Inc. assigned PCI Vendor and Device IDs */ 27 #ifndef PCI_VENDOR_ID_RIVOS 28 #define PCI_VENDOR_ID_RIVOS 0x1efd 29 #endif 30 31 #define PCI_DEVICE_ID_RIVOS_RISCV_IOMMU_GA 0x0008 32 33 static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 34 { 35 struct device *dev = &pdev->dev; 36 struct riscv_iommu_device *iommu; 37 int rc, vec; 38 39 rc = pcim_enable_device(pdev); 40 if (rc) 41 return rc; 42 43 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) 44 return -ENODEV; 45 46 if (pci_resource_len(pdev, 0) < RISCV_IOMMU_REG_SIZE) 47 return -ENODEV; 48 49 rc = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); 50 if (rc) 51 return dev_err_probe(dev, rc, "pcim_iomap_regions failed\n"); 52 53 iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL); 54 if (!iommu) 55 return -ENOMEM; 56 57 iommu->dev = dev; 58 iommu->reg = pcim_iomap_table(pdev)[0]; 59 60 pci_set_master(pdev); 61 dev_set_drvdata(dev, iommu); 62 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); 66 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: 71 break; 72 default: 73 return dev_err_probe(dev, -ENODEV, 74 "unable to use message-signaled interrupts\n"); 75 } 76 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); 80 if (rc <= 0) 81 return dev_err_probe(dev, -ENODEV, 82 "unable to allocate irq vectors\n"); 83 84 iommu->irqs_count = rc; 85 for (vec = 0; vec < iommu->irqs_count; vec++) 86 iommu->irqs[vec] = msi_get_virq(dev, vec); 87 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); 92 } 93 94 return riscv_iommu_init(iommu); 95 } 96 97 static void riscv_iommu_pci_remove(struct pci_dev *pdev) 98 { 99 struct riscv_iommu_device *iommu = dev_get_drvdata(&pdev->dev); 100 101 riscv_iommu_remove(iommu); 102 } 103 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}, 107 {0,} 108 }; 109 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, 115 .driver = { 116 .suppress_bind_attrs = true, 117 }, 118 }; 119 120 builtin_pci_driver(riscv_iommu_pci_driver); 121