These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / kernel / resource.c
index 90552aa..249b1eb 100644 (file)
@@ -492,40 +492,51 @@ int __weak page_is_ram(unsigned long pfn)
 }
 EXPORT_SYMBOL_GPL(page_is_ram);
 
-/*
- * Search for a resouce entry that fully contains the specified region.
- * If found, return 1 if it is RAM, 0 if not.
- * If not found, or region is not fully contained, return -1
+/**
+ * region_intersects() - determine intersection of region with known resources
+ * @start: region start address
+ * @size: size of region
+ * @name: name of resource (in iomem_resource)
  *
- * Used by the ioremap functions to ensure the user is not remapping RAM and is
- * a vast speed up over walking through the resource table page by page.
+ * Check if the specified region partially overlaps or fully eclipses a
+ * resource identified by @name.  Return REGION_DISJOINT if the region
+ * does not overlap @name, return REGION_MIXED if the region overlaps
+ * @type and another resource, and return REGION_INTERSECTS if the
+ * region overlaps @type and no other defined resource. Note, that
+ * REGION_INTERSECTS is also returned in the case when the specified
+ * region overlaps RAM and undefined memory holes.
+ *
+ * region_intersect() is used by memory remapping functions to ensure
+ * the user is not remapping RAM and is a vast speed up over walking
+ * through the resource table page by page.
  */
-int region_is_ram(resource_size_t start, unsigned long size)
+int region_intersects(resource_size_t start, size_t size, const char *name)
 {
-       struct resource *p;
+       unsigned long flags = IORESOURCE_MEM | IORESOURCE_BUSY;
        resource_size_t end = start + size - 1;
-       int flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-       const char *name = "System RAM";
-       int ret = -1;
+       int type = 0; int other = 0;
+       struct resource *p;
 
        read_lock(&resource_lock);
        for (p = iomem_resource.child; p ; p = p->sibling) {
-               if (end < p->start)
-                       continue;
-
-               if (p->start <= start && end <= p->end) {
-                       /* resource fully contains region */
-                       if ((p->flags != flags) || strcmp(p->name, name))
-                               ret = 0;
-                       else
-                               ret = 1;
-                       break;
-               }
-               if (p->end < start)
-                       break;  /* not found */
+               bool is_type = strcmp(p->name, name) == 0 && p->flags == flags;
+
+               if (start >= p->start && start <= p->end)
+                       is_type ? type++ : other++;
+               if (end >= p->start && end <= p->end)
+                       is_type ? type++ : other++;
+               if (p->start >= start && p->end <= end)
+                       is_type ? type++ : other++;
        }
        read_unlock(&resource_lock);
-       return ret;
+
+       if (other == 0)
+               return type ? REGION_INTERSECTS : REGION_DISJOINT;
+
+       if (type)
+               return REGION_MIXED;
+
+       return REGION_DISJOINT;
 }
 
 void __weak arch_remove_reservations(struct resource *avail)
@@ -1072,9 +1083,10 @@ struct resource * __request_region(struct resource *parent,
                if (!conflict)
                        break;
                if (conflict != parent) {
-                       parent = conflict;
-                       if (!(conflict->flags & IORESOURCE_BUSY))
+                       if (!(conflict->flags & IORESOURCE_BUSY)) {
+                               parent = conflict;
                                continue;
+                       }
                }
                if (conflict->flags & flags & IORESOURCE_MUXED) {
                        add_wait_queue(&muxed_resource_wait, &wait);