linux/drivers/dax/kmem.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright(c) 2016-2019 Intel Corporation. All rights reserved. */
   3#include <linux/memremap.h>
   4#include <linux/pagemap.h>
   5#include <linux/memory.h>
   6#include <linux/module.h>
   7#include <linux/device.h>
   8#include <linux/pfn_t.h>
   9#include <linux/slab.h>
  10#include <linux/dax.h>
  11#include <linux/fs.h>
  12#include <linux/mm.h>
  13#include <linux/mman.h>
  14#include "dax-private.h"
  15#include "bus.h"
  16
  17int dev_dax_kmem_probe(struct device *dev)
  18{
  19        struct dev_dax *dev_dax = to_dev_dax(dev);
  20        struct resource *res = &dev_dax->region->res;
  21        resource_size_t kmem_start;
  22        resource_size_t kmem_size;
  23        resource_size_t kmem_end;
  24        struct resource *new_res;
  25        int numa_node;
  26        int rc;
  27
  28        /*
  29         * Ensure good NUMA information for the persistent memory.
  30         * Without this check, there is a risk that slow memory
  31         * could be mixed in a node with faster memory, causing
  32         * unavoidable performance issues.
  33         */
  34        numa_node = dev_dax->target_node;
  35        if (numa_node < 0) {
  36                dev_warn(dev, "rejecting DAX region %pR with invalid node: %d\n",
  37                         res, numa_node);
  38                return -EINVAL;
  39        }
  40
  41        /* Hotplug starting at the beginning of the next block: */
  42        kmem_start = ALIGN(res->start, memory_block_size_bytes());
  43
  44        kmem_size = resource_size(res);
  45        /* Adjust the size down to compensate for moving up kmem_start: */
  46        kmem_size -= kmem_start - res->start;
  47        /* Align the size down to cover only complete blocks: */
  48        kmem_size &= ~(memory_block_size_bytes() - 1);
  49        kmem_end = kmem_start + kmem_size;
  50
  51        /* Region is permanently reserved.  Hot-remove not yet implemented. */
  52        new_res = request_mem_region(kmem_start, kmem_size, dev_name(dev));
  53        if (!new_res) {
  54                dev_warn(dev, "could not reserve region [%pa-%pa]\n",
  55                         &kmem_start, &kmem_end);
  56                return -EBUSY;
  57        }
  58
  59        /*
  60         * Set flags appropriate for System RAM.  Leave ..._BUSY clear
  61         * so that add_memory() can add a child resource.  Do not
  62         * inherit flags from the parent since it may set new flags
  63         * unknown to us that will break add_memory() below.
  64         */
  65        new_res->flags = IORESOURCE_SYSTEM_RAM;
  66        new_res->name = dev_name(dev);
  67
  68        rc = add_memory(numa_node, new_res->start, resource_size(new_res));
  69        if (rc)
  70                return rc;
  71
  72        return 0;
  73}
  74
  75static int dev_dax_kmem_remove(struct device *dev)
  76{
  77        /*
  78         * Purposely leak the request_mem_region() for the device-dax
  79         * range and return '0' to ->remove() attempts. The removal of
  80         * the device from the driver always succeeds, but the region
  81         * is permanently pinned as reserved by the unreleased
  82         * request_mem_region().
  83         */
  84        return 0;
  85}
  86
  87static struct dax_device_driver device_dax_kmem_driver = {
  88        .drv = {
  89                .probe = dev_dax_kmem_probe,
  90                .remove = dev_dax_kmem_remove,
  91        },
  92};
  93
  94static int __init dax_kmem_init(void)
  95{
  96        return dax_driver_register(&device_dax_kmem_driver);
  97}
  98
  99static void __exit dax_kmem_exit(void)
 100{
 101        dax_driver_unregister(&device_dax_kmem_driver);
 102}
 103
 104MODULE_AUTHOR("Intel Corporation");
 105MODULE_LICENSE("GPL v2");
 106module_init(dax_kmem_init);
 107module_exit(dax_kmem_exit);
 108MODULE_ALIAS_DAX_DEVICE(0);
 109