1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
29476df7dSDan Williams #ifndef _LINUX_MEMREMAP_H_
39476df7dSDan Williams #define _LINUX_MEMREMAP_H_
4dc90f084SChristoph Hellwig
55bb88dc5SAlex Sierra #include <linux/mmzone.h>
6a4574f63SDan Williams #include <linux/range.h>
75c2c2587SDan Williams #include <linux/ioport.h>
85c2c2587SDan Williams #include <linux/percpu-refcount.h>
99476df7dSDan Williams
109476df7dSDan Williams struct resource;
119476df7dSDan Williams struct device;
124b94ffdcSDan Williams
134b94ffdcSDan Williams /**
144b94ffdcSDan Williams * struct vmem_altmap - pre-allocated storage for vmemmap_populate
154b94ffdcSDan Williams * @base_pfn: base of the entire dev_pagemap mapping
164b94ffdcSDan Williams * @reserve: pages mapped, but reserved for driver use (relative to @base)
174b94ffdcSDan Williams * @free: free pages set aside in the mapping for memmap storage
184b94ffdcSDan Williams * @align: pages reserved to meet allocation alignments
194b94ffdcSDan Williams * @alloc: track pages consumed, private to vmemmap_populate()
204b94ffdcSDan Williams */
214b94ffdcSDan Williams struct vmem_altmap {
22a08a2ae3SOscar Salvador unsigned long base_pfn;
23cf387d96SAneesh Kumar K.V const unsigned long end_pfn;
244b94ffdcSDan Williams const unsigned long reserve;
254b94ffdcSDan Williams unsigned long free;
264b94ffdcSDan Williams unsigned long align;
274b94ffdcSDan Williams unsigned long alloc;
28c5f1e2d1SSumanth Korikkar bool inaccessible;
294b94ffdcSDan Williams };
304b94ffdcSDan Williams
315042db43SJérôme Glisse /*
32041711ceSZhen Lei * Specialize ZONE_DEVICE memory into multiple types each has a different
335042db43SJérôme Glisse * usage.
345042db43SJérôme Glisse *
355042db43SJérôme Glisse * MEMORY_DEVICE_PRIVATE:
365042db43SJérôme Glisse * Device memory that is not directly addressable by the CPU: CPU can neither
375042db43SJérôme Glisse * read nor write private memory. In this case, we do still have struct pages
385042db43SJérôme Glisse * backing the device memory. Doing so simplifies the implementation, but it is
395042db43SJérôme Glisse * important to remember that there are certain points at which the struct page
405042db43SJérôme Glisse * must be treated as an opaque object, rather than a "normal" struct page.
415042db43SJérôme Glisse *
425042db43SJérôme Glisse * A more complete discussion of unaddressable memory may be found in
43ee65728eSMike Rapoport * include/linux/hmm.h and Documentation/mm/hmm.rst.
44df6ad698SJérôme Glisse *
45f25cbb7aSAlex Sierra * MEMORY_DEVICE_COHERENT:
46f25cbb7aSAlex Sierra * Device memory that is cache coherent from device and CPU point of view. This
47f25cbb7aSAlex Sierra * is used on platforms that have an advanced system bus (like CAPI or CXL). A
48f25cbb7aSAlex Sierra * driver can hotplug the device memory using ZONE_DEVICE and with that memory
49f25cbb7aSAlex Sierra * type. Any page of a process can be migrated to such memory. However no one
50f25cbb7aSAlex Sierra * should be allowed to pin such memory so that it can always be evicted.
51f25cbb7aSAlex Sierra *
52e7638488SDan Williams * MEMORY_DEVICE_FS_DAX:
53e7638488SDan Williams * Host memory that has similar access semantics as System RAM i.e. DMA
54e7638488SDan Williams * coherent and supports page pinning. In support of coordinating page
55e7638488SDan Williams * pinning vs other operations MEMORY_DEVICE_FS_DAX arranges for a
56e7638488SDan Williams * wakeup event whenever a page is unpinned and becomes idle. This
57e7638488SDan Williams * wakeup is used to coordinate physical address space management (ex:
58e7638488SDan Williams * fs truncate/hole punch) vs pinned pages (ex: device dma).
5952916982SLogan Gunthorpe *
604533d3aeSRoger Pau Monne * MEMORY_DEVICE_GENERIC:
613ed2dcdfSChristoph Hellwig * Host memory that has similar access semantics as System RAM i.e. DMA
624533d3aeSRoger Pau Monne * coherent and supports page pinning. This is for example used by DAX devices
634533d3aeSRoger Pau Monne * that expose memory using a character device.
643ed2dcdfSChristoph Hellwig *
6552916982SLogan Gunthorpe * MEMORY_DEVICE_PCI_P2PDMA:
6652916982SLogan Gunthorpe * Device memory residing in a PCI BAR intended for use with Peer-to-Peer
6752916982SLogan Gunthorpe * transactions.
685042db43SJérôme Glisse */
695042db43SJérôme Glisse enum memory_type {
703ed2dcdfSChristoph Hellwig /* 0 is reserved to catch uninitialized type fields */
71e7638488SDan Williams MEMORY_DEVICE_PRIVATE = 1,
72f25cbb7aSAlex Sierra MEMORY_DEVICE_COHERENT,
73e7638488SDan Williams MEMORY_DEVICE_FS_DAX,
744533d3aeSRoger Pau Monne MEMORY_DEVICE_GENERIC,
7552916982SLogan Gunthorpe MEMORY_DEVICE_PCI_P2PDMA,
765042db43SJérôme Glisse };
775042db43SJérôme Glisse
781e240e8dSChristoph Hellwig struct dev_pagemap_ops {
795042db43SJérôme Glisse /*
8027674ef6SChristoph Hellwig * Called once the page refcount reaches 0. The reference count will be
8127674ef6SChristoph Hellwig * reset to one by the core code after the method is called to prepare
8227674ef6SChristoph Hellwig * for handing out the page again.
835042db43SJérôme Glisse */
8480a72d0aSChristoph Hellwig void (*page_free)(struct page *page);
851e240e8dSChristoph Hellwig
861e240e8dSChristoph Hellwig /*
87897e6365SChristoph Hellwig * Used for private (un-addressable) device memory only. Must migrate
88897e6365SChristoph Hellwig * the page back to a CPU accessible page.
89897e6365SChristoph Hellwig */
90897e6365SChristoph Hellwig vm_fault_t (*migrate_to_ram)(struct vm_fault *vmf);
9133a8f7f2SShiyang Ruan
9233a8f7f2SShiyang Ruan /*
9333a8f7f2SShiyang Ruan * Handle the memory failure happens on a range of pfns. Notify the
9433a8f7f2SShiyang Ruan * processes who are using these pfns, and try to recover the data on
9533a8f7f2SShiyang Ruan * them if necessary. The mf_flags is finally passed to the recover
9633a8f7f2SShiyang Ruan * function through the whole notify routine.
9733a8f7f2SShiyang Ruan *
9833a8f7f2SShiyang Ruan * When this is not implemented, or it returns -EOPNOTSUPP, the caller
9933a8f7f2SShiyang Ruan * will fall back to a common handler called mf_generic_kill_procs().
10033a8f7f2SShiyang Ruan */
10133a8f7f2SShiyang Ruan int (*memory_failure)(struct dev_pagemap *pgmap, unsigned long pfn,
10233a8f7f2SShiyang Ruan unsigned long nr_pages, int mf_flags);
1031e240e8dSChristoph Hellwig };
1045042db43SJérôme Glisse
105514caf23SChristoph Hellwig #define PGMAP_ALTMAP_VALID (1 << 0)
106514caf23SChristoph Hellwig
1079476df7dSDan Williams /**
1089476df7dSDan Williams * struct dev_pagemap - metadata for ZONE_DEVICE mappings
1094b94ffdcSDan Williams * @altmap: pre-allocated/reserved memory for vmemmap allocations
1105c2c2587SDan Williams * @ref: reference count that pins the devm_memremap_pages() mapping
111b80892caSChristoph Hellwig * @done: completion for @ref
1120c32c9f7SJohn Groves * @type: memory type: see MEMORY_* above in memremap.h
113514caf23SChristoph Hellwig * @flags: PGMAP_* flags to specify defailed behavior
114c4386bd8SJoao Martins * @vmemmap_shift: structural definition of how the vmemmap page metadata
115c4386bd8SJoao Martins * is populated, specifically the metadata page order.
116c4386bd8SJoao Martins * A zero value (default) uses base pages as the vmemmap metadata
117c4386bd8SJoao Martins * representation. A bigger value will set up compound struct pages
118c4386bd8SJoao Martins * of the requested order value.
1191e240e8dSChristoph Hellwig * @ops: method table
120f894ddd5SChristoph Hellwig * @owner: an opaque pointer identifying the entity that manages this
121f894ddd5SChristoph Hellwig * instance. Used by various helpers to make sure that no
122f894ddd5SChristoph Hellwig * foreign ZONE_DEVICE memory is accessed.
123b7b3c01bSDan Williams * @nr_range: number of ranges to be mapped
124b7b3c01bSDan Williams * @range: range to be mapped when nr_range == 1
125b7b3c01bSDan Williams * @ranges: array of ranges to be mapped when nr_range > 1
1269476df7dSDan Williams */
1279476df7dSDan Williams struct dev_pagemap {
128e7744aa2SLogan Gunthorpe struct vmem_altmap altmap;
129b80892caSChristoph Hellwig struct percpu_ref ref;
13024917f6bSChristoph Hellwig struct completion done;
1315042db43SJérôme Glisse enum memory_type type;
132514caf23SChristoph Hellwig unsigned int flags;
133c4386bd8SJoao Martins unsigned long vmemmap_shift;
1341e240e8dSChristoph Hellwig const struct dev_pagemap_ops *ops;
135f894ddd5SChristoph Hellwig void *owner;
136b7b3c01bSDan Williams int nr_range;
137b7b3c01bSDan Williams union {
138b7b3c01bSDan Williams struct range range;
13906919d22SGustavo A. R. Silva DECLARE_FLEX_ARRAY(struct range, ranges);
140b7b3c01bSDan Williams };
1419476df7dSDan Williams };
1429476df7dSDan Williams
pgmap_has_memory_failure(struct dev_pagemap * pgmap)14365d3440eSDan Williams static inline bool pgmap_has_memory_failure(struct dev_pagemap *pgmap)
14465d3440eSDan Williams {
14565d3440eSDan Williams return pgmap->ops && pgmap->ops->memory_failure;
14665d3440eSDan Williams }
14765d3440eSDan Williams
pgmap_altmap(struct dev_pagemap * pgmap)148514caf23SChristoph Hellwig static inline struct vmem_altmap *pgmap_altmap(struct dev_pagemap *pgmap)
149514caf23SChristoph Hellwig {
150514caf23SChristoph Hellwig if (pgmap->flags & PGMAP_ALTMAP_VALID)
151514caf23SChristoph Hellwig return &pgmap->altmap;
152514caf23SChristoph Hellwig return NULL;
153514caf23SChristoph Hellwig }
154514caf23SChristoph Hellwig
pgmap_vmemmap_nr(struct dev_pagemap * pgmap)155c4386bd8SJoao Martins static inline unsigned long pgmap_vmemmap_nr(struct dev_pagemap *pgmap)
156c4386bd8SJoao Martins {
157c4386bd8SJoao Martins return 1 << pgmap->vmemmap_shift;
158c4386bd8SJoao Martins }
159c4386bd8SJoao Martins
is_device_private_page(const struct page * page)160dc90f084SChristoph Hellwig static inline bool is_device_private_page(const struct page *page)
161dc90f084SChristoph Hellwig {
16227674ef6SChristoph Hellwig return IS_ENABLED(CONFIG_DEVICE_PRIVATE) &&
163dc90f084SChristoph Hellwig is_zone_device_page(page) &&
16482ba975eSAlistair Popple page_pgmap(page)->type == MEMORY_DEVICE_PRIVATE;
165dc90f084SChristoph Hellwig }
166dc90f084SChristoph Hellwig
folio_is_device_private(const struct folio * folio)167536939ffSMatthew Wilcox (Oracle) static inline bool folio_is_device_private(const struct folio *folio)
168536939ffSMatthew Wilcox (Oracle) {
169536939ffSMatthew Wilcox (Oracle) return is_device_private_page(&folio->page);
170536939ffSMatthew Wilcox (Oracle) }
171536939ffSMatthew Wilcox (Oracle)
is_pci_p2pdma_page(const struct page * page)172dc90f084SChristoph Hellwig static inline bool is_pci_p2pdma_page(const struct page *page)
173dc90f084SChristoph Hellwig {
17427674ef6SChristoph Hellwig return IS_ENABLED(CONFIG_PCI_P2PDMA) &&
175dc90f084SChristoph Hellwig is_zone_device_page(page) &&
17682ba975eSAlistair Popple page_pgmap(page)->type == MEMORY_DEVICE_PCI_P2PDMA;
177dc90f084SChristoph Hellwig }
178dc90f084SChristoph Hellwig
is_device_coherent_page(const struct page * page)179f25cbb7aSAlex Sierra static inline bool is_device_coherent_page(const struct page *page)
180f25cbb7aSAlex Sierra {
181f25cbb7aSAlex Sierra return is_zone_device_page(page) &&
18282ba975eSAlistair Popple page_pgmap(page)->type == MEMORY_DEVICE_COHERENT;
183f25cbb7aSAlex Sierra }
184f25cbb7aSAlex Sierra
folio_is_device_coherent(const struct folio * folio)185f25cbb7aSAlex Sierra static inline bool folio_is_device_coherent(const struct folio *folio)
186f25cbb7aSAlex Sierra {
187f25cbb7aSAlex Sierra return is_device_coherent_page(&folio->page);
188f25cbb7aSAlex Sierra }
189f25cbb7aSAlex Sierra
is_fsdax_page(const struct page * page)190*e5cb2325SAlistair Popple static inline bool is_fsdax_page(const struct page *page)
191*e5cb2325SAlistair Popple {
192*e5cb2325SAlistair Popple return is_zone_device_page(page) &&
193*e5cb2325SAlistair Popple page_pgmap(page)->type == MEMORY_DEVICE_FS_DAX;
194*e5cb2325SAlistair Popple }
195*e5cb2325SAlistair Popple
folio_is_fsdax(const struct folio * folio)196*e5cb2325SAlistair Popple static inline bool folio_is_fsdax(const struct folio *folio)
197*e5cb2325SAlistair Popple {
198*e5cb2325SAlistair Popple return is_fsdax_page(&folio->page);
199*e5cb2325SAlistair Popple }
200*e5cb2325SAlistair Popple
2019476df7dSDan Williams #ifdef CONFIG_ZONE_DEVICE
202ef233450SAlistair Popple void zone_device_page_init(struct page *page);
2036869b7b2SChristoph Hellwig void *memremap_pages(struct dev_pagemap *pgmap, int nid);
2046869b7b2SChristoph Hellwig void memunmap_pages(struct dev_pagemap *pgmap);
205e8d51348SChristoph Hellwig void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap);
2062e3f139eSDan Williams void devm_memunmap_pages(struct device *dev, struct dev_pagemap *pgmap);
2070822acb8SChristoph Hellwig struct dev_pagemap *get_dev_pagemap(unsigned long pfn,
2080822acb8SChristoph Hellwig struct dev_pagemap *pgmap);
20934dc45beSDan Williams bool pgmap_pfn_valid(struct dev_pagemap *pgmap, unsigned long pfn);
2107b2d55d2SJérôme Glisse
2119ffc1d19SDan Williams unsigned long memremap_compat_align(void);
2129476df7dSDan Williams #else
devm_memremap_pages(struct device * dev,struct dev_pagemap * pgmap)2139476df7dSDan Williams static inline void *devm_memremap_pages(struct device *dev,
214e8d51348SChristoph Hellwig struct dev_pagemap *pgmap)
2159476df7dSDan Williams {
2169476df7dSDan Williams /*
2179476df7dSDan Williams * Fail attempts to call devm_memremap_pages() without
2189476df7dSDan Williams * ZONE_DEVICE support enabled, this requires callers to fall
2199476df7dSDan Williams * back to plain devm_memremap() based on config
2209476df7dSDan Williams */
2219476df7dSDan Williams WARN_ON_ONCE(1);
2229476df7dSDan Williams return ERR_PTR(-ENXIO);
2239476df7dSDan Williams }
2249476df7dSDan Williams
devm_memunmap_pages(struct device * dev,struct dev_pagemap * pgmap)2252e3f139eSDan Williams static inline void devm_memunmap_pages(struct device *dev,
2262e3f139eSDan Williams struct dev_pagemap *pgmap)
2272e3f139eSDan Williams {
2282e3f139eSDan Williams }
2292e3f139eSDan Williams
get_dev_pagemap(unsigned long pfn,struct dev_pagemap * pgmap)2300822acb8SChristoph Hellwig static inline struct dev_pagemap *get_dev_pagemap(unsigned long pfn,
2310822acb8SChristoph Hellwig struct dev_pagemap *pgmap)
2329476df7dSDan Williams {
2339476df7dSDan Williams return NULL;
2349476df7dSDan Williams }
2358e37d00aSChristoph Hellwig
pgmap_pfn_valid(struct dev_pagemap * pgmap,unsigned long pfn)23634dc45beSDan Williams static inline bool pgmap_pfn_valid(struct dev_pagemap *pgmap, unsigned long pfn)
23734dc45beSDan Williams {
23834dc45beSDan Williams return false;
23934dc45beSDan Williams }
24034dc45beSDan Williams
2419ffc1d19SDan Williams /* when memremap_pages() is disabled all archs can remap a single page */
memremap_compat_align(void)2429ffc1d19SDan Williams static inline unsigned long memremap_compat_align(void)
2439ffc1d19SDan Williams {
2449ffc1d19SDan Williams return PAGE_SIZE;
2459ffc1d19SDan Williams }
2468e37d00aSChristoph Hellwig #endif /* CONFIG_ZONE_DEVICE */
2477b2d55d2SJérôme Glisse
put_dev_pagemap(struct dev_pagemap * pgmap)2485c2c2587SDan Williams static inline void put_dev_pagemap(struct dev_pagemap *pgmap)
2495c2c2587SDan Williams {
2505c2c2587SDan Williams if (pgmap)
251b80892caSChristoph Hellwig percpu_ref_put(&pgmap->ref);
2525c2c2587SDan Williams }
2539ffc1d19SDan Williams
2549476df7dSDan Williams #endif /* _LINUX_MEMREMAP_H_ */
255