xref: /linux/drivers/uio/uio_pci_generic_sva.c (revision 83bd89291f5cc866f60d32c34e268896c7ba8a3d)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * UIO PCI Express sva driver
4  *
5  * Copyright (c) 2025 Beijing Institute of Open Source Chip (BOSC)
6  */
7 
8 #include <linux/device.h>
9 #include <linux/module.h>
10 #include <linux/pci.h>
11 #include <linux/uio_driver.h>
12 #include <linux/iommu.h>
13 
14 struct uio_pci_sva_dev {
15 	struct pci_dev *pdev;
16 	struct uio_info info;
17 	struct iommu_sva *sva_handle;
18 	int pasid;
19 };
20 
irq_handler(int irq,struct uio_info * dev_info)21 static irqreturn_t irq_handler(int irq, struct uio_info *dev_info)
22 {
23 	return IRQ_HANDLED;
24 }
25 
uio_pci_sva_open(struct uio_info * info,struct inode * inode)26 static int uio_pci_sva_open(struct uio_info *info, struct inode *inode)
27 {
28 	struct iommu_sva *handle;
29 	struct uio_pci_sva_dev *udev = info->priv;
30 	struct iommu_domain *domain;
31 
32 	if (!udev && !udev->pdev)
33 		return -ENODEV;
34 
35 	domain = iommu_get_domain_for_dev(&udev->pdev->dev);
36 	if (domain)
37 		iommu_detach_device(domain, &udev->pdev->dev);
38 
39 	handle = iommu_sva_bind_device(&udev->pdev->dev, current->mm);
40 	if (IS_ERR(handle))
41 		return -EINVAL;
42 
43 	udev->pasid = iommu_sva_get_pasid(handle);
44 
45 	udev->sva_handle = handle;
46 
47 	return 0;
48 }
49 
uio_pci_sva_release(struct uio_info * info,struct inode * inode)50 static int uio_pci_sva_release(struct uio_info *info, struct inode *inode)
51 {
52 	struct uio_pci_sva_dev *udev = info->priv;
53 
54 	if (!udev && !udev->pdev)
55 		return -ENODEV;
56 
57 	iommu_sva_unbind_device(udev->sva_handle);
58 
59 	return 0;
60 }
61 
probe(struct pci_dev * pdev,const struct pci_device_id * id)62 static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
63 {
64 	struct uio_pci_sva_dev *udev;
65 	int ret, i, irq = 0;
66 
67 	ret = pci_enable_device(pdev);
68 	if (ret) {
69 		dev_err(&pdev->dev, "pci_enable_device failed: %d\n", ret);
70 		return ret;
71 	}
72 
73 	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
74 	if (ret)
75 		goto out_disable;
76 
77 	pci_set_master(pdev);
78 
79 	ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX | PCI_IRQ_MSI);
80 	if (ret > 0) {
81 		irq = pci_irq_vector(pdev, 0);
82 		if (irq < 0) {
83 			dev_err(&pdev->dev, "Failed to get MSI vector\n");
84 			ret = irq;
85 			goto out_disable;
86 		}
87 	} else
88 		dev_warn(&pdev->dev,
89 			 "No IRQ vectors available (%d), using polling\n", ret);
90 
91 	udev = devm_kzalloc(&pdev->dev, sizeof(struct uio_pci_sva_dev),
92 			    GFP_KERNEL);
93 	if (!udev) {
94 		ret =  -ENOMEM;
95 		goto out_disable;
96 	}
97 
98 	udev->pdev = pdev;
99 	udev->info.name = "uio_pci_sva";
100 	udev->info.version = "0.0.1";
101 	udev->info.open = uio_pci_sva_open;
102 	udev->info.release = uio_pci_sva_release;
103 	udev->info.irq = irq;
104 	udev->info.handler = irq_handler;
105 	udev->info.priv = udev;
106 
107 	for (i = 0; i < MAX_UIO_MAPS; i++) {
108 		struct resource *r = &pdev->resource[i];
109 		struct uio_mem *uiomem = &udev->info.mem[i];
110 
111 		if (r->flags != (IORESOURCE_SIZEALIGN | IORESOURCE_MEM))
112 			continue;
113 
114 		if (uiomem >= &udev->info.mem[MAX_UIO_MAPS]) {
115 			dev_warn(&pdev->dev, "Do not support more than %d iomem\n",
116 				 MAX_UIO_MAPS);
117 			break;
118 		}
119 
120 		uiomem->memtype = UIO_MEM_PHYS;
121 		uiomem->addr = r->start & PAGE_MASK;
122 		uiomem->offs = r->start & ~PAGE_MASK;
123 		uiomem->size =
124 			(uiomem->offs + resource_size(r) + PAGE_SIZE - 1) &
125 			PAGE_MASK;
126 		uiomem->name = r->name;
127 	}
128 
129 	ret = devm_uio_register_device(&pdev->dev, &udev->info);
130 	if (ret) {
131 		dev_err(&pdev->dev, "Failed to register uio device\n");
132 		goto out_free;
133 	}
134 
135 	pci_set_drvdata(pdev, udev);
136 
137 	return 0;
138 
139 out_free:
140 	kfree(udev);
141 out_disable:
142 	pci_disable_device(pdev);
143 
144 	return ret;
145 }
146 
remove(struct pci_dev * pdev)147 static void remove(struct pci_dev *pdev)
148 {
149 	struct uio_pci_sva_dev *udev = pci_get_drvdata(pdev);
150 
151 	pci_release_regions(pdev);
152 	pci_disable_device(pdev);
153 	kfree(udev);
154 }
155 
pasid_show(struct device * dev,struct device_attribute * attr,char * buf)156 static ssize_t pasid_show(struct device *dev,
157 			  struct device_attribute *attr, char *buf)
158 {
159 	struct pci_dev *pdev = to_pci_dev(dev);
160 	struct uio_pci_sva_dev *udev = pci_get_drvdata(pdev);
161 
162 	return sysfs_emit(buf, "%d\n", udev->pasid);
163 }
164 static DEVICE_ATTR_RO(pasid);
165 
166 static struct attribute *uio_pci_sva_attrs[] = {
167 	&dev_attr_pasid.attr,
168 	NULL
169 };
170 
171 static const struct attribute_group uio_pci_sva_attr_group = {
172 	.attrs = uio_pci_sva_attrs,
173 };
174 
175 static const struct attribute_group *uio_pci_sva_attr_groups[] = {
176 	&uio_pci_sva_attr_group,
177 	NULL
178 };
179 
180 static struct pci_driver uio_pci_generic_sva_driver = {
181 	.name = "uio_pci_sva",
182 	.dev_groups = uio_pci_sva_attr_groups,
183 	.id_table = NULL,
184 	.probe = probe,
185 	.remove = remove,
186 };
187 
188 module_pci_driver(uio_pci_generic_sva_driver);
189 MODULE_VERSION("0.0.01");
190 MODULE_LICENSE("GPL v2");
191 MODULE_AUTHOR("Yaxing Guo <guoyaxing@bosc.ac.cn>");
192 MODULE_DESCRIPTION("Generic UIO sva driver for PCI");
193