[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-ia64-devel] [Patch 4/4] Xwindow: Modify pci_acpi_scan_root()



Hi,

   Some more comments below.  Thanks for switching to the standard list
implementation, it looks better.  How do you propose coordinating the
patches for xen-ia64-devel vs the one for xen-devel?  Should we get the
latter in first, then proceed w/ the xen-ia64-devel patch?  Thanks,

        Alex

On Wed, 2007-06-13 at 15:56 +0900, Jun Kamada wrote:
> # HG changeset patch
> # User Jun Kamada <kama@xxxxxxxxxxxxxx>
> # Date 1181706151 -32400
> # Node ID 76e7ecd69d2ce751bf33784f62762c2ba8ed7162
> # Parent  7286707307032b6b3117a4f48aa4f0fdce6e7587
> Issue ioremap hypercall in pci_acpi_scan_root() in order to
> map /dev/mem.
> 
> Signed-off-by: Jun Kamada <kama@xxxxxxxxxxxxxx>
> 
> diff -r 728670730703 -r 76e7ecd69d2c
> linux-2.6-xen-sparse/arch/ia64/pci/pci.c
> --- a/linux-2.6-xen-sparse/arch/ia64/pci/pci.c  Wed Jun 13 12:38:18
> 2007 +0900
> +++ b/linux-2.6-xen-sparse/arch/ia64/pci/pci.c  Wed Jun 13 12:42:31
> 2007 +0900
> @@ -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
> @@ -332,6 +341,165 @@ pcibios_setup_root_windows(struct pci_bu
>         }
>  }
>  
> +#ifdef CONFIG_XEN
> +
> +#define MIN(x,y)       (((x) <= (y)) ? (x) : (y))
> +#define MAX(x,y)       (((x) >= (y)) ? (x) : (y))

min() and max() are already defined in kernel.h, can you make use of
those?

> +static int
> +__add_issue_list(unsigned long start, unsigned long end,
> +                ioremap_issue_list_t *top)
> +{
> +       ioremap_issue_list_t    *ptr, *new;
> +
> +       if (start > end) {
> +               printk(KERN_ERR "%s: Internal error (start addr > end
> addr)\n",
> +                          __FUNCTION__);
> +               return 0;
> +       }
> +
> +       start &= ~(PAGE_SIZE - 1);

Use PAGE_MASK

> +       end   |=  (PAGE_SIZE - 1);

And ~PAGE_MASK

