Merge tag 'trace-v5.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[linux-2.6-microblaze.git] / drivers / dax / device.c
index 1e89513..25e0b84 100644 (file)
@@ -17,7 +17,6 @@
 static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
                const char *func)
 {
-       struct dax_region *dax_region = dev_dax->region;
        struct device *dev = &dev_dax->dev;
        unsigned long mask;
 
@@ -32,7 +31,7 @@ static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
                return -EINVAL;
        }
 
-       mask = dax_region->align - 1;
+       mask = dev_dax->align - 1;
        if (vma->vm_start & mask || vma->vm_end & mask) {
                dev_info_ratelimited(dev,
                                "%s: %s: fail, unaligned vma (%#lx - %#lx, %#lx)\n",
@@ -41,14 +40,6 @@ static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
                return -EINVAL;
        }
 
-       if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) == PFN_DEV
-                       && (vma->vm_flags & VM_DONTCOPY) == 0) {
-               dev_info_ratelimited(dev,
-                               "%s: %s: fail, dax range requires MADV_DONTFORK\n",
-                               current->comm, func);
-               return -EINVAL;
-       }
-
        if (!vma_is_dax(vma)) {
                dev_info_ratelimited(dev,
                                "%s: %s: fail, vma is not DAX capable\n",
@@ -63,15 +54,22 @@ static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
 __weak phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff,
                unsigned long size)
 {
-       struct resource *res = &dev_dax->region->res;
-       phys_addr_t phys;
-
-       phys = pgoff * PAGE_SIZE + res->start;
-       if (phys >= res->start && phys <= res->end) {
-               if (phys + size - 1 <= res->end)
+       int i;
+
+       for (i = 0; i < dev_dax->nr_range; i++) {
+               struct dev_dax_range *dax_range = &dev_dax->ranges[i];
+               struct range *range = &dax_range->range;
+               unsigned long long pgoff_end;
+               phys_addr_t phys;
+
+               pgoff_end = dax_range->pgoff + PHYS_PFN(range_len(range)) - 1;
+               if (pgoff < dax_range->pgoff || pgoff > pgoff_end)
+                       continue;
+               phys = PFN_PHYS(pgoff - dax_range->pgoff) + range->start;
+               if (phys + size - 1 <= range->end)
                        return phys;
+               break;
        }
-
        return -1;
 }
 
@@ -79,21 +77,19 @@ static vm_fault_t __dev_dax_pte_fault(struct dev_dax *dev_dax,
                                struct vm_fault *vmf, pfn_t *pfn)
 {
        struct device *dev = &dev_dax->dev;
-       struct dax_region *dax_region;
        phys_addr_t phys;
        unsigned int fault_size = PAGE_SIZE;
 
        if (check_vma(dev_dax, vmf->vma, __func__))
                return VM_FAULT_SIGBUS;
 
-       dax_region = dev_dax->region;
-       if (dax_region->align > PAGE_SIZE) {
+       if (dev_dax->align > PAGE_SIZE) {
                dev_dbg(dev, "alignment (%#x) > fault size (%#x)\n",
-                       dax_region->align, fault_size);
+                       dev_dax->align, fault_size);
                return VM_FAULT_SIGBUS;
        }
 
-       if (fault_size != dax_region->align)
+       if (fault_size != dev_dax->align)
                return VM_FAULT_SIGBUS;
 
        phys = dax_pgoff_to_phys(dev_dax, vmf->pgoff, PAGE_SIZE);
@@ -102,7 +98,7 @@ static vm_fault_t __dev_dax_pte_fault(struct dev_dax *dev_dax,
                return VM_FAULT_SIGBUS;
        }
 
-       *pfn = phys_to_pfn_t(phys, dax_region->pfn_flags);
+       *pfn = phys_to_pfn_t(phys, PFN_DEV|PFN_MAP);
 
        return vmf_insert_mixed(vmf->vma, vmf->address, *pfn);
 }
@@ -112,7 +108,6 @@ static vm_fault_t __dev_dax_pmd_fault(struct dev_dax *dev_dax,
 {
        unsigned long pmd_addr = vmf->address & PMD_MASK;
        struct device *dev = &dev_dax->dev;
-       struct dax_region *dax_region;
        phys_addr_t phys;
        pgoff_t pgoff;
        unsigned int fault_size = PMD_SIZE;
@@ -120,22 +115,15 @@ static vm_fault_t __dev_dax_pmd_fault(struct dev_dax *dev_dax,
        if (check_vma(dev_dax, vmf->vma, __func__))
                return VM_FAULT_SIGBUS;
 
-       dax_region = dev_dax->region;
-       if (dax_region->align > PMD_SIZE) {
+       if (dev_dax->align > PMD_SIZE) {
                dev_dbg(dev, "alignment (%#x) > fault size (%#x)\n",
-                       dax_region->align, fault_size);
-               return VM_FAULT_SIGBUS;
-       }
-
-       /* dax pmd mappings require pfn_t_devmap() */
-       if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) != (PFN_DEV|PFN_MAP)) {
-               dev_dbg(dev, "region lacks devmap flags\n");
+                       dev_dax->align, fault_size);
                return VM_FAULT_SIGBUS;
        }
 
-       if (fault_size < dax_region->align)
+       if (fault_size < dev_dax->align)
                return VM_FAULT_SIGBUS;
-       else if (fault_size > dax_region->align)
+       else if (fault_size > dev_dax->align)
                return VM_FAULT_FALLBACK;
 
        /* if we are outside of the VMA */
@@ -150,7 +138,7 @@ static vm_fault_t __dev_dax_pmd_fault(struct dev_dax *dev_dax,
                return VM_FAULT_SIGBUS;
        }
 
-       *pfn = phys_to_pfn_t(phys, dax_region->pfn_flags);
+       *pfn = phys_to_pfn_t(phys, PFN_DEV|PFN_MAP);
 
        return vmf_insert_pfn_pmd(vmf, *pfn, vmf->flags & FAULT_FLAG_WRITE);
 }
@@ -161,7 +149,6 @@ static vm_fault_t __dev_dax_pud_fault(struct dev_dax *dev_dax,
 {
        unsigned long pud_addr = vmf->address & PUD_MASK;
        struct device *dev = &dev_dax->dev;
-       struct dax_region *dax_region;
        phys_addr_t phys;
        pgoff_t pgoff;
        unsigned int fault_size = PUD_SIZE;
@@ -170,22 +157,15 @@ static vm_fault_t __dev_dax_pud_fault(struct dev_dax *dev_dax,
        if (check_vma(dev_dax, vmf->vma, __func__))
                return VM_FAULT_SIGBUS;
 
-       dax_region = dev_dax->region;
-       if (dax_region->align > PUD_SIZE) {
+       if (dev_dax->align > PUD_SIZE) {
                dev_dbg(dev, "alignment (%#x) > fault size (%#x)\n",
-                       dax_region->align, fault_size);
-               return VM_FAULT_SIGBUS;
-       }
-
-       /* dax pud mappings require pfn_t_devmap() */
-       if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) != (PFN_DEV|PFN_MAP)) {
-               dev_dbg(dev, "region lacks devmap flags\n");
+                       dev_dax->align, fault_size);
                return VM_FAULT_SIGBUS;
        }
 
-       if (fault_size < dax_region->align)
+       if (fault_size < dev_dax->align)
                return VM_FAULT_SIGBUS;
-       else if (fault_size > dax_region->align)
+       else if (fault_size > dev_dax->align)
                return VM_FAULT_FALLBACK;
 
        /* if we are outside of the VMA */
@@ -200,7 +180,7 @@ static vm_fault_t __dev_dax_pud_fault(struct dev_dax *dev_dax,
                return VM_FAULT_SIGBUS;
        }
 
-       *pfn = phys_to_pfn_t(phys, dax_region->pfn_flags);
+       *pfn = phys_to_pfn_t(phys, PFN_DEV|PFN_MAP);
 
        return vmf_insert_pfn_pud(vmf, *pfn, vmf->flags & FAULT_FLAG_WRITE);
 }
@@ -280,9 +260,8 @@ static int dev_dax_split(struct vm_area_struct *vma, unsigned long addr)
 {
        struct file *filp = vma->vm_file;
        struct dev_dax *dev_dax = filp->private_data;
-       struct dax_region *dax_region = dev_dax->region;
 
-       if (!IS_ALIGNED(addr, dax_region->align))
+       if (!IS_ALIGNED(addr, dev_dax->align))
                return -EINVAL;
        return 0;
 }
@@ -291,9 +270,8 @@ static unsigned long dev_dax_pagesize(struct vm_area_struct *vma)
 {
        struct file *filp = vma->vm_file;
        struct dev_dax *dev_dax = filp->private_data;
-       struct dax_region *dax_region = dev_dax->region;
 
-       return dax_region->align;
+       return dev_dax->align;
 }
 
 static const struct vm_operations_struct dax_vm_ops = {
@@ -332,13 +310,11 @@ static unsigned long dax_get_unmapped_area(struct file *filp,
 {
        unsigned long off, off_end, off_align, len_align, addr_align, align;
        struct dev_dax *dev_dax = filp ? filp->private_data : NULL;
-       struct dax_region *dax_region;
 
        if (!dev_dax || addr)
                goto out;
 
-       dax_region = dev_dax->region;
-       align = dax_region->align;
+       align = dev_dax->align;
        off = pgoff << PAGE_SHIFT;
        off_end = off + len;
        off_align = round_up(off, align);
@@ -412,25 +388,45 @@ static void dev_dax_kill(void *dev_dax)
        kill_dev_dax(dev_dax);
 }
 
-int dev_dax_probe(struct device *dev)
+int dev_dax_probe(struct dev_dax *dev_dax)
 {
-       struct dev_dax *dev_dax = to_dev_dax(dev);
        struct dax_device *dax_dev = dev_dax->dax_dev;
-       struct resource *res = &dev_dax->region->res;
+       struct device *dev = &dev_dax->dev;
+       struct dev_pagemap *pgmap;
        struct inode *inode;
        struct cdev *cdev;
        void *addr;
-       int rc;
+       int rc, i;
 
-       /* 1:1 map region resource range to device-dax instance range */
-       if (!devm_request_mem_region(dev, res->start, resource_size(res),
-                               dev_name(dev))) {
-               dev_warn(dev, "could not reserve region %pR\n", res);
-               return -EBUSY;
+       pgmap = dev_dax->pgmap;
+       if (dev_WARN_ONCE(dev, pgmap && dev_dax->nr_range > 1,
+                       "static pgmap / multi-range device conflict\n"))
+               return -EINVAL;
+
+       if (!pgmap) {
+               pgmap = devm_kzalloc(dev, sizeof(*pgmap) + sizeof(struct range)
+                               * (dev_dax->nr_range - 1), GFP_KERNEL);
+               if (!pgmap)
+                       return -ENOMEM;
+               pgmap->nr_range = dev_dax->nr_range;
+       }
+
+       for (i = 0; i < dev_dax->nr_range; i++) {
+               struct range *range = &dev_dax->ranges[i].range;
+
+               if (!devm_request_mem_region(dev, range->start,
+                                       range_len(range), dev_name(dev))) {
+                       dev_warn(dev, "mapping%d: %#llx-%#llx could not reserve range\n",
+                                       i, range->start, range->end);
+                       return -EBUSY;
+               }
+               /* don't update the range for static pgmap */
+               if (!dev_dax->pgmap)
+                       pgmap->ranges[i] = *range;
        }
 
-       dev_dax->pgmap.type = MEMORY_DEVICE_GENERIC;
-       addr = devm_memremap_pages(dev, &dev_dax->pgmap);
+       pgmap->type = MEMORY_DEVICE_GENERIC;
+       addr = devm_memremap_pages(dev, pgmap);
        if (IS_ERR(addr))
                return PTR_ERR(addr);
 
@@ -456,17 +452,15 @@ int dev_dax_probe(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dev_dax_probe);
 
-static int dev_dax_remove(struct device *dev)
+static int dev_dax_remove(struct dev_dax *dev_dax)
 {
        /* all probe actions are unwound by devm */
        return 0;
 }
 
 static struct dax_device_driver device_dax_driver = {
-       .drv = {
-               .probe = dev_dax_probe,
-               .remove = dev_dax_remove,
-       },
+       .probe = dev_dax_probe,
+       .remove = dev_dax_remove,
        .match_always = 1,
 };