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