From aa1df4e9a9e8cd3c0a2b32ae2d8054a4b0f7d08b Mon Sep 17 00:00:00 2001 From: lipengfei28 Date: Wed, 27 Nov 2024 17:59:49 +0800 Subject: [PATCH] pci: fix pci dev alloc bridge mem error Signed-off-by: lipengfei28 --- drivers/devicetree/fdt_pci.c | 25 ++++++-- drivers/pci/pci.c | 118 +++++++++++++++++++++++++---------- drivers/pci/pci_ecam.c | 2 +- include/nuttx/pci/pci.h | 6 +- 4 files changed, 108 insertions(+), 43 deletions(-) diff --git a/drivers/devicetree/fdt_pci.c b/drivers/devicetree/fdt_pci.c index 96ce7140958..7bdd6d9c5be 100644 --- a/drivers/devicetree/fdt_pci.c +++ b/drivers/devicetree/fdt_pci.c @@ -118,26 +118,39 @@ int fdt_pci_ecam_register(FAR const void *fdt) if ((type & FDT_PCI_TYPE_MASK) == FDT_PCI_TYPE_IO) { - io.start = fdt_ld_by_cells(ranges + 1, na -1); + io.start = fdt_ld_by_cells(ranges + 1, na - 1); io.end = io.start + fdt_ld_by_cells(ranges + na + pna, ns); io.offset = fdt_ld_by_cells(ranges + na, pna) - io.start; + io.flags = PCI_RESOURCE_IO; } - else if ((type & FDT_PCI_PREFTCH) == FDT_PCI_PREFTCH) + else if ((type & FDT_PCI_PREFTCH) == FDT_PCI_PREFTCH || + (type & FDT_PCI_TYPE_MASK) == FDT_PCI_TYPE_MEM64) { prefetch.start = fdt_ld_by_cells(ranges + 1, na - 1); prefetch.end = prefetch.start + fdt_ld_by_cells(ranges + na + pna, ns); prefetch.offset = fdt_ld_by_cells(ranges + na, pna) - prefetch.start; + if ((type & FDT_PCI_PREFTCH) == FDT_PCI_PREFTCH) + { + prefetch.flags = PCI_RESOURCE_PREFETCH; + } + + if ((type & FDT_PCI_TYPE_MASK) == FDT_PCI_TYPE_MEM64) + { + prefetch.flags |= PCI_RESOURCE_MEM_64; + } + else + { + prefetch.flags |= PCI_RESOURCE_MEM; + } } - else if (((type & FDT_PCI_TYPE_MEM32) == FDT_PCI_TYPE_MEM32 && - sizeof(uintptr_t) == 4) || - ((type & FDT_PCI_TYPE_MEM64) == FDT_PCI_TYPE_MEM64 && - sizeof(uintptr_t) == 8)) + else { mem.start = fdt_ld_by_cells(ranges + 1, na - 1); mem.end = mem.start + fdt_ld_by_cells(ranges + na + pna, ns); mem.offset = fdt_ld_by_cells(ranges + na, pna) - mem.start; + mem.flags = PCI_RESOURCE_MEM; } } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 869a8d797a4..e55f6c25463 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -645,9 +645,9 @@ static void pci_register_bus_devices(FAR struct pci_bus_s *bus) * ****************************************************************************/ -static uint32_t pci_size(uint32_t base, uint32_t maxbase, uint32_t mask) +static uint64_t pci_size(uint64_t base, uint64_t maxbase, uint64_t mask) { - uint32_t size = maxbase & mask; + uint64_t size = maxbase & mask; if (size == 0) { @@ -689,8 +689,11 @@ static void pci_setup_device(FAR struct pci_device_s *dev, int max_bar, int bar; uint32_t orig; uint32_t mask; - uint32_t size; + uint64_t orig64; + uint64_t size64; uintptr_t start; + uint64_t maxbase; + uint64_t mask64 = 0; #ifdef CONFIG_PCI_ASSIGN_ALL_BUSES uint8_t cmd; @@ -723,54 +726,91 @@ static void pci_setup_device(FAR struct pci_device_s *dev, int max_bar, { /* IO */ - size = pci_size(orig, mask, 0xfffffffe); - flags = PCI_RESOURCE_IO; - res = io; + mask64 = 0xfffffffe; + flags = PCI_RESOURCE_IO; + res = io; } else if ((mask & PCI_BASE_ADDRESS_MEM_PREFETCH) && pci_resource_size(&dev->bus->ctrl->mem_pref)) { - /* Prefetchable MEM */ + if ((mask & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + { + /* Prefetchable MEM */ - size = pci_size(orig, mask, 0xfffffff0); - flags = PCI_RESOURCE_MEM | PCI_RESOURCE_PREFETCH; - res = mem_pref; + mask64 = 0xfffffff0; + flags = PCI_RESOURCE_MEM_64 | PCI_RESOURCE_PREFETCH; + res = mem_pref; + } + else if (((mask & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_32) && + (dev->bus->ctrl->mem_pref.flags & PCI_RESOURCE_MEM)) + { + /* Prefetchable MEM */ + + mask64 = 0xfffffff0; + flags = PCI_RESOURCE_MEM | PCI_RESOURCE_PREFETCH; + res = mem_pref; + } + else + { + /* Non-prefetch MEM */ + + mask64 = 0xfffffff0; + flags = PCI_RESOURCE_MEM; + res = mem; + } } else { /* Non-prefetch MEM */ - size = pci_size(orig, mask, 0xfffffff0); - flags = PCI_RESOURCE_MEM; - res = mem; + mask64 = 0xfffffff0; + flags = PCI_RESOURCE_MEM; + res = mem; } - if (size == 0) + orig64 = orig; + maxbase = mask; + if (mask & PCI_BASE_ADDRESS_MEM_TYPE_64) + { + uint32_t masktmp; + + pci_read_config_dword(dev, base_address_1, &orig); + pci_write_config_dword(dev, base_address_1, 0xffffffff); + pci_read_config_dword(dev, base_address_1, &masktmp); + pci_write_config_dword(dev, base_address_1, orig); + mask64 |= (uint64_t)masktmp << 32; + orig64 |= (uint64_t)orig << 32; + maxbase |= (uint64_t)masktmp << 32; + } + + size64 = pci_size(orig64, maxbase, mask64); + if (size64 == 0) { pcierr("pbar%d bad mask\n", bar); continue; } - pciinfo("pbar%d: mask=%08" PRIx32 " %" PRIu32 "bytes\n", - bar, mask, size); + pciinfo("pbar%d: mask64=%08" PRIx64 " %" PRIu64 "bytes\n", + bar, mask64, size64); #ifdef CONFIG_PCI_ASSIGN_ALL_BUSES - if (ALIGN(res->start, size) + size > res->end) + if (ALIGN(res->start, size64) + size64 > res->end) { pcierr("pbar%d: does not fit within bus res\n", bar); return; } - res->start = ALIGN(res->start, size); + res->start = ALIGN(res->start, size64); pci_write_config_dword(dev, base_address_0, res->start); if (mask & PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_write_config_dword(dev, base_address_1, - (uint64_t)res->start >> 32); + pci_write_config_dword(dev, base_address_1, res->start >> 32); } start = res->start; - res->start += size; + res->start += size64; #else UNUSED(res); pci_read_config_dword(dev, base_address_0, &tmp); @@ -792,7 +832,7 @@ static void pci_setup_device(FAR struct pci_device_s *dev, int max_bar, dev->resource[bar].flags = flags; dev->resource[bar].start = start; - dev->resource[bar].end = start + size - 1; + dev->resource[bar].end = start + size64 - 1; if (mask & PCI_BASE_ADDRESS_MEM_TYPE_64) { @@ -806,13 +846,13 @@ static void pci_setup_device(FAR struct pci_device_s *dev, int max_bar, pci_read_config_dword(dev, rom_addr, &mask); pci_write_config_dword(dev, rom_addr, orig); start = PCI_ROM_ADDR(orig); - size = PCI_ROM_SIZE(mask); - if (start != 0 && size != 0) + size64 = PCI_ROM_SIZE(mask); + if (start != 0 && size64 != 0) { dev->resource[PCI_ROM_RESOURCE].flags |= PCI_RESOURCE_MEM | PCI_RESOURCE_PREFETCH; dev->resource[PCI_ROM_RESOURCE].start = start; - dev->resource[PCI_ROM_RESOURCE].end = start + size - 1; + dev->resource[PCI_ROM_RESOURCE].end = start + size64 - 1; } #ifdef CONFIG_PCI_ASSIGN_ALL_BUSES @@ -867,13 +907,18 @@ static void pci_presetup_bridge(FAR struct pci_device_s *dev) if (pci_resource_size(&ctrl->mem_pref)) { - /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + uint8_t base; + pci_read_config_byte(dev, PCI_PREF_MEMORY_BASE, &base); ctrl->mem_pref.start = ALIGN(ctrl->mem_pref.start, 1024 * 1024); pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, (ctrl->mem_pref.start & 0xfff00000) >> 16); - pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, - (uint64_t)ctrl->mem_pref.start >> 32); + if (base & PCI_PREF_RANGE_TYPE_64) + { + pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, + ctrl->mem_pref.start >> 32); + } + cmdstat |= PCI_COMMAND_MEMORY; } else @@ -888,11 +933,18 @@ static void pci_presetup_bridge(FAR struct pci_device_s *dev) if (pci_resource_size(&ctrl->io)) { + uint8_t base; + + pci_read_config_byte(dev, PCI_IO_BASE, &base); ctrl->io.start = ALIGN(ctrl->io.start, 1024 * 4); pci_write_config_byte(dev, PCI_IO_BASE, (ctrl->io.start & 0x0000f000) >> 8); - pci_write_config_word(dev, PCI_IO_BASE_UPPER16, - (ctrl->io.start & 0xffff0000) >> 16); + if (base & PCI_IO_RANGE_TYPE_32) + { + pci_write_config_word(dev, PCI_IO_BASE_UPPER16, + (ctrl->io.start & 0xffff0000) >> 16); + } + cmdstat |= PCI_COMMAND_IO; } @@ -925,7 +977,7 @@ static void pci_postsetup_bridge(FAR struct pci_device_s *dev) if (pci_resource_size(&ctrl->mem)) { ctrl->mem.start = ALIGN(ctrl->mem.start, 1024 * 1024); - pciinfo("bridge NP limit at %" PRIxPTR "\n", ctrl->mem.start); + pciinfo("bridge NP limit at %" PRIx64 "\n", ctrl->mem.start); pci_write_config_word(dev, PCI_MEMORY_LIMIT, ((ctrl->mem.start - 1) & 0xfff00000) >> 16); } @@ -933,7 +985,7 @@ static void pci_postsetup_bridge(FAR struct pci_device_s *dev) if (pci_resource_size(&ctrl->mem_pref)) { ctrl->mem_pref.start = ALIGN(ctrl->mem_pref.start, 1024 * 1024); - pciinfo("bridge P limit at %" PRIxPTR "\n", ctrl->mem_pref.start); + pciinfo("bridge P limit at %" PRIx64 "\n", ctrl->mem_pref.start); pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, ((ctrl->mem_pref.start - 1) & 0xfff00000) >> 16); pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, @@ -943,7 +995,7 @@ static void pci_postsetup_bridge(FAR struct pci_device_s *dev) if (pci_resource_size(&ctrl->io)) { ctrl->io.start = ALIGN(ctrl->io.start, 1024 * 4); - pciinfo("bridge IO limit at %" PRIxPTR "\n", ctrl->io.start); + pciinfo("bridge IO limit at %" PRIx64 "\n", ctrl->io.start); pci_write_config_byte(dev, PCI_IO_LIMIT, ((ctrl->io.start - 1) & 0x0000f000) >> 8); pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, diff --git a/drivers/pci/pci_ecam.c b/drivers/pci/pci_ecam.c index 011e2c0d027..3a31d065ab8 100644 --- a/drivers/pci/pci_ecam.c +++ b/drivers/pci/pci_ecam.c @@ -152,7 +152,7 @@ static FAR void *pci_ecam_conf_address(FAR const struct pci_bus_s *bus, FAR struct pci_ecam_s *ecam = pci_ecam_from_controller(bus->ctrl); FAR void *addr; - addr = (FAR void *)ecam->cfg.start; + addr = (FAR void *)(uintptr_t)ecam->cfg.start; addr += bus->number << 20; addr += PCI_SLOT(devfn) << 15; addr += PCI_FUNC(devfn) << 12; diff --git a/include/nuttx/pci/pci.h b/include/nuttx/pci/pci.h index 07929342f22..3cc0af14c64 100644 --- a/include/nuttx/pci/pci.h +++ b/include/nuttx/pci/pci.h @@ -236,9 +236,9 @@ struct pci_resource_s { - uintptr_t start; - uintptr_t end; - uintptr_t offset; + uint64_t start; + uint64_t end; + uint64_t offset; unsigned int flags; };