virtio: add modern device support
[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 (virtio_if_t * vif, u16 queue_id)
212 {
213   u16 queue_notify_off = 0;
214   virtio_pci_modern_set_queue_select (vif, queue_id);
215   queue_notify_off =
216     virtio_pci_reg_read_u16 (vif, VIRTIO_QUEUE_NOTIFY_OFF_OFFSET (vif));
217   return queue_notify_off;
218 }
219
220 static u64
221 virtio_pci_modern_get_queue_desc (virtio_if_t * vif)
222 {
223   u64 queue_desc = 0;
224   queue_desc = virtio_pci_reg_read_u64 (vif, VIRTIO_QUEUE_DESC_OFFSET (vif));
225   return queue_desc;
226 }
227
228 static void
229 virtio_pci_modern_set_queue_desc (virtio_if_t * vif, u64 queue_desc)
230 {
231   virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DESC_OFFSET (vif), queue_desc);
232 }
233
234 static u64
235 virtio_pci_modern_get_queue_driver (virtio_if_t * vif)
236 {
237   u64 queue_driver = 0;
238   queue_driver =
239     virtio_pci_reg_read_u64 (vif, VIRTIO_QUEUE_DRIVER_OFFSET (vif));
240   return queue_driver;
241 }
242
243 static void
244 virtio_pci_modern_set_queue_driver (virtio_if_t * vif, u64 queue_driver)
245 {
246   virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DRIVER_OFFSET (vif),
247                             queue_driver);
248 }
249
250 static u64
251 virtio_pci_modern_get_queue_device (virtio_if_t * vif)
252 {
253   u64 queue_device = 0;
254   queue_device =
255     virtio_pci_reg_read_u64 (vif, VIRTIO_QUEUE_DEVICE_OFFSET (vif));
256   return queue_device;
257 }
258
259 static void
260 virtio_pci_modern_set_queue_device (virtio_if_t * vif, u64 queue_device)
261 {
262   virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DEVICE_OFFSET (vif),
263                             queue_device);
264 }
265
266 static u8
267 virtio_pci_modern_setup_queue (vlib_main_t * vm, virtio_if_t * vif,
268                                u16 queue_id, void *p)
269 {
270   struct vring vr;
271   u16 queue_size = 0;
272
273   virtio_pci_modern_set_queue_select (vif, queue_id);
274   queue_size = virtio_pci_modern_get_queue_size (vm, vif, queue_id);
275   vring_init (&vr, queue_size, p, VIRTIO_PCI_VRING_ALIGN);
276
277   u64 desc = vlib_physmem_get_pa (vm, vr.desc);
278   virtio_pci_modern_set_queue_desc (vif, desc);
279   if (desc != virtio_pci_modern_get_queue_desc (vif))
280     return 1;
281
282   u64 avail = vlib_physmem_get_pa (vm, vr.avail);
283   virtio_pci_modern_set_queue_driver (vif, avail);
284   if (avail != virtio_pci_modern_get_queue_driver (vif))
285     return 1;
286
287   u64 used = vlib_physmem_get_pa (vm, vr.used);
288   virtio_pci_modern_set_queue_device (vif, used);
289   if (used != virtio_pci_modern_get_queue_device (vif))
290     return 1;
291
292   virtio_pci_modern_set_queue_enable (vif, queue_id, 1);
293
294   if (virtio_pci_modern_get_queue_enable (vif, queue_id))
295     return 0;
296
297   return 1;
298 }
299
300 static void
301 virtio_pci_modern_del_queue (vlib_main_t * vm, virtio_if_t * vif,
302                              u16 queue_id)
303 {
304   virtio_pci_modern_set_queue_select (vif, queue_id);
305   virtio_pci_modern_set_queue_enable (vif, queue_id, 0);
306   virtio_pci_modern_set_queue_desc (vif, 0);
307   virtio_pci_modern_set_queue_driver (vif, 0);
308   virtio_pci_modern_set_queue_device (vif, 0);
309 }
310
311 static void
312 virtio_pci_modern_get_device_mac (vlib_main_t * vm, virtio_if_t * vif)
313 {
314   *((u32 *) vif->mac_addr) =
315     virtio_pci_reg_read_u32 (vif, VIRTIO_MAC_OFFSET (vif));
316   *((u16 *) (vif->mac_addr + 4)) =
317     virtio_pci_reg_read_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4);
318 }
319
320 static void
321 virtio_pci_modern_set_device_mac (vlib_main_t * vm, virtio_if_t * vif)
322 {
323   virtio_pci_reg_write_u32 (vif, VIRTIO_MAC_OFFSET (vif),
324                             *((u32 *) vif->mac_addr));
325   virtio_pci_reg_write_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4,
326                             *((u16 *) (vif->mac_addr + 4)));
327 }
328
329 static u16
330 virtio_pci_modern_get_device_status (vlib_main_t * vm, virtio_if_t * vif)
331 {
332   u16 status = 0;
333   status = virtio_pci_reg_read_u16 (vif, VIRTIO_STATUS_OFFSET (vif));
334   return status;
335 }
336
337 static u16
338 virtio_pci_modern_get_max_virtqueue_pairs (vlib_main_t * vm,
339                                            virtio_if_t * vif)
340 {
341   u16 max_virtqueue_pairs = 0;
342   max_virtqueue_pairs =
343     virtio_pci_reg_read_u16 (vif, VIRTIO_MAX_VIRTQUEUE_PAIRS_OFFSET (vif));
344   u16 supported_queues = virtio_pci_modern_get_num_queues (vif);
345   virtio_log_debug (vif, "max-virtqueue-pairs %u, supported-queues %u",
346                     max_virtqueue_pairs, supported_queues);
347   return max_virtqueue_pairs;
348 }
349
350 static u16
351 virtio_pci_modern_get_device_mtu (vlib_main_t * vm, virtio_if_t * vif)
352 {
353   u16 mtu = 0;
354   mtu = virtio_pci_reg_read_u16 (vif, VIRTIO_MTU_OFFSET (vif));
355   return mtu;
356 }
357
358 static void
359 virtio_pci_modern_read_config (vlib_main_t * vm, virtio_if_t * vif, void *dst,
360                                int len, u32 addr)
361 {
362   u8 config_count;
363   do
364     {
365       config_count = virtio_pci_modern_get_config_generation (vif);
366       virtio_pci_modern_get_device_mac (vm, vif);
367       u16 status = virtio_pci_modern_get_device_status (vm, vif);
368       u16 max_queue_pairs =
369         virtio_pci_modern_get_max_virtqueue_pairs (vm, vif);
370       u16 mtu = virtio_pci_modern_get_device_mtu (vm, vif);
371       virtio_log_debug (vif, "status %u, max_queue_pairs %u, mtu %u", status,
372                         max_queue_pairs, mtu);
373     }
374   while (config_count != virtio_pci_modern_get_config_generation (vif));
375 }
376
377 static void
378 virtio_pci_modern_write_config (vlib_main_t * vm, virtio_if_t * vif,
379                                 void *src, int len, u32 addr)
380 {
381   // do nothing
382 }
383
384 static u8
385 virtio_pci_modern_get_isr (vlib_main_t * vm, virtio_if_t * vif)
386 {
387   return virtio_pci_reg_read_u8 (vif, VIRTIO_ISR_OFFSET (vif));
388 }
389
390 inline void
391 virtio_pci_modern_notify_queue (vlib_main_t * vm, virtio_if_t * vif,
392                                 u16 queue_id)
393 {
394   u16 queue_notify_off =
395     virtio_pci_modern_get_queue_notify_off (vif, queue_id);
396   virtio_pci_reg_write_u16 (vif,
397                             VIRTIO_NOTIFICATION_OFFSET (vif) +
398                             vif->notify_off_multiplier * queue_notify_off,
399                             queue_id);
400 }
401
402 static void
403 virtio_pci_modern_device_debug_config_space (vlib_main_t * vm,
404                                              virtio_if_t * vif)
405 {
406   // do nothing for now
407 }
408
409 const virtio_pci_func_t virtio_pci_modern_func = {
410   .read_config = virtio_pci_modern_read_config,
411   .write_config = virtio_pci_modern_write_config,
412   .get_device_features = virtio_pci_modern_get_device_features,
413   .get_driver_features = virtio_pci_modern_get_driver_features,
414   .set_driver_features = virtio_pci_modern_set_driver_features,
415   .get_status = virtio_pci_modern_get_status,
416   .set_status = virtio_pci_modern_set_status,
417   .device_reset = virtio_pci_modern_reset,
418   .get_isr = virtio_pci_modern_get_isr,
419   .get_queue_size = virtio_pci_modern_get_queue_size,
420   .set_queue_size = virtio_pci_modern_set_queue_size,
421   .setup_queue = virtio_pci_modern_setup_queue,
422   .del_queue = virtio_pci_modern_del_queue,
423   .notify_queue = virtio_pci_modern_notify_queue,
424   .set_config_irq = virtio_pci_modern_set_msix_config,
425   .set_queue_irq = virtio_pci_modern_set_queue_msix_vector,
426   .get_mac = virtio_pci_modern_get_device_mac,
427   .set_mac = virtio_pci_modern_set_device_mac,
428   .get_device_status = virtio_pci_modern_get_device_status,
429   .get_max_queue_pairs = virtio_pci_modern_get_max_virtqueue_pairs,
430   .get_mtu = virtio_pci_modern_get_device_mtu,
431   .device_debug_config_space = virtio_pci_modern_device_debug_config_space,
432 };
433
434 /*
435  * fd.io coding-style-patch-verification: ON
436  *
437  * Local Variables:
438  * eval: (c-set-style "gnu")
439  * End:
440  */