blob: a4e9eb2dda6cd816cc031bb8b0c94027aa55ef79 [file] [log] [blame]
Tom Jonesb2a357b2024-01-30 10:39:23 +00001/*
2 * SPDX-License-Identifier: Apache-2.0
3 * Copyright (c) 2024 Tom Jones <thj@freebsd.org>
4 *
5 * This software was developed by Tom Jones <thj@freebsd.org> under sponsorship
6 * from the FreeBSD Foundation.
7 *
8 */
9
10#include <vlib/vlib.h>
11#include <vlib/pci/pci.h>
12#include <vlib/unix/unix.h>
13
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <sys/ioctl.h>
17#include <sys/eventfd.h>
18
19#include <sys/pciio.h>
20
21#include <fcntl.h>
22#include <dirent.h>
23#include <net/if.h>
24
25extern vlib_pci_main_t freebsd_pci_main;
26
27uword
28vlib_pci_get_private_data (vlib_main_t *vm, vlib_pci_dev_handle_t h)
29{
30 return 0;
31}
32
33void
34vlib_pci_set_private_data (vlib_main_t *vm, vlib_pci_dev_handle_t h,
35 uword private_data)
36{
37}
38
39vlib_pci_addr_t *
40vlib_pci_get_addr (vlib_main_t *vm, vlib_pci_dev_handle_t h)
41{
42 return NULL;
43}
44
45u32
46vlib_pci_get_numa_node (vlib_main_t *vm, vlib_pci_dev_handle_t h)
47{
48 return 0;
49}
50
51u32
52vlib_pci_get_num_msix_interrupts (vlib_main_t *vm, vlib_pci_dev_handle_t h)
53{
54 return 0;
55}
56
57/* Call to allocate/initialize the pci subsystem.
58 This is not an init function so that users can explicitly enable
59 pci only when it's needed. */
60clib_error_t *pci_bus_init (vlib_main_t *vm);
61
62vlib_pci_device_info_t *
63vlib_pci_get_device_info (vlib_main_t *vm, vlib_pci_addr_t *addr,
64 clib_error_t **error)
65{
66 /* Populate a vlib_pci_device_info_t from the given address */
67 clib_error_t *err = NULL;
68 vlib_pci_device_info_t *di = NULL;
69
70 int fd = -1;
71 struct pci_conf_io pci;
72 struct pci_conf match;
73 struct pci_match_conf pattern;
74 bzero (&match, sizeof (match));
75 bzero (&pattern, sizeof (pattern));
76
77 pattern.pc_sel.pc_domain = addr->domain;
78 pattern.pc_sel.pc_bus = addr->bus;
79 pattern.pc_sel.pc_dev = addr->slot;
80 pattern.pc_sel.pc_func = addr->function;
81 pattern.flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS |
82 PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC;
83
84 pci.pat_buf_len = sizeof (pattern);
85 pci.num_patterns = 1;
86 pci.patterns = &pattern;
87 pci.match_buf_len = sizeof (match);
88 pci.num_matches = 1;
89 pci.matches = &match;
90 pci.offset = 0;
91 pci.generation = 0;
92 pci.status = 0;
93
94 fd = open ("/dev/pci", 0);
95 if (fd == -1)
96 {
97 err = clib_error_return_unix (0, "open '/dev/pci'");
98 goto error;
99 }
100
101 if (ioctl (fd, PCIOCGETCONF, &pci) == -1)
102 {
103 err = clib_error_return_unix (0, "reading PCIOCGETCONF");
104 goto error;
105 }
106
107 di = clib_mem_alloc (sizeof (vlib_pci_device_info_t));
108 clib_memset (di, 0, sizeof (vlib_pci_device_info_t));
109
110 di->addr.as_u32 = addr->as_u32;
111 di->numa_node = 0; /* TODO: Place holder until we have NUMA on FreeBSD */
112
113 di->device_class = match.pc_class;
114 di->vendor_id = match.pc_vendor;
115 di->device_id = match.pc_device;
116 di->revision = match.pc_revid;
117
118 di->product_name = NULL;
119 di->vpd_r = 0;
120 di->vpd_w = 0;
121 di->driver_name = format (0, "%s", &match.pd_name);
122 di->iommu_group = -1;
123
124 goto done;
125
126error:
127 vlib_pci_free_device_info (di);
128 di = NULL;
129done:
130 if (error)
131 *error = err;
132 close (fd);
133 return di;
134}
135
136clib_error_t *__attribute__ ((weak))
137vlib_pci_get_device_root_bus (vlib_pci_addr_t *addr, vlib_pci_addr_t *root_bus)
138{
139 return NULL;
140}
141
142clib_error_t *
143vlib_pci_bind_to_uio (vlib_main_t *vm, vlib_pci_addr_t *addr,
144 char *uio_drv_name, int force)
145{
146 clib_error_t *error = 0;
147
148 if (error)
149 {
150 return error;
151 }
152
153 if (strncmp ("auto", uio_drv_name, 5) == 0)
154 {
155 /* TODO: We should confirm that nic_uio is loaded and return an error. */
156 uio_drv_name = "nic_uio";
157 }
158 return error;
159}
160
161clib_error_t *
162vlib_pci_register_intx_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h,
163 pci_intx_handler_function_t *intx_handler)
164{
165 return NULL;
166}
167
168clib_error_t *
169vlib_pci_unregister_intx_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h)
170{
171 return NULL;
172}
173
174clib_error_t *
175vlib_pci_register_msix_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h,
176 u32 start, u32 count,
177 pci_msix_handler_function_t *msix_handler)
178{
179 return NULL;
180}
181
182clib_error_t *
183vlib_pci_unregister_msix_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h,
184 u32 start, u32 count)
185{
186 return NULL;
187}
188
189clib_error_t *
190vlib_pci_enable_msix_irq (vlib_main_t *vm, vlib_pci_dev_handle_t h, u16 start,
191 u16 count)
192{
193 return NULL;
194}
195
196uword
197vlib_pci_get_msix_file_index (vlib_main_t *vm, vlib_pci_dev_handle_t h,
198 u16 index)
199{
200 return 0;
201}
202
203clib_error_t *
204vlib_pci_disable_msix_irq (vlib_main_t *vm, vlib_pci_dev_handle_t h, u16 start,
205 u16 count)
206{
207 return NULL;
208}
209
210/* Configuration space read/write. */
211clib_error_t *
212vlib_pci_read_write_config (vlib_main_t *vm, vlib_pci_dev_handle_t h,
213 vlib_read_or_write_t read_or_write, uword address,
214 void *data, u32 n_bytes)
215{
216 return NULL;
217}
218
219clib_error_t *
220vlib_pci_map_region (vlib_main_t *vm, vlib_pci_dev_handle_t h, u32 resource,
221 void **result)
222{
223 return NULL;
224}
225
226clib_error_t *
227vlib_pci_map_region_fixed (vlib_main_t *vm, vlib_pci_dev_handle_t h,
228 u32 resource, u8 *addr, void **result)
229{
230 return NULL;
231}
232
233clib_error_t *
234vlib_pci_io_region (vlib_main_t *vm, vlib_pci_dev_handle_t h, u32 resource)
235{
236 return NULL;
237}
238
239clib_error_t *
240vlib_pci_read_write_io (vlib_main_t *vm, vlib_pci_dev_handle_t h,
241 vlib_read_or_write_t read_or_write, uword offset,
242 void *data, u32 length)
243{
244 return NULL;
245}
246
247clib_error_t *
248vlib_pci_map_dma (vlib_main_t *vm, vlib_pci_dev_handle_t h, void *ptr)
249{
250 return NULL;
251}
252
253int
254vlib_pci_supports_virtual_addr_dma (vlib_main_t *vm, vlib_pci_dev_handle_t h)
255{
256 return 0;
257}
258
259clib_error_t *
260vlib_pci_device_open (vlib_main_t *vm, vlib_pci_addr_t *addr,
261 pci_device_id_t ids[], vlib_pci_dev_handle_t *handle)
262{
263 return NULL;
264}
265
266void
267vlib_pci_device_close (vlib_main_t *vm, vlib_pci_dev_handle_t h)
268{
269}
270
271void
272init_device_from_registered (vlib_main_t *vm, vlib_pci_device_info_t *di)
273{
274}
275
276static int
277pci_addr_cmp (void *v1, void *v2)
278{
279 vlib_pci_addr_t *a1 = v1;
280 vlib_pci_addr_t *a2 = v2;
281
282 if (a1->domain > a2->domain)
283 return 1;
284 if (a1->domain < a2->domain)
285 return -1;
286 if (a1->bus > a2->bus)
287 return 1;
288 if (a1->bus < a2->bus)
289 return -1;
290 if (a1->slot > a2->slot)
291 return 1;
292 if (a1->slot < a2->slot)
293 return -1;
294 if (a1->function > a2->function)
295 return 1;
296 if (a1->function < a2->function)
297 return -1;
298 return 0;
299}
300
301vlib_pci_addr_t *
302vlib_pci_get_all_dev_addrs ()
303{
304 vlib_pci_addr_t *addrs = 0;
305
306 int fd = -1;
307 struct pci_conf_io pci;
308 struct pci_conf matches[32];
309 bzero (matches, sizeof (matches));
310
311 pci.pat_buf_len = 0;
312 pci.num_patterns = 0;
313 pci.patterns = NULL;
314 pci.match_buf_len = sizeof (matches);
315 pci.num_matches = 32;
316 pci.matches = (struct pci_conf *) &matches;
317 pci.offset = 0;
318 pci.generation = 0;
319 pci.status = 0;
320
321 fd = open ("/dev/pci", 0);
322 if (fd == -1)
323 {
324 clib_error_return_unix (0, "opening /dev/pci");
325 return (NULL);
326 }
327
328 if (ioctl (fd, PCIOCGETCONF, &pci) == -1)
329 {
330 clib_error_return_unix (0, "reading pci config");
331 close (fd);
332 return (NULL);
333 }
334
335 for (int i = 0; i < pci.num_matches; i++)
336 {
337 struct pci_conf *m = &pci.matches[i];
338 vlib_pci_addr_t addr;
339
340 addr.domain = m->pc_sel.pc_domain;
341 addr.bus = m->pc_sel.pc_bus;
342 addr.slot = m->pc_sel.pc_dev;
343 addr.function = m->pc_sel.pc_func;
344
345 vec_add1 (addrs, addr);
346 }
347
348 vec_sort_with_function (addrs, pci_addr_cmp);
349 close (fd);
350
351 return addrs;
352}
353
354clib_error_t *
355freebsd_pci_init (vlib_main_t *vm)
356{
357 vlib_pci_main_t *pm = &pci_main;
358 vlib_pci_addr_t *addr = 0, *addrs;
359
360 pm->vlib_main = vm;
361
362 ASSERT (sizeof (vlib_pci_addr_t) == sizeof (u32));
363
364 addrs = vlib_pci_get_all_dev_addrs ();
365 vec_foreach (addr, addrs)
366 {
367 vlib_pci_device_info_t *d;
368 if ((d = vlib_pci_get_device_info (vm, addr, 0)))
369 {
370 init_device_from_registered (vm, d);
371 vlib_pci_free_device_info (d);
372 }
373 }
374
375 return 0;
376}
377
378VLIB_INIT_FUNCTION (freebsd_pci_init) = {
379 .runs_after = VLIB_INITS ("unix_input_init"),
380};