FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
virtio_pci_modern.c
Go to the documentation of this file.
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>
28 
29 
30 static u64
32 {
33  u64 features_lo, features_hi;
34  virtio_pci_reg_write_u32 (vif, VIRTIO_DEVICE_FEATURE_SELECT_OFFSET (vif),
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),
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
48 {
49  u64 features_lo, features_hi;
50  virtio_pci_reg_write_u32 (vif, VIRTIO_DRIVER_FEATURE_SELECT_OFFSET (vif),
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),
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
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),
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),
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
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
94  u16 msix_config)
95 {
96  virtio_pci_reg_write_u16 (vif, VIRTIO_MSIX_CONFIG_VECTOR_OFFSET (vif),
97  msix_config);
99 }
100 
101 static u16
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
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
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
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
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
143 {
144  virtio_pci_reg_write_u16 (vif, VIRTIO_QUEUE_SELECT_OFFSET (vif),
145  queue_select);
146 }
147 
148 static u16
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
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
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
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);
189 }
190 
191 static u16
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
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
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
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
231 {
232  virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DESC_OFFSET (vif), queue_desc);
233 }
234 
235 static u64
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
246 {
247  virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DRIVER_OFFSET (vif),
248  queue_driver);
249 }
250 
251 static u64
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
262 {
263  virtio_pci_reg_write_u64 (vif, VIRTIO_QUEUE_DEVICE_OFFSET (vif),
264  queue_device);
265 }
266 
267 static u8
269  u16 queue_id, void *p)
270 {
271  vring_t vr;
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  vring_init (&vr, queue_size, p, VIRTIO_PCI_VRING_ALIGN);
277 
278  u64 desc = vlib_physmem_get_pa (vm, vr.desc);
280  if (desc != virtio_pci_modern_get_queue_desc (vif))
281  return 1;
282 
283  u64 avail = vlib_physmem_get_pa (vm, vr.avail);
285  if (avail != virtio_pci_modern_get_queue_driver (vif))
286  return 1;
287 
288  u64 used = vlib_physmem_get_pa (vm, vr.used);
290  if (used != virtio_pci_modern_get_queue_device (vif))
291  return 1;
292 
293  virtio_pci_modern_set_queue_enable (vif, queue_id, 1);
294 
295  if (virtio_pci_modern_get_queue_enable (vif, queue_id))
296  return 0;
297 
298  return 1;
299 }
300 
301 static void
303  u16 queue_id)
304 {
305  virtio_pci_modern_set_queue_select (vif, queue_id);
306  virtio_pci_modern_set_queue_enable (vif, queue_id, 0);
310 }
311 
312 static void
314 {
315  vif->mac_addr32 = virtio_pci_reg_read_u32 (vif, VIRTIO_MAC_OFFSET (vif));
316  vif->mac_addr16 =
317  virtio_pci_reg_read_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4);
318 }
319 
320 static void
322 {
323  virtio_pci_reg_write_u32 (vif, VIRTIO_MAC_OFFSET (vif), vif->mac_addr32);
324  virtio_pci_reg_write_u16 (vif, VIRTIO_MAC_OFFSET (vif) + 4,
325  vif->mac_addr16);
326 }
327 
328 static u16
330 {
331  u16 status = 0;
332  status = virtio_pci_reg_read_u16 (vif, VIRTIO_STATUS_OFFSET (vif));
333  return status;
334 }
335 
336 static u16
338  virtio_if_t * vif)
339 {
340  u16 max_virtqueue_pairs = 0;
341  max_virtqueue_pairs =
342  virtio_pci_reg_read_u16 (vif, VIRTIO_MAX_VIRTQUEUE_PAIRS_OFFSET (vif));
343  u16 supported_queues = virtio_pci_modern_get_num_queues (vif);
344  virtio_log_debug (vif, "max-virtqueue-pairs %u, supported-queues %u",
345  max_virtqueue_pairs, supported_queues);
346  return max_virtqueue_pairs;
347 }
348 
349 static u16
351 {
352  u16 mtu = 0;
353  mtu = virtio_pci_reg_read_u16 (vif, VIRTIO_MTU_OFFSET (vif));
354  return mtu;
355 }
356 
357 static void
359  int len, u32 addr)
360 {
361  u8 config_count;
362  do
363  {
364  config_count = virtio_pci_modern_get_config_generation (vif);
366  u16 status = virtio_pci_modern_get_device_status (vm, vif);
367  u16 max_queue_pairs =
369  u16 mtu = virtio_pci_modern_get_device_mtu (vm, vif);
370  virtio_log_debug (vif, "status %u, max_queue_pairs %u, mtu %u", status,
371  max_queue_pairs, mtu);
372  }
373  while (config_count != virtio_pci_modern_get_config_generation (vif));
374 }
375 
376 static void
378  void *src, int len, u32 addr)
379 {
380  // do nothing
381 }
382 
383 static u8
385 {
386  return virtio_pci_reg_read_u8 (vif, VIRTIO_ISR_OFFSET (vif));
387 }
388 
389 inline void
391  u16 queue_id, u16 queue_notify_off)
392 {
393  virtio_pci_reg_write_u16 (vif,
395  queue_notify_off, queue_id);
396 }
397 
398 static void
400  virtio_if_t * vif)
401 {
402  // do nothing for now
403 }
404 
406  .read_config = virtio_pci_modern_read_config,
407  .write_config = virtio_pci_modern_write_config,
408  .get_device_features = virtio_pci_modern_get_device_features,
409  .get_driver_features = virtio_pci_modern_get_driver_features,
410  .set_driver_features = virtio_pci_modern_set_driver_features,
411  .get_status = virtio_pci_modern_get_status,
412  .set_status = virtio_pci_modern_set_status,
413  .device_reset = virtio_pci_modern_reset,
414  .get_isr = virtio_pci_modern_get_isr,
415  .get_queue_size = virtio_pci_modern_get_queue_size,
416  .set_queue_size = virtio_pci_modern_set_queue_size,
417  .setup_queue = virtio_pci_modern_setup_queue,
418  .del_queue = virtio_pci_modern_del_queue,
419  .get_queue_notify_off = virtio_pci_modern_get_queue_notify_off,
420  .notify_queue = virtio_pci_modern_notify_queue,
421  .set_config_irq = virtio_pci_modern_set_msix_config,
425  .get_device_status = virtio_pci_modern_get_device_status,
426  .get_max_queue_pairs = virtio_pci_modern_get_max_virtqueue_pairs,
428  .device_debug_config_space = virtio_pci_modern_device_debug_config_space,
429 };
430 
431 /*
432  * fd.io coding-style-patch-verification: ON
433  *
434  * Local Variables:
435  * eval: (c-set-style "gnu")
436  * End:
437  */
#define VIRTIO_ISR_OFFSET(v)
static u16 virtio_pci_modern_get_max_virtqueue_pairs(vlib_main_t *vm, virtio_if_t *vif)
const virtio_pci_func_t virtio_pci_modern_func
static void virtio_pci_modern_read_config(vlib_main_t *vm, virtio_if_t *vif, void *dst, int len, u32 addr)
#define VIRTIO_MAX_VIRTQUEUE_PAIRS_OFFSET(v)
static void virtio_pci_modern_set_queue_enable(virtio_if_t *vif, u16 queue_id, u16 queue_enable)
vring_used_t * used
Definition: virtio_std.h:177
static u64 virtio_pci_modern_get_queue_desc(virtio_if_t *vif)
void virtio_pci_modern_notify_queue(vlib_main_t *vm, virtio_if_t *vif, u16 queue_id, u16 queue_notify_off)
unsigned long u64
Definition: types.h:89
#define VIRTIO_QUEUE_DRIVER_OFFSET(v)
#define VIRTIO_QUEUE_DEVICE_OFFSET(v)
vl_api_address_t src
Definition: gre.api:54
#define VIRTIO_NUM_QUEUES_OFFSET(v)
vlib_main_t * vm
Definition: in2out_ed.c:1582
#define VIRTIO_QUEUE_MSIX_VECTOR_OFFSET(v)
vring_avail_t * avail
Definition: virtio_std.h:176
vhost_vring_addr_t addr
Definition: vhost_user.h:111
unsigned char u8
Definition: types.h:56
static u8 virtio_pci_modern_reset(vlib_main_t *vm, virtio_if_t *vif)
static void virtio_pci_modern_set_driver_features(vlib_main_t *vm, virtio_if_t *vif, u64 features)
u64 features
Definition: virtio.h:107
static u16 virtio_pci_modern_get_num_queues(virtio_if_t *vif)
#define VIRTIO_DEVICE_STATUS_OFFSET(v)
#define VIRTIO_QUEUE_NOTIFY_OFF_OFFSET(v)
static u8 virtio_pci_modern_get_status(vlib_main_t *vm, virtio_if_t *vif)
#define VIRTIO_DRIVER_FEATURE_OFFSET(v)
#define VIRTIO_STATUS_OFFSET(v)
unsigned int u32
Definition: types.h:88
#define VIRTIO_FEATURE_SELECT_LO
static u16 virtio_pci_modern_get_queue_enable(virtio_if_t *vif, u16 queue_id)
static u16 virtio_pci_modern_get_queue_size(vlib_main_t *vm, virtio_if_t *vif, u16 queue_id)
unsigned short u16
Definition: types.h:57
#define VIRTIO_CONFIG_GENERATION_OFFSET(v)
#define VIRTIO_QUEUE_SELECT_OFFSET(v)
static u16 virtio_pci_modern_set_queue_msix_vector(vlib_main_t *vm, virtio_if_t *vif, u16 queue_msix_vector, u16 queue_id)
static void virtio_pci_modern_set_status(vlib_main_t *vm, virtio_if_t *vif, u8 status)
vl_api_address_t dst
Definition: gre.api:55
vring_desc_t * desc
Definition: virtio_std.h:175
static u16 virtio_pci_modern_get_device_mtu(vlib_main_t *vm, virtio_if_t *vif)
#define virtio_log_debug(vif, f,...)
Definition: virtio.h:244
static u8 virtio_pci_modern_setup_queue(vlib_main_t *vm, virtio_if_t *vif, u16 queue_id, void *p)
u8 len
Definition: ip_types.api:92
#define VIRTIO_PCI_VRING_ALIGN
Definition: pci.h:90
static u64 virtio_pci_modern_get_queue_driver(virtio_if_t *vif)
static void virtio_pci_modern_set_queue_device(virtio_if_t *vif, u64 queue_device)
#define clib_warning(format, args...)
Definition: error.h:59
static_always_inline void vring_init(vring_t *vr, u32 num, void *p, u32 align)
Definition: virtio_std.h:181
static void virtio_pci_modern_set_queue_driver(virtio_if_t *vif, u64 queue_driver)
static u8 virtio_pci_modern_get_config_generation(virtio_if_t *vif)
static u64 virtio_pci_modern_get_device_features(vlib_main_t *vm, virtio_if_t *vif)
static void virtio_pci_modern_set_queue_size(vlib_main_t *vm, virtio_if_t *vif, u16 queue_id, u16 queue_size)
static u16 virtio_pci_modern_get_msix_config(virtio_if_t *vif)
static u64 virtio_pci_modern_get_driver_features(vlib_main_t *vm, virtio_if_t *vif)
static u8 virtio_pci_modern_get_isr(vlib_main_t *vm, virtio_if_t *vif)
#define VIRTIO_QUEUE_SIZE_OFFSET(v)
#define VIRTIO_FEATURE_SELECT_HI
static void virtio_pci_modern_device_debug_config_space(vlib_main_t *vm, virtio_if_t *vif)
static u16 virtio_pci_modern_get_device_status(vlib_main_t *vm, virtio_if_t *vif)
#define VIRTIO_QUEUE_DESC_OFFSET(v)
u32 mac_addr32
Definition: virtio.h:143
#define VIRTIO_MTU_OFFSET(v)
static uword is_pow2(uword x)
Definition: clib.h:252
static void virtio_pci_modern_del_queue(vlib_main_t *vm, virtio_if_t *vif, u16 queue_id)
#define VIRTIO_DEVICE_FEATURE_OFFSET(v)
static u64 vlib_physmem_get_pa(vlib_main_t *vm, void *mem)
static void virtio_pci_modern_write_config(vlib_main_t *vm, virtio_if_t *vif, void *src, int len, u32 addr)
#define VIRTIO_MSIX_CONFIG_VECTOR_OFFSET(v)
struct _virtio_pci_func virtio_pci_func_t
static void virtio_pci_modern_set_queue_select(virtio_if_t *vif, u16 queue_select)
#define VIRTIO_QUEUE_ENABLE_OFFSET(v)
#define VIRTIO_MAC_OFFSET(v)
static u16 virtio_pci_modern_set_msix_config(vlib_main_t *vm, virtio_if_t *vif, u16 msix_config)
u16 mac_addr16
Definition: virtio.h:144
static void virtio_pci_modern_get_device_mac(vlib_main_t *vm, virtio_if_t *vif)
#define VIRTIO_NOTIFICATION_OFFSET(v)
static u64 virtio_pci_modern_get_queue_device(virtio_if_t *vif)
static void virtio_pci_modern_set_queue_desc(virtio_if_t *vif, u64 queue_desc)
static void virtio_pci_modern_set_device_mac(vlib_main_t *vm, virtio_if_t *vif)
static u16 virtio_pci_modern_get_queue_msix_vector(virtio_if_t *vif)
#define VIRTIO_DRIVER_FEATURE_SELECT_OFFSET(v)
#define VIRTIO_DEVICE_FEATURE_SELECT_OFFSET(v)
static u16 virtio_pci_modern_get_queue_notify_off(vlib_main_t *vm, virtio_if_t *vif, u16 queue_id)