/* SPDX-License-Identifier: Apache-2.0 * Copyright (c) 2022 Cisco Systems, Inc. * Copyright (c) 2022 Intel and/or its affiliates. */ #include #include #include #include #include #include #include #include #include #include VLIB_REGISTER_LOG_CLASS (intel_dsa_log, static) = { .class_name = "intel_dsa", }; intel_dsa_main_t intel_dsa_main; void intel_dsa_assign_channels (vlib_main_t *vm) { intel_dsa_main_t *idm = &intel_dsa_main; intel_dsa_channel_t *ch, **chv = 0; u16 n_threads; int n; vec_foreach_index (n, idm->channels) vec_append (chv, idm->channels[n]); vec_validate (idm->dsa_threads, vlib_get_n_threads () - 1); if (vec_len (chv) == 0) { dsa_log_debug ("No DSA channels found"); goto done; } if (vec_len (chv) >= vlib_get_n_threads ()) n_threads = 1; else n_threads = vlib_get_n_threads () % vec_len (chv) ? vlib_get_n_threads () / vec_len (chv) + 1 : vlib_get_n_threads () / vec_len (chv); for (int i = 0; i < vlib_get_n_threads (); i++) { vlib_main_t *tvm = vlib_get_main_by_index (i); ch = *vec_elt_at_index (chv, i / n_threads); idm->dsa_threads[i].ch = ch; ch->n_threads = n_threads; dsa_log_debug ("Assigning channel %u/%u to thread %u (numa %u)", ch->did, ch->qid, i, tvm->numa_node); } done: /* free */ vec_free (chv); } static clib_error_t * intel_dsa_map_region (intel_dsa_channel_t *ch) { static clib_error_t *error = NULL; /* map one page */ uword size = 0x1000; uword offset = 0; char path[256] = { 0 }; snprintf (path, sizeof (path), "%s/wq%d.%d", DSA_DEV_PATH, ch->did, ch->qid); int fd = open (path, O_RDWR); if (fd < 0) return clib_error_return (0, "failed to open dsa device %s", path); ch->portal = clib_mem_vm_map_shared (0, size, fd, offset, "%s", (char *) path); if (ch->portal == CLIB_MEM_VM_MAP_FAILED) { error = clib_error_return (0, "mmap portal %s failed", path); close (fd); return error; } return NULL; } static clib_error_t * intel_dsa_get_info (intel_dsa_channel_t *ch, clib_error_t **error) { clib_error_t *err; u8 *tmpstr; u8 *dev_dir_name = 0, *wq_dir_name = 0; u8 *f = 0; dev_dir_name = format (0, "%s/dsa%d", SYS_DSA_PATH, ch->did); vec_reset_length (f); f = format (f, "%v/numa_node%c", dev_dir_name, 0); err = clib_sysfs_read ((char *) f, "%s", &tmpstr); if (err) goto error; ch->numa = atoi ((char *) tmpstr); wq_dir_name = format (0, "%s/%U", SYS_DSA_PATH, format_intel_dsa_addr, ch); vec_reset_length (f); f = format (f, "%v/max_transfer_size%c", wq_dir_name, 0); err = clib_sysfs_read ((char *) f, "%s", &tmpstr); if (err) goto error; ch->max_transfer_size = atoi ((char *) tmpstr); vec_reset_length (f); f = format (f, "%v/max_batch_size%c", wq_dir_name, 0); err = clib_sysfs_read ((char *) f, "%s", &tmpstr); if (err) goto error; ch->max_transfers = atoi ((char *) tmpstr); vec_reset_length (f); f = format (f, "%v/size%c", wq_dir_name, 0); err = clib_sysfs_read ((char *) f, "%s", &tmpstr); if (err) goto error; ch->size = atoi ((char *) tmpstr); vec_reset_length (f); f = format (f, "%v/type%c", wq_dir_name, 0); err = clib_sysfs_read ((char *) f, "%s", &tmpstr); if (err) goto error; if (tmpstr) { if (!clib_strcmp ((char *) tmpstr, "enabled")) ch->type = INTEL_DSA_DEVICE_TYPE_UNKNOWN; else if (!clib_strcmp ((char *) tmpstr, "user")) ch->type = INTEL_DSA_DEVICE_TYPE_USER; else if (!clib_strcmp ((char *) tmpstr, "mdev")) ch->type = INTEL_DSA_DEVICE_TYPE_KERNEL; else ch->type = INTEL_DSA_DEVICE_TYPE_UNKNOWN; vec_free (tmpstr); } vec_reset_length (f); f = format (f, "%v/state%c", wq_dir_name, 0); err = clib_sysfs_read ((char *) f, "%s", &tmpstr); if (err) goto error; if (tmpstr) { if (!clib_strcmp ((char *) tmpstr, "enabled")) ch->state = 1; else ch->state = 0; vec_free (tmpstr); } vec_reset_length (f); f = format (f, "%v/ats_disable%c", wq_dir_name, 0); err = clib_sysfs_read ((char *) f, "%s", &tmpstr); if (err) goto error; ch->ats_disable = atoi ((char *) tmpstr); vec_reset_length (f); f = format (f, "%v/block_on_fault%c", wq_dir_name, 0); err = clib_sysfs_read ((char *) f, "%s", &tmpstr); if (err) goto error; ch->block_on_fault = atoi ((char *) tmpstr); vec_reset_length (f); f = format (f, "%v/mode%c", wq_dir_name, 0); err = clib_sysfs_read ((char *) f, "%s", &tmpstr); if (err) goto error; if (tmpstr) { if (!clib_strcmp ((char *) tmpstr, "dedicated")) ch->mode = 1; else ch->mode = 0; vec_free (tmpstr); } vec_free (f); vec_free (dev_dir_name); vec_free (wq_dir_name); return NULL; error: vec_free (f); vec_free (dev_dir_name); vec_free (wq_dir_name); return err; } clib_error_t * intel_dsa_add_channel (vlib_main_t *vm, intel_dsa_channel_t *ch) { intel_dsa_main_t *dm = &intel_dsa_main; clib_error_t *err = 0; if (intel_dsa_map_region (ch)) return clib_error_return (0, "dsa open device failed"); if (intel_dsa_get_info (ch, &err)) return clib_error_return (err, "dsa info not scanned"); vec_validate (dm->channels, ch->numa); vec_add1 (dm->channels[ch->numa], ch); return err; } static clib_error_t * dsa_config (vlib_main_t *vm, unformat_input_t *input) { clib_error_t *error = 0; intel_dsa_channel_t *ch; u32 did, qid; if (intel_dsa_main.lock == 0) clib_spinlock_init (&(intel_dsa_main.lock)); if ((error = vlib_dma_register_backend (vm, &intel_dsa_backend))) goto done; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "dev wq%d.%d", &did, &qid)) { ch = clib_mem_alloc_aligned (sizeof (*ch), CLIB_CACHE_LINE_BYTES); clib_memset (ch, 0, sizeof (*ch)); ch->did = did; ch->qid = qid; if (intel_dsa_add_channel (vm, ch)) clib_mem_free (ch); } else if (unformat_skip_white_space (input)) ; else { error = clib_error_return (0, "unknown input `%U'", format_unformat_error, input); goto done; } } done: return error; } VLIB_CONFIG_FUNCTION (dsa_config, "dsa"); clib_error_t * intel_dsa_num_workers_change (vlib_main_t *vm) { intel_dsa_assign_channels (vm); return 0; } VLIB_NUM_WORKERS_CHANGE_FN (intel_dsa_num_workers_change); VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER, .description = "Intel DSA Backend", };