clk: rockchip: rk3368: add CLK_SET_RATE_PARENT flag for dclk_vop
[firefly-linux-kernel-4.4.55.git] / drivers / acpi / acpi_memhotplug.c
index 5e6301e949206adb9f9b512a4b44b9d093e588df..6b0d3ef7309cb710a63b38848ad35b770fed3c1a 100644 (file)
  * NON INFRINGEMENT.  See the GNU General Public License for more
  * details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
  * ACPI based HotPlug driver that supports Memory Hotplug
  * This driver fields notifications from firmware for memory add
  * and remove operations and alerts the VM of the affected memory
@@ -28,6 +23,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/memory.h>
 #include <linux/memory_hotplug.h>
 
 #include "internal.h"
 
 ACPI_MODULE_NAME("acpi_memhotplug");
 
+static const struct acpi_device_id memory_device_ids[] = {
+       {ACPI_MEMORY_DEVICE_HID, 0},
+       {"", 0},
+};
+
+#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
+
 /* Memory Device States */
 #define MEMORY_INVALID_STATE   0
 #define MEMORY_POWER_ON_STATE  1
@@ -52,11 +55,6 @@ static int acpi_memory_device_add(struct acpi_device *device,
                                  const struct acpi_device_id *not_used);
 static void acpi_memory_device_remove(struct acpi_device *device);
 
-static const struct acpi_device_id memory_device_ids[] = {
-       {ACPI_MEMORY_DEVICE_HID, 0},
-       {"", 0},
-};
-
 static struct acpi_scan_handler memory_device_handler = {
        .ids = memory_device_ids,
        .attach = acpi_memory_device_add,
@@ -98,8 +96,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
                /* Can we combine the resource range information? */
                if ((info->caching == address64.info.mem.caching) &&
                    (info->write_protect == address64.info.mem.write_protect) &&
-                   (info->start_addr + info->length == address64.minimum)) {
-                       info->length += address64.address_length;
+                   (info->start_addr + info->length == address64.address.minimum)) {
+                       info->length += address64.address.address_length;
                        return AE_OK;
                }
        }
@@ -111,8 +109,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
        INIT_LIST_HEAD(&new->list);
        new->caching = address64.info.mem.caching;
        new->write_protect = address64.info.mem.write_protect;
-       new->start_addr = address64.minimum;
-       new->length = address64.address_length;
+       new->start_addr = address64.address.minimum;
+       new->length = address64.address.address_length;
        list_add_tail(&new->list, &mem_device->res_list);
 
        return AE_OK;
@@ -151,8 +149,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
        unsigned long long current_status;
 
        /* Get device present/absent information from the _STA */
-       if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_STA",
-                                              NULL, &current_status)))
+       if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle,
+                                              METHOD_NAME__STA, NULL,
+                                              &current_status)))
                return -ENODEV;
        /*
         * Check for device status. Device should be
@@ -166,13 +165,49 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
        return 0;
 }
 
+static unsigned long acpi_meminfo_start_pfn(struct acpi_memory_info *info)
+{
+       return PFN_DOWN(info->start_addr);
+}
+
+static unsigned long acpi_meminfo_end_pfn(struct acpi_memory_info *info)
+{
+       return PFN_UP(info->start_addr + info->length-1);
+}
+
+static int acpi_bind_memblk(struct memory_block *mem, void *arg)
+{
+       return acpi_bind_one(&mem->dev, arg);
+}
+
+static int acpi_bind_memory_blocks(struct acpi_memory_info *info,
+                                  struct acpi_device *adev)
+{
+       return walk_memory_range(acpi_meminfo_start_pfn(info),
+                                acpi_meminfo_end_pfn(info), adev,
+                                acpi_bind_memblk);
+}
+
+static int acpi_unbind_memblk(struct memory_block *mem, void *arg)
+{
+       acpi_unbind_one(&mem->dev);
+       return 0;
+}
+
+static void acpi_unbind_memory_blocks(struct acpi_memory_info *info)
+{
+       walk_memory_range(acpi_meminfo_start_pfn(info),
+                         acpi_meminfo_end_pfn(info), NULL, acpi_unbind_memblk);
+}
+
 static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
 {
+       acpi_handle handle = mem_device->device->handle;
        int result, num_enabled = 0;
        struct acpi_memory_info *info;
        int node;
 
-       node = acpi_get_node(mem_device->device->handle);
+       node = acpi_get_node(handle);
        /*
         * Tell the VM there is more memory here...
         * Note: Assume that this function returns zero on success
@@ -203,6 +238,12 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
                if (result && result != -EEXIST)
                        continue;
 
+               result = acpi_bind_memory_blocks(info, mem_device->device);
+               if (result) {
+                       acpi_unbind_memory_blocks(info);
+                       return -ENODEV;
+               }
+
                info->enabled = 1;
 
                /*
@@ -227,28 +268,24 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
        return 0;
 }
 
-static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
+static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
 {
-       int result = 0, nid;
+       acpi_handle handle = mem_device->device->handle;
        struct acpi_memory_info *info, *n;
-
-       nid = acpi_get_node(mem_device->device->handle);
+       int nid = acpi_get_node(handle);
 
        list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
                if (!info->enabled)
                        continue;
 
-               if (nid < 0)
+               if (nid == NUMA_NO_NODE)
                        nid = memory_add_physaddr_to_nid(info->start_addr);
-               result = remove_memory(nid, info->start_addr, info->length);
-               if (result)
-                       return result;
 
+               acpi_unbind_memory_blocks(info);
+               remove_memory(nid, info->start_addr, info->length);
                list_del(&info->list);
                kfree(info);
        }
-
-       return result;
 }
 
 static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
@@ -283,6 +320,7 @@ static int acpi_memory_device_add(struct acpi_device *device,
        /* Get the range from the _CRS */
        result = acpi_memory_get_device_resources(mem_device);
        if (result) {
+               device->driver_data = NULL;
                kfree(mem_device);
                return result;
        }
@@ -300,7 +338,7 @@ static int acpi_memory_device_add(struct acpi_device *device,
        if (result) {
                dev_err(&device->dev, "acpi_memory_enable_device() error\n");
                acpi_memory_device_free(mem_device);
-               return -ENODEV;
+               return result;
        }
 
        dev_dbg(&device->dev, "Memory device configured by ACPI\n");
@@ -319,7 +357,34 @@ static void acpi_memory_device_remove(struct acpi_device *device)
        acpi_memory_device_free(mem_device);
 }
 
+static bool __initdata acpi_no_memhotplug;
+
 void __init acpi_memory_hotplug_init(void)
 {
+       if (acpi_no_memhotplug) {
+               memory_device_handler.attach = NULL;
+               acpi_scan_add_handler(&memory_device_handler);
+               return;
+       }
        acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
 }
+
+static int __init disable_acpi_memory_hotplug(char *str)
+{
+       acpi_no_memhotplug = true;
+       return 1;
+}
+__setup("acpi_no_memhotplug", disable_acpi_memory_hotplug);
+
+#else
+
+static struct acpi_scan_handler memory_device_handler = {
+       .ids = memory_device_ids,
+};
+
+void __init acpi_memory_hotplug_init(void)
+{
+       acpi_scan_add_handler(&memory_device_handler);
+}
+
+#endif /* CONFIG_ACPI_HOTPLUG_MEMORY */