+ unformat_free (line_input);
+
+ if (auto_en)
+ {
+ crypto_auto_placement ();
+ return 0;
+ }
+
+ /* TODO support device name */
+
+ if (!(dev_idx < vec_len (dcm->dev)))
+ return clib_error_return (0, "please specify valid device index");
+
+ if (thread_idx != (u32) ~ 0 && !(thread_idx < vec_len (dcm->workers_main)))
+ return clib_error_return (0, "invalid thread index");
+
+ dev = vec_elt_at_index (dcm->dev, dev_idx);
+ if (!(vec_len (dev->free_resources)))
+ return clib_error_return (0, "all device resources are being used");
+
+ /* Check thread is not already using the device */
+ /* *INDENT-OFF* */
+ vec_foreach (idx, dev->used_resources)
+ if (dcm->resource[idx[0]].thread_idx == thread_idx)
+ return clib_error_return (0, "thread %u already using device %u",
+ thread_idx, dev_idx);
+ /* *INDENT-ON* */
+
+ res_idx = vec_pop (dev->free_resources);
+ vec_add1 (dev->used_resources, res_idx);
+
+ cwm = vec_elt_at_index (dcm->workers_main, thread_idx);
+
+ ASSERT (dcm->resource[res_idx].thread_idx == (u16) ~ 0);
+ dcm->resource[res_idx].thread_idx = thread_idx;
+
+ /* Add device to vector of polling resources */
+ vec_add1 (cwm->resource_idx, res_idx);
+
+ /* Set device as default for all supported algos */
+ for (i = 0; i < IPSEC_CRYPTO_N_ALG; i++)
+ if (dev->cipher_support[i])
+ {
+ if (cwm->cipher_resource_idx[i] == (u16) ~ 0)
+ dcm->cipher_algs[i].disabled--;
+ cwm->cipher_resource_idx[i] = res_idx;
+ }
+
+ for (i = 0; i < IPSEC_INTEG_N_ALG; i++)
+ if (dev->auth_support[i])
+ {
+ if (cwm->auth_resource_idx[i] == (u16) ~ 0)
+ dcm->auth_algs[i].disabled--;
+ cwm->auth_resource_idx[i] = res_idx;
+ }
+
+ /* Check if any unused resource */
+
+ u8 used = 0;
+ /* *INDENT-OFF* */
+ vec_foreach (idx, cwm->resource_idx)
+ {
+ if (idx[0] == res_idx)
+ continue;
+
+ for (i = 0; i < IPSEC_CRYPTO_N_ALG; i++)
+ used |= cwm->cipher_resource_idx[i] == idx[0];
+
+ for (i = 0; i < IPSEC_INTEG_N_ALG; i++)
+ used |= cwm->auth_resource_idx[i] == idx[0];
+
+ vec_elt_at_index (dcm->resource, idx[0])->remove = !used;
+ }
+ /* *INDENT-ON* */
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (set_dpdk_crypto_placement, static) = {
+ .path = "set dpdk crypto placement",
+ .short_help = "set dpdk crypto placement (<device> <thread> | auto)",
+ .function = set_dpdk_crypto_placement_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * The thread will not enqueue more operatios to the device but will poll
+ * from it until there are no more inflight operations.
+*/
+static void
+dpdk_crypto_clear_resource (u16 res_idx)
+{
+ dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
+ crypto_resource_t *res = vec_elt_at_index (dcm->resource, res_idx);
+ crypto_worker_main_t *cwm = &dcm->workers_main[res->thread_idx];
+ u32 i;
+
+ for (i = 0; i < IPSEC_CRYPTO_N_ALG; i++)
+ if (cwm->cipher_resource_idx[i] == res_idx)
+ {
+ cwm->cipher_resource_idx[i] = (u16) ~ 0;
+ dcm->cipher_algs[i].disabled++;
+ }
+
+ for (i = 0; i < IPSEC_INTEG_N_ALG; i++)
+ if (cwm->auth_resource_idx[i] == res_idx)
+ {
+ cwm->auth_resource_idx[i] = (u16) ~ 0;
+ dcm->auth_algs[i].disabled++;
+ }
+
+ /* Fully remove device on crypto_node once there are no inflights */
+ res->remove = 1;
+}
+
+static clib_error_t *
+clear_dpdk_crypto_placement_fn (vlib_main_t * vm,
+ unformat_input_t *
+ input, vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
+ crypto_dev_t *dev;
+ u32 thread_idx = (u32) ~ 0;
+ u16 *res_idx;
+ u8 dev_idx = (u8) ~ 0;
+ u8 free_all = 0;
+
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return clib_error_return (0, "invalid syntax");
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "%u %u", &dev_idx, &thread_idx))
+ ;
+ else if (unformat (line_input, "%u", &dev_idx))
+ free_all = 1;
+ else
+ {
+ unformat_free (line_input);
+ return clib_error_return (0, "parse error: '%U'",
+ format_unformat_error, line_input);
+ }
+ }