On 25/04/12 13:48, Kevin O'Connor wrote: > On Tue, Apr 24, 2012 at 06:25:39PM +1200, Alexey Korolev wrote: >> Migrate 64bit entries to 64bit pci regions if they do >> not fit in 32bit range. > [...] >> +static void pci_region_migrate_64bit_entries(struct pci_region *from, >> + struct pci_region *to) >> +{ >> + struct pci_region_entry **pprev = &from->list; >> + struct pci_region_entry **last = &to->list; >> + while(*pprev) { >> + if ((*pprev)->is64) { >> + struct pci_region_entry *entry; >> + entry = *pprev; >> + /* Delete the entry and move next */ >> + *pprev = (*pprev)->next; >> + /* Add entry at tail to keep a sorted order */ >> + entry->next = NULL; >> + if (*last) { >> + (*last)->next = entry; >> + last = &(*last)->next; >> + } >> + else >> + (*last) = entry; >> + } >> + else >> + pprev = &(*pprev)->next; >> + } >> +} > It should be possible to simplify this - something like (untested): > > static void pci_region_migrate_64bit_entries(struct pci_region *from, > struct pci_region *to) > { > struct pci_region_entry **pprev = &from->list, **last = &to->list; > for (; *pprev; pprev = &(*pprev)->next) { > struct pci_region_entry *entry = *pprev; > if (!entry->is64) > continue; > // Move from source list to dest list. > *pprev = entry->next; > entry->next = NULL; > *last = entry; > last = &entry->next; > } > } Sorry it's not working. I agree it's possible to simplify code a bit.
static void pci_region_migrate_64bit_entries(struct pci_region *from, struct pci_region *to) { struct pci_region_entry **pprev = &from->list; struct pci_region_entry **last = &to->list; while(*pprev) { if ((*pprev)->is64) { struct pci_region_entry *entry; entry = *pprev; /* Delete the entry and move next */ *pprev = (*pprev)->next; /* Add entry at tail to keep the order */ entry->next = NULL; *last = entry; last = &entry->next; } else pprev = &(*pprev)->next; } } That should work. > [...] >> static void pci_bios_map_devices(struct pci_bus *busses) >> { >> + if (pci_bios_init_root_regions(busses)) { >> + struct pci_region r64_mem, r64_pref; >> + r64_mem.list = NULL; >> + r64_pref.list = NULL; >> + pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_MEM], >> + &r64_mem); >> + >> pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_PREFMEM], >> + &r64_pref); >> + >> + if (pci_bios_init_root_regions(busses)) >> + panic("PCI: out of address space\n"); >> + >> + r64_mem.base = BUILD_PCIMEM64_START; >> + r64_pref.base = ALIGN(r64_mem.base + pci_region_sum(&r64_mem), >> + pci_region_align(&r64_pref)); > There should be a check to see if the regions fit. Maybe pass > start/end into pci_bios_init_root_regions() and call it again for the >> 4g region? Agree, I just ignored the check as 64bit range size is 2^39. I will think how to make it better. >> + pci_region_map_entries(busses, &r64_mem); >> + pci_region_map_entries(busses, &r64_pref); >> + } >> // Map regions on each device. > This doesn't look right to me. This will map the devices on bus 0 to > the proper >4g address, but devices on any subsequent bus will use > busses[0].r[].base which will be reset to the <4gig address. Perhaps > pull base out of pci_region and make pci_region_map_entries() > recursive? No recursion is need here! We map all entries which are 64bit on root bus. If entry is a bridge region - a corresponding bus address will be updated. Region won't be reseted to <4gig address as address is derived from parent region only. Thanks, Alexey