This patch is all about service functions It includes: - basic operations with lists - 64bit modification of Pci_size_roundup() - modification of pci_bios_get_bar to support HUGE bars (size over 4GB) - 2 service function to get pci_region statistics - dump entry - for debug output
Signed-off-by: Alexey Korolev alexey.korolev@endace.com --- src/pciinit.c | 132 +++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 91 insertions(+), 41 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index 2e5416c..dbfa4f2 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -51,33 +51,30 @@ struct pci_region { u64 base; };
-static int pci_size_to_index(u32 size, enum pci_region_type type) -{ - int index = __fls(size); - int shift = (type == PCI_REGION_TYPE_IO) ? - PCI_IO_INDEX_SHIFT : PCI_MEM_INDEX_SHIFT; - - if (index < shift) - index = shift; - index -= shift; - return index; -} +#define foreach_region_entry(R, ENTRY) \ + for (ENTRY = (R)->list; ENTRY; ENTRY = ENTRY->next)
-static u32 pci_index_to_size(int index, enum pci_region_type type) -{ - int shift = (type == PCI_REGION_TYPE_IO) ? - PCI_IO_INDEX_SHIFT : PCI_MEM_INDEX_SHIFT; +#define foreach_region_entry_safe(R, N, ENTRY) \ + for (ENTRY = (R)->list; ENTRY && ({N=ENTRY->next; 1;}); \ + ENTRY = N)
- return 0x1 << (index + shift); +static inline void region_entry_del(struct pci_region_entry *entry) +{ + struct pci_region_entry *next = entry->next; + *entry->pprev = next; + if (next) + next->pprev = entry->pprev; }
-static enum pci_region_type pci_addr_to_type(u32 addr) +static inline void +region_entry_add(struct pci_region *r, struct pci_region_entry *entry) { - if (addr & PCI_BASE_ADDRESS_SPACE_IO) - return PCI_REGION_TYPE_IO; - if (addr & PCI_BASE_ADDRESS_MEM_PREFETCH) - return PCI_REGION_TYPE_PREFMEM; - return PCI_REGION_TYPE_MEM; + struct pci_region_entry *first = r->list; + entry->next = first; + if (first) + first->pprev = &entry->next; + r->list = entry; + entry->pprev = &r->list; }
static u32 pci_bar(struct pci_device *pci, int region_num) @@ -324,38 +321,91 @@ pci_bios_init_bus(void) pci_bios_init_bus_rec(0 /* host bus */, &pci_bus); }
- /**************************************************************** * Bus sizing ****************************************************************/
-static u32 pci_size_roundup(u32 size) +static u64 pci_size_roundup(u64 size) { - int index = __fls(size-1)+1; - return 0x1 << index; + int index = __fls((u32)((size - 1) >> 32)); + if (!index) + index = __fls((u32)(size - 1)); + return 0x1 << (index + 1); }
-static void -pci_bios_get_bar(struct pci_device *pci, int bar, u32 *val, u32 *size) +static u64 +pci_get_bar_size(struct pci_device *pci, int bar, + enum pci_region_type *type, int *is64bit) { u32 ofs = pci_bar(pci, bar); u16 bdf = pci->bdf; - u32 old = pci_config_readl(bdf, ofs); - u32 mask; - - if (bar == PCI_ROM_SLOT) { - mask = PCI_ROM_ADDRESS_MASK; - pci_config_writel(bdf, ofs, mask); + u32 l, sz, mask; + + mask = (bar == PCI_ROM_SLOT) ? PCI_ROM_ADDRESS_MASK : ~0; + l = pci_config_readl(bdf, ofs); + pci_config_writel(bdf, ofs, mask); + sz = pci_config_readl(bdf, ofs); + pci_config_writel(bdf, ofs, l); + + *is64bit = 0; + if (l & PCI_BASE_ADDRESS_SPACE_IO) { + mask = PCI_BASE_ADDRESS_IO_MASK; + *type = PCI_REGION_TYPE_IO; } else { - if (old & PCI_BASE_ADDRESS_SPACE_IO) - mask = PCI_BASE_ADDRESS_IO_MASK; + mask = PCI_BASE_ADDRESS_MEM_MASK; + if (l & PCI_BASE_ADDRESS_MEM_TYPE_64) + *is64bit = 1; + if (l & PCI_BASE_ADDRESS_MEM_PREFETCH) + *type = PCI_REGION_TYPE_PREFMEM; else - mask = PCI_BASE_ADDRESS_MEM_MASK; - pci_config_writel(bdf, ofs, ~0); + *type = PCI_REGION_TYPE_MEM; + } + if (*is64bit) { + u64 mask64, sz64 = sz; + l = pci_config_readl(bdf, ofs + 4); + pci_config_writel(bdf, ofs + 4, ~0); + sz = pci_config_readl(bdf, ofs + 4); + pci_config_writel(bdf, ofs + 4, l); + mask64 = mask | ((u64)0xffffffff << 32); + sz64 |= ((u64)sz << 32); + return (~(sz64 & mask64)) + 1; + } + return (u32)((~(sz & mask)) + 1); +} + +static u64 pci_region_max_size(struct pci_region *r) +{ + u64 max = 0; + struct pci_region_entry *entry; + foreach_region_entry(r, entry) { + max = (max > entry->size) ? max : entry->size; + } + return max; +} + +static u64 pci_region_sum(struct pci_region *r) +{ + u64 sum = 0; + struct pci_region_entry *entry; + foreach_region_entry(r, entry) { + sum += entry->size; } - *val = pci_config_readl(bdf, ofs); - pci_config_writel(bdf, ofs, old); - *size = (~(*val & mask)) + 1; + return sum; +} + +static void +dump_entry(struct pci_region_entry *entry) +{ + if (entry->this_region ) + dprintf(1, "PCI bus %d (secondary)", entry->dev->secondary_bus); + else + dprintf(1, "PCI region entry: bdf=%02x:%02x.%x BAR %d", + pci_bdf_to_bus(entry->dev->bdf), pci_bdf_to_dev(entry->dev->bdf), + pci_bdf_to_fn(entry->dev->bdf), entry->bar); + dprintf(1, " base=0x%08x%08x size=0x%08x%08x [%s, %s]\n", + (u32)(entry->base>>32), (u32)entry->base, + (u32)(entry->size>>32), (u32)entry->size, + region_type_name[entry->type],entry->is64bit ? "64bits" : "32bits"); }
static void pci_bios_bus_reserve(struct pci_bus *bus, int type, u32 size)