
Added support for PCI prefetchable region and BARs
Signed-off-by: Kumar Gala galak@kernel.crashing.org
CHANGELOG: * Added support for PCI prefetchable region and BARs If a host controller sets up a region as prefetchable and a device's BAR denotes it as prefetchable, allocate the BAR into the prefetch region.
If a BAR is prefetchable and no prefetchable region has been setup by the controller we fall back to allocating the BAR into the normally memory region.
Patch by Kumar Gala 22 Nov 2005
--- commit f6a259d086597f691d821a5ac2181ce249fad987 tree 455dc92391d7b33119acd175595a2778ea6bcaa5 parent 680def7ecaabea707792ff987cd9baa9b4e18b38 author Kumar Gala galak@kernel.crashing.org Tue, 22 Nov 2005 13:29:25 -0600 committer Kumar Gala galak@kernel.crashing.org Tue, 22 Nov 2005 13:29:25 -0600
drivers/pci_auto.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ include/pci.h | 4 +++- 2 files changed, 47 insertions(+), 7 deletions(-)
diff --git a/drivers/pci_auto.c b/drivers/pci_auto.c index 3302457..b70bacc 100644 --- a/drivers/pci_auto.c +++ b/drivers/pci_auto.c @@ -77,6 +77,7 @@ int pciauto_region_allocate(struct pci_r void pciauto_setup_device(struct pci_controller *hose, pci_dev_t dev, int bars_num, struct pci_region *mem, + struct pci_region *prefetch, struct pci_region *io) { unsigned int bar_value, bar_response, bar_size; @@ -111,7 +112,10 @@ void pciauto_setup_device(struct pci_con found_mem64 = 1;
bar_size = ~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1; - bar_res = mem; + if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH)) + bar_res = prefetch; + else + bar_res = mem;
DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%x, ", bar_nr, bar_size); } @@ -148,6 +152,7 @@ static void pciauto_prescan_setup_bridge pci_dev_t dev, int sub_bus) { struct pci_region *pci_mem = hose->pci_mem; + struct pci_region *pci_prefetch = hose->pci_prefetch; struct pci_region *pci_io = hose->pci_io; unsigned int cmdstat;
@@ -169,6 +174,17 @@ static void pciauto_prescan_setup_bridge cmdstat |= PCI_COMMAND_MEMORY; }
+ if (pci_prefetch) { + /* Round memory allocator to 1MB boundary */ + pciauto_region_align(pci_prefetch, 0x100000); + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + pci_hose_write_config_word(hose, dev, PCI_MEMORY_BASE, + (pci_prefetch->bus_lower & 0xfff00000) >> 16); + + cmdstat |= PCI_COMMAND_MEMORY; + } + if (pci_io) { /* Round I/O allocator to 4KB boundary */ pciauto_region_align(pci_io, 0x1000); @@ -193,6 +209,7 @@ static void pciauto_postscan_setup_bridg pci_dev_t dev, int sub_bus) { struct pci_region *pci_mem = hose->pci_mem; + struct pci_region *pci_prefetch = hose->pci_prefetch; struct pci_region *pci_io = hose->pci_io;
/* Configure bus number registers */ @@ -206,6 +223,14 @@ static void pciauto_postscan_setup_bridg (pci_mem->bus_lower-1) >> 16); }
+ if (pci_prefetch) { + /* Round memory allocator to 1MB boundary */ + pciauto_region_align(pci_prefetch, 0x100000); + + pci_hose_write_config_word(hose, dev, PCI_MEMORY_LIMIT, + (pci_prefetch->bus_lower-1) >> 16); + } + if (pci_io) { /* Round I/O allocator to 4KB boundary */ pciauto_region_align(pci_io, 0x1000); @@ -239,6 +264,11 @@ void pciauto_config_init(struct pci_cont hose->pci_mem->size < hose->regions[i].size) hose->pci_mem = hose->regions + i; break; + case (PCI_REGION_MEM | PCI_REGION_PREFETCH): + if (!hose->pci_prefetch || + hose->pci_prefetch->size < hose->regions[i].size) + hose->pci_prefetch = hose->regions + i; + break; } }
@@ -251,6 +281,14 @@ void pciauto_config_init(struct pci_cont hose->pci_mem->bus_start + hose->pci_mem->size - 1); }
+ if (hose->pci_prefetch) { + pciauto_region_init(hose->pci_prefetch); + + DEBUGF("PCI Autoconfig: Prefetchable Memory region: [%lx-%lx]\n", + hose->pci_prefetch->bus_start, + hose->pci_prefetch->bus_start + hose->pci_prefetch->size - 1); + } + if (hose->pci_io) { pciauto_region_init(hose->pci_io);
@@ -275,7 +313,7 @@ int pciauto_config_device(struct pci_con switch(class) { case PCI_CLASS_BRIDGE_PCI: hose->current_busno++; - pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_io); + pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev));
@@ -301,12 +339,12 @@ int pciauto_config_device(struct pci_con return sub_bus; }
- pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_io); + pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io); break;
case PCI_CLASS_BRIDGE_CARDBUS: /* just do a minimal setup of the bridge, let the OS take care of the rest */ - pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_io); + pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n", PCI_DEV(dev));
@@ -328,11 +366,11 @@ int pciauto_config_device(struct pci_con * the PIMMR window to be allocated (BAR0 - 1MB size) */ DEBUGF("PCI Autoconfig: Broken bridge found, only minimal config\n"); - pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_io); + pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io); break; #endif default: - pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_io); + pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io); break; }
diff --git a/include/pci.h b/include/pci.h index 8f19997..f78a769 100644 --- a/include/pci.h +++ b/include/pci.h @@ -309,6 +309,7 @@ struct pci_region { #define PCI_REGION_MEM 0x00000000 /* PCI memory space */ #define PCI_REGION_IO 0x00000001 /* PCI IO space */ #define PCI_REGION_TYPE 0x00000001 +#define PCI_REGION_PREFETCH 0x00000008 /* prefetchable PCI memory */
#define PCI_REGION_MEMORY 0x00000100 /* System memory */ #define PCI_REGION_RO 0x00000200 /* Read-only memory */ @@ -386,7 +387,7 @@ struct pci_controller { int (*write_dword)(struct pci_controller*, pci_dev_t, int where, u32);
/* Used by auto config */ - struct pci_region *pci_mem, *pci_io; + struct pci_region *pci_mem, *pci_io, *pci_prefetch;
/* Used by ppc405 autoconfig*/ struct pci_region *pci_fb; @@ -472,6 +473,7 @@ extern int pciauto_region_allocate(struc extern void pciauto_setup_device(struct pci_controller *hose, pci_dev_t dev, int bars_num, struct pci_region *mem, + struct pci_region *prefetch, struct pci_region *io); int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev);