blob: 1426a7035a21e0dcbc2fc40d6d1c80b32eb9c6bd [file] [log] [blame]
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001/*
2 * Copyright (c) 2018 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 <vlib/vlib.h>
17#include <vlib/pci/pci.h>
18#include <vnet/ethernet/ethernet.h>
19#include <vnet/ip/ip4_packet.h>
20#include <vnet/ip/ip6_packet.h>
21#include <vnet/devices/virtio/virtio.h>
22#include <vnet/devices/virtio/virtio_pci_legacy.h>
23#include <vnet/devices/virtio/pci.h>
24
25#define PCI_CONFIG_SIZE(vif) ((vif->msix_enabled == VIRTIO_MSIX_ENABLED) ? \
26 24 : 20)
27
28static void
29virtio_pci_legacy_read_config (vlib_main_t * vm, virtio_if_t * vif, void *dst,
30 int len, u32 addr)
31{
32 u32 size = 0;
33 vlib_pci_dev_handle_t h = vif->pci_dev_handle;
34
35 while (len > 0)
36 {
37 if (len >= 4)
38 {
39 size = 4;
40 vlib_pci_read_io_u32 (vm, h, PCI_CONFIG_SIZE (vif) + addr, dst);
41 }
42 else if (len >= 2)
43 {
44 size = 2;
45 vlib_pci_read_io_u16 (vm, h, PCI_CONFIG_SIZE (vif) + addr, dst);
46 }
47 else
48 {
49 size = 1;
50 vlib_pci_read_io_u8 (vm, h, PCI_CONFIG_SIZE (vif) + addr, dst);
51 }
52 dst = (u8 *) dst + size;
53 addr += size;
54 len -= size;
55 }
56}
57
58static void
59virtio_pci_legacy_write_config (vlib_main_t * vm, virtio_if_t * vif,
60 void *src, int len, u32 addr)
61{
62 u32 size = 0;
63 vlib_pci_dev_handle_t h = vif->pci_dev_handle;
64
65 while (len > 0)
66 {
67 if (len >= 4)
68 {
69 size = 4;
70 vlib_pci_write_io_u32 (vm, h, PCI_CONFIG_SIZE (vif) + addr, src);
71 }
72 else if (len >= 2)
73 {
74 size = 2;
75 vlib_pci_write_io_u16 (vm, h, PCI_CONFIG_SIZE (vif) + addr, src);
76 }
77 else
78 {
79 size = 1;
80 vlib_pci_write_io_u8 (vm, h, PCI_CONFIG_SIZE (vif) + addr, src);
81 }
82 src = (u8 *) src + size;
83 addr += size;
84 len -= size;
85 }
86}
87
88static u64
89virtio_pci_legacy_get_host_features (vlib_main_t * vm, virtio_if_t * vif)
90{
91 u32 host_features;
92 vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_HOST_FEATURES,
93 &host_features);
94 return host_features;
95}
96
97static u64
98virtio_pci_legacy_get_guest_features (vlib_main_t * vm, virtio_if_t * vif)
99{
100 u32 guest_features = 0;
101 vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
102 &guest_features);
103 vif->features = guest_features;
104 return guest_features;
105}
106
107static void
108virtio_pci_legacy_set_guest_features (vlib_main_t * vm, virtio_if_t * vif,
109 u64 guest_features)
110{
111 if ((guest_features >> 32) != 0)
112 {
113 clib_warning ("only 32 bit features are allowed for legacy virtio!");
114 }
115 u32 features = 0;
Mohsin Kazmi133c91c12020-08-20 17:18:56 +0200116 u32 gf = (u32) guest_features;
117
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000118 vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
Mohsin Kazmi133c91c12020-08-20 17:18:56 +0200119 &gf);
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000120 vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
121 &features);
122 if (features != (u32) guest_features)
123 {
124 clib_warning ("legacy set guest features failed!");
125 }
126}
127
128static u8
129virtio_pci_legacy_get_status (vlib_main_t * vm, virtio_if_t * vif)
130{
131 u8 status = 0;
132 vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_STATUS, &status);
133 return status;
134}
135
136static void
137virtio_pci_legacy_set_status (vlib_main_t * vm, virtio_if_t * vif, u8 status)
138{
139 if (status != VIRTIO_CONFIG_STATUS_RESET)
140 status |= virtio_pci_legacy_get_status (vm, vif);
141 vlib_pci_write_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_STATUS, &status);
142}
143
144static u8
145virtio_pci_legacy_reset (vlib_main_t * vm, virtio_if_t * vif)
146{
147 virtio_pci_legacy_set_status (vm, vif, VIRTIO_CONFIG_STATUS_RESET);
148 return virtio_pci_legacy_get_status (vm, vif);
149}
150
151static u8
152virtio_pci_legacy_get_isr (vlib_main_t * vm, virtio_if_t * vif)
153{
154 u8 isr = 0;
155 vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_ISR, &isr);
156 return isr;
157}
158
159static u16
160virtio_pci_legacy_get_queue_num (vlib_main_t * vm, virtio_if_t * vif,
161 u16 queue_id)
162{
163 u16 queue_num = 0;
164 vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
165 &queue_id);
166 vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NUM,
167 &queue_num);
168 return queue_num;
169}
170
171static void
172virtio_pci_legacy_set_queue_num (vlib_main_t * vm, virtio_if_t * vif,
173 u16 queue_id, u16 queue_size)
174{
175 /* do nothing */
176}
177
178static u8
179virtio_pci_legacy_setup_queue (vlib_main_t * vm, virtio_if_t * vif,
180 u16 queue_id, void *p)
181{
182 u64 addr = vlib_physmem_get_pa (vm, p) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
Mohsin Kazmi133c91c12020-08-20 17:18:56 +0200183 u32 addr2 = 0, a = (u32) addr;
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000184 vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
185 &queue_id);
Mohsin Kazmi133c91c12020-08-20 17:18:56 +0200186 vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN, &a);
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000187 vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN,
188 &addr2);
Mohsin Kazmi133c91c12020-08-20 17:18:56 +0200189 if (addr == addr2)
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000190 return 0;
191
192 clib_warning ("legacy queue setup failed!");
193 return 1;
194}
195
196static void
197virtio_pci_legacy_del_queue (vlib_main_t * vm, virtio_if_t * vif,
198 u16 queue_id)
199{
200 u32 src = 0;
201 vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
202 &queue_id);
203 vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN, &src);
204}
205
Mohsin Kazmi162a2962020-09-29 10:01:25 +0000206static u16
207virtio_pci_legacy_get_queue_notify_off (vlib_main_t * vm, virtio_if_t * vif,
208 u16 queue_id)
209{
210 return 0;
211}
212
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000213inline void
214virtio_pci_legacy_notify_queue (vlib_main_t * vm, virtio_if_t * vif,
Mohsin Kazmi162a2962020-09-29 10:01:25 +0000215 u16 queue_id, u16 queue_notify_off)
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000216{
217 vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NOTIFY,
218 &queue_id);
219}
220
221/* Enable one vector (0) for Link State Intrerrupt */
222static u16
223virtio_pci_legacy_set_config_irq (vlib_main_t * vm, virtio_if_t * vif,
224 u16 vec)
225{
226 vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_CONFIG_VECTOR,
227 &vec);
228 vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_CONFIG_VECTOR,
229 &vec);
230 return vec;
231}
232
233static u16
234virtio_pci_legacy_set_queue_irq (vlib_main_t * vm, virtio_if_t * vif, u16 vec,
235 u16 queue_id)
236{
237 vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
238 &queue_id);
239 vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_QUEUE_VECTOR,
240 &vec);
241 vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_QUEUE_VECTOR,
242 &vec);
243 return vec;
244}
245
246static void
247virtio_pci_legacy_get_mac (vlib_main_t * vm, virtio_if_t * vif)
248{
249 virtio_pci_legacy_read_config (vm, vif, vif->mac_addr,
250 sizeof (vif->mac_addr), 0);
251}
252
253static void
254virtio_pci_legacy_set_mac (vlib_main_t * vm, virtio_if_t * vif)
255{
256 virtio_pci_legacy_write_config (vm, vif, vif->mac_addr,
257 sizeof (vif->mac_addr), 0);
258}
259
260static u16
261virtio_pci_legacy_get_device_status (vlib_main_t * vm, virtio_if_t * vif)
262{
263 u16 status = 0;
264 virtio_pci_legacy_read_config (vm, vif, &status,
265 sizeof (status),
266 STRUCT_OFFSET_OF
267 (virtio_net_config_t, status));
268 return status;
269}
270
271static u16
272virtio_pci_legacy_get_max_queue_pairs (vlib_main_t * vm, virtio_if_t * vif)
273{
274 virtio_net_config_t config;
275 virtio_pci_legacy_read_config (vm, vif, &config.max_virtqueue_pairs,
276 sizeof (config.max_virtqueue_pairs),
277 STRUCT_OFFSET_OF
278 (virtio_net_config_t, max_virtqueue_pairs));
279 return config.max_virtqueue_pairs;
280}
281
282static u16
283virtio_pci_legacy_get_mtu (vlib_main_t * vm, virtio_if_t * vif)
284{
285 virtio_net_config_t config;
286 virtio_pci_legacy_read_config (vm, vif, &config.mtu,
287 sizeof (config.mtu),
288 STRUCT_OFFSET_OF (virtio_net_config_t, mtu));
289 return config.mtu;
290}
291
292
293static void
294virtio_pci_legacy_device_debug_config_space (vlib_main_t * vm,
295 virtio_if_t * vif)
296{
297 u32 data_u32;
298 u16 data_u16;
299 u8 data_u8;
300 vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_HOST_FEATURES,
301 &data_u32);
302 vlib_cli_output (vm, "remote features 0x%lx", data_u32);
303 vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
304 &data_u32);
305 vlib_cli_output (vm, "guest features 0x%lx", data_u32);
306 vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN,
307 &data_u32);
308 vlib_cli_output (vm, "queue address 0x%lx", data_u32);
309 vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NUM,
310 &data_u16);
311 vlib_cli_output (vm, "queue size 0x%x", data_u16);
312 vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
313 &data_u16);
314 vlib_cli_output (vm, "queue select 0x%x", data_u16);
315 vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NOTIFY,
316 &data_u16);
317 vlib_cli_output (vm, "queue notify 0x%x", data_u16);
318 vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_STATUS, &data_u8);
319 vlib_cli_output (vm, "status 0x%x", data_u8);
320 vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_ISR, &data_u8);
321 vlib_cli_output (vm, "isr 0x%x", data_u8);
322
323 if (vif->msix_enabled == VIRTIO_MSIX_ENABLED)
324 {
325 vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_CONFIG_VECTOR,
326 &data_u16);
327 vlib_cli_output (vm, "config vector 0x%x", data_u16);
328 u16 queue_id = 0;
329 vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
330 &queue_id);
331 vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_QUEUE_VECTOR,
332 &data_u16);
333 vlib_cli_output (vm, "queue vector for queue (0) 0x%x", data_u16);
334 }
335
336 u8 mac[6];
337 virtio_pci_legacy_read_config (vm, vif, mac, sizeof (mac), 0);
338 vlib_cli_output (vm, "mac %U", format_ethernet_address, mac);
339 virtio_pci_legacy_read_config (vm, vif, &data_u16, sizeof (u16), /* offset to status */
340 6);
341 vlib_cli_output (vm, "link up/down status 0x%x", data_u16);
342 virtio_pci_legacy_read_config (vm, vif, &data_u16, sizeof (u16),
343 /* offset to max_virtqueue */ 8);
344 vlib_cli_output (vm, "num of virtqueue 0x%x", data_u16);
345 virtio_pci_legacy_read_config (vm, vif, &data_u16, sizeof (u16), /* offset to mtu */
346 10);
347 vlib_cli_output (vm, "mtu 0x%x", data_u16);
348
349 u32 i = PCI_CONFIG_SIZE (vif) + 12, a = 4;
350 i += a;
351 i &= ~a;
352 for (; i < 64; i += 4)
353 {
354 u32 data = 0;
355 vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, i, &data);
356 vlib_cli_output (vm, "0x%lx", data);
357 }
358}
359
360const virtio_pci_func_t virtio_pci_legacy_func = {
361 .read_config = virtio_pci_legacy_read_config,
362 .write_config = virtio_pci_legacy_write_config,
363 .get_device_features = virtio_pci_legacy_get_host_features,
364 .get_driver_features = virtio_pci_legacy_get_guest_features,
365 .set_driver_features = virtio_pci_legacy_set_guest_features,
366 .get_status = virtio_pci_legacy_get_status,
367 .set_status = virtio_pci_legacy_set_status,
368 .device_reset = virtio_pci_legacy_reset,
369 .get_isr = virtio_pci_legacy_get_isr,
370 .get_queue_size = virtio_pci_legacy_get_queue_num,
371 .set_queue_size = virtio_pci_legacy_set_queue_num,
372 .setup_queue = virtio_pci_legacy_setup_queue,
373 .del_queue = virtio_pci_legacy_del_queue,
Mohsin Kazmi162a2962020-09-29 10:01:25 +0000374 .get_queue_notify_off = virtio_pci_legacy_get_queue_notify_off,
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000375 .notify_queue = virtio_pci_legacy_notify_queue,
376 .set_config_irq = virtio_pci_legacy_set_config_irq,
377 .set_queue_irq = virtio_pci_legacy_set_queue_irq,
378 .get_mac = virtio_pci_legacy_get_mac,
379 .set_mac = virtio_pci_legacy_set_mac,
380 .get_device_status = virtio_pci_legacy_get_device_status,
381 .get_max_queue_pairs = virtio_pci_legacy_get_max_queue_pairs,
382 .get_mtu = virtio_pci_legacy_get_mtu,
383 .device_debug_config_space = virtio_pci_legacy_device_debug_config_space,
384};
385
386/*
387 * fd.io coding-style-patch-verification: ON
388 *
389 * Local Variables:
390 * eval: (c-set-style "gnu")
391 * End:
392 */