| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. |
| */ |
| |
| #include "queueing.h" |
| |
| struct multicore_worker __percpu * |
| wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr) |
| { |
| int cpu; |
| struct multicore_worker __percpu *worker = |
| alloc_percpu(struct multicore_worker); |
| |
| if (!worker) |
| return NULL; |
| |
| for_each_possible_cpu(cpu) { |
| per_cpu_ptr(worker, cpu)->ptr = ptr; |
| INIT_WORK(&per_cpu_ptr(worker, cpu)->work, function); |
| } |
| return worker; |
| } |
| |
| int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function, |
| bool multicore, unsigned int len) |
| { |
| int ret; |
| |
| memset(queue, 0, sizeof(*queue)); |
| ret = ptr_ring_init(&queue->ring, len, GFP_KERNEL); |
| if (ret) |
| return ret; |
| if (function) { |
| if (multicore) { |
| queue->worker = wg_packet_percpu_multicore_worker_alloc( |
| function, queue); |
| if (!queue->worker) { |
| ptr_ring_cleanup(&queue->ring, NULL); |
| return -ENOMEM; |
| } |
| } else { |
| INIT_WORK(&queue->work, function); |
| } |
| } |
| return 0; |
| } |
| |
| void wg_packet_queue_free(struct crypt_queue *queue, bool multicore) |
| { |
| if (multicore) |
| free_percpu(queue->worker); |
| WARN_ON(!__ptr_ring_empty(&queue->ring)); |
| ptr_ring_cleanup(&queue->ring, NULL); |
| } |