xref: /linux-6.15/crypto/async_tx/async_tx.c (revision 07f2211e)
1 /*
2  * core routines for the asynchronous memory transfer/transform api
3  *
4  * Copyright © 2006, Intel Corporation.
5  *
6  *	Dan Williams <[email protected]>
7  *
8  *	with architecture considerations by:
9  *	Neil Brown <[email protected]>
10  *	Jeff Garzik <[email protected]>
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms and conditions of the GNU General Public License,
14  * version 2, as published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  *
21  * You should have received a copy of the GNU General Public License along with
22  * this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
24  *
25  */
26 #include <linux/rculist.h>
27 #include <linux/kernel.h>
28 #include <linux/async_tx.h>
29 
30 #ifdef CONFIG_DMA_ENGINE
31 static enum dma_state_client
32 dma_channel_add_remove(struct dma_client *client,
33 	struct dma_chan *chan, enum dma_state state);
34 
35 static struct dma_client async_tx_dma = {
36 	.event_callback = dma_channel_add_remove,
37 	/* .cap_mask == 0 defaults to all channels */
38 };
39 
40 /**
41  * dma_cap_mask_all - enable iteration over all operation types
42  */
43 static dma_cap_mask_t dma_cap_mask_all;
44 
45 /**
46  * chan_ref_percpu - tracks channel allocations per core/opertion
47  */
48 struct chan_ref_percpu {
49 	struct dma_chan_ref *ref;
50 };
51 
52 static int channel_table_initialized;
53 static struct chan_ref_percpu *channel_table[DMA_TX_TYPE_END];
54 
55 /**
56  * async_tx_lock - protect modification of async_tx_master_list and serialize
57  *	rebalance operations
58  */
59 static spinlock_t async_tx_lock;
60 
61 static LIST_HEAD(async_tx_master_list);
62 
63 /* async_tx_issue_pending_all - start all transactions on all channels */
64 void async_tx_issue_pending_all(void)
65 {
66 	struct dma_chan_ref *ref;
67 
68 	rcu_read_lock();
69 	list_for_each_entry_rcu(ref, &async_tx_master_list, node)
70 		ref->chan->device->device_issue_pending(ref->chan);
71 	rcu_read_unlock();
72 }
73 EXPORT_SYMBOL_GPL(async_tx_issue_pending_all);
74 
75 static void
76 free_dma_chan_ref(struct rcu_head *rcu)
77 {
78 	struct dma_chan_ref *ref;
79 	ref = container_of(rcu, struct dma_chan_ref, rcu);
80 	kfree(ref);
81 }
82 
83 static void
84 init_dma_chan_ref(struct dma_chan_ref *ref, struct dma_chan *chan)
85 {
86 	INIT_LIST_HEAD(&ref->node);
87 	INIT_RCU_HEAD(&ref->rcu);
88 	ref->chan = chan;
89 	atomic_set(&ref->count, 0);
90 }
91 
92 /**
93  * get_chan_ref_by_cap - returns the nth channel of the given capability
94  * 	defaults to returning the channel with the desired capability and the
95  * 	lowest reference count if the index can not be satisfied
96  * @cap: capability to match
97  * @index: nth channel desired, passing -1 has the effect of forcing the
98  *  default return value
99  */
100 static struct dma_chan_ref *
101 get_chan_ref_by_cap(enum dma_transaction_type cap, int index)
102 {
103 	struct dma_chan_ref *ret_ref = NULL, *min_ref = NULL, *ref;
104 
105 	rcu_read_lock();
106 	list_for_each_entry_rcu(ref, &async_tx_master_list, node)
107 		if (dma_has_cap(cap, ref->chan->device->cap_mask)) {
108 			if (!min_ref)
109 				min_ref = ref;
110 			else if (atomic_read(&ref->count) <
111 				atomic_read(&min_ref->count))
112 				min_ref = ref;
113 
114 			if (index-- == 0) {
115 				ret_ref = ref;
116 				break;
117 			}
118 		}
119 	rcu_read_unlock();
120 
121 	if (!ret_ref)
122 		ret_ref = min_ref;
123 
124 	if (ret_ref)
125 		atomic_inc(&ret_ref->count);
126 
127 	return ret_ref;
128 }
129 
130 /**
131  * async_tx_rebalance - redistribute the available channels, optimize
132  * for cpu isolation in the SMP case, and opertaion isolation in the
133  * uniprocessor case
134  */
135 static void async_tx_rebalance(void)
136 {
137 	int cpu, cap, cpu_idx = 0;
138 	unsigned long flags;
139 
140 	if (!channel_table_initialized)
141 		return;
142 
143 	spin_lock_irqsave(&async_tx_lock, flags);
144 
145 	/* undo the last distribution */
146 	for_each_dma_cap_mask(cap, dma_cap_mask_all)
147 		for_each_possible_cpu(cpu) {
148 			struct dma_chan_ref *ref =
149 				per_cpu_ptr(channel_table[cap], cpu)->ref;
150 			if (ref) {
151 				atomic_set(&ref->count, 0);
152 				per_cpu_ptr(channel_table[cap], cpu)->ref =
153 									NULL;
154 			}
155 		}
156 
157 	for_each_dma_cap_mask(cap, dma_cap_mask_all)
158 		for_each_online_cpu(cpu) {
159 			struct dma_chan_ref *new;
160 			if (NR_CPUS > 1)
161 				new = get_chan_ref_by_cap(cap, cpu_idx++);
162 			else
163 				new = get_chan_ref_by_cap(cap, -1);
164 
165 			per_cpu_ptr(channel_table[cap], cpu)->ref = new;
166 		}
167 
168 	spin_unlock_irqrestore(&async_tx_lock, flags);
169 }
170 
171 static enum dma_state_client
172 dma_channel_add_remove(struct dma_client *client,
173 	struct dma_chan *chan, enum dma_state state)
174 {
175 	unsigned long found, flags;
176 	struct dma_chan_ref *master_ref, *ref;
177 	enum dma_state_client ack = DMA_DUP; /* default: take no action */
178 
179 	switch (state) {
180 	case DMA_RESOURCE_AVAILABLE:
181 		found = 0;
182 		rcu_read_lock();
183 		list_for_each_entry_rcu(ref, &async_tx_master_list, node)
184 			if (ref->chan == chan) {
185 				found = 1;
186 				break;
187 			}
188 		rcu_read_unlock();
189 
190 		pr_debug("async_tx: dma resource available [%s]\n",
191 			found ? "old" : "new");
192 
193 		if (!found)
194 			ack = DMA_ACK;
195 		else
196 			break;
197 
198 		/* add the channel to the generic management list */
199 		master_ref = kmalloc(sizeof(*master_ref), GFP_KERNEL);
200 		if (master_ref) {
201 			/* keep a reference until async_tx is unloaded */
202 			dma_chan_get(chan);
203 			init_dma_chan_ref(master_ref, chan);
204 			spin_lock_irqsave(&async_tx_lock, flags);
205 			list_add_tail_rcu(&master_ref->node,
206 				&async_tx_master_list);
207 			spin_unlock_irqrestore(&async_tx_lock,
208 				flags);
209 		} else {
210 			printk(KERN_WARNING "async_tx: unable to create"
211 				" new master entry in response to"
212 				" a DMA_RESOURCE_ADDED event"
213 				" (-ENOMEM)\n");
214 			return 0;
215 		}
216 
217 		async_tx_rebalance();
218 		break;
219 	case DMA_RESOURCE_REMOVED:
220 		found = 0;
221 		spin_lock_irqsave(&async_tx_lock, flags);
222 		list_for_each_entry(ref, &async_tx_master_list, node)
223 			if (ref->chan == chan) {
224 				/* permit backing devices to go away */
225 				dma_chan_put(ref->chan);
226 				list_del_rcu(&ref->node);
227 				call_rcu(&ref->rcu, free_dma_chan_ref);
228 				found = 1;
229 				break;
230 			}
231 		spin_unlock_irqrestore(&async_tx_lock, flags);
232 
233 		pr_debug("async_tx: dma resource removed [%s]\n",
234 			found ? "ours" : "not ours");
235 
236 		if (found)
237 			ack = DMA_ACK;
238 		else
239 			break;
240 
241 		async_tx_rebalance();
242 		break;
243 	case DMA_RESOURCE_SUSPEND:
244 	case DMA_RESOURCE_RESUME:
245 		printk(KERN_WARNING "async_tx: does not support dma channel"
246 			" suspend/resume\n");
247 		break;
248 	default:
249 		BUG();
250 	}
251 
252 	return ack;
253 }
254 
255 static int __init
256 async_tx_init(void)
257 {
258 	enum dma_transaction_type cap;
259 
260 	spin_lock_init(&async_tx_lock);
261 	bitmap_fill(dma_cap_mask_all.bits, DMA_TX_TYPE_END);
262 
263 	/* an interrupt will never be an explicit operation type.
264 	 * clearing this bit prevents allocation to a slot in 'channel_table'
265 	 */
266 	clear_bit(DMA_INTERRUPT, dma_cap_mask_all.bits);
267 
268 	for_each_dma_cap_mask(cap, dma_cap_mask_all) {
269 		channel_table[cap] = alloc_percpu(struct chan_ref_percpu);
270 		if (!channel_table[cap])
271 			goto err;
272 	}
273 
274 	channel_table_initialized = 1;
275 	dma_async_client_register(&async_tx_dma);
276 	dma_async_client_chan_request(&async_tx_dma);
277 
278 	printk(KERN_INFO "async_tx: api initialized (async)\n");
279 
280 	return 0;
281 err:
282 	printk(KERN_ERR "async_tx: initialization failure\n");
283 
284 	while (--cap >= 0)
285 		free_percpu(channel_table[cap]);
286 
287 	return 1;
288 }
289 
290 static void __exit async_tx_exit(void)
291 {
292 	enum dma_transaction_type cap;
293 
294 	channel_table_initialized = 0;
295 
296 	for_each_dma_cap_mask(cap, dma_cap_mask_all)
297 		if (channel_table[cap])
298 			free_percpu(channel_table[cap]);
299 
300 	dma_async_client_unregister(&async_tx_dma);
301 }
302 
303 /**
304  * __async_tx_find_channel - find a channel to carry out the operation or let
305  *	the transaction execute synchronously
306  * @depend_tx: transaction dependency
307  * @tx_type: transaction type
308  */
309 struct dma_chan *
310 __async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
311 	enum dma_transaction_type tx_type)
312 {
313 	/* see if we can keep the chain on one channel */
314 	if (depend_tx &&
315 		dma_has_cap(tx_type, depend_tx->chan->device->cap_mask))
316 		return depend_tx->chan;
317 	else if (likely(channel_table_initialized)) {
318 		struct dma_chan_ref *ref;
319 		int cpu = get_cpu();
320 		ref = per_cpu_ptr(channel_table[tx_type], cpu)->ref;
321 		put_cpu();
322 		return ref ? ref->chan : NULL;
323 	} else
324 		return NULL;
325 }
326 EXPORT_SYMBOL_GPL(__async_tx_find_channel);
327 #else
328 static int __init async_tx_init(void)
329 {
330 	printk(KERN_INFO "async_tx: api initialized (sync-only)\n");
331 	return 0;
332 }
333 
334 static void __exit async_tx_exit(void)
335 {
336 	do { } while (0);
337 }
338 #endif
339 
340 
341 /**
342  * async_tx_channel_switch - queue an interrupt descriptor with a dependency
343  * 	pre-attached.
344  * @depend_tx: the operation that must finish before the new operation runs
345  * @tx: the new operation
346  */
347 static void
348 async_tx_channel_switch(struct dma_async_tx_descriptor *depend_tx,
349 			struct dma_async_tx_descriptor *tx)
350 {
351 	struct dma_chan *chan;
352 	struct dma_device *device;
353 	struct dma_async_tx_descriptor *intr_tx = (void *) ~0;
354 
355 	/* first check to see if we can still append to depend_tx */
356 	spin_lock_bh(&depend_tx->lock);
357 	if (depend_tx->parent && depend_tx->chan == tx->chan) {
358 		tx->parent = depend_tx;
359 		depend_tx->next = tx;
360 		intr_tx = NULL;
361 	}
362 	spin_unlock_bh(&depend_tx->lock);
363 
364 	if (!intr_tx)
365 		return;
366 
367 	chan = depend_tx->chan;
368 	device = chan->device;
369 
370 	/* see if we can schedule an interrupt
371 	 * otherwise poll for completion
372 	 */
373 	if (dma_has_cap(DMA_INTERRUPT, device->cap_mask))
374 		intr_tx = device->device_prep_dma_interrupt(chan, 0);
375 	else
376 		intr_tx = NULL;
377 
378 	if (intr_tx) {
379 		intr_tx->callback = NULL;
380 		intr_tx->callback_param = NULL;
381 		tx->parent = intr_tx;
382 		/* safe to set ->next outside the lock since we know we are
383 		 * not submitted yet
384 		 */
385 		intr_tx->next = tx;
386 
387 		/* check if we need to append */
388 		spin_lock_bh(&depend_tx->lock);
389 		if (depend_tx->parent) {
390 			intr_tx->parent = depend_tx;
391 			depend_tx->next = intr_tx;
392 			async_tx_ack(intr_tx);
393 			intr_tx = NULL;
394 		}
395 		spin_unlock_bh(&depend_tx->lock);
396 
397 		if (intr_tx) {
398 			intr_tx->parent = NULL;
399 			intr_tx->tx_submit(intr_tx);
400 			async_tx_ack(intr_tx);
401 		}
402 	} else {
403 		if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR)
404 			panic("%s: DMA_ERROR waiting for depend_tx\n",
405 			      __func__);
406 		tx->tx_submit(tx);
407 	}
408 }
409 
410 
411 /**
412  * submit_disposition - while holding depend_tx->lock we must avoid submitting
413  * 	new operations to prevent a circular locking dependency with
414  * 	drivers that already hold a channel lock when calling
415  * 	async_tx_run_dependencies.
416  * @ASYNC_TX_SUBMITTED: we were able to append the new operation under the lock
417  * @ASYNC_TX_CHANNEL_SWITCH: when the lock is dropped schedule a channel switch
418  * @ASYNC_TX_DIRECT_SUBMIT: when the lock is dropped submit directly
419  */
420 enum submit_disposition {
421 	ASYNC_TX_SUBMITTED,
422 	ASYNC_TX_CHANNEL_SWITCH,
423 	ASYNC_TX_DIRECT_SUBMIT,
424 };
425 
426 void
427 async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx,
428 	enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx,
429 	dma_async_tx_callback cb_fn, void *cb_param)
430 {
431 	tx->callback = cb_fn;
432 	tx->callback_param = cb_param;
433 
434 	if (depend_tx) {
435 		enum submit_disposition s;
436 
437 		/* sanity check the dependency chain:
438 		 * 1/ if ack is already set then we cannot be sure
439 		 * we are referring to the correct operation
440 		 * 2/ dependencies are 1:1 i.e. two transactions can
441 		 * not depend on the same parent
442 		 */
443 		BUG_ON(async_tx_test_ack(depend_tx) || depend_tx->next ||
444 		       tx->parent);
445 
446 		/* the lock prevents async_tx_run_dependencies from missing
447 		 * the setting of ->next when ->parent != NULL
448 		 */
449 		spin_lock_bh(&depend_tx->lock);
450 		if (depend_tx->parent) {
451 			/* we have a parent so we can not submit directly
452 			 * if we are staying on the same channel: append
453 			 * else: channel switch
454 			 */
455 			if (depend_tx->chan == chan) {
456 				tx->parent = depend_tx;
457 				depend_tx->next = tx;
458 				s = ASYNC_TX_SUBMITTED;
459 			} else
460 				s = ASYNC_TX_CHANNEL_SWITCH;
461 		} else {
462 			/* we do not have a parent so we may be able to submit
463 			 * directly if we are staying on the same channel
464 			 */
465 			if (depend_tx->chan == chan)
466 				s = ASYNC_TX_DIRECT_SUBMIT;
467 			else
468 				s = ASYNC_TX_CHANNEL_SWITCH;
469 		}
470 		spin_unlock_bh(&depend_tx->lock);
471 
472 		switch (s) {
473 		case ASYNC_TX_SUBMITTED:
474 			break;
475 		case ASYNC_TX_CHANNEL_SWITCH:
476 			async_tx_channel_switch(depend_tx, tx);
477 			break;
478 		case ASYNC_TX_DIRECT_SUBMIT:
479 			tx->parent = NULL;
480 			tx->tx_submit(tx);
481 			break;
482 		}
483 	} else {
484 		tx->parent = NULL;
485 		tx->tx_submit(tx);
486 	}
487 
488 	if (flags & ASYNC_TX_ACK)
489 		async_tx_ack(tx);
490 
491 	if (depend_tx && (flags & ASYNC_TX_DEP_ACK))
492 		async_tx_ack(depend_tx);
493 }
494 EXPORT_SYMBOL_GPL(async_tx_submit);
495 
496 /**
497  * async_trigger_callback - schedules the callback function to be run after
498  * any dependent operations have been completed.
499  * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
500  * @depend_tx: 'callback' requires the completion of this transaction
501  * @cb_fn: function to call after depend_tx completes
502  * @cb_param: parameter to pass to the callback routine
503  */
504 struct dma_async_tx_descriptor *
505 async_trigger_callback(enum async_tx_flags flags,
506 	struct dma_async_tx_descriptor *depend_tx,
507 	dma_async_tx_callback cb_fn, void *cb_param)
508 {
509 	struct dma_chan *chan;
510 	struct dma_device *device;
511 	struct dma_async_tx_descriptor *tx;
512 
513 	if (depend_tx) {
514 		chan = depend_tx->chan;
515 		device = chan->device;
516 
517 		/* see if we can schedule an interrupt
518 		 * otherwise poll for completion
519 		 */
520 		if (device && !dma_has_cap(DMA_INTERRUPT, device->cap_mask))
521 			device = NULL;
522 
523 		tx = device ? device->device_prep_dma_interrupt(chan, 0) : NULL;
524 	} else
525 		tx = NULL;
526 
527 	if (tx) {
528 		pr_debug("%s: (async)\n", __func__);
529 
530 		async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
531 	} else {
532 		pr_debug("%s: (sync)\n", __func__);
533 
534 		/* wait for any prerequisite operations */
535 		async_tx_quiesce(&depend_tx);
536 
537 		async_tx_sync_epilog(cb_fn, cb_param);
538 	}
539 
540 	return tx;
541 }
542 EXPORT_SYMBOL_GPL(async_trigger_callback);
543 
544 /**
545  * async_tx_quiesce - ensure tx is complete and freeable upon return
546  * @tx - transaction to quiesce
547  */
548 void async_tx_quiesce(struct dma_async_tx_descriptor **tx)
549 {
550 	if (*tx) {
551 		/* if ack is already set then we cannot be sure
552 		 * we are referring to the correct operation
553 		 */
554 		BUG_ON(async_tx_test_ack(*tx));
555 		if (dma_wait_for_async_tx(*tx) == DMA_ERROR)
556 			panic("DMA_ERROR waiting for transaction\n");
557 		async_tx_ack(*tx);
558 		*tx = NULL;
559 	}
560 }
561 EXPORT_SYMBOL_GPL(async_tx_quiesce);
562 
563 module_init(async_tx_init);
564 module_exit(async_tx_exit);
565 
566 MODULE_AUTHOR("Intel Corporation");
567 MODULE_DESCRIPTION("Asynchronous Bulk Memory Transactions API");
568 MODULE_LICENSE("GPL");
569