blob: 8e090ffed3a0dc7ea2c4c9f7b8f65208ffa9f7ce [file] [log] [blame]
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001/*
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
30static u64
31virtio_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
46static u64
47virtio_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
63static void
64virtio_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
83static u16
84virtio_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
92static u16
93virtio_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
101static u16
102virtio_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
109static u8
110virtio_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
117static void
118virtio_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
125static u8
126virtio_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
132static u8
133virtio_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
141static void
142virtio_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
148static u16
149virtio_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
158static void
159virtio_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
172static u16
173virtio_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
181static u16
182virtio_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
191static u16
192virtio_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
201static void
202virtio_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
210static u16
Mohsin Kazmi162a2962020-09-29 10:01:25 +0000211virtio_pci_modern_get_queue_notify_off (vlib_main_t * vm, virtio_if_t * vif,
212 u16 queue_id)
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200213{
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
221static u64
222virtio_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
229static void
230virtio_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
235static u64
236virtio_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
244static void
245virtio_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
251static u64
252virtio_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
260static void
261virtio_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
267static u8
268virtio_pci_modern_setup_queue (vlib_main_t * vm, virtio_if_t * vif,
269 u16 queue_id, void *p)
270{
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100271 u64 desc, avail, used;
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200272 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);
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200276
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100277 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
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200296 virtio_pci_modern_set_queue_desc (vif, desc);
297 if (desc != virtio_pci_modern_get_queue_desc (vif))
298 return 1;
299
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200300 virtio_pci_modern_set_queue_driver (vif, avail);
301 if (avail != virtio_pci_modern_get_queue_driver (vif))
302 return 1;
303
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200304 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
316static void
317virtio_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
327static void
328virtio_pci_modern_get_device_mac (vlib_main_t * vm, virtio_if_t * vif)
329{
Benoît Ganne3f0ae662020-09-09 12:50:07 +0200330 vif->mac_addr32 = virtio_pci_reg_read_u32 (vif, VIRTIO_MAC_OFFSET (vif));
331 vif->mac_addr16 =
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200332 virtio_pci_reg_read_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4);
333}
334
335static void
336virtio_pci_modern_set_device_mac (vlib_main_t * vm, virtio_if_t * vif)
337{
Benoît Ganne3f0ae662020-09-09 12:50:07 +0200338 virtio_pci_reg_write_u32 (vif, VIRTIO_MAC_OFFSET (vif), vif->mac_addr32);
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200339 virtio_pci_reg_write_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4,
Benoît Ganne3f0ae662020-09-09 12:50:07 +0200340 vif->mac_addr16);
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200341}
342
343static u16
344virtio_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
351static u16
352virtio_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
364static u16
365virtio_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
372static void
373virtio_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
391static void
392virtio_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
398static u8
399virtio_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
404inline void
405virtio_pci_modern_notify_queue (vlib_main_t * vm, virtio_if_t * vif,
Mohsin Kazmi162a2962020-09-29 10:01:25 +0000406 u16 queue_id, u16 queue_notify_off)
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200407{
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200408 virtio_pci_reg_write_u16 (vif,
409 VIRTIO_NOTIFICATION_OFFSET (vif) +
Mohsin Kazmi162a2962020-09-29 10:01:25 +0000410 queue_notify_off, queue_id);
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200411}
412
413static void
414virtio_pci_modern_device_debug_config_space (vlib_main_t * vm,
415 virtio_if_t * vif)
416{
417 // do nothing for now
418}
419
420const 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,
Mohsin Kazmi162a2962020-09-29 10:01:25 +0000434 .get_queue_notify_off = virtio_pci_modern_get_queue_notify_off,
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200435 .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 */