FILE
iommu-pci.c
File preview with syntax highlighting.
linux-6.19.14/drivers/iommu/riscv/iommu-pci.c
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 33static 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 97static 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 104static void riscv_iommu_pci_shutdown(struct pci_dev *pdev) 105{ 106 struct riscv_iommu_device *iommu = dev_get_drvdata(&pdev->dev); 107 108 riscv_iommu_disable(iommu); 109} 110 111static const struct pci_device_id riscv_iommu_pci_tbl[] = { 112 {PCI_VDEVICE(REDHAT, PCI_DEVICE_ID_REDHAT_RISCV_IOMMU), 0}, 113 {PCI_VDEVICE(RIVOS, PCI_DEVICE_ID_RIVOS_RISCV_IOMMU_GA), 0}, 114 {0,} 115}; 116 117static struct pci_driver riscv_iommu_pci_driver = { 118 .name = KBUILD_MODNAME, 119 .id_table = riscv_iommu_pci_tbl, 120 .probe = riscv_iommu_pci_probe, 121 .remove = riscv_iommu_pci_remove, 122 .shutdown = riscv_iommu_pci_shutdown, 123 .driver = { 124 .suppress_bind_attrs = true, 125 }, 126}; 127 128builtin_pci_driver(riscv_iommu_pci_driver);
~/
Read-only file preview.