]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
drivers:hv: Lock access to hyperv_mmio resource tree
authorJake Oshins <jakeo@microsoft.com>
Tue, 5 Apr 2016 17:22:50 +0000 (10:22 -0700)
committerTim Gardner <tim.gardner@canonical.com>
Fri, 16 Sep 2016 17:08:45 +0000 (11:08 -0600)
BugLink: http://bugs.launchpad.net/bugs/1616677
In existing code, this tree of resources is created
in single-threaded code and never modified after it is
created, and thus needs no locking.  This patch introduces
a semaphore for tree access, as other patches in this
series introduce run-time modifications of this resource
tree which can happen on multiple threads.

Signed-off-by: Jake Oshins <jakeo@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(back ported from commit e16dad6bfe1437aaee565f875a6713ca7ce81bdf)
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
 Conflicts:
drivers/hv/vmbus_drv.c
Acked-by: Brad Figg <brad.figg@canonical.com>
Acked-by: Kamal Mostafa <kamal@canonical.com>
drivers/hv/vmbus_drv.c

index 7649a4d8dc300cb7492a8a5f22971a1ecb3582fe..10fb2fe7f44d2b0328b4442e15fd84753bd3f109 100644 (file)
@@ -1164,10 +1164,11 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
                        resource_size_t size, resource_size_t align,
                        bool fb_overlap_ok)
 {
-       struct resource *iter, *shadow;
-       resource_size_t range_min, range_max, start;
+       struct resource *iter;
+       resource_size_t range_min, range_max, start, local_min, local_max;
        const char *dev_n = dev_name(&device_obj->device);
-       int retval;
+       u32 fb_end = screen_info.lfb_base + (screen_info.lfb_size << 1);
+       int i, retval;
 
        retval = -ENXIO;
        down(&hyperv_mmio_lock);
@@ -1198,21 +1199,40 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
 
                range_min = iter->start;
                range_max = iter->end;
-               start = (range_min + align - 1) & ~(align - 1);
-               for (; start + size - 1 <= range_max; start += align) {
-                       shadow = __request_region(iter, start, size, NULL,
-                                                 IORESOURCE_BUSY);
-                       if (!shadow)
-                               continue;
 
-                       *new = request_mem_region_exclusive(start, size, dev_n);
-                       if (*new) {
-                               shadow->name = (char *)*new;
-                               retval = 0;
-                               goto exit;
+               /* If this range overlaps the frame buffer, split it into
+                  two tries. */
+               for (i = 0; i < 2; i++) {
+                       local_min = range_min;
+                       local_max = range_max;
+                       if (fb_overlap_ok || (range_min >= fb_end) ||
+                           (range_max <= screen_info.lfb_base)) {
+                               i++;
+                       } else {
+                               if ((range_min <= screen_info.lfb_base) &&
+                                   (range_max >= screen_info.lfb_base)) {
+                                       /*
+                                        * The frame buffer is in this window,
+                                        * so trim this into the part that
+                                        * preceeds the frame buffer.
+                                        */
+                                       local_max = screen_info.lfb_base - 1;
+                                       range_min = fb_end;
+                               } else {
+                                       range_min = fb_end;
+                                       continue;
+                               }
                        }
 
-                       __release_region(iter, start, size);
+                       start = (local_min + align - 1) & ~(align - 1);
+                       for (; start + size - 1 <= local_max; start += align) {
+                               *new = request_mem_region_exclusive(start, size,
+                                                                   dev_n);
+                               if (*new) {
+                                       retval = 0;
+                                       goto exit;
+                               }
+                       }
                }
        }