FD.io VPP  v18.07-rc0-415-g6c78436
Vector Packet Processing
vfio.c
Go to the documentation of this file.
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 <unistd.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <linux/vfio.h>
21 #include <sys/ioctl.h>
22 
23 #include <vppinfra/linux/sysfs.h>
24 
25 #include <vlib/vlib.h>
26 #include <vlib/unix/unix.h>
27 #include <vlib/pci/pci.h>
28 #include <vlib/linux/vfio.h>
29 #include <vlib/physmem.h>
30 
31 #ifndef VFIO_NOIOMMU_IOMMU
32 #define VFIO_NOIOMMU_IOMMU 8
33 #endif
34 
36 
37 static int
39 {
42  struct vfio_iommu_type1_dma_map dm = { 0 };
43  int i;
44 
45  dm.argsz = sizeof (struct vfio_iommu_type1_dma_map);
46  dm.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
47 
48  /* *INDENT-OFF* */
49  pool_foreach (pr, vpm->regions,
50  {
51  vec_foreach_index (i, pr->page_table)
52  {
53  int rv;
54  dm.vaddr = pointer_to_uword (pr->mem) + (i << pr->log2_page_size);
55  dm.size = 1 << pr->log2_page_size;
56  dm.iova = dm.vaddr;
57  if ((rv = ioctl (fd, VFIO_IOMMU_MAP_DMA, &dm)))
58  return rv;
59  }
60  });
61  /* *INDENT-ON* */
62  return 0;
63 }
64 
65 void
67 {
69 
70  if (lvm->container_fd != -1)
71  map_regions (vm, lvm->container_fd);
72 }
73 
76 {
78  uword *p;
79 
80  p = hash_get (lvm->iommu_pool_index_by_group, group);
81 
82  return p ? pool_elt_at_index (lvm->iommu_groups, p[0]) : 0;
83 }
84 
85 static clib_error_t *
86 open_vfio_iommu_group (int group, int is_noiommu)
87 {
90  clib_error_t *err = 0;
91  struct vfio_group_status group_status;
92  u8 *s = 0;
93  int fd;
94 
95  g = get_vfio_iommu_group (group);
96  if (g)
97  {
98  g->refcnt++;
99  return 0;
100  }
101  s = format (s, "/dev/vfio/%s%u%c", is_noiommu ? "noiommu-" : "", group, 0);
102  fd = open ((char *) s, O_RDWR);
103  if (fd < 0)
104  return clib_error_return_unix (0, "open '%s'", s);
105 
106  group_status.argsz = sizeof (group_status);
107  if (ioctl (fd, VFIO_GROUP_GET_STATUS, &group_status) < 0)
108  {
109  err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_STATUS) '%s'",
110  s);
111  goto error;
112  }
113 
114  if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE))
115  {
116  err = clib_error_return (0, "iommu group %d is not viable (not all "
117  "devices in this group bound to vfio-pci)",
118  group);
119  goto error;
120  }
121 
122  if (ioctl (fd, VFIO_GROUP_SET_CONTAINER, &lvm->container_fd) < 0)
123  {
124  err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_SET_CONTAINER) '%s'",
125  s);
126  goto error;
127  }
128 
129  if (lvm->iommu_mode == 0)
130  {
131  if (is_noiommu)
133  else
134  lvm->iommu_mode = VFIO_TYPE1_IOMMU;
135 
136  if (ioctl (lvm->container_fd, VFIO_SET_IOMMU, lvm->iommu_mode) < 0)
137  {
138  err = clib_error_return_unix (0, "ioctl(VFIO_SET_IOMMU) "
139  "'/dev/vfio/vfio'");
140  goto error;
141  }
142  }
143 
144 
145  pool_get (lvm->iommu_groups, g);
146  g->fd = fd;
147  g->refcnt = 1;
148  hash_set (lvm->iommu_pool_index_by_group, group, g - lvm->iommu_groups);
149  vec_free (s);
150  return 0;
151 error:
152  close (fd);
153  return err;
154 }
155 
156 clib_error_t *
157 linux_vfio_group_get_device_fd (vlib_pci_addr_t * addr, int *fdp)
158 {
159  clib_error_t *err = 0;
161  u8 *s = 0;
162  int iommu_group;
163  u8 *tmpstr;
164  int fd;
165  int is_noiommu = 0;
166 
167  s = format (s, "/sys/bus/pci/devices/%U/iommu_group", format_vlib_pci_addr,
168  addr);
169  tmpstr = clib_sysfs_link_to_name ((char *) s);
170  if (tmpstr)
171  {
172  iommu_group = atoi ((char *) tmpstr);
173  vec_free (tmpstr);
174  }
175  else
176  {
177  err = clib_error_return (0, "Cannot find IOMMU group for PCI device ",
178  "'%U'", format_vlib_pci_addr, addr);
179  goto error;
180  }
181  vec_reset_length (s);
182 
183  s =
184  format (s, "/sys/bus/pci/devices/%U/iommu_group/name",
185  format_vlib_pci_addr, addr);
186  err = clib_sysfs_read ((char *) s, "%s", &tmpstr);
187  if (err == 0)
188  {
189  if (strncmp ((char *) tmpstr, "vfio-noiommu", 12) == 0)
190  is_noiommu = 1;
191  vec_free (tmpstr);
192  }
193  else
194  clib_error_free (err);
195  vec_reset_length (s);
196  if ((err = open_vfio_iommu_group (iommu_group, is_noiommu)))
197  return err;
198 
199  g = get_vfio_iommu_group (iommu_group);
200 
201  s = format (s, "%U%c", format_vlib_pci_addr, addr, 0);
202  if ((fd = ioctl (g->fd, VFIO_GROUP_GET_DEVICE_FD, (char *) s)) < 0)
203  {
204  err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_DEVICE_FD) '%U'",
205  format_vlib_pci_addr, addr);
206  goto error;
207  }
208  vec_reset_length (s);
209 
210  *fdp = fd;
211 
212 error:
213  vec_free (s);
214  return err;
215 }
216 
217 clib_error_t *
219 {
221  int fd;
222 
223  fd = open ("/dev/vfio/vfio", O_RDWR);
224 
225  /* check if iommu is available */
226  if (fd != -1)
227  {
228  if (ioctl (fd, VFIO_GET_API_VERSION) != VFIO_API_VERSION)
229  {
230  close (fd);
231  fd = -1;
232  }
233  else
234  {
235  if (ioctl (fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU) == 1)
237  if (ioctl (fd, VFIO_CHECK_EXTENSION, VFIO_NOIOMMU_IOMMU) == 1)
239  }
240  }
241 
242  lvm->iommu_pool_index_by_group = hash_create (0, sizeof (uword));
243  lvm->container_fd = fd;
244  return 0;
245 }
246 
247 /*
248  * fd.io coding-style-patch-verification: ON
249  *
250  * Local Variables:
251  * eval: (c-set-style "gnu")
252  * End:
253  */
format_function_t format_vlib_pci_addr
Definition: pci.h:288
#define hash_set(h, key, value)
Definition: hash.h:255
void linux_vfio_dma_map_regions(vlib_main_t *vm)
Definition: vfio.c:66
clib_error_t * linux_vfio_group_get_device_fd(vlib_pci_addr_t *addr, int *fdp)
Definition: vfio.c:157
static linux_pci_vfio_iommu_group_t * get_vfio_iommu_group(int group)
Definition: vfio.c:75
static int map_regions(vlib_main_t *vm, int fd)
Definition: vfio.c:38
int i
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
int iommu_mode
Definition: vfio.h:34
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:227
unsigned char u8
Definition: types.h:56
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
linux_pci_vfio_iommu_group_t * iommu_groups
Definition: vfio.h:37
#define LINUX_VFIO_F_HAVE_IOMMU
Definition: vfio.h:29
#define LINUX_VFIO_F_HAVE_NOIOMMU
Definition: vfio.h:30
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:440
#define clib_error_return(e, args...)
Definition: error.h:99
#define hash_get(h, key)
Definition: hash.h:249
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:461
#define clib_error_return_unix(e, args...)
Definition: error.h:102
#define VFIO_NOIOMMU_IOMMU
Definition: vfio.c:32
clib_error_t * linux_vfio_init(vlib_main_t *vm)
Definition: vfio.c:218
clib_error_t * clib_sysfs_read(char *file_name, char *fmt,...)
Definition: sysfs.c:50
vlib_main_t * vm
Definition: buffer.c:294
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
#define hash_create(elts, value_bytes)
Definition: hash.h:696
uword * iommu_pool_index_by_group
Definition: vfio.h:40
u64 uword
Definition: types.h:112
#define clib_error_free(e)
Definition: error.h:86
int container_fd
Definition: vfio.h:31
vlib_physmem_main_t physmem_main
Definition: main.c:64
static clib_error_t * open_vfio_iommu_group(int group, int is_noiommu)
Definition: vfio.c:86
vhost_vring_addr_t addr
Definition: vhost-user.h:83
vlib_physmem_region_t * regions
Definition: physmem.h:73
u8 * clib_sysfs_link_to_name(char *link)
Definition: sysfs.c:90
linux_vfio_main_t vfio_main
Definition: vfio.c:35