diff options
Diffstat (limited to 'lib/devres.c')
| -rw-r--r-- | lib/devres.c | 82 | 
1 files changed, 82 insertions, 0 deletions
| diff --git a/lib/devres.c b/lib/devres.c index b0e1c6702c71..14664bbb4875 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -528,3 +528,85 @@ void pcim_iounmap_regions(struct pci_dev *pdev, int mask)  }  EXPORT_SYMBOL(pcim_iounmap_regions);  #endif /* CONFIG_PCI */ + +static void devm_arch_phys_ac_add_release(struct device *dev, void *res) +{ +	arch_phys_wc_del(*((int *)res)); +} + +/** + * devm_arch_phys_wc_add - Managed arch_phys_wc_add() + * @dev: Managed device + * @base: Memory base address + * @size: Size of memory range + * + * Adds a WC MTRR using arch_phys_wc_add() and sets up a release callback. + * See arch_phys_wc_add() for more information. + */ +int devm_arch_phys_wc_add(struct device *dev, unsigned long base, unsigned long size) +{ +	int *mtrr; +	int ret; + +	mtrr = devres_alloc(devm_arch_phys_ac_add_release, sizeof(*mtrr), GFP_KERNEL); +	if (!mtrr) +		return -ENOMEM; + +	ret = arch_phys_wc_add(base, size); +	if (ret < 0) { +		devres_free(mtrr); +		return ret; +	} + +	*mtrr = ret; +	devres_add(dev, mtrr); + +	return ret; +} +EXPORT_SYMBOL(devm_arch_phys_wc_add); + +struct arch_io_reserve_memtype_wc_devres { +	resource_size_t start; +	resource_size_t size; +}; + +static void devm_arch_io_free_memtype_wc_release(struct device *dev, void *res) +{ +	const struct arch_io_reserve_memtype_wc_devres *this = res; + +	arch_io_free_memtype_wc(this->start, this->size); +} + +/** + * devm_arch_io_reserve_memtype_wc - Managed arch_io_reserve_memtype_wc() + * @dev: Managed device + * @start: Memory base address + * @size: Size of memory range + * + * Reserves a memory range with WC caching using arch_io_reserve_memtype_wc() + * and sets up a release callback See arch_io_reserve_memtype_wc() for more + * information. + */ +int devm_arch_io_reserve_memtype_wc(struct device *dev, resource_size_t start, +				    resource_size_t size) +{ +	struct arch_io_reserve_memtype_wc_devres *dr; +	int ret; + +	dr = devres_alloc(devm_arch_io_free_memtype_wc_release, sizeof(*dr), GFP_KERNEL); +	if (!dr) +		return -ENOMEM; + +	ret = arch_io_reserve_memtype_wc(start, size); +	if (ret < 0) { +		devres_free(dr); +		return ret; +	} + +	dr->start = start; +	dr->size = size; +	devres_add(dev, dr); + +	return ret; +} +EXPORT_SYMBOL(devm_arch_io_reserve_memtype_wc); |