]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - kernel/memremap.c
Merge remote-tracking branch 'origin/master' into drm-misc-fixes
[linux.git] / kernel / memremap.c
index 066e73c2fcc9dbbd89c13923e203ed47aaff7d58..6bcbfbf1a8fdfd2f1008cde707db9a798a68cdc6 100644 (file)
  * General Public License for more details.
  */
 #include <linux/radix-tree.h>
-#include <linux/memremap.h>
 #include <linux/device.h>
 #include <linux/types.h>
 #include <linux/pfn_t.h>
 #include <linux/io.h>
 #include <linux/mm.h>
 #include <linux/memory_hotplug.h>
+#include <linux/swap.h>
+#include <linux/swapops.h>
 
 #ifndef ioremap_cache
 /* temporary while we convert existing ioremap_cache users to memremap */
@@ -219,6 +220,34 @@ static unsigned long order_at(struct resource *res, unsigned long pgoff)
        for (pgoff = 0, order = order_at((res), pgoff); order < ULONG_MAX; \
                        pgoff += 1UL << order, order = order_at((res), pgoff))
 
+#if IS_ENABLED(CONFIG_DEVICE_PRIVATE)
+int device_private_entry_fault(struct vm_area_struct *vma,
+                      unsigned long addr,
+                      swp_entry_t entry,
+                      unsigned int flags,
+                      pmd_t *pmdp)
+{
+       struct page *page = device_private_entry_to_page(entry);
+
+       /*
+        * The page_fault() callback must migrate page back to system memory
+        * so that CPU can access it. This might fail for various reasons
+        * (device issue, device was unsafely unplugged, ...). When such
+        * error conditions happen, the callback must return VM_FAULT_SIGBUS.
+        *
+        * Note that because memory cgroup charges are accounted to the device
+        * memory, this should never fail because of memory restrictions (but
+        * allocation of regular system page might still fail because we are
+        * out of memory).
+        *
+        * There is a more in-depth description of what that callback can and
+        * cannot do, in include/linux/memremap.h
+        */
+       return page->pgmap->page_fault(vma, addr, page, flags, pmdp);
+}
+EXPORT_SYMBOL(device_private_entry_fault);
+#endif /* CONFIG_DEVICE_PRIVATE */
+
 static void pgmap_radix_release(struct resource *res)
 {
        unsigned long pgoff, order;
@@ -356,6 +385,10 @@ void *devm_memremap_pages(struct device *dev, struct resource *res,
        }
        pgmap->ref = ref;
        pgmap->res = &page_map->res;
+       pgmap->type = MEMORY_DEVICE_HOST;
+       pgmap->page_fault = NULL;
+       pgmap->page_free = NULL;
+       pgmap->data = NULL;
 
        mutex_lock(&pgmap_lock);
        error = 0;
@@ -466,3 +499,28 @@ struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start)
        return pgmap ? pgmap->altmap : NULL;
 }
 #endif /* CONFIG_ZONE_DEVICE */
+
+
+#if IS_ENABLED(CONFIG_DEVICE_PRIVATE) ||  IS_ENABLED(CONFIG_DEVICE_PUBLIC)
+void put_zone_device_private_or_public_page(struct page *page)
+{
+       int count = page_ref_dec_return(page);
+
+       /*
+        * If refcount is 1 then page is freed and refcount is stable as nobody
+        * holds a reference on the page.
+        */
+       if (count == 1) {
+               /* Clear Active bit in case of parallel mark_page_accessed */
+               __ClearPageActive(page);
+               __ClearPageWaiters(page);
+
+               page->mapping = NULL;
+               mem_cgroup_uncharge(page);
+
+               page->pgmap->page_free(page, page->pgmap->data);
+       } else if (!count)
+               __put_page(page);
+}
+EXPORT_SYMBOL(put_zone_device_private_or_public_page);
+#endif /* CONFIG_DEVICE_PRIVATE || CONFIG_DEVICE_PUBLIC */