|  | // 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) | 
|  | 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); | 
|  | } |