1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright(c) 2015 Intel Deutschland GmbH
4 */
5#ifndef __DEVCOREDUMP_H
6#define __DEVCOREDUMP_H
7
8#include <linux/device.h>
9#include <linux/module.h>
10#include <linux/vmalloc.h>
11
12#include <linux/scatterlist.h>
13#include <linux/slab.h>
14
15/*
16 * _devcd_free_sgtable - free all the memory of the given scatterlist table
17 * (i.e. both pages and scatterlist instances)
18 * NOTE: if two tables allocated and chained using the sg_chain function then
19 * this function should be called only once on the first table
20 * @table: pointer to sg_table to free
21 */
22static inline void _devcd_free_sgtable(struct scatterlist *table)
23{
24	int i;
25	struct page *page;
26	struct scatterlist *iter;
27	struct scatterlist *delete_iter;
28
29	/* free pages */
30	iter = table;
31	for_each_sg(table, iter, sg_nents(table), i) {
32		page = sg_page(iter);
33		if (page)
34			__free_page(page);
35	}
36
37	/* then free all chained tables */
38	iter = table;
39	delete_iter = table;	/* always points on a head of a table */
40	while (!sg_is_last(iter)) {
41		iter++;
42		if (sg_is_chain(iter)) {
43			iter = sg_chain_ptr(iter);
44			kfree(delete_iter);
45			delete_iter = iter;
46		}
47	}
48
49	/* free the last table */
50	kfree(delete_iter);
51}
52
53
54#ifdef CONFIG_DEV_COREDUMP
55void dev_coredumpv(struct device *dev, void *data, size_t datalen,
56		   gfp_t gfp);
57
58void dev_coredumpm(struct device *dev, struct module *owner,
59		   void *data, size_t datalen, gfp_t gfp,
60		   ssize_t (*read)(char *buffer, loff_t offset, size_t count,
61				   void *data, size_t datalen),
62		   void (*free)(void *data));
63
64void dev_coredumpsg(struct device *dev, struct scatterlist *table,
65		    size_t datalen, gfp_t gfp);
66#else
67static inline void dev_coredumpv(struct device *dev, void *data,
68				 size_t datalen, gfp_t gfp)
69{
70	vfree(data);
71}
72
73static inline void
74dev_coredumpm(struct device *dev, struct module *owner,
75	      void *data, size_t datalen, gfp_t gfp,
76	      ssize_t (*read)(char *buffer, loff_t offset, size_t count,
77			      void *data, size_t datalen),
78	      void (*free)(void *data))
79{
80	free(data);
81}
82
83static inline void dev_coredumpsg(struct device *dev, struct scatterlist *table,
84				  size_t datalen, gfp_t gfp)
85{
86	_devcd_free_sgtable(table);
87}
88#endif /* CONFIG_DEV_COREDUMP */
89
90#endif /* __DEVCOREDUMP_H */
91