diff options
Diffstat (limited to 'drivers/pci_auto.c')
| -rw-r--r-- | drivers/pci_auto.c | 58 | 
1 files changed, 48 insertions, 10 deletions
| diff --git a/drivers/pci_auto.c b/drivers/pci_auto.c index 3302457a3..15f74328f 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;  	} |