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