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 | */ |
22 | static 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(sg: 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(sg: iter)) { |
41 | iter++; |
42 | if (sg_is_chain(sg: iter)) { |
43 | iter = sg_chain_ptr(sg: iter); |
44 | kfree(objp: delete_iter); |
45 | delete_iter = iter; |
46 | } |
47 | } |
48 | |
49 | /* free the last table */ |
50 | kfree(objp: delete_iter); |
51 | } |
52 | |
53 | |
54 | #ifdef CONFIG_DEV_COREDUMP |
55 | void dev_coredumpv(struct device *dev, void *data, size_t datalen, |
56 | gfp_t gfp); |
57 | |
58 | void 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 | |
64 | void dev_coredumpsg(struct device *dev, struct scatterlist *table, |
65 | size_t datalen, gfp_t gfp); |
66 | #else |
67 | static inline void dev_coredumpv(struct device *dev, void *data, |
68 | size_t datalen, gfp_t gfp) |
69 | { |
70 | vfree(data); |
71 | } |
72 | |
73 | static inline void |
74 | dev_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 | |
83 | static 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 | |