From a179012e37ae75de1fa7d6597e69d985ef79b7d0 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 11 Jan 2006 13:24:15 -0600 Subject: 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 11 Jan 2006 --- drivers/pci_auto.c | 58 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pci_auto.c b/drivers/pci_auto.c index 3302457..15f7432 100644 --- a/drivers/pci_auto.c +++ b/drivers/pci_auto.c @@ -77,6 +77,7 @@ int pciauto_region_allocate(struct pci_region* res, unsigned int size, unsigned 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_controller *hose, 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(struct pci_controller *hose, 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,21 @@ static void pciauto_prescan_setup_bridge(struct pci_controller *hose, 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_PREF_MEMORY_BASE, + (pci_prefetch->bus_lower & 0xfff00000) >> 16); + + cmdstat |= PCI_COMMAND_MEMORY; + } else { + /* We don't support prefetchable memory for now, so disable */ + pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, 0x1000); + pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, 0x1000); + } + if (pci_io) { /* Round I/O allocator to 4KB boundary */ pciauto_region_align(pci_io, 0x1000); @@ -181,10 +201,6 @@ static void pciauto_prescan_setup_bridge(struct pci_controller *hose, cmdstat |= PCI_COMMAND_IO; } - /* We don't support prefetchable memory for now, so disable */ - pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, 0x1000); - pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, 0x1000); - /* Enable memory and I/O accesses, enable bus master */ pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER); } @@ -193,6 +209,7 @@ static void pciauto_postscan_setup_bridge(struct pci_controller *hose, 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_bridge(struct pci_controller *hose, (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_PREF_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_controller *hose) 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_controller *hose) 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_controller *hose, pci_dev_t dev) 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_controller *hose, pci_dev_t dev) 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_controller *hose, pci_dev_t dev) * 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; } -- cgit v1.1 From 3411d1176102249f0e85dfc01820940e2faa7d13 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 11 Jan 2006 13:27:19 -0600 Subject: Report back PCI bus when doing table based device config Patch by Kumar Gala 11 Jan 2006 --- drivers/pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pci.c b/drivers/pci.c index 5360030..3c24b99 100644 --- a/drivers/pci.c +++ b/drivers/pci.c @@ -459,6 +459,7 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus) PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev)); if (cfg) { cfg->config_device(hose, dev, cfg); + sub_bus = max(sub_bus, hose->current_busno); #ifdef CONFIG_PCI_PNP } else { int n = pciauto_config_device(hose, dev); -- cgit v1.1 From dffb70f3305daa16625ec9d5b02a2c0d23ff84b3 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 12 Jan 2006 15:30:24 -0600 Subject: Fixed PCI indirect config ops to handle multiple PCI controllers We need to adjust the bus number we are trying to access based on which PCI controller its on Patch by Kumar Gala 12 Jan 2006 --- drivers/pci_indirect.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/pci_indirect.c b/drivers/pci_indirect.c index e8f19f5..f0c4a1c 100644 --- a/drivers/pci_indirect.c +++ b/drivers/pci_indirect.c @@ -36,6 +36,10 @@ static int \ indirect_##rw##_config_##size(struct pci_controller *hose, \ pci_dev_t dev, int offset, type val) \ { \ + u32 b, d,f; \ + b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ + b = b - hose->first_busno; \ + dev = PCI_BDF(b, d, f); \ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ sync(); \ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ @@ -47,6 +51,10 @@ static int \ indirect_##rw##_config_##size(struct pci_controller *hose, \ pci_dev_t dev, int offset, type val) \ { \ + u32 b, d,f; \ + b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ + b = b - hose->first_busno; \ + dev = PCI_BDF(b, d, f); \ *(hose->cfg_addr) = dev | (offset & 0xfc) | 0x80000000; \ sync(); \ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ @@ -58,6 +66,10 @@ static int \ indirect_##rw##_config_##size(struct pci_controller *hose, \ pci_dev_t dev, int offset, type val) \ { \ + u32 b, d,f; \ + b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ + b = b - hose->first_busno; \ + dev = PCI_BDF(b, d, f); \ if (PCI_BUS(dev) > 0) \ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000001); \ else \ @@ -71,6 +83,10 @@ static int \ indirect_##rw##_config_##size(struct pci_controller *hose, \ pci_dev_t dev, int offset, type val) \ { \ + u32 b, d,f; \ + b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ + b = b - hose->first_busno; \ + dev = PCI_BDF(b, d, f); \ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ return 0; \ -- cgit v1.1