From patchwork Fri Jan 21 21:06:37 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Wysocki X-Patchwork-Id: 496761 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p0LL75aC010782 for ; Fri, 21 Jan 2011 21:07:05 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752174Ab1AUVHE (ORCPT ); Fri, 21 Jan 2011 16:07:04 -0500 Received: from ogre.sisk.pl ([217.79.144.158]:40977 "EHLO ogre.sisk.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752049Ab1AUVHC (ORCPT ); Fri, 21 Jan 2011 16:07:02 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by ogre.sisk.pl (Postfix) with ESMTP id 6C5071A2C51; Fri, 21 Jan 2011 21:51:16 +0100 (CET) Received: from ogre.sisk.pl ([127.0.0.1]) by localhost (ogre.sisk.pl [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 04040-03; Fri, 21 Jan 2011 21:51:01 +0100 (CET) Received: from ferrari.rjw.lan (220-bem-13.acn.waw.pl [82.210.184.220]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ogre.sisk.pl (Postfix) with ESMTP id 058ED1A2C13; Fri, 21 Jan 2011 21:51:01 +0100 (CET) From: "Rafael J. Wysocki" To: Jeff Chua Subject: Re: [PATCH 0/11] ACPI: Fixes and cleanups related to iomaps management Date: Fri, 21 Jan 2011 22:06:37 +0100 User-Agent: KMail/1.13.5 (Linux/2.6.38-rc1+; KDE/4.4.4; x86_64; ; ) Cc: Len Brown , LKML , ACPI Devel Maling List , "Linux-pm mailing list" , Matthew Garrett References: <201101201226.41021.rjw@sisk.pl> <201101210104.43641.rjw@sisk.pl> In-Reply-To: MIME-Version: 1.0 Message-Id: <201101212206.37469.rjw@sisk.pl> X-Virus-Scanned: amavisd-new at ogre.sisk.pl using MkS_Vir for Linux Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Fri, 21 Jan 2011 21:07:09 +0000 (UTC) Index: linux-2.6/drivers/acpi/nvs.c =================================================================== --- linux-2.6.orig/drivers/acpi/nvs.c +++ linux-2.6/drivers/acpi/nvs.c @@ -22,15 +22,15 @@ */ struct nvs_page { - unsigned long phys_start; unsigned int size; - void *kaddr; + void __iomem *kaddr; void *data; bool unmap; - struct list_head node; }; -static LIST_HEAD(nvs_list); +static struct nvs_page *nvs; +static unsigned long nvs_start; +static unsigned int nvs_span; /** * suspend_nvs_register - register platform NVS memory region to save @@ -43,31 +43,40 @@ static LIST_HEAD(nvs_list); */ int suspend_nvs_register(unsigned long start, unsigned long size) { - struct nvs_page *entry, *next; + struct nvs_page *p, *p_end; + unsigned int head, tail; - while (size > 0) { - unsigned int nr_bytes; + pr_info("PM: Registering ACPI NVS region at %lx (%ld bytes)\n", + start, size); - entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL); - if (!entry) - goto Error; - - list_add_tail(&entry->node, &nvs_list); - entry->phys_start = start; - nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK); - entry->size = (size < nr_bytes) ? size : nr_bytes; - - start += entry->size; - size -= entry->size; + nvs_start = start; + head = PAGE_SIZE - (start & ~PAGE_MASK); + if (head) { + nvs_span = 1; + size -= size > head ? head : size; + } else { + nvs_span = 0; + head = PAGE_SIZE; } - return 0; + nvs_span += size >> PAGE_SHIFT; + tail = size & ~PAGE_MASK; + if (tail) + nvs_span++; + else + tail = PAGE_SIZE; + + nvs = kzalloc(sizeof(*nvs) * nvs_span, GFP_KERNEL); + if (!nvs) + return -ENOMEM; + + p = nvs; + p->size = head; + for (p++, p_end = nvs + nvs_span - 1; p < p_end; p++) + p->size = PAGE_SIZE; + if (p_end > nvs) + p_end->size = tail; - Error: - list_for_each_entry_safe(entry, next, &nvs_list, node) { - list_del(&entry->node); - kfree(entry); - } - return -ENOMEM; + return 0; } /** @@ -75,17 +84,23 @@ int suspend_nvs_register(unsigned long s */ void suspend_nvs_free(void) { - struct nvs_page *entry; + struct nvs_page *entry, *end; - list_for_each_entry(entry, &nvs_list, node) + for (entry = nvs, end = nvs + nvs_span; entry < end; entry++) if (entry->data) { free_page((unsigned long)entry->data); entry->data = NULL; if (entry->kaddr) { if (entry->unmap) { + pr_info("%s: Unmapping %p\n", __func__, + entry->kaddr); + iounmap(entry->kaddr); entry->unmap = false; } else { + pr_info("%s: Releasing %p\n", __func__, + entry->kaddr); + acpi_os_unmap_memory(entry->kaddr, entry->size); } @@ -99,9 +114,9 @@ void suspend_nvs_free(void) */ int suspend_nvs_alloc(void) { - struct nvs_page *entry; + struct nvs_page *entry, *end; - list_for_each_entry(entry, &nvs_list, node) { + for (entry = nvs, end = nvs + nvs_span; entry < end; entry++) { entry->data = (void *)__get_free_page(GFP_KERNEL); if (!entry->data) { suspend_nvs_free(); @@ -116,26 +131,44 @@ int suspend_nvs_alloc(void) */ int suspend_nvs_save(void) { - struct nvs_page *entry; + struct nvs_page *entry, *end; + unsigned long phys = nvs_start; printk(KERN_INFO "PM: Saving platform NVS memory\n"); - list_for_each_entry(entry, &nvs_list, node) - if (entry->data) { - unsigned long phys = entry->phys_start; - unsigned int size = entry->size; + for (entry = nvs, end = nvs + nvs_span; entry < end; entry++) { + unsigned int size = entry->size; + void __iomem *kaddr; - entry->kaddr = acpi_os_get_iomem(phys, size); - if (!entry->kaddr) { - entry->kaddr = acpi_os_ioremap(phys, size); - entry->unmap = true; - } - if (!entry->kaddr) { - suspend_nvs_free(); - return -ENOMEM; - } - memcpy(entry->data, entry->kaddr, entry->size); + if (!entry->data) { + suspend_nvs_free(); + return -ENOMEM; + } + + pr_info("%s: Trying to map %lx, %d\n", __func__, phys, size); + + kaddr = acpi_os_get_iomem(phys, size); + if (!kaddr) { + kaddr = acpi_os_ioremap(phys, size); + entry->unmap = !!kaddr; + } else { + pr_info("%s: Got address %p\n", __func__, kaddr); } + entry->kaddr = kaddr; + + if (!entry->kaddr) { + pr_info("%s: Mapping failed\n", __func__); + + suspend_nvs_free(); + return -EIO; + } else { + pr_info("%s: Using address %p\n", __func__, entry->kaddr); + } + + memcpy(entry->data, entry->kaddr, size); + + phys += size; + } return 0; } @@ -148,11 +181,11 @@ int suspend_nvs_save(void) */ void suspend_nvs_restore(void) { - struct nvs_page *entry; + struct nvs_page *entry, *end; printk(KERN_INFO "PM: Restoring platform NVS memory\n"); - list_for_each_entry(entry, &nvs_list, node) + for (entry = nvs, end = nvs + nvs_span; entry < end; entry++) if (entry->data) memcpy(entry->kaddr, entry->data, entry->size); }