From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-12-06 08:11:30
This serie of patches converts the 32 bits PCI code to use the generic
pci_assign_unassigned_resources() instead of its own assignment code
which was unable to deal with unassigned PCI<->PCI bridges among
other issues.
It then merges the resource fixup and allocation code between 32 and
64 bits (mostly making 64 bits use the 32 bits code with a few fixups),
hopefully fixing the longstanding issue that not setting pci_probe_only
on ppc64 would generally not work.
We also add flags to control the behaviour of the PCI code, such as
letting some platforms force a full re-assignment (similar to what
pci-auto used to provide in arch/ppc) and remove a whole bunch of
hackish code that is made obsolete by that change.
32 bits platforms with 64 bits resources support will also need my
separate patch to fix the generic setup-bus.c for that situation.
Note that the patch that updates 4xx platforms to enable full resource
assignments applied on top of my 4xx series for which I'll post a new
version soon. You can apply the other ones and ignore this one if you
want to test on some other platform without the other patch serie.
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-12-06 08:11:31
There's a stale & bogus piece of code in 32 bits PCI code that
complains about ISA related alignment issues. Just remove it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci_32.c | 6 ------
1 file changed, 6 deletions(-)
Index: linux-work/arch/powerpc/kernel/pci_32.c
===================================================================
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-12-06 08:11:32
This makes the 32 bits PowerPC PCI code use the generic code to assign
resources to devices that had unassigned or conflicting resources.
This allow to remove the local implementation that was incomplete and
could not assign for example a PCI<->PCI bridge from scratch, which is
needed on various embedded platforms.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci_32.c | 191 +++----------------------------------------
1 file changed, 17 insertions(+), 174 deletions(-)
Index: linux-work/arch/powerpc/kernel/pci_32.c
===================================================================
@@ -37,10 +37,6 @@ int pcibios_assign_bus_offset = 1;voidpcibios_make_OF_bus_map(void);-staticintpci_relocate_bridge_resource(structpci_bus*bus,inti);-staticintprobe_resource(structpci_bus*parent,structresource*pr,-structresource*res,structresource**conflict);-staticvoidupdate_bridge_base(structpci_bus*bus,inti);staticvoidpcibios_fixup_resources(structpci_dev*dev);staticvoidfixup_broken_pcnet32(structpci_dev*dev);staticintreparent_resources(structresource*parent,structresource*res);
@@ -134,7 +130,7 @@ pcibios_fixup_resources(struct pci_dev *if(offset!=0){res->start=(res->start+offset)&mask;res->end=(res->end+offset)&mask;-DBG("Fixup res %d (%lx) of dev %s: %llx -> %llx\n",+DBG("PCI: Fixup res %d (0x%lx) of dev %s: %llx -> %llx\n",i,res->flags,pci_name(dev),(u64)res->start-offset,(u64)res->start);}
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-12-06 08:11:33
The 32 bits PowerPC PCI code has a hack for use by some PowerMacs
to try to re-open PCI<->PCI bridge IO resources that were closed
by the firmware. This is no longer necessary as the generic code
will now do that for us.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci_32.c | 215 -------------------------------------------
1 file changed, 1 insertion(+), 214 deletions(-)
Index: linux-work/arch/powerpc/kernel/pci_32.c
===================================================================
@@ -711,217 +711,6 @@ void pcibios_make_OF_bus_map(void)}#endif /* CONFIG_PPC_OF */-#ifdef CONFIG_PPC_PMAC-/*-*ThissetofroutineschecksforPCI<->PCIbridgesthathaveclosed-*IOresourcesandhavechilddevices.Ittriestore-openanIO-*windowonthem.-*-*Thisisa_temporary_fixtoworkaroundaproblemwithApple'sOF-*closingIOwindowsonP2PbridgeswhentheOFdriversofcards-*belowthisbridgedon'tclaimanyIOrange(typicallyATIor-*Adaptec).-*-*Amorecompletefixwouldbetousedrivers/pci/setup-bus.c,which-*involvesaworkingpcibios_fixup_pbus_ranges(),somemorecareabout-*orderingwhencreatingthehostbusresources,andmaybeafewmore-*minortweaks-*/--/* Initialize bridges with base/limit values we have collected */-staticvoid__init-do_update_p2p_io_resource(structpci_bus*bus,intenable_vga)-{-structpci_dev*bridge=bus->self;-structpci_controller*hose=(structpci_controller*)bridge->sysdata;-u32l;-u16w;-structresourceres;--if(bus->resource[0]==NULL)-return;-res=*(bus->resource[0]);--DBG("Remapping Bus %d, bridge: %s\n",bus->number,pci_name(bridge));-res.start-=((unsignedlong)hose->io_base_virt-isa_io_base);-res.end-=((unsignedlong)hose->io_base_virt-isa_io_base);-DBG(" IO window: %016llx-%016llx\n",res.start,res.end);--/* Set up the top and bottom of the PCI I/O segment for this bus. */-pci_read_config_dword(bridge,PCI_IO_BASE,&l);-l&=0xffff000f;-l|=(res.start>>8)&0x00f0;-l|=res.end&0xf000;-pci_write_config_dword(bridge,PCI_IO_BASE,l);--if((l&PCI_IO_RANGE_TYPE_MASK)==PCI_IO_RANGE_TYPE_32){-l=(res.start>>16)|(res.end&0xffff0000);-pci_write_config_dword(bridge,PCI_IO_BASE_UPPER16,l);-}--pci_read_config_word(bridge,PCI_COMMAND,&w);-w|=PCI_COMMAND_IO;-pci_write_config_word(bridge,PCI_COMMAND,w);--#if 0 /* Enabling this causes XFree 4.2.0 to hang during PCI probe */-if(enable_vga){-pci_read_config_word(bridge,PCI_BRIDGE_CONTROL,&w);-w|=PCI_BRIDGE_CTL_VGA;-pci_write_config_word(bridge,PCI_BRIDGE_CONTROL,w);-}-#endif-}--/* This function is pretty basic and actually quite broken for the-*generalcase,it'senoughforusrightnowthough.It'ssupposed-*totellusifweneedtoopenanIOrangeatallornotandwhat-*size.-*/-staticint__init-check_for_io_childs(structpci_bus*bus,structresource*res,int*found_vga)-{-structpci_dev*dev;-inti;-intrc=0;--#define push_end(res, mask) do { \-BUG_ON((mask+1)&mask);\-res->end=(res->end+mask)|mask;\-}while(0)--list_for_each_entry(dev,&bus->devices,bus_list){-u16class=dev->class>>8;--if(class==PCI_CLASS_DISPLAY_VGA||-class==PCI_CLASS_NOT_DEFINED_VGA)-*found_vga=1;-if(class>>8==PCI_BASE_CLASS_BRIDGE&&dev->subordinate)-rc|=check_for_io_childs(dev->subordinate,res,found_vga);-if(class==PCI_CLASS_BRIDGE_CARDBUS)-push_end(res,0xfff);--for(i=0;i<PCI_NUM_RESOURCES;i++){-structresource*r;-unsignedlongr_size;--if(dev->class>>8==PCI_CLASS_BRIDGE_PCI-&&i>=PCI_BRIDGE_RESOURCES)-continue;-r=&dev->resource[i];-r_size=r->end-r->start;-if(r_size<0xfff)-r_size=0xfff;-if(r->flags&IORESOURCE_IO&&(r_size)!=0){-rc=1;-push_end(res,r_size);-}-}-}--returnrc;-}--/* Here we scan all P2P bridges of a given level that have a closed-*IOwindow.NotethatthetestforthepresenceofaVGAcardshould-*beimprovedtotakeintoaccountalreadyconfiguredP2Pbridges,-*currently,wedon'tseethemandmightendupconfiguring2bridges-*withVGApassthroughenabled-*/-staticvoid__init-do_fixup_p2p_level(structpci_bus*bus)-{-structpci_bus*b;-inti,parent_io;-inthas_vga=0;--for(parent_io=0;parent_io<4;parent_io++)-if(bus->resource[parent_io]-&&bus->resource[parent_io]->flags&IORESOURCE_IO)-break;-if(parent_io>=4)-return;--list_for_each_entry(b,&bus->children,node){-structpci_dev*d=b->self;-structpci_controller*hose=(structpci_controller*)d->sysdata;-structresource*res=b->resource[0];-structresourcetmp_res;-unsignedlongmax;-intfound_vga=0;--memset(&tmp_res,0,sizeof(tmp_res));-tmp_res.start=bus->resource[parent_io]->start;--/* We don't let low addresses go through that closed P2P bridge, well,-*thatmaynotbenecessarybutIfeelsaferthatway-*/-if(tmp_res.start==0)-tmp_res.start=0x1000;--if(!list_empty(&b->devices)&&res&&res->flags==0&&-res!=bus->resource[parent_io]&&-(d->class>>8)==PCI_CLASS_BRIDGE_PCI&&-check_for_io_childs(b,&tmp_res,&found_vga)){-u8io_base_lo;--printk(KERN_INFO"Fixing up IO bus %s\n",b->name);--if(found_vga){-if(has_vga){-printk(KERN_WARNING"Skipping VGA, already active"-" on bus segment\n");-found_vga=0;-}else-has_vga=1;-}-pci_read_config_byte(d,PCI_IO_BASE,&io_base_lo);--if((io_base_lo&PCI_IO_RANGE_TYPE_MASK)==PCI_IO_RANGE_TYPE_32)-max=((unsignedlong)hose->io_base_virt--isa_io_base)+0xffffffff;-else-max=((unsignedlong)hose->io_base_virt--isa_io_base)+0xffff;--*res=tmp_res;-res->flags=IORESOURCE_IO;-res->name=b->name;--/* Find a resource in the parent where we can allocate */-for(i=0;i<4;i++){-structresource*r=bus->resource[i];-if(!r)-continue;-if((r->flags&IORESOURCE_IO)==0)-continue;-DBG("Trying to allocate from %016llx, size %016llx from parent"-" res %d: %016llx -> %016llx\n",-res->start,res->end,i,r->start,r->end);--if(allocate_resource(r,res,res->end+1,res->start,max,-res->end+1,NULL,NULL)<0){-DBG("Failed !\n");-continue;-}-do_update_p2p_io_resource(b,found_vga);-break;-}-}-do_fixup_p2p_level(b);-}-}--staticvoid-pcibios_fixup_p2p_bridges(void)-{-structpci_bus*b;--list_for_each_entry(b,&pci_root_buses,node)-do_fixup_p2p_level(b);-}--#endif /* CONFIG_PPC_PMAC */-staticint__initpcibios_init(void){
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-12-06 08:11:33
This adds to the 32 bits PCI code some flags, replacing the old
pci_assign_all_busses global, that allow to control various
aspects of the PCI probing, such as whether to re-assign all
resources or not, or to not try to assign anything at all.
This also adds the flag x86 already has to avoid ISA alignment
on bridges that don't have ISA forwarding enabled (no legacy
devices on the top level bus) and sets it for PowerMacs.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci_32.c | 42 ++++++++++++++++++++++++------
arch/powerpc/kernel/pci_64.c | 1
arch/powerpc/kernel/rtas_pci.c | 6 ++--
arch/powerpc/platforms/52xx/mpc52xx_pci.c | 2 -
arch/powerpc/platforms/82xx/pq2.c | 2 -
arch/powerpc/platforms/83xx/pci.c | 2 -
arch/powerpc/platforms/chrp/pci.c | 2 -
arch/powerpc/platforms/powermac/pci.c | 7 +++--
arch/powerpc/sysdev/fsl_pci.c | 2 -
arch/powerpc/sysdev/grackle.c | 2 -
include/asm-powerpc/pci-bridge.h | 20 ++++++++++++++
include/asm-powerpc/pci.h | 9 ++++--
12 files changed, 75 insertions(+), 22 deletions(-)
Index: linux-work/arch/powerpc/kernel/pci_32.c
===================================================================
@@ -35,6 +35,9 @@ unsigned long isa_io_base = 0;unsignedlongpci_dram_offset=0;intpcibios_assign_bus_offset=1;+/* Default PCI flags is 0 */+unsignedintppc_pci_flags;+voidpcibios_make_OF_bus_map(void);staticvoidpcibios_fixup_resources(structpci_dev*dev);
@@ -48,7 +51,7 @@ static u8* pci_to_OF_bus_map;/* By default, we don't re-assign bus numbers. We do this only on*somepmacs*/-intpci_assign_all_buses;+staticintpci_assign_all_buses;LIST_HEAD(hose_list);
@@ -251,8 +264,13 @@ pcibios_allocate_bus_resources(struct licontinue;if(bus->parent==NULL)pr=(res->flags&IORESOURCE_IO)?-&ioport_resource:&iomem_resource;+&ioport_resource:&iomem_resource;else{+/* Don't bother with non-root busses when+*re-assigningallresources.+*/+if(ppc_pci_flags&PPC_PCI_REASSIGN_ALL_RSRC)+continue;pr=pci_find_parent_resource(bus->self,res);if(pr==res){/* this happens when the generic PCI
@@ -720,6 +738,9 @@ pcibios_init(void)printk(KERN_INFO"PCI: Probing PCI hardware\n");+if(ppc_pci_flags&PPC_PCI_REASSIGN_ALL_BUS)+pci_assign_all_buses=1;+/* Scan all of the recorded PCI controllers. */list_for_each_entry_safe(hose,tmp,&hose_list,list_node){if(pci_assign_all_buses)
@@ -746,13 +767,18 @@ pcibios_init(void)if(ppc_md.pcibios_fixup)ppc_md.pcibios_fixup();-/* Allocate and assign resources */+/* Allocate and assign resources. If we re-assign everything, then+*weskiptheallocatephase+*/pcibios_allocate_bus_resources(&pci_root_buses);-pcibios_allocate_resources(0);-pcibios_allocate_resources(1);--DBG("PCI: Assigning unassigned resouces...\n");-pci_assign_unassigned_resources();+if(!(ppc_pci_flags&PPC_PCI_REASSIGN_ALL_RSRC)){+pcibios_allocate_resources(0);+pcibios_allocate_resources(1);+}+if(!(ppc_pci_flags&PPC_PCI_PROBE_ONLY)){+DBG("PCI: Assigning unassigned resouces...\n");+pci_assign_unassigned_resources();+}/* Call machine dependent post-init code */if(ppc_md.pcibios_after_init)
@@ -54,7 +54,7 @@ int __init mpc83xx_add_bridge(struct dev" bus 0\n",dev->full_name);}-pci_assign_all_buses=1;+ppc_pci_flags|=PPC_PCI_REASSIGN_ALL_BUS;hose=pcibios_alloc_controller(dev);if(!hose)return-ENOMEM;
@@ -198,7 +198,7 @@ static void __init setup_peg2(struct pciprintk("RTAS supporting Pegasos OF not found, please upgrade"" your firmware\n");}-pci_assign_all_buses=1;+ppc_pci_flags|=PPC_PCI_REASSIGN_ALL_BUS;/* keep the reference to the root node */}
@@ -202,7 +202,7 @@ int __init fsl_add_bridge(struct device_printk(KERN_WARNING"Can't get bus-range for %s, assume"" bus 0\n",dev->full_name);-pci_assign_all_buses=1;+ppc_pci_flags|=PPC_PCI_REASSIGN_ALL_BUS;hose=pcibios_alloc_controller(dev);if(!hose)return-ENOMEM;
@@ -11,6 +11,26 @@structdevice_node;structpci_controller;+externunsignedintppc_pci_flags;+enum{+/* Force re-assigning all resources (ignore firmware+*setupcompletely)+*/+PPC_PCI_REASSIGN_ALL_RSRC=0x00000001,++/* Re-assign all bus numbers */+PPC_PCI_REASSIGN_ALL_BUS=0x00000002,++/* Do not try to assign, just use existing setup */+PPC_PCI_PROBE_ONLY=0x00000004,++/* Don't bother with ISA alignment unless the bridge has+*ISAforwardingenabled+*/+PPC_PCI_CAN_SKIP_ISA_ALIGN=0x00000008,+};++/**StructureofaPCIcontroller(hostbridge)*/
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-12-06 08:11:34
The 32 bits PCI code carries an old hack that was only useful for G5
machines. Nowdays, the 32 bits kernel doesn't support any of those
machines anymore so the hack is basically never used, remove it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci_32.c | 11 -----------
1 file changed, 11 deletions(-)
Index: linux-work/arch/powerpc/kernel/pci_32.c
===================================================================
@@ -922,17 +922,6 @@ long sys_pciconfig_iobase(long which, unstructpci_controller*hose;longresult=-EOPNOTSUPP;-/* Argh ! Please forgive me for that hack, but that's the-*simplestwaytogetexistingXFreetonotlockuponsome-*G5machines...Sowhensomethingasksforbus0iobase-*(bus0isHTroot),wereturntheAGPoneinstead.-*/-#ifdef CONFIG_PPC_PMAC-if(machine_is(powermac)&&machine_is_compatible("MacRISC4"))-if(bus==0)-bus=0xf0;-#endif /* CONFIG_PPC_PMAC */-hose=pci_bus_to_hose(bus);if(!hose)return-ENODEV;
@@ -656,3 +656,23 @@ void __devinit pci_process_bridge_OF_ranhose->mem_resources[memno-1]=tmp;}}++/* Decide whether to display the domain number in /proc */+intpci_proc_domain(structpci_bus*bus)+{+if(firmware_has_feature(FW_FEATURE_ISERIES))+return0;+else{+structpci_controller*hose=pci_bus_to_host(bus);+#ifdef CONFIG_PPC64+returnhose->buid!=0;+#else+if(!(ppc_pci_flags&PPC_PCI_ENABLE_PROC_DOMAINS))+return0;+if(ppc_pci_flags&PPC_PCI_COMPAT_DOMAIN_0)+returnhose->global_number!=0;+return1;+#endif+}+}+
@@ -580,18 +580,6 @@ int pcibios_enable_device(struct pci_devreturn0;}-/* Decide whether to display the domain number in /proc */-intpci_proc_domain(structpci_bus*bus)-{-if(firmware_has_feature(FW_FEATURE_ISERIES))-return0;-else{-structpci_controller*hose=pci_bus_to_host(bus);-returnhose->buid!=0;-}-}--#ifdef CONFIG_HOTPLUGintpcibios_unmap_io_space(structpci_bus*bus)
@@ -98,9 +98,6 @@ static inline void pci_dma_burst_advice(#define get_pci_dma_ops() NULL#endif-/* Decide whether to display the domain number in /proc */-externintpci_proc_domain(structpci_bus*bus);-#else /* 32-bit */#ifdef CONFIG_PCI
@@ -112,17 +109,14 @@ static inline void pci_dma_burst_advice(*strategy_parameter=~0UL;}#endif--/* Set the name of the bus as it appears in /proc/bus/pci */-staticinlineintpci_proc_domain(structpci_bus*bus)-{-return0;-}-#endif /* CONFIG_PPC64 */externintpci_domain_nr(structpci_bus*bus);+/* Decide whether to display the domain number in /proc */+externintpci_proc_domain(structpci_bus*bus);++structvm_area_struct;/* Map a range of PCI memory or I/O space for a device into user space */intpci_mmap_page_range(structpci_dev*pdev,structvm_area_struct*vma,
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-12-06 08:11:36
The PCI code in 32 and 64 bits fixes up resources differently.
32 bits uses a header quirk plus handles bridges in pcibios_fixup_bus()
while 64 bits does things in various places depending on whether you
are using OF probing, using PCI hotplug, etc...
This merges those by basically using the 32 bits approach for both,
with various tweaks to make 64 bits work with the new approach.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This requires serious testing which I haven't had a chance to do yet,
especially with DLPAR PCI hotplug.
arch/powerpc/kernel/pci-common.c | 132 ++++++++++++++++++++++++++++-
arch/powerpc/kernel/pci_32.c | 83 ------------------
arch/powerpc/kernel/pci_64.c | 106 +++--------------------
arch/powerpc/platforms/pseries/pci_dlpar.c | 14 +--
drivers/pci/hotplug/rpadlpar_core.c | 2
include/asm-powerpc/machdep.h | 14 +--
include/asm-powerpc/pci-bridge.h | 2
include/asm-powerpc/pci.h | 6 -
8 files changed, 169 insertions(+), 190 deletions(-)
Index: linux-work/arch/powerpc/kernel/pci_64.c
===================================================================
@@ -42,9 +42,6 @@unsignedlongpci_probe_only=1;-staticvoidfixup_resource(structresource*res,structpci_dev*dev);-staticvoiddo_bus_setup(structpci_bus*bus);-/* pci_io_base -- the base address from which io bars are offsets.*ThisisthelowestI/Obaseaddress(sobarvaluesarealwayspositive),*andit*must*bethestartofISAspaceifanISAbusexistsbecause
@@ -305,6 +301,7 @@ void __devinit of_scan_bus(struct deviceDBG("of_scan_bus(%s) bus no %d... \n",node->full_name,bus->number);+/* Scan direct children */while((child=of_get_next_child(node,child))!=NULL){DBG(" * %s\n",child->full_name);reg=of_get_property(child,"reg",®len);
@@ -316,19 +313,26 @@ void __devinit of_scan_bus(struct devicedev=of_create_pci_dev(child,bus,devfn);if(!dev)continue;-DBG("dev header type: %x\n",dev->hdr_type);+DBG(" dev header type: %x\n",dev->hdr_type);+}++/* Ally all fixups */+pcibios_fixup_of_probed_bus(bus);+/* Now scan child busses */+list_for_each_entry(dev,&bus->devices,bus_list){if(dev->hdr_type==PCI_HEADER_TYPE_BRIDGE||-dev->hdr_type==PCI_HEADER_TYPE_CARDBUS)-of_scan_pci_bridge(child,dev);+dev->hdr_type==PCI_HEADER_TYPE_CARDBUS){+structdevice_node*child=pci_device_to_OF_node(dev);+if(dev)+of_scan_pci_bridge(child,dev);+}}--do_bus_setup(bus);}EXPORT_SYMBOL(of_scan_bus);void__devinitof_scan_pci_bridge(structdevice_node*node,-structpci_dev*dev)+structpci_dev*dev){structpci_bus*bus;constu32*busrange,*ranges;
@@ -398,7 +402,6 @@ void __devinit of_scan_pci_bridge(structres->start=of_read_number(&ranges[1],2);res->end=res->start+size-1;res->flags=flags;-fixup_resource(res,dev);}sprintf(bus->name,"PCI Bus %04x:%02x",pci_domain_nr(bus),bus->number);
@@ -655,51 +658,13 @@ int __devinit pcibios_map_io_space(struc}EXPORT_SYMBOL_GPL(pcibios_map_io_space);-staticvoid__devinitfixup_resource(structresource*res,structpci_dev*dev)-{-structpci_controller*hose=pci_bus_to_host(dev->bus);-unsignedlongoffset;--if(res->flags&IORESOURCE_IO){-offset=(unsignedlong)hose->io_base_virt-_IO_BASE;-res->start+=offset;-res->end+=offset;-}elseif(res->flags&IORESOURCE_MEM){-res->start+=hose->pci_mem_offset;-res->end+=hose->pci_mem_offset;-}-}--void__devinitpcibios_fixup_device_resources(structpci_dev*dev,-structpci_bus*bus)-{-/* Update device resources. */-inti;--DBG("%s: Fixup resources:\n",pci_name(dev));-for(i=0;i<PCI_NUM_RESOURCES;i++){-structresource*res=&dev->resource[i];-if(!res->flags)-continue;--DBG(" 0x%02x < %08lx:0x%016lx...0x%016lx\n",-i,res->flags,res->start,res->end);--fixup_resource(res,dev);--DBG(" > %08lx:0x%016lx...0x%016lx\n",-res->flags,res->start,res->end);-}-}-EXPORT_SYMBOL(pcibios_fixup_device_resources);-void__devinitpcibios_setup_new_device(structpci_dev*dev){structdev_archdata*sd=&dev->dev.archdata;sd->of_node=pci_device_to_OF_node(dev);-DBG("PCI device %s OF node: %s\n",pci_name(dev),+DBG("PCI: device %s OF node: %s\n",pci_name(dev),sd->of_node?sd->of_node->full_name:"<none>");sd->dma_ops=pci_dma_ops;
@@ -722,42 +687,7 @@ static void __devinit do_bus_setup(struclist_for_each_entry(dev,&bus->devices,bus_list)pcibios_setup_new_device(dev);--/* Read default IRQs and fixup if necessary */-list_for_each_entry(dev,&bus->devices,bus_list){-pci_read_irq_line(dev);-if(ppc_md.pci_irq_fixup)-ppc_md.pci_irq_fixup(dev);-}-}--void__devinitpcibios_fixup_bus(structpci_bus*bus)-{-structpci_dev*dev=bus->self;-structdevice_node*np;--np=pci_bus_to_OF_node(bus);--DBG("pcibios_fixup_bus(%s)\n",np?np->full_name:"<???>");--if(dev&&pci_probe_only&&-(dev->class>>8)==PCI_CLASS_BRIDGE_PCI){-/* This is a subordinate bridge */--pci_read_bridge_bases(bus);-pcibios_fixup_device_resources(dev,bus);-}--do_bus_setup(bus);--if(!pci_probe_only)-return;--list_for_each_entry(dev,&bus->devices,bus_list)-if((dev->class>>8)!=PCI_CLASS_BRIDGE_PCI)-pcibios_fixup_device_resources(dev,bus);}-EXPORT_SYMBOL(pcibios_fixup_bus);unsignedlongpci_address_to_pio(phys_addr_taddress){
@@ -712,3 +712,133 @@ void pcibios_bus_to_resource(struct pci_res->end=(region->end+offset)&mask;}EXPORT_SYMBOL(pcibios_bus_to_resource);++/* Fixup a bus resource into a linux resource */+staticvoid__devinitfixup_resource(structresource*res,structpci_dev*dev)+{+structpci_controller*hose=pci_bus_to_host(dev->bus);+resource_size_toffset=0,mask=(resource_size_t)-1;++if(res->flags&IORESOURCE_IO){+offset=(unsignedlong)hose->io_base_virt-_IO_BASE;+mask=0xffffffffu;+}elseif(res->flags&IORESOURCE_MEM)+offset=hose->pci_mem_offset;++res->start=(res->start+offset)&mask;+res->end=(res->end+offset)&mask;++pr_debug("PCI:%s %016llx-%016llx\n",+pci_name(dev),+(unsignedlonglong)res->start,+(unsignedlonglong)res->end);+}+++/* This header fixup will do the resource fixup for all devices as they are+*probed,butnotforbridgeranges+*/+staticvoid__devinitpcibios_fixup_resources(structpci_dev*dev)+{+structpci_controller*hose=pci_bus_to_host(dev->bus);+inti;++if(!hose){+printk(KERN_ERR"No host bridge for PCI dev %s !\n",+pci_name(dev));+return;+}+for(i=0;i<DEVICE_COUNT_RESOURCE;i++){+structresource*res=dev->resource+i;+if(!res->flags)+continue;+if(res->end==0xffffffff){+pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] is unassigned\n",+pci_name(dev),i,+(unsignedlonglong)res->start,+(unsignedlonglong)res->end,+(unsignedint)res->flags);+res->end-=res->start;+res->start=0;+res->flags|=IORESOURCE_UNSET;+continue;+}++pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n",+pci_name(dev),i,+(unsignedlonglong)res->start,\+(unsignedlonglong)res->end,+(unsignedint)res->flags);++fixup_resource(res,dev);+}++/* Call machine specific resource fixup */+if(ppc_md.pcibios_fixup_resources)+ppc_md.pcibios_fixup_resources(dev);+}+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID,PCI_ANY_ID,pcibios_fixup_resources);++staticvoid__devinit__pcibios_fixup_bus(structpci_bus*bus)+{+structpci_dev*dev=bus->self;++pr_debug("PCI: Fixup bus %d (%s)\n",bus->number,dev?pci_name(dev):"PHB");++/* Fixup PCI<->PCI bridges. Host bridges are handled separately, for+*nowdifferentlybetween32and64bits.+*/+if(dev!=NULL){+structresource*res;+inti;++for(i=0;i<PCI_BUS_NUM_RESOURCES;++i){+if((res=bus->resource[i])==NULL)+continue;+if(!res->flags||bus->self->transparent)+continue;++pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",+pci_name(dev),i,+(unsignedlonglong)res->start,\+(unsignedlonglong)res->end,+(unsignedint)res->flags);++fixup_resource(res,dev);+}+}++/* Additional setup that is different between 32 and 64 bits for now */+pcibios_do_bus_setup(bus);++/* Platform specific bus fixups */+if(ppc_md.pcibios_fixup_bus)+ppc_md.pcibios_fixup_bus(bus);++/* Read default IRQs and fixup if necessary */+list_for_each_entry(dev,&bus->devices,bus_list){+pci_read_irq_line(dev);+if(ppc_md.pci_irq_fixup)+ppc_md.pci_irq_fixup(dev);+}+}++void__devinitpcibios_fixup_bus(structpci_bus*bus)+{+/* When called from the generic PCI probe, read PCI<->PCI bridge+*basesbeforeproceeding+*/+if(bus->self!=NULL)+pci_read_bridge_bases(bus);+__pcibios_fixup_bus(bus);+}+EXPORT_SYMBOL(pcibios_fixup_bus);++/* When building a bus from the OF tree rather than probing, we need a+*slightlydifferentversionofthefixupwhichdoesn'treadthe+*bridgebasesusingconfigspaceaccesses+*/+void__devinitpcibios_fixup_of_probed_bus(structpci_bus*bus)+{+__pcibios_fixup_bus(bus);+}
@@ -40,7 +40,6 @@ unsigned int ppc_pci_flags;voidpcibios_make_OF_bus_map(void);-staticvoidpcibios_fixup_resources(structpci_dev*dev);staticvoidfixup_broken_pcnet32(structpci_dev*dev);staticintreparent_resources(structresource*parent,structresource*res);staticvoidfixup_cpc710_pci64(structpci_dev*dev);
@@ -98,53 +97,6 @@ fixup_cpc710_pci64(struct pci_dev* dev)}DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,PCI_DEVICE_ID_IBM_CPC710_PCI64,fixup_cpc710_pci64);-staticvoid-pcibios_fixup_resources(structpci_dev*dev)-{-structpci_controller*hose=(structpci_controller*)dev->sysdata;-inti;-resource_size_toffset,mask;--if(!hose){-printk(KERN_ERR"No hose for PCI dev %s!\n",pci_name(dev));-return;-}-for(i=0;i<DEVICE_COUNT_RESOURCE;i++){-structresource*res=dev->resource+i;-if(!res->flags)-continue;-if(res->end==0xffffffff){-DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n",-pci_name(dev),i,(u64)res->start,(u64)res->end);-res->end-=res->start;-res->start=0;-res->flags|=IORESOURCE_UNSET;-continue;-}-offset=0;-mask=(resource_size_t)-1;-if(res->flags&IORESOURCE_MEM){-offset=hose->pci_mem_offset;-}elseif(res->flags&IORESOURCE_IO){-offset=(unsignedlong)hose->io_base_virt--isa_io_base;-mask=0xffffffffu;-}-if(offset!=0){-res->start=(res->start+offset)&mask;-res->end=(res->end+offset)&mask;-DBG("PCI: Fixup res %d (0x%lx) of dev %s: %llx -> %llx\n",-i,res->flags,pci_name(dev),-(u64)res->start-offset,(u64)res->start);-}-}--/* Call machine specific resource fixup */-if(ppc_md.pcibios_fixup_resources)-ppc_md.pcibios_fixup_resources(dev);-}-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID,PCI_ANY_ID,pcibios_fixup_resources);-staticintskip_isa_ioresource_align(structpci_dev*dev){if((ppc_pci_flags&PPC_PCI_CAN_SKIP_ISA_ALIGN)&&
@@ -757,14 +709,14 @@ pcibios_init(void)subsys_initcall(pcibios_init);-voidpcibios_fixup_bus(structpci_bus*bus)+void__devinitpcibios_do_bus_setup(structpci_bus*bus){structpci_controller*hose=(structpci_controller*)bus->sysdata;unsignedlongio_offset;structresource*res;-structpci_dev*dev;inti;+/* Hookup PHB resources */io_offset=(unsignedlong)hose->io_base_virt-isa_io_base;if(bus->parent==NULL){/* This is a host bridge - fill in its resources */
@@ -795,37 +747,6 @@ void pcibios_fixup_bus(struct pci_bus *b}bus->resource[i+1]=res;}-}else{-/* This is a subordinate bridge */-pci_read_bridge_bases(bus);--for(i=0;i<4;++i){-if((res=bus->resource[i])==NULL)-continue;-if(!res->flags||bus->self->transparent)-continue;-if(io_offset&&(res->flags&IORESOURCE_IO)){-res->start=(res->start+io_offset)&-0xffffffffu;-res->end=(res->end+io_offset)&-0xffffffffu;-}elseif(hose->pci_mem_offset-&&(res->flags&IORESOURCE_MEM)){-res->start+=hose->pci_mem_offset;-res->end+=hose->pci_mem_offset;-}-}-}--/* Platform specific bus fixups */-if(ppc_md.pcibios_fixup_bus)-ppc_md.pcibios_fixup_bus(bus);--/* Read default IRQs and fixup if necessary */-list_for_each_entry(dev,&bus->devices,bus_list){-pci_read_irq_line(dev);-if(ppc_md.pci_irq_fixup)-ppc_md.pci_irq_fixup(dev);}}
@@ -83,7 +83,7 @@ EXPORT_SYMBOL_GPL(pcibios_remove_pci_dev/* Must be called before pci_bus_add_devices */void-pcibios_fixup_new_pci_devices(structpci_bus*bus,intfix_bus)+pcibios_fixup_new_pci_devices(structpci_bus*bus){structpci_dev*dev;
@@ -98,8 +98,6 @@ pcibios_fixup_new_pci_devices(struct pci/* Fill device archdata and setup iommu table */pcibios_setup_new_device(dev);-if(fix_bus)-pcibios_fixup_device_resources(dev,bus);pci_read_irq_line(dev);for(i=0;i<PCI_NUM_RESOURCES;i++){structresource*r=&dev->resource[i];
@@ -132,8 +130,8 @@ pcibios_pci_config_bridge(struct pci_devpci_scan_child_bus(child_bus);-/* Fixup new pci devices without touching bus struct */-pcibios_fixup_new_pci_devices(child_bus,0);+/* Fixup new pci devices */+pcibios_fixup_new_pci_devices(child_bus);/* Make the discovered devices available */pci_bus_add_devices(child_bus);
@@ -205,13 +205,6 @@ struct machdep_calls {*optionalPCI"hooks"*/-/* Called after PPC generic resource fixup to perform-machinespecificfixups*/-void(*pcibios_fixup_resources)(structpci_dev*);--/* Called for each PCI bus in the system when it's probed */-void(*pcibios_fixup_bus)(structpci_bus*);-/* Called when pci_enable_device() is called (initial=0) or*whenadevicewithnoassignedresourceisfound(initial=1).*Returns0toallowassignment/enablingofthedevice.*/
@@ -225,6 +218,13 @@ struct machdep_calls {#endif /* CONFIG_PPC32 */+/* Called after PPC generic resource fixup to perform+machinespecificfixups*/+void(*pcibios_fixup_resources)(structpci_dev*);++/* Called for each PCI bus in the system when it's probed */+void(*pcibios_fixup_bus)(structpci_bus*);+/* Called to shutdown machine specific hardware not already controlled*byotherdrivers.*/
@@ -260,7 +260,7 @@ void pcibios_remove_pci_devices(struct p/** Discover new pci devices under this bus, and add them */voidpcibios_add_pci_devices(structpci_bus*bus);-voidpcibios_fixup_new_pci_devices(structpci_bus*bus,intfix_bus);+voidpcibios_fixup_new_pci_devices(structpci_bus*bus);externintpcibios_remove_root_bus(structpci_controller*phb);
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-12-06 08:11:37
The 32 bits PCI code now uses the generic code for assigning unassigned
resources and an algorithm similar to x86 for claiming existing ones.
This works far better than the 64 bits code which basically can only
claim existing ones (pci_probe_only=1) or would fall appart completely.
This merges them so that the new 32 bits implementation is used for both.
64 bits now gets the new PCI flags for controlling the behaviour, though
the old pci_probe_only global is still there for now to be cleared if you
want to.
I kept a pcibios_claim_one_bus() function mostly based on the old 64
bits code for use by the DLPAR hotplug. This will have to be cleaned
up, thought I hope it will work in the meantime.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This requires serious testing which I haven't had a chance to do yet,
especially with DLPAR PCI hotplug.
arch/powerpc/kernel/pci-common.c | 288 ++++++++++++++++++++++++++++++++++
arch/powerpc/kernel/pci_32.c | 246 -----------------------------
arch/powerpc/kernel/pci_64.c | 123 +-------------
arch/powerpc/platforms/powermac/pci.c | 3
include/asm-powerpc/pci-bridge.h | 9 -
include/asm-powerpc/pci.h | 8
6 files changed, 312 insertions(+), 365 deletions(-)
Index: linux-work/arch/powerpc/kernel/pci-common.c
===================================================================
@@ -55,6 +55,8 @@ extern struct list_head hose_list;/* ISA Memory physical address */resource_size_tisa_mem_base;+/* Default PCI flags is 0 */+unsignedintppc_pci_flags;/**pci_controller(phb)initializedcommonvariables.
@@ -842,3 +844,289 @@ void __devinit pcibios_fixup_of_probed_b{__pcibios_fixup_bus(bus);}++staticintskip_isa_ioresource_align(structpci_dev*dev)+{+if((ppc_pci_flags&PPC_PCI_CAN_SKIP_ISA_ALIGN)&&+!(dev->bus->bridge_ctl&PCI_BRIDGE_CTL_ISA))+return1;+return0;+}++/*+*Weneedtoavoidcollisionswith`mirrored'VGAports+*andotherstrangeISAhardware,sowealwayswantthe+*addressestobeallocatedinthe0x000-0x0ffregion+*modulo0x400.+*+*Why?BecausesomesillyexternalIOcardsonlydecode+*thelow10bitsoftheIOaddress.The0x00-0xffregion+*isreservedformotherboarddevicesthatdecodeall16+*bits,soit'soktoallocateat,say,0x2800-0x28ff,+*butwewanttotrytoavoidallocatingat0x2900-0x2bff+*whichmighthavebemirroredat0x0100-0x03ff..+*/+voidpcibios_align_resource(void*data,structresource*res,+resource_size_tsize,resource_size_talign)+{+structpci_dev*dev=data;++if(res->flags&IORESOURCE_IO){+resource_size_tstart=res->start;++if(skip_isa_ioresource_align(dev))+return;+if(start&0x300){+start=(start+0x3ff)&~0x3ff;+res->start=start;+}+}+}+EXPORT_SYMBOL(pcibios_align_resource);++/*+*Reparentresourcechildrenofprthatconflictwithres+*underres,andmakeresreplacethosechildren.+*/+staticint__initreparent_resources(structresource*parent,+structresource*res)+{+structresource*p,**pp;+structresource**firstpp=NULL;++for(pp=&parent->child;(p=*pp)!=NULL;pp=&p->sibling){+if(p->end<res->start)+continue;+if(res->end<p->start)+break;+if(p->start<res->start||p->end>res->end)+return-1;/* not completely contained */+if(firstpp==NULL)+firstpp=pp;+}+if(firstpp==NULL)+return-1;/* didn't find any conflicting entries? */+res->parent=parent;+res->child=*firstpp;+res->sibling=*pp;+*firstpp=res;+*pp=NULL;+for(p=res->child;p!=NULL;p=p->sibling){+p->parent=res;+DBG(KERN_INFO"PCI: reparented %s [%llx..%llx] under %s\n",+p->name,+(unsignedlonglong)p->start,+(unsignedlonglong)p->end,res->name);+}+return0;+}++/*+*HandleresourcesofPCIdevices.Iftheworldwereperfect,wecould+*justallocatealltheresourceregionsanddonothingmore.Itisn't.+*Ontheotherhand,wecannotjustre-allocatealldevices,asitwould+*requireustoknowlotsofhostbridgeinternals.Soweattemptto+*keepasmuchoftheoriginalconfigurationaspossible,buttweakit+*whenit'sfoundtobewrong.+*+*KnownBIOSproblemswehavetoworkaround:+*-I/Oormemoryregionsnotconfigured+*-regionsconfigured,butnotenabledinthecommandregister+*-bogusI/Oaddressesabove64Kused+*-expansionROMsleftenabled(thismaysoundharmless,butgiven+*thefactthePCIspecsexplicitlyallowaddressdecoderstobe+*sharedbetweenexpansionROMsandotherresourceregions,it's+*atleastdangerous)+*+*Oursolution:+*(1)AllocateresourcesforallbusesbehindPCI-to-PCIbridges.+*Thisgivesusfixedbarriersonwherewecanallocate.+*(2)Allocateresourcesforallenableddevices.Ifthereis+*acollision,justmarktheresourceasunallocated.Also+*disableexpansionROMsduringthisstep.+*(3)Trytoallocateresourcesfordisableddevices.Ifthe+*resourceswereassignedcorrectly,everythinggoeswell,+*iftheyweren't,theywon'tdisturballocationofother+*resources.+*(4)Assignnewaddressestoresourceswhichwereeither+*notconfiguredatallormisconfigured.Ifexplicitly+*requestedbytheuser,configureexpansionROMaddress+*aswell.+*/++staticvoid__initpcibios_allocate_bus_resources(structlist_head*bus_list)+{+structpci_bus*bus;+inti;+structresource*res,*pr;++/* Depth-First Search on bus tree */+list_for_each_entry(bus,bus_list,node){+for(i=0;i<PCI_BUS_NUM_RESOURCES;++i){+if((res=bus->resource[i])==NULL||!res->flags+||res->start>res->end)+continue;+if(bus->parent==NULL)+pr=(res->flags&IORESOURCE_IO)?+&ioport_resource:&iomem_resource;+else{+/* Don't bother with non-root busses when+*re-assigningallresources.+*/+if(ppc_pci_flags&PPC_PCI_REASSIGN_ALL_RSRC)+continue;+pr=pci_find_parent_resource(bus->self,res);+if(pr==res){+/* this happens when the generic PCI+*code(wrongly)decidesthatthis+*bridgeistransparent--paulus+*/+continue;+}+}++DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx "+"[0x%x], parent %p (%s)\n",+bus->self?pci_name(bus->self):"PHB",+bus->number,i,+(unsignedlonglong)res->start,+(unsignedlonglong)res->end,+(unsignedint)res->flags,+pr,(pr&&pr->name)?pr->name:"nil");++if(pr&&!(pr->flags&IORESOURCE_UNSET)){+if(request_resource(pr,res)==0)+continue;+/*+*Mustbeaconflictwithanexistingentry.+*Movethatentry(orentries)underthe+*bridgeresourceandtryagain.+*/+if(reparent_resources(pr,res)==0)+continue;+}+printk(KERN_WARNING+"PCI: Cannot allocate resource region "+"%d of PCI bridge %d, will remap\n",+i,bus->number);+res->flags|=IORESOURCE_UNSET;+}+pcibios_allocate_bus_resources(&bus->children);+}+}++staticinlinevoid__devinitalloc_resource(structpci_dev*dev,intidx)+{+structresource*pr,*r=&dev->resource[idx];++DBG("PCI: Allocating %s: Resource %d: %016llx..%016llx [%x]\n",+pci_name(dev),idx,+(unsignedlonglong)r->start,+(unsignedlonglong)r->end,+(unsignedint)r->flags);++pr=pci_find_parent_resource(dev,r);+if(!pr||(pr->flags&IORESOURCE_UNSET)||+request_resource(pr,r)<0){+printk(KERN_WARNING"PCI: Cannot allocate resource region %d"+" of device %s, will remap\n",idx,pci_name(dev));+if(pr)+DBG("PCI: parent is %p: %016llx-%016llx [%x]\n",pr,+(unsignedlonglong)pr->start,+(unsignedlonglong)pr->end,+(unsignedint)pr->flags);+/* We'll assign a new address later */+r->flags|=IORESOURCE_UNSET;+r->end-=r->start;+r->start=0;+}+}++staticvoid__initpcibios_allocate_resources(intpass)+{+structpci_dev*dev=NULL;+intidx,disabled;+u16command;+structresource*r;++for_each_pci_dev(dev){+pci_read_config_word(dev,PCI_COMMAND,&command);+for(idx=0;idx<6;idx++){+r=&dev->resource[idx];+if(r->parent)/* Already allocated */+continue;+if(!r->flags||(r->flags&IORESOURCE_UNSET))+continue;/* Not assigned at all */+if(r->flags&IORESOURCE_IO)+disabled=!(command&PCI_COMMAND_IO);+else+disabled=!(command&PCI_COMMAND_MEMORY);+if(pass==disabled)+alloc_resource(dev,idx);+}+if(pass)+continue;+r=&dev->resource[PCI_ROM_RESOURCE];+if(r->flags&IORESOURCE_ROM_ENABLE){+/* Turn the ROM off, leave the resource region,+*butkeepitunregistered.+*/+u32reg;+DBG("PCI: Switching off ROM of %s\n",pci_name(dev));+r->flags&=~IORESOURCE_ROM_ENABLE;+pci_read_config_dword(dev,dev->rom_base_reg,®);+pci_write_config_dword(dev,dev->rom_base_reg,+reg&~PCI_ROM_ADDRESS_ENABLE);+}+}+}++void__initpcibios_resource_survey(void)+{+/* Allocate and assign resources. If we re-assign everything, then+*weskiptheallocatephase+*/+pcibios_allocate_bus_resources(&pci_root_buses);++if(!(ppc_pci_flags&PPC_PCI_REASSIGN_ALL_RSRC)){+pcibios_allocate_resources(0);+pcibios_allocate_resources(1);+}++if(!(ppc_pci_flags&PPC_PCI_PROBE_ONLY)){+DBG("PCI: Assigning unassigned resouces...\n");+pci_assign_unassigned_resources();+}++/* Call machine dependent fixup */+if(ppc_md.pcibios_fixup)+ppc_md.pcibios_fixup();+}++#ifdef CONFIG_HOTPLUG+/* This is used by the pSeries hotplug driver to allocate resource+*ofnewlypluggedbusses.Wecantrytoconsolidatewiththe+*restofthecodelater,fornow,keepitas-is+*/+void__devinitpcibios_claim_one_bus(structpci_bus*bus)+{+structpci_dev*dev;+structpci_bus*child_bus;++list_for_each_entry(dev,&bus->devices,bus_list){+inti;++for(i=0;i<PCI_NUM_RESOURCES;i++){+structresource*r=&dev->resource[i];++if(r->parent||!r->start||!r->flags)+continue;+pci_claim_resource(dev,i);+}+}++list_for_each_entry(child_bus,&bus->children,node)+pcibios_claim_one_bus(child_bus);+}+EXPORT_SYMBOL_GPL(pcibios_claim_one_bus);+#endif /* CONFIG_HOTPLUG */
@@ -35,13 +35,9 @@ unsigned long isa_io_base = 0;unsignedlongpci_dram_offset=0;intpcibios_assign_bus_offset=1;-/* Default PCI flags is 0 */-unsignedintppc_pci_flags;-voidpcibios_make_OF_bus_map(void);staticvoidfixup_broken_pcnet32(structpci_dev*dev);-staticintreparent_resources(structresource*parent,structresource*res);staticvoidfixup_cpc710_pci64(structpci_dev*dev);#ifdef CONFIG_PPC_OFstaticu8*pci_to_OF_bus_map;
@@ -97,170 +93,6 @@ fixup_cpc710_pci64(struct pci_dev* dev)}DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,PCI_DEVICE_ID_IBM_CPC710_PCI64,fixup_cpc710_pci64);-staticintskip_isa_ioresource_align(structpci_dev*dev)-{-if((ppc_pci_flags&PPC_PCI_CAN_SKIP_ISA_ALIGN)&&-!(dev->bus->bridge_ctl&PCI_BRIDGE_CTL_ISA))-return1;-return0;-}--/*-*Weneedtoavoidcollisionswith`mirrored'VGAports-*andotherstrangeISAhardware,sowealwayswantthe-*addressestobeallocatedinthe0x000-0x0ffregion-*modulo0x400.-*-*Why?BecausesomesillyexternalIOcardsonlydecode-*thelow10bitsoftheIOaddress.The0x00-0xffregion-*isreservedformotherboarddevicesthatdecodeall16-*bits,soit'soktoallocateat,say,0x2800-0x28ff,-*butwewanttotrytoavoidallocatingat0x2900-0x2bff-*whichmighthavebemirroredat0x0100-0x03ff..-*/-voidpcibios_align_resource(void*data,structresource*res,-resource_size_tsize,resource_size_talign)-{-structpci_dev*dev=data;--if(res->flags&IORESOURCE_IO){-resource_size_tstart=res->start;--if(skip_isa_ioresource_align(dev))-return;-if(start&0x300){-start=(start+0x3ff)&~0x3ff;-res->start=start;-}-}-}-EXPORT_SYMBOL(pcibios_align_resource);--/*-*HandleresourcesofPCIdevices.Iftheworldwereperfect,wecould-*justallocatealltheresourceregionsanddonothingmore.Itisn't.-*Ontheotherhand,wecannotjustre-allocatealldevices,asitwould-*requireustoknowlotsofhostbridgeinternals.Soweattemptto-*keepasmuchoftheoriginalconfigurationaspossible,buttweakit-*whenit'sfoundtobewrong.-*-*KnownBIOSproblemswehavetoworkaround:-*-I/Oormemoryregionsnotconfigured-*-regionsconfigured,butnotenabledinthecommandregister-*-bogusI/Oaddressesabove64Kused-*-expansionROMsleftenabled(thismaysoundharmless,butgiven-*thefactthePCIspecsexplicitlyallowaddressdecoderstobe-*sharedbetweenexpansionROMsandotherresourceregions,it's-*atleastdangerous)-*-*Oursolution:-*(1)AllocateresourcesforallbusesbehindPCI-to-PCIbridges.-*Thisgivesusfixedbarriersonwherewecanallocate.-*(2)Allocateresourcesforallenableddevices.Ifthereis-*acollision,justmarktheresourceasunallocated.Also-*disableexpansionROMsduringthisstep.-*(3)Trytoallocateresourcesfordisableddevices.Ifthe-*resourceswereassignedcorrectly,everythinggoeswell,-*iftheyweren't,theywon'tdisturballocationofother-*resources.-*(4)Assignnewaddressestoresourceswhichwereeither-*notconfiguredatallormisconfigured.Ifexplicitly-*requestedbytheuser,configureexpansionROMaddress-*aswell.-*/--staticvoid__init-pcibios_allocate_bus_resources(structlist_head*bus_list)-{-structpci_bus*bus;-inti;-structresource*res,*pr;--/* Depth-First Search on bus tree */-list_for_each_entry(bus,bus_list,node){-for(i=0;i<4;++i){-if((res=bus->resource[i])==NULL||!res->flags-||res->start>res->end)-continue;-if(bus->parent==NULL)-pr=(res->flags&IORESOURCE_IO)?-&ioport_resource:&iomem_resource;-else{-/* Don't bother with non-root busses when-*re-assigningallresources.-*/-if(ppc_pci_flags&PPC_PCI_REASSIGN_ALL_RSRC)-continue;-pr=pci_find_parent_resource(bus->self,res);-if(pr==res){-/* this happens when the generic PCI-*code(wrongly)decidesthatthis-*bridgeistransparent--paulus-*/-continue;-}-}--DBG("PCI: dev %s (bus 0x%02x) bridge rsrc %d: %016llx..%016llx "-"(f:0x%08lx), parent %p\n",-bus->self?pci_name(bus->self):"PHB",bus->number,i,-(u64)res->start,(u64)res->end,res->flags,pr);--if(pr&&!(pr->flags&IORESOURCE_UNSET)){-if(request_resource(pr,res)==0)-continue;-/*-*Mustbeaconflictwithanexistingentry.-*Movethatentry(orentries)underthe-*bridgeresourceandtryagain.-*/-if(reparent_resources(pr,res)==0)-continue;-}-printk(KERN_WARNING-"PCI: Cannot allocate resource region "-"%d of PCI bridge %d, will remap\n",-i,bus->number);-res->flags|=IORESOURCE_UNSET;-}-pcibios_allocate_bus_resources(&bus->children);-}-}--/*-*Reparentresourcechildrenofprthatconflictwithres-*underres,andmakeresreplacethosechildren.-*/-staticint__init-reparent_resources(structresource*parent,structresource*res)-{-structresource*p,**pp;-structresource**firstpp=NULL;--for(pp=&parent->child;(p=*pp)!=NULL;pp=&p->sibling){-if(p->end<res->start)-continue;-if(res->end<p->start)-break;-if(p->start<res->start||p->end>res->end)-return-1;/* not completely contained */-if(firstpp==NULL)-firstpp=pp;-}-if(firstpp==NULL)-return-1;/* didn't find any conflicting entries? */-res->parent=parent;-res->child=*firstpp;-res->sibling=*pp;-*firstpp=res;-*pp=NULL;-for(p=res->child;p!=NULL;p=p->sibling){-p->parent=res;-DBG(KERN_INFO"PCI: reparented %s [%llx..%llx] under %s\n",-p->name,(u64)p->start,(u64)p->end,res->name);-}-return0;-}void__initupdate_bridge_resource(structpci_dev*dev,structresource*res)
@@ -318,63 +150,6 @@ update_bridge_resource(struct pci_dev *dpci_write_config_word(dev,PCI_COMMAND,cmd);}-staticinlinevoidalloc_resource(structpci_dev*dev,intidx)-{-structresource*pr,*r=&dev->resource[idx];--DBG("PCI: Allocating %s: Resource %d: %016llx..%016llx (f=%lx)\n",-pci_name(dev),idx,(u64)r->start,(u64)r->end,r->flags);-pr=pci_find_parent_resource(dev,r);-if(!pr||(pr->flags&IORESOURCE_UNSET)||request_resource(pr,r)<0){-printk(KERN_WARNING"PCI: Cannot allocate resource region %d"-" of device %s, will remap\n",idx,pci_name(dev));-if(pr)-DBG("PCI: parent is %p: %016llx-%016llx (f=%lx)\n",-pr,(u64)pr->start,(u64)pr->end,pr->flags);-/* We'll assign a new address later */-r->flags|=IORESOURCE_UNSET;-r->end-=r->start;-r->start=0;-}-}--staticvoid__init-pcibios_allocate_resources(intpass)-{-structpci_dev*dev=NULL;-intidx,disabled;-u16command;-structresource*r;--for_each_pci_dev(dev){-pci_read_config_word(dev,PCI_COMMAND,&command);-for(idx=0;idx<6;idx++){-r=&dev->resource[idx];-if(r->parent)/* Already allocated */-continue;-if(!r->flags||(r->flags&IORESOURCE_UNSET))-continue;/* Not assigned at all */-if(r->flags&IORESOURCE_IO)-disabled=!(command&PCI_COMMAND_IO);-else-disabled=!(command&PCI_COMMAND_MEMORY);-if(pass==disabled)-alloc_resource(dev,idx);-}-if(pass)-continue;-r=&dev->resource[PCI_ROM_RESOURCE];-if(r->flags&IORESOURCE_ROM_ENABLE){-/* Turn the ROM off, leave the resource region, but keep it unregistered. */-u32reg;-DBG("PCI: Switching off ROM of %s\n",pci_name(dev));-r->flags&=~IORESOURCE_ROM_ENABLE;-pci_read_config_dword(dev,dev->rom_base_reg,®);-pci_write_config_dword(dev,dev->rom_base_reg,-reg&~PCI_ROM_ADDRESS_ENABLE);-}-}-}#ifdef CONFIG_PPC_OF/*
@@ -76,88 +76,6 @@ static void fixup_broken_pcnet32(struct DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT,PCI_ANY_ID,fixup_broken_pcnet32);-/*-*Weneedtoavoidcollisionswith`mirrored'VGAports-*andotherstrangeISAhardware,sowealwayswantthe-*addressestobeallocatedinthe0x000-0x0ffregion-*modulo0x400.-*-*Why?BecausesomesillyexternalIOcardsonlydecode-*thelow10bitsoftheIOaddress.The0x00-0xffregion-*isreservedformotherboarddevicesthatdecodeall16-*bits,soit'soktoallocateat,say,0x2800-0x28ff,-*butwewanttotrytoavoidallocatingat0x2900-0x2bff-*whichmighthavebemirroredat0x0100-0x03ff..-*/-voidpcibios_align_resource(void*data,structresource*res,-resource_size_tsize,resource_size_talign)-{-structpci_dev*dev=data;-structpci_controller*hose=pci_bus_to_host(dev->bus);-resource_size_tstart=res->start;-unsignedlongalignto;--if(res->flags&IORESOURCE_IO){-unsignedlongoffset=(unsignedlong)hose->io_base_virt--_IO_BASE;-/* Make sure we start at our min on all hoses */-if(start-offset<PCIBIOS_MIN_IO)-start=PCIBIOS_MIN_IO+offset;--/*-*Puteverythinginto0x00-0xffregionmodulo0x400-*/-if(start&0x300)-start=(start+0x3ff)&~0x3ff;--}elseif(res->flags&IORESOURCE_MEM){-/* Make sure we start at our min on all hoses */-if(start-hose->pci_mem_offset<PCIBIOS_MIN_MEM)-start=PCIBIOS_MIN_MEM+hose->pci_mem_offset;--/* Align to multiple of size of minimum base. */-alignto=max(0x1000UL,align);-start=ALIGN(start,alignto);-}--res->start=start;-}--void__devinitpcibios_claim_one_bus(structpci_bus*b)-{-structpci_dev*dev;-structpci_bus*child_bus;--list_for_each_entry(dev,&b->devices,bus_list){-inti;--for(i=0;i<PCI_NUM_RESOURCES;i++){-structresource*r=&dev->resource[i];--if(r->parent||!r->start||!r->flags)-continue;-pci_claim_resource(dev,i);-}-}--list_for_each_entry(child_bus,&b->children,node)-pcibios_claim_one_bus(child_bus);-}-#ifdef CONFIG_HOTPLUG-EXPORT_SYMBOL_GPL(pcibios_claim_one_bus);-#endif--staticvoid__initpcibios_claim_of_setup(void)-{-structpci_bus*b;--if(firmware_has_feature(FW_FEATURE_ISERIES))-return;--list_for_each_entry(b,&pci_root_buses,node)-pcibios_claim_one_bus(b);-}-staticu32get_int_prop(structdevice_node*np,constchar*name,u32def){constu32*prop;
@@ -428,6 +346,7 @@ void __devinit scan_phb(struct pci_contrDBG("Scanning PHB %s\n",node?node->full_name:"<NO NAME>");+/* Create an empty bus for the toplevel */bus=pci_create_bus(hose->parent,hose->first_busno,hose->ops,node);if(bus==NULL){printk(KERN_ERR"Failed to create bus for PCI domain %04x\n",
@@ -437,27 +356,17 @@ void __devinit scan_phb(struct pci_contrbus->secondary=hose->first_busno;hose->bus=bus;+/* Get some IO space for the new PHB */if(!firmware_has_feature(FW_FEATURE_ISERIES))pcibios_map_io_space(bus);+/* Wire up PHB bus resources */bus->resource[0]=res=&hose->io_resource;-if(res->flags&&request_resource(&ioport_resource,res)){-printk(KERN_ERR"Failed to request PCI IO region "-"on PCI domain %04x\n",hose->global_number);-DBG("res->start = 0x%016lx, res->end = 0x%016lx\n",-res->start,res->end);-}--for(i=0;i<3;++i){-res=&hose->mem_resources[i];-bus->resource[i+1]=res;-if(res->flags&&request_resource(&iomem_resource,res))-printk(KERN_ERR"Failed to request PCI memory region "-"on PCI domain %04x\n",hose->global_number);-}+for(i=0;i<3;++i)+bus->resource[i+1]=&hose->mem_resources[i];+/* Get probe mode and perform scan */mode=PCI_PROBE_NORMAL;-if(node&&ppc_md.pci_probe_mode)mode=ppc_md.pci_probe_mode(bus);DBG(" probe mode: %d\n",mode);
@@ -474,6 +383,8 @@ static int __init pcibios_init(void){structpci_controller*hose,*tmp;+printk(KERN_INFO"PCI: Probing PCI hardware\n");+/* For now, override phys_mem_access_prot. If we need it,*later,wemaymovethatinitializationtoeachppc_md*/
@@ -484,25 +395,17 @@ static int __init pcibios_init(void)printk(KERN_DEBUG"PCI: Probing PCI hardware\n");+if(pci_probe_only)+ppc_pci_flags|=PPC_PCI_PROBE_ONLY;+/* Scan all of the recorded PCI controllers. */list_for_each_entry_safe(hose,tmp,&hose_list,list_node){scan_phb(hose);pci_bus_add_devices(hose->bus);}-if(!firmware_has_feature(FW_FEATURE_ISERIES)){-if(pci_probe_only)-pcibios_claim_of_setup();-else-/* FIXME: `else' will be removed when-pci_assign_unassigned_resources()isabletowork-correctlywith[partially]allocatedPCItree.*/-pci_assign_unassigned_resources();-}--/* Call machine dependent final fixup */-if(ppc_md.pcibios_fixup)-ppc_md.pcibios_fixup();+/* Call common code to handle resource allocation */+pcibios_resource_survey();printk(KERN_DEBUG"PCI: Probing PCI hardware done\n");
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-12-06 08:11:38
It should now be safe to re-assign unassigned resources on 64 bits PowerMac
machines (G5s). This clears pci_probe_only on those.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/platforms/powermac/pci.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Index: linux-work/arch/powerpc/platforms/powermac/pci.c
===================================================================
@@ -1041,8 +1041,8 @@ void __init pmac_pci_init(void)}/* pmac_check_ht_link(); */-/* Tell pci.c to not use the common resource allocation mechanism */-pci_probe_only=1;+/* We can allocate missing resources if any */+pci_probe_only=0;#else /* CONFIG_PPC64 */init_p2pbridge();
From: Jon Loeliger <hidden> Date: 2007-12-06 17:03:15
On Thu, 2007-12-06 at 02:11, Benjamin Herrenschmidt wrote:
quoted hunk
The 32 bits PCI code carries an old hack that was only useful for G5
machines. Nowdays, the 32 bits kernel doesn't support any of those
machines anymore so the hack is basically never used, remove it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci_32.c | 11 -----------
1 file changed, 11 deletions(-)
Index: linux-work/arch/powerpc/kernel/pci_32.c
===================================================================
@@ -922,17 +922,6 @@ long sys_pciconfig_iobase(long which, unstructpci_controller*hose;longresult=-EOPNOTSUPP;-/* Argh ! Please forgive me for that hack, but that's the-*simplestwaytogetexistingXFreetonotlockuponsome-*G5machines...Sowhensomethingasksforbus0iobase-*(bus0isHTroot),wereturntheAGPoneinstead.-*/-#ifdef CONFIG_PPC_PMAC-if(machine_is(powermac)&&machine_is_compatible("MacRISC4"))-if(bus==0)-bus=0xf0;-#endif /* CONFIG_PPC_PMAC */-
I believe, with this patch, you are officially forgiven. :-)
jdl
From: Stefan Roese <sr@denx.de> Date: 2007-12-07 10:19:43
On Thursday 06 December 2007, Benjamin Herrenschmidt wrote:
This serie of patches converts the 32 bits PCI code to use the generic
pci_assign_unassigned_resources() instead of its own assignment code
which was unable to deal with unassigned PCI<->PCI bridges among
other issues.
It then merges the resource fixup and allocation code between 32 and
64 bits (mostly making 64 bits use the 32 bits code with a few fixups),
hopefully fixing the longstanding issue that not setting pci_probe_only
on ppc64 would generally not work.
We also add flags to control the behaviour of the PCI code, such as
letting some platforms force a full re-assignment (similar to what
pci-auto used to provide in arch/ppc) and remove a whole bunch of
hackish code that is made obsolete by that change.
32 bits platforms with 64 bits resources support will also need my
separate patch to fix the generic setup-bus.c for that situation.
Note that the patch that updates 4xx platforms to enable full resource
assignments applied on top of my 4xx series for which I'll post a new
version soon. You can apply the other ones and ignore this one if you
want to test on some other platform without the other patch serie.
No problems on Katmai (440SPe) and Kilauea (405EX) so far. Apart from DEBUG
still enabled in patch 8/10 as Olof already pointed out.
Tested-by: Stefan Roese <sr@denx.de>
Best regards,
Stefan