Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2687

kernel-2.6.18-128.1.10.el5.src.rpm

From: Tetsu Yamamoto <tyamamot@redhat.com>
Date: Mon, 4 Aug 2008 15:48:31 -0400
Subject: [xen] ia64: issue ioremap HC in pci_acpi_scan_root
Message-id: 20080804194830.8452.35387.sendpatchset@pq0-1.lab.bos.redhat.com
O-Subject: [RHEL5.3 PATCH 7/10] xen-ia64: Issue ioremap hypercall in pci_acpi_scan_root()
Bugzilla: 430219
RH-Acked-by: Bill Burns <bburns@redhat.com>

bz430219
# HG changeset patch
# User Alex Williamson <alex.williamson@hp.com>
# Date 1185814887 21600
# Node ID 8f0c93df3e113058f0b582b06ce7d3d897ccc9d6
# Parent  f017328288ea42600509b62882f687d7331ce194
[IA64] Issue ioremap hypercall in pci_acpi_scan_root()

This setups up mapping in /dev/mem.

Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>

diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 5c6464a..8d272a1 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -30,6 +30,15 @@
 #include <asm/irq.h>
 #include <asm/hw_irq.h>
 
+#ifdef CONFIG_XEN
+struct ioremap_issue_list {
+	struct list_head		listp;
+	unsigned long			start;
+	unsigned long			end;
+};
+typedef struct ioremap_issue_list	ioremap_issue_list_t;
+#endif /* CONFIG_XEN */
+
 /*
  * Low-level SAL-based PCI configuration access functions. Note that SAL
  * calls are already serialized (via sal_lock), so we don't need another
@@ -337,6 +346,169 @@ pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
 	}
 }
 
+#ifdef CONFIG_XEN
+static void
+__cleanup_issue_list(struct list_head *top)
+{
+	ioremap_issue_list_t *ptr, *tmp_ptr;
+
+	list_for_each_entry_safe(ptr, tmp_ptr, top, listp) {
+		list_del(&(ptr->listp));
+		kfree(ptr);
+	}
+}
+
+static int
+__add_issue_list(unsigned long start, unsigned long end, struct list_head *top)
+{
+	ioremap_issue_list_t *ptr, *new;
+
+	if (start > end) {
+		printk(KERN_ERR "%s: Internal error (start addr > end addr)\n",
+		       __FUNCTION__);
+		return 0;
+	}
+
+	/*
+	 * Head of the resource structure list contains
+	 * dummy val.(start=0, end=~0), so skip it
+	 */
+	if ((start == 0) && (end == ~0))
+		return 0;
+
+	start &= PAGE_MASK;
+	end |= ~PAGE_MASK;
+
+	/* We can merge specified address range into existing entry */
+	list_for_each_entry(ptr, top, listp) {
+		if ((ptr->start > end + 1) || (ptr->end + 1 < start))
+			continue;
+		ptr->start = min(start, ptr->start);
+		ptr->end = max(end, ptr->end);
+		return 0;
+	}
+
+	/* We could not merge, so create new entry */
+	new = kmalloc(sizeof(ioremap_issue_list_t), GFP_KERNEL);
+	if (new == NULL) {
+		printk(KERN_ERR "%s: Could not allocate memory. "
+		       "HYPERVISOR_ioremap will not be issued\n",
+		       __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	new->start = start;
+	new->end = end;
+
+	/* Insert the new entry to the list by ascending order */
+	if (list_empty(top)) {
+		list_add_tail(&(new->listp), top);
+		return 0;
+	}
+	list_for_each_entry(ptr, top, listp) {
+		if (new->start > ptr->start)
+			continue;
+		list_add(&(new->listp), ((struct list_head *)ptr)->prev);
+		return 0;
+	}
+	list_add_tail(&(new->listp), top);
+
+	return 0;
+}
+
+static int
+__make_issue_list(struct resource *ptr, struct list_head *top)
+{
+	int ret;
+
+	if (ptr->child) {
+		ret = __make_issue_list(ptr->child, top);
+		if (ret)
+			return ret;
+	}
+	if (ptr->sibling) {
+		ret = __make_issue_list(ptr->sibling, top);
+		if (ret)
+			return ret;
+	}
+
+	if (ptr->flags & IORESOURCE_MEM) {
+		ret = __add_issue_list(ptr->start, ptr->end, top);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void
+__compress_issue_list(struct list_head *top)
+{
+	ioremap_issue_list_t *ptr, *tmp_ptr, *next;
+	int compressed;
+
+	/*
+	 * Merge adjacent entries, if overlapped
+	 * (entries are sorted by ascending order)
+	 */
+	list_for_each_entry_safe(ptr, tmp_ptr, top, listp) {
+		if (list_is_last((struct list_head *)ptr, top))
+			continue;
+
+		next = (ioremap_issue_list_t *)
+			(((struct list_head *)ptr)->next);
+		if (next->start <= (ptr->end) + 1) {
+			next->start = min(ptr->start, next->start);
+			next->end   = max(ptr->end, next->end);
+
+			list_del(&(ptr->listp));
+			kfree(ptr);
+		}
+	}
+}
+
+static int
+__issue_ioremap(struct list_head *top)
+{
+	ioremap_issue_list_t *ptr, *tmp_ptr;
+	unsigned int offset;
+
+	list_for_each_entry_safe(ptr, tmp_ptr, top, listp) {
+		offset = HYPERVISOR_ioremap(ptr->start,
+					    ptr->end - ptr->start + 1);
+		if (offset == ~0) {
+			printk(KERN_ERR "%s: HYPERVISOR_ioremap() failed. "
+			       "Address Range: 0x%016lx-0x%016lx\n",
+			       __FUNCTION__, ptr->start, ptr->end);
+		}
+
+		list_del(&(ptr->listp));
+		kfree(ptr);
+	}
+	
+	return 0;
+}
+
+static int
+do_ioremap_on_resource_list(struct resource *top)
+{
+	LIST_HEAD(ioremap_issue_list_top);
+	int ret;
+
+	ret = __make_issue_list(top, &ioremap_issue_list_top);
+	if (ret) {
+		__cleanup_issue_list(&ioremap_issue_list_top);
+		return ret;
+	}
+
+	__compress_issue_list(&ioremap_issue_list_top);
+
+	(void)__issue_ioremap(&ioremap_issue_list_top);
+
+	return 0;
+}
+#endif /* CONFIG_XEN */
+
 struct pci_bus * __devinit
 pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
 {
@@ -380,6 +552,18 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
 	if (pbus)
 		pcibios_setup_root_windows(pbus, controller);
 
+#ifdef CONFIG_XEN
+	if (is_initial_xendomain()) {
+		if (do_ioremap_on_resource_list(&iomem_resource) != 0) {
+			printk(KERN_ERR
+			       "%s: Counld not issue HYPERVISOR_ioremap "
+			       "due to lack of memory or hypercall failure\n",
+			       __FUNCTION__);
+			goto out3;
+		}
+	}
+#endif /* CONFIG_XEN */
+
 	return pbus;
 
 out3: