Messages in this thread Patches in this message | | | Date | Tue, 13 Jul 1999 17:01:20 -0700 | From | Johnnie Peters <> | Subject | How Swap PCI changes. |
| |
Hi Everybody,
I am sorry to say I forgot to attach the diff files for the PCI changes from Motorola. I apologize but this is a mistake I make time after time. Here they are.
Johnnie Peters Motorola Computer Group Tempe, Az.diff -u -r --new-file linux/CREDITS linux_mot/CREDITS --- linux/CREDITS Wed Jun 9 22:23:01 1999 +++ linux_mot/CREDITS Fri Jul 9 14:40:03 1999 @@ -1659,6 +1659,13 @@ W: http://www.nyx.net/~arobinso D: Hayes ESP serial port driver +N: Robert Robinson +E: robr@phx.mcd.mot.com +D: Added PCI services to support hotswapping +S: 2900 South Diablo Way, DW278 +S: Tempe, Arizona 85282 +S: USA + N: Florian La Roche E: rzsfl@rz.uni-sb.de E: flla@stud.uni-sb.de diff -u -r --new-file linux/Documentation/Configure.help linux_mot/Documentation/Configure.help --- linux/Documentation/Configure.help Sun Jun 13 19:54:06 1999 +++ linux_mot/Documentation/Configure.help Fri Jul 9 12:57:19 1999 @@ -1394,6 +1394,289 @@ kernel will try the direct access method and falls back to the BIOS if that doesn't work. If unsure, go with the default. +PCI services +CONFIG_PCI_SERVICES + If your platform supports PCI hot swap capability, you can add + dynamic PCI device/resource management services here, e.g. dynamic + PCI bus node management, as well as PCI memory and I/O space + management. If unsure, say N. + +PCI Bus Level 0 nodes +CONFIG_PCI_BUSLVL0_NODES + This PCI Services option sets the number of Bus Level 0 nodes for + your platform. The number of Bus Level 0 nodes is the same as + the number of PCI Host Bridges connected to the Host Bus. Normally, + each system has only one Host Bridge. + +PCI Bus Level 1 nodes +CONFIG_PCI_BUSLVL1_NODES + This PCI Services option sets the number of Bus Level 1 nodes for + your platform. The number of Bus Level 1 nodes is the number of + PCI-to-PCI bridges (excluding any AGP bridges) whose primary bus + is the Host Bridges' secondary bus, e.g. PCI bus 0. Normally, + each system has only one such bridge. + +PCI Bus Level 2 nodes +CONFIG_PCI_BUSLVL2_NODES + This PCI Services option sets the number of Bus Level 2 nodes for + your platform. Typically, each PCI slot or card in a system is + a Bus Level 2 node. Each card usually has one PCI-to-PCI bridge + which is connected to a Bus Level 1 node. The maximum number of + PCI cards (hence, Bus Level 2 nodes) is normally eight for a system. + +PCI Bus Level 3 nodes +CONFIG_PCI_BUSLVL3_NODES + This PCI Services option sets the number of Bus Level 3 nodes for + your platform. A Bus Level 3 node is an additional PCI-to-PCI + bridge located on the PCI card. Normally, there is no more than + one additional bridge (connected to a Bus Level 2 node) per card. + +PCI I/O space starting address +CONFIG_PCI_IO_START + This PCI Services option sets the starting address of configurable + PCI I/O space for your platform. If no configurable PCI I/O space + is needed or available, then set this value to 00000000 and + the CONFIG_PCI_IO_END PCI Services option to ffffffff. + +PCI I/O space ending address +CONFIG_PCI_IO_END + This PCI Services option sets the ending address of configurable + PCI I/O space for your platform. If no configurable PCI I/O space + is needed or available, then set this value to ffffffff and the + CONFIG_PCI_IO_START PCI Services option to 00000000. + +PCI 20-bit memory space starting address +CONFIG_PCI_MEM20_START + This PCI Services option sets the starting address of configurable + PCI 20-bit memory space (i.e. memory below 1M byte) for your platform. + Note that only Bus 0 devices can be configured to use 20-bit memory. + +PCI 20-bit memory space ending address +CONFIG_PCI_MEM20_END + This PCI Services option sets the ending address of configurable + PCI 20-bit memory space (i.e. memory below 1M byte) for your platform. + Note that only Bus 0 devices can be configured to use 20-bit memory. + +PCI memory space starting address +CONFIG_PCI_MEM_START + This PCI Services option sets the starting address of normal + configurable PCI memory space (i.e. either 32-bit memory or + 64-bit memory). + +PCI memory space ending address +CONFIG_PCI_MEM_END + This PCI Services option sets the ending address of normal + configurable PCI memory space (i.e. either 32-bit memory or + 64-bit memory). + +PCI prefetch memory space starting address +CONFIG_PCI_MEMPF_START + This PCI Services option sets the starting address of configurable + PCI prefetchable memory space, (i.e. either 32-bit prefetchable + memory or 64-bit prefetchable memory). If no configurable PCI + prefetchable memory space is needed or available, then set this + value to 00000000 and the CONFIG_PCI_MEMPF_END PCI Services option + to ffffffff. + +PCI prefetch memory space ending address +CONFIG_PCI_MEMPF_END + This PCI Services option sets the ending address of configurable + PCI prefetchable memory space, (i.e. either 32-bit prefetchable + memory or 64-bit prefetchable memory). If no configurable PCI + prefetchable memory space is needed or available, then set this + value to ffffffff and the CONFIG_PCI_MEMPF_START PCI Services + option to 00000000. + +PCI AGP bridge +CONFIG_PCI_AGP_BRIDGE + This PCI Services option enables support for an AGP PCI-2-PCI bridge + device. If your platform doesn't have an AGP PCI-2-PCI bridge device, + then you should say N here. If unsure, say N. + +PCI AGP bridge I/O space size +CONFIG_PCI_AGP_IO_SIZE + If the AGP PCI-2-PCI bridge option is enabled, this PCI Services option + sets the size of I/O space that will be allocated for the AGP PCI-2-PCI + bridge device. + +PCI AGP bridge memory space size +CONFIG_PCI_AGP_MEM_SIZE + If the AGP PCI-2-PCI bridge option is enabled, this PCI Services option + sets the size of memory space that will be allocated for the AGP PCI-2-PCI + bridge device. + +PCI AGP prefetch memory space size +CONFIG_PCI_AGP_MEMPF_SIZE + If the AGP PCI-2-PCI bridge option is enabled, this PCI Services option + sets the size of prefetchable memory space that will be allocated for the + AGP PCI-2-PCI bridge device. + +PCI local IRQ A +CONFIG_PCI_LOCAL_PIRQA + This PCI Services option sets the PCI Interrupt A (PIRQA) + value for PCI for the local domain. + +PCI local IRQ B +CONFIG_PCI_LOCAL_PIRQB + This PCI Services option sets the PCI Interrupt B (PIRQB) + value for PCI for the local domain. + +PCI local IRQ C +CONFIG_PCI_LOCAL_PIRQC + This PCI Services option sets the PCI Interrupt C (PIRQC) + value for PCI for the local domain. + +PCI local IRQ D +CONFIG_PCI_LOCAL_PIRQD + This PCI Services option sets the PCI Interrupt D (PIRQD) + value for PCI for the local domain. + +PCI multi-domain system +CONFIG_PCI_MULTI_DOMAIN + This PCI Services option enables support for systems with more + than one PCI domain, i.e. a local domain and a remote domain. If + you have a system with only one domain, like most personal + computers, say N. + +PCI remote IRQ A +CONFIG_PCI_REMOTE_PIRQA + If the multi-domain option is enabled, this PCI + PCI Services option sets the PIRQA value for PCI + Interrupt A in the remote domain. + +PCI remote IRQ B +CONFIG_PCI_REMOTE_PIRQB + If the multi-domain option is enabled, this PCI + PCI Services option sets the PIRQB value for PCI + Interrupt A in the remote domain. + +PCI remote IRQ C +CONFIG_PCI_REMOTE_PIRQC + If the multi-domain option is enabled, this PCI + PCI Services option sets the PIRQC value for PCI + Interrupt A in the remote domain. + +PCI remote IRQ D +CONFIG_PCI_REMOTE_PIRQD + If the multi-domain option is enabled, this PCI + PCI Services option sets the PIRQD value for PCI + Interrupt A in the remote domain. + +PCI remote domain bridge device/function +CONFIG_PCI_REMOTE_DEV + This PCI Services option sets the device/function value + for the remote domain PCI-2-PCI bridge. This is used + by the PCI Services to differentiate between local and + remote devices in a multi-domain system. + +PCI local domain bridge device/function +CONFIG_PCI_LOCAL_DEV + This PCI Services option sets the device/function value + for the local domain PCI-2-PCI bridge. This is used + by the PCI Services to differentiate between local and + remote devices in a multi-domain system. + +PCI PIRQ registers update +CONFIG_PCI_PIRQ_UPDATE + This PCI Services option will update the interrupt + control device's PIRQ registers with the local PCI + IRQ values if selected. If unsure, say Y. + +PCI Bus 0 device configuration +CONFIG_PCI_BUS_0_DEVICES + This PCI Services option enables the dynamic configuration of Bus 0 + PCI devices. If not enabled, then the PCIBIOS configuration of Bus 0 + PCI devices, except for PCI-to-PCI bridges, will be retained and used. + If your platform is Intel based, then you should say N here. If unsure, + say N. + +PCI Command Reg. - Special Cycle Recognition +CONFIG_PCI_COMMAND_SPECIAL + This PCI Services option will set the Special Cycle Recognition bit + in each device's command register. When set, the device will be + enabled to monitor PCI special cycles (if it's designed to monitor + special cycles). If not set, the device will ignore special cycles. + If unsure, say N. + +PCI Command Reg. - Memory Write/Invalidate +CONFIG_PCI_COMMAND_INVALIDATE + This PCI Services option will set the Memory Write and Invalidate + Enable bit in each device's command register. When set, the device + will be enabled to generate the memory write and invalidate command. + If not set, the device will use memory write commands instead. If + unsure, say N. + +PCI Command Reg. - Parity Error Response +CONFIG_PCI_COMMAND_PARITY + This PCI Services option will set the Parity Error Response bit + in each device's command register. When set, the device can report + parity errors. If not set, the device ignores parity errors. If + unsure, say N. + +PCI Command Reg. - Wait Cycle +CONFIG_PCI_COMMAND_WAIT + This PCI Services option will set the Wait Cycle Enable bit + in each device's command register. This bit controls whether + the device does address/data stepping. If unsure, say N. + +PCI Command Reg. - System Error +CONFIG_PCI_COMMAND_SERR + This PCI Services option will set the System Error Enable bit + in each device's command register. When set, the device can + drive the SERR# line. If unsure, say Y. + +PCI Cache Line Size +CONFIG_PCI_CACHE_LINE_SIZE + This PCI Services option will set the Cache Line Size value for + each device. For Intel-based platforms, this is normally 4. For + PowerPC-based platforms, this is normally 8. + +PCI Latency Timer +CONFIG_PCI_LATENCY_TIMER + This PCI Services option will set the Latency Timer value for + each device. For Intel-based platforms, this is normally 32. For + PowerPC-based platforms, this is normally 128. + +PCI Secondary Latency Timer +CONFIG_PCI_SEC_LATENCY_TIMER + This PCI Services option will set the Secondary Latency Timer value + for each bridge device. For Intel-based platforms, this is normally + 64. For PowerPC-based platforms, this is normally 128. + +PCI Bridge Ctl. - Parity Error Response +CONFIG_PCI_BRIDGE_CTL_PARITY + This PCI Services option will set the Parity Error Response bit + in each bridge device's bridge control register. When set, the + bridge takes the normal actions when a parity error is detected + on the secondary side. If not set, parity errors are ignored, but + the bridge must generate proper parity. If unsure, say N. + +PCI Bridge Ctl. - System Error +CONFIG_PCI_BRIDGE_CTL_SERR + This PCI Services option will set the System Error Enable bit + in each bridge device's bridge control register. When set, + detection of SERR# asserted on the secondary side causes the + bridge to assert SERR# on the primary side (but only if the + SERR# enable bit in the command register is set). If not set, + detection of SERR# on the secondary side is ignored. If unsure, + say N. + +PCI Bridge Ctl. - ISA Mode +CONFIG_PCI_BRIDGE_CTL_ISA_MODE + This PCI Services option will set the ISA Mode bit in each bridge + device's bridge control register. When set, the bridge only + recognizes I/O addresses within the usable ranges that do not + alias to an ISA range. If unsure, say N. + +PCI Bridge Ctl. - Master Abort Mode +CONFIG_PCI_BRIDGE_CTL_MASTER_ABORT + This PCI Services option will set the Master Abort Mode bit in + each bridge device's bridge control register. When set, if the + bridge experiences a master abort, it issues a target abort to + the initiating master. If not set, any reads that experiences + a master abort returns all ones; any writes complete normally + and the data is thrown away. If unsure, say N. + PCI quirks CONFIG_PCI_QUIRKS If you have a broken BIOS, it may fail to set up the PCI bus in a diff -u -r --new-file linux/arch/i386/config.in linux_mot/arch/i386/config.in --- linux/arch/i386/config.in Mon Apr 26 13:49:17 1999 +++ linux_mot/arch/i386/config.in Fri Jul 9 12:24:55 1999 @@ -63,6 +63,10 @@ if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then define_bool CONFIG_PCI_DIRECT y fi + bool ' PCI services' CONFIG_PCI_SERVICES + if [ "$CONFIG_PCI_SERVICES" = "y" ]; then + source drivers/pci/Config.in.5350 + fi bool ' PCI quirks' CONFIG_PCI_QUIRKS if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE diff -u -r --new-file linux/arch/ppc/config.in linux_mot/arch/ppc/config.in --- linux/arch/ppc/config.in Fri Jun 4 13:30:47 1999 +++ linux_mot/arch/ppc/config.in Tue Jun 22 12:53:49 1999 @@ -92,7 +92,6 @@ bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT -bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP if [ "$CONFIG_PREP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then bool 'PReP bootloader kernel arguments' CONFIG_CMDLINE_BOOL y if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then dep_tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND source drivers/sound/Config.in fi +endmenu + +mainmenu_option next_comment +comment 'Motorola Hot Swap Support' +bool 'PCI services' CONFIG_PCI_SERVICES +if [ "$CONFIG_PCI_SERVICES" = "y" ]; then + source drivers/pci/Config.in.cpx8216 +fi endmenu
mainmenu_option next_comment comment 'Kernel hacking' diff -u -r --new-file linux/drivers/pci/Config.in.cpv5000 linux_mot/drivers/pci/Config.in.cpv5000 --- linux/drivers/pci/Config.in.cpv5000 Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/Config.in.cpv5000 Tue Jun 8 10:36:04 1999 @@ -0,0 +1,127 @@ +# +# drivers/pci/Config.in.cpv5000 +# +# See drivers/pci/README.CONFIG for more information. +# + + +# +# Prompt user for number of nodes at each Bus Level. +# + +int ' PCI Bus Level 0 nodes' CONFIG_PCI_BUSLVL0_NODES 1 +int ' PCI Bus Level 1 nodes' CONFIG_PCI_BUSLVL1_NODES 1 +int ' PCI Bus Level 2 nodes' CONFIG_PCI_BUSLVL2_NODES 7 +int ' PCI Bus Level 3 nodes' CONFIG_PCI_BUSLVL3_NODES 1 + +# +# Prompt user for starting/ending address for PCI I/O space, +# PCI 20-bit memory space, PCI normal memory space, and PCI +# prefetch memory space. +# + +hex ' PCI I/O space starting address' CONFIG_PCI_IO_START 00007000 +hex ' PCI I/O space ending address' CONFIG_PCI_IO_END 0000dfff + +hex ' PCI 20-bit memory space starting address' CONFIG_PCI_MEM20_START 00000000 +hex ' PCI 20-bit memory space ending address' CONFIG_PCI_MEM20_END 000fffff + +hex ' PCI memory space starting address' CONFIG_PCI_MEM_START ff000000 +hex ' PCI memory space ending address' CONFIG_PCI_MEM_END ff8fffff + +hex ' PCI prefetch memory space starting address' CONFIG_PCI_MEMPF_START fe000000 +hex ' PCI prefetch memory space ending address' CONFIG_PCI_MEMPF_END feffffff + +# +# Prompt the user as to whether the system has an AGP +# PCI-2-PCI bridge or not. If it does have an AGP bridge, +# then prompt the user for the size of it's I/O, memory, +# and prefetchable memory space size. +# + +bool ' PCI AGP bridge' CONFIG_PCI_AGP_BRIDGE + +if [ "$CONFIG_PCI_AGP_BRIDGE" = "y" ]; then + hex ' PCI AGP bridge I/O space size' CONFIG_PCI_AGP_IO_SIZE 00001000 + hex ' PCI AGP bridge memory space size' CONFIG_PCI_AGP_MEM_SIZE 00100000 + hex ' PCI AGP prefetch memory space size' CONFIG_PCI_AGP_MEMPF_SIZE 00100000 +fi + +# +# Prompt user for local domain PCI IRQ values for PIRQA, PIRQB, +# PIRQC, and PIRQD. +# + +int ' PCI local IRQ A' CONFIG_PCI_LOCAL_PIRQA 5 +int ' PCI local IRQ B' CONFIG_PCI_LOCAL_PIRQB 9 +int ' PCI local IRQ C' CONFIG_PCI_LOCAL_PIRQC 5 +int ' PCI local IRQ D' CONFIG_PCI_LOCAL_PIRQD 10 + +# +# Prompt user as to whether the system is a multi-domain system +# or not. If so, then prompt the user for remote domain PCI IRQ +# values for PIRQA, PIRQB, PIRQC, and PIRQD. +# + +bool ' PCI multi-domain system' CONFIG_PCI_MULTI_DOMAIN + +if [ "$CONFIG_PCI_MULTI_DOMAIN" = "y" ]; then + int ' PCI remote IRQ A' CONFIG_PCI_REMOTE_PIRQA 5 + int ' PCI remote IRQ B' CONFIG_PCI_REMOTE_PIRQB 9 + int ' PCI remote IRQ C' CONFIG_PCI_REMOTE_PIRQC 5 + int ' PCI remote IRQ D' CONFIG_PCI_REMOTE_PIRQD 10 + hex ' PCI remote domain bridge device/function' CONFIG_PCI_REMOTE_DEV 000000c0 + hex ' PCI local domain bridge device/function' CONFIG_PCI_LOCAL_DEV 000000a0 +fi + +# +# Prompt user as well as whether to configure hardware +# interrupts or not. +# + +bool ' PCI PIRQ registers update' CONFIG_PCI_PIRQ_UPDATE + +# +# Prompt user as to whether to configure PCI bus 0 +# devices or not, excluding PCI-to-PCI bridges. +# + +bool ' PCI Bus 0 device configuration' CONFIG_PCI_BUS_0_DEVICES + +# +# Prompt user for devices' Command register bits. +# + +bool ' PCI Command Reg. - Special Cycle Recognition' CONFIG_PCI_COMMAND_SPECIAL +bool ' PCI Command Reg. - Memory Write/Invalidate' CONFIG_PCI_COMMAND_INVALIDATE +bool ' PCI Command Reg. - Parity Error Response' CONFIG_PCI_COMMAND_PARITY +bool ' PCI Command Reg. - Wait Cycle' CONFIG_PCI_COMMAND_WAIT +bool ' PCI Command Reg. - System Error' CONFIG_PCI_COMMAND_SERR + +# +# Prompt user for devices' Cache Line Size value. +# + +int ' PCI Cache Line Size' CONFIG_PCI_CACHE_LINE_SIZE 4 + +# +# Prompt user for devices' Latency Timer value. +# + +int ' PCI Latency Timer' CONFIG_PCI_LATENCY_TIMER 32 + +# +# Prompt user for bridges' Secondary Latency Timer value. +# + +int ' PCI Secondary Latency Timer' CONFIG_PCI_SEC_LATENCY_TIMER 64 + +# +# Prompt user for bridges' Bridge Control register bits. +# + +bool ' PCI Bridge Ctl. - Parity Error Response' CONFIG_PCI_BRIDGE_CTL_PARITY +bool ' PCI Bridge Ctl. - System Error' CONFIG_PCI_BRIDGE_CTL_SERR +bool ' PCI Bridge Ctl. - ISA Mode' CONFIG_PCI_BRIDGE_CTL_ISA_MODE +bool ' PCI Bridge Ctl. - Master Abort Mode' CONFIG_PCI_BRIDGE_CTL_MASTER_ABORT + diff -u -r --new-file linux/drivers/pci/Config.in.cpv5300 linux_mot/drivers/pci/Config.in.cpv5300 --- linux/drivers/pci/Config.in.cpv5300 Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/Config.in.cpv5300 Tue Jun 8 10:36:04 1999 @@ -0,0 +1,127 @@ +# +# drivers/pci/Config.in.cpv5300 +# +# See drivers/pci/README.CONFIG for more information. +# + + +# +# Prompt user for number of nodes at each Bus Level. +# + +int ' PCI Bus Level 0 nodes' CONFIG_PCI_BUSLVL0_NODES 1 +int ' PCI Bus Level 1 nodes' CONFIG_PCI_BUSLVL1_NODES 2 +int ' PCI Bus Level 2 nodes' CONFIG_PCI_BUSLVL2_NODES 7 +int ' PCI Bus Level 3 nodes' CONFIG_PCI_BUSLVL3_NODES 1 + +# +# Prompt user for starting/ending address for PCI I/O space, +# PCI 20-bit memory space, PCI normal memory space, and PCI +# prefetch memory space. +# + +hex ' PCI I/O space starting address' CONFIG_PCI_IO_START 00001000 +hex ' PCI I/O space ending address' CONFIG_PCI_IO_END 00007fff + +hex ' PCI 20-bit memory space starting address' CONFIG_PCI_MEM20_START 00000000 +hex ' PCI 20-bit memory space ending address' CONFIG_PCI_MEM20_END 000fffff + +hex ' PCI memory space starting address' CONFIG_PCI_MEM_START fc000000 +hex ' PCI memory space ending address' CONFIG_PCI_MEM_END feafffff + +hex ' PCI prefetch memory space starting address' CONFIG_PCI_MEMPF_START f5000000 +hex ' PCI prefetch memory space ending address' CONFIG_PCI_MEMPF_END f7ffffff + +# +# Prompt the user as to whether the system has an AGP +# PCI-2-PCI bridge or not. If it does have an AGP bridge, +# then prompt the user for the size of it's I/O, memory, +# and prefetchable memory space size. +# + +bool ' PCI AGP bridge' CONFIG_PCI_AGP_BRIDGE + +if [ "$CONFIG_PCI_AGP_BRIDGE" = "y" ]; then + hex ' PCI AGP bridge I/O space size' CONFIG_PCI_AGP_IO_SIZE 00000000 + hex ' PCI AGP bridge memory space size' CONFIG_PCI_AGP_MEM_SIZE 00100000 + hex ' PCI AGP prefetch memory space size' CONFIG_PCI_AGP_MEMPF_SIZE 01000000 +fi + +# +# Prompt user for local domain PCI IRQ values for PIRQA, PIRQB, +# PIRQC, and PIRQD. +# + +int ' PCI local IRQ A' CONFIG_PCI_LOCAL_PIRQA 5 +int ' PCI local IRQ B' CONFIG_PCI_LOCAL_PIRQB 9 +int ' PCI local IRQ C' CONFIG_PCI_LOCAL_PIRQC 5 +int ' PCI local IRQ D' CONFIG_PCI_LOCAL_PIRQD 10 + +# +# Prompt user as to whether the system is a multi-domain system +# or not. If so, then prompt the user for remote domain PCI IRQ +# values for PIRQA, PIRQB, PIRQC, and PIRQD. +# + +bool ' PCI multi-domain system' CONFIG_PCI_MULTI_DOMAIN + +if [ "$CONFIG_PCI_MULTI_DOMAIN" = "y" ]; then + int ' PCI remote IRQ A' CONFIG_PCI_REMOTE_PIRQA 5 + int ' PCI remote IRQ B' CONFIG_PCI_REMOTE_PIRQB 9 + int ' PCI remote IRQ C' CONFIG_PCI_REMOTE_PIRQC 5 + int ' PCI remote IRQ D' CONFIG_PCI_REMOTE_PIRQD 10 + hex ' PCI remote domain bridge device/function' CONFIG_PCI_REMOTE_DEV 000000c0 + hex ' PCI local domain bridge device/function' CONFIG_PCI_LOCAL_DEV 000000a0 +fi + +# +# Prompt user as well as whether to configure hardware +# interrupts or not. +# + +bool ' PCI PIRQ registers update' CONFIG_PCI_PIRQ_UPDATE + +# +# Prompt user as to whether to configure PCI bus 0 +# devices or not, excluding PCI-to-PCI bridges. +# + +bool ' PCI Bus 0 device configuration' CONFIG_PCI_BUS_0_DEVICES + +# +# Prompt user for devices' Command register bits. +# + +bool ' PCI Command Reg. - Special Cycle Recognition' CONFIG_PCI_COMMAND_SPECIAL +bool ' PCI Command Reg. - Memory Write/Invalidate' CONFIG_PCI_COMMAND_INVALIDATE +bool ' PCI Command Reg. - Parity Error Response' CONFIG_PCI_COMMAND_PARITY +bool ' PCI Command Reg. - Wait Cycle' CONFIG_PCI_COMMAND_WAIT +bool ' PCI Command Reg. - System Error' CONFIG_PCI_COMMAND_SERR + +# +# Prompt user for devices' Cache Line Size value. +# + +int ' PCI Cache Line Size' CONFIG_PCI_CACHE_LINE_SIZE 4 + +# +# Prompt user for devices' Latency Timer value. +# + +int ' PCI Latency Timer' CONFIG_PCI_LATENCY_TIMER 128 + +# +# Prompt user for bridges' Secondary Latency Timer value. +# + +int ' PCI Secondary Latency Timer' CONFIG_PCI_SEC_LATENCY_TIMER 64 + +# +# Prompt user for bridges' Bridge Control register bits. +# + +bool ' PCI Bridge Ctl. - Parity Error Response' CONFIG_PCI_BRIDGE_CTL_PARITY +bool ' PCI Bridge Ctl. - System Error' CONFIG_PCI_BRIDGE_CTL_SERR +bool ' PCI Bridge Ctl. - ISA Mode' CONFIG_PCI_BRIDGE_CTL_ISA_MODE +bool ' PCI Bridge Ctl. - Master Abort Mode' CONFIG_PCI_BRIDGE_CTL_MASTER_ABORT + diff -u -r --new-file linux/drivers/pci/Config.in.cpv5350 linux_mot/drivers/pci/Config.in.cpv5350 --- linux/drivers/pci/Config.in.cpv5350 Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/Config.in.cpv5350 Tue Jun 8 10:36:04 1999 @@ -0,0 +1,127 @@ +# +# drivers/pci/Config.in.cpv5350 +# +# See drivers/pci/README.CONFIG for more information. +# + + +# +# Prompt user for number of nodes at each Bus Level. +# + +int ' PCI Bus Level 0 nodes' CONFIG_PCI_BUSLVL0_NODES 1 +int ' PCI Bus Level 1 nodes' CONFIG_PCI_BUSLVL1_NODES 2 +int ' PCI Bus Level 2 nodes' CONFIG_PCI_BUSLVL2_NODES 7 +int ' PCI Bus Level 3 nodes' CONFIG_PCI_BUSLVL3_NODES 1 + +# +# Prompt user for starting/ending address for PCI I/O space, +# PCI 20-bit memory space, PCI normal memory space, and PCI +# prefetch memory space. +# + +hex ' PCI I/O space starting address' CONFIG_PCI_IO_START 00002000 +hex ' PCI I/O space ending address' CONFIG_PCI_IO_END 0000ffff + +hex ' PCI 20-bit memory space starting address' CONFIG_PCI_MEM20_START 00000000 +hex ' PCI 20-bit memory space ending address' CONFIG_PCI_MEM20_END 000fffff + +hex ' PCI memory space starting address' CONFIG_PCI_MEM_START f4300000 +hex ' PCI memory space ending address' CONFIG_PCI_MEM_END f4ffffff + +hex ' PCI prefetch memory space starting address' CONFIG_PCI_MEMPF_START f5000000 +hex ' PCI prefetch memory space ending address' CONFIG_PCI_MEMPF_END f7ffffff + +# +# Prompt the user as to whether the system has an AGP +# PCI-2-PCI bridge or not. If it does have an AGP bridge, +# then prompt the user for the size of it's I/O, memory, +# and prefetchable memory space size. +# + +bool ' PCI AGP bridge' CONFIG_PCI_AGP_BRIDGE + +if [ "$CONFIG_PCI_AGP_BRIDGE" = "y" ]; then + hex ' PCI AGP bridge I/O space size' CONFIG_PCI_AGP_IO_SIZE 00000000 + hex ' PCI AGP bridge memory space size' CONFIG_PCI_AGP_MEM_SIZE 00100000 + hex ' PCI AGP prefetch memory space size' CONFIG_PCI_AGP_MEMPF_SIZE 01000000 +fi + +# +# Prompt user for local domain PCI IRQ values for PIRQA, PIRQB, +# PIRQC, and PIRQD. +# + +int ' PCI local IRQ A' CONFIG_PCI_LOCAL_PIRQA 5 +int ' PCI local IRQ B' CONFIG_PCI_LOCAL_PIRQB 9 +int ' PCI local IRQ C' CONFIG_PCI_LOCAL_PIRQC 5 +int ' PCI local IRQ D' CONFIG_PCI_LOCAL_PIRQD 10 + +# +# Prompt user as to whether the system is a multi-domain system +# or not. If so, then prompt the user for remote domain PCI IRQ +# values for PIRQA, PIRQB, PIRQC, and PIRQD. +# + +bool ' PCI multi-domain system' CONFIG_PCI_MULTI_DOMAIN + +if [ "$CONFIG_PCI_MULTI_DOMAIN" = "y" ]; then + int ' PCI remote IRQ A' CONFIG_PCI_REMOTE_PIRQA 5 + int ' PCI remote IRQ B' CONFIG_PCI_REMOTE_PIRQB 9 + int ' PCI remote IRQ C' CONFIG_PCI_REMOTE_PIRQC 5 + int ' PCI remote IRQ D' CONFIG_PCI_REMOTE_PIRQD 10 + hex ' PCI remote domain bridge device/function' CONFIG_PCI_REMOTE_DEV 00000068 + hex ' PCI local domain bridge device/function' CONFIG_PCI_LOCAL_DEV 00000088 +fi + +# +# Prompt user as well as whether to configure hardware +# interrupts or not. +# + +bool ' PCI PIRQ registers update' CONFIG_PCI_PIRQ_UPDATE + +# +# Prompt user as to whether to configure PCI bus 0 +# devices or not, excluding PCI-to-PCI bridges. +# + +bool ' PCI Bus 0 device configuration' CONFIG_PCI_BUS_0_DEVICES + +# +# Prompt user for devices' Command register bits. +# + +bool ' PCI Command Reg. - Special Cycle Recognition' CONFIG_PCI_COMMAND_SPECIAL +bool ' PCI Command Reg. - Memory Write/Invalidate' CONFIG_PCI_COMMAND_INVALIDATE +bool ' PCI Command Reg. - Parity Error Response' CONFIG_PCI_COMMAND_PARITY +bool ' PCI Command Reg. - Wait Cycle' CONFIG_PCI_COMMAND_WAIT +bool ' PCI Command Reg. - System Error' CONFIG_PCI_COMMAND_SERR + +# +# Prompt user for devices' Cache Line Size value. +# + +int ' PCI Cache Line Size' CONFIG_PCI_CACHE_LINE_SIZE 4 + +# +# Prompt user for devices' Latency Timer value. +# + +int ' PCI Latency Timer' CONFIG_PCI_LATENCY_TIMER 64 + +# +# Prompt user for bridges' Secondary Latency Timer value. +# + +int ' PCI Secondary Latency Timer' CONFIG_PCI_SEC_LATENCY_TIMER 64 + +# +# Prompt user for bridges' Bridge Control register bits. +# + +bool ' PCI Bridge Ctl. - Parity Error Response' CONFIG_PCI_BRIDGE_CTL_PARITY +bool ' PCI Bridge Ctl. - System Error' CONFIG_PCI_BRIDGE_CTL_SERR +bool ' PCI Bridge Ctl. - ISA Mode' CONFIG_PCI_BRIDGE_CTL_ISA_MODE +bool ' PCI Bridge Ctl. - Master Abort Mode' CONFIG_PCI_BRIDGE_CTL_MASTER_ABORT + diff -u -r --new-file linux/drivers/pci/Config.in.cpx8216 linux_mot/drivers/pci/Config.in.cpx8216 --- linux/drivers/pci/Config.in.cpx8216 Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/Config.in.cpx8216 Tue Jun 8 10:36:04 1999 @@ -0,0 +1,127 @@ +# +# drivers/pci/Config.in.cpx8216 +# +# See drivers/pci/README.CONFIG for more information. +# + + +# +# Prompt user for number of nodes at each Bus Level. +# + +int ' PCI Bus Level 0 nodes' CONFIG_PCI_BUSLVL0_NODES 1 +int ' PCI Bus Level 1 nodes' CONFIG_PCI_BUSLVL1_NODES 2 +int ' PCI Bus Level 2 nodes' CONFIG_PCI_BUSLVL2_NODES 6 +int ' PCI Bus Level 3 nodes' CONFIG_PCI_BUSLVL3_NODES 1 + +# +# Prompt user for starting/ending address for PCI I/O space, +# PCI 20-bit memory space, PCI normal memory space, and PCI +# prefetch memory space. +# + +hex ' PCI I/O space starting address' CONFIG_PCI_IO_START 00001000 +hex ' PCI I/O space ending address' CONFIG_PCI_IO_END 0000efff + +hex ' PCI 20-bit memory space starting address' CONFIG_PCI_MEM20_START 00000000 +hex ' PCI 20-bit memory space ending address' CONFIG_PCI_MEM20_END 000fffff + +hex ' PCI memory space starting address' CONFIG_PCI_MEM_START 01000000 +hex ' PCI memory space ending address' CONFIG_PCI_MEM_END 3affffff + +hex ' PCI prefetch memory space starting address' CONFIG_PCI_MEMPF_START 00000000 +hex ' PCI prefetch memory space ending address' CONFIG_PCI_MEMPF_END ffffffff + +# +# Prompt the user as to whether the system has an AGP +# PCI-2-PCI bridge or not. If it does have an AGP bridge, +# then prompt the user for the size of it's I/O, memory, +# and prefetchable memory space size. +# + +bool ' PCI AGP bridge' CONFIG_PCI_AGP_BRIDGE + +if [ "$CONFIG_PCI_AGP_BRIDGE" = "y" ]; then + hex ' PCI AGP bridge I/O space size' CONFIG_PCI_AGP_IO_SIZE 00001000 + hex ' PCI AGP bridge memory space size' CONFIG_PCI_AGP_MEM_SIZE 00100000 + hex ' PCI AGP prefetch memory space size' CONFIG_PCI_AGP_MEMPF_SIZE 00100000 +fi + +# +# Prompt user for local domain PCI IRQ values for PIRQA, PIRQB, +# PIRQC, and PIRQD. +# + +int ' PCI local IRQ A' CONFIG_PCI_LOCAL_PIRQA 24 +int ' PCI local IRQ B' CONFIG_PCI_LOCAL_PIRQB 25 +int ' PCI local IRQ C' CONFIG_PCI_LOCAL_PIRQC 26 +int ' PCI local IRQ D' CONFIG_PCI_LOCAL_PIRQD 27 + +# +# Prompt user as to whether the system is a multi-domain system +# or not. If so, then prompt the user for remote domain PCI IRQ +# values for PIRQA, PIRQB, PIRQC, and PIRQD. +# + +bool ' PCI multi-domain system' CONFIG_PCI_MULTI_DOMAIN + +if [ "$CONFIG_PCI_MULTI_DOMAIN" = "y" ]; then + int ' PCI remote IRQ A' CONFIG_PCI_REMOTE_PIRQA 28 + int ' PCI remote IRQ B' CONFIG_PCI_REMOTE_PIRQB 29 + int ' PCI remote IRQ C' CONFIG_PCI_REMOTE_PIRQC 30 + int ' PCI remote IRQ D' CONFIG_PCI_REMOTE_PIRQD 31 + hex ' PCI remote domain bridge device/function' CONFIG_PCI_REMOTE_DEV 000000c0 + hex ' PCI local domain bridge device/function' CONFIG_PCI_LOCAL_DEV 000000a0 +fi + +# +# Prompt user as well as whether to configure hardware +# interrupts or not. +# + +bool ' PCI PIRQ registers update' CONFIG_PCI_PIRQ_UPDATE + +# +# Prompt user as to whether to configure PCI bus 0 +# devices or not, excluding PCI-to-PCI bridges. +# + +bool ' PCI Bus 0 device configuration' CONFIG_PCI_BUS_0_DEVICES + +# +# Prompt user for devices' Command register bits. +# + +bool ' PCI Command Reg. - Special Cycle Recognition' CONFIG_PCI_COMMAND_SPECIAL +bool ' PCI Command Reg. - Memory Write/Invalidate' CONFIG_PCI_COMMAND_INVALIDATE +bool ' PCI Command Reg. - Parity Error Response' CONFIG_PCI_COMMAND_PARITY +bool ' PCI Command Reg. - Wait Cycle' CONFIG_PCI_COMMAND_WAIT +bool ' PCI Command Reg. - System Error' CONFIG_PCI_COMMAND_SERR + +# +# Prompt user for devices' Cache Line Size value. +# + +int ' PCI Cache Line Size' CONFIG_PCI_CACHE_LINE_SIZE 8 + +# +# Prompt user for devices' Latency Timer value. +# + +int ' PCI Latency Timer' CONFIG_PCI_LATENCY_TIMER 128 + +# +# Prompt user for bridges' Secondary Latency Timer value. +# + +int ' PCI Secondary Latency Timer' CONFIG_PCI_SEC_LATENCY_TIMER 128 + +# +# Prompt user for bridges' Bridge Control register bits. +# + +bool ' PCI Bridge Ctl. - Parity Error Response' CONFIG_PCI_BRIDGE_CTL_PARITY +bool ' PCI Bridge Ctl. - System Error' CONFIG_PCI_BRIDGE_CTL_SERR +bool ' PCI Bridge Ctl. - ISA Mode' CONFIG_PCI_BRIDGE_CTL_ISA_MODE +bool ' PCI Bridge Ctl. - Master Abort Mode' CONFIG_PCI_BRIDGE_CTL_MASTER_ABORT + diff -u -r --new-file linux/drivers/pci/Config.in.default linux_mot/drivers/pci/Config.in.default --- linux/drivers/pci/Config.in.default Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/Config.in.default Tue Jun 8 10:36:04 1999 @@ -0,0 +1,127 @@ +# +# drivers/pci/Config.in.cpv5350 +# +# See drivers/pci/README.CONFIG for more information. +# + + +# +# Prompt user for number of nodes at each Bus Level. +# + +int ' PCI Bus Level 0 nodes' CONFIG_PCI_BUSLVL0_NODES 1 +int ' PCI Bus Level 1 nodes' CONFIG_PCI_BUSLVL1_NODES 2 +int ' PCI Bus Level 2 nodes' CONFIG_PCI_BUSLVL2_NODES 7 +int ' PCI Bus Level 3 nodes' CONFIG_PCI_BUSLVL3_NODES 1 + +# +# Prompt user for starting/ending address for PCI I/O space, +# PCI 20-bit memory space, PCI normal memory space, and PCI +# prefetch memory space. +# + +hex ' PCI I/O space starting address' CONFIG_PCI_IO_START 00002000 +hex ' PCI I/O space ending address' CONFIG_PCI_IO_END 0000ffff + +hex ' PCI 20-bit memory space starting address' CONFIG_PCI_MEM20_START 00000000 +hex ' PCI 20-bit memory space ending address' CONFIG_PCI_MEM20_END 000fffff + +hex ' PCI memory space starting address' CONFIG_PCI_MEM_START f4300000 +hex ' PCI memory space ending address' CONFIG_PCI_MEM_END f4ffffff + +hex ' PCI prefetch memory space starting address' CONFIG_PCI_MEMPF_START f5000000 +hex ' PCI prefetch memory space ending address' CONFIG_PCI_MEMPF_END f7ffffff + +# +# Prompt the user as to whether the system has an AGP +# PCI-2-PCI bridge or not. If it does have an AGP bridge, +# then prompt the user for the size of it's I/O, memory, +# and prefetchable memory space size. +# + +bool ' PCI AGP bridge' CONFIG_PCI_AGP_BRIDGE + +if [ "$CONFIG_PCI_AGP_BRIDGE" = "y" ]; then + hex ' PCI AGP bridge I/O space size' CONFIG_PCI_AGP_IO_SIZE 00001000 + hex ' PCI AGP bridge memory space size' CONFIG_PCI_AGP_MEM_SIZE 00100000 + hex ' PCI AGP prefetch memory space size' CONFIG_PCI_AGP_MEMPF_SIZE 00100000 +fi + +# +# Prompt user for local domain PCI IRQ values for PIRQA, PIRQB, +# PIRQC, and PIRQD. +# + +int ' PCI local IRQ A' CONFIG_PCI_LOCAL_PIRQA 5 +int ' PCI local IRQ B' CONFIG_PCI_LOCAL_PIRQB 9 +int ' PCI local IRQ C' CONFIG_PCI_LOCAL_PIRQC 5 +int ' PCI local IRQ D' CONFIG_PCI_LOCAL_PIRQD 10 + +# +# Prompt user as to whether the system is a multi-domain system +# or not. If so, then prompt the user for remote domain PCI IRQ +# values for PIRQA, PIRQB, PIRQC, and PIRQD. +# + +bool ' PCI multi-domain system' CONFIG_PCI_MULTI_DOMAIN + +if [ "$CONFIG_PCI_MULTI_DOMAIN" = "y" ]; then + int ' PCI remote IRQ A' CONFIG_PCI_REMOTE_PIRQA 5 + int ' PCI remote IRQ B' CONFIG_PCI_REMOTE_PIRQB 9 + int ' PCI remote IRQ C' CONFIG_PCI_REMOTE_PIRQC 5 + int ' PCI remote IRQ D' CONFIG_PCI_REMOTE_PIRQD 10 + hex ' PCI remote domain bridge device/function' CONFIG_PCI_REMOTE_DEV 000000c0 + hex ' PCI local domain bridge device/function' CONFIG_PCI_LOCAL_DEV 000000a0 +fi + +# +# Prompt user as well as whether to configure hardware +# interrupts or not. +# + +bool ' PCI PIRQ registers update' CONFIG_PCI_PIRQ_UPDATE + +# +# Prompt user as to whether to configure PCI bus 0 +# devices or not, excluding PCI-to-PCI bridges. +# + +bool ' PCI Bus 0 device configuration' CONFIG_PCI_BUS_0_DEVICES + +# +# Prompt user for devices' Command register bits. +# + +bool ' PCI Command Reg. - Special Cycle Recognition' CONFIG_PCI_COMMAND_SPECIAL +bool ' PCI Command Reg. - Memory Write/Invalidate' CONFIG_PCI_COMMAND_INVALIDATE +bool ' PCI Command Reg. - Parity Error Response' CONFIG_PCI_COMMAND_PARITY +bool ' PCI Command Reg. - Wait Cycle' CONFIG_PCI_COMMAND_WAIT +bool ' PCI Command Reg. - System Error' CONFIG_PCI_COMMAND_SERR + +# +# Prompt user for devices' Cache Line Size value. +# + +int ' PCI Cache Line Size' CONFIG_PCI_CACHE_LINE_SIZE 4 + +# +# Prompt user for devices' Latency Timer value. +# + +int ' PCI Latency Timer' CONFIG_PCI_LATENCY_TIMER 64 + +# +# Prompt user for bridges' Secondary Latency Timer value. +# + +int ' PCI Secondary Latency Timer' CONFIG_PCI_SEC_LATENCY_TIMER 64 + +# +# Prompt user for bridges' Bridge Control register bits. +# + +bool ' PCI Bridge Ctl. - Parity Error Response' CONFIG_PCI_BRIDGE_CTL_PARITY +bool ' PCI Bridge Ctl. - System Error' CONFIG_PCI_BRIDGE_CTL_SERR +bool ' PCI Bridge Ctl. - ISA Mode' CONFIG_PCI_BRIDGE_CTL_ISA_MODE +bool ' PCI Bridge Ctl. - Master Abort Mode' CONFIG_PCI_BRIDGE_CTL_MASTER_ABORT + diff -u -r --new-file linux/drivers/pci/Makefile linux_mot/drivers/pci/Makefile --- linux/drivers/pci/Makefile Tue Apr 28 22:41:33 1998 +++ linux_mot/drivers/pci/Makefile Tue Mar 16 22:11:21 1999 @@ -32,6 +32,10 @@ L_OBJS += quirks.o endif +ifdef CONFIG_PCI_SERVICES +L_OBJS += pci_alloc.o pci_conf.o pci_node.o pci_scan.o pci_hwints.o +endif + L_OBJS += compat.o include $(TOPDIR)/Rules.make diff -u -r --new-file linux/drivers/pci/README.CONFIG linux_mot/drivers/pci/README.CONFIG --- linux/drivers/pci/README.CONFIG Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/README.CONFIG Tue Jun 8 10:36:04 1999 @@ -0,0 +1,229 @@ +PCI Services Configuration Notes + +01 Feb 1998 + +Config.in defines a set of symbols with the form CONFIG_PCI_*. +These are the -native symbols-. Here is a description: + + CONFIG_PCI + + This is the master symbol. It controls whether the basic + PCI driver code is present or not. + + If the basic PCI driver code is not present, the PCI + Services code will not be present. + + + + CONFIG_PCI_SERVICES + + This is the PCI Services symbol. It determines whether the + PCI Services code is present or not. + + + + CONFIG_PCI_BUSLVL0_NODES + CONFIG_PCI_BUSLVL1_NODES + CONFIG_PCI_BUSLVL2_NODES + CONFIG_PCI_BUSLVL3_NODES + + These define the number of nodes (possible PCI-2-PCI bridge + devices, excluding AGP bridge devices) at each bus level. Bus + Level 0 usually has only one node, i.e. the primary Host Bridge. + Bus Level 2 usually only has one node, i.e. one PCI-to-PCI bridge. + Bus Level 3 usually has about 8 nodes, i.e. 8 CompactPCI slots + with one PCI-to-PCI bridge per slot/card. Bus Level 4 ususally + has only one node, i.e. one PCI-to-PCI bridge. + + + + CONFIG_PCI_IO_START + CONFIG_PCI_IO_END + + These define the starting and ending addresses for PCI I/O + space, respectively. If no PCI I/O space is needed/available, + then the starting address should be set to 00000000 and the + ending address set to ffffffff. + + + + CONFIG_PCI_MEM20_START + CONFIG_PCI_MEM20_END + + These define the starting and ending addresses for PCI 1M + memory space, respectively. + + + + CONFIG_PCI_MEM_START + CONFIG_PCI_MEM_END + + These define the starting and ending addresses for PCI normal + memory space, respectively. + + + + CONFIG_PCI_MEMPF_START + CONFIG_PCI_MEMPF_END + + These define the starting and ending addresses for PCI prefetch + memory space, respectively. If no PCI prefetch space is needed + or available, then the starting address should be set to 00000000 + and the ending address set to ffffffff. + + + + CONFIG_PCI_AGP_BRIDGE + + This is the PCI AGP PCI-2-PCI bridge symbol. It determines whether + an AGP bridge device exists or not in the system. + + + + CONFIG_PCI_AGP_IO_SIZE + CONFIG_PCI_AGP_MEM_SIZE + CONFIG_PCI_AGP_MEMPF_SIZE + + If an AGP PCI-2-PCI bridge device exists, then these define the + I/O, memory, and prefetchable memory size size, respectively, + needed by the PCI AGP PCI-2-PCI bridge device. + + + + CONFIG_PCI_LOCAL_PIRQA + CONFIG_PCI_LOCAL_PIRQB + CONFIG_PCI_LOCAL_PIRQC + CONFIG_PCI_LOCAL_PIRQD + + These define the PIRQ values for the system's interrupt + controller for local domain PCI INT A, INT B, INT C, and + INT D, respectively. + + + + CONFIG_PCI_MULTI_DOMAIN + + This defines whether there are multiple PCI domains in + the system or not. + + + + CONFIG_PCI_REMOTE_PIRQA + CONFIG_PCI_REMOTE_PIRQB + CONFIG_PCI_REMOTE_PIRQC + CONFIG_PCI_REMOTE_PIRQD + + If the system is a multi-domain system, these define the + PIRQ values for the system's interrupt controller for remote + domain PCI INT A, INT B, INT C, and INT D, respectively. + + + + CONFIG_PCI_REMOTE_DEV + CONFIG_PCI_LOCAL_DEV + + If the system is a multi-domain system, these define the + device/function values for the remote domain PCI bridge and + the local domain PCI bridge. + + + + CONFIG_PCI_PIRQ_UPDATE + + This definition determines whether the PIRQ registers for the + system's interrupt controller get updated or not with the + CONFIG_PCI_LOCAL_PIRQx value. + + + + CONFIG_PCI_BUS_0_DEVICES + + This is the PCI Bus 0 Devices Configuration symbol. It + determines whether Bus 0 devices are configured by the PCI + Services code or not. + + + + CONFIG_PCI_COMMAND_SPECIAL + + This definition, when defined, will set the Special Cycle + Recognition bit in each device's command register. + + + + CONFIG_PCI_COMMAND_INVALIDATE + + This definition, when defined, will set the Memory Write + and Invalidate Enable bit in each device's command register. + + + + CONFIG_PCI_COMMAND_PARITY + + This definition, when defined, will set the Parity Error + Response bit in each device's command register. + + + + CONFIG_PCI_COMMAND_WAIT + + This definition, when defined, will set the Wait Cycle + Enable bit in each device's command register. + + + + CONFIG_PCI_COMMAND_SERR + + This definition, when defined, will set the System Error + Enable bit in each device's command register. + + + + CONFIG_PCI_CACHE_LINE_SIZE + + This defines the Cache Line Size value for each device. + + + + CONFIG_PCI_LATENCY_TIMER + + This defines the Latency Timer value for each device. + + + + CONFIG_PCI_SEC_LATENCY_TIMER + + This defines the Secondary Latency Timer value for each + bridge device, except the primary Host Bridge. + + + + CONFIG_PCI_BRIDGE_CTL_PARITY + + This definition, when defined, will set the Parity Error + Response bit in each bridge device's bridge control register, + except the primary Host Bridge. + + + + CONFIG_PCI_BRIDGE_CTL_SERR + + This definition, when defined, will set the System Error + Enable bit in each bridge device's bridge control register, + except the primary Host Bridge. + + + + CONFIG_PCI_BRIDGE_CTL_ISA_MODE + + This definition, when defined, will set the ISA Mode + bit in each bridge device's bridge control register, + except the primary Host Bridge. + + + + CONFIG_PCI_BRIDGE_CTL_MASTER_ABORT + + This definition, when defined, will set the Master Abort + Mode bit in each bridge device's bridge control register, + except the primary Host Bridge. diff -u -r --new-file linux/drivers/pci/pci.c linux_mot/drivers/pci/pci.c --- linux/drivers/pci/pci.c Sun Mar 7 16:19:55 1999 +++ linux_mot/drivers/pci/pci.c Fri Jul 9 13:49:34 1999 @@ -16,6 +16,9 @@ #include <linux/string.h> #include <linux/init.h> #include <linux/malloc.h> +#ifdef CONFIG_PCI_SERVICES +#include <linux/pci_res.h> +#endif #include <asm/page.h> @@ -29,8 +32,12 @@ struct pci_bus pci_root; struct pci_dev *pci_devices = NULL; +#ifndef CONFIG_PCI_SERVICES static struct pci_dev **pci_last_dev_p = &pci_devices; static int pci_reverse __initdata = 0; +#else +int pci_reverse = 0; +#endif struct pci_dev * pci_find_slot(unsigned int bus, unsigned int devfn) @@ -156,6 +163,7 @@ } +#ifndef CONFIG_PCI_SERVICES __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus)) { unsigned int devfn, l, max, class; @@ -367,6 +375,7 @@ DBG("PCI: pci_scan_bus returning with max=%02x\n", max); return max; } +#endif /* CONFIG_PCI_SERVICES */ struct pci_bus * __init pci_scan_peer_bridge(int bus) { @@ -393,6 +402,8 @@ printk("PCI: Probing PCI hardware\n"); memset(&pci_root, 0, sizeof(pci_root)); + +#ifndef CONFIG_PCI_SERVICES pci_root.subordinate = pci_scan_bus(&pci_root); /* give BIOS a chance to apply platform specific fixes: */ @@ -405,6 +416,36 @@ #ifdef CONFIG_PROC_FS pci_proc_init(); #endif + +#else /* CONFIG_PCI_SERVICES */ + + if (pci_alloc_businit() != PCI_OK) + return; + +#ifdef CONFIG_PROC_FS + pci_proc_init(); +#endif + + pci_root.subordinate = pci_scan_bus(&pci_root); + +#ifdef CONFIG_PCI_PIRQ_UPDATE + if (pci_hwints_update_pirqs() != PCI_OK) + return; +#endif + +#ifdef CONFIG_VISWS + pci_other.number = 1; /* XXX unless bridge(s) on pci_root */ + pci_other.subordinate = pci_scan_bus(&pci_other); + pci_root.next = &pci_other; +#endif + + /* give BIOS a chance to apply platform specific fixes: */ + pcibios_fixup(); + +#ifdef CONFIG_PCI_QUIRKS + pci_quirks_init(); +#endif +#endif /* CONFIG_PCI_SERVICES */ } __initfunc(void pci_setup (char *str, int *ints)) diff -u -r --new-file linux/drivers/pci/pci_alloc.c linux_mot/drivers/pci/pci_alloc.c --- linux/drivers/pci/pci_alloc.c Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/pci_alloc.c Tue Jun 8 10:36:04 1999 @@ -0,0 +1,2664 @@ +/* +** PCI Bus Number/Device Resource Allocation +*/ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/pci_res.h> + +#include <asm/errno.h> +#include <asm/system.h> + + + + + +#if (CONFIG_PCI_BUSLVL0_NODES > 1) +/* +** PCI Host Bridge Structure +** +** This structure is used by the pci_alloc_hosts() +** functions only. +*/ + +struct pci_host +{ + unsigned int devfn; /* Host Device/Function Number */ + unsigned int number; /* Host Current Bus Number */ + unsigned int primary; /* Host New Primary Number */ + unsigned int secondary; /* Host New Secondary Number */ + unsigned int subordinate; /* Host New Subordinate Number */ +}; +#endif + + + + + +/* +** Array of maximum number of PCI bus nodes per +** PCI bus level. +*/ + +static int pci_max_busnodes_perlevel[MAX_PCI_LEVELS] = +{ + CONFIG_PCI_BUSLVL0_NODES, /* Bus Level 0 Nodes */ + CONFIG_PCI_BUSLVL1_NODES, /* Bus Level 1 Nodes */ + CONFIG_PCI_BUSLVL2_NODES, /* Bus Level 2 Nodes */ + CONFIG_PCI_BUSLVL3_NODES /* Bus Level 3 Nodes */ +}; + +/* +** Array of PCI bus numbers at each level. The +** array will be filled in as follows, with H0 +** denoting host node 0, H1 denoting host node 1, +** etc.: +** +** BusH0, Level 0 +** BusH0, BusH0,..., Level 1 +** BusH0, BusH0,..., Level 2 +** BusH0, BusH0,..., Level 3 +** +** BusH1, Level 0 +** BusH1, BusH1,..., Level 1 +** BusH1, BusH1,..., Level 2 +** BusH1, BusH1,..., Level 3 +** +** BusH2, Level 0 +** BusH2, BusH2,..., Level 1 +** BusH2, BusH2,..., Level 2 +** BusH2, BusH2,..., Level 3 +** +** For example, with two Bus Level 0 nodes, two Bus Level 1 +** nodes, four Bus Level 2 nodes, and two Bus Level 3 nodes, +** (for a maximum node count of 54) the array would look +** like this: +** +** { +** 0, Level 0 - Host 0 +** 1, 14, Level 1 +** 2, 5, 8, 11, Level 2 +** 15, 18, 21, 24, +** 3, 4, Level 3 +** 6, 7, +** 9, 10, +** 12, 13, +** 16, 17, +** 19, 20, +** 22, 23, +** 25, 26, +** +** 27, Level 0 - Host 1 +** 28, 41, Level 1 +** 29, 32, 35, 38, Level 2 +** 42, 45, 48, 51, +** 30, 31, Level 3 +** 33, 34, +** 36, 37, +** 39, 40, +** 43, 44, +** 46, 47, +** 49, 50, +** 52, 53 +** } +*/ + +static int pci_busnum_perlevel[MAX_PCI_NODES]; + +/* +** Array of indexes into the pci_busnum_perlevel[] +** array to provide the starting index of bus +** children. A -1 value indicates there are no +** child bus numbers. The input to this array is +** a bus number. +** +** For example, with two Bus Level 0 nodes, two Bus Level 1 +** nodes, four Bus Level 2 nodes, and two Bus Level 3 nodes, +** (for a maximum node count of 54) the array would look +** like this: +** +** { 1, *Bus 0 * - Host 0 +** 3, *Bus 1 * +** 11, *Bus 2 * +** -1, -1, *Buses 3-4 * +** 13, *Bus 5 * +** -1, -1, *Buses 6-7 * +** 15, *Bus 8 * +** -1, -1, *Buses 9-10 * +** 17, *Bus 11 * +** -1, -1, *Buses 12-13* +** 7, *Bus 14 * +** 19, *Bus 15 * +** -1, -1, *Buses 16-17* +** 21, *Bus 18 * +** -1, -1, *Buses 19-20* +** 23, *Bus 21 * +** -1, -1, *Buses 22-23* +** 25, *Bus 24 * +** -1, -1, *Buses 25-26* +** +** 28, *Bus 27 * - Host 1 +** 30, *Bus 28 * +** 38, *Bus 29 * +** -1, -1, *Buses 30-31* +** 40, *Bus 32 * +** -1, -1, *Buses 33-34* +** 42, *Bus 35 * +** -1, -1, *Buses 36-37* +** 44, *Bus 38 * +** -1, -1, *Buses 39-40* +** 34, *Bus 41 * +** 46, *Bus 42 * +** -1, -1, *Buses 43-44* +** 48, *Bus 45 * +** -1, -1, *Buses 46-47* +** 50, *Bus 48 * +** -1, -1, *Buses 49-50* +** 52, *Bus 51 * +** -1, -1 *Buses 52-53* +** } +*/ + +static int pci_busnum_indx[MAX_PCI_NODES]; + +/* +** Array of subordinate bus numbers for each bus. +** Leaf bus nodes just return their own bus number. +** The input to this array is a bus number. +** +** For example, with two Bus Level 0 nodes, two Bus Level 1 +** nodes, four Bus Level 2 nodes, and two Bus Level 3 nodes, +** (for a maximum node count of 54) the array would look +** like this: +** +** { +** * HOST 0 * +** 26, *Bus 0* 13, *Bus 1* 4, *Bus 2* 3, *Bus 3* +** 4, *Bus 4* 7, *Bus 5* 6, *Bus 6* 7, *Bus 7* +** 10, *Bus 8* 9, *Bus 9* 10, *Bus 10* 13, *Bus 11* +** 12, *Bus 12* 13, *Bus 13* 26, *Bus 14* 17, *Bus 15* +** 16, *Bus 16* 17, *Bus 17* 20, *Bus 18* 19, *Bus 19* +** 20, *Bus 20* 23, *Bus 21* 22, *Bus 22* 23, *Bus 23* +** 26, *Bus 24* 25, *Bus 25* 26, *Bus 26* +** +** * HOST 1 * +** 53, *Bus 27* 40, *Bus 28* 31, *Bus 29* 30, *Bus 30* +** 31, *Bus 31* 34, *Bus 32* 33, *Bus 33* 34, *Bus 34* +** 37, *Bus 35* 36, *Bus 36* 37, *Bus 37* 40, *Bus 38* +** 39, *Bus 39* 40, *Bus 40* 53, *Bus 41* 44, *Bus 42* +** 43, *Bus 43* 44, *Bus 44* 47, *Bus 45* 46, *Bus 46* +** 47, *Bus 47* 50, *Bus 48* 49, *Bus 49* 50, *Bus 50* +** 53, *Bus 51* 52, *Bus 52* 53 *Bus 53* +** } +*/ + +static int pci_sub_busnum[MAX_PCI_NODES]; + +/* +** Array to hold bus number allocation status, +** i.e. allocated (PCI_BUS_ALLOC) or not +** allocated (PCI_BUS_NOT_ALLOC). +*/ + +static unsigned char pci_busnum_alloc_status[MAX_PCI_NODES]; + +/* +** Array to hold amount (in bytes) of available PCI +** I/O space size per bus level. +*/ + +static unsigned long pci_bus_io_size[MAX_PCI_LEVELS]; + +/* +** Array to hold amount (in bytes) of available PCI +** memory space size per bus level. +*/ + +static unsigned long pci_bus_mem_size[MAX_PCI_LEVELS]; + +/* +** Array to hold amount (in bytes) of available PCI +** 20-bit memory space size per bus level. +*/ + +static unsigned long pci_bus_mem20_size[MAX_PCI_LEVELS]; + +/* +** Array to hold amount (in bytes) of available PCI +** prefetchable memory space size per bus level. +*/ + +static unsigned long pci_bus_mempf_size[MAX_PCI_LEVELS]; + +/* +** Some common error messages. +*/ + +static char no_bus_struct[] = "no PCI-2-PCI bridge bus structure"; + +static char no_dev_struct[] = "no PCI-2-PCI bridge device structure"; + + + + + +/* +** pci_alloc_businit - PCI Bus Number Allocation Initialization +** +** This is the PCI bus number allocation initialization +** function. It will fill in the pci_busnum_perlevel[], +** pci_busnum_indx[], and pci_sub_busnum[] arrays per the +** Bus Level 0 (CONFIG_PCI_BUSLVL0_NODES), +** Bus Level 1 (CONFIG_PCI_BUSLVL1_NODES), +** Bus Level 2 (CONFIG_PCI_BUSLVL2_NODES), and +** Bus Level 3 (CONFIG_PCI_BUSLVL3_NODES) +** node configuration parameters. +** +** It will then set the entries in the bus number +** allocation array, pci_busnum_alloc_status[], to "not +** allocated" (PCI_BUS_NOT_ALLOC). +** +** Finally, it will initialize the PCI I/O and memory +** space arrays (i.e. pci_bus_io_size[], pci_bus_mem_size[], +** pci_bus_mem20_size[], and pci_bus_mempf_size[]) for +** available space per node at each bus level. +*/ + +__initfunc(int pci_alloc_businit(void)) +{ + unsigned int busnum; /* Current Bus Number */ + + unsigned int l0sub; /* Bus Level 0 Subordinate Bus Number */ + unsigned int l0cnt; /* Bus Level 0 Count */ + unsigned int l0indx; /* Bus Level 0 Index */ + + unsigned int l1sub; /* Bus Level 1 Subordinate Bus Number */ + unsigned int l1cnt; /* Bus Level 1 Count */ + unsigned int l1indx; /* Bus Level 1 Index */ + + unsigned int l2sub; /* Bus Level 2 Subordinate Bus Number */ + unsigned int l2cnt; /* Bus Level 2 Count */ + unsigned int l2indx; /* Bus Level 2 Index */ + + unsigned int l3sub; /* Bus Level 3 Subordinate Bus Number */ + unsigned int l3cnt; /* Bus Level 3 Count */ + unsigned int l3indx; /* Bus Level 3 Index */ + + unsigned int indx; /* Just An Array Index */ + + unsigned long size; /* PCI Memory or I/O Space Size */ + + int ret_code; /* Function Return Code */ + + char *func; /* Function Name */ + + /* + ** Validate the maximum node count against the + ** maximum allowed for bus nodes. + */ + + func = "pci_alloc_businit"; + + ret_code = PCI_OK; + + if ((unsigned int)MAX_PCI_NODES == 0) + ret_code = PCI_ERR; + + if ((unsigned int)MAX_PCI_NODES > 255) + ret_code = PCI_ERR; + + if (ret_code != PCI_OK) + { + /* + ** Invalid number of bus nodes. + */ + + pci_kern_err(func, "invalid number of bus nodes"); + + return (PCI_ERR); + } + + /* + ** Validate the I/O space address definitions. + */ + + if ((unsigned int)CONFIG_PCI_IO_START > (unsigned int)CONFIG_PCI_IO_END) + ret_code = PCI_ERR; + + if (((unsigned int)CONFIG_PCI_IO_END - (unsigned int)CONFIG_PCI_IO_START) < 0x1000) + ret_code = PCI_ERR; + + if (ret_code != PCI_OK) + { + /* + ** Invalid I/O space addresses. + */ + + pci_kern_err(func, "invalid PCI I/O space addresses"); + + return (PCI_ERR); + } + + /* + ** Validate the 20-bit memory space address definitions. + */ + + if ((unsigned int)CONFIG_PCI_MEM20_END > 0x000fffff) + ret_code = PCI_ERR; + + if ((unsigned int)CONFIG_PCI_MEM20_START > (unsigned int)CONFIG_PCI_MEM20_END) + ret_code = PCI_ERR; + + if (ret_code != PCI_OK) + { + /* + ** Invalid 20-bit memory space addresses. + */ + + pci_kern_err(func, "invalid PCI 20-bit memory space addresses"); + + return (PCI_ERR); + } + + /* + ** Validate the memory space address definitions. + */ + + if ((unsigned int)CONFIG_PCI_MEM_START < (unsigned int)CONFIG_PCI_MEM20_END) + ret_code = PCI_ERR; + + if ((unsigned int)CONFIG_PCI_MEM_START > (unsigned int)CONFIG_PCI_MEM_END) + ret_code = PCI_ERR; + + if (((unsigned int)CONFIG_PCI_MEM_END - (unsigned int)CONFIG_PCI_MEM_START) < 0x00100000) + ret_code = PCI_ERR; + + if (ret_code != PCI_OK) + { + /* + ** Invalid memory space addresses. + */ + + pci_kern_err(func, "invalid PCI memory space addresses"); + + return (PCI_ERR); + } + + /* + ** Validate the prefetchable memory space address definitions. + */ + + if ((unsigned int)CONFIG_PCI_MEMPF_START > (unsigned int)CONFIG_PCI_MEMPF_END) + ret_code = PCI_ERR; + + if (((unsigned int)CONFIG_PCI_MEMPF_END - (unsigned int)CONFIG_PCI_MEMPF_START) < 0x00100000) + ret_code = PCI_ERR; + + if (ret_code != PCI_OK) + { + /* + ** Invalid prefetchable memory space addresses. + */ + + pci_kern_err(func, "invalid PCI prefetchable memory space addresses"); + + return (PCI_ERR); + } + +#ifdef CONFIG_PCI_AGP_BRIDGE + /* + ** Validate the I/O space size definition for the AGP bridge. + */ + + if ((unsigned int)CONFIG_PCI_AGP_IO_SIZE > ((unsigned int)(CONFIG_PCI_IO_END + 1) - (unsigned int)CONFIG_PCI_IO_START)) + { + /* + ** Invalid I/O space size for the AGP bridge. + */ + + pci_kern_err(func, "invalid I/O size for AGP bridge"); + + return (PCI_ERR); + } + + /* + ** Validate the memory space size definition for the AGP bridge. + */ + + if ((unsigned int)CONFIG_PCI_AGP_MEM_SIZE > ((unsigned int)(CONFIG_PCI_MEM_END + 1) - (unsigned int)CONFIG_PCI_MEM_START)) + { + /* + ** Invalid memory space size for the AGP bridge. + */ + + pci_kern_err(func, "invalid memory size for AGP bridge"); + + return (PCI_ERR); + } + + /* + ** Validate the prefetchable memory space size definition + ** for the AGP bridge. + */ + + if ((unsigned int)CONFIG_PCI_AGP_MEMPF_SIZE > ((unsigned int)(CONFIG_PCI_MEMPF_END + 1) - (unsigned int)CONFIG_PCI_MEMPF_START)) + { + /* + ** Invalid prefetchable memory space size for the AGP bridge. + */ + + pci_kern_err(func, "invalid prefetchable memory size for AGP bridge"); + + return (PCI_ERR); + } +#endif /* CONFIG_PCI_AGP_BRIDGE */ + + /* + ** Validate the PCI local IRQs. + */ + + if ((unsigned int)CONFIG_PCI_LOCAL_PIRQA > 255) + ret_code = PCI_ERR; + + if ((unsigned int)CONFIG_PCI_LOCAL_PIRQB > 255) + ret_code = PCI_ERR; + + if ((unsigned int)CONFIG_PCI_LOCAL_PIRQC > 255) + ret_code = PCI_ERR; + + if ((unsigned int)CONFIG_PCI_LOCAL_PIRQD > 255) + ret_code = PCI_ERR; + + if (ret_code != PCI_OK) + { + /* + ** Invalid PCI local IRQ. + */ + + pci_kern_err(func, "invalid PCI local IRQ"); + + return (PCI_ERR); + } + +#ifdef CONFIG_PCI_MULTI_DOMAIN + /* + ** Validate the PCI remote IRQs. + */ + + if ((unsigned int)CONFIG_PCI_REMOTE_PIRQA > 255) + ret_code = PCI_ERR; + + if ((unsigned int)CONFIG_PCI_REMOTE_PIRQB > 255) + ret_code = PCI_ERR; + + if ((unsigned int)CONFIG_PCI_REMOTE_PIRQC > 255) + ret_code = PCI_ERR; + + if ((unsigned int)CONFIG_PCI_REMOTE_PIRQD > 255) + ret_code = PCI_ERR; + + if (ret_code != PCI_OK) + { + /* + ** Invalid PCI remote IRQ. + */ + + pci_kern_err(func, "invalid PCI remote IRQ"); + + return (PCI_ERR); + } + + /* + ** Validate the PCI local domain bridge device/function. + */ + + if ((unsigned int)CONFIG_PCI_LOCAL_DEV == 0x00) + ret_code = PCI_ERR; + + if ((unsigned int)CONFIG_PCI_LOCAL_DEV > 0xff) + ret_code = PCI_ERR; + + if (ret_code != PCI_OK) + { + /* + ** Invalid PCI local domain bridge device/function. + */ + + pci_kern_err(func, "invalid PCI local domain bridge device/function"); + + return (PCI_ERR); + } + + /* + ** Validate the PCI remote domain bridge device/function. + */ + + if ((unsigned int)CONFIG_PCI_REMOTE_DEV == 0x00) + ret_code = PCI_ERR; + + if ((unsigned int)CONFIG_PCI_REMOTE_DEV > 0xff) + ret_code = PCI_ERR; + + if (ret_code != PCI_OK) + { + /* + ** Invalid PCI remote domain bridge device/function. + */ + + pci_kern_err(func, "invalid PCI remote domain bridge device/function"); + + return (PCI_ERR); + } +#endif /* CONFIG_PCI_MULTI_DOMAIN */ + + /* + ** Validate the device's cache line size. + */ + + if ((unsigned int)CONFIG_PCI_CACHE_LINE_SIZE > 255) + { + /* + ** Invalid cache line size. + */ + + pci_kern_err(func, "invalid device cache line size"); + + return (PCI_ERR); + } + + /* + ** Validate the devices' latency timer value. + */ + + if ((unsigned int)CONFIG_PCI_LATENCY_TIMER > 255) + { + /* + ** Invalid latency timer value. + */ + + pci_kern_err(func, "invalid device latency timer value"); + + return (PCI_ERR); + } + + /* + ** Validate the bridges' secondary latency timer value. + */ + + if ((unsigned int)CONFIG_PCI_SEC_LATENCY_TIMER > 255) + { + /* + ** Invalid secondary latency timer value. + */ + + pci_kern_err(func, "invalid bridge secondary latency timer value"); + + return (PCI_ERR); + } + + /* + ** Initialize the bus number, then loop + ** through the "Bus Level 0" node count. + */ + + busnum = 0; + + for (l0cnt = 0; l0cnt < CONFIG_PCI_BUSLVL0_NODES; ++l0cnt) + { + /* + ** Generate "Bus Level 0" index, then + ** set "Bus Level 0" node bus number in + ** the array. Also save it as the "Bus + ** Level 0" subordinate bus number. + */ + + l0indx = BUSLVL1_NODES * l0cnt; + l0indx += l0cnt; + + pci_busnum_perlevel[l0indx] = l0sub = busnum; + + /* + ** Generate starting "Bus Level 1" index. Then + ** set the starting index of bus children for + ** this bus number and increment the bus number. + */ + + l1indx = l0indx + 1; + + pci_busnum_indx[busnum++] = l1indx; + +#ifdef CONFIG_PCI_AGP_BRIDGE + /* + ** Reserve this bus number for the AGP PCI-2-PCI + ** bridge device. + */ + + ++busnum; +#endif + + /* + ** Loop through the "Bus Level 1" node count. + */ + + for (l1cnt = 0; l1cnt < CONFIG_PCI_BUSLVL1_NODES; ++l1cnt) + { + /* + ** Set "Bus Level 1" node bus number in + ** the array. Also save it as the "Bus + ** Level 1" subordinate bus number. + */ + + pci_busnum_perlevel[l1indx++] = l1sub = busnum; + + /* + ** Generate starting "Bus Level 2". Then + ** set the starting index of bus children + ** for this bus number and increment the + ** bus number. + */ + + l2indx = ( CONFIG_PCI_BUSLVL1_NODES + l0indx + 1 ); + l2indx += ( CONFIG_PCI_BUSLVL2_NODES * l1cnt ); + + pci_busnum_indx[busnum++] = l2indx; + + /* + ** Loop through the "Bus Level 2" node count. + */ + + for (l2cnt = 0; l2cnt < CONFIG_PCI_BUSLVL2_NODES; ++l2cnt) + { + /* + ** Set "Bus Level 2" node bus number in + ** the array. Also save it as the "Bus + ** Level 2" subordinate bus number. + */ + + pci_busnum_perlevel[l2indx++] = l2sub = busnum; + + /* + ** Generate starting "Bus Level 3". Then + ** set the starting index of bus children + ** for this bus number and increment the + ** bus number. + */ + + l3indx = ( CONFIG_PCI_BUSLVL1_NODES + l0indx + 1 ); + l3indx += ( CONFIG_PCI_BUSLVL1_NODES * CONFIG_PCI_BUSLVL2_NODES ); + + l3indx += ( CONFIG_PCI_BUSLVL2_NODES * CONFIG_PCI_BUSLVL3_NODES * l1cnt ); + l3indx += ( CONFIG_PCI_BUSLVL3_NODES * l2cnt ); + + pci_busnum_indx[busnum++] = l3indx; + + /* + ** Loop through the "Bus Level 3" node count. + */ + + for (l3cnt = 0; l3cnt < CONFIG_PCI_BUSLVL3_NODES; ++l3cnt) + { + /* + ** Set "Bus Level 3" node bus number in + ** the array. Also save it as the "Bus + ** Level 3" subordinate bus number. + */ + + pci_busnum_perlevel[l3indx++] = l3sub = busnum; + + /* + ** Set "no more bus children" flag in + ** the child index array and increment + ** the bus number. + */ + + pci_busnum_indx[busnum++] = -1; + + /* + ** Set "Bus Level 3" subordinate bus number. + ** This is a leaf node, thus it has the + ** same number. + */ + + pci_sub_busnum[l3sub] = l3sub; + } + + /* + ** Set "Bus Level 2" subordinate bus number. + */ + + pci_sub_busnum[l2sub] = busnum - 1; + } + + /* + ** Set "Bus Level 1" subordinate bus number. + */ + + pci_sub_busnum[l1sub] = busnum - 1; + } + + /* + ** Set "Bus Level 0" subordinate bus number. + */ + + pci_sub_busnum[l0sub] = busnum - 1; + } + + /* + ** Clear the bus number allocation array. + */ + + for (indx = 0; indx < MAX_PCI_NODES; ++indx) + pci_busnum_alloc_status[indx] = PCI_BUS_NOT_ALLOC; + + /* + ** Set bus level 0 PCI "spaces". This is based upon + ** the ending address minus the starting address, + ** divided by the maximum number of "Bus Level 0" + ** nodes. + */ + + pci_bus_io_size[0] = (CONFIG_PCI_IO_END + 1); + pci_bus_io_size[0] -= CONFIG_PCI_IO_START; +#ifdef CONFIG_PCI_AGP_BRIDGE + pci_bus_io_size[0] -= CONFIG_PCI_AGP_IO_SIZE; +#endif + pci_bus_io_size[0] /= CONFIG_PCI_BUSLVL0_NODES; + + pci_bus_mem_size[0] = (CONFIG_PCI_MEM_END + 1); + pci_bus_mem_size[0] -= CONFIG_PCI_MEM_START; +#ifdef CONFIG_PCI_AGP_BRIDGE + pci_bus_mem_size[0] -= CONFIG_PCI_AGP_MEM_SIZE; +#endif + pci_bus_mem_size[0] /= CONFIG_PCI_BUSLVL0_NODES; + + pci_bus_mempf_size[0] = (CONFIG_PCI_MEMPF_END + 1); + pci_bus_mempf_size[0] -= CONFIG_PCI_MEMPF_START; +#ifdef CONFIG_PCI_AGP_BRIDGE + pci_bus_mempf_size[0] -= CONFIG_PCI_AGP_MEMPF_SIZE; +#endif + pci_bus_mempf_size[0] /= CONFIG_PCI_BUSLVL0_NODES; + + pci_bus_mem20_size[0] = (CONFIG_PCI_MEM20_END + 1); + pci_bus_mem20_size[0] -= CONFIG_PCI_MEM20_START; + + /* + ** Set PCI "spaces" for each subordinate + ** bus level, i.e. "Bus Level 1" and on. + */ + + for (indx = 1; indx < MAX_PCI_LEVELS; ++indx) + { + /* + ** Clear the space sizes at this level. + */ + + pci_bus_io_size[indx] = 0; + pci_bus_mem_size[indx] = 0; + pci_bus_mem20_size[indx] = 0; + pci_bus_mempf_size[indx] = 0; + + /* + ** Check to see if we have any nodes + ** at this level. + */ + + if (pci_max_busnodes_perlevel[indx] != 0) + { + /* + ** Generate PCI I/O space. + */ + + size = pci_bus_io_size[indx - 1]; + size /= (pci_max_busnodes_perlevel[indx] * CONFIG_PCI_BUSLVL0_NODES); + + if (size > 0) + { + if (size > PCI_ALIGN_IO) + size &= ~(PCI_ALIGN_IO - 1); + else + size = PCI_ALIGN_IO; + + pci_bus_io_size[indx] = size; + } + + /* + ** Generate PCI memory space. + */ + + size = pci_bus_mem_size[indx - 1]; + size /= (pci_max_busnodes_perlevel[indx] * CONFIG_PCI_BUSLVL0_NODES); + + if (size > 0) + { + if (size > PCI_ALIGN_MEM) + size &= ~(PCI_ALIGN_MEM - 1); + else + size = PCI_ALIGN_MEM; + + pci_bus_mem_size[indx] = size; + } + + /* + ** Generate PCI prefetchable memory space. + */ + + size = pci_bus_mempf_size[indx - 1]; + size /= (pci_max_busnodes_perlevel[indx] * CONFIG_PCI_BUSLVL0_NODES); + + if (size > 0) + { + if (size > PCI_ALIGN_MEM) + size &= ~(PCI_ALIGN_MEM - 1); + else + size = PCI_ALIGN_MEM; + + pci_bus_mempf_size[indx] = size; + } + } + } + + /* + ** Everything is OK! + */ + + return (PCI_OK); +} + + + + + +#if (CONFIG_PCI_BUSLVL0_NODES > 1) +/* +** pci_alloc_hosts - Allocate Bus Nubmers For Host Bridge Devices +** +** This function will probe the PCI bus for Host +** Bridge Devices and reconfigure their bus numbers. +** This is done to prevent possible PCI bus access +** problems during the initial scanning. +*/ + +__initfunc(int pci_alloc_hosts(void)) +{ + struct pci_host *phost; /* Pointer to Current Host */ + + unsigned int number; /* Bus Number */ + + unsigned int devfn; /* Device/Function Number */ + + unsigned int buses; /* Buses Config. Register */ + + int numhosts; /* Number of Hosts */ + + struct pci_host hosts[CONFIG_PCI_BUSLVL0_NODES]; + + /* + ** Initialize the number of Host Bridge devices. Then + ** loop through each bus/dev to find Host Bridges. + */ + + numhosts = 0; + + for (number = 0; number <= MAX_PCI_BUS; ++number) + { + /* + ** Look for a Host Bridge on this bus. + */ + + if (pci_find_host(number, &devfn) == PCI_OK) + { + /* + ** We have found one. Check to see if we + ** have exceeded the number of configurable + ** Host Bridge devices. + */ + + if (numhosts >= CONFIG_PCI_BUSLVL0_NODES) + { + /* + ** We have exceeded the number of + ** configurable Host Bridge devices. + */ + + pci_kern_err("pci_alloc_hosts", "too many Host Bridge devices"); + + return (PCI_ERR); + } + + /* + ** Set the host structure pointer, along + ** with the device/function and current + ** bus number for the Host Bridge device. + */ + + phost = &(hosts[numhosts]); + + phost->devfn = devfn; + phost->number = number; + + /* + ** Set the new primray, secondary, and + ** subordinate bus numbers for the Host + ** Bridge device. + */ + + phost->primary = 0; + + if (numhosts != 0) + { + phost->primary = hosts[numhosts - 1].subordinate; + phost->primary += 1; + } + + phost->secondary = phost->primary; + phost->subordinate = pci_sub_busnum[phost->primary]; + + /* + ** Increment the number of hosts. + */ + + ++numhosts; + } + } + + /* + ** Starting with the last Host Bridge device, + ** reconfigure the bus numbers for each host. + */ + + while (numhosts-- > 0) + { + /* + ** Set the host structure pointer. Then + ** set the new Subordinate, Primary, and + ** Secondary bus numbers. + */ + + phost = &(hosts[numhosts]); + + buses = 0; + + buses = (buses << 8) | phost->subordinate; + buses = (buses << 8) | phost->secondary; + buses = (buses << 8) | phost->primary; + + pcibios_write_config_dword(phost->number, phost->devfn, PCI_PRIMARY_BUS, buses); + } + + /* + ** Everything is ok! + */ + + return (PCI_OK); +} +#endif /* (CONFIG_PCI_BUSLVL0_NODES > 1) */ + + + + + +#ifdef CONFIG_PCI_AGP_BRIDGE +/* +** pci_agp_bridge - Is Device An AGP Bridge +** +** This function will determine if the given device +** is an AGP bridge device (TRUE) or not (FALSE). +** +** NOTE: This list will need to be filled in with +** future AGP bridge devices. +*/ + +int +pci_agp_bridge(struct pci_bus *pbus, unsigned int devfn) +{ + unsigned short vendor; /* Vendor ID */ + + unsigned short device; /* Device ID */ + + int ret_code; /* Function Return Code */ + + /* + ** Clear the return code. Then, determine if the + ** device is an AGP bridge or not. + */ + + ret_code = FALSE; + + pcibios_read_config_word(pbus->number, devfn, PCI_VENDOR_ID, &vendor); + + pcibios_read_config_word(pbus->number, devfn, PCI_DEVICE_ID, &device); + + switch (vendor) + { + case PCI_VENDOR_ID_INTEL: + { + switch (device) + { + case 0x7181: /* Intel 440LX - 82443LX AGP bridge */ + case 0x7191: /* Intel 440BX/ZX - 82443BX/ZX AGP bridge */ + case 0x71a1: /* Intel 440GX - 82443GX AGP bridge */ + { + ret_code = TRUE; + break; + } + } + } + } + + /* + ** Return function result. + */ + + return (ret_code); +} +#endif /* CONFIG_PCI_AGP_BRIDGE */ + + + + + +/* +** pci_find_level - Determine PCI Bus Level +** +** This function will return the PCI bus level for +** the given bus node. +*/ + +static int +pci_find_level(struct pci_bus *pbus) +{ + struct pci_bus *nbus; /* Pointer To Next Bus Parent */ + + unsigned int bus_level; /* Current Bus Level */ + + /* + ** Initialize the bus level value, then + ** find the actual level of the bus node. + */ + + bus_level = 0; + + for (nbus = pbus->parent; nbus != (struct pci_bus *)NULL; nbus = nbus->parent) + ++bus_level; + + return (bus_level); +} + + + + + +/* +** pci_alloc_busnum - PCI Bus Number Allocation +** +** This is the PCI bus number allocation function. It will +** allocate secondary and subordinate bus numbers. +*/ + +int +pci_alloc_busnum(struct pci_bus *pbus, unsigned int devfn) +{ + unsigned long flags; /* CPU Interrupt Flags */ + + int bus_level; /* Current Bus Level */ + + int bus_num; /* Current Bus Number */ + + int child_indx; /* Child Bus Index */ + + int i; /* Just An Array Index */ + + char *func; /* Function Name */ + + /* + ** Initialize the bus number and the bus + ** level. Then check for bus level 0. + */ + + func = "pci_alloc_busnum"; + + bus_num = 0; + + bus_level = pci_find_level(pbus); + + if (bus_level == 0) + { + /* + ** We are at bus level 0. Disable interrupts + ** for now. + */ + + save_flags(flags); + + /* + ** Look for free bus numbers for this host node. + */ + + for (i = 0; i < pci_max_busnodes_perlevel[0]; ++i) + { + if (pci_busnum_alloc_status[bus_num] == PCI_BUS_NOT_ALLOC) + { + pci_busnum_alloc_status[bus_num] = PCI_BUS_ALLOC; + + break; + } + + bus_num += (pci_sub_busnum[bus_num] + 1); + } + + /* + ** Restore interrupts. + */ + + restore_flags(flags); + + /* + ** Did we find free host bus numbers at this + ** level? If not, then set the bus number + ** to indicate an error. + */ + + if (i < pci_max_busnodes_perlevel[0]) + { + /* + ** We have free host bus numbers. Hence, set + ** the primary, secondary, and subordinate + ** bus numbers. + */ + + pbus->number = bus_num; + pbus->primary = bus_num; + pbus->secondary = bus_num; + pbus->subordinate = pci_sub_busnum[bus_num]; + + return (PCI_OK); + } + + pci_kern_err(func, "couldn't find free bus numbers for the Host bridge"); + + return (-ENOSPC); + } + else + { +#ifdef CONFIG_PCI_AGP_BRIDGE + /* + ** Check to see if this is an AGP bridge device. + */ + + if (pci_agp_bridge(pbus->parent, devfn) == TRUE) + { + /* + ** Check the bus level. An AGP bridge device + ** can only be at bus level 1. + */ + + if (bus_level == 1) + { + /* + ** We are an AGP bridge device. Look for free + ** bus numbers for this bridge. + */ + + save_flags(flags); + + bus_num = (pbus->parent)->secondary + 1; + + if (pci_busnum_alloc_status[bus_num] == PCI_BUS_NOT_ALLOC) + { + /* + ** We have free AGP bridge bus numbers. Hence, + ** set the primary, secondary, and subordinate + ** bus numbers. + */ + + pci_busnum_alloc_status[bus_num] = PCI_BUS_ALLOC; + + restore_flags(flags); + + pbus->number = bus_num; + pbus->primary = (pbus->parent)->secondary; + pbus->secondary = bus_num; + pbus->subordinate = bus_num; + + return (PCI_OK); + } + + /* + ** Couldn't find free bus numbers for the + ** AGP bridge device. + */ + + restore_flags(flags); + + pci_kern_err(func, "couldn't find free bus numbers for the AGP bridge"); + + return (-ENOSPC); + } + + /* + ** An AGP bridge device is only allowed at + ** bus level 1. + */ + + pci_kern_err(func, "an AGP bridge is only allowed at bus level 1"); + + return (-EACCES); + } +#endif /* CONFIG_PCI_AGP_BRIDGE */ + + /* + ** Get the bus child index. If no child buses + ** at this level, then display an error message + ** and return an error. + */ + + child_indx = pci_busnum_indx[(pbus->parent)->secondary]; + + if (child_indx != -1) + { + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + /* + ** Initialize the bus number (not found), then + ** allocate the child bus. + */ + + bus_num = -1; + + for (i = 0; i < pci_max_busnodes_perlevel[bus_level]; ++i) + { + bus_num = pci_busnum_perlevel[child_indx + i]; + + if (pci_busnum_alloc_status[bus_num] == PCI_BUS_NOT_ALLOC) + { + pci_busnum_alloc_status[bus_num] = PCI_BUS_ALLOC; + + break; + } + + bus_num = -1; + } + + /* + ** Restore interrupts. + */ + + restore_flags(flags); + + /* + ** Did we find free bus numbers at this level? + */ + + if (bus_num != -1) + { + /* + ** Set the primary, secondary, and + ** subordinate bus numbers. + */ + + pbus->number = bus_num; + pbus->primary = (pbus->parent)->secondary; + pbus->secondary = bus_num; + pbus->subordinate = pci_sub_busnum[bus_num]; + + return (PCI_OK); + } + + pci_kern_err(func, "couldn't find free bus numbers"); + + return (-ENOSPC); + } + + pci_kern_err(func, "no child bus numbers"); + + return (-ENODEV); + } +} + + + + +/* +** pci_alloc_busres - PCI Bus Resource Allocation +** +** This is the PCI bus resource allocation function. It will +** allocate I/O and memory space from it's parent. 64-bit +** and prefetch memory space are not allocated for bus nodes. +*/ + +int +pci_alloc_busres(struct pci_bus *pbus) +{ + struct pci_res *pres; /* Pointer To Bus Resources */ + + struct pci_dev *pdev; /* Pointer to Bus Device */ + + unsigned long flags; /* CPU Interrupt Flags */ + + unsigned int indx; /* Resource Index */ + + unsigned int host_num; /* Host Number */ + + int bus_level; /* Current Bus Level */ + + char *func; /* Function Name */ + +#if (CONFIG_PCI_BUSLVL0_NODES > 1) + unsigned int bus_min; /* Host Minimum Bus Number */ + + unsigned int bus_max; /* Host Maximum Bus Number */ +#endif + + /* + ** First, set the function name for possible error + ** messages. Then, ensure that there is a P2P bridge + ** device structure associated with this bus. + */ + + func = "pci_alloc_busres"; + + pdev = pbus->self; + + if (pdev != (struct pci_dev *)NULL) + { + /* + ** Next, initialize the bus level and + ** host number. + */ + + bus_level = pci_find_level(pbus); + + host_num = 0; + +#if (CONFIG_PCI_BUSLVL0_NODES > 1) + /* + ** Initialize the starting minimum bus number. + ** Then loop until the host number is generated. + */ + + for (bus_min = 0; host_num < pci_max_busnodes_perlevel[0]; ++host_num) + { + /* + ** Set the maximum bus number, which is the + ** subordinate bus number for the minimum + ** bus number. + */ + + bus_max = pci_sub_busnum[bus_min]; + + /* + ** Compare the bus number against the minimum + ** and maximum numbers. If within range, then + ** we have found our host number. + */ + + if ((pbus->number >= bus_min) && (pbus->number <= bus_max)) + break; + + /* + ** Set the next minimum bus number, which is + ** just one more than the maximum number. + */ + + bus_min = bus_max + 1; + } +#endif + +#ifdef CONFIG_PCI_AGP_BRIDGE + /* + ** Does this bridge have a parent? If not, then it + ** is a host bridge and not a P2P bridge. + */ + + if (pbus->parent != (struct pci_bus *)NULL) + { + /* + ** Check to see if this is an AGP bridge device. + */ + + if (pci_agp_bridge(pbus->parent, pdev->devfn) == TRUE) + { + /* + ** Check the bus level. An AGP bridge device + ** can only be at bus level 1. + */ + + if (bus_level == 1) + { + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + /* + ** Set the AGP bridge device's PCI bus node resources + ** here starting with the PCI I/O space resource. + */ + + pres = &(pbus->resources[PCI_RES_INDX_IO]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_IO; + pres->align = PCI_ALIGN_IO; + pres->size = CONFIG_PCI_AGP_IO_SIZE; + + pres = &((pdev->bus)->resources[PCI_RES_INDX_IO]); + pres->size += CONFIG_PCI_AGP_IO_SIZE; + + /* + ** Set the PCI memory resource. + */ + + pres = &(pbus->resources[PCI_RES_INDX_MEM]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_MEM; + pres->align = PCI_ALIGN_MEM; + pres->size = CONFIG_PCI_AGP_MEM_SIZE; + + pres = &((pdev->bus)->resources[PCI_RES_INDX_MEM]); + pres->size += CONFIG_PCI_AGP_MEM_SIZE; + + /* + ** Clear the PCI 20-bit memory resource. + */ + + pres = &(pbus->resources[PCI_RES_INDX_MEM20]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_MEM20; + pres->align = PCI_ALIGN_MEM20; + pres->size = 0; + + /* + ** Set the PCI prefetchable memory resource. + */ + + pres = &(pbus->resources[PCI_RES_INDX_MEMPF]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_MEMPF; + pres->align = PCI_ALIGN_MEM; + pres->size = CONFIG_PCI_AGP_MEMPF_SIZE; + + pres = &((pdev->bus)->resources[PCI_RES_INDX_MEMPF]); + pres->size += CONFIG_PCI_AGP_MEMPF_SIZE; + + /* + ** Clear the child device resource link lists. + */ + + pbus->res_head_io = (struct pci_res *)NULL; + pbus->res_head_mem = (struct pci_res *)NULL; + pbus->res_head_mem20 = (struct pci_res *)NULL; + pbus->res_head_mempf = (struct pci_res *)NULL; + + /* + ** Restore interrupts. + */ + + restore_flags(flags); + + /* + ** For each node resource, allocate space. + */ + + for (indx = PCI_RES_INDX_IO; indx <= PCI_RES_INDX_MEMPF; ++indx) + { + /* + ** Set the resource pointer. Then, if there + ** is space available, allocate it from the + ** parent bus node and link it up. + */ + + pres = &(pbus->resources[indx]); + + if (pres->size != 0) + pci_alloc_devres(pdev, pres, indx); + } + + /* + ** Everything is A-OK. + */ + + return (PCI_OK); + } + + /* + ** An AGP bridge device is only allowed at + ** bus level 1. + */ + + pci_kern_err(func, "an AGP bridge is only allowed at bus level 1"); + + return (-EACCES); + } + } +#endif /* CONFIG_PCI_AGP_BRIDGE */ + + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + /* + ** Set the PCI bus node resources here + ** starting with the PCI I/O space resource. + */ + + pres = &(pbus->resources[PCI_RES_INDX_IO]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_IO; + pres->align = PCI_ALIGN_IO; + pres->size = pci_bus_io_size[bus_level]; + + if (bus_level == 0) + { + pres->baddr = pci_bus_io_size[0]; + pres->baddr *= host_num; + pres->baddr += CONFIG_PCI_IO_START; + +#ifdef CONFIG_PCI_AGP_BRIDGE + if (host_num != 0) + pres->baddr += CONFIG_PCI_AGP_IO_SIZE; +#endif + } + + /* + ** Set the PCI memory resource. + */ + + pres = &(pbus->resources[PCI_RES_INDX_MEM]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_MEM; + pres->align = PCI_ALIGN_MEM; + pres->size = pci_bus_mem_size[bus_level]; + + if (bus_level == 0) + { + pres->baddr = pci_bus_mem_size[0]; + pres->baddr *= host_num; + pres->baddr += CONFIG_PCI_MEM_START; + +#ifdef CONFIG_PCI_AGP_BRIDGE + if (host_num != 0) + pres->baddr += CONFIG_PCI_AGP_MEM_SIZE; +#endif + } + + /* + ** Set the PCI 20-bit memory resource. + */ + + pres = &(pbus->resources[PCI_RES_INDX_MEM20]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_MEM20; + pres->align = PCI_ALIGN_MEM20; + pres->size = pci_bus_mem20_size[bus_level]; + + if ((bus_level == 0) && (host_num == 0)) + pres->baddr = CONFIG_PCI_MEM20_START; + + /* + ** Set the PCI prefetchable memory resource. + */ + + pres = &(pbus->resources[PCI_RES_INDX_MEMPF]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_MEMPF; + pres->align = PCI_ALIGN_MEM; + pres->size = pci_bus_mempf_size[bus_level]; + + if (bus_level == 0) + { + pres->baddr = pci_bus_mempf_size[0]; + pres->baddr *= host_num; + pres->baddr += CONFIG_PCI_MEMPF_START; + +#ifdef CONFIG_PCI_AGP_BRIDGE + if (host_num != 0) + pres->baddr += CONFIG_PCI_AGP_MEMPF_SIZE; +#endif + } + + /* + ** Clear the child device resource link lists. + */ + + pbus->res_head_io = (struct pci_res *)NULL; + pbus->res_head_mem = (struct pci_res *)NULL; + pbus->res_head_mem20 = (struct pci_res *)NULL; + pbus->res_head_mempf = (struct pci_res *)NULL; + + /* + ** Restore interrupts. + */ + + restore_flags(flags); + + /* + ** Check for bus level 0 - it's a special case. + */ + + if (bus_level != 0) + { + /* + ** For each node resource, allocate space. + */ + + for (indx = PCI_RES_INDX_IO; indx <= PCI_RES_INDX_MEMPF; ++indx) + { + /* + ** Set the resource pointer. Then, if there + ** is space available, allocate it from the + ** parent bus node and link it up. + */ + + pres = &(pbus->resources[indx]); + + if (pres->size != 0) + pci_alloc_devres(pdev, pres, indx); + } + } + + /* + ** Everything is A-OK. + */ + + return (PCI_OK); + } + + /* + ** No P2P bridge device structure. + */ + + pci_kern_err(func, no_dev_struct); + + return (-ENOLINK); +} + + + + + +/* +** pci_alloc_devres - PCI Device Resource Allocation +** +** This is the PCI device resource allocation function. It will +** allocate I/O and memory space from it's parent bus. A linked +** list of resources is maintained in the parent node. There +** is one linked list per type. This routine searches on a +** first-fit basis for a gap to accomodate the new resource +** and inserts the resource into the list. +*/ + +int +pci_alloc_devres(struct pci_dev *pdev, struct pci_res *pres, int bar) +{ + struct pci_bus *pbus; /* Parent Bus Node Pointer */ + + struct pci_res *pres_bus; /* Bus Node Resource Pointer */ + + struct pci_res **pres_head; /* Resource Head Pointer */ + + struct pci_res *pres_cur; /* Current Resource Pointer */ + + struct pci_res *pres_nxt; /* Next Resource Pointer */ + + unsigned long flags; /* CPU Interrupt Flags */ + + unsigned long baddr; /* Base Address */ + + unsigned long align; /* Base Address Alignment */ + + long size; /* PCI Space Size */ + + long gap; /* PCI Space Gap */ + + char *func; /* Function Name */ + + char err_msg[256]; /* Error Message */ + + /* + ** First, set the function name for possible error + ** messages. Then, ensure that there is a P2P bridge + ** bus structure associated with this device. + */ + + func = "pci_alloc_devres"; + + pbus = pdev->bus; + + if (pbus != (struct pci_bus *)NULL) + { +#ifndef CONFIG_PCI_BUS_0_DEVICES + /* + ** Check for a Bus 0 non-P2P bridge device. + */ + + if ((pbus->number == 0) && ((pdev->class >> 8) != PCI_CLASS_BRIDGE_PCI)) + { + u32 base_reg; /* Base Address Register */ + + u8 base; /* Base Register Offset */ + + /* + ** Bus 0 non-PCI-2-PCI device resources are allocated + ** by the BIOS and are static. Hence, just read the + ** Base Address register then adjust the resource + ** type and pointers based upon the value in the + ** Base Address register. + */ + + base = PCI_BASE_ADDRESS_0 + (bar << 2); + + pci_read_config_dword(pdev, base, &base_reg); + + if ((base_reg & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) + { + /* + ** PCI I/O space. Set PCI I/O variables. + */ + + baddr = base_reg & PCI_BASE_ADDRESS_IO_MASK; + + pres_head = &(pbus->res_head_io); + + pres->type = PCI_RES_TYPE_IO; + pres->align = pres->size; + } + else + { + /* + ** PCI memory space. Set default PCI + ** memory variables. + */ + + baddr = base_reg & PCI_BASE_ADDRESS_MEM_MASK; + + pres_head = &(pbus->res_head_mem); + + pres->type = PCI_RES_TYPE_MEM; + pres->align = pres->size; + + /* + ** Is it a 64-bit address? + */ + + if ((base_reg & PCI_BASE_ADDRESS_MEM_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) + { +#if (BITS_PER_LONG == 64) + /* + ** 64-bit address. Thus, do a double read. + */ + + base = PCI_BASE_ADDRESS_0 + ((bar + 1) << 2); + + pci_read_config_dword(pdev, base, &base_reg); + + baddr = base_reg; + + baddr <<= 32; + + base = PCI_BASE_ADDRESS_0 + (bar << 2); + + pci_read_config_dword(pdev, base, &base_reg); + + baddr |= (base_reg & PCI_BASE_ADDRESS_MEM_MASK); +#else + printk("PCI: Unable to handle 64-bit address for device %02x:%02x\n", + pbus->number, pdev->devfn); +#endif + } + + /* + ** Prefetchable memory? + */ + + if ((base_reg & PCI_BASE_ADDRESS_MEM_PREFETCH) != 0) + { + /* + ** Prefetchable memory. Set PCI + ** prefetch memory variables. + */ + + pres_head = &(pbus->res_head_mempf); + + pres->type = PCI_RES_TYPE_MEMPF; + } + + /* + ** Check to see if address is below 1M. + */ + + if (baddr < 0x00100000UL) + { + /* + ** Below 1M. Set PCI memory variables. + */ + + pres_head = &(pbus->res_head_mem20); + + pres->type = PCI_RES_TYPE_MEM20; + } + } + + /* + ** Clear the next field and set the + ** Base Address register field. + */ + + pres->next = (struct pci_res *)NULL; + pres->baddr = baddr; + + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + /* + ** Is this the first entry into the list? + */ + + if ((*pres_head) == (struct pci_res *)NULL) + { + /* + ** This is the first entry in the linked list. + */ + + (*pres_head) = pres; + } + else + { + /* + ** Should this be the new first entry? + */ + + if ((*pres_head)->baddr > baddr) + { + /* + ** This is the new first entry in the linked list. + */ + + pres->next = (*pres_head); + + (*pres_head) = pres; + } + else + { + /* + ** Find the entry point in the list. + */ + + pres_cur = (*pres_head); + + while (pres_cur->next != (struct pci_res *)NULL) + { + if ((pres_cur->next)->baddr > baddr) + { + pres->next = pres_cur->next; + + break; + } + else + pres_cur = pres_cur->next; + } + + pres_cur->next = pres; + } + } + + /* + ** Restore interrupts and return. + */ + + restore_flags(flags); + + return (PCI_OK); + } +#endif /* CONFIG_PCI_BUS_0_DEVICES */ + + /* + ** Determine which resource we will + ** allocate from. + */ + + switch (pres->type) + { + /* + ** PCI I/O space + */ + + case PCI_RES_TYPE_IO: + { + pres_bus = &(pbus->resources[PCI_RES_INDX_IO]); + pres_head = &(pbus->res_head_io); + + break; + } + + /* + ** PCI memory space + */ + + case PCI_RES_TYPE_MEM: + { + pres_bus = &(pbus->resources[PCI_RES_INDX_MEM]); + pres_head = &(pbus->res_head_mem); + + break; + } + + /* + ** PCI 20-bit memory space + */ + + case PCI_RES_TYPE_MEM20: + { + pres_bus = &(pbus->resources[PCI_RES_INDX_MEM20]); + pres_head = &(pbus->res_head_mem20); + + break; + } + + /* + ** PCI prefetch memory space + */ + + case PCI_RES_TYPE_MEMPF: + { + pres_bus = &(pbus->resources[PCI_RES_INDX_MEMPF]); + pres_head = &(pbus->res_head_mempf); + + break; + } + + default: + { + /* + ** Return an error if the child/parent resource + ** structure is not setup properly. + */ + + sprintf(err_msg, "unknown resource type for bus %d, devfn = 0x%02x, bar = %d", + pbus->number, + pdev->devfn, + bar); + + pci_kern_err(func, err_msg); + + return (-EIDRM); + } + } + + /* + ** Get the PCI size and alignment values. + */ + + size = pres->size; + align = pres->align; + + /* + ** Use a first fit algorithim for allocating the bus + ** address. There are four possible scenarios when + ** inserting into the resource list. + ** + ** 1. This is a empty list and insertion happens at the + ** head. + ** + ** 2. This is a non empty list and there is room at the + ** head of the list. Insertion happens at the head + ** of the list. + ** + ** 3. This is a non empty list. Scanning for gaps in list + ** succeeds and insertion happens in between two + ** existing entries. + ** + ** 4. This is a non empty list. Scanning for gaps fails + ** and insertion happens at the end of the list. + ** + ** + ** Scenario 1: Empty list + */ + + save_flags(flags); + + if (*pres_head == (struct pci_res *)NULL) + { + /* + ** This is the first entry in the linked list. + */ + + pres->next = *pres_head; + + *pres_head = pres; + + /* + ** The bus address is the start address of the bus. + */ + + pres->baddr = PCI_ALIGN_ADDR(pres_bus->baddr, align); + + /* + ** Restore interrupts and return. + */ + + restore_flags(flags); + + return (PCI_OK); + } + + /* + ** Scenario 2: Non Empty list + ** + ** First, check if there is a gap at the head. + */ + + gap = (*pres_head)->baddr - pres_bus->baddr; + + if (gap > size) + { + /* + ** Do an address alignment first. + */ + + baddr = PCI_ALIGN_ADDR(pres_bus->baddr, align); + +#ifdef CONFIG_PCI_BRIDGE_CTL_ISA_MODE + /* + ** Is this an I/O address? + */ + + if (pres->type == PCI_RES_TYPE_IO) + { + /* + ** Check for an "unusable ISA address". If + ** so, then adjust for a "usable ISA address". + */ + + if ((baddr & 0x0300) != 0) + baddr = PCI_ALIGN_ADDR(baddr, 0x400); + } +#endif + + /* + ** Do a size check. + */ + + gap = (*pres_head)->baddr - baddr; + + if (gap > size) + { + /* + ** We can fit the resource at the head. Thus, + ** setup the linked list. + */ + + pres->next = (*pres_head); + + (*pres_head) = pres; + + /* + ** The bus address is the start address of the bus + */ + + pres->baddr = baddr; + + /* + ** Restore interrupts and return. + */ + + restore_flags(flags); + + return (PCI_OK); + } + } + + /* + ** Scenario 3: Non Empty list + ** + ** Check if there is a gap in the middle of the linked list. + */ + + pres_cur = (*pres_head); + pres_nxt = pres_cur->next; + + while (pres_nxt != (struct pci_res *)NULL) + { + /* + ** This check speeds up the search. + */ + + gap = pres_nxt->baddr - (pres_cur->baddr + pres_cur->size); + + if (gap > size ) + { + /* + ** Do an address alignment first. + */ + + baddr = pres_cur->baddr + pres_cur->size; + baddr = PCI_ALIGN_ADDR(baddr, align); + +#ifdef CONFIG_PCI_BRIDGE_CTL_ISA_MODE + /* + ** Is this an I/O address? + */ + + if (pres->type == PCI_RES_TYPE_IO) + { + /* + ** Check for an "unusable ISA address". If + ** so, then adjust for a "usable ISA address". + */ + + if ((baddr & 0x0300) != 0) + baddr = PCI_ALIGN_ADDR(baddr, 0x400); + } +#endif + + /* + ** Do a size check. + */ + + gap = pres_nxt->baddr - baddr; + + if (gap > size) + { + /* + ** This is an aligned fit. Setup the + ** linked list. + */ + + pres->next = pres_nxt; + pres_cur->next = pres; + + /* + ** The bus address is the start address + ** of the bus. + */ + + pres->baddr = baddr; + + /* + ** Restore interrupts and return. + */ + + restore_flags(flags); + + return (PCI_OK); + } + } + + /* + ** Try next one. + */ + + pres_cur = pres_nxt; + pres_nxt = pres_cur->next; + } + + /* + ** Scenario 4: Non Empty list + ** + ** Current pointer is at end of list. Thus, + ** append to the list. First, check here to + ** see that we are within bounds. If no space + ** to allocate the BAR resource, then return + ** an error. + */ + + baddr = pres_cur->baddr + pres_cur->size; + baddr = PCI_ALIGN_ADDR(baddr, align); + +#ifdef CONFIG_PCI_BRIDGE_CTL_ISA_MODE + /* + ** Is this an I/O address? + */ + + if (pres->type == PCI_RES_TYPE_IO) + { + /* + ** Check for an "unusable ISA address". If + ** so, then adjust for a "usable ISA address". + */ + + if ((baddr & 0x0300) != 0) + baddr = PCI_ALIGN_ADDR(baddr, 0x400); + } +#endif + + /* + ** Do a size check. + */ + + if ((baddr + size) <= (pres_bus->baddr + pres_bus->size)) + { + /* + ** Setup the linked list. + */ + + pres->next = pres_nxt; + pres_cur->next = pres; + + /* + ** The bus address is the start address of the bus. + */ + + pres->baddr = baddr; + + /* + ** Restore interrupts and return. + */ + + restore_flags(flags); + + return (PCI_OK); + } + + /* + ** Restore interrupts. Then display an error message + ** and return an errorj + */ + + restore_flags(flags); + + pci_kern_err(func, "no space left"); + + return (-ENOMEM); + } + + /* + ** No P2P bridge bus structure. + */ + + pci_kern_err(func, no_bus_struct); + + return (-ENOLINK); +} + + + + + +/* +** pci_free_busnum - Free PCI Bus Number +** +** This function will free the PCI bus number for +** re-allocation. +*/ + +int +pci_free_busnum(struct pci_bus *pbus) +{ + pci_busnum_alloc_status[pbus->secondary] = PCI_BUS_NOT_ALLOC; + + return (PCI_OK); +} + + + + + +/* +** pci_free_busres - Free PCI Bus Resources +** +** This is the free PCI bus resources function. It will +** re-allocate I/O and memory space to it's parent. +*/ + +int +pci_free_busres(struct pci_bus *pbus) +{ + struct pci_res *pres; /* Pointer To Bus Resources */ + + struct pci_dev *pdev; /* Pointer to Bus Device */ + + unsigned long flags; /* CPU Interrupt Flags */ + + unsigned int indx; /* Resource Index */ + + int bus_level; /* Current Bus Level */ + + char *func; /* Function Name */ + + /* + ** First, set the function name for possible error + ** messages. Then, initialize the bus level. + */ + + func = "pci_free_busres"; + + bus_level = pci_find_level(pbus); + + /* + ** Next, ensure child resources have been freed for + ** this bus. + */ + + if ((pbus->res_head_io == (struct pci_res *)NULL) + && (pbus->res_head_mem == (struct pci_res *)NULL) + && (pbus->res_head_mem20 == (struct pci_res *)NULL) + && (pbus->res_head_mempf == (struct pci_res *)NULL)) + { + /* + ** Check for bus level 0 - it's a special case. + */ + + if (bus_level != 0) + { + /* + ** Ensure that there is a P2P bridge device + ** structure associated with this bus. + */ + + pdev = pbus->self; + + if (pdev == (struct pci_dev *)NULL) + { + /* + ** No P2P bridge device structure. + */ + + pci_kern_err(func, no_dev_struct); + + return (-ENOLINK); + } + + /* + ** For each node resource, free the space. + */ + + for (indx = PCI_RES_INDX_IO; indx <= PCI_RES_INDX_MEMPF; ++indx) + { + /* + ** Set the resource pointer. Then, if space + ** has been allocated, free it back to the + ** parent bus node and link it up. + */ + + pres = &(pbus->resources[indx]); + + if (pres->size != 0) + pci_free_devres(pdev, pres); + } + } + + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + /* + ** Free PCI I/O resources. + */ + + pres = &(pbus->resources[PCI_RES_INDX_IO]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_NOTUSED; + pres->align = 0; + pres->size = 0; + pres->baddr = 0; + + /* + ** Free PCI memory resources. + */ + + pres = &(pbus->resources[PCI_RES_INDX_MEM]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_NOTUSED; + pres->align = 0; + pres->size = 0; + pres->baddr = 0; + + /* + ** Free PCI 20-bit memory resources. + */ + + pres = &(pbus->resources[PCI_RES_INDX_MEM20]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_NOTUSED; + pres->align = 0; + pres->size = 0; + pres->baddr = 0; + + /* + ** Free PCI prefetch memory resources. + */ + + pres = &(pbus->resources[PCI_RES_INDX_MEMPF]); + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_NOTUSED; + pres->align = 0; + pres->size = 0; + pres->baddr = 0; + + /* + ** Restore interrupts and return. + */ + + restore_flags(flags); + + return (PCI_OK); + } + + /* + ** Child resources not freed. + */ + + pci_kern_err(func, "child resources not freed"); + + return (-ENOTEMPTY); +} + + + + + +/* +** pci_free_devres - Free PCI Device Resources +** +** This is the free PCI device resources function. It will +** re-allocate I/O and memory space to it's parent. +*/ + +int +pci_free_devres(struct pci_dev *pdev, struct pci_res *pres) +{ + struct pci_bus *pbus; /* Parent Bus Node Pointer */ + + struct pci_res **pres_head; /* Resource Head Pointer */ + + struct pci_res *pres_prv; /* Previous Resource Pointer */ + + unsigned long flags; /* CPU Interrupt Flags */ + + char *func; /* Function Name */ + + /* + ** First, set the function name for possible error + ** messages. Then, ensure that there is a P2P bridge + ** bus structure associated with this device. + */ + + func = "pci_free_devres"; + + pbus = pdev->bus; + + if (pbus != (struct pci_bus *)NULL) + { + /* + ** Setup pointer to the device and parent resource + ** structures. Then determine which resource we will + ** allocate from. + */ + + switch (pres->type) + { + /* + ** PCI I/O space + */ + + case PCI_RES_TYPE_IO: + { + pres_head = &(pbus->res_head_io); + break; + } + + /* + ** PCI memory space + */ + + case PCI_RES_TYPE_MEM: + { + pres_head = &(pbus->res_head_mem); + break; + } + + /* + ** PCI 20-bit memory space + */ + + case PCI_RES_TYPE_MEM20: + { + pres_head = &(pbus->res_head_mem20); + break; + } + + /* + ** PCI prefetch memory space + */ + + case PCI_RES_TYPE_MEMPF: + { + pres_head = &(pbus->res_head_mempf); + break; + } + + /* + ** Unused PCI resource + */ + + case PCI_RES_TYPE_NOTUSED: + { + return (PCI_OK); + } + + default: + { + /* + ** Return an error if the child/parent resource + ** structure is not setup properly. + */ + + pci_kern_err(func, "child/parent resource structure not setup"); + + return (-EIDRM); + } + } + + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + /* + ** The resource being removed can be the first on the + ** list and, hence, has no previous entry. The other + ** case is that the the resource has a previous entry. + */ + + if (*pres_head == pres) + { + /* + ** Case 1: First on the list + ** + ** Make the next in the list the resource head. + */ + + *pres_head = pres->next; + } + else + { + /* + ** Case 2: search the linked list for the entry. + */ + + pres_prv = *pres_head; + + while ((pres_prv != (struct pci_res *)NULL) && (pres_prv->next != pres)) + pres_prv = pres_prv->next; + + /* + ** If we have come to the end of the list without + ** finding the resource, the list is somehow busted. + */ + + if (pres_prv == (struct pci_res *)NULL) + { + /* + ** Restore interrupts. + */ + + restore_flags(flags); + + pci_kern_err(func, "resource structure not on list"); + + return (-ENOENT); + } + + /* + ** We have found the previous entry, fix the + ** list pointers. + */ + + pres_prv->next = pres->next; + } + + /* + ** Clear the entry. + */ + + pres->next = (struct pci_res *)NULL; + pres->type = PCI_RES_TYPE_NOTUSED; + pres->align = 0; + pres->size = 0; + pres->baddr = 0; + + /* + ** Restore interrupts and return. + */ + + restore_flags(flags); + + return (PCI_OK); + } + + /* + ** No P2P bridge bus structure. + */ + + pci_kern_err(func, no_bus_struct); + + return (-ENOLINK); +} diff -u -r --new-file linux/drivers/pci/pci_conf.c linux_mot/drivers/pci/pci_conf.c --- linux/drivers/pci/pci_conf.c Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/pci_conf.c Tue Jun 8 10:36:04 1999 @@ -0,0 +1,1532 @@ +/* +** PCI Bus/Device Node Configuration +*/ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/pci_res.h> + +#include <asm/errno.h> + + + + + +/* +** +** pci_conf_int_line - Configure Interrupt Line Register +** +** This function will determine the correct value +** for the device's Interrupt Line and set it. +*/ + +static void +pci_conf_int_line(struct pci_dev *pdev) +{ + u8 irq; /* Interrupt Pin/Line */ + + /* + ** First, read the Interrupt Pin register. It is + ** used to determine the value for the Interrupt + ** Line register. + */ + + pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &irq); + + if (irq != PCI_INT_NONE) + { +#ifndef CONFIG_PCI_BUS_0_DEVICES + /* + ** Check for a non-bridge Bus 0 device. + */ + + if ((pdev->bus)->number == 0) + { + if ((pdev->class >> 8) != PCI_CLASS_BRIDGE_PCI) + { + /* + ** Bus 0 device resources are configured by + ** the BIOS and are static. Hence, just read + ** the Interrupt Line register and use it. + */ + + pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &irq); + + /* + ** Set the Interrupt Line register and save the + ** IRQ number in the device's structure and exit. + */ + + pdev->irq = irq; + + return; + } + } +#endif + + /* + ** Initialize the device's Interrupt Line register. + */ + + pci_hwints_getirq(pdev); + } +} + + + + + +/* +** +** pci_conf_cache - Configure Cache Line Size Register +** +** This function will write the Cache Line Size +** register with the configuration value. +*/ + +static void +pci_conf_cache(struct pci_dev *pdev) +{ +#ifndef CONFIG_PCI_BUS_0_DEVICES + /* + ** Check for a non-bridge Bus 0 device. If so, + ** just return because resources are configured + ** by the BIOS and are static. + */ + + if ((pdev->bus)->number == 0) + if ((pdev->class >> 8) != PCI_CLASS_BRIDGE_PCI) + return; +#endif + + /* + ** Set the Cache Line Size register + ** and exit. + */ + + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, CONFIG_PCI_CACHE_LINE_SIZE); +} + + + + + +/* +** +** pci_conf_latency - Configure Latency Timer Register +** +** This function will write the latency timer +** register with the configuratino value. +*/ + +static void +pci_conf_latency(struct pci_dev *pdev) +{ +#ifndef CONFIG_PCI_BUS_0_DEVICES + /* + ** Check for a non-bridge Bus 0 device. If so, + ** just return because resources are configured + ** by the BIOS and are static. + */ + + if ((pdev->bus)->number == 0) + if ((pdev->class >> 8) != PCI_CLASS_BRIDGE_PCI) + return; +#endif + + /* + ** Set the Latency Timer register + ** and exit. + */ + + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, CONFIG_PCI_LATENCY_TIMER); +} + + + + + +/* +** pci_conf_cmd - Configure Command Register +** +** This function will write the Command register +** for the device with the configured bits. +*/ + +static void +pci_conf_cmd(struct pci_dev *pdev, u16 cmd) +{ + unsigned int number; /* Bus Number */ + + unsigned int dev; /* Device Number */ + + unsigned int func; /* Function Number */ + + unsigned int devfn; /* Device/Function Number */ + + unsigned short status; /* Status Register */ + + unsigned short class; /* Class Code */ + + u16 tmpcmd; /* Temporary Command Register */ + + /* + ** First, read the current Command register. + */ + + pci_read_config_word(pdev, PCI_COMMAND, &tmpcmd); + + /* + ** Next, ensure the appropriate space enable bit(s) + ** are set in the Command register. + */ + + class = pdev->class >> 8; + + if ((class == PCI_CLASS_BRIDGE_HOST) || (class == PCI_CLASS_BRIDGE_PCI)) + cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + + /* + ** Next, check to see if we are a bus master. + */ + + if (pdev->master == TRUE) + { + /* + ** Set the Enable Master bit. + */ + + cmd |= PCI_COMMAND_MASTER; + + /* + ** Set the Fast Back-to-Back Enable bit. + ** Then, search each device on this bus, + ** i.e. device 0 to 31. + */ + + cmd |= PCI_COMMAND_FAST_BACK; + + number = (pdev->bus)->number; + + for (dev = 0; dev <= MAX_PCI_DEV; ++dev) + { + /* + ** Function loop, from 0 to 7. + */ + + for (func = 0; func <= MAX_PCI_FUNC; ++func) + { + /* + ** Generate the Device/Function number, + ** then read and validate the Device ID + ** word from the device's configuration + ** space. + */ + + devfn = PCI_DEVFN(dev, func); + + if (pci_valid_devid(number, devfn) == TRUE) + { + /* + ** Read the Status register and check the + ** Fast Back-to-Back Capable bit. If not + ** set, then clear the bit in the Command + ** register. + */ + + pcibios_read_config_word(number, devfn, PCI_STATUS, &status); + + if ((status & PCI_STATUS_FAST_BACK) == 0) + cmd &= ~PCI_COMMAND_FAST_BACK; + + /* + ** Check for a multi-function device. + */ + + if (pci_multi_func(number, devfn) == FALSE) + break; + } + } + } + } + +#ifdef CONFIG_PCI_COMMAND_SPECIAL + /* + ** Next, set the Special Cycle Recognition bit. + */ + + cmd |= PCI_COMMAND_SPECIAL; +#endif + +#ifdef CONFIG_PCI_COMMAND_INVALIDATE + /* + ** Next, set the Memory Write and Invalidate Enable bit. + */ + + cmd |= PCI_COMMAND_INVALIDATE; +#endif + +#ifdef CONFIG_PCI_COMMAND_PARITY + /* + ** Next, set the Parity Error Response bit. + */ + + cmd |= PCI_COMMAND_PARITY; +#endif + +#ifdef CONFIG_PCI_COMMAND_WAIT + /* + ** Next, set the Wait Cycle Enable bit. + */ + + cmd |= PCI_COMMAND_WAIT; +#endif + +#ifdef CONFIG_PCI_COMMAND_SERR + /* + ** Next, set the System Error Enable bit. + */ + + cmd |= PCI_COMMAND_SERR; +#endif + + /* + ** Finally, "or" in the new command bits and + ** write the Command register. + */ + + cmd |= tmpcmd; + + pci_write_config_word(pdev, PCI_COMMAND, cmd); +} + + + + + +/* +** pci_conf_bridge_ctl - Configure Bridge Control Register +** +** This function will write the Bridge Control +** register for the bridge device with the +** configured bits. +*/ + +static void +pci_conf_bridge_ctl(struct pci_dev *pdev) +{ + unsigned int number; /* Bus Number */ + + unsigned int dev; /* Device Number */ + + unsigned int func; /* Function Number */ + + unsigned int devfn; /* Device/Function Number */ + + unsigned short status; /* Status Register */ + + u16 brdgctl; /* Bridge Control Register */ + + /* + ** First, read and save the configuration + ** Bridge Control register. This will be + ** used later. + */ + + pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &brdgctl); + + /* + ** Next, set the Fast Back-to-Back Enable bit. + ** Then, search each device on the secondary + ** bus, i.e. device 0 to 31. + */ + + brdgctl |= PCI_BRIDGE_CTL_FAST_BACK; + + number = (pdev->bus)->secondary; + + for (dev = 0; dev <= MAX_PCI_DEV; ++dev) + { + /* + ** Function loop, from 0 to 7. + */ + + for (func = 0; func <= MAX_PCI_FUNC; ++func) + { + /* + ** Generate the Device/Function number, + ** then read and validate the Device ID + ** word from the device's configuration + ** space. + */ + + devfn = PCI_DEVFN(dev, func); + + if (pci_valid_devid(number, devfn) == TRUE) + { + /* + ** Read the Status register and check the + ** Fast Back-to-Back Capable bit. If not + ** set, then clear the bit in the Command + ** register. + */ + + pcibios_read_config_word(number, devfn, PCI_STATUS, &status); + + if ((status & PCI_STATUS_FAST_BACK) == 0) + brdgctl &= ~PCI_BRIDGE_CTL_FAST_BACK; + + /* + ** Check for a multi-function device. + */ + + if (pci_multi_func(number, devfn) == FALSE) + break; + } + } + } + +#ifdef CONFIG_PCI_BRIDGE_CTL_PARITY + /* + ** Next, set the Parity Error Response bit. + */ + + brdgctl |= PCI_BRIDGE_CTL_PARITY; +#endif + +#ifdef CONFIG_PCI_BRIDGE_CTL_SERR + /* + ** Next, set the System Error Enable bit. + */ + + brdgctl |= PCI_BRIDGE_CTL_SERR; +#endif + +#ifdef CONFIG_PCI_BRIDGE_CTL_ISA_MODE + /* + ** Next, set the ISA Mode bit. + */ + + brdgctl |= PCI_BRIDGE_CTL_NO_ISA; +#endif + +#ifdef CONFIG_PCI_BRIDGE_CTL_VGA + /* + ** Next, set the VGA Enable bit + */ + + brdgctl |= PCI_BRIDGE_CTL_VGA; +#endif + +#ifdef CONFIG_PCI_BRIDGE_CTL_MASTER_ABORT + /* + ** Next, set the Master Abort Mode bit. + */ + + brdgctl |= PCI_BRIDGE_CTL_MASTER_ABORT; +#endif + + /* + ** Finally, write the Bridge Control register. + */ + + pci_write_config_word(pdev, PCI_BRIDGE_CONTROL, brdgctl); +} + + + + + +/* +** +** pci_conf_bar - Determine Base Address Register Requirements +** +** This function will determine the memory or I/O space +** requirements for the given base address register. +** The PCI specification defines that after 0xffffffff +** is written to a base address register, the value +** read back will indicate the size requirements of the +** base address register. The highest bit set in register +** can be converted to the address space size. +*/ + +static unsigned int +pci_conf_bar(struct pci_dev *pdev, unsigned int bar, unsigned int *size) +{ + struct pci_bus *pbus; /* Device's Bus Structure Pointer */ + + unsigned int type; /* Resource Type */ + + u32 base_reg; /* Base Address Register */ + + u32 saved_base; /* Saved Base Address Register */ + + /* + ** Write all F's to the base address registers so we + ** can later read them back and determine what type + ** of space the device needs and how much space it + ** needs. + */ + + bar = PCI_BASE_ADDRESS_0 + (bar << 2); + + pci_read_config_dword(pdev, bar, &saved_base); + + pci_write_config_dword(pdev, bar, 0xffffffff); + + pci_read_config_dword(pdev, bar, &base_reg); + + pci_write_config_dword(pdev, bar, saved_base); + + /* + ** Set the resource type and clear the size. Then + ** check the base register value. If it is zero, + ** then the base register isn't implemented. If + ** it is 0xffffffff, then it may be broken. + */ + + type = PCI_RES_TYPE_NOTUSED; + + *size = 0; + + if ((base_reg != 0) && (base_reg != 0xffffffff)) + { + /* + ** Get the parent bus structure pointer. Then + ** see if the base register is an I/O type. + */ + + pbus = pdev->bus; + + if ((base_reg & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) + { + /* + ** It is an I/O base register. Set the + ** resource type if we have space. + */ + + if (pbus->resources[PCI_RES_INDX_IO].size != 0) + type = PCI_RES_TYPE_IO; + + /* + ** Adjust the base address register content + ** for the I/O bits and initialize the size. + */ + + base_reg >>= 2; + + *size = 4; + } + else + { + /* + ** It is a memory base register. Set the + ** default resource type to anywhere in + ** memory. + */ + + type = PCI_RES_TYPE_MEM; + + /* + ** Is it prefetchable memory? + */ + + if ((base_reg & PCI_BASE_ADDRESS_MEM_PREFETCH) != 0) + { + /* + ** Prefetchable memory. See if we can locate + ** in prefetchable memory space. + */ + + if (pbus->resources[PCI_RES_INDX_MEMPF].size != 0) + type = PCI_RES_TYPE_MEMPF; + } + + /* + ** Locate below 1MB? + */ + + if ((base_reg & PCI_BASE_ADDRESS_MEM_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_1M) + { + /* + ** Only bus 0 devices can be mapped below 1MB. + ** See if this device is a bus 0 device and if + ** we have 20-bit space. + */ + + if (pbus->number == 0) + if (pbus->resources[PCI_RES_INDX_MEM20].size != 0) + type = PCI_RES_TYPE_MEM20; + } + + /* + ** Adjust the base address register content + ** for the address memory bits and initialize + ** the size. + */ + + base_reg >>= 4; + + *size = 16; + } + + /* + ** Did we find a good resource type? + */ + + if (type != PCI_RES_TYPE_NOTUSED) + { + /* + ** Shift the base register right till a + ** 0 bit is seen. + */ + + while ((base_reg != 0) && ((base_reg & 1) == 0)) + { + /* + ** Multiply size by 2 and look for + ** another bit in the base address + ** register. + */ + + *size <<= 1; + + base_reg >>= 1; + } + } + } + + /* + ** Return the resource type. + */ + + return (type); +} + + + + + +/* +** pci_get_bars - Get Number Of BARs +** +** This function will return the number of Base +** Address registers for the device. +*/ + +int +pci_get_bars(struct pci_dev *pdev, int *num_bars) +{ + int ret_code; /* Function Return Code */ + + /* + ** Initialize the return code, then determine + ** the number of Base Address registers we need. + */ + + ret_code = PCI_OK; + + switch (pdev->hdr_type & 0x7f) + { + /* + ** Standard Header + */ + + case PCI_HEADER_TYPE_NORMAL: + { + *num_bars = 6; + break; + } + + /* + ** Bridge Header + */ + + case PCI_HEADER_TYPE_BRIDGE: + { + *num_bars = 2; + break; + } + + /* + ** CardBus Bridge Header + */ + + case PCI_HEADER_TYPE_CARDBUS: + { + *num_bars = 1; + break; + } + + /* + ** Anything else is an error. + */ + + default: + { + *num_bars = 0; + ret_code = -EFAULT; + } + } + + /* + ** Return the function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_conf_dev - Configure Device +** +** This function will configure memory and I/O space +** for each function on the given device. 64-bit +** memory and prefetch memory are not allocated at +** this time. +*/ + +int +pci_conf_dev(struct pci_dev *pdev) +{ + struct pci_res *pres; /* Resource Structure Pointer */ + + unsigned int num_bars; /* Maximum Number Of BARs */ + + unsigned int bar; /* Base Address Register */ + + unsigned int size; /* Size Requirement */ + + unsigned int type; /* PCI Space Type */ + + unsigned int barindx; /* Base Address Reg. Index */ + + u32 base_reg; /* Base Address Register */ + + u16 cmd; /* Command Register */ + + int ret_code; /* Function Return Code */ + + /* + ** First, set the Cache Line Size register. + */ + + pci_conf_cache(pdev); + + /* + ** Next, configure the Latency Timer register. + */ + + pci_conf_latency(pdev); + + /* + ** Next, configure the Interrupt Line register. + */ + + pci_conf_int_line(pdev); + + /* + ** Next, determine the number of Base Address + ** registers we need to allocate resources for. + */ + + ret_code = pci_get_bars(pdev, &num_bars); + + for (cmd = 0, bar = 0; (ret_code == PCI_OK) && (bar < num_bars); ++bar) + { + /* + ** Next, get the Base Address Register size and + ** resource type. If the size is zero or the + ** type is unknown, then we are done. + */ + + type = pci_conf_bar(pdev, bar, &size); + + if ((size != 0) && (type != PCI_RES_TYPE_NOTUSED)) + { + /* + ** Get the current resource structure pointer. + ** Then, set the resource type, size, and + ** alignment. Then based upon the resource + ** type, set command space access enable bit. + */ + + pres = &(pdev->resources[bar]); + + pres->type = type; + pres->size = size; + pres->align = size; + + if (type == PCI_RES_TYPE_IO) + { + /* + ** Set command I/O Access Enable. + */ + + cmd |= PCI_COMMAND_IO; + } + else + { + /* + ** Set command Memory Access Enable. + */ + + cmd |= PCI_COMMAND_MEMORY; + } + + /* + ** Allocate device memory and I/O resources. + */ + + ret_code = pci_alloc_devres(pdev, pres, bar); + + if (ret_code == PCI_OK) + { + /* + ** If allocated, then write the configuration + ** Base Address Register with the allocated + ** address value. Also, read it back and + ** place the value in the base address register + ** array. + */ + + barindx = PCI_BASE_ADDRESS_0 + (bar << 2); + + base_reg = pres->baddr; + + pci_write_config_dword(pdev, barindx, base_reg); + + pci_read_config_dword(pdev, barindx, &base_reg); + + pdev->base_address[bar] = base_reg; + + /* + ** Check for a 64-bit memory register. + */ + + if ((base_reg & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) + { + if ((base_reg & PCI_BASE_ADDRESS_MEM_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) + { + /* + ** It is a 64-bit register. Thus, write the next + ** configuration Base Address Register with the + ** allocated upper address value. Also, read it + ** back and place the value in the base address + ** register array. + */ + +#if (BITS_PER_LONG == 64) + base_reg = pres->baddr >> 32; +#else + base_reg = 0; +#endif + + barindx = PCI_BASE_ADDRESS_0 + (++bar << 2); + + pci_write_config_dword(pdev, barindx, base_reg); + + pci_read_config_dword(pdev, barindx, &base_reg); + + pdev->base_address[bar] = base_reg; + } + } + + } + } + } + + /* + ** Any errors? + */ + + if (ret_code == PCI_OK) + { + /* + ** Configure and write the Command register. + */ + + pci_conf_cmd(pdev, cmd); + + /* + ** If it is a bridge device, then configure and + ** write the Bridge Control register. + */ + + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + pci_conf_bridge_ctl(pdev); + } + + /* + ** Return the function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_conf_bus - Configure Bus +** +** This function will configure memory and I/O space +** for the bus and its devices. +*/ + +int +pci_conf_bus(struct pci_bus *pbus) +{ + struct pci_bus *child; /* Child Bus Pointer */ + + struct pci_dev *pdev; /* Device Structure Pointer */ + + struct pci_res *pres; /* Pointer To Bus Resources */ + + unsigned int class; /* Class Code */ + + u32 memupper; /* Base/Limit Upper 32 Bits */ + + u16 membaddr; /* Memory Base Address */ + + u16 membase; /* Memory Base register */ + + u16 iobaddr; /* I/O Base Address */ + + u8 iobase; /* I/O Base Register */ + + int ret_code; /* Function Return Code */ + + /* + ** First, allocate bus resources. + */ + + ret_code = pci_alloc_busres(pbus); + + if (ret_code == PCI_OK) + { + /* + ** Next, configure the bridge device first, + ** if it's an actual bridge. + */ + + pdev = pbus->self; + + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + { + /* + ** Set the Secondary Latency Timer register. + */ + + pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, CONFIG_PCI_SEC_LATENCY_TIMER); + + /* + ** Next, shut off PCI I/O space. Then read + ** the I/O Base register to be used later to + ** determine the bridge's I/O range. + */ + + pci_write_config_byte(pdev, PCI_IO_BASE, 0xf0); + + pci_write_config_byte(pdev, PCI_IO_LIMIT, 0x00); + + pci_write_config_word(pdev, PCI_IO_BASE_UPPER16, 0xffff); + + pci_write_config_word(pdev, PCI_IO_LIMIT_UPPER16, 0x0000); + + pci_read_config_byte(pdev, PCI_IO_BASE, &iobase); + + iobase &= PCI_IO_RANGE_TYPE_MASK; + + /* + ** Next, set the I/O resource pointer and see + ** if we have any allocated I/O space for this + ** this node. + */ + + pres = &(pbus->resources[PCI_RES_INDX_IO]); + + if (pres->size != 0) + { + /* + ** We have space. Is the I/O decoder correct? + */ + + if ((iobase == PCI_IO_RANGE_TYPE_16) || (iobase == PCI_IO_RANGE_TYPE_32)) + { + /* + ** Set the I/O Base register. + */ + + iobaddr = pres->baddr >> 8; + iobaddr &= 0xf0; + + pci_write_config_byte(pdev, PCI_IO_BASE, (u8)iobaddr); + + /* + ** Set the I/O Limit register. + */ + + iobaddr = (pres->baddr + (pres->size - 1)) >> 8; + iobaddr &= 0xf0; + + pci_write_config_byte(pdev, PCI_IO_LIMIT, (u8)iobaddr); + + /* + ** Next, see if we need to set the I/O + ** Base/Limit Upper 16 Bits registers. + */ + + if (iobase == PCI_IO_RANGE_TYPE_32) + { + /* + ** Set the I/O Base Upper 16-Bits + ** register. + */ + + iobaddr = pres->baddr >> 16; + iobaddr &= 0xffff; + + pci_write_config_word(pdev, PCI_IO_BASE_UPPER16, iobaddr); + + /* + ** Set the I/O Limit Upper 16-Bits + ** register. + */ + + iobaddr = (pres->baddr + (pres->size - 1)) >> 16; + iobaddr &= 0xffff; + + pci_write_config_word(pdev, PCI_IO_LIMIT_UPPER16, iobaddr); + } + } + } + + /* + ** Next, shut off PCI memory space. Then set + ** the memory resource pointer and see if we + ** have any allocated 32-bit memory for this + ** node. + */ + + pci_write_config_word(pdev, PCI_MEMORY_BASE, 0xffff); + + pci_write_config_word(pdev, PCI_MEMORY_LIMIT, 0x0000); + + pres = &(pbus->resources[PCI_RES_INDX_MEM]); + + if (pres->size != 0) + { + /* + ** Set the Memory Base register. + */ + + membaddr = pres->baddr >> 16; + membaddr &= 0xffff; + + pci_write_config_word(pdev, PCI_MEMORY_BASE, membaddr); + + /* + ** Set the Memory Limit register. + */ + + membaddr = (pres->baddr + (pres->size - 1)) >> 16; + membaddr &= 0xffff; + + pci_write_config_word(pdev, PCI_MEMORY_LIMIT, membaddr); + } + + /* + ** Next, shut off PCI prefetch memory space. Then + ** read the Prefetchable Memory Base register to + ** be used later to determine the bridge's prefetchable + ** memory range. + */ + + pci_write_config_word(pdev, PCI_PREF_MEMORY_BASE, 0xfff0); + + pci_write_config_word(pdev, PCI_PREF_MEMORY_LIMIT, 0x0000); + + pci_write_config_dword(pdev, PCI_PREF_BASE_UPPER32, 0xffffffff); + + pci_write_config_dword(pdev, PCI_PREF_LIMIT_UPPER32, 0x00000000); + + pci_read_config_word(pdev, PCI_PREF_MEMORY_BASE, &membase); + + membase &= PCI_PREF_RANGE_TYPE_MASK; + + /* + ** Next, set the prefetchable memory resource pointer + ** and see if we have any allocated prefetchable + ** memory for this node and if the memory decoder is + ** correct. + */ + + pres = &(pbus->resources[PCI_RES_INDX_MEMPF]); + + if (pres->size != 0) + { + /* + ** We have space. Is the memory decoder correct? + */ + + if ((membase == PCI_PREF_RANGE_TYPE_32) || (membase == PCI_PREF_RANGE_TYPE_64)) + { + /* + ** Set the Prefetchable Memory + ** Base register. + */ + + membaddr = pres->baddr >> 16; + membaddr &= 0xfff0; + + pci_write_config_word(pdev, PCI_PREF_MEMORY_BASE, membaddr); + + /* + ** Set the Prefetchable Memory + ** Limit register. + */ + + membaddr = (pres->baddr + (pres->size - 1)) >> 16; + membaddr &= 0xfff0; + + pci_write_config_word(pdev, PCI_PREF_MEMORY_LIMIT, membaddr); + + /* + ** Next, determine if we need to set the + ** Prefetchable Base/Limit Upper 32 Bits registers. + */ + + if (membase == PCI_PREF_RANGE_TYPE_64) + { + /* + ** Set the Prefetchable Base Upper 32-Bits + ** register. + */ + +#if (BITS_PER_LONG == 64) + memupper = pres->baddr >> 32; +#else + memupper = 0; +#endif + + pci_write_config_dword(pdev, PCI_PREF_BASE_UPPER32, memupper); + + /* + ** Set the Prefetchable Limit Upper 32-Bits + ** register. + */ + +#if (BITS_PER_LONG == 64) + memupper = (pres->baddr + (pres->size - 1)) >> 32; +#else + memupper = 0; +#endif + + pci_write_config_dword(pdev, PCI_PREF_LIMIT_UPPER32, memupper); + } + } + } + + /* + ** Finally, do the bridge device. + */ + + ret_code = pci_conf_dev(pbus->self); + } + + /* + ** Next, configure each bridge and it's devices + ** on the bus. + */ + + child = pbus->children; + + while ((ret_code == PCI_OK) && (child != (struct pci_bus *)NULL)) + { + /* + ** Allocate/assign memory and I/O space to + ** each bridge and it's devices on this bus. + */ + + ret_code = pci_conf_bus(child); + + /* + ** Do the next child. + */ + + child = child->next; + } + + /* + ** Next, configure each non-bridge device on + ** the bus. + */ + + pdev = pbus->devices; + + while ((ret_code == PCI_OK) && (pdev != (struct pci_dev *)NULL)) + { + /* + ** Get the device's class. If it's either a + ** Host Bridge or a PCI-2-PCI bridge, then + ** don't configure the device. + */ + + class = pdev->class >> 8; + + if (class != PCI_CLASS_BRIDGE_HOST) + if (class != PCI_CLASS_BRIDGE_PCI) + ret_code = pci_conf_dev(pdev); + + /* + ** Do the next sibling. + */ + + pdev = pdev->sibling; + } + } + + /* + ** Return the function result. + */ + + return (ret_code); +} + + + + + +/* +** +** pci_conf_display - Configure VGA and GFX Display Controllers +** +** This function is used to detect and set up all +** VGA-compatible controllers and non-VGA, GFX, +** controllers. +*/ + +void +pci_conf_display(void) +{ + struct pci_bus *pbus; /* Bus Structure Pointer */ + + struct pci_dev *pdev; /* Device Structure Pointer */ + + struct pci_dev *pdev_vga; /* VGA Device Structure Pointer */ + + struct pci_dev *pdev_gfx; /* GFX Device Structure Pointer */ + + unsigned int number; /* Bus Number */ + + unsigned int dev; /* Device Number */ + + unsigned int func; /* Function Number */ + + unsigned short class; /* Class Code */ + + u16 cnfgreg; /* Command/Bridge Control Register */ + + /* + ** Identify the VGA display device to be utilized + ** during initialization. This is accomplished by + ** first scanning the standard expansion bus (i.e., + ** ISA, EISA or Micro Channel). If the VGA display + ** device is found on the expansion bus, that display + ** is used during initialization and the display + ** configuration process has completed. + */ + + pdev_vga = (struct pci_dev *)NULL; + + pdev = pci_find_class((PCI_CLASS_BRIDGE_ISA << 8), (struct pci_dev *)NULL); + + if (pdev == (struct pci_dev *)NULL) + pdev = pci_find_class((PCI_CLASS_BRIDGE_EISA << 8), (struct pci_dev *)NULL); + + if (pdev == (struct pci_dev *)NULL) + pdev = pci_find_class((PCI_CLASS_BRIDGE_MC << 8), (struct pci_dev *)NULL); + + if (pdev != (struct pci_dev *)NULL) + { + /* + ** An expansion bus bridge device has been found. + ** Save the bridge's bus and device numbers. Then, + ** loop through each function looking for a VGA + ** display device. + */ + + number = (pdev->bus)->number; + + dev = PCI_SLOT(pdev->devfn); + + for (func = 0; func <= MAX_PCI_FUNC; ++func) + { + /* + ** Is there a device here? + */ + + pdev = pci_find_slot(number, PCI_DEVFN(dev, func)); + + if (pdev != (struct pci_dev *)NULL) + { + /* + ** Read the Class register and check for + ** a VGA-compatible controller. If so, + ** then we are done here. + */ + + if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) + return; + } + } + } + + /* + ** Is a VGA device on the PCI bus? + */ + + pdev_vga = pci_find_class((PCI_CLASS_DISPLAY_VGA << 8), (struct pci_dev *)NULL); + + if (pdev_vga != (struct pci_dev *)NULL) + { + /* + ** Set the I/O ENABLE and MEMORY ENABLE + ** bits in the device's command register + ** so it can respond to VGA accesses. + */ + + pci_read_config_word(pdev_vga, PCI_COMMAND, &cnfgreg); + + cnfgreg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + + pci_write_config_word(pdev_vga, PCI_COMMAND, cnfgreg); + + /* + ** Starting at the PCI bus number the VGA + ** display device is on, scan the PCI bus + ** hierarchy upstream (towards the Host Bridge). + */ + + pbus = pdev_vga->bus; + + while (pbus->primary != pbus->secondary) + { + /* + ** In each PCI-to-PCI bridge detected, set + ** the VGA ENABLE bit in its bridge control + ** register. + */ + + pci_read_config_word(pbus->self, PCI_BRIDGE_CONTROL, &cnfgreg); + + cnfgreg |= PCI_BRIDGE_CTL_VGA; + + pci_write_config_word(pbus->self, PCI_BRIDGE_CONTROL, cnfgreg); + + pbus = pbus->parent; + } + + /* + ** Starting at the PCI bus number the VGA + ** display device is on, scan the PCI buses + ** downstream (all buses subordinate to + ** this bus) looking for GFXs. + */ + + pdev_gfx = (struct pci_dev *)NULL; + + for (number = (pdev_vga->bus)->number; number <= (pdev_vga->bus)->subordinate; ++number) + { + /* + ** Device loop, from 0 to 31. + */ + + for (dev = 0; dev <= MAX_PCI_DEV; ++dev) + { + /* + ** Function loop, from 0 to 7. + */ + + for (func = 0; func <= MAX_PCI_FUNC; ++func) + { + /* + ** Is there a device here? + */ + + pdev = pci_find_slot(number, PCI_DEVFN(dev, func)); + + if (pdev != (struct pci_dev *)NULL) + { + /* + ** Read the Class register and + ** check for a GFX controller. + */ + + class = pdev->class >> 8; + + if (class != PCI_CLASS_DISPLAY_XGA) + if (class != PCI_CLASS_DISPLAY_OTHER) + pdev = (struct pci_dev *)NULL; + } + + /* + ** Was a GFX controller found? + */ + + if (pdev != (struct pci_dev *)NULL) + { + /* + ** Set the GFX device's I/O ENABLE + ** and VGA SNOOP ENABLE bits in the + ** device's command register. + */ + + pdev_gfx = pdev; + + pci_read_config_word(pdev_gfx, PCI_COMMAND, &cnfgreg); + + cnfgreg |= (PCI_COMMAND_IO | PCI_COMMAND_VGA_PALETTE); + + pci_write_config_word(pdev_gfx, PCI_COMMAND, cnfgreg); + + /* + ** Scan back upstream from the bus + ** the GFX is on towards the bus the + ** VGA display device resides on. + */ + + pbus = pdev_gfx->bus; + + while (pbus->number != (pdev_vga->bus)->number) + { + /* + ** At each PCI-to-PCI bridge + ** encountered, set the VGA + ** SNOOP ENABLE bit in the + ** bridge command register. + */ + + pci_read_config_word(pbus->self, PCI_COMMAND, &cnfgreg); + + cnfgreg |= PCI_COMMAND_VGA_PALETTE; + + pci_write_config_word(pbus->self, PCI_COMMAND, cnfgreg); + + pbus = pbus->parent; + } + } + } + } + } + + /* + ** Was a GFX controller found? + */ + + if (pdev_gfx != (struct pci_dev *)NULL) + { + /* + ** A GFX controller was found. Set the + ** the VGA SNOOP ENABLE bit in the VGA + ** display device's command register. + */ + + pci_read_config_word(pdev_vga, PCI_COMMAND, &cnfgreg); + + cnfgreg |= PCI_COMMAND_VGA_PALETTE; + + pci_write_config_word(pdev_vga, PCI_COMMAND, cnfgreg); + } + else + { + /* + ** A GFX controller was not found. Clear + ** the the VGA SNOOP ENABLE bit in the + ** VGA display device's command register. + */ + + pci_read_config_word(pdev_vga, PCI_COMMAND, &cnfgreg); + + cnfgreg &= ~PCI_COMMAND_VGA_PALETTE; + + pci_write_config_word(pdev_vga, PCI_COMMAND, cnfgreg); + } + + /* + ** We are done here. + */ + + return; + } + + /* + ** We have no VGA device on the PCI bus. Hence, + ** we need to reset the SNOOP ENABLE bits. + */ + + for (pdev = pci_devices; pdev != (struct pci_dev *)NULL; pdev = pdev->next) + { + /* + ** Read the Class register and check for + ** a GFX controller. + */ + + class = pdev->class >> 8; + + if ((class == PCI_CLASS_DISPLAY_XGA) || (class == PCI_CLASS_DISPLAY_OTHER)) + { + /* + ** It is a GFX controller. Hence, set + ** the the VGA SNOOP ENABLE bit in the + ** device's command register. + */ + + pci_read_config_word(pdev, PCI_COMMAND, &cnfgreg); + + cnfgreg |= PCI_COMMAND_VGA_PALETTE; + + pci_write_config_word(pdev, PCI_COMMAND, cnfgreg); + } + else + { + /* + ** It is not a GFX controller. Hence, clear + ** the the VGA SNOOP ENABLE bit in the device's + ** command register. + */ + + pci_read_config_word(pdev, PCI_COMMAND, &cnfgreg); + + cnfgreg &= ~PCI_COMMAND_VGA_PALETTE; + + pci_write_config_word(pdev, PCI_COMMAND, cnfgreg); + } + + /* + ** Is it a bridge device? + */ + + if (class == PCI_CLASS_BRIDGE_PCI) + { + /* + ** In each bridge detected, clear the VGA + ** ENABLE bit in its bridge control register. + */ + + pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &cnfgreg); + + cnfgreg &= ~PCI_BRIDGE_CTL_VGA; + + pci_write_config_word(pdev, PCI_BRIDGE_CONTROL, cnfgreg); + } + } +} diff -u -r --new-file linux/drivers/pci/pci_hwints.c linux_mot/drivers/pci/pci_hwints.c --- linux/drivers/pci/pci_hwints.c Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/pci_hwints.c Tue Jun 8 10:36:04 1999 @@ -0,0 +1,292 @@ +/* +** PCI PIRQ Hardware Interrupt Register Update +*/ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/pci_res.h> + + + + + +/* +** Array of PCI local domain IRQs. +*/ + +static unsigned int pci_localpirqs[4] = +{ + CONFIG_PCI_LOCAL_PIRQA, + CONFIG_PCI_LOCAL_PIRQB, + CONFIG_PCI_LOCAL_PIRQC, + CONFIG_PCI_LOCAL_PIRQD +}; + + +#ifdef CONFIG_PCI_MULTI_DOMAIN +/* +** Array of PCI remote domain IRQs. +*/ + +static unsigned int pci_remotepirqs[4] = +{ + CONFIG_PCI_REMOTE_PIRQA, + CONFIG_PCI_REMOTE_PIRQB, + CONFIG_PCI_REMOTE_PIRQC, + CONFIG_PCI_REMOTE_PIRQD +}; + +/* +** PCI remote domain bridge device/function. +*/ + +static unsigned int pci_remotedev = CONFIG_PCI_REMOTE_DEV; +#endif + + + + + +#ifdef CONFIG_PCI_PIRQ_UPDATE +/* +** Mapping from PCI vendor/device ID pairs to PIRQ +** hardware interrupt register update function types +** and arguments +*/ + +typedef int (*pci_hwints_handler)(struct pci_dev *); + +struct pci_hwints_info +{ + unsigned short vendor; /* Vendor ID */ + unsigned short device; /* Device ID */ + pci_hwints_handler handler; /* Function/Handler */ +}; + + + + + +/* +** +** set_82371 - Intel 82371 ISA Bridge +** +** This function will write the IRQ value to the +** i82371SB's PIIX3 ISA PIRQ register. +*/ + +__initfunc(static int set_82371(struct pci_dev *pdev)) +{ + unsigned int intnum; /* PIRQ Interrupt Number */ + + u8 offset; /* PIRQ Register Offset */ + + u8 irq; /* Interrupt Pin/Line */ + + /* + ** Loop through each one. + */ + + for (intnum = 0; intnum < 4; ++intnum) + { + /* + ** First, read the current IRQ value from the + ** i82371's PIRQ PCI configuration register. + ** Check to see if it has been initialized by + ** the BIOS or not. If it has, then save the + ** PIRQ value in the PIRQ array. + */ + + offset = 0x60 + intnum; + + pci_read_config_byte(pdev, offset, &irq); + + if ((irq & 0x80) != 0) + { + /* + ** This PIRQ PCI configuration register has + ** not been initialized. Hence, write the + ** IRQ value to the i82371's PIRQ PCI + ** configuration register. + */ + + irq = pci_pirqs[intnum]; + + pci_write_config_byte(pdev, offset, 0x80); + + pci_write_config_byte(pdev, offset, irq); + } + else + pci_pirqs[intnum] = irq; + } + + /* + ** Everything is OK! + */ + + return (PCI_OK); +} + + + + + +/* +** Table of devices and handlers. +*/ + +static struct pci_hwints_info pci_hwints_list[] __initdata = +{ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, set_82371 }, + { 0xffff, 0xffff, NULL }, +}; + + + + + +/* +** +** pci_hwints_update_pirqs - Update PIRQ hardware interrupt register +** +** This function will call a function/handler to write +** the given IRQ value to the PIRQ hardware interrupt +** register for the selected devices. +*/ + +__initfunc(int pci_hwints_update_pirqs(void)) +{ + struct pci_dev *pdev; /* Device Structure Pointer */ + + struct pci_hwints_info *pinfo; /* Hardware Info Structure Pointer */ + + /* + ** Go through each vendor/device in the list + ** of hardware interrupt handlers. + */ + + for (pinfo = pci_hwints_list; pinfo->vendor != 0xffff; ++pinfo) + { + /* + ** Compare the vendor and device IDs. If the same, then + ** call the hardware interrupt update handler. + */ + + pdev = pci_find_device(pinfo->vendor, pinfo->device, (struct pci_dev *)NULL); + if (pdev != (struct pci_dev *)NULL) + if (pinfo->handler(pdev) != PCI_OK) + return (PCI_ERR); + } + + /* + ** Everything is OK! + */ + + return (PCI_OK); +} +#endif + + + + + +/* +** +** pci_hwints_getirq - Return IRQ value +** +** This function will return the IRQ value for the +** given device. It will also update the Interrupt +** Line register of the device with the value. +*/ + +void +pci_hwints_getirq(struct pci_dev *pdev) +{ + struct pci_bus *pbus; /* Parent Bus Structure Pointer */ + + unsigned int devnum; /* Accumulated Device Number */ + + unsigned int irq; /* IRQ Value */ + + /* + ** Device Interrupt Line register initialization. + */ + + devnum = PCI_SLOT(pdev->devfn); + + pbus = pdev->bus; + + /* + ** Check to see if this could possibly be a + ** peer Host Bridge device. + */ + + if (pbus->parent != (struct pci_bus *)NULL) + { + /* + ** The IRQ line number will be generated after + ** taking into account all the PCI-2-PCI bridge + ** devices between the device and the Host Bridge. + */ + + while ((pbus->parent)->primary != (pbus->parent)->secondary) + { + devnum += PCI_SLOT((pbus->self)->devfn); + + pbus = pbus->parent; + } + } + + devnum &= 0x03; + + /* + ** By default, get the PCI local domain IRQ value. + */ + + irq = pci_localpirqs[devnum]; + +#ifdef CONFIG_PCI_MULTI_DOMAIN + /* + ** Check to see if this could possibly be a + ** peer Host Bridge device. + */ + + pbus = pdev->bus; + + if (pbus->parent != (struct pci_bus *)NULL) + { + /* + ** Determine if the device is located in the + ** remote domain or not. We must find the + ** domain's bridge device located on bus 0. + */ + + while (pbus->primary != 0) + pbus = pbus->parent; + + /* + ** Check the device/function of domain's bridge + ** device against the remote device/function. + ** If the same, then the device is located in + ** the remote domain. Thus, get the PCI remote + ** domain IRQ value. + */ + + if ((pbus->self)->devfn == pci_remotedev) + irq = pci_remotepirqs[devnum]; + } +#endif + + /* + ** Set the device's Interrupt Line register + ** to the IRQ number and save it in the + ** device's structure. + */ + + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, (u8)irq); + + pdev->irq = irq; +} diff -u -r --new-file linux/drivers/pci/pci_node.c linux_mot/drivers/pci/pci_node.c --- linux/drivers/pci/pci_node.c Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/pci_node.c Tue Jun 8 10:36:04 1999 @@ -0,0 +1,1434 @@ +/* +** PCI Bus/Device Node Management +*/ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/malloc.h> +#include <linux/pci.h> +#include <linux/pci_res.h> + +#include <asm/errno.h> +#include <asm/system.h> + + + + + +/* +** pci_add_dev - Add Device Structure +** +** This function will allocate a device structure +** and fill it with the appropriate device information, +** If the device structure cannot be allocated or +** if the device header is incorrect, a NULL pointer +** will be returned. +*/ + +int +pci_add_dev(struct pci_bus *pbus, unsigned int devfn, struct pci_dev **pdev) +{ + struct pci_dev *pdev_list; /* PCI Device List Pointer */ + + unsigned long flags; /* CPU Interrupt Flags */ + + unsigned int cmp_stat; /* Compare Status For Device/Func. */ + + int ret_code; /* Function Return Code */ + + u32 devid; /* Device/Vendor ID */ + + u32 class; /* Configuration Class Code */ + + u32 rom_adr; /* Configuration Expansion ROM Base Addr. */ + + u16 cmd; /* Configuration Command Register */ + + u16 tmp; /* Just A Temporary */ + + u8 hdr_type; /* Configuration Header Type */ + + char *func; /* Function Name */ + + char err_msg[256]; /* Error Message */ + + /* + ** First, set the function name for possible error + ** messages. Then, clear the return code and allocate + ** a device structure. + */ + + func = "pci_add_dev"; + + ret_code = PCI_OK; + + *pdev = (struct pci_dev *)kmalloc(sizeof(struct pci_dev), GFP_ATOMIC); + + if (*pdev != (struct pci_dev *)NULL) + { + /* + ** Next, clear it and fill in the bus pointer, + ** device, function, and vendor/device IDs. + */ + + memset(*pdev, 0, sizeof(struct pci_dev)); + + (*pdev)->bus = pbus; + (*pdev)->devfn = devfn; + + /* + ** Get the device ID and put the vendor and + ** device IDs into the device structure. + */ + + pci_read_config_dword(*pdev, PCI_VENDOR_ID, &devid); + + (*pdev)->vendor = devid & 0xffff; + (*pdev)->device = (devid >> 16) & 0xffff; + + /* + ** Determine if device can be a master. Set + ** the master field in the device structure + ** appropriately. If the device is not the + ** Host Bridge, then disable it. + */ + + pci_read_config_word(*pdev, PCI_COMMAND, &cmd); + + pci_write_config_word(*pdev, PCI_COMMAND, (cmd | PCI_COMMAND_MASTER)); + + pci_read_config_word(*pdev, PCI_COMMAND, &tmp); + + pci_write_config_word(*pdev, PCI_COMMAND, cmd); + + (*pdev)->master = ((tmp & PCI_COMMAND_MASTER) != 0) ? TRUE : FALSE; + + /* + ** Read the class code and set it in the + ** device structure. + */ + + pci_read_config_dword(*pdev, PCI_CLASS_REVISION, &class); + + (*pdev)->class = class >> 8; + + /* + ** Read the header type and set it in the + ** device structure. + */ + + pci_read_config_byte(*pdev, PCI_HEADER_TYPE, &hdr_type); + + (*pdev)->hdr_type = hdr_type; + + /* + ** Next, fill in the remainder of the device + ** structure based upon the header type. + */ + + switch (hdr_type & 0x7f) + { + /* + ** Standard Header + */ + + case PCI_HEADER_TYPE_NORMAL: + { + /* + ** Check for an invalid class code, + ** i.e. PCI-To-PCI Bridge. + */ + + if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) + { + /* + ** Read the ROM Expansion address. Then + ** see if it's a valid address. + */ + + pci_read_config_dword(*pdev, PCI_ROM_ADDRESS, &rom_adr); + + if (rom_adr != 0xffffffff) + { + /* + ** If not a bus 0 device, then disable + ** the Expansion ROM Address. Otherwise, + ** save the address. + */ + + if (pbus->number != 0) + pci_write_config_dword(*pdev, PCI_ROM_ADDRESS, 0xfffffffe); + else + (*pdev)->rom_address = rom_adr; + } + } + else + ret_code = -EBADF; + + break; + } + + /* + ** Bridge Header + */ + + case PCI_HEADER_TYPE_BRIDGE: + { + /* + ** Check for a valid class code, + ** i.e. PCI-To-PCI Bridge. + */ + + if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) + { + /* + ** Read the ROM Expansion address. Then + ** see if it's a valid address. + */ + + pci_read_config_dword(*pdev, PCI_ROM_ADDRESS1, &rom_adr); + + if (rom_adr != 0xffffffff) + { + /* + ** If not a bus 0 bridge, then disable + ** the Expansion ROM Address. Otherwise, + ** save the address. + */ + + if (pbus->number != 0) + pci_write_config_dword(*pdev, PCI_ROM_ADDRESS1, 0xfffffffe); + else + (*pdev)->rom_address = rom_adr; + } + } + else + ret_code = -EBADF; + + break; + } + + /* + ** CardBus Bridge Header + */ + + case PCI_HEADER_TYPE_CARDBUS: + { + /* + ** Check for a valid class code, + ** i.e. CardBus Bridge. If so, then + ** clear the device error flag. + */ + + if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) + ret_code = -EBADF; + + break; + } + + /* + ** Unknown header type. + */ + + default: + { + /* + ** A header error. Display a message and + ** free the device structure. + */ + + sprintf(err_msg, "%02x:%02x [%04x/%04x/%06x] has unknown header type %02x", + pbus->number, + (*pdev)->devfn, + (*pdev)->vendor, + (*pdev)->device, + class, + hdr_type); + + pci_kern_err(func, err_msg); + + ret_code = -ENOSYS; + } + } + + /* + ** Any device errors? If not, then put the + ** device structure on the various lists. + */ + + if (ret_code == PCI_OK) + { + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + /* + ** Put it into the bus node's device list + ** first. + */ + + if ((pdev_list = pbus->devices) != (struct pci_dev *)NULL) + { + /* + ** Loop through the list to find the + ** position for the new device. + */ + + do + { + /* + ** Clear the compare status, i.e. denotes + ** the device/function numbers are equal. + ** Then, if the device/function numbers are + ** "greater than", try the next sibling, if + ** there is one. + */ + + cmp_stat = 0; + + if ((*pdev)->devfn > pdev_list->devfn) + { + /* + ** Set the compare status. Then, see if + ** we at the end of the list If not, then + ** try the next one. + */ + + cmp_stat = 1; + + if (pdev_list->sibling == (struct pci_dev *)NULL) + { + /* + ** Add the device at the end and + ** exit the compare loop. + */ + + pdev_list->sibling = *pdev; + break; + } + else + pdev_list = pdev_list->sibling; + } + else + { + /* + ** If "less than", then we've gone + ** too far. + */ + + if ((*pdev)->devfn < pdev_list->devfn) + { + /* + ** Set the compare status. Then, + ** set the next sibling pointer and + ** find our previous sibling. + */ + + cmp_stat = 1; + + (*pdev)->sibling = pdev_list; + + if ((pdev_list = pbus->devices) != (*pdev)->sibling) + { + while (pdev_list->sibling != (*pdev)->sibling) + pdev_list = pdev_list->sibling; + + pdev_list->sibling = *pdev; + } + else + pbus->devices = *pdev; + + break; + } + } + } + while (cmp_stat != 0); + + /* + ** Restore interrupts, then check for same + ** device/function number error. If so, then + ** display a message and set the device error + ** flag. + */ + + restore_flags(flags); + + if (cmp_stat == 0) + { + /* + ** Display an error message. Then set the + ** device error flag. + */ + + sprintf(err_msg, "%02x:%02x [%04x/%04x/%06x] has same devfn", + pbus->number, + (*pdev)->devfn, + (*pdev)->vendor, + (*pdev)->device, + class); + + pci_kern_err(func, err_msg); + + ret_code = -EEXIST; + } + } + else + { + /* + ** Put the device on the list and + ** restore interrupt.s + */ + + pbus->devices = *pdev; + + restore_flags(flags); + } + } + + /* + ** Check for any errors so far. + */ + + if (ret_code == PCI_OK) + { + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + /* + ** Put the device into the global PCI + ** device chain. It's used to find + ** devices once everything is set up. + */ + + if ((pdev_list = pci_devices) != (struct pci_dev *)NULL) + { + /* + ** Next, set the "next pointer" of the + ** device structure, based upon the + ** sort flag, pci_reverse. + */ + + if (pci_reverse == 0) + { + /* + ** Find the last device structure. Then + ** set its next pointer to the new device + ** structure. + */ + + while (pdev_list->next != (struct pci_dev *)NULL) + pdev_list = pdev_list->next; + + pdev_list->next = *pdev; + } + else + { + /* + ** Set the initial pointer to the new + ** device structure. + */ + + (*pdev)->next = pdev_list; + + pci_devices = *pdev; + } + } + else + pci_devices = *pdev; + + /* + ** Restore interrupts. + */ + + restore_flags(flags); + + /* + ** Attach a proc interface entry + ** to the device. + */ + + if (pci_proc_attach_device(*pdev) != 0) + { + sprintf(err_msg, "%02x:%02x [%04x/%04x/%06x] can't attach proc interface", + pbus->number, + (*pdev)->devfn, + (*pdev)->vendor, + (*pdev)->device, + class); + + pci_kern_err(func, err_msg); + } + } + else + { + /* + ** Free the device structure and return + ** a NULL pointer. + */ + + kfree(*pdev); + + *pdev = (struct pci_dev *)NULL; + } + } + else + { + pci_kern_err(func, "couldn't allocate a device structure"); + + ret_code = -ENOBUFS; + } + + /* + ** Return the function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_add_bus - Add Bus Structure +** +** This function will allocate a bus structure for +** a child bus and fill it with the appropriate +** bus node information. If the child bus structure +** cannot be allocated, a NULL pointer will be +** returned. +*/ + +int +pci_add_bus(struct pci_bus *pbus, struct pci_dev *pdev, struct pci_bus **child) +{ + struct pci_bus *last_child; /* PCI Bus Child Last Pointer */ + + unsigned long flags; /* CPU Interrupt Flags */ + + int ret_code; /* Function Return Code */ + + /* + ** First, clear the return code. Then, allocate a + ** child pci_bus structure. + */ + + ret_code = PCI_OK; + + *child = (struct pci_bus *)kmalloc(sizeof(struct pci_bus), GFP_ATOMIC); + + if (*child != (struct pci_bus *)NULL) + { + /* + ** Next, clear it and initialize the pointers. + */ + + memset(*child, 0, sizeof(struct pci_bus)); + + (*child)->self = pdev; + (*child)->parent = pbus; + + /* + ** Insert the child pci_bus structure into + ** the parent's list of children. + */ + + if (pbus != (struct pci_bus *)NULL) + { + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + if ((last_child = pbus->children) != (struct pci_bus *)NULL) + { + while (last_child->next != (struct pci_bus *)NULL) + last_child = last_child->next; + + last_child->next = *child; + } + else + pbus->children = *child; + + /* + ** Restore interrupts. + */ + + restore_flags(flags); + } + } + else + { + pci_kern_err("pci_add_bus", "couldn't allocate a bus structure"); + + ret_code = -ENOBUFS; + } + + /* + ** Return the function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_add_node - Add Node Structure +** +** This function will allocate a structure for the +** node, i.e. either bus or device structure, and +** all resources for that node. It will be added to +** the various lists as well. +*/ + +int +pci_add_node(unsigned int number, unsigned int devfn) +{ + struct pci_bus *pbus; /* PCI Parent Bus Pointer */ + + struct pci_bus *child; /* PCI Child Bus Pointer */ + + struct pci_dev *pdev; /* PCI Device Pointer */ + + unsigned short class; /* Class Code */ + + int ret_code; /* Function Return Code */ + + char *func; /* Function Name */ + + char err_msg[256]; /* Error Message */ + + /* + ** First, set the function name for possible error + ** messages. Then, initialize the function return + ** code and see if the device already exists in + ** the list. + */ + + func = "pci_add_node"; + + ret_code = PCI_OK; + + if (pci_find_slot(number, devfn) == (struct pci_dev *)NULL) + { + /* + ** Next, ensure the Device ID is valid. + */ + + if (pci_valid_devid(number, devfn) == TRUE) + { + /* + ** Read the Class Code. Then add the node + ** based upon it. + */ + + pcibios_read_config_word(number, devfn, PCI_CLASS_DEVICE, &class); + + if (class == PCI_CLASS_BRIDGE_HOST) + { + /* + ** Next, check for primary Host Bridge. This + ** we cannot add. + */ + + if (number != 0) + { + /* + ** Add a new bus structure to the + ** various lists. + */ + + ret_code = pci_add_bus((struct pci_bus *)NULL, (struct pci_dev *)NULL, &pbus); + + if (ret_code == PCI_OK) + { + /* + ** Fill in the bus structure and + ** add it to the list. + */ + + pbus->number = number; + pbus->primary = number; + pbus->secondary = number; + pbus->subordinate = 0xff; + + pbus->next = pci_root.next; + + pci_root.next = pbus; + + /* + ** Do the initial call to pci_probe_bus() + ** to find all the devices for each bus + ** under the Host Bridge device. + */ + + ret_code = pci_probe_bus(pbus, devfn); + + if (ret_code == PCI_OK) + { + /* + ** Next, set the Host Bridge node's + ** device structure. + */ + + pbus->self = pci_find_slot(number, devfn); + + /* + ** Finally, configure all the devices + ** and bridges. + */ + + ret_code = pci_conf_bus(pbus); + } + + /* + ** Did we get any errors? + */ + + if (ret_code != PCI_OK) + { + /* + ** Delete the bus structure. + */ + + pci_del_bus(pbus); + } + } + } + else + { + pci_kern_err(func, "cannot add primary Host Bridge"); + + ret_code = -EPERM; + } + } + else + { + /* + ** Not a Host Bridge. First, find the parent + ** bus structure. + */ + + pbus = &pci_root; + + while ((pbus != (struct pci_bus *)NULL) && (pbus->secondary != number)) + { + /* + ** Compare the subordinate bus number. + */ + + if (number < pbus->subordinate) + pbus = pbus->children; + else + pbus = pbus->next; + } + + /* + ** Did we find the parent bus structure? + */ + + if (pbus != (struct pci_bus *)NULL) + { + /* + ** Get a PCI device structure and fill + ** it. Then add it to the various device + ** lists. + */ + + ret_code = pci_add_dev(pbus, devfn, &pdev); + + if (ret_code == PCI_OK) + { + /* + ** Is the new node a bridge? If not, + ** then just configure the device. + */ + + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + { + /* + ** Add a new bus structure to the + ** various lists. If we can't then + ** delete the device node. + */ + + ret_code = pci_add_bus(pbus, pdev, &child); + + if (ret_code == PCI_OK) + { + /* + ** Probe for new devices. + */ + + ret_code = pci_probe_bus(child, devfn); + +#ifdef CONFIG_PCI_AGP_BRIDGE + if (ret_code == PCI_OK) + { + /* + ** Check to see if this is an AGP + ** bridge device. + */ + + if (pci_agp_bridge(pdev->bus, devfn) == TRUE) + { + sprintf(err_msg, "cannot add AGP bridge at %02x:%02x", + number, + devfn); + + pci_kern_err(func, err_msg); + + ret_code = -EPERM; + } + } +#endif + + /* + ** If no errors, then configure all + ** the new devices. + */ + + if (ret_code == PCI_OK) + ret_code = pci_conf_bus(child); + } + } + else + { + /* + ** Clear the child bus structure pointer. + ** Then, check for a bus 0 device. this + ** we cannot add. + */ + + child = (struct pci_bus *)NULL; + + if (number != 0) + { + /* + ** Configure the device. + */ + + ret_code = pci_conf_dev(pdev); + } + else + { + pci_kern_err(func, "cannot add bus 0 device"); + + ret_code = -EPERM; + } + } + + /* + ** Check for any errors. + */ + + if (ret_code != PCI_OK) + { + /* + ** Do we have a bus or device + ** structure to delete? + */ + + if (child != (struct pci_bus *)NULL) + pci_del_bus(child); + else + if (pdev != (struct pci_dev *)NULL) + pci_del_dev(pdev); + } + } + } + else + { + sprintf(err_msg, "couldn't find parent bus structure for %02x:%02x", + number, + devfn); + + pci_kern_err(func, err_msg); + + ret_code = -ENOENT; + } + } + + /* + ** Finally, if no errors, ensure all the display + ** devices have been properly (re)configured. + */ + + if (ret_code == PCI_OK) + pci_conf_display(); + } + else + { + sprintf(err_msg, "invalid device ID for %02x:%02x", + number, + devfn); + + pci_kern_err(func, err_msg); + + ret_code = -ENODEV; + } + } + else + { + sprintf(err_msg, "device already exists at %02x:%02x", + number, + devfn); + + pci_kern_err(func, err_msg); + + ret_code = -EEXIST; + } + + /* + ** Return the function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_del_dev - Delete Device Structure +** +** This function will delete a device structure from +** the list of devices for the bus.. The device structure +** memory will be freed as well. +*/ + +int +pci_del_dev(struct pci_dev *pdev) +{ + struct pci_bus *pbus; /* PCI Bus Pointer */ + + struct pci_dev *pdev_del; /* PCI Deleted Device Pointer */ + + unsigned long flags; /* CPU Interrupt Flags */ + + unsigned int num_bars; /* Maximum Number Of BARs */ + + unsigned int bar; /* Base Address Register */ + + int ret_code; /* Function Return Code */ + + int alt_ret_code; /* Alternate Return Code */ + + /* + ** Initialize the return code, then + ** remove the proc interface. + */ + + ret_code = PCI_OK; + + if ((alt_ret_code = pci_proc_detach_device(pdev)) != 0) + ret_code = alt_ret_code; + + /* + ** Determine the number of Base Address registers + ** we need to free resources for. + */ + + if ((alt_ret_code = pci_get_bars(pdev, &num_bars)) != PCI_OK) + if (ret_code == PCI_OK) + ret_code = alt_ret_code; + + /* + ** Next, free the device's resources. + */ + + for (bar = 0; bar < num_bars; ++bar) + if ((alt_ret_code = pci_free_devres(pdev, &(pdev->resources[bar]))) != PCI_OK) + if (ret_code == PCI_OK) + ret_code = alt_ret_code; + + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + /* + ** Set the device's bus structure pointer, then + ** check to see if it's the first device. + */ + + pbus = pdev->bus; + + if ((pdev_del = pbus->devices) != pdev) + { + /* + ** Loop until we find the device. + */ + + while (pdev_del->sibling != pdev) + pdev_del = pdev_del->sibling; + + /* + ** Set the next sibling pointer. + */ + + pdev_del->sibling = pdev->sibling; + } + else + pbus->devices = pdev->sibling; + + /* + ** Next, check to see if the device is + ** the first one on the list of devices. + */ + + if ((pdev_del = pci_devices) != pdev) + { + /* + ** Loop until we find the device. + */ + + while (pdev_del->next != pdev) + pdev_del = pdev_del->next; + + /* + ** Set the next device pointer. + */ + + pdev_del->next = pdev->next; + } + else + pci_devices = pdev->next; + + /* + ** Restore interrupts. + */ + + restore_flags(flags); + + /* + ** Free the device structure memory. + */ + + kfree(pdev); + + /* + ** Return the function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_del_bus - Delete Bus Structure +** +** This function will delete a bus structure and +** all the child bus/device structures associated +** with it. All resources will be freed. +*/ + +int +pci_del_bus(struct pci_bus *pbus) +{ + struct pci_bus *pbus_child; /* PCI Bus Child Pointer */ + + struct pci_bus *pbus_del; /* PCI Bus Deleted Child Pointer */ + + struct pci_bus *pbus_par; /* PCI Bus Parent Pointer */ + + struct pci_dev *pdev; /* PCI Device Pointer */ + + struct pci_dev *pdev_del; /* PCI Deleted Device Pointer */ + + unsigned long flags; /* CPU Interrupt Flags */ + + int ret_code; /* Function Return Code */ + + int alt_ret_code; /* Alternate Return Code */ + + /* + ** Initialize the function return code. Then, + ** recursively delete each child bus structure. + */ + + ret_code = PCI_OK; + + pbus_child = pbus->children; + + while (pbus_child != (struct pci_bus *)NULL) + { + /* + ** Set the pointer to the next child first. + */ + + pbus_del = pbus_child; + + pbus_child = pbus_child->next; + + /* + ** Delete the child bus structure. + */ + + if ((alt_ret_code = pci_del_bus(pbus_del)) != PCI_OK) + if (ret_code == PCI_OK) + ret_code = alt_ret_code; + } + + /* + ** Next, loop and delete each device structure. + */ + + pdev = pbus->devices; + + while (pdev != (struct pci_dev *)NULL) + { + /* + ** Set the pointer to the next sibling first. + */ + + pdev_del = pdev; + + pdev = pdev->sibling; + + /* + ** Ensure the device to be deleted is not the + ** bus node's device. If it is the bus node's + ** device, then the device is a Host Bridge. + */ + + if (pdev_del != pbus->self) + { + /* + ** It is not the bus node's device. Free the + ** device's resources and delete the device + ** structure. + */ + + if ((alt_ret_code = pci_del_dev(pdev_del)) != PCI_OK) + if (ret_code == PCI_OK) + ret_code = alt_ret_code; + } + else + { + /* + ** It is the bus node's device. Set it as + ** the "only" device. + */ + + pbus->devices = pdev_del; + + pdev_del->sibling = (struct pci_dev *)NULL; + } + } + + /* + ** Free the bus' resources, i.e. memory and bus + ** numbers. Then delete the bus's device structure. + */ + + if ((alt_ret_code = pci_free_busres(pbus)) != PCI_OK) + if (ret_code == PCI_OK) + ret_code = alt_ret_code; + + if ((alt_ret_code = pci_free_busnum(pbus)) != PCI_OK) + if (ret_code == PCI_OK) + ret_code = alt_ret_code; + + if (pbus->self != (struct pci_dev *)NULL) + if ((alt_ret_code = pci_del_dev(pbus->self)) != PCI_OK) + if (ret_code == PCI_OK) + ret_code = alt_ret_code; + + /* + ** Disable interrupts for now. + */ + + save_flags(flags); + + /* + ** Set the parent bus structure pointer and + ** check it for the root structure. + */ + + if ((pbus_par = pbus->parent) != (struct pci_bus *)NULL) + { + /* + ** Check to see if it's the first bus structure. + */ + + if ((pbus_del = pbus_par->children) != pbus) + { + /* + ** Loop until we find the bus structure. + ** Then set the next sibling pointer. + */ + + while (pbus_del->next != pbus) + pbus_del = pbus_del->next; + + pbus_del->next = pbus->next; + } + else + pbus_par->children = pbus->next; + } + else + { + /* + ** Check to see if it's the next root + ** bus structure. + */ + + if ((pbus_del = pci_root.next) != pbus) + { + /* + ** Loop until we find the bus structure. + ** Then set the next sibling pointer. + */ + + while (pbus_del->next != pbus) + pbus_del = pbus_del->next; + + pbus_del->next = pbus->next; + } + else + pci_root.next = pbus->next; + } + + /* + ** Restore interrupts and detach the + ** proc interface for this bus. + */ + + restore_flags(flags); + + if ((alt_ret_code = pci_proc_detach_bus(pbus)) != 0) + if (ret_code == PCI_OK) + ret_code = alt_ret_code; + + /* + ** Free the bus structure memory. + */ + + kfree(pbus); + + /* + ** Return the function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_del_node - Delete Node Structure +** +** This function will free all resources associated +** with the node, i.e. either bus or device structure, +** for the given bus and device/function numbers. It +** will then remove the device structure from the bus' +** list of devices as well as from the global list of devices. +*/ + +int +pci_del_node(unsigned int number, unsigned int devfn) +{ + struct pci_bus *pbus; /* PCI Bus Pointer */ + + struct pci_dev *pdev; /* PCI Device Pointer */ + + unsigned int class; /* Class Code */ + + int ret_code; /* Function Return Code */ + + char *func; /* Function Name */ + + char err_msg[256]; /* Error Message */ + + /* + ** First, set the function name for possible error + ** messages. Then, initialize the function return + ** code and find the device structure in the devices' + ** list. + */ + + func = "pci_del_node"; + + ret_code = PCI_OK; + + pdev = pci_find_slot(number, devfn); + + if (pdev != (struct pci_dev *)NULL) + { + /* + ** Next, determine if this is a device or a + ** bus node. + */ + + class = pdev->class >> 8; + + switch (class) + { + /* + ** Host Bridge + */ + + case PCI_CLASS_BRIDGE_HOST: + { + /* + ** Check for primary Host Bridge. This, + ** we cannot delete it. + */ + + if ((pdev->bus)->number == 0) + { + pci_kern_err(func, "cannot delete primary Host Bridge"); + + ret_code = -EPERM; + + break; + } + } + + /* + ** PCI Bridge + */ + + case PCI_CLASS_BRIDGE_PCI: + { + /* + ** Find the bus structure associated + ** with the bridge device structure. + */ + + if (class == PCI_CLASS_BRIDGE_HOST) + pbus = pci_root.next; + else + pbus = (pdev->bus)->children; + + while (pbus != (struct pci_bus *)NULL) + { + /* + ** Compare for the the device + ** structure pointer. + */ + + if (pbus->self != pdev) + pbus = pbus->next; + else + break; + } + + /* + ** Did we find the bus structure? + */ + + if (pbus != (struct pci_bus *)NULL) + { +#ifdef CONFIG_PCI_AGP_BRIDGE + /* + ** Check to see if this is an AGP bridge device. + */ + + if (pci_agp_bridge(pdev->bus, devfn) == TRUE) + { + sprintf(err_msg, "cannot delete AGP bridge at %02x:%02x", + number, + devfn); + + pci_kern_err(func, err_msg); + + ret_code = -EPERM; + } +#endif + + /* + ** Delete the bus/devices. + */ + + if (ret_code == PCI_OK) + ret_code = pci_del_bus(pbus); + } + else + { + sprintf(err_msg, "couldn't find bus structure for %02x:%02x", + number, + devfn); + + pci_kern_err(func, err_msg); + + ret_code = -ENOENT; + } + + break; + } + + /* + ** PCI Device + */ + + default: + { + /* + ** Next, check for a bus 0 device. These, + ** we cannot delete. + */ + + if ((pdev->bus)->number != 0) + { + /* + ** Anything else is just a device. Free + ** the device's resources and delete the + ** device structure. + */ + + ret_code = pci_del_dev(pdev); + } + else + { + pci_kern_err(func, "cannot delete a bus 0 device"); + + ret_code = -EPERM; + } + } + } + + /* + ** Finally, if no errors, ensure all the display + ** devices have been properly (re)configured. + */ + + if (ret_code == PCI_OK) + pci_conf_display(); + } + else + { + sprintf(err_msg, "couldn't find device structure for %02x:%02x", + number, + devfn); + + pci_kern_err(func, err_msg); + + ret_code = -ENODEV; + } + + /* + ** Return the function result. + */ + + return (ret_code); +} diff -u -r --new-file linux/drivers/pci/pci_scan.c linux_mot/drivers/pci/pci_scan.c --- linux/drivers/pci/pci_scan.c Wed Dec 31 17:00:00 1969 +++ linux_mot/drivers/pci/pci_scan.c Tue Jun 8 10:36:04 1999 @@ -0,0 +1,606 @@ +/* +** PCI Bus Probe/Scan +*/ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/pci_res.h> + + + + + +/* +** Debug info printing setup +*/ + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + + + + + +/* +** pci_find_host - Find Host Bridge Device on Bus +** +** This function will probe the given PCI bus for +** a Host Bridge Device. +*/ + +__initfunc(int pci_find_host(unsigned int number, unsigned int *devfn)) +{ + unsigned int dev; /* Device Number */ + + unsigned int func; /* Function Number */ + + unsigned short class; /* Class Code */ + + int ret_code; /* Function Return Code */ + + /* + ** Set the return code, then loop through each + ** device to find a Host Bridge. + */ + + ret_code = PCI_ERR; + + for (dev = 0; (ret_code == PCI_ERR) && (dev <= MAX_PCI_DEV); ++dev) + { + /* + ** Function loop, from 0 to 7. + */ + + for (func = 0; (ret_code == PCI_ERR) && (func <= MAX_PCI_FUNC); ++func) + { + /* + ** Generate the Device/Function number, + ** then read and validate the Device ID + ** word from the device's configuration + ** space. + */ + + *devfn = PCI_DEVFN(dev, func); + + if (pci_valid_devid(number, *devfn) == TRUE) + { + /* + ** Read the Class Code and see if it's a + ** PCI Host Bridge Device. If so, then + ** set good status. + */ + + pcibios_read_config_word(number, *devfn, PCI_CLASS_DEVICE, &class); + + if (class != PCI_CLASS_BRIDGE_HOST) + { + /* + ** Check for a multi-function device. + */ + + if (pci_multi_func(number, *devfn) == FALSE) + break; + } + else + ret_code = PCI_OK; + } + } + } + + /* + ** Return function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_kern_err - Display PCI Kernel Error Message +** +** This function will format and display a +** PCI kernel error message. It will always +** return PCI_ERR. +*/ + +int +pci_kern_err(char *func, char *err_msg) +{ + /* + ** Do the error message. + */ + + if (func != (char *)NULL) + printk(KERN_ERR "PCI: %s() - %s\n", func, err_msg); + else + printk(KERN_ERR "PCI: %s\n", err_msg); + + return (PCI_ERR); +} + + + + + +/* +** pci_valid_devid - Read and Validate the device ID +** +** This function will read the device ID at the given +** bus, device, and function number. It will also +** validate it. +*/ + +int +pci_valid_devid(unsigned int number, unsigned int devfn) +{ + unsigned short devid; /* Device/Vendor ID */ + + int ret_code; /* Function Return Code */ + + /* + ** First, Read the device ID. + */ + + pcibios_read_config_word(number, devfn, PCI_DEVICE_ID, &devid); + + /* + ** Next, set the return code and validate + ** the device ID. + ** + ** NOTE: Some broken boards return 0 if a + ** slot is empty. + */ + + ret_code = TRUE; + + if (devid == 0xffff) + ret_code = FALSE; + + if (devid == 0x0000) + ret_code = FALSE; + + /* + ** Return function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_multi_func - Check for Multi-Function Device +** +** This function will read the header type at the given +** bus, device, and function number. It will check it +** for a multi-function device or not. +*/ + +int +pci_multi_func(unsigned int number, unsigned int devfn) +{ + unsigned char hdr_type; /* Device Header Type */ + + int ret_code; /* Function Return Code */ + + /* + ** First, set the return code. Then, if + ** we are at function 0, check for a + ** multi-function device. + */ + + ret_code = TRUE; + + if (PCI_FUNC(devfn) == 0) + { + /* + ** Read the configuration header type + ** register and check for a multi-function + ** device. If not multi-function, then + ** clear the return code. + */ + + pcibios_read_config_byte(number, devfn, PCI_HEADER_TYPE, &hdr_type); + + if ((hdr_type & 0x80) == 0) + ret_code = FALSE; + } + + /* + ** Return function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_probe_dev - Probe PCI Bus For Devices +** +** This function will probe the given bus for all +** devices connected to it. It will add the found +** devices to the global device list and to the +** bus structure devices list. +*/ + +static int +pci_probe_dev(struct pci_bus *pbus) +{ + struct pci_dev *pdev; /* PCI Device Pointer */ + + struct pci_bus *child; /* PCI Bus Child Pointer */ + + unsigned int dev; /* Device Number */ + + unsigned int func; /* Function Number */ + + unsigned int devfn; /* Device/Function Number */ + + unsigned int buses; /* Buses Config. Register */ + + unsigned char slat_timer; /* Secondary Latency Timer */ + + int ret_code; /* Function Return Code */ + + /* + ** Initialize the function return code, then + ** search each device on this bus, i.e. device + ** 0 to 31. + */ + + ret_code = PCI_OK; + + for (dev = 0; (ret_code == PCI_OK) && (dev <= MAX_PCI_DEV); ++dev) + { + /* + ** Function loop, from 0 to 7. + */ + + for (func = 0; (ret_code == PCI_OK) && (func <= MAX_PCI_FUNC); ++func) + { + /* + ** Generate the Device/Function number, + ** then read and validate the Device ID + ** word from the device's configuration + ** space. + */ + + devfn = PCI_DEVFN(dev, func); + + if (pci_valid_devid(pbus->number, devfn) == TRUE) + { + /* + ** Next, get a PCI device structure and fill + ** it. + */ + + ret_code = pci_add_dev(pbus, devfn, &pdev); + + if (ret_code == PCI_OK) + { + /* + ** Next, check to see if it's a bridge. If so, + ** then disable the bus(es) behind it. + */ + + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + { + /* + ** First, read the Secondary Latency Timer value + ** and save it. + */ + + pcibios_read_config_byte(pbus->number, devfn, PCI_SEC_LATENCY_TIMER, &slat_timer); + + /* + ** Then set the Secondary Latency Timer value + ** and clear the Subordinate, Primary, and + ** Secondary bus numbers. This will disable + ** the bridge for now. + */ + + buses = slat_timer; + + buses = (buses << 8) | 0; + buses = (buses << 8) | 0; + buses = (buses << 8) | 0; + + pcibios_write_config_dword(pbus->number, devfn, PCI_PRIMARY_BUS, buses); + } + + /* + ** Check for a multi-function device. + */ + + if (pci_multi_func(pbus->number, devfn) == FALSE) + break; + } + } + } + } + + /* + ** Look behind all PCI-to-PCI bridges on this bus. + */ + + pdev = pbus->devices; + + while ((ret_code == PCI_OK) && (pdev != (struct pci_dev *)NULL)) + { + /* + ** If it's a bridge, scan the bus behind it. + */ + + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + { + /* + ** Allocate a child pci_bus structure, + ** initialize it, and insert it into the + ** tree of buses. Then scan all the child's + ** subordinate buses. + */ + + ret_code = pci_add_bus(pbus, pdev, &child); + + if (ret_code == PCI_OK) + ret_code = pci_probe_bus(child, pdev->devfn); + } + + /* + ** Do the next sibling. + */ + + pdev = pdev->sibling; + } + + /* + ** Return the function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_probe_bus - Probe PCI Bus +** +** This function gets called recursively. However, for +** the first time it gets called from pci_init(). The +** argument to this function has to be bus node. +*/ + +int +pci_probe_bus(struct pci_bus *pbus, unsigned int devfn) +{ + struct pci_bus *pbus_par; /* Parent Bus Pointer */ + + unsigned int buses; /* Buses Config. Register */ + + unsigned short cmd; /* Command Register */ + + unsigned short class; /* Class Code */ + + unsigned char slat_timer; /* Secondary Latency Timer */ + + int ret_code; /* Function Return Code */ + + /* + ** Initialize the function return code, then + ** see if we need to allocate bus numbers. We + ** only do this once. + */ + + ret_code = PCI_OK; + + if ((pbus->subordinate == 0) || (pbus->subordinate == MAX_PCI_BUS)) + { + /* + ** Allocate bus numbers, i.e. secondary and + ** subordinate. + */ + + ret_code = pci_alloc_busnum(pbus, devfn); + + if (ret_code == PCI_OK) + { + /* + ** Set the parent bus pointer. We need this + ** for the bridge's bus number. + */ + + if ((pbus_par = pbus->parent) == (struct pci_bus *)NULL) + pbus_par = pbus; + + /* + ** Clear the Secondary Latency Timer value. Then + ** read the Class Code to see if this is a PCI + ** bridge device? + */ + + slat_timer = 0; + + pcibios_read_config_word(pbus_par->number, devfn, PCI_CLASS_DEVICE, &class); + + if (class == PCI_CLASS_BRIDGE_PCI) + { + /* + ** Disable this bridge device by clearing the + ** Master, Memory, and I/O enable bits. + */ + + pcibios_read_config_word(pbus_par->number, devfn, PCI_COMMAND, &cmd); + + cmd &= ~0x0007; + + pcibios_write_config_word(pbus_par->number, devfn, PCI_COMMAND, cmd); + + /* + ** Read the Secondary Latency Timer value and + ** set it if it is below 16. + */ + + pcibios_read_config_byte(pbus_par->number, devfn, PCI_SEC_LATENCY_TIMER, &slat_timer); + + if (slat_timer < 16) + slat_timer = 64; + } + + /* + ** Then set the Secondary Latency Timer value, + ** the Primary Bus number, and the Secondary + ** Bus number. Write the configuration register. + */ + + buses = slat_timer; + buses = (buses << 8) | pbus->subordinate; + buses = (buses << 8) | pbus->secondary; + buses = (buses << 8) | pbus->primary; + + pcibios_write_config_dword(pbus_par->number, devfn, PCI_PRIMARY_BUS, buses); + + /* + ** Finally, clear the Status register. + */ + + pcibios_write_config_word(pbus_par->number, devfn, PCI_STATUS, 0xffff); + } + } + + /* + ** Did we get any errors? + */ + + if (ret_code == PCI_OK) + { + /* + ** Next, probe the bus for all devices. + */ + + ret_code = pci_probe_dev(pbus); + } + + /* + ** Return the function result. + */ + + return (ret_code); +} + + + + + +/* +** pci_scan_bus - Scan PCI Bus +** +** This function gets called recursively. However, for +** the first time it gets called from pci_init(). The +** argument to this function has to be bus node. +*/ + +__initfunc(unsigned int pci_scan_bus(struct pci_bus *pbus)) +{ + unsigned int devfn; /* Host Device/Function Number */ + + int ret_code; /* Function Return Code */ + + /* + ** First, find the Host Bridge on this bus + ** and check for probing errors. + */ + + DBG("pci_scan_bus for bus %d\n", pbus->number); + + ret_code = pci_find_host(pbus->number, &devfn); + +#if (CONFIG_PCI_BUSLVL0_NODES > 1) + if (ret_code == PCI_OK) + { + /* + ** Next, check to see if this is our first time + ** through. + */ + + if (pbus->number == 0) + { + /* + ** It is our first time through. Thus, we must + ** reassign bus numbers to all Host Bridge + ** devices before probing. + */ + + ret_code = pci_alloc_hosts(); + } + } +#endif + + /* + ** Any errors yet? + */ + + if (ret_code == PCI_OK) + { + /* + ** Next, if no errors, do the initial call + ** to pci_probe_bus() to find all the devices + ** for each bus under the Host Bridge device. + */ + + if (pci_probe_bus(pbus, devfn) == PCI_OK) + { + /* + ** Next, set the Host Bridge node's + ** device structure. + */ + + pbus->self = pci_find_slot(pbus->number, devfn); + + /* + ** Configure all the devices and bridges. + */ + + pci_conf_bus(pbus); + + /* + ** Finally, ensure all the display devices + ** have been properly configured. + */ + + pci_conf_display(); + + /* + ** We've scanned the bus and so we know + ** all about what's on the other side of + ** any bridges that may be on this bus + ** plus any devices. + */ + + DBG("PCI: pci_scan_bus returning with max = %d\n", pbus->subordinate); + } + } + + /* + ** Return the subordinate bus number. + */ + + return (pbus->subordinate); +} diff -u -r --new-file linux/drivers/pci/pcisyms.c linux_mot/drivers/pci/pcisyms.c --- linux/drivers/pci/pcisyms.c Wed Dec 16 14:35:49 1998 +++ linux_mot/drivers/pci/pcisyms.c Tue Mar 16 22:11:22 1999 @@ -33,6 +33,9 @@ #ifdef CONFIG_PROC_FS EXPORT_SYMBOL(pci_proc_attach_device); EXPORT_SYMBOL(pci_proc_detach_device); +#ifdef CONFIG_PCI_SERVICES +EXPORT_SYMBOL(pci_proc_detach_bus); +#endif #endif /* Backward compatibility */ diff -u -r --new-file linux/drivers/pci/proc.c linux_mot/drivers/pci/proc.c --- linux/drivers/pci/proc.c Mon Aug 24 13:14:10 1998 +++ linux_mot/drivers/pci/proc.c Fri Jul 9 13:51:04 1999 @@ -9,9 +9,12 @@ #include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <linux/pci.h> +#ifdef CONFIG_PCI_SERVICES +#include <linux/pci_res.h> +#endif #include <linux/proc_fs.h> -#include <linux/init.h> #include <asm/uaccess.h> #include <asm/byteorder.h> @@ -195,6 +198,77 @@ return nbytes; } +#ifdef CONFIG_PCI_SERVICES +static int +proc_node_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + unsigned char *nodep; + unsigned char *buf; + unsigned char val; + + unsigned int cnt; + + int ret_code; + + struct pci_dev *pdev; + + struct pci_node node_info; + + if (capable(CAP_SYS_ADMIN) == 0) + return (-EPERM); + + cnt = sizeof(struct pci_node); + + buf = (unsigned char *)arg; + + if (access_ok(VERIFY_READ, buf, cnt) == 0) + return (-EINVAL); + + for (nodep = (unsigned char *)&node_info; cnt > 0; --cnt, ++nodep, ++buf) + { + __get_user(val, buf); + + *nodep = val; + } + + printk(KERN_INFO "PCI proc: cmd = %d, node bus = %d, devfn = 0x%02x\n", + node_info.cmd, node_info.number, node_info.devfn); + + switch (node_info.cmd) + { + case PCI_NODE_NOP: + { + if ((pdev = pci_find_slot(node_info.number, node_info.devfn)) == NULL) + return (-ENOENT); + break; + } + + case PCI_NODE_ADD: + { + if ((ret_code = pci_add_node(node_info.number, node_info.devfn)) != PCI_OK) + return (ret_code); + + break; + } + + case PCI_NODE_DEL: + { + if ((ret_code = pci_del_node(node_info.number, node_info.devfn)) != PCI_OK) + return (ret_code); + + break; + } + + default: + { + return (-EINVAL); + } + } + + return (0); +} +#endif /* CONFIG_PCI_SERVICES */ + static struct file_operations proc_bus_pci_operations = { proc_bus_pci_lseek, proc_bus_pci_read, @@ -229,6 +303,42 @@ NULL /* permission */ }; +#ifdef CONFIG_PCI_SERVICES +static struct file_operations proc_node_pci_operations = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + proc_node_pci_ioctl, + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +static struct inode_operations proc_node_pci_inode_operations = { + &proc_node_pci_operations, /* default base directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; +#endif /* CONFIG_PCI_SERVICES */ + int get_pci_dev_info(char *buf, char **start, off_t pos, int count, int wr) { @@ -282,6 +392,9 @@ }; static struct proc_dir_entry *proc_bus_pci_dir; +#ifdef CONFIG_PCI_SERVICES +static struct proc_dir_entry *proc_node_pci; +#endif int pci_proc_attach_device(struct pci_dev *dev) { @@ -318,6 +431,21 @@ return 0; } +#ifdef CONFIG_PCI_SERVICES +int pci_proc_detach_bus(struct pci_bus *bus) +{ + struct proc_dir_entry *e; + + if ((e = bus->procdir)) { + if (e->count) + return -EBUSY; + remove_proc_entry(e->name, proc_bus_pci_dir); + bus->procdir = NULL; + } + return 0; +} +#endif + __initfunc(void proc_bus_pci_add(struct pci_bus *bus)) { while (bus) { @@ -337,7 +465,13 @@ return; proc_bus_pci_dir = create_proc_entry("pci", S_IFDIR, proc_bus); proc_register(proc_bus_pci_dir, &proc_pci_devices); +#ifndef CONFIG_PCI_SERVICES proc_bus_pci_add(&pci_root); +#else + proc_node_pci = create_proc_entry("node", S_IFREG | S_IRUGO | S_IWUSR, proc_bus_pci_dir); + proc_node_pci->ops = &proc_node_pci_inode_operations; + proc_node_pci->size = sizeof(struct pci_node); +#endif #ifdef CONFIG_PCI_OLD_PROC proc_old_pci_init(); diff -u -r --new-file linux/include/linux/pci.h linux_mot/include/linux/pci.h --- linux/include/linux/pci.h Wed Jun 9 16:59:34 1999 +++ linux_mot/include/linux/pci.h Fri Jul 9 13:01:40 1999 @@ -794,6 +794,9 @@ #define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000 #define PCI_DEVICE_ID_EF_ATM_ASIC 0x0002 +#define PCI_VENDOR_ID_IDT 0x111d +#define PCI_DEVICE_ID_IDT_NICSTAR 0x0001 + #define PCI_VENDOR_ID_FORE 0x1127 #define PCI_DEVICE_ID_FORE_PCA200PC 0x0210 #define PCI_DEVICE_ID_FORE_PCA200E 0x0300 @@ -1132,10 +1134,39 @@ #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) #define PCI_FUNC(devfn) ((devfn) & 0x07) +#ifdef CONFIG_PCI_SERVICES +/* + * This is the add/delete node structure passed with the ioctl(). + */ + +#define PCI_NODE_NOP 0 /* NOP ioctl command */ +#define PCI_NODE_ADD 1 /* Add node ioctl command */ +#define PCI_NODE_DEL 2 /* Delete node ioctl command */ + +struct pci_node { + unsigned int cmd; /* command */ + unsigned int number; /* bus number */ + unsigned int devfn; /* encoded device & function index */ +}; +#endif + #ifdef __KERNEL__ #include <linux/types.h> #include <linux/config.h> +#ifdef CONFIG_PCI_SERVICES +/* + * There is one pci_res structure for each device. This + * structure holds the alignment, type, and size. + */ +struct pci_res { + struct pci_res *next; + unsigned int type; + unsigned long align; + unsigned long size; + unsigned long baddr; +}; +#endif /* * There is one pci_dev structure for each slot-number/function-number @@ -1173,6 +1204,13 @@ */ unsigned long base_address[6]; unsigned long rom_address; + +#ifdef CONFIG_PCI_SERVICES + /* + * Resources for each BAR. + */ + struct pci_res resources[6]; +#endif }; struct pci_bus { @@ -1190,10 +1228,25 @@ unsigned char primary; /* number of primary bridge */ unsigned char secondary; /* number of secondary bridge */ unsigned char subordinate; /* max number of subordinate buses */ + +#ifdef CONFIG_PCI_SERVICES + /* + * Resources for the node + */ + struct pci_res resources[4]; + + struct pci_res *res_head_io; /* PCI I/O space */ + struct pci_res *res_head_mem; /* PCI memory space */ + struct pci_res *res_head_mem20; /* PCI 20-bit memory space */ + struct pci_res *res_head_mempf; /* PCI prefetch memory space */ +#endif }; extern struct pci_bus pci_root; /* root bus */ extern struct pci_dev *pci_devices; /* list of all devices */ +#ifdef CONFIG_PCI_SERVICES +extern int pci_reverse; +#endif /* * Error values that may be returned by the PCI bios. @@ -1245,6 +1298,9 @@ int get_pci_list(char *buf); int pci_proc_attach_device(struct pci_dev *dev); int pci_proc_detach_device(struct pci_dev *dev); +#ifdef CONFIG_PCI_SERVICES +int pci_proc_detach_bus(struct pci_bus *bus); +#endif struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, struct pci_dev *from); struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from); diff -u -r --new-file linux/include/linux/pci_res.h linux_mot/include/linux/pci_res.h --- linux/include/linux/pci_res.h Wed Dec 31 17:00:00 1969 +++ linux_mot/include/linux/pci_res.h Fri Jul 9 13:02:00 1999 @@ -0,0 +1,208 @@ +/* +** PCI resource definitions and function prototypes +*/ + +#ifndef LINUX_PCI_RES_H +#define LINUX_PCI_RES_H + +/* +** PCI Bus Number/Level Definitions +** +** MAX_PCI_NODES - Maximum Number of Bus Nodes +** MAX_PCI_LEVELS - Maximum Number of Bus Levels +*/ + +#define BUSLVL3_NODES CONFIG_PCI_BUSLVL3_NODES + +#define BUSLVL2_NODES ( CONFIG_PCI_BUSLVL2_NODES \ + + ( CONFIG_PCI_BUSLVL2_NODES * BUSLVL3_NODES ) ) + +#define BUSLVL1_NODES ( CONFIG_PCI_BUSLVL1_NODES \ + + ( CONFIG_PCI_BUSLVL1_NODES * BUSLVL2_NODES ) ) + +#define BUSLVL0_NODES ( CONFIG_PCI_BUSLVL0_NODES \ + + ( CONFIG_PCI_BUSLVL0_NODES * BUSLVL1_NODES ) ) + +#ifndef CONFIG_PCI_AGP_BRIDGE +#define MAX_PCI_NODES BUSLVL0_NODES +#else +#define MAX_PCI_NODES ( BUSLVL0_NODES + 1 ) +#endif + +#define MAX_PCI_LEVELS 4 + +/* +** PCI IRQ Pin Definitions +** +*/ + +#define PCI_INT_NONE 0 +#define PCI_INTA 1 +#define PCI_INTB 2 +#define PCI_INTC 3 +#define PCI_INTD 4 + +/* +** PCI Memory and I/O Space Alignment Definitions +** +** PCI_ALIGN_IO - PCI I/O Alignment +** PCI_ALIGN_MEM - PCI Memory Alignment +** PCI_ALIGN_MEM20 - PCI 20-bit Memory Alignment +** +** PCI_ALIGN_ADDR - Macro to Align PCI Memory or I/O Address +*/ + +#define PCI_ALIGN_IO 0x00001000 +#define PCI_ALIGN_MEM 0x00100000 +#define PCI_ALIGN_MEM20 0x00000010 + +#define PCI_ALIGN_ADDR(addr,align) ((addr + (align - 1)) & ~(align - 1)) + +/* +** PCI Resource Array Indexes +** +** PCI_RES_INDX_IO - PCI I/O Resource Array Index +** PCI_RES_INDX_MEM - PCI Memory Resource Array Index +** PCI_RES_INDX_MEM20 - PCI 20-bit Memory Resource Array Index +** PCI_RES_INDX_MEMPF - PCI Prefetch Memory Resource Array Index +*/ + +#define PCI_RES_INDX_IO 0 +#define PCI_RES_INDX_MEM 1 +#define PCI_RES_INDX_MEM20 2 +#define PCI_RES_INDX_MEMPF 3 + +/* +** PCI Resource Types +** +** PCI_RES_TYPE_NOTUSED - Unused PCI Resouce Type +** +** PCI_RES_TYPE_IO - PCI I/O Resource Type +** PCI_RES_TYPE_MEM - PCI Memory Resource Type +** PCI_RES_TYPE_MEM20 - PCI 20-bit Memory Resource Type +** PCI_RES_TYPE_MEMPF - PCI Prefetch Memory Resource Type +** +** PCI_RES_ADDR_START - Starting Address +** PCI_RES_ADDR_END - Ending Address +*/ + +#define PCI_RES_TYPE_NOTUSED 0 +#define PCI_RES_TYPE_IO 1 +#define PCI_RES_TYPE_MEM 2 +#define PCI_RES_TYPE_MEM20 3 +#define PCI_RES_TYPE_MEMPF 4 + +#define PCI_RES_ADDR_START 0 +#define PCI_RES_ADDR_END 1 + +/* +** PCI Bus/Device/Function +** +** MAX_PCI_BUS - Maximum PCI Bus Number +** MAX_PCI_DEV - Maximum PCI Device Number +** MAX_PCI_FUNC - Maximum PCI Function Number +*/ + +#define MAX_PCI_BUS 255 +#define MAX_PCI_DEV 31 +#define MAX_PCI_FUNC 7 + +/* +** Miscellaneous Definitions +** +** PCI_OK - Function Return Code - OK +** PCI_ERR - Function Return Code - Error +** +** PCI_BUS_NOT_ALLOC - PCI Bus Number Not Allocated +** PCI_BUS_ALLOC - PCI Bus Number Allocated +** +** NUM_BARS - Number of Base Address Registers +*/ + +#define PCI_OK 0 +#define PCI_ERR -1 + +#define PCI_BUS_NOT_ALLOC 0 +#define PCI_BUS_ALLOC 1 + +#define NUM_BARS 6 + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* +** PCI bus number/device resource allocation arrays +** and functions. +*/ + +int pci_alloc_businit(void) __init; + +#if (CONFIG_PCI_BUSLVL0_NODES > 1) +int pci_alloc_hosts(void) __init; +#endif + +#ifdef CONFIG_PCI_AGP_BRIDGE +int pci_agp_bridge(struct pci_bus *pbus, unsigned int devfn); +#endif + +int pci_alloc_busnum(struct pci_bus *pbus, unsigned int devfn); +int pci_alloc_busres(struct pci_bus *pbus); +int pci_alloc_devres(struct pci_dev *pdev, struct pci_res *pres, int bar); + +int pci_free_busnum(struct pci_bus *pbus); +int pci_free_busres(struct pci_bus *pbus); +int pci_free_devres(struct pci_dev *pdev, struct pci_res *pres); + +/* +** PCI bus/device node management functions. +*/ + +int pci_add_dev(struct pci_bus *pbus, unsigned int devfn, struct pci_dev **pdev); +int pci_add_bus(struct pci_bus *pbus, struct pci_dev *pdev, struct pci_bus **child); +int pci_add_node(unsigned int number, unsigned int devfn); + +int pci_del_dev(struct pci_dev *pdev); +int pci_del_bus(struct pci_bus *pbus); +int pci_del_node(unsigned int number, unsigned int devfn); + +/* +** PCI bus/device configuration functions. +*/ + +unsigned int pci_pirqs[4]; + +int pci_get_bars(struct pci_dev *pdev, int *num_bars); +int pci_conf_dev(struct pci_dev *pdev); +int pci_conf_bus(struct pci_bus *pbus); +void pci_conf_display(void); + +/* +** PCI bus scan/probe functions. +*/ +int pci_find_host(unsigned int number, unsigned int *devfn) __init; +int pci_kern_err(char *func, char *err_msg); +int pci_valid_devid(unsigned int number, unsigned int devfn); +int pci_multi_func(unsigned int number, unsigned int devfn); +int pci_probe_bus(struct pci_bus *pbus, unsigned int devfn); + +unsigned int pci_scan_bus(struct pci_bus *pbus) __init; + +/* +** PCI interrupt configuration function. +*/ + +#ifdef CONFIG_PCI_PIRQ_UPDATE +int pci_hwints_update_pirqs(void) __init; +#endif +void pci_hwints_getirq(struct pci_dev *pdev); + +#endif /* LINUX_PCI_RES_H */ | |