1426a7035a21e0dcbc2fc40d6d1c80b32eb9c6bd
[vpp.git] / src / vnet / devices / virtio / virtio_pci_legacy.c
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 virtio_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
58 static void
59 virtio_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
88 static u64
89 virtio_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
97 static u64
98 virtio_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
107 static void
108 virtio_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;
116   u32 gf = (u32) guest_features;
117
118   vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
119                          &gf);
120   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
128 static u8
129 virtio_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
136 static void
137 virtio_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
144 static u8
145 virtio_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
151 static u8
152 virtio_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
159 static u16
160 virtio_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
171 static void
172 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 }
177
178 static u8
179 virtio_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;
183   u32 addr2 = 0, a = (u32) addr;
184   vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
185                          &queue_id);
186   vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN, &a);
187   vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN,
188                         &addr2);
189   if (addr == addr2)
190     return 0;
191
192   clib_warning ("legacy queue setup failed!");
193   return 1;
194 }
195
196 static void
197 virtio_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
206 static u16
207 virtio_pci_legacy_get_queue_notify_off (vlib_main_t * vm, virtio_if_t * vif,
208                                         u16 queue_id)
209 {
210   return 0;
211 }
212
213 inline void
214 virtio_pci_legacy_notify_queue (vlib_main_t * vm, virtio_if_t * vif,
215                                 u16 queue_id, u16 queue_notify_off)
216 {
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 */
222 static u16
223 virtio_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
233 static u16
234 virtio_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
246 static void
247 virtio_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
253 static void
254 virtio_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
260 static u16
261 virtio_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
271 static u16
272 virtio_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
282 static u16
283 virtio_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
293 static void
294 virtio_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
360 const 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,
374   .get_queue_notify_off = virtio_pci_legacy_get_queue_notify_off,
375   .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  */