File Index
Files and directories
Sign in
FILE

iommu-pci.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iommu/riscv/iommu-pci.c 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.