1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Virtio PCI driver - legacy device support |
4 | * |
5 | * This module allows virtio devices to be used over a virtual PCI device. |
6 | * This can be used with QEMU based VMMs like KVM or Xen. |
7 | * |
8 | * Copyright IBM Corp. 2007 |
9 | * Copyright Red Hat, Inc. 2014 |
10 | * |
11 | * Authors: |
12 | * Anthony Liguori <aliguori@us.ibm.com> |
13 | * Rusty Russell <rusty@rustcorp.com.au> |
14 | * Michael S. Tsirkin <mst@redhat.com> |
15 | */ |
16 | |
17 | #include "linux/virtio_pci_legacy.h" |
18 | #include "virtio_pci_common.h" |
19 | |
20 | /* virtio config->get_features() implementation */ |
21 | static u64 vp_get_features(struct virtio_device *vdev) |
22 | { |
23 | struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
24 | |
25 | /* When someone needs more than 32 feature bits, we'll need to |
26 | * steal a bit to indicate that the rest are somewhere else. */ |
27 | return vp_legacy_get_features(ldev: &vp_dev->ldev); |
28 | } |
29 | |
30 | /* virtio config->finalize_features() implementation */ |
31 | static int vp_finalize_features(struct virtio_device *vdev) |
32 | { |
33 | struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
34 | |
35 | /* Give virtio_ring a chance to accept features. */ |
36 | vring_transport_features(vdev); |
37 | |
38 | /* Make sure we don't have any features > 32 bits! */ |
39 | BUG_ON((u32)vdev->features != vdev->features); |
40 | |
41 | /* We only support 32 feature bits. */ |
42 | vp_legacy_set_features(ldev: &vp_dev->ldev, features: vdev->features); |
43 | |
44 | return 0; |
45 | } |
46 | |
47 | /* virtio config->get() implementation */ |
48 | static void vp_get(struct virtio_device *vdev, unsigned int offset, |
49 | void *buf, unsigned int len) |
50 | { |
51 | struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
52 | void __iomem *ioaddr = vp_dev->ldev.ioaddr + |
53 | VIRTIO_PCI_CONFIG_OFF(vp_dev->msix_enabled) + |
54 | offset; |
55 | u8 *ptr = buf; |
56 | int i; |
57 | |
58 | for (i = 0; i < len; i++) |
59 | ptr[i] = ioread8(ioaddr + i); |
60 | } |
61 | |
62 | /* the config->set() implementation. it's symmetric to the config->get() |
63 | * implementation */ |
64 | static void vp_set(struct virtio_device *vdev, unsigned int offset, |
65 | const void *buf, unsigned int len) |
66 | { |
67 | struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
68 | void __iomem *ioaddr = vp_dev->ldev.ioaddr + |
69 | VIRTIO_PCI_CONFIG_OFF(vp_dev->msix_enabled) + |
70 | offset; |
71 | const u8 *ptr = buf; |
72 | int i; |
73 | |
74 | for (i = 0; i < len; i++) |
75 | iowrite8(ptr[i], ioaddr + i); |
76 | } |
77 | |
78 | /* config->{get,set}_status() implementations */ |
79 | static u8 vp_get_status(struct virtio_device *vdev) |
80 | { |
81 | struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
82 | return vp_legacy_get_status(ldev: &vp_dev->ldev); |
83 | } |
84 | |
85 | static void vp_set_status(struct virtio_device *vdev, u8 status) |
86 | { |
87 | struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
88 | /* We should never be setting status to 0. */ |
89 | BUG_ON(status == 0); |
90 | vp_legacy_set_status(ldev: &vp_dev->ldev, status); |
91 | } |
92 | |
93 | static void vp_reset(struct virtio_device *vdev) |
94 | { |
95 | struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
96 | /* 0 status means a reset. */ |
97 | vp_legacy_set_status(ldev: &vp_dev->ldev, status: 0); |
98 | /* Flush out the status write, and flush in device writes, |
99 | * including MSi-X interrupts, if any. */ |
100 | vp_legacy_get_status(ldev: &vp_dev->ldev); |
101 | /* Flush pending VQ/configuration callbacks. */ |
102 | vp_synchronize_vectors(vdev); |
103 | } |
104 | |
105 | static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector) |
106 | { |
107 | return vp_legacy_config_vector(ldev: &vp_dev->ldev, vector); |
108 | } |
109 | |
110 | static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, |
111 | struct virtio_pci_vq_info *info, |
112 | unsigned int index, |
113 | void (*callback)(struct virtqueue *vq), |
114 | const char *name, |
115 | bool ctx, |
116 | u16 msix_vec) |
117 | { |
118 | struct virtqueue *vq; |
119 | u16 num; |
120 | int err; |
121 | u64 q_pfn; |
122 | |
123 | /* Check if queue is either not available or already active. */ |
124 | num = vp_legacy_get_queue_size(ldev: &vp_dev->ldev, idx: index); |
125 | if (!num || vp_legacy_get_queue_enable(ldev: &vp_dev->ldev, idx: index)) |
126 | return ERR_PTR(error: -ENOENT); |
127 | |
128 | info->msix_vector = msix_vec; |
129 | |
130 | /* create the vring */ |
131 | vq = vring_create_virtqueue(index, num, |
132 | VIRTIO_PCI_VRING_ALIGN, vdev: &vp_dev->vdev, |
133 | weak_barriers: true, may_reduce_num: false, ctx, |
134 | notify: vp_notify, callback, name); |
135 | if (!vq) |
136 | return ERR_PTR(error: -ENOMEM); |
137 | |
138 | vq->num_max = num; |
139 | |
140 | q_pfn = virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
141 | if (q_pfn >> 32) { |
142 | dev_err(&vp_dev->pci_dev->dev, |
143 | "platform bug: legacy virtio-pci must not be used with RAM above 0x%llxGB\n" , |
144 | 0x1ULL << (32 + PAGE_SHIFT - 30)); |
145 | err = -E2BIG; |
146 | goto out_del_vq; |
147 | } |
148 | |
149 | /* activate the queue */ |
150 | vp_legacy_set_queue_address(ldev: &vp_dev->ldev, index, queue_pfn: q_pfn); |
151 | |
152 | vq->priv = (void __force *)vp_dev->ldev.ioaddr + VIRTIO_PCI_QUEUE_NOTIFY; |
153 | |
154 | if (msix_vec != VIRTIO_MSI_NO_VECTOR) { |
155 | msix_vec = vp_legacy_queue_vector(ldev: &vp_dev->ldev, idx: index, vector: msix_vec); |
156 | if (msix_vec == VIRTIO_MSI_NO_VECTOR) { |
157 | err = -EBUSY; |
158 | goto out_deactivate; |
159 | } |
160 | } |
161 | |
162 | return vq; |
163 | |
164 | out_deactivate: |
165 | vp_legacy_set_queue_address(ldev: &vp_dev->ldev, index, queue_pfn: 0); |
166 | out_del_vq: |
167 | vring_del_virtqueue(vq); |
168 | return ERR_PTR(error: err); |
169 | } |
170 | |
171 | static void del_vq(struct virtio_pci_vq_info *info) |
172 | { |
173 | struct virtqueue *vq = info->vq; |
174 | struct virtio_pci_device *vp_dev = to_vp_device(vdev: vq->vdev); |
175 | |
176 | if (vp_dev->msix_enabled) { |
177 | vp_legacy_queue_vector(ldev: &vp_dev->ldev, idx: vq->index, |
178 | VIRTIO_MSI_NO_VECTOR); |
179 | /* Flush the write out to device */ |
180 | ioread8(vp_dev->ldev.ioaddr + VIRTIO_PCI_ISR); |
181 | } |
182 | |
183 | /* Select and deactivate the queue */ |
184 | vp_legacy_set_queue_address(ldev: &vp_dev->ldev, index: vq->index, queue_pfn: 0); |
185 | |
186 | vring_del_virtqueue(vq); |
187 | } |
188 | |
189 | static const struct virtio_config_ops virtio_pci_config_ops = { |
190 | .get = vp_get, |
191 | .set = vp_set, |
192 | .get_status = vp_get_status, |
193 | .set_status = vp_set_status, |
194 | .reset = vp_reset, |
195 | .find_vqs = vp_find_vqs, |
196 | .del_vqs = vp_del_vqs, |
197 | .synchronize_cbs = vp_synchronize_vectors, |
198 | .get_features = vp_get_features, |
199 | .finalize_features = vp_finalize_features, |
200 | .bus_name = vp_bus_name, |
201 | .set_vq_affinity = vp_set_vq_affinity, |
202 | .get_vq_affinity = vp_get_vq_affinity, |
203 | }; |
204 | |
205 | /* the PCI probing function */ |
206 | int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev) |
207 | { |
208 | struct virtio_pci_legacy_device *ldev = &vp_dev->ldev; |
209 | struct pci_dev *pci_dev = vp_dev->pci_dev; |
210 | int rc; |
211 | |
212 | ldev->pci_dev = pci_dev; |
213 | |
214 | rc = vp_legacy_probe(ldev); |
215 | if (rc) |
216 | return rc; |
217 | |
218 | vp_dev->isr = ldev->isr; |
219 | vp_dev->vdev.id = ldev->id; |
220 | |
221 | vp_dev->vdev.config = &virtio_pci_config_ops; |
222 | |
223 | vp_dev->config_vector = vp_config_vector; |
224 | vp_dev->setup_vq = setup_vq; |
225 | vp_dev->del_vq = del_vq; |
226 | vp_dev->is_legacy = true; |
227 | |
228 | return 0; |
229 | } |
230 | |
231 | void virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev) |
232 | { |
233 | struct virtio_pci_legacy_device *ldev = &vp_dev->ldev; |
234 | |
235 | vp_legacy_remove(ldev); |
236 | } |
237 | |