mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
6.0 KiB
197 lines
6.0 KiB
/* SPDX-License-Identifier: GPL-2.0 */ |
|
#ifndef _LINUX_MEMREMAP_H_ |
|
#define _LINUX_MEMREMAP_H_ |
|
#include <linux/range.h> |
|
#include <linux/ioport.h> |
|
#include <linux/percpu-refcount.h> |
|
|
|
struct resource; |
|
struct device; |
|
|
|
/** |
|
* struct vmem_altmap - pre-allocated storage for vmemmap_populate |
|
* @base_pfn: base of the entire dev_pagemap mapping |
|
* @reserve: pages mapped, but reserved for driver use (relative to @base) |
|
* @free: free pages set aside in the mapping for memmap storage |
|
* @align: pages reserved to meet allocation alignments |
|
* @alloc: track pages consumed, private to vmemmap_populate() |
|
*/ |
|
struct vmem_altmap { |
|
const unsigned long base_pfn; |
|
const unsigned long end_pfn; |
|
const unsigned long reserve; |
|
unsigned long free; |
|
unsigned long align; |
|
unsigned long alloc; |
|
}; |
|
|
|
/* |
|
* Specialize ZONE_DEVICE memory into multiple types each having differents |
|
* usage. |
|
* |
|
* MEMORY_DEVICE_PRIVATE: |
|
* Device memory that is not directly addressable by the CPU: CPU can neither |
|
* read nor write private memory. In this case, we do still have struct pages |
|
* backing the device memory. Doing so simplifies the implementation, but it is |
|
* important to remember that there are certain points at which the struct page |
|
* must be treated as an opaque object, rather than a "normal" struct page. |
|
* |
|
* A more complete discussion of unaddressable memory may be found in |
|
* include/linux/hmm.h and Documentation/vm/hmm.rst. |
|
* |
|
* MEMORY_DEVICE_FS_DAX: |
|
* Host memory that has similar access semantics as System RAM i.e. DMA |
|
* coherent and supports page pinning. In support of coordinating page |
|
* pinning vs other operations MEMORY_DEVICE_FS_DAX arranges for a |
|
* wakeup event whenever a page is unpinned and becomes idle. This |
|
* wakeup is used to coordinate physical address space management (ex: |
|
* fs truncate/hole punch) vs pinned pages (ex: device dma). |
|
* |
|
* MEMORY_DEVICE_GENERIC: |
|
* Host memory that has similar access semantics as System RAM i.e. DMA |
|
* coherent and supports page pinning. This is for example used by DAX devices |
|
* that expose memory using a character device. |
|
* |
|
* MEMORY_DEVICE_PCI_P2PDMA: |
|
* Device memory residing in a PCI BAR intended for use with Peer-to-Peer |
|
* transactions. |
|
*/ |
|
enum memory_type { |
|
/* 0 is reserved to catch uninitialized type fields */ |
|
MEMORY_DEVICE_PRIVATE = 1, |
|
MEMORY_DEVICE_FS_DAX, |
|
MEMORY_DEVICE_GENERIC, |
|
MEMORY_DEVICE_PCI_P2PDMA, |
|
}; |
|
|
|
struct dev_pagemap_ops { |
|
/* |
|
* Called once the page refcount reaches 1. (ZONE_DEVICE pages never |
|
* reach 0 refcount unless there is a refcount bug. This allows the |
|
* device driver to implement its own memory management.) |
|
*/ |
|
void (*page_free)(struct page *page); |
|
|
|
/* |
|
* Transition the refcount in struct dev_pagemap to the dead state. |
|
*/ |
|
void (*kill)(struct dev_pagemap *pgmap); |
|
|
|
/* |
|
* Wait for refcount in struct dev_pagemap to be idle and reap it. |
|
*/ |
|
void (*cleanup)(struct dev_pagemap *pgmap); |
|
|
|
/* |
|
* Used for private (un-addressable) device memory only. Must migrate |
|
* the page back to a CPU accessible page. |
|
*/ |
|
vm_fault_t (*migrate_to_ram)(struct vm_fault *vmf); |
|
}; |
|
|
|
#define PGMAP_ALTMAP_VALID (1 << 0) |
|
|
|
/** |
|
* struct dev_pagemap - metadata for ZONE_DEVICE mappings |
|
* @altmap: pre-allocated/reserved memory for vmemmap allocations |
|
* @ref: reference count that pins the devm_memremap_pages() mapping |
|
* @internal_ref: internal reference if @ref is not provided by the caller |
|
* @done: completion for @internal_ref |
|
* @type: memory type: see MEMORY_* in memory_hotplug.h |
|
* @flags: PGMAP_* flags to specify defailed behavior |
|
* @ops: method table |
|
* @owner: an opaque pointer identifying the entity that manages this |
|
* instance. Used by various helpers to make sure that no |
|
* foreign ZONE_DEVICE memory is accessed. |
|
* @nr_range: number of ranges to be mapped |
|
* @range: range to be mapped when nr_range == 1 |
|
* @ranges: array of ranges to be mapped when nr_range > 1 |
|
*/ |
|
struct dev_pagemap { |
|
struct vmem_altmap altmap; |
|
struct percpu_ref *ref; |
|
struct percpu_ref internal_ref; |
|
struct completion done; |
|
enum memory_type type; |
|
unsigned int flags; |
|
const struct dev_pagemap_ops *ops; |
|
void *owner; |
|
int nr_range; |
|
union { |
|
struct range range; |
|
struct range ranges[0]; |
|
}; |
|
}; |
|
|
|
static inline struct vmem_altmap *pgmap_altmap(struct dev_pagemap *pgmap) |
|
{ |
|
if (pgmap->flags & PGMAP_ALTMAP_VALID) |
|
return &pgmap->altmap; |
|
return NULL; |
|
} |
|
|
|
#ifdef CONFIG_ZONE_DEVICE |
|
void *memremap_pages(struct dev_pagemap *pgmap, int nid); |
|
void memunmap_pages(struct dev_pagemap *pgmap); |
|
void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap); |
|
void devm_memunmap_pages(struct device *dev, struct dev_pagemap *pgmap); |
|
struct dev_pagemap *get_dev_pagemap(unsigned long pfn, |
|
struct dev_pagemap *pgmap); |
|
bool pgmap_pfn_valid(struct dev_pagemap *pgmap, unsigned long pfn); |
|
|
|
unsigned long vmem_altmap_offset(struct vmem_altmap *altmap); |
|
void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns); |
|
unsigned long memremap_compat_align(void); |
|
#else |
|
static inline void *devm_memremap_pages(struct device *dev, |
|
struct dev_pagemap *pgmap) |
|
{ |
|
/* |
|
* Fail attempts to call devm_memremap_pages() without |
|
* ZONE_DEVICE support enabled, this requires callers to fall |
|
* back to plain devm_memremap() based on config |
|
*/ |
|
WARN_ON_ONCE(1); |
|
return ERR_PTR(-ENXIO); |
|
} |
|
|
|
static inline void devm_memunmap_pages(struct device *dev, |
|
struct dev_pagemap *pgmap) |
|
{ |
|
} |
|
|
|
static inline struct dev_pagemap *get_dev_pagemap(unsigned long pfn, |
|
struct dev_pagemap *pgmap) |
|
{ |
|
return NULL; |
|
} |
|
|
|
static inline bool pgmap_pfn_valid(struct dev_pagemap *pgmap, unsigned long pfn) |
|
{ |
|
return false; |
|
} |
|
|
|
static inline unsigned long vmem_altmap_offset(struct vmem_altmap *altmap) |
|
{ |
|
return 0; |
|
} |
|
|
|
static inline void vmem_altmap_free(struct vmem_altmap *altmap, |
|
unsigned long nr_pfns) |
|
{ |
|
} |
|
|
|
/* when memremap_pages() is disabled all archs can remap a single page */ |
|
static inline unsigned long memremap_compat_align(void) |
|
{ |
|
return PAGE_SIZE; |
|
} |
|
#endif /* CONFIG_ZONE_DEVICE */ |
|
|
|
static inline void put_dev_pagemap(struct dev_pagemap *pgmap) |
|
{ |
|
if (pgmap) |
|
percpu_ref_put(pgmap->ref); |
|
} |
|
|
|
#endif /* _LINUX_MEMREMAP_H_ */
|
|
|