# HG changeset patch
# User Alex Williamson <alex.williamson@xxxxxx>
# 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@xxxxxxxxxxxxxx>
---
arch/ia64/pci/pci.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 184 insertions(+)
diff -r f017328288ea -r 8f0c93df3e11 arch/ia64/pci/pci.c
--- a/arch/ia64/pci/pci.c Mon Jul 30 10:53:36 2007 -0600
+++ b/arch/ia64/pci/pci.c Mon Jul 30 11:01:27 2007 -0600
@@ -29,6 +29,15 @@
#include <asm/smp.h>
#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
@@ -337,6 +346,169 @@ pcibios_setup_root_windows(struct pci_bu
}
}
+#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)
{
@@ -379,6 +551,18 @@ pci_acpi_scan_root(struct acpi_device *d
pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
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;
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|