| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| /* | |
| * Copyright(c) 2015 Intel Deutschland GmbH | |
| */ | |
| #ifndef __DEVCOREDUMP_H | |
| #define __DEVCOREDUMP_H | |
| #include <linux/device.h> | |
| #include <linux/module.h> | |
| #include <linux/vmalloc.h> | |
| #include <linux/scatterlist.h> | |
| #include <linux/slab.h> | |
| /* | |
| * _devcd_free_sgtable - free all the memory of the given scatterlist table | |
| * (i.e. both pages and scatterlist instances) | |
| * NOTE: if two tables allocated and chained using the sg_chain function then | |
| * this function should be called only once on the first table | |
| * @table: pointer to sg_table to free | |
| */ | |
| static inline void _devcd_free_sgtable(struct scatterlist *table) | |
| { | |
| int i; | |
| struct page *page; | |
| struct scatterlist *iter; | |
| struct scatterlist *delete_iter; | |
| /* free pages */ | |
| iter = table; | |
| for_each_sg(table, iter, sg_nents(table), i) { | |
| page = sg_page(iter); | |
| if (page) | |
| __free_page(page); | |
| } | |
| /* then free all chained tables */ | |
| iter = table; | |
| delete_iter = table; /* always points on a head of a table */ | |
| while (!sg_is_last(iter)) { | |
| iter++; | |
| if (sg_is_chain(iter)) { | |
| iter = sg_chain_ptr(iter); | |
| kfree(delete_iter); | |
| delete_iter = iter; | |
| } | |
| } | |
| /* free the last table */ | |
| kfree(delete_iter); | |
| } | |
| #ifdef CONFIG_DEV_COREDUMP | |
| void dev_coredumpv(struct device *dev, void *data, size_t datalen, | |
| gfp_t gfp); | |
| void dev_coredumpm(struct device *dev, struct module *owner, | |
| void *data, size_t datalen, gfp_t gfp, | |
| ssize_t (*read)(char *buffer, loff_t offset, size_t count, | |
| void *data, size_t datalen), | |
| void (*free)(void *data)); | |
| void dev_coredumpsg(struct device *dev, struct scatterlist *table, | |
| size_t datalen, gfp_t gfp); | |
| #else | |
| static inline void dev_coredumpv(struct device *dev, void *data, | |
| size_t datalen, gfp_t gfp) | |
| { | |
| vfree(data); | |
| } | |
| static inline void | |
| dev_coredumpm(struct device *dev, struct module *owner, | |
| void *data, size_t datalen, gfp_t gfp, | |
| ssize_t (*read)(char *buffer, loff_t offset, size_t count, | |
| void *data, size_t datalen), | |
| void (*free)(void *data)) | |
| { | |
| free(data); | |
| } | |
| static inline void dev_coredumpsg(struct device *dev, struct scatterlist *table, | |
| size_t datalen, gfp_t gfp) | |
| { | |
| _devcd_free_sgtable(table); | |
| } | |
| #endif /* CONFIG_DEV_COREDUMP */ | |
| #endif /* __DEVCOREDUMP_H */ |