lin
2025-06-05 ed3dd9d3e7519a82bb871d5eedb24a2fa0c91f47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#ifndef _LINUX_MEMREMAP_H_
#define _LINUX_MEMREMAP_H_
#include <linux/mm.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 reserve;
   unsigned long free;
   unsigned long align;
   unsigned long alloc;
};
 
unsigned long vmem_altmap_offset(struct vmem_altmap *altmap);
void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns);
 
#ifdef CONFIG_ZONE_DEVICE
struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start);
#else
static inline struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start)
{
   return NULL;
}
#endif
 
/**
 * struct dev_pagemap - metadata for ZONE_DEVICE mappings
 * @altmap: pre-allocated/reserved memory for vmemmap allocations
 * @res: physical address range covered by @ref
 * @ref: reference count that pins the devm_memremap_pages() mapping
 * @dev: host device of the mapping for debug
 */
struct dev_pagemap {
   struct vmem_altmap *altmap;
   const struct resource *res;
   struct percpu_ref *ref;
   struct device *dev;
};
 
#ifdef CONFIG_ZONE_DEVICE
void *devm_memremap_pages(struct device *dev, struct resource *res,
       struct percpu_ref *ref, struct vmem_altmap *altmap);
struct dev_pagemap *find_dev_pagemap(resource_size_t phys);
#else
static inline void *devm_memremap_pages(struct device *dev,
       struct resource *res, struct percpu_ref *ref,
       struct vmem_altmap *altmap)
{
   /*
    * 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 struct dev_pagemap *find_dev_pagemap(resource_size_t phys)
{
   return NULL;
}
#endif
 
/**
 * get_dev_pagemap() - take a new live reference on the dev_pagemap for @pfn
 * @pfn: page frame number to lookup page_map
 * @pgmap: optional known pgmap that already has a reference
 *
 * @pgmap allows the overhead of a lookup to be bypassed when @pfn lands in the
 * same mapping.
 */
static inline struct dev_pagemap *get_dev_pagemap(unsigned long pfn,
       struct dev_pagemap *pgmap)
{
   const struct resource *res = pgmap ? pgmap->res : NULL;
   resource_size_t phys = PFN_PHYS(pfn);
 
   /*
    * In the cached case we're already holding a live reference so
    * we can simply do a blind increment
    */
   if (res && phys >= res->start && phys <= res->end) {
       percpu_ref_get(pgmap->ref);
       return pgmap;
   }
 
   /* fall back to slow path lookup */
   rcu_read_lock();
   pgmap = find_dev_pagemap(phys);
   if (pgmap && !percpu_ref_tryget_live(pgmap->ref))
       pgmap = NULL;
   rcu_read_unlock();
 
   return pgmap;
}
 
static inline void put_dev_pagemap(struct dev_pagemap *pgmap)
{
   if (pgmap)
       percpu_ref_put(pgmap->ref);
}
#endif /* _LINUX_MEMREMAP_H_ */