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
|