> +
> +       list_for_each_entry(ptr, &(top->listp), listp) {
> +               if (((ptr->start >= start) && (ptr->start <= end + 1))
> ||
> +                   ((ptr->end >= start - 1) && (ptr->end <= end))
> ||
> +                   ((start >= ptr->start) && (start <= ptr->end) &&
> +                    (end >= ptr->start) && (end <= ptr->end))) {
> +                       ptr->start = MIN(start, ptr->start);
> +                       ptr->end   = MAX(end, ptr->end);
> +                       return 0;
> +               }

Can't this be greatly simplified?  Instead of checking all the degrees
of overlap, just look for the non-overlap cases.  Everything else is
overlap

                if (ptr->start > end + 1 || ptr->end + 1 < start)
                        continue;

                ptr->start = min(start, ptr->start);
                ptr->end = max(end, ptr->end);
                return 0;

However, what if this grows the range such that it bumps into the
entries around it.  Do you plan to merge them?  Maybe keeping the list
sorted would make this easier.

> +       }
> +
> +       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;
> +
> +       list_add(&(new->listp), &(top->listp));
> +
> +       return 0;
> +}
> +
> +static int
> +__make_issue_list(struct resource *ptr, ioremap_issue_list_t *top) {
> +       unsigned int    curr_lvl = 1;
> +       unsigned int    prev_lvl = 0;
> +       int             ret;
> +
> +       for ( ;; ) {
> +               if (ptr->flags & IORESOURCE_MEM) {
> +                       ret = __add_issue_list(ptr->start, ptr->end,
> top);
> +                       if (ret)
> +                               return ret;
> +               }
> +

Thanks, the comments below are helpful, but wouldn't it make sense to do
this as a recursive algorithm?  Doesn't something like this do the same
thing (untested)?

int scan_foo(struct resource *res, ioremap_issue_list_t *list)
{
        int ret;

        if (res->child) {
                ret = scan_foo(res->child, list);
                if (ret)
                        return ret;
        }
        if (res->sibling) {
                ret = scan_foo(res->sibling, list);
                if (ret)
                        return ret;
        }

        if (ptr->flags & IORESOURCE_MEM) {
                ret = __add_issue_list(res->start, res->end, list);
                if (ret)
                        return ret;
        }
        return 0;
}

> +               /* means that the "ptr" came here from parent (upper
> level) */
> +               if (curr_lvl > prev_lvl) {
> +                       /* child exists, so go down to the child */
> +                       if (ptr->child != 0) {
> +                               ptr = ptr->child;
> +                               curr_lvl++;
> +                               prev_lvl++;
> +                       /* sibling exists, so go to the sibling */
> +                       } else if (ptr->sibling != 0) {
> +                               ptr = ptr->sibling;
> +                       /* no child and no sibling exist, so go up to
> parent */
> +                       } else {
> +                               ptr = ptr->parent;
> +                               curr_lvl--;
> +                               prev_lvl++;
> +                               if (curr_lvl == 0)
> +                                       return 0;
> +                       }
> +
> +               /* means that the "ptr" came here from child (lower
> level) */
> +               } else if (curr_lvl < prev_lvl) {
> +                       /* sibling exists, so go to the sibling */
> +                       if (ptr->sibling != 0) {
> +                               ptr = ptr->sibling;
> +                               prev_lvl = curr_lvl - 1;
> +                       /* no sibling exists, so go up to parent */
> +                       } else {
> +                               ptr = ptr->parent;
> +                               curr_lvl--;
> +                               prev_lvl--;
> +                               if (curr_lvl == 0)
> +                                       return 0;
> +                       }
> +               } else {
> +                       printk(KERN_ERR "%s: Internal error. "
> +                              "Must not reach here\n", __FUNCTION__);
> +                       return -EFAULT;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int
> +__issue_ioremap(struct ioremap_issue_list *top)
> +{
> +       ioremap_issue_list_t    *ptr, *tmp_ptr;
> +       unsigned int            offset;
> +
> +       list_for_each_entry(ptr, &(top->listp), 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_for_each_entry_safe(ptr, tmp_ptr, &(top->listp), listp) {
> +               list_del(&(ptr->listp));
> +               kfree(ptr);
> +       }

   These could be done in the same pass through the list.

> +       return 0;
> +}
> +
> +static int
> +do_ioremap_on_resource_list(struct resource *ptr)
> +{
> +       ioremap_issue_list_t    *ioremap_issue_list_top;
> +       int                     ret;
> +
> +       ioremap_issue_list_top = kmalloc(sizeof(ioremap_issue_list_t),
> +                                        GFP_KERNEL);
> +       if (ioremap_issue_list_top == NULL)
> +               return -ENOMEM;

  The top of the list doesn't need to be an ioremap_issue_list_t, it can
just be a struct list.  That could just be put on the stack rather than
dynamically allocated.

> +
> +       INIT_LIST_HEAD(&(ioremap_issue_list_top->listp));
> +

   If you took the recursive approach above, these could be eliminated,
just call scan_foo(ptr, &list).

> +       if (ptr->child != 0) {
> +               ret = __make_issue_list(ptr->child,
> ioremap_issue_list_top);
> +               if (ret) {

memory leak - be careful to do list_del & kfree should anything fail

> +                       return ret;
> +               }
> +       }
> +       if (ptr->sibling != 0) {
> +               ret = __make_issue_list(ptr->sibling,
> ioremap_issue_list_top);
> +               if (ret) {

memory leak - ditto

> +                       return ret;
> +               }
> +       }
> +
> +       (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)
>  {
> @@ -374,6 +542,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;
>   
-- 
Alex Williamson                             HP Open Source & Linux Org.


_______________________________________________
Xen-ia64-devel mailing list
Xen-ia64-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-ia64-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.