Line data Source code
1 : /*
2 : * Copyright (c) 2020 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <fcntl.h>
17 : #include <sys/ioctl.h>
18 :
19 : #include <vppinfra/types.h>
20 : #include <vlib/vlib.h>
21 : #include <vlib/pci/pci.h>
22 : #include <vnet/ethernet/ethernet.h>
23 : #include <vnet/ip/ip4_packet.h>
24 : #include <vnet/ip/ip6_packet.h>
25 : #include <vnet/devices/virtio/virtio.h>
26 : #include <vnet/devices/virtio/virtio_pci_modern.h>
27 : #include <vnet/devices/virtio/pci.h>
28 :
29 :
30 : static u64
31 0 : virtio_pci_modern_get_device_features (vlib_main_t * vm, virtio_if_t * vif)
32 : {
33 : u64 features_lo, features_hi;
34 0 : virtio_pci_reg_write_u32 (vif, VIRTIO_DEVICE_FEATURE_SELECT_OFFSET (vif),
35 : VIRTIO_FEATURE_SELECT_LO);
36 0 : features_lo =
37 0 : virtio_pci_reg_read_u32 (vif, VIRTIO_DEVICE_FEATURE_OFFSET (vif));
38 0 : virtio_pci_reg_write_u32 (vif, VIRTIO_DEVICE_FEATURE_SELECT_OFFSET (vif),
39 : VIRTIO_FEATURE_SELECT_HI);
40 0 : features_hi =
41 0 : virtio_pci_reg_read_u32 (vif, VIRTIO_DEVICE_FEATURE_OFFSET (vif));
42 0 : u64 features = ((features_hi << 32) | features_lo);
43 0 : return features;
44 : }
45 :
46 : static u64
47 0 : virtio_pci_modern_get_driver_features (vlib_main_t * vm, virtio_if_t * vif)
48 : {
49 : u64 features_lo, features_hi;
50 0 : virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_SELECT_OFFSET (vif),
51 : VIRTIO_FEATURE_SELECT_LO);
52 0 : features_lo =
53 0 : virtio_pci_reg_read_u32 (vif, VIRTIO_DRIVER_FEATURE_OFFSET (vif));
54 0 : virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_SELECT_OFFSET (vif),
55 : VIRTIO_FEATURE_SELECT_HI);
56 0 : features_hi =
57 0 : virtio_pci_reg_read_u32 (vif, VIRTIO_DRIVER_FEATURE_OFFSET (vif));
58 :
59 0 : vif->features = ((features_hi << 32) | features_lo);
60 0 : return vif->features;
61 : }
62 :
63 : static void
64 0 : virtio_pci_modern_set_driver_features (vlib_main_t * vm, virtio_if_t * vif,
65 : u64 features)
66 : {
67 0 : u32 features_lo = (u32) features, features_hi = (u32) (features >> 32);
68 0 : virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_SELECT_OFFSET (vif),
69 : VIRTIO_FEATURE_SELECT_LO);
70 0 : virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_OFFSET (vif),
71 : features_lo);
72 0 : virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_SELECT_OFFSET (vif),
73 : VIRTIO_FEATURE_SELECT_HI);
74 0 : virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_OFFSET (vif),
75 : features_hi);
76 :
77 0 : if (features != virtio_pci_modern_get_driver_features (vm, vif))
78 : {
79 0 : clib_warning ("modern set guest features failed!");
80 : }
81 0 : }
82 :
83 : static u16
84 0 : virtio_pci_modern_get_msix_config (virtio_if_t * vif)
85 : {
86 : u16 msix_config;
87 : msix_config =
88 0 : virtio_pci_reg_read_u16 (vif, VIRTIO_MSIX_CONFIG_VECTOR_OFFSET (vif));
89 0 : return msix_config;
90 : }
91 :
92 : static u16
93 0 : virtio_pci_modern_set_msix_config (vlib_main_t * vm, virtio_if_t * vif,
94 : u16 msix_config)
95 : {
96 0 : virtio_pci_reg_write_u16 (vif, VIRTIO_MSIX_CONFIG_VECTOR_OFFSET (vif),
97 : msix_config);
98 0 : return virtio_pci_modern_get_msix_config (vif);
99 : }
100 :
101 : static u16
102 0 : virtio_pci_modern_get_num_queues (virtio_if_t * vif)
103 : {
104 0 : u16 num_queues = 0;
105 0 : num_queues = virtio_pci_reg_read_u16 (vif, VIRTIO_NUM_QUEUES_OFFSET (vif));
106 0 : return num_queues;
107 : }
108 :
109 : static u8
110 0 : virtio_pci_modern_get_status (vlib_main_t * vm, virtio_if_t * vif)
111 : {
112 0 : u8 status = 0;
113 0 : status = virtio_pci_reg_read_u8 (vif, VIRTIO_DEVICE_STATUS_OFFSET (vif));
114 0 : return status;
115 : }
116 :
117 : static void
118 0 : virtio_pci_modern_set_status (vlib_main_t * vm, virtio_if_t * vif, u8 status)
119 : {
120 0 : if (status != VIRTIO_CONFIG_STATUS_RESET)
121 0 : status |= virtio_pci_modern_get_status (vm, vif);
122 0 : virtio_pci_reg_write_u8 (vif, VIRTIO_DEVICE_STATUS_OFFSET (vif), status);
123 0 : }
124 :
125 : static u8
126 0 : virtio_pci_modern_reset (vlib_main_t * vm, virtio_if_t * vif)
127 : {
128 0 : virtio_pci_modern_set_status (vm, vif, VIRTIO_CONFIG_STATUS_RESET);
129 0 : return virtio_pci_modern_get_status (vm, vif);
130 : }
131 :
132 : static u8
133 0 : virtio_pci_modern_get_config_generation (virtio_if_t * vif)
134 : {
135 0 : u8 config_generation = 0;
136 : config_generation =
137 0 : virtio_pci_reg_read_u8 (vif, VIRTIO_CONFIG_GENERATION_OFFSET (vif));
138 0 : return config_generation;
139 : }
140 :
141 : static void
142 0 : virtio_pci_modern_set_queue_select (virtio_if_t * vif, u16 queue_select)
143 : {
144 0 : virtio_pci_reg_write_u16 (vif, VIRTIO_QUEUE_SELECT_OFFSET (vif),
145 : queue_select);
146 0 : }
147 :
148 : static u16
149 0 : virtio_pci_modern_get_queue_size (vlib_main_t * vm, virtio_if_t * vif,
150 : u16 queue_id)
151 : {
152 0 : u16 queue_size = 0;
153 0 : virtio_pci_modern_set_queue_select (vif, queue_id);
154 0 : queue_size = virtio_pci_reg_read_u16 (vif, VIRTIO_QUEUE_SIZE_OFFSET (vif));
155 0 : return queue_size;
156 : }
157 :
158 : static void
159 0 : virtio_pci_modern_set_queue_size (vlib_main_t * vm, virtio_if_t * vif,
160 : u16 queue_id, u16 queue_size)
161 : {
162 0 : if (!is_pow2 (queue_size))
163 : {
164 0 : return;
165 : }
166 :
167 0 : if (virtio_pci_modern_get_queue_size (vm, vif, queue_id) > queue_size)
168 0 : virtio_pci_reg_write_u16 (vif, VIRTIO_QUEUE_SIZE_OFFSET (vif),
169 : queue_size);
170 : }
171 :
172 : static u16
173 0 : virtio_pci_modern_get_queue_msix_vector (virtio_if_t * vif)
174 : {
175 0 : u16 queue_msix_vector = 0;
176 : queue_msix_vector =
177 0 : virtio_pci_reg_read_u16 (vif, VIRTIO_QUEUE_MSIX_VECTOR_OFFSET (vif));
178 0 : return queue_msix_vector;
179 : }
180 :
181 : static u16
182 0 : virtio_pci_modern_set_queue_msix_vector (vlib_main_t * vm, virtio_if_t * vif,
183 : u16 queue_msix_vector, u16 queue_id)
184 : {
185 0 : virtio_pci_modern_set_queue_select (vif, queue_id);
186 0 : virtio_pci_reg_write_u16 (vif, VIRTIO_QUEUE_MSIX_VECTOR_OFFSET (vif),
187 : queue_msix_vector);
188 0 : return virtio_pci_modern_get_queue_msix_vector (vif);
189 : }
190 :
191 : static u16
192 0 : virtio_pci_modern_get_queue_enable (virtio_if_t * vif, u16 queue_id)
193 : {
194 0 : u16 queue_enable = 0;
195 0 : virtio_pci_modern_set_queue_select (vif, queue_id);
196 : queue_enable =
197 0 : virtio_pci_reg_read_u16 (vif, VIRTIO_QUEUE_ENABLE_OFFSET (vif));
198 0 : return queue_enable;
199 : }
200 :
201 : static void
202 0 : virtio_pci_modern_set_queue_enable (virtio_if_t * vif, u16 queue_id,
203 : u16 queue_enable)
204 : {
205 0 : virtio_pci_modern_set_queue_select (vif, queue_id);
206 0 : virtio_pci_reg_write_u16 (vif, VIRTIO_QUEUE_ENABLE_OFFSET (vif),
207 : queue_enable);
208 0 : }
209 :
210 : static u16
211 0 : virtio_pci_modern_get_queue_notify_off (vlib_main_t * vm, virtio_if_t * vif,
212 : u16 queue_id)
213 : {
214 0 : u16 queue_notify_off = 0;
215 0 : virtio_pci_modern_set_queue_select (vif, queue_id);
216 : queue_notify_off =
217 0 : virtio_pci_reg_read_u16 (vif, VIRTIO_QUEUE_NOTIFY_OFF_OFFSET (vif));
218 0 : return queue_notify_off;
219 : }
220 :
221 : static u64
222 0 : virtio_pci_modern_get_queue_desc (virtio_if_t * vif)
223 : {
224 0 : u64 queue_desc = 0;
225 0 : queue_desc = virtio_pci_reg_read_u64 (vif, VIRTIO_QUEUE_DESC_OFFSET (vif));
226 0 : return queue_desc;
227 : }
228 :
229 : static void
230 0 : virtio_pci_modern_set_queue_desc (virtio_if_t * vif, u64 queue_desc)
231 : {
232 0 : virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DESC_OFFSET (vif), queue_desc);
233 0 : }
234 :
235 : static u64
236 0 : virtio_pci_modern_get_queue_driver (virtio_if_t * vif)
237 : {
238 0 : u64 queue_driver = 0;
239 : queue_driver =
240 0 : virtio_pci_reg_read_u64 (vif, VIRTIO_QUEUE_DRIVER_OFFSET (vif));
241 0 : return queue_driver;
242 : }
243 :
244 : static void
245 0 : virtio_pci_modern_set_queue_driver (virtio_if_t * vif, u64 queue_driver)
246 : {
247 0 : virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DRIVER_OFFSET (vif),
248 : queue_driver);
249 0 : }
250 :
251 : static u64
252 0 : virtio_pci_modern_get_queue_device (virtio_if_t * vif)
253 : {
254 0 : u64 queue_device = 0;
255 : queue_device =
256 0 : virtio_pci_reg_read_u64 (vif, VIRTIO_QUEUE_DEVICE_OFFSET (vif));
257 0 : return queue_device;
258 : }
259 :
260 : static void
261 0 : virtio_pci_modern_set_queue_device (virtio_if_t * vif, u64 queue_device)
262 : {
263 0 : virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DEVICE_OFFSET (vif),
264 : queue_device);
265 0 : }
266 :
267 : static u8
268 0 : virtio_pci_modern_setup_queue (vlib_main_t *vm, virtio_if_t *vif, u16 queue_id,
269 : vnet_virtio_vring_t *vring)
270 : {
271 : u64 desc, avail, used;
272 :
273 0 : virtio_pci_modern_set_queue_select (vif, queue_id);
274 :
275 0 : if (vif->is_packed)
276 : {
277 0 : desc = vlib_physmem_get_pa (vm, vring->packed_desc);
278 0 : avail = vlib_physmem_get_pa (vm, vring->driver_event);
279 0 : used = vlib_physmem_get_pa (vm, vring->device_event);
280 : }
281 : else
282 : {
283 0 : desc = vlib_physmem_get_pa (vm, vring->desc);
284 0 : avail = vlib_physmem_get_pa (vm, vring->avail);
285 0 : used = vlib_physmem_get_pa (vm, vring->used);
286 : }
287 :
288 0 : virtio_pci_modern_set_queue_desc (vif, desc);
289 0 : if (desc != virtio_pci_modern_get_queue_desc (vif))
290 0 : return 1;
291 :
292 0 : virtio_pci_modern_set_queue_driver (vif, avail);
293 0 : if (avail != virtio_pci_modern_get_queue_driver (vif))
294 0 : return 1;
295 :
296 0 : virtio_pci_modern_set_queue_device (vif, used);
297 0 : if (used != virtio_pci_modern_get_queue_device (vif))
298 0 : return 1;
299 :
300 0 : virtio_pci_modern_set_queue_enable (vif, queue_id, 1);
301 :
302 0 : if (virtio_pci_modern_get_queue_enable (vif, queue_id))
303 0 : return 0;
304 :
305 0 : return 1;
306 : }
307 :
308 : static void
309 0 : virtio_pci_modern_del_queue (vlib_main_t * vm, virtio_if_t * vif,
310 : u16 queue_id)
311 : {
312 0 : virtio_pci_modern_set_queue_select (vif, queue_id);
313 0 : virtio_pci_modern_set_queue_enable (vif, queue_id, 0);
314 0 : virtio_pci_modern_set_queue_desc (vif, 0);
315 0 : virtio_pci_modern_set_queue_driver (vif, 0);
316 0 : virtio_pci_modern_set_queue_device (vif, 0);
317 0 : }
318 :
319 : static void
320 0 : virtio_pci_modern_get_device_mac (vlib_main_t * vm, virtio_if_t * vif)
321 : {
322 0 : vif->mac_addr32 = virtio_pci_reg_read_u32 (vif, VIRTIO_MAC_OFFSET (vif));
323 0 : vif->mac_addr16 =
324 0 : virtio_pci_reg_read_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4);
325 0 : }
326 :
327 : static void
328 0 : virtio_pci_modern_set_device_mac (vlib_main_t * vm, virtio_if_t * vif)
329 : {
330 0 : virtio_pci_reg_write_u32 (vif, VIRTIO_MAC_OFFSET (vif), vif->mac_addr32);
331 0 : virtio_pci_reg_write_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4,
332 0 : vif->mac_addr16);
333 0 : }
334 :
335 : static u16
336 0 : virtio_pci_modern_get_device_status (vlib_main_t * vm, virtio_if_t * vif)
337 : {
338 0 : u16 status = 0;
339 0 : status = virtio_pci_reg_read_u16 (vif, VIRTIO_STATUS_OFFSET (vif));
340 0 : return status;
341 : }
342 :
343 : static u16
344 0 : virtio_pci_modern_get_max_virtqueue_pairs (vlib_main_t * vm,
345 : virtio_if_t * vif)
346 : {
347 0 : u16 max_virtqueue_pairs = 0;
348 : max_virtqueue_pairs =
349 0 : virtio_pci_reg_read_u16 (vif, VIRTIO_MAX_VIRTQUEUE_PAIRS_OFFSET (vif));
350 0 : u16 supported_queues = virtio_pci_modern_get_num_queues (vif);
351 0 : virtio_log_debug (vif, "max-virtqueue-pairs %u, supported-queues %u",
352 : max_virtqueue_pairs, supported_queues);
353 0 : return max_virtqueue_pairs;
354 : }
355 :
356 : static u16
357 0 : virtio_pci_modern_get_device_mtu (vlib_main_t * vm, virtio_if_t * vif)
358 : {
359 0 : u16 mtu = 0;
360 0 : mtu = virtio_pci_reg_read_u16 (vif, VIRTIO_MTU_OFFSET (vif));
361 0 : return mtu;
362 : }
363 :
364 : static void
365 0 : virtio_pci_modern_read_config (vlib_main_t * vm, virtio_if_t * vif, void *dst,
366 : int len, u32 addr)
367 : {
368 : u8 config_count;
369 : do
370 : {
371 0 : config_count = virtio_pci_modern_get_config_generation (vif);
372 0 : virtio_pci_modern_get_device_mac (vm, vif);
373 0 : u16 status = virtio_pci_modern_get_device_status (vm, vif);
374 : u16 max_queue_pairs =
375 0 : virtio_pci_modern_get_max_virtqueue_pairs (vm, vif);
376 0 : u16 mtu = virtio_pci_modern_get_device_mtu (vm, vif);
377 0 : virtio_log_debug (vif, "status %u, max_queue_pairs %u, mtu %u", status,
378 : max_queue_pairs, mtu);
379 : }
380 0 : while (config_count != virtio_pci_modern_get_config_generation (vif));
381 0 : }
382 :
383 : static void
384 0 : virtio_pci_modern_write_config (vlib_main_t * vm, virtio_if_t * vif,
385 : void *src, int len, u32 addr)
386 : {
387 : // do nothing
388 0 : }
389 :
390 : static u8
391 0 : virtio_pci_modern_get_isr (vlib_main_t * vm, virtio_if_t * vif)
392 : {
393 0 : return virtio_pci_reg_read_u8 (vif, VIRTIO_ISR_OFFSET (vif));
394 : }
395 :
396 : inline void
397 0 : virtio_pci_modern_notify_queue (vlib_main_t * vm, virtio_if_t * vif,
398 : u16 queue_id, u16 queue_notify_off)
399 : {
400 0 : virtio_pci_reg_write_u16 (vif,
401 0 : VIRTIO_NOTIFICATION_OFFSET (vif) +
402 : queue_notify_off, queue_id);
403 0 : }
404 :
405 : static void
406 0 : virtio_pci_modern_device_debug_config_space (vlib_main_t * vm,
407 : virtio_if_t * vif)
408 : {
409 : // do nothing for now
410 0 : }
411 :
412 : const virtio_pci_func_t virtio_pci_modern_func = {
413 : .read_config = virtio_pci_modern_read_config,
414 : .write_config = virtio_pci_modern_write_config,
415 : .get_device_features = virtio_pci_modern_get_device_features,
416 : .get_driver_features = virtio_pci_modern_get_driver_features,
417 : .set_driver_features = virtio_pci_modern_set_driver_features,
418 : .get_status = virtio_pci_modern_get_status,
419 : .set_status = virtio_pci_modern_set_status,
420 : .device_reset = virtio_pci_modern_reset,
421 : .get_isr = virtio_pci_modern_get_isr,
422 : .get_queue_size = virtio_pci_modern_get_queue_size,
423 : .set_queue_size = virtio_pci_modern_set_queue_size,
424 : .setup_queue = virtio_pci_modern_setup_queue,
425 : .del_queue = virtio_pci_modern_del_queue,
426 : .get_queue_notify_off = virtio_pci_modern_get_queue_notify_off,
427 : .notify_queue = virtio_pci_modern_notify_queue,
428 : .set_config_irq = virtio_pci_modern_set_msix_config,
429 : .set_queue_irq = virtio_pci_modern_set_queue_msix_vector,
430 : .get_mac = virtio_pci_modern_get_device_mac,
431 : .set_mac = virtio_pci_modern_set_device_mac,
432 : .get_device_status = virtio_pci_modern_get_device_status,
433 : .get_max_queue_pairs = virtio_pci_modern_get_max_virtqueue_pairs,
434 : .get_mtu = virtio_pci_modern_get_device_mtu,
435 : .device_debug_config_space = virtio_pci_modern_device_debug_config_space,
436 : };
437 :
438 : /*
439 : * fd.io coding-style-patch-verification: ON
440 : *
441 : * Local Variables:
442 : * eval: (c-set-style "gnu")
443 : * End:
444 : */
|