vlib: introduce DMA infrastructure
[vpp.git] / src / plugins / dma_intel / main.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright (c) 2022 Cisco Systems, Inc.
3  * Copyright (c) 2022 Intel and/or its affiliates.
4  */
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <vlib/vlib.h>
9 #include <vlib/pci/pci.h>
10 #include <vlib/dma/dma.h>
11 #include <vnet/plugin/plugin.h>
12 #include <vpp/app/version.h>
13 #include <vppinfra/linux/sysfs.h>
14 #include <dma_intel/dsa_intel.h>
15
16 VLIB_REGISTER_LOG_CLASS (intel_dsa_log, static) = {
17   .class_name = "intel_dsa",
18 };
19
20 intel_dsa_main_t intel_dsa_main;
21
22 void
23 intel_dsa_assign_channels (vlib_main_t *vm)
24 {
25   intel_dsa_main_t *idm = &intel_dsa_main;
26   intel_dsa_channel_t *ch, **chv = 0;
27   u16 n_threads;
28   int n;
29
30   vec_foreach_index (n, idm->channels)
31     vec_append (chv, idm->channels[n]);
32
33   vec_validate (idm->dsa_threads, vlib_get_n_threads () - 1);
34
35   if (vec_len (chv) == 0)
36     {
37       dsa_log_debug ("No DSA channels found");
38       goto done;
39     }
40
41   if (vec_len (chv) >= vlib_get_n_threads ())
42     n_threads = 1;
43   else
44     n_threads = vlib_get_n_threads () % vec_len (chv) ?
45                         vlib_get_n_threads () / vec_len (chv) + 1 :
46                         vlib_get_n_threads () / vec_len (chv);
47
48   for (int i = 0; i < vlib_get_n_threads (); i++)
49     {
50       vlib_main_t *tvm = vlib_get_main_by_index (i);
51       ch = *vec_elt_at_index (chv, i / n_threads);
52       idm->dsa_threads[i].ch = ch;
53       ch->n_threads = n_threads;
54       dsa_log_debug ("Assigning channel %u/%u to thread %u (numa %u)", ch->did,
55                      ch->qid, i, tvm->numa_node);
56     }
57
58 done:
59   /* free */
60   vec_free (chv);
61 }
62
63 static clib_error_t *
64 intel_dsa_map_region (intel_dsa_channel_t *ch)
65 {
66   static clib_error_t *error = NULL;
67   /* map one page */
68   uword size = 0x1000;
69   uword offset = 0;
70   char path[256] = { 0 };
71
72   snprintf (path, sizeof (path), "%s/wq%d.%d", DSA_DEV_PATH, ch->did, ch->qid);
73   int fd = open (path, O_RDWR);
74   if (fd < 0)
75     return clib_error_return (0, "failed to open dsa device %s", path);
76
77   ch->portal =
78     clib_mem_vm_map_shared (0, size, fd, offset, "%s", (char *) path);
79   if (ch->portal == CLIB_MEM_VM_MAP_FAILED)
80     {
81       error = clib_error_return (0, "mmap portal %s failed", path);
82       close (fd);
83       return error;
84     }
85
86   return NULL;
87 }
88
89 static clib_error_t *
90 intel_dsa_get_info (intel_dsa_channel_t *ch, clib_error_t **error)
91 {
92   clib_error_t *err;
93   u8 *tmpstr;
94   u8 *dev_dir_name = 0, *wq_dir_name = 0;
95
96   u8 *f = 0;
97   dev_dir_name = format (0, "%s/dsa%d", SYS_DSA_PATH, ch->did);
98
99   vec_reset_length (f);
100   f = format (f, "%v/numa_node%c", dev_dir_name, 0);
101   err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
102   if (err)
103     goto error;
104   ch->numa = atoi ((char *) tmpstr);
105
106   wq_dir_name = format (0, "%s/%U", SYS_DSA_PATH, format_intel_dsa_addr, ch);
107
108   vec_reset_length (f);
109   f = format (f, "%v/max_transfer_size%c", wq_dir_name, 0);
110   err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
111   if (err)
112     goto error;
113   ch->max_transfer_size = atoi ((char *) tmpstr);
114
115   vec_reset_length (f);
116   f = format (f, "%v/max_batch_size%c", wq_dir_name, 0);
117   err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
118   if (err)
119     goto error;
120   ch->max_transfers = atoi ((char *) tmpstr);
121
122   vec_reset_length (f);
123   f = format (f, "%v/size%c", wq_dir_name, 0);
124   err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
125   if (err)
126     goto error;
127   ch->size = atoi ((char *) tmpstr);
128
129   vec_reset_length (f);
130   f = format (f, "%v/type%c", wq_dir_name, 0);
131   err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
132   if (err)
133     goto error;
134   if (tmpstr)
135     {
136       if (!clib_strcmp ((char *) tmpstr, "enabled"))
137         ch->type = INTEL_DSA_DEVICE_TYPE_UNKNOWN;
138       else if (!clib_strcmp ((char *) tmpstr, "user"))
139         ch->type = INTEL_DSA_DEVICE_TYPE_USER;
140       else if (!clib_strcmp ((char *) tmpstr, "mdev"))
141         ch->type = INTEL_DSA_DEVICE_TYPE_KERNEL;
142       else
143         ch->type = INTEL_DSA_DEVICE_TYPE_UNKNOWN;
144       vec_free (tmpstr);
145     }
146
147   vec_reset_length (f);
148   f = format (f, "%v/state%c", wq_dir_name, 0);
149   err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
150   if (err)
151     goto error;
152   if (tmpstr)
153     {
154       if (!clib_strcmp ((char *) tmpstr, "enabled"))
155         ch->state = 1;
156       else
157         ch->state = 0;
158       vec_free (tmpstr);
159     }
160
161   vec_reset_length (f);
162   f = format (f, "%v/ats_disable%c", wq_dir_name, 0);
163   err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
164   if (err)
165     goto error;
166   ch->ats_disable = atoi ((char *) tmpstr);
167
168   vec_reset_length (f);
169   f = format (f, "%v/block_on_fault%c", wq_dir_name, 0);
170   err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
171   if (err)
172     goto error;
173   ch->block_on_fault = atoi ((char *) tmpstr);
174
175   vec_reset_length (f);
176   f = format (f, "%v/mode%c", wq_dir_name, 0);
177   err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
178   if (err)
179     goto error;
180   if (tmpstr)
181     {
182       if (!clib_strcmp ((char *) tmpstr, "dedicated"))
183         ch->mode = 1;
184       else
185         ch->mode = 0;
186       vec_free (tmpstr);
187     }
188
189   vec_free (f);
190   vec_free (dev_dir_name);
191   vec_free (wq_dir_name);
192   return NULL;
193
194 error:
195   vec_free (f);
196   vec_free (dev_dir_name);
197   vec_free (wq_dir_name);
198
199   return err;
200 }
201
202 clib_error_t *
203 intel_dsa_add_channel (vlib_main_t *vm, intel_dsa_channel_t *ch)
204 {
205   intel_dsa_main_t *dm = &intel_dsa_main;
206   clib_error_t *err = 0;
207
208   if (intel_dsa_map_region (ch))
209     return clib_error_return (0, "dsa open device failed");
210
211   if (intel_dsa_get_info (ch, &err))
212     return clib_error_return (err, "dsa info not scanned");
213
214   vec_validate (dm->channels, ch->numa);
215   vec_add1 (dm->channels[ch->numa], ch);
216
217   return err;
218 }
219
220 static clib_error_t *
221 dsa_config (vlib_main_t *vm, unformat_input_t *input)
222 {
223   clib_error_t *error = 0;
224   intel_dsa_channel_t *ch;
225   u8 did, qid;
226
227   if (intel_dsa_main.lock == 0)
228     clib_spinlock_init (&(intel_dsa_main.lock));
229
230   if ((error = vlib_dma_register_backend (vm, &intel_dsa_backend)))
231     goto done;
232
233   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
234     {
235       if (unformat (input, "dev wq%d.%d", &did, &qid))
236         {
237           ch = clib_mem_alloc_aligned (sizeof (*ch), CLIB_CACHE_LINE_BYTES);
238           clib_memset (ch, 0, sizeof (*ch));
239           ch->did = did;
240           ch->qid = qid;
241           if (intel_dsa_add_channel (vm, ch))
242             clib_mem_free (ch);
243         }
244       else if (unformat_skip_white_space (input))
245         ;
246       else
247         {
248           error = clib_error_return (0, "unknown input `%U'",
249                                      format_unformat_error, input);
250           goto done;
251         }
252     }
253
254 done:
255   return error;
256 }
257
258 VLIB_CONFIG_FUNCTION (dsa_config, "dsa");
259
260 clib_error_t *
261 intel_dsa_num_workers_change (vlib_main_t *vm)
262 {
263   intel_dsa_assign_channels (vm);
264   return 0;
265 }
266
267 VLIB_NUM_WORKERS_CHANGE_FN (intel_dsa_num_workers_change);
268
269 VLIB_PLUGIN_REGISTER () = {
270   .version = VPP_BUILD_VER,
271   .description = "Intel DSA Backend",
272 };