f7313d84bbd7c8b12aa9a0f659a57d8b9a8f03f7
[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, u16 queue_id,
269                                vnet_virtio_vring_t *vring)
270 {
271   u64 desc, avail, used;
272
273   virtio_pci_modern_set_queue_select (vif, queue_id);
274
275   if (vif->is_packed)
276     {
277       desc = vlib_physmem_get_pa (vm, vring->packed_desc);
278       avail = vlib_physmem_get_pa (vm, vring->driver_event);
279       used = vlib_physmem_get_pa (vm, vring->device_event);
280     }
281   else
282     {
283       desc = vlib_physmem_get_pa (vm, vring->desc);
284       avail = vlib_physmem_get_pa (vm, vring->avail);
285       used = vlib_physmem_get_pa (vm, vring->used);
286     }
287
288   virtio_pci_modern_set_queue_desc (vif, desc);
289   if (desc != virtio_pci_modern_get_queue_desc (vif))
290     return 1;
291
292   virtio_pci_modern_set_queue_driver (vif, avail);
293   if (avail != virtio_pci_modern_get_queue_driver (vif))
294     return 1;
295
296   virtio_pci_modern_set_queue_device (vif, used);
297   if (used != virtio_pci_modern_get_queue_device (vif))
298     return 1;
299
300   virtio_pci_modern_set_queue_enable (vif, queue_id, 1);
301
302   if (virtio_pci_modern_get_queue_enable (vif, queue_id))
303     return 0;
304
305   return 1;
306 }
307
308 static void
309 virtio_pci_modern_del_queue (vlib_main_t * vm, virtio_if_t * vif,
310                              u16 queue_id)
311 {
312   virtio_pci_modern_set_queue_select (vif, queue_id);
313   virtio_pci_modern_set_queue_enable (vif, queue_id, 0);
314   virtio_pci_modern_set_queue_desc (vif, 0);
315   virtio_pci_modern_set_queue_driver (vif, 0);
316   virtio_pci_modern_set_queue_device (vif, 0);
317 }
318
319 static void
320 virtio_pci_modern_get_device_mac (vlib_main_t * vm, virtio_if_t * vif)
321 {
322   vif->mac_addr32 = virtio_pci_reg_read_u32 (vif, VIRTIO_MAC_OFFSET (vif));
323   vif->mac_addr16 =
324     virtio_pci_reg_read_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4);
325 }
326
327 static void
328 virtio_pci_modern_set_device_mac (vlib_main_t * vm, virtio_if_t * vif)
329 {
330   virtio_pci_reg_write_u32 (vif, VIRTIO_MAC_OFFSET (vif), vif->mac_addr32);
331   virtio_pci_reg_write_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4,
332                             vif->mac_addr16);
333 }
334
335 static u16
336 virtio_pci_modern_get_device_status (vlib_main_t * vm, virtio_if_t * vif)
337 {
338   u16 status = 0;
339   status = virtio_pci_reg_read_u16 (vif, VIRTIO_STATUS_OFFSET (vif));
340   return status;
341 }
342
343 static u16
344 virtio_pci_modern_get_max_virtqueue_pairs (vlib_main_t * vm,
345                                            virtio_if_t * vif)
346 {
347   u16 max_virtqueue_pairs = 0;
348   max_virtqueue_pairs =
349     virtio_pci_reg_read_u16 (vif, VIRTIO_MAX_VIRTQUEUE_PAIRS_OFFSET (vif));
350   u16 supported_queues = virtio_pci_modern_get_num_queues (vif);
351   virtio_log_debug (vif, "max-virtqueue-pairs %u, supported-queues %u",
352                     max_virtqueue_pairs, supported_queues);
353   return max_virtqueue_pairs;
354 }
355
356 static u16
357 virtio_pci_modern_get_device_mtu (vlib_main_t * vm, virtio_if_t * vif)
358 {
359   u16 mtu = 0;
360   mtu = virtio_pci_reg_read_u16 (vif, VIRTIO_MTU_OFFSET (vif));
361   return mtu;
362 }
363
364 static void
365 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       config_count = virtio_pci_modern_get_config_generation (vif);
372       virtio_pci_modern_get_device_mac (vm, vif);
373       u16 status = virtio_pci_modern_get_device_status (vm, vif);
374       u16 max_queue_pairs =
375         virtio_pci_modern_get_max_virtqueue_pairs (vm, vif);
376       u16 mtu = virtio_pci_modern_get_device_mtu (vm, vif);
377       virtio_log_debug (vif, "status %u, max_queue_pairs %u, mtu %u", status,
378                         max_queue_pairs, mtu);
379     }
380   while (config_count != virtio_pci_modern_get_config_generation (vif));
381 }
382
383 static void
384 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 }
389
390 static u8
391 virtio_pci_modern_get_isr (vlib_main_t * vm, virtio_if_t * vif)
392 {
393   return virtio_pci_reg_read_u8 (vif, VIRTIO_ISR_OFFSET (vif));
394 }
395
396 inline void
397 virtio_pci_modern_notify_queue (vlib_main_t * vm, virtio_if_t * vif,
398                                 u16 queue_id, u16 queue_notify_off)
399 {
400   virtio_pci_reg_write_u16 (vif,
401                             VIRTIO_NOTIFICATION_OFFSET (vif) +
402                             queue_notify_off, queue_id);
403 }
404
405 static void
406 virtio_pci_modern_device_debug_config_space (vlib_main_t * vm,
407                                              virtio_if_t * vif)
408 {
409   // do nothing for now
410 }
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  */