Rework of DPDK PCI device uio driver binding process
[vpp.git] / vlib / vlib / unix / pci.c
1 /*
2  * Copyright (c) 2015 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  * pci.c: Linux user space PCI bus management.
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include <vlib/vlib.h>
41 #include <vlib/pci/pci.h>
42 #include <vlib/unix/unix.h>
43 #include <vlib/unix/pci.h>
44
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #include <dirent.h>
49 #include <sys/ioctl.h>
50 #include <net/if.h>
51 #include <linux/ethtool.h>
52 #include <linux/sockios.h>
53
54
55 linux_pci_main_t linux_pci_main;
56
57 clib_error_t *
58 vlib_pci_bind_to_uio (vlib_pci_device_t * d, char * uio_driver_name)
59 {
60   clib_error_t * error = 0;
61   u8 *s = 0;
62   DIR *dir = 0;
63   struct dirent *e;
64   int fd;
65   pci_config_header_t * c;
66   u8 * dev_dir_name = format(0, "/sys/bus/pci/devices/%U",
67                              format_vlib_pci_addr, &d->bus_address);
68
69   c = &d->config0.header;
70
71   /* if uio sub-directory exists, we are fine, device is
72      already bound to UIO driver */
73   s = format (s, "%v/uio%c", dev_dir_name, 0);
74   if (access ( (char *) s, F_OK) == 0)
75     goto done;
76   vec_reset_length (s);
77
78   /* walk trough all linux interfaces and if interface belonging to
79      this device is founf check if interface is admin up  */
80   dir = opendir ("/sys/class/net");
81   s = format(s, "%U%c", format_vlib_pci_addr, &d->bus_address, 0);
82
83   if (!dir)
84     {
85       error = clib_error_return (0, "Skipping PCI device %U: failed to "
86                                  "read /sys/class/net",
87                                  format_vlib_pci_addr, &d->bus_address);
88       goto done;
89     }
90
91   fd = socket(PF_INET, SOCK_DGRAM, 0);
92
93   while((e = readdir (dir)))
94     {
95       struct ifreq ifr;
96       struct ethtool_drvinfo drvinfo;
97
98       if (e->d_name[0] == '.') /* skip . and .. */
99         continue;
100
101       memset(&ifr, 0, sizeof ifr);
102       memset(&drvinfo, 0, sizeof drvinfo);
103       ifr.ifr_data = (char *) &drvinfo;
104       strncpy(ifr.ifr_name, e->d_name, IFNAMSIZ);
105       drvinfo.cmd = ETHTOOL_GDRVINFO;
106       ioctl (fd, SIOCETHTOOL, &ifr);
107
108       if (strcmp ((char *) s, drvinfo.bus_info))
109         continue;
110
111       memset (&ifr, 0, sizeof(ifr));
112       strncpy (ifr.ifr_name, e->d_name, IFNAMSIZ);
113       ioctl (fd, SIOCGIFFLAGS, &ifr);
114       close (fd);
115
116       if (ifr.ifr_flags & IFF_UP)
117         {
118           error = clib_error_return (0, "Skipping PCI device %U as host "
119                                      "interface %s is up",
120                                      format_vlib_pci_addr, &d->bus_address,
121                                      e->d_name);
122           goto done;
123         }
124     }
125
126   close (fd);
127   vec_reset_length (s);
128
129   s = format (s, "%v/driver/unbind%c", dev_dir_name, 0);
130   write_sys_fs ((char *) s, "%U", format_vlib_pci_addr, &d->bus_address);
131   vec_reset_length (s);
132
133   s = format (s, "/sys/bus/pci/drivers/%s/new_id%c", uio_driver_name, 0);
134   write_sys_fs ((char *) s, "0x%04x 0x%04x", c->vendor_id, c->device_id);
135   vec_reset_length (s);
136
137   s = format (s, "/sys/bus/pci/drivers/%s/bind%c", uio_driver_name, 0);
138   write_sys_fs ((char *) s, "%U", format_vlib_pci_addr, &d->bus_address);
139
140 done:
141   closedir (dir);
142   vec_free (s);
143   vec_free (dev_dir_name);
144   return error;
145 }
146
147
148 static clib_error_t *
149 scan_uio_dir (void * arg, u8 * path_name, u8 * file_name)
150 {
151   linux_pci_device_t * l = arg;
152   unformat_input_t input;
153
154   unformat_init_string (&input, (char *) file_name, vec_len (file_name));
155
156   if (! unformat (&input, "uio%d", &l->uio_minor))
157     abort ();
158
159   unformat_free (&input);
160   return 0;
161 }
162
163 static clib_error_t * linux_pci_uio_read_ready (unix_file_t * uf)
164 {
165   linux_pci_main_t * pm = &linux_pci_main;
166   vlib_main_t * vm = pm->vlib_main;
167   linux_pci_device_t * l;
168   u32 li = uf->private_data;
169
170   l = pool_elt_at_index (pm->linux_pci_devices, li);
171   vlib_node_set_interrupt_pending (vm, l->device_input_node_index);
172
173   /* Let node know which device is interrupting. */
174   {
175     vlib_node_runtime_t * rt = vlib_node_get_runtime (vm, l->device_input_node_index);
176     rt->runtime_data[0] |= 1 << l->device_index;
177   }
178
179   return /* no error */ 0;
180 }
181
182 static clib_error_t *linux_pci_uio_error_ready (unix_file_t *uf)
183 {
184   u32 error_index = (u32) uf->private_data;
185
186   return clib_error_return (0, "pci device %d: error", error_index);
187 }
188
189 static uword pci_resource_size (uword os_handle, uword resource)
190 {
191   linux_pci_main_t * pm = &linux_pci_main;
192   linux_pci_device_t * p;
193   u8 * file_name;
194   struct stat b;
195   uword result = 0;
196
197   p = pool_elt_at_index (pm->linux_pci_devices, os_handle);
198
199   file_name = format (0, "%v/resource%d%c", p->dev_dir_name, resource, 0);
200   if (stat ((char *) file_name, &b) >= 0)
201     result = b.st_size;
202   vec_free (file_name);
203   return result;
204 }
205
206 void os_add_pci_disable_interrupts_reg (uword os_handle, u32 resource,
207                                         u32 reg_offset, u32 reg_value)
208 {
209   linux_pci_main_t * pm = &linux_pci_main;
210   linux_pci_device_t * l;
211   char * file_name;
212   clib_error_t * error;
213
214   l = pool_elt_at_index (pm->linux_pci_devices, os_handle);
215   ASSERT (resource == 0);
216   ASSERT (reg_offset < pci_resource_size (os_handle, resource));
217   file_name = (char *) format (0, "%s/disable_interrupt_regs%c", l->dev_dir_name, 0);
218   error = write_sys_fs (file_name, "%x %x", reg_offset, reg_value);
219   if (error)
220     clib_error_report (error);
221   vec_free (file_name);
222 }
223
224 static void add_device (vlib_pci_device_t * dev, linux_pci_device_t * pdev)
225 {
226   linux_pci_main_t * pm = &linux_pci_main;
227   linux_pci_device_t * l;
228   pci_config_header_t * c;
229   u32 x[4];
230   clib_error_t * error;
231
232   c = &dev->config0.header;
233
234   pool_get (pm->linux_pci_devices, l);
235   l[0] = pdev[0];
236
237   l->dev_dir_name = vec_dup (l->dev_dir_name);
238
239   dev->os_handle = l - pm->linux_pci_devices;
240
241   error = write_sys_fs ("/sys/bus/pci/drivers/uio_pci_dma/new_id",
242                         "%x %x", c->vendor_id, c->device_id);
243   if (error)
244     clib_error_report (error);
245   error = write_sys_fs ("/sys/bus/pci/drivers/uio_pci_dma/bind",
246                         "%04x:%02x:%02x.%x", x[0], x[1], x[2], x[3]);
247   /* Errors happen when re-binding so just ignore them. */
248   if (error)
249     clib_error_free (error);
250
251   {
252     u8 * uio_dir = format (0, "%s/uio", l->dev_dir_name);
253     foreach_directory_file ((char *) uio_dir, scan_uio_dir, l, /* scan_dirs */ 1);
254     vec_free (uio_dir);
255   }
256
257   {
258     char * uio_name = (char *) format (0, "/dev/uio%d%c", l->uio_minor, 0);
259     l->uio_fd = open (uio_name, O_RDWR);
260     if (l->uio_fd < 0)
261       clib_unix_error ("open `%s'", uio_name);
262     vec_free (uio_name);
263   }
264
265   {
266     unix_file_t template = {0};
267     unix_main_t * um = &unix_main;
268
269     template.read_function = linux_pci_uio_read_ready;
270     template.file_descriptor = l->uio_fd;
271     template.error_function = linux_pci_uio_error_ready;
272     template.private_data = l - pm->linux_pci_devices;
273
274     /* To be filled in by driver. */
275     l->device_input_node_index = ~0;
276     l->device_index = 0;
277
278     l->unix_file_index = unix_file_add (um, &template);
279   }
280 }
281
282 static void linux_pci_device_free (linux_pci_device_t * l)
283 {
284   int i;
285   for (i = 0; i < vec_len (l->resource_fds); i++)
286     if (l->resource_fds[i] > 0)
287       close (l->resource_fds[i]);
288   if (l->config_fd > 0)
289     close (l->config_fd);
290   if (l->uio_fd > 0)
291     close (l->uio_fd);
292   vec_free (l->resource_fds);
293   vec_free (l->dev_dir_name);
294 }
295
296 /* Configuration space read/write. */
297 clib_error_t *
298 os_read_write_pci_config (uword os_handle,
299                           vlib_read_or_write_t read_or_write,
300                           uword address,
301                           void * data,
302                           u32 n_bytes)
303 {
304   linux_pci_main_t * pm = &linux_pci_main;
305   linux_pci_device_t * p;
306   int n;
307
308   p = pool_elt_at_index (pm->linux_pci_devices, os_handle);
309
310   if (address != lseek (p->config_fd, address, SEEK_SET))
311     return clib_error_return_unix (0, "seek offset %d", address);
312
313   if (read_or_write == VLIB_READ)
314     n = read (p->config_fd, data, n_bytes);
315   else
316     n = write (p->config_fd, data, n_bytes);
317
318   if (n != n_bytes)
319     return clib_error_return_unix (0, "%s",
320                                    read_or_write == VLIB_READ
321                                    ? "read" : "write");
322
323   return 0;
324 }
325
326 static clib_error_t *
327 os_map_pci_resource_internal (uword os_handle,
328                               u32 resource,
329                               u8 *addr,
330                               void ** result)
331 {
332   linux_pci_main_t * pm = &linux_pci_main;
333   linux_pci_device_t * p;
334   struct stat stat_buf;
335   u8 * file_name;
336   int fd;
337   clib_error_t * error;
338   int flags = MAP_SHARED;
339
340   error = 0;
341   p = pool_elt_at_index (pm->linux_pci_devices, os_handle);
342
343   file_name = format (0, "%v/resource%d%c", p->dev_dir_name, resource, 0);
344   fd = open ((char *) file_name, O_RDWR);
345   if (fd < 0)
346     {
347       error = clib_error_return_unix (0, "open `%s'", file_name);
348       goto done;
349     }
350
351   if (fstat (fd, &stat_buf) < 0)
352     {
353       error = clib_error_return_unix (0, "fstat `%s'", file_name);
354       goto done;
355     }
356
357   vec_validate (p->resource_fds, resource);
358   p->resource_fds[resource] = fd;
359   if (addr != 0)
360     flags |= MAP_FIXED;
361
362   *result = mmap (addr,
363                   /* size */ stat_buf.st_size,
364                   PROT_READ | PROT_WRITE,
365                   flags,
366                   /* file */ fd,
367                   /* offset */ 0);
368   if (*result == (void *) -1)
369     {
370       error = clib_error_return_unix (0, "mmap `%s'", file_name);
371       goto done;
372     }
373
374  done:
375   if (error)
376     {
377       if (fd > 0)
378         close (fd);
379     }
380   vec_free (file_name);
381   return error;
382 }
383
384 clib_error_t *
385 os_map_pci_resource (uword os_handle,
386                      u32 resource,
387                      void ** result)
388 {
389   return (os_map_pci_resource_internal (os_handle, resource, 0 /* addr */,
390                                         result));
391 }
392
393 clib_error_t *
394 os_map_pci_resource_fixed (uword os_handle,
395                            u32 resource,
396                            u8 *addr,
397                            void ** result)
398 {
399   return (os_map_pci_resource_internal (os_handle, resource, addr, result));
400 }
401
402 void os_free_pci_device (uword os_handle)
403 {
404   linux_pci_main_t * pm = &linux_pci_main;
405   linux_pci_device_t * l;
406
407   l = pool_elt_at_index (pm->linux_pci_devices, os_handle);
408   linux_pci_device_free (l);
409   pool_put (pm->linux_pci_devices, l);
410 }
411
412 u8 * format_os_pci_handle (u8 * s, va_list * va)
413 {
414   linux_pci_main_t * pm = &linux_pci_main;
415   uword os_pci_handle = va_arg (*va, uword);
416   linux_pci_device_t * l;
417
418   l = pool_elt_at_index (pm->linux_pci_devices, os_pci_handle);
419   return format (s, "%x/%x/%x", l->bus_address.bus,
420                  l->bus_address.slot, l->bus_address.function);
421 }
422
423 static inline pci_device_registration_t *
424 pci_device_next_registered (pci_device_registration_t * r)
425 {
426   uword i;
427
428   /* Null vendor id marks end of initialized list. */
429   for (i = 0; r->supported_devices[i].vendor_id != 0; i++)
430     ;
431
432   return clib_elf_section_data_next (r, i * sizeof (r->supported_devices[0]));
433 }
434
435 static inline u8 kernel_driver_installed (pci_device_registration_t *r)
436 {
437   u8 * link_name;
438   struct stat b;
439
440   link_name = format (0, "/sys/bus/pci/drivers/%s", r->kernel_driver);
441   if (stat ((char *)link_name, &b) >= 0)
442     r->kernel_driver_running++;
443   else
444     r->kernel_driver_running=0;
445
446   vec_free (link_name);
447   return r->kernel_driver_running;
448 }
449
450 static clib_error_t *
451 init_device_from_registered (vlib_main_t * vm,
452                              vlib_pci_device_t * dev,
453                              linux_pci_device_t * pdev)
454 {
455   linux_pci_main_t * lpm = &linux_pci_main;
456   pci_device_registration_t * r;
457   pci_device_id_t * i;
458   pci_config_header_t * c;
459
460   c = &dev->config0.header;
461
462   r = lpm->pci_device_registrations;
463
464   while (r)
465     {
466       for (i = r->supported_devices; i->vendor_id != 0; i++)
467         if (i->vendor_id == c->vendor_id && i->device_id == c->device_id)
468           {
469             if (r->kernel_driver && kernel_driver_installed(r))
470               {
471                 if (r->kernel_driver_running == 1)
472                   {
473                     clib_warning("PCI device type [%04x:%04x] is busy!\n"
474                                  "\tUninstall the associated linux kernel "
475                                  "driver:  sudo rmmod %s",
476                                  c->vendor_id, c->device_id, r->kernel_driver);
477                   }
478                 continue;
479               }
480             add_device (dev, pdev);
481             return r->init_function (vm, dev);
482           }
483       r = r->next_registration;
484   }
485   /* No driver, close the PCI config-space FD */
486   close (pdev->config_fd);
487   return 0;
488 }
489
490 static clib_error_t *
491 init_device (vlib_main_t * vm,
492              vlib_pci_device_t * dev,
493              linux_pci_device_t * pdev)
494 {
495   return init_device_from_registered (vm, dev, pdev);
496 }
497
498 static clib_error_t *
499 scan_device (void * arg, u8 * dev_dir_name, u8 * ignored)
500 {
501   vlib_main_t * vm = arg;
502   linux_pci_main_t * pm = &linux_pci_main;
503   int fd;
504   u8 * f;
505   clib_error_t * error = 0;
506   vlib_pci_device_t * dev;
507   linux_pci_device_t pdev = {0};
508
509   f = format (0, "%v/config%c", dev_dir_name, 0);
510   fd = open ((char *) f, O_RDWR);
511
512   /* Try read-only access if write fails. */
513   if (fd < 0)
514     fd = open ((char *) f, O_RDONLY);
515
516   if (fd < 0)
517     {
518       error = clib_error_return_unix (0, "open `%s'", f);
519       goto done;
520     }
521
522   pool_get (pm->pci_devs, dev);
523
524   /* You can only read more that 64 bytes of config space as root; so we try to
525      read the full space but fall back to just the first 64 bytes. */
526   if (read (fd, &dev->config_data, sizeof (dev->config_data)) != sizeof (dev->config_data)
527       && read (fd, &dev->config0, sizeof (dev->config0)) != sizeof (dev->config0))
528     {
529       pool_put (pm->pci_devs, dev);
530       error = clib_error_return_unix (0, "read `%s'", f);
531       goto done;
532     }
533
534   {
535     static pci_config_header_t all_ones;
536     if (all_ones.vendor_id == 0)
537       memset (&all_ones, ~0, sizeof (all_ones));
538
539     if (! memcmp (&dev->config0.header, &all_ones, sizeof (all_ones)))
540       {
541         pool_put (pm->pci_devs, dev);
542         error = clib_error_return (0, "invalid PCI config for `%s'", f);
543         goto done;
544       }
545   }
546
547   if (dev->config0.header.header_type == 0)
548     pci_config_type0_little_to_host (&dev->config0);
549   else
550     pci_config_type1_little_to_host (&dev->config1);
551
552   /* Parse bus, dev, function from directory name. */
553   {
554     unformat_input_t input;
555
556     unformat_init_string (&input, (char *) dev_dir_name,
557                           vec_len (dev_dir_name));
558
559     if (! unformat (&input, "/sys/bus/pci/devices/%U",
560                     unformat_vlib_pci_addr, &dev->bus_address))
561       abort ();
562
563     unformat_free (&input);
564
565     pdev.bus_address = dev->bus_address;
566   }
567
568
569   pdev.config_fd = fd;
570   pdev.dev_dir_name = dev_dir_name;
571
572   hash_set(pm->pci_dev_index_by_pci_addr, dev->bus_address.as_u32,
573            dev - pm->pci_devs);
574
575   error = init_device (vm, dev, &pdev);
576
577  done:
578   vec_free (f);
579   return error;
580 }
581
582 clib_error_t * pci_bus_init (vlib_main_t * vm)
583 {
584   linux_pci_main_t * pm = &linux_pci_main;
585   clib_error_t * error;
586
587   pm->vlib_main = vm;
588
589   if ((error = vlib_call_init_function (vm, unix_input_init)))
590     return error;
591
592   ASSERT(sizeof(vlib_pci_addr_t) == sizeof(u32));
593   pm->pci_dev_index_by_pci_addr = hash_create (0, sizeof (uword));
594
595   error = foreach_directory_file ("/sys/bus/pci/devices", scan_device, vm, /* scan_dirs */ 0);
596
597   /* Complain and continue. might not be root, etc. */
598   if (error)
599     clib_error_report (error);
600
601   return error;
602 }
603
604 VLIB_INIT_FUNCTION (pci_bus_init);