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