diff -u -r --new-file linux/Documentation/Configure.help ha/Documentation/Configure.help --- linux/Documentation/Configure.help Thu Nov 22 11:52:44 2001 +++ ha/Documentation/Configure.help Thu Dec 13 13:04:17 2001 @@ -23938,6 +23938,741 @@ would like kernel messages to be formatted into GDB $O packets so that GDB prints them as program output, say 'Y'. +Kernel Event Reporting Broker support +CONFIG_EVENT_BROKER + The kernel event broker drivers is an implementation of the many + subscribers to one sender eventing system. It has been added to + support cPCI hot swap but may be useful for many other systems + also. + + Select Y here if you wish to have it included. The cPCI driver + will automatically set this config parameter. + +Compact PCI Bus Hot Swap Support +CONFIG_CPCI_HOTSWAP + Most Compact PCI (cPCI) chassis are capable of insertion and removal + of devices while powered on. This entails knowing many things about + the cPCI bus configuration. Selecting this paramater enables the + core code to support this functionality and brings up a list of + supported configurations. + + Select Y here if you wish to support Hot Swap on the cPCI busses. + +Host and Compact PCI Chassis Type +CONFIG_MOT_GEN + This option selects the particular Host Slot CPU board support + and the paticular cPCI chassis support. + + The CONFIG_MOT_GEN option selects functionality to enable either the + Motorola MPC750 (Mesquite) or CPV5350 CPU modules to perform hot insertion + and removal of cPCI boards. It software selects between support + for the Motorola 82XX HA cPCI chassis series and support for standard + Hot Swap cPCI chassis scanned in decending order. + + The CONFIG_ZT_5550 option selects functionality to enable the Ziatech + 5550 Host slot CPU modules to perform hot insertion and removal of cPCI + boards. It Currently configures the Ziatech 5083 cPCI HA chassis. + + A menu with these selections will appear when CONFIG_CPCI_HOTSWAP has + been selected. Choose the configuration of CPU and chassis desired. + +Compact PCI IO Sizes for 82XX chassis Slot 1 +CONFIG_MOT_82XX_SLOT1_IO_SIZE + Select the amount of space to reserve for PCI IO on slot one of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 2 +CONFIG_MOT_82XX_SLOT2_IO_SIZE + Select the amount of space to reserve for PCI IO on slot two of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 3 +CONFIG_MOT_82XX_SLOT3_IO_SIZE + Select the amount of space to reserve for PCI IO on slot three of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 4 +CONFIG_MOT_82XX_SLOT4_IO_SIZE + Select the amount of space to reserve for PCI IO on slot four of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 5 +CONFIG_MOT_82XX_SLOT5_IO_SIZE + Select the amount of space to reserve for PCI IO on slot five of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 6 +CONFIG_MOT_82XX_SLOT6_IO_SIZE + Select the amount of space to reserve for PCI IO on slot six of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 11 +CONFIG_MOT_82XX_SLOT11_IO_SIZE + Select the amount of space to reserve for PCI IO on slot eleven of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 12 +CONFIG_MOT_82XX_SLOT12_IO_SIZE + Select the amount of space to reserve for PCI IO on slot twelve of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 13 +CONFIG_MOT_82XX_SLOT13_IO_SIZE + Select the amount of space to reserve for PCI IO on slot thirteen of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 14 +CONFIG_MOT_82XX_SLOT14_IO_SIZE + Select the amount of space to reserve for PCI IO on slot fourteen of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 15 +CONFIG_MOT_82XX_SLOT15_IO_SIZE + Select the amount of space to reserve for PCI IO on slot fifteen of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 82XX chassis Slot 16 +CONFIG_MOT_82XX_SLOT16_IO_SIZE + Select the amount of space to reserve for PCI IO on slot sixteen of a + Motorola 82XX cPCI chassis. Space is indicated in kilobytes and must + be allocated on 4K boundries. Each slot should not require more than + 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 1 +CONFIG_MOT_82XX_SLOT1_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + one of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 2 +CONFIG_MOT_82XX_SLOT2_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + two of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 3 +CONFIG_MOT_82XX_SLOT3_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + three of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 4 +CONFIG_MOT_82XX_SLOT4_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + four of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 5 +CONFIG_MOT_82XX_SLOT5_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + five of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 6 +CONFIG_MOT_82XX_SLOT6_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + six of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 11 +CONFIG_MOT_82XX_SLOT11_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + eleven of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 12 +CONFIG_MOT_82XX_SLOT12_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + twelve of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 13 +CONFIG_MOT_82XX_SLOT13_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + thirteen of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 14 +CONFIG_MOT_82XX_SLOT14_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + fourteen of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 15 +CONFIG_MOT_82XX_SLOT15_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + fifteen of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 82XX chassis Slot 16 +CONFIG_MOT_82XX_SLOT16_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot + sixteen of a Motorola 82XX cPCI chassis. Space is indicated in megabytes + and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for Generic Hot Swap chassis Slot 1 +CONFIG_MOT_GEN_SLOT1_IO_SIZE + Select the amount of space to reserve for PCI IO on slot one of a + standard Hot Swap cPCI chassis with either a Motorola MCP750 + or CPV5350 host slot CPU board. Space is indicated in kilobytes and + must be allocated on 4K boundries. Each slot should not require more + than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for Generic Hot Swap chassis Slot 2 +CONFIG_MOT_GEN_SLOT2_IO_SIZE + Select the amount of space to reserve for PCI IO on slot two of a + standard Hot Swap cPCI chassis with either a Motorola MCP750 + or CPV5350 host slot CPU board. Space is indicated in kilobytes and + must be allocated on 4K boundries. Each slot should not require more + than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for Generic Hot Swap chassis Slot 3 +CONFIG_MOT_GEN_SLOT3_IO_SIZE + Select the amount of space to reserve for PCI IO on slot three of a + standard Hot Swap cPCI chassis with either a Motorola MCP750 + or CPV5350 host slot CPU board. Space is indicated in kilobytes and + must be allocated on 4K boundries. Each slot should not require more + than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for Generic Hot Swap chassis Slot 4 +CONFIG_MOT_GEN_SLOT4_IO_SIZE + Select the amount of space to reserve for PCI IO on slot four of a + standard Hot Swap cPCI chassis with either a Motorola MCP750 + or CPV5350 host slot CPU board. Space is indicated in kilobytes and + must be allocated on 4K boundries. Each slot should not require more + than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for Generic Hot Swap chassis Slot 5 +CONFIG_MOT_GEN_SLOT5_IO_SIZE + Select the amount of space to reserve for PCI IO on slot five of a + standard Hot Swap cPCI chassis with either a Motorola MCP750 + or CPV5350 host slot CPU board. Space is indicated in kilobytes and + must be allocated on 4K boundries. Each slot should not require more + than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for Generic Hot Swap chassis Slot 6 +CONFIG_MOT_GEN_SLOT6_IO_SIZE + Select the amount of space to reserve for PCI IO on slot six of a + standard Hot Swap cPCI chassis with either a Motorola MCP750 + or CPV5350 host slot CPU board. Space is indicated in kilobytes and + must be allocated on 4K boundries. Each slot should not require more + than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for Generic Hot Swap chassis Slot 7 +CONFIG_MOT_GEN_SLOT7_IO_SIZE + Select the amount of space to reserve for PCI IO on slot seven of a + standard Hot Swap cPCI chassis with either a Motorola MCP750 + or CPV5350 host slot CPU board. Space is indicated in kilobytes and + must be allocated on 4K boundries. Each slot should not require more + than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for Generic Hot Swap chassis Slot 1 +CONFIG_MOT_GEN_SLOT1_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot one + of a standared Hot Swap cPCI chassis either a Motorola MCP750 or + CPV5350 host slot CPU board. Space is indicated in megabytes and must + be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for Generic Hot Swap chassis Slot 2 +CONFIG_MOT_GEN_SLOT2_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot tow + of a standared Hot Swap cPCI chassis either a Motorola MCP750 or + CPV5350 host slot CPU board. Space is indicated in megabytes and must + be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for Generic Hot Swap chassis Slot 3 +CONFIG_MOT_GEN_SLOT3_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot three + of a standared Hot Swap cPCI chassis either a Motorola MCP750 or + CPV5350 host slot CPU board. Space is indicated in megabytes and must + be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for Generic Hot Swap chassis Slot 4 +CONFIG_MOT_GEN_SLOT4_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot four + of a standared Hot Swap cPCI chassis either a Motorola MCP750 or + CPV5350 host slot CPU board. Space is indicated in megabytes and must + be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for Generic Hot Swap chassis Slot 5 +CONFIG_MOT_GEN_SLOT5_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot five + of a standared Hot Swap cPCI chassis either a Motorola MCP750 or + CPV5350 host slot CPU board. Space is indicated in megabytes and must + be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for Generic Hot Swap chassis Slot 6 +CONFIG_MOT_GEN_SLOT6_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot six + of a standared Hot Swap cPCI chassis either a Motorola MCP750 or + CPV5350 host slot CPU board. Space is indicated in megabytes and must + be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for Generic Hot Swap chassis Slot 7 +CONFIG_MOT_GEN_SLOT7_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot seven + of a standared Hot Swap cPCI chassis either a Motorola MCP750 or + CPV5350 host slot CPU board. Space is indicated in megabytes and must + be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 1 +CONFIG_ZIA_5083_SLOT1_IO_SIZE + Select the amount of space to reserve for PCI IO on slot one of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 2 +CONFIG_ZIA_5083_SLOT2_IO_SIZE + Select the amount of space to reserve for PCI IO on slot towof a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 3 +CONFIG_ZIA_5083_SLOT3_IO_SIZE + Select the amount of space to reserve for PCI IO on slot three of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 4 +CONFIG_ZIA_5083_SLOT4_IO_SIZE + Select the amount of space to reserve for PCI IO on slot four of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 5 +CONFIG_ZIA_5083_SLOT5_IO_SIZE + Select the amount of space to reserve for PCI IO on slot five of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 6 +CONFIG_ZIA_5083_SLOT6_IO_SIZE + Select the amount of space to reserve for PCI IO on slot six of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 11 +CONFIG_ZIA_5083_SLOT11_IO_SIZE + Select the amount of space to reserve for PCI IO on slot eleven of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 12 +CONFIG_ZIA_5083_SLOT12_IO_SIZE + Select the amount of space to reserve for PCI IO on slot twelve of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 13 +CONFIG_ZIA_5083_SLOT13_IO_SIZE + Select the amount of space to reserve for PCI IO on slot thirteen of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 14 +CONFIG_ZIA_5083_SLOT14_IO_SIZE + Select the amount of space to reserve for PCI IO on slot fourteen of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 15 +CONFIG_ZIA_5083_SLOT15_IO_SIZE + Select the amount of space to reserve for PCI IO on slot fifteen of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI IO Sizes for 5083 chassis Slot 16 +CONFIG_ZIA_5083_SLOT16_IO_SIZE + Select the amount of space to reserve for PCI IO on slot sixteen of a + Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. Space + is indicated in kilobytes and must be allocated on 4K boundries. Each + slot should not require more than 8K under most circumstance. + + A limiting factor to watch for is allocating IO space on most Intel + X86 architectures. The total IO space allocated to the cPCI bus + cannot exceed 48K. On the Motorola and Ziatech HA chassis this leaves + only 4K of space for most cPCI slots. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 1 +CONFIG_ZIA_5083_SLOT1_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot one + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 2 +CONFIG_ZIA_5083_SLOT2_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot two + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 3 +CONFIG_ZIA_5083_SLOT3_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot three + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 4 +CONFIG_ZIA_5083_SLOT4_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot four + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 5 +CONFIG_ZIA_5083_SLOT5_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot five + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 6 +CONFIG_ZIA_5083_SLOT6_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot six + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 11 +CONFIG_ZIA_5083_SLOT11_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot eleven + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 12 +CONFIG_ZIA_5083_SLOT12_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot twelve + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 13 +CONFIG_ZIA_5083_SLOT13_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot thirteen + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 14 +CONFIG_ZIA_5083_SLOT14_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot fourteen + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 15 +CONFIG_ZIA_5083_SLOT15_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot fifteen + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + +Compact PCI Memory Sizes for 5083 chassis Slot 16 +CONFIG_ZIA_5083_SLOT16_MEM_SIZE + Select the amount of space to reserve for PCI Memory BARs on slot sixteen + of a Ziatech 5083 cPCI chassis with a Ziatech 5550 host slot CPU board. + Space is indicated in megabytes and must be allocated on 1M boundries. + + Set this selection to the value you wish to reserve. + + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -u -r --new-file linux/Makefile ha/Makefile --- linux/Makefile Mon Nov 26 06:29:17 2001 +++ ha/Makefile Thu Dec 13 13:04:49 2001 @@ -185,6 +185,9 @@ DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o +DRIVERS-$(CONFIG_CPCI_HOTSWAP) += drivers/ha/cpci/cpci.o +DRIVERS-$(CONFIG_EVENT_BROKER) += drivers/ha/event/event.o + DRIVERS := $(DRIVERS-y) diff -u -r --new-file linux/arch/i386/config.in ha/arch/i386/config.in --- linux/arch/i386/config.in Mon Nov 12 12:58:08 2001 +++ ha/arch/i386/config.in Thu Dec 13 13:06:09 2001 @@ -392,6 +392,12 @@ source drivers/usb/Config.in +mainmenu_option next_comment +comment 'High Availability features' +bool 'Kernel Event Reporting Broker support' CONFIG_EVENT_BROKER +source drivers/ha/Config.in +endmenu + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in fi diff -u -r --new-file linux/arch/i386/kernel/pci-pc.c ha/arch/i386/kernel/pci-pc.c --- linux/arch/i386/kernel/pci-pc.c Fri Nov 9 14:58:02 2001 +++ ha/arch/i386/kernel/pci-pc.c Thu Dec 13 13:03:13 2001 @@ -12,6 +12,8 @@ #include #include +#include + #include #include @@ -23,6 +25,11 @@ struct pci_bus *pci_root_bus = NULL; struct pci_ops *pci_root_ops = NULL; +#ifdef CONFIG_CPCI_HOTSWAP +extern struct list_head pci_root_buses; +extern struct pci_controller* hose_head; +#endif /* CONFIG_CPCI_HOTSWAP */ + int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL; int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL; @@ -1196,6 +1203,10 @@ return; } +#ifdef CONFIG_CPCI_HOTSWAP + CpciFindBridges(); +#endif /* CONFIG_CPCI_HOTSWAP */ + printk("PCI: Probing PCI hardware\n"); pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL); @@ -1271,3 +1282,82 @@ pcibios_enable_irq(dev); return 0; } + +#ifdef CONFIG_CPCI_HOTSWAP +struct pci_controller* +pci_bus_to_hose(int bus) +{ + struct pci_controller* hose = hose_head; + + for (; hose; hose = hose->next) + if (bus >= hose->first_busno && bus <= hose->last_busno) + return hose; + return NULL; +} + +/* + * * Null PCI config access functions, for the case when we can't + * * find a hose. + * */ +#define NULL_PCI_OP(rw, size, type) \ +static int \ +null_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ +{ \ + return PCIBIOS_DEVICE_NOT_FOUND; \ +} + +NULL_PCI_OP(read, byte, u8 *) +NULL_PCI_OP(read, word, u16 *) +NULL_PCI_OP(read, dword, u32 *) +NULL_PCI_OP(write, byte, u8) +NULL_PCI_OP(write, word, u16) +NULL_PCI_OP(write, dword, u32) + +static struct pci_ops null_pci_ops = +{ + null_read_config_byte, + null_read_config_word, + null_read_config_dword, + null_write_config_byte, + null_write_config_word, + null_write_config_dword +}; + +/* + * These functions are used early on before PCI scanning is done + * and all of the pci_dev and pci_bus structures have been created. + */ +static struct pci_dev * +fake_pci_dev(struct pci_controller *hose, int busnr, int devfn) +{ + static struct pci_dev dev; + static struct pci_bus bus; + + if (hose == 0) { + hose = pci_bus_to_hose(busnr); + if (hose == 0) + printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr); + } + dev.bus = &bus; + dev.sysdata = hose; + dev.devfn = devfn; + bus.number = busnr; + bus.ops = hose? hose->ops: &null_pci_ops; + return &dev; +} + +#define EARLY_PCI_OP(rw, size, type) \ +int early_##rw##_config_##size(struct pci_controller *hose, int bus, \ + int devfn, int offset, type value) \ +{ \ + return pci_##rw##_config_##size(fake_pci_dev(hose, bus, devfn), \ + offset, value); \ +} + +EARLY_PCI_OP(read, byte, u8 *) +EARLY_PCI_OP(read, word, u16 *) +EARLY_PCI_OP(read, dword, u32 *) +EARLY_PCI_OP(write, byte, u8) +EARLY_PCI_OP(write, word, u16) +EARLY_PCI_OP(write, dword, u32) +#endif /* CONFIG_CPCI_HOTSWAP */ diff -u -r --new-file linux/drivers/Makefile ha/drivers/Makefile --- linux/drivers/Makefile Sun Nov 11 11:09:32 2001 +++ ha/drivers/Makefile Thu Dec 13 13:06:49 2001 @@ -47,4 +47,7 @@ subdir-$(CONFIG_BLUEZ) += bluetooth +subdir-$(CONFIG_CPCI_HOTSWAP) += ha +subdir-$(CONFIG_EVENT_BROKER) += ha/event + include $(TOPDIR)/Rules.make diff -u -r --new-file linux/drivers/ha/Config.in ha/drivers/ha/Config.in --- linux/drivers/ha/Config.in Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/Config.in Thu Dec 13 13:07:07 2001 @@ -0,0 +1,21 @@ +# +# Compact PCI chassis support code and drivers +# +bool 'Compact PCI Bus Hot Swap Support' CONFIG_CPCI_HOTSWAP + +if [ "$CONFIG_CPCI_HOTSWAP" = "y" ]; then + define_bool CONFIG_EVENT_BROKER y + + choice ' Host and Compact PCI Chassis Type' \ + " Motorola-MCP750-CPV5350 CONFIG_MOT_GEN \ + Ziatech-ZT5550 CONFIG_ZT_5550" + + if [ "$CONFIG_MOT_GEN" = "y" ]; then + source drivers/ha/cpci/Config.mot82XX.in + source drivers/ha/cpci/Config.mot_nonha.in + fi + + if [ "$CONFIG_ZT_5550" = "y" ]; then + source drivers/ha/cpci/Config.zia5083.in + fi +fi diff -u -r --new-file linux/drivers/ha/Makefile ha/drivers/ha/Makefile --- linux/drivers/ha/Makefile Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/Makefile Thu Dec 13 13:07:15 2001 @@ -0,0 +1,18 @@ +# +# Makefile for the Linux kernel device drivers. +# +# 15 Sep 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. +# + + +mod-subdirs := + +subdir-y := +subdir-m := + + +subdir-$(CONFIG_CPCI_HOTSWAP) += cpci + +include $(TOPDIR)/Rules.make + Binary files linux/drivers/ha/cpci/.mot82XXhsc.c.swp and ha/drivers/ha/cpci/.mot82XXhsc.c.swp differ diff -u -r --new-file linux/drivers/ha/cpci/Config.mot82XX.in ha/drivers/ha/cpci/Config.mot82XX.in --- linux/drivers/ha/cpci/Config.mot82XX.in Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/Config.mot82XX.in Thu Dec 13 13:03:13 2001 @@ -0,0 +1,70 @@ +# +# Compact PCI chassis support code and drivers +# +if [ "$CONFIG_PPC" = "y" ]; then + comment '' + comment 'Compact PCI IO Sizes for 82XX chassis (4K boundries required)' + int 'Slot 1' CONFIG_MOT_82XX_SLOT1_IO_SIZE 16 + int 'Slot 2' CONFIG_MOT_82XX_SLOT2_IO_SIZE 16 + int 'Slot 3' CONFIG_MOT_82XX_SLOT3_IO_SIZE 16 + int 'Slot 4' CONFIG_MOT_82XX_SLOT4_IO_SIZE 16 + int 'Slot 5' CONFIG_MOT_82XX_SLOT5_IO_SIZE 16 + int 'Slot 6' CONFIG_MOT_82XX_SLOT6_IO_SIZE 16 + + int 'Slot 11' CONFIG_MOT_82XX_SLOT11_IO_SIZE 16 + int 'Slot 12' CONFIG_MOT_82XX_SLOT12_IO_SIZE 16 + int 'Slot 13' CONFIG_MOT_82XX_SLOT13_IO_SIZE 16 + int 'Slot 14' CONFIG_MOT_82XX_SLOT14_IO_SIZE 16 + int 'Slot 15' CONFIG_MOT_82XX_SLOT15_IO_SIZE 16 + int 'Slot 16' CONFIG_MOT_82XX_SLOT16_IO_SIZE 16 + + comment '' + comment 'Compact PCI Memory Sizes for 82XX chassis (1M boundries required)' + int 'Slot 1' CONFIG_MOT_82XX_SLOT1_MEM_SIZE 64 + int 'Slot 2' CONFIG_MOT_82XX_SLOT2_MEM_SIZE 64 + int 'Slot 3' CONFIG_MOT_82XX_SLOT3_MEM_SIZE 64 + int 'Slot 4' CONFIG_MOT_82XX_SLOT4_MEM_SIZE 64 + int 'Slot 5' CONFIG_MOT_82XX_SLOT5_MEM_SIZE 64 + int 'Slot 6' CONFIG_MOT_82XX_SLOT6_MEM_SIZE 64 + + int 'Slot 11' CONFIG_MOT_82XX_SLOT11_MEM_SIZE 64 + int 'Slot 12' CONFIG_MOT_82XX_SLOT12_MEM_SIZE 64 + int 'Slot 13' CONFIG_MOT_82XX_SLOT13_MEM_SIZE 64 + int 'Slot 14' CONFIG_MOT_82XX_SLOT14_MEM_SIZE 64 + int 'Slot 15' CONFIG_MOT_82XX_SLOT15_MEM_SIZE 64 + int 'Slot 16' CONFIG_MOT_82XX_SLOT16_MEM_SIZE 64 +fi + +if [ "$CONFIG_X86" = "y" ]; then + comment '' + comment 'Compact PCI IO Sizes for 82XX chassis (4K boundries required)' + int 'Slot 1' CONFIG_MOT_82XX_SLOT1_IO_SIZE 4 + int 'Slot 2' CONFIG_MOT_82XX_SLOT2_IO_SIZE 4 + int 'Slot 3' CONFIG_MOT_82XX_SLOT3_IO_SIZE 4 + int 'Slot 4' CONFIG_MOT_82XX_SLOT4_IO_SIZE 4 + int 'Slot 5' CONFIG_MOT_82XX_SLOT5_IO_SIZE 4 + int 'Slot 6' CONFIG_MOT_82XX_SLOT6_IO_SIZE 4 + + int 'Slot 11' CONFIG_MOT_82XX_SLOT11_IO_SIZE 4 + int 'Slot 12' CONFIG_MOT_82XX_SLOT12_IO_SIZE 4 + int 'Slot 13' CONFIG_MOT_82XX_SLOT13_IO_SIZE 4 + int 'Slot 14' CONFIG_MOT_82XX_SLOT14_IO_SIZE 4 + int 'Slot 15' CONFIG_MOT_82XX_SLOT15_IO_SIZE 4 + int 'Slot 16' CONFIG_MOT_82XX_SLOT16_IO_SIZE 4 + + comment '' + comment 'Compact PCI Memory Sizes for 82XX chassis (1M boundries required)' + int 'Slot 1' CONFIG_MOT_82XX_SLOT1_MEM_SIZE 64 + int 'Slot 2' CONFIG_MOT_82XX_SLOT2_MEM_SIZE 64 + int 'Slot 3' CONFIG_MOT_82XX_SLOT3_MEM_SIZE 64 + int 'Slot 4' CONFIG_MOT_82XX_SLOT4_MEM_SIZE 64 + int 'Slot 5' CONFIG_MOT_82XX_SLOT5_MEM_SIZE 64 + int 'Slot 6' CONFIG_MOT_82XX_SLOT6_MEM_SIZE 64 + + int 'Slot 11' CONFIG_MOT_82XX_SLOT11_MEM_SIZE 64 + int 'Slot 12' CONFIG_MOT_82XX_SLOT12_MEM_SIZE 64 + int 'Slot 13' CONFIG_MOT_82XX_SLOT13_MEM_SIZE 64 + int 'Slot 14' CONFIG_MOT_82XX_SLOT14_MEM_SIZE 64 + int 'Slot 15' CONFIG_MOT_82XX_SLOT15_MEM_SIZE 64 + int 'Slot 16' CONFIG_MOT_82XX_SLOT16_MEM_SIZE 64 +fi diff -u -r --new-file linux/drivers/ha/cpci/Config.mot_nonha.in ha/drivers/ha/cpci/Config.mot_nonha.in --- linux/drivers/ha/cpci/Config.mot_nonha.in Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/Config.mot_nonha.in Thu Dec 13 13:03:13 2001 @@ -0,0 +1,46 @@ +# +# Compact PCI chassis support code and drivers +# +if [ "$CONFIG_PPC" = "y" ]; then + comment '' + comment 'Compact PCI IO Sizes for Generic Hot Swap chassis (4K boundries required)' + hex 'Slot 1' CONFIG_MOT_GEN_SLOT1_IO_SIZE 16 + hex 'Slot 2' CONFIG_MOT_GEN_SLOT2_IO_SIZE 16 + hex 'Slot 3' CONFIG_MOT_GEN_SLOT3_IO_SIZE 16 + hex 'Slot 4' CONFIG_MOT_GEN_SLOT4_IO_SIZE 16 + hex 'Slot 5' CONFIG_MOT_GEN_SLOT5_IO_SIZE 16 + hex 'Slot 6' CONFIG_MOT_GEN_SLOT6_IO_SIZE 16 + hex 'Slot 7' CONFIG_MOT_GEN_SLOT7_IO_SIZE 16 + + comment '' + comment 'Compact PCI Memory Sizes for Generic Hot Swap chassis (1M boundries required)' + hex 'Slot 1' CONFIG_MOT_GEN_SLOT1_MEM_SIZE 64 + hex 'Slot 2' CONFIG_MOT_GEN_SLOT2_MEM_SIZE 64 + hex 'Slot 3' CONFIG_MOT_GEN_SLOT3_MEM_SIZE 64 + hex 'Slot 4' CONFIG_MOT_GEN_SLOT4_MEM_SIZE 64 + hex 'Slot 5' CONFIG_MOT_GEN_SLOT5_MEM_SIZE 64 + hex 'Slot 6' CONFIG_MOT_GEN_SLOT6_MEM_SIZE 64 + hex 'Slot 7' CONFIG_MOT_GEN_SLOT7_MEM_SIZE 64 +fi + +if [ "$CONFIG_X86" = "y" ]; then + comment '' + comment 'Compact PCI IO Sizes for Generic Hot Swap chassis (4K boundries required)' + hex 'Slot 1' CONFIG_MOT_GEN_SLOT1_IO_SIZE 8 + hex 'Slot 2' CONFIG_MOT_GEN_SLOT2_IO_SIZE 8 + hex 'Slot 3' CONFIG_MOT_GEN_SLOT3_IO_SIZE 8 + hex 'Slot 4' CONFIG_MOT_GEN_SLOT4_IO_SIZE 8 + hex 'Slot 5' CONFIG_MOT_GEN_SLOT5_IO_SIZE 8 + hex 'Slot 6' CONFIG_MOT_GEN_SLOT6_IO_SIZE 8 + hex 'Slot 7' CONFIG_MOT_GEN_SLOT7_IO_SIZE 4 + + comment '' + comment 'Compact PCI Memory Sizes for Generic Hot Swap chassis (1M boundries required)' + hex 'Slot 1' CONFIG_MOT_GEN_SLOT1_MEM_SIZE 64 + hex 'Slot 2' CONFIG_MOT_GEN_SLOT2_MEM_SIZE 64 + hex 'Slot 3' CONFIG_MOT_GEN_SLOT3_MEM_SIZE 64 + hex 'Slot 4' CONFIG_MOT_GEN_SLOT4_MEM_SIZE 64 + hex 'Slot 5' CONFIG_MOT_GEN_SLOT5_MEM_SIZE 64 + hex 'Slot 6' CONFIG_MOT_GEN_SLOT6_MEM_SIZE 64 + hex 'Slot 7' CONFIG_MOT_GEN_SLOT7_MEM_SIZE 64 +fi diff -u -r --new-file linux/drivers/ha/cpci/Config.zia5083.in ha/drivers/ha/cpci/Config.zia5083.in --- linux/drivers/ha/cpci/Config.zia5083.in Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/Config.zia5083.in Thu Dec 13 13:03:13 2001 @@ -0,0 +1,34 @@ +# +# Compact PCI chassis support code and drivers +# +comment '' +comment 'Compact PCI IO Sizes for 5083 chassis (4K boundries required)' +int 'Slot 1' CONFIG_ZIA_5083_SLOT1_IO_SIZE 4 +int 'Slot 2' CONFIG_ZIA_5083_SLOT2_IO_SIZE 4 +int 'Slot 3' CONFIG_ZIA_5083_SLOT3_IO_SIZE 4 +int 'Slot 4' CONFIG_ZIA_5083_SLOT4_IO_SIZE 4 +int 'Slot 5' CONFIG_ZIA_5083_SLOT5_IO_SIZE 4 +int 'Slot 6' CONFIG_ZIA_5083_SLOT6_IO_SIZE 4 + +int 'Slot 11' CONFIG_ZIA_5083_SLOT11_IO_SIZE 4 +int 'Slot 12' CONFIG_ZIA_5083_SLOT12_IO_SIZE 4 +int 'Slot 13' CONFIG_ZIA_5083_SLOT13_IO_SIZE 4 +int 'Slot 14' CONFIG_ZIA_5083_SLOT14_IO_SIZE 4 +int 'Slot 15' CONFIG_ZIA_5083_SLOT15_IO_SIZE 4 +int 'Slot 16' CONFIG_ZIA_5083_SLOT16_IO_SIZE 4 + +comment '' +comment 'Compact PCI Memory Sizes for 5083 chassis (1M boundries required)' +int 'Slot 1' CONFIG_ZIA_5083_SLOT1_MEM_SIZE 64 +int 'Slot 2' CONFIG_ZIA_5083_SLOT2_MEM_SIZE 64 +int 'Slot 3' CONFIG_ZIA_5083_SLOT3_MEM_SIZE 64 +int 'Slot 4' CONFIG_ZIA_5083_SLOT4_MEM_SIZE 64 +int 'Slot 5' CONFIG_ZIA_5083_SLOT5_MEM_SIZE 64 +int 'Slot 6' CONFIG_ZIA_5083_SLOT6_MEM_SIZE 64 + +int 'Slot 11' CONFIG_ZIA_5083_SLOT11_MEM_SIZE 64 +int 'Slot 12' CONFIG_ZIA_5083_SLOT12_MEM_SIZE 64 +int 'Slot 13' CONFIG_ZIA_5083_SLOT13_MEM_SIZE 64 +int 'Slot 14' CONFIG_ZIA_5083_SLOT14_MEM_SIZE 64 +int 'Slot 15' CONFIG_ZIA_5083_SLOT15_MEM_SIZE 64 +int 'Slot 16' CONFIG_ZIA_5083_SLOT16_MEM_SIZE 64 diff -u -r --new-file linux/drivers/ha/cpci/Makefile ha/drivers/ha/cpci/Makefile --- linux/drivers/ha/cpci/Makefile Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/Makefile Thu Dec 13 13:03:13 2001 @@ -0,0 +1,19 @@ +# +# Makefile for the Compact PCI Chassis support drivers. +# + +O_TARGET := cpci.o + +obj-y := cpci_core.o cpci_enum.o cpci_debug.o piphs.o +obj-m := +obj-n := +obj- := + +export-objs := cpci_core.o + +obj-$(CONFIG_MOT_GEN) += mot82XXhsc.o mot_enum.o mot_cpci.o +obj-$(CONFIG_ZT_5550) += pdphs_zt5550.o zia5083cpci.o + + +include $(TOPDIR)/Rules.make + diff -u -r --new-file linux/drivers/ha/cpci/cpci_core.c ha/drivers/ha/cpci/cpci_core.c --- linux/drivers/ha/cpci/cpci_core.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/cpci_core.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,1220 @@ +/* + * cpci_core.c + * + * Core control routines for cPCI control. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpci_core.h" +#include "phs.h" + +#define MODVERSIONS + +/* Prototypes for internal functionality. */ +int CpciAddBus(int); +int CpciDelBus(int, int); +int CpciAddSlot(int); +int CpciDelSlot(int); +int CpciFillInSlotInfo(CpciIoctlSlotInfo *); +void CpciHandleNextEnum(void *); +int CpciGetAsnycReq(unsigned long); +int CpciSendAsyncResult(unsigned long); +void CpciFindDriver(struct pci_dev *); +char *CpciGetName(struct pci_dev *); + +void CpciSendAddSlotFail(int, int, int); + +/* Prototypes for device dependant init functions. */ +#ifdef CONFIG_MOT_GEN +void motCpci_init(void); +void motCpci_find_bridges(void); +#endif +#ifdef CONFIG_MOT_GENERIC +void motGenCpci_init(void); +void motGenCpci_find_bridges(void); +#endif +#ifdef CONFIG_ZT_5550 +void zia5083cpci_init(void); +void zia5083cpci_find_bridges(void); +#endif + +/* Linux Driver prototypes. */ +static int cpci_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +static int cpci_open(struct inode *, struct file *); +static int cpci_release(struct inode *, struct file *); + +typedef struct _CpciOpenDevQ { + struct pci_dev *Dev; + struct _CpciOpenDevQ *Next; +} CpciOpenDevQ; + +static struct file_operations cpci_fops = { + ioctl: cpci_ioctl, + open: cpci_open, + release: cpci_release, +}; + +/* Data structure declaration. */ +int CpciMajor; +CpciFunc *CpciFunctions; +CpciNodeInfo *CpciBuses; +CpciNodeInfo *CpciSlots; +CpciInfo *CpciInfos; + +int CpciEventId; +int CpciHsiEventClass; + +int CpciOpenCount; +CpciOpenDevQ *CpciOpenDevHead = NULL; + +wait_queue_head_t CpciHandleEnumWaitQ; +struct timer_list CpciHandleEnumTimeOut; +void CpciHandleEnumTimeOutFunc(unsigned long); + +spinlock_t CpciPciAccessLock = SPIN_LOCK_UNLOCKED; + +extern struct list_head pci_drivers; + +/* + * Init function. Called after first setup of pci bus. + */ +int +cpci_init(void) +{ + if ((CpciMajor = register_chrdev(0, "cPCI", &cpci_fops)) < 0) { + printk("Cound not register cPCI driver\n"); + return -ENODEV; + } + + /* Init controls for the HandleNextEnum timeout sequence. */ + init_waitqueue_head(&CpciHandleEnumWaitQ); + init_timer(&CpciHandleEnumTimeOut); + CpciHandleEnumTimeOut.function = CpciHandleEnumTimeOutFunc; + + /* Register to send and receive events */ + CpciEventId = EventRegisterId("cPCI"); + + /* Register an event class for the cPCI hot swap events */ + EventRegisterEventClass("cPCI_Hsi", &CpciHsiEventClass); + +#ifdef CONFIG_MOT_GEN + motCpci_init(); +#endif +#ifdef CONFIG_MOT_GENERIC + motGenCpci_init(); +#endif +#ifdef CONFIG_ZT_5550 + zia5083cpci_init(); +#endif + /* Register the enum callback with the PICMG 2.12 routines. */ + SetEnumEventCallback(NULL, CpciHandleNextEnum, (void *)NULL); + EnableEnumEvents(NULL, TRUE); + + return 0; +} + +/* + * Linux driver ioctl functionality. + */ +static int +cpci_ioctl(struct inode *inode, + struct file *file, unsigned int cmd, unsigned long arg) +{ + int RetVal; + CpciIoctlBusInfo BusInfoIoctl; + CpciIoctlSlotInfo SlotInfoIoctl; + unsigned long flags; + int Loop; + int LoopEnd; + int Offset; + + switch (cmd) { + case CPCI_ADD_BUS: + spin_lock_irqsave(&CpciPciAccessLock, flags); + RetVal = CpciAddBus(arg - 1); + spin_unlock_irqrestore(&CpciPciAccessLock, flags); + + return RetVal; + + case CPCI_DEL_BUS: + spin_lock_irqsave(&CpciPciAccessLock, flags); + RetVal = CpciDelBus(arg - 1, 1); + spin_unlock_irqrestore(&CpciPciAccessLock, flags); + + return RetVal; + + case CPCI_ADD_SLOT: + spin_lock_irqsave(&CpciPciAccessLock, flags); + RetVal = CpciAddSlot(arg - 1); + spin_unlock_irqrestore(&CpciPciAccessLock, flags); + + return RetVal; + + case CPCI_DEL_SLOT: + spin_lock_irqsave(&CpciPciAccessLock, flags); + RetVal = CpciDelSlot(arg - 1); + spin_unlock_irqrestore(&CpciPciAccessLock, flags); + + return RetVal; + + case CPCI_GET_CHASSIS_TYPE: + if (copy_to_user((void *)arg, + &CpciInfos->ChassisType, sizeof(int))) { + return -EFAULT; + } + + return 0; + + case CPCI_GET_BUS_INFO: + if (copy_from_user((void *)&BusInfoIoctl, + (void *)arg, sizeof(CpciIoctlBusInfo))) { + return -EFAULT; + } + + BusInfoIoctl.StartSlot = CpciInfos->StartSlotNum[BusInfoIoctl.Bus]; + BusInfoIoctl.EndSlot = CpciInfos->EndSlotNum[BusInfoIoctl.Bus]; + + LoopEnd = BusInfoIoctl.EndSlot - BusInfoIoctl.StartSlot + 1; + Offset = BusInfoIoctl.StartSlot; + for (Loop = 0; Loop < LoopEnd; Loop ++) { + BusInfoIoctl.Allocated[Loop] = + CpciSlots[Loop + Offset].Allocated; + } + + if (copy_to_user((void *)arg, + &BusInfoIoctl, sizeof(CpciIoctlBusInfo))) { + return -EFAULT; + } + + return 0; + + case CPCI_GET_SLOT_INFO: + if (copy_from_user((void *)&SlotInfoIoctl, + (void *)arg, sizeof(CpciIoctlSlotInfo))) { + return -EFAULT; + } + + if ((RetVal = CpciFillInSlotInfo(&SlotInfoIoctl)) < 0) { + return RetVal; + } + + if (copy_to_user((void *)arg, + &SlotInfoIoctl, sizeof(CpciIoctlSlotInfo))) { + return -EFAULT; + } + + return 0; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Linux driver open functionality. + */ +static int +cpci_open(struct inode *inode, struct file *file) +{ + CpciOpenDevQ *DelDev; + + CpciOpenCount++; + + while (CpciOpenDevHead) { + if (!(CpciOpenDevHead->Dev->driver)) { + EventSendEvent(CpciEventId, 0, + CpciHsiEventClass, CPCI_EVENT_INSERT, + CpciOpenDevHead->Dev->vendor, + CpciOpenDevHead->Dev->device, + CpciOpenDevHead->Dev->subsystem_vendor, + CpciOpenDevHead->Dev->subsystem_device, + 0, NULL); + } + + DelDev = CpciOpenDevHead; + CpciOpenDevHead = CpciOpenDevHead->Next; + kfree(DelDev); + } + + return 0; +} + +void +CpciRegisterOpenCheck(struct pci_dev *dev) +{ + CpciOpenDevQ *TmpDev = CpciOpenDevHead; + + if (CpciOpenDevHead == NULL) { + CpciOpenDevHead = kmalloc(sizeof(CpciOpenDevQ), GFP_KERNEL); + CpciOpenDevHead->Dev = dev; + CpciOpenDevHead->Next = NULL; + return; + } + + while (TmpDev->Next) { + TmpDev = TmpDev->Next; + } + + TmpDev->Next = kmalloc(sizeof(CpciOpenDevQ), GFP_KERNEL); + TmpDev->Next->Dev = dev; + TmpDev->Next->Next = NULL; + return; +} + +/* + * Linux driver close functionality. + */ +static int +cpci_release(struct inode *inode, struct file *file) +{ + CpciOpenCount -= 1; + + return 0; +} + +void +CpciFindBridges(void) +{ +#ifdef CONFIG_MOT_GEN + motCpci_find_bridges(); +#endif +#ifdef CONFIG_MOT_GENERIC + motGenCpci_find_bridges(); +#endif +#ifdef CONFIG_ZT_5550 + zia5083cpci_find_bridges(); +#endif +} + +/* + * Basis for the add bus ioctl functionality. This function + * first checks to see if the bus is already mapped in. If not + * it calls the device dependent allocate and init function to + * physically attach the bus and the device independant function + * to setup the kernel data structures. + */ +int +CpciAddBus(int bus) +{ + /* If this is a standard hot swap chassis with no + * bus control this function is not supported. The + * individual processor - chassis startup code is + * responsible to setting the AllocAndInitBus function + * pointer to NULL to indicate this. + */ + if (CpciFunctions->AllocAndInitBus == NULL) { + return -EINVAL; + } + + if ((bus < 0) || (bus > CpciInfos->MaxBusNum)) { + return -EINVAL; + } + + if (CpciBuses[bus].Allocated) { + return -EBUSY; + } + + + EnableEnumEvents(NULL, FALSE); + CpciFunctions->AllocAndInitBus(bus); + CpciSetupBus(bus); + EnableEnumEvents(NULL, TRUE); + + return 0; +} + +/* + * Basis for the delete bus ioctl. After chicking to ensure this + * is a correct bus to remove, the kernel data structures are reset + * and deallocated and then a device dependant function is called to + * physically remove the bus from the host processor. + */ +int +CpciDelBus(int bus, int detach) +{ + int Slot; + struct pci_dev *Dev; + + /* If this is a standard hot swap chassis with no + * bus control this function is not supported. The + * individual processor - chassis startup code is + * responsible to setting the AllocAndInitBus function + * pointer to NULL to indicate this. + */ + if (CpciFunctions->DeallocAndShutdownBus == NULL) { + return -EINVAL; + } + + if ((bus < 0) || (bus > CpciInfos->MaxBusNum)) { + return -EINVAL; + } + + if (!CpciBuses[bus].Allocated) { + return -ENODEV; + } + + for (Slot = CpciInfos->StartSlotNum[bus]; + Slot <= CpciInfos->EndSlotNum[bus]; Slot++) { + CpciDelSlot(Slot); + } + + Dev = pci_find_slot(0, CpciBuses[bus].DevFn); + +#ifdef CONFIG_PROC_FS + pci_proc_detach_device(Dev); +#endif + list_del(&Dev->bus_list); + list_del(&Dev->global_list); + CpciFreeResources(Dev); + kfree(Dev); + + CpciBuses[bus].Allocated = 0; + + if (detach) { + CpciFunctions->DeallocAndShutdownBus(bus); + } + + return 0; +} + +/* + * This function is the basis for the add slot ioctl and provides the + * slot mapping functionality for the add buss ioctl. The slot number + * is first checked to decide which bus it is on. After that + * the hardware is configured and then the operating system data structurs + * are allocated and filled in. + */ +int +CpciAddSlot(int slot) +{ + int Bus; + struct pci_dev *Dev; + struct pci_dev TempDev; + struct pci_dev *CpciDev; + struct pci_bus *CpciBus; + struct pci_bus *SlotBus; + unsigned char HdrType; + int SlotSubDev = 0; + int Type; + + if ((slot >= CpciInfos->StartSlotNum[0]) && + (slot <= CpciInfos->EndSlotNum[0])) { + Bus = 0; + } else if ((slot >= CpciInfos->StartSlotNum[1]) && + (slot <= CpciInfos->EndSlotNum[1])) { + Bus = 1; + } else { + return -EINVAL; + } + + if (CpciSlots[slot].Allocated == CPCI_SLOT_ALLOCATED) { + EventSendEvent(CpciEventId, 0, CpciHsiEventClass, CPCI_BOARD_INS_FAIL, + slot, CPCI_BI_FAIL_BUSY, 0, 0, 0, NULL); + return -EBUSY; + } + + /* Can have a dangling condition so reset it first. */ + if ((CpciSlots[slot].Allocated & 0xff) == CPCI_SLOT_INSFAILED) { + CpciSlots[slot].Allocated = CPCI_SLOT_FREE; + } + + /* Standard hot swap chassis do not support this. */ + if ((CpciFunctions->CheckHealthy != NULL) && + !CpciFunctions->CheckHealthy(slot)) { + EventSendEvent(CpciEventId, 0, CpciHsiEventClass, CPCI_BOARD_INS_FAIL, + slot, CPCI_BI_FAIL_HEALTH, 0, 0, 0, NULL); + return -ENODEV; + } + + if ((Type = CpciConfigSlot(slot, CpciSlots[slot].Hose, + CpciBuses[Bus].FirstBusNo)) < 0) { + CpciSendAddSlotFail(slot, Bus, CPCI_BI_FAIL_CONFIG); + return Type; + } + + if (!(CpciDev = pci_find_slot(0, CpciBuses[Bus].DevFn))) { + CpciSendAddSlotFail(slot, Bus, CPCI_BI_FAIL_NODEV); + return -ENODEV; + } + + if (!(CpciBus = CpciDev->subordinate)) { + CpciSendAddSlotFail(slot, Bus, CPCI_BI_FAIL_NOSUB); + return -ENODEV; + } + + CpciSlots[slot].UseCount = 0; + + /* scan this sub bus */ + memset(&TempDev, 0, sizeof(TempDev)); + TempDev.bus = CpciBus; + TempDev.sysdata = CpciSlots[slot].Hose; + TempDev.devfn = CpciSlots[slot].DevFn; + + pci_read_config_byte(&TempDev, PCI_HEADER_TYPE, &HdrType); + TempDev.hdr_type = HdrType & 0x7f; + + /* If this is just a device being inserted then don't scan it. */ + if (Type == PCI_HEADER_TYPE_NORMAL) { + if (!(Dev = pci_scan_slot(&TempDev))) { + CpciSendAddSlotFail(slot, Bus, CPCI_BI_FAIL_SCAN); + return -ENODEV; + } +#ifdef CONFIG_PROC_FS + pci_proc_attach_device(Dev); +#endif + CpciFunctions->MapIrq(Dev); + + Dev->cpci_location = (slot << 16) | SlotSubDev++; + + EventSendEvent(CpciEventId, 0, CpciHsiEventClass, CPCI_BOARD_INS_SUCC, + slot, 0, 0, 0, 0, NULL); + + CpciFindDriver(Dev); + return 0; + } + + if (!(Dev = pci_scan_device(&TempDev))) { + CpciSendAddSlotFail(slot, Bus, CPCI_BI_FAIL_SCAN); + return -ENODEV; + } + + pci_name_device(Dev); + + list_add_tail(&Dev->global_list, &pci_devices); + list_add_tail(&Dev->bus_list, &CpciBus->devices); +#ifdef CONFIG_PROC_FS + pci_proc_attach_device(Dev); +#endif + + SlotBus = pci_add_new_bus(CpciBus, Dev, CpciSlots[slot].FirstBusNo); + + pci_do_scan_bus(SlotBus); + + SlotBus->subordinate = CpciSlots[slot].LastBusNo; + pci_read_bridge_bases(SlotBus); + + if (SlotBus->resource[1]->start && (SlotBus->resource[1]->end != -1)) { + SlotBus->resource[1]->start += CpciSlots[slot].Hose->pci_mem_offset; + SlotBus->resource[1]->end += CpciSlots[slot].Hose->pci_mem_offset; + } + + EventSendEvent(CpciEventId, 0, CpciHsiEventClass, CPCI_BOARD_INS_SUCC, + slot, 0, 0, 0, 0, NULL); + + pci_for_each_dev(Dev) { + if ((Dev->bus->number >= SlotBus->number) && + (Dev->bus->number <= SlotBus->subordinate)) { + CpciFunctions->MapIrq(Dev); +#ifdef CONFIG_PROC_FS + pci_proc_attach_device(Dev); +#endif + /* If this is bridge then do not look for a driver. */ + if ((Dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + continue; + } + + Dev->cpci_location = (slot << 16) | SlotSubDev++; + + CpciFindDriver(Dev); + } + } + + return 0; +} + +/* + * Provide the remove slot ioctl functionality and other functionality used + * by the remove bus ioctl. + */ +int +CpciDelSlot(int slot) +{ + int Bus; + struct pci_dev *Dev; + char *name; + + if ((slot >= CpciInfos->StartSlotNum[0]) && + (slot <= CpciInfos->EndSlotNum[0])) { + Bus = 0; + } else if ((slot >= CpciInfos->StartSlotNum[1]) && + (slot <= CpciInfos->EndSlotNum[1])) { + Bus = 1; + } else { + return -EINVAL; + } + + if (CpciSlots[slot].Allocated == CPCI_SLOT_FREE) { + EventSendEvent(CpciEventId, 0, CpciHsiEventClass, CPCI_BOARD_REM_FAIL, + slot, 0, 0, 0, 0, NULL); + return -ENODEV; + } + + if ((CpciSlots[slot].Allocated & 0xff) == CPCI_SLOT_INSFAILED) { + CpciTurnBlueLedOn(slot); + CpciSlots[slot].Allocated = CPCI_SLOT_FREE; + } + + CpciSlots[slot].UseCount |= CPCI_ENUM_EXTRACT; + + pci_for_each_dev_reverse(Dev) { + if ((Dev->bus->number >= CpciSlots[slot].FirstBusNo) && + (Dev->bus->number <= CpciSlots[slot].LastBusNo)) { + if (Dev->driver) { + if (Dev->driver->remove) { + + name = CpciGetName(Dev); + + EventSendEvent(CpciEventId, 0, + CpciHsiEventClass, CPCI_EVENT_SHUTDOWN, + slot, Dev->cpci_location & 0xffff, + Dev->class >> 8, 0, + strlen(name) + 1, name); + + Dev->driver->remove(Dev); + continue; + } + } + +#ifdef CONFIG_PROC_FS + pci_proc_detach_device(Dev); +#endif + list_del(&Dev->bus_list); + list_del(&Dev->global_list); + CpciFreeResources(Dev); + kfree(Dev); + } + + if ((Dev->bus->number == CpciSlots[slot].Bus) && + (Dev->devfn == CpciSlots[slot].DevFn)) { + if (Dev->driver) { + if (Dev->driver->remove) { + + name = CpciGetName(Dev); + + EventSendEvent(CpciEventId, 0, + CpciHsiEventClass, CPCI_EVENT_SHUTDOWN, + slot, Dev->cpci_location & 0xffff, + Dev->class >> 8, 0, + strlen(name) + 1, name); + + Dev->driver->remove(Dev); + } + } + } + } + + if ((CpciSlots[slot].Allocated == CPCI_SLOT_ALLOCATED) && + ((CpciSlots[slot].UseCount & 0xffff) == 0)) { + Dev = pci_find_slot(CpciBuses[Bus].FirstBusNo, CpciSlots[slot].DevFn); + +#ifdef CONFIG_PROC_FS + pci_proc_detach_device(Dev); +#endif + list_del(&Dev->bus_list); + list_del(&Dev->global_list); + CpciFreeResources(Dev); + kfree(Dev); + + CpciSlots[slot].Allocated = CPCI_SLOT_FREE; + + EventSendEvent(CpciEventId, 0, CpciHsiEventClass, CPCI_BOARD_REM_SUCC, + slot, 0, 0, 0, 0, NULL); + CpciTurnBlueLedOn(slot); + } + + return 0; +} + +/* + * Configure a top level cPCI bridge based on device dependant values. + */ +int +CpciConfigCpciBridge(struct pci_controller *hose, int bus, int devfn, int offset) +{ + unsigned Latency, CacheLine; + unsigned short SecondaryStatus; + unsigned int Upper; + struct pci_auto_addrs PciAddrs; + unsigned short BridgeControl; + + PciAddrs.io_start = CpciBuses[offset].IoStart; + PciAddrs.io_end = CpciBuses[offset].IoEnd; + PciAddrs.mem_start = CpciBuses[offset].MemStart; + PciAddrs.mem_end = CpciBuses[offset].MemEnd; + + pciauto_prescan_setup_bridge(hose, bus, devfn, + CpciBuses[offset].FirstBusNo, + &PciAddrs); + + PciAddrs.io_end = CpciBuses[offset].IoStart; + PciAddrs.mem_end = CpciBuses[offset].MemStart; + + pciauto_postscan_setup_bridge(hose, bus, devfn, + CpciBuses[offset].LastBusNo, + &PciAddrs); + + CacheLine = 0x8; + early_write_config_byte(hose, bus, devfn, PCI_CACHE_LINE_SIZE, CacheLine); + + Latency = 0x80; + early_write_config_byte(hose, bus, devfn, PCI_LATENCY_TIMER, Latency); + early_write_config_byte(hose, bus, devfn, PCI_SEC_LATENCY_TIMER, Latency); + + Upper = 0xffffffff; + early_write_config_dword(hose, bus, devfn, PCI_PREF_BASE_UPPER32, Upper); + + SecondaryStatus = 0x2000; + early_write_config_word(hose, bus, devfn, PCI_SEC_STATUS, SecondaryStatus); + + early_read_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, &BridgeControl); + BridgeControl &= ~PCI_BRIDGE_CTL_NO_ISA; + early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, BridgeControl); + + return 0; +} + +/* + * Configure the bridge for a cPCI slot and then autoscan below it. + */ +int +CpciConfigSlot(int slot, struct pci_controller *hose, int bus) +{ + int SubBus; + unsigned short Command; + unsigned char HeaderType; + unsigned int Latency, CacheLine; + unsigned short SecondaryStatus; + unsigned int Upper; + struct pci_auto_addrs PciAddrs; + int ProbeDevFn = CpciSlots[slot].DevFn; + + PciAddrs.io_start = CpciSlots[slot].IoStart; + PciAddrs.io_end = CpciSlots[slot].IoEnd; + PciAddrs.mem_start = CpciSlots[slot].MemStart; + PciAddrs.mem_end = CpciSlots[slot].MemEnd; + + early_read_config_byte(hose, bus, ProbeDevFn, PCI_HEADER_TYPE, &HeaderType); + + /* If header is 0xff then the slot is considered to be not populated. */ + if (HeaderType == 0xff) + return -ENOENT; + + switch (HeaderType & 0x7f) { /* Strip the multifunction bit off */ + case PCI_HEADER_TYPE_NORMAL: + /* This code assumes an IDE controller will not be installed + * for the moment. + */ + early_read_config_word(hose, bus, ProbeDevFn, PCI_COMMAND, &Command); + early_write_config_word(hose, bus, ProbeDevFn, PCI_COMMAND, + Command & ~(PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER)); + early_write_config_byte(hose, bus, ProbeDevFn, PCI_LATENCY_TIMER, 0x80); + + /* Allocate PCI I/O and/or memory space */ + if (pciauto_setup_bars(hose, bus, ProbeDevFn, &PciAddrs) << 0) { + return -ENOSPC; + } + + early_read_config_word(hose, bus, ProbeDevFn, PCI_COMMAND, &Command); + early_write_config_word(hose, bus, ProbeDevFn, PCI_COMMAND, + Command | PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + early_write_config_byte(hose, bus, ProbeDevFn, PCI_LATENCY_TIMER, 0x80); + /* Indicte the slot has been initialized */ + CpciSlots[slot].Allocated = CPCI_SLOT_ALLOCATED; + return PCI_HEADER_TYPE_NORMAL; + + case PCI_HEADER_TYPE_BRIDGE: + CacheLine = 0x8; + early_write_config_byte(hose, bus, ProbeDevFn, PCI_CACHE_LINE_SIZE, CacheLine); + + Latency = 0x80; + early_write_config_byte(hose, bus, ProbeDevFn, PCI_LATENCY_TIMER, Latency); + early_write_config_byte(hose, bus, ProbeDevFn, PCI_SEC_LATENCY_TIMER, Latency); + + Upper = 0xffffffff; + early_write_config_dword(hose, bus, ProbeDevFn, PCI_PREF_BASE_UPPER32, Upper); + + SecondaryStatus = 0x2000; + early_write_config_word(hose, bus, ProbeDevFn, PCI_SEC_STATUS, SecondaryStatus); + + pciauto_prescan_setup_bridge(hose, bus, ProbeDevFn, + CpciSlots[slot].FirstBusNo, + &PciAddrs); + + if ((SubBus = pciauto_bus_scan(hose, CpciSlots[slot].FirstBusNo, + &PciAddrs)) < 0) { + return -ENOSPC; + } + + pciauto_postscan_setup_bridge(hose, bus, ProbeDevFn, SubBus, &PciAddrs); + + CpciSlots[slot].Allocated = CPCI_SLOT_ALLOCATED; + return PCI_HEADER_TYPE_BRIDGE; + + default: + printk("Slot %d has an unknown PCI header type %d\n", slot+1, HeaderType); + return -EINVAL; + } +} + +/* + * Thus function is used by both the add bus ioctl and system startup + * code. It confifure a cPCI bus and all the existing slots below it. + * The initialization includes pci bridges, devices and all the associated + * kernel data structures. + */ +void +CpciSetupBus(int domain) +{ + int Slot; + struct pci_dev *Dev; + struct pci_dev TempDev; + struct pci_bus *HeadBus; + struct pci_bus *CpciBus; + unsigned char HdrType; + unsigned short Command; + + CpciConfigCpciBridge(CpciBuses[domain].Hose, 0, + CpciBuses[domain].DevFn, domain); + CpciBuses[domain].Allocated = 1; + + /* Set up the kernel info for this bus. */ + HeadBus = pci_bus_b(pci_root_buses.next); + + memset(&TempDev, 0, sizeof(TempDev)); + TempDev.bus = HeadBus; + TempDev.sysdata = CpciBuses[domain].Hose; + TempDev.devfn = CpciBuses[domain].DevFn; + + pci_read_config_byte(&TempDev, PCI_HEADER_TYPE, &HdrType); + TempDev.hdr_type = HdrType & 0x7f; + + Dev = pci_scan_device(&TempDev); + pci_name_device(Dev); + + list_add_tail(&Dev->global_list, &pci_devices); + list_add_tail(&Dev->bus_list, &HeadBus->devices); +#ifdef CONFIG_PROC_FS + pci_proc_attach_device(Dev); +#endif + + CpciBus = pci_add_new_bus(HeadBus, Dev, CpciBuses[domain].FirstBusNo); + + pci_read_bridge_bases(CpciBus); + + if (CpciBus->resource[1]->start && (CpciBus->resource[1]->end != -1)) { + CpciBus->resource[1]->start += + CpciBuses[domain].Hose->pci_mem_offset; + CpciBus->resource[1]->end += + CpciBuses[domain].Hose->pci_mem_offset; + } + + CpciBus->subordinate = CpciBuses[domain].LastBusNo; + + /* Sanitize the slots before starting to config them. */ + for (Slot = CpciInfos->StartSlotNum[domain]; + Slot <= CpciInfos->EndSlotNum[domain]; Slot++) { + struct pci_controller *Hose = CpciSlots[Slot].Hose; + int Bus = CpciBuses[domain].FirstBusNo; + int ProbeDevFn = CpciSlots[Slot].DevFn; + + early_read_config_word(Hose, Bus, ProbeDevFn, + PCI_COMMAND, &Command); + Command &= ~(PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + early_write_config_word(Hose, Bus, ProbeDevFn, + PCI_COMMAND, Command); + + early_read_config_byte(Hose, Bus, ProbeDevFn, + PCI_HEADER_TYPE, &HdrType); + if ((HdrType & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { + early_write_config_byte(Hose, Bus, ProbeDevFn, + PCI_SECONDARY_BUS, 0); + early_write_config_byte(Hose, Bus, ProbeDevFn, + PCI_SUBORDINATE_BUS, 0); + } + } + + for (Slot = CpciInfos->StartSlotNum[domain]; + Slot <= CpciInfos->EndSlotNum[domain]; Slot++) { + CpciAddSlot(Slot); + } + + /* Turn on enum processing. */ + CpciFunctions->SetEnumMask(domain, CPCI_BIT_SET); + + return; +} + +/* + * Free the resource data structures allocated in a pci_dev struct. + */ +void +CpciFreeResources(struct pci_dev *dev) +{ + int loop; + + for (loop = 0; loop < PCI_NUM_RESOURCES; loop++) { + struct resource *res = dev->resource + loop; + if (res->parent) + release_resource(res); + } +} + +void +CpciHandleNextEnum(void *arg) +{ + int Bus, Slot; + int TimeOutCnt; + unsigned long flags; + + /* Check for an extract enum first. If one is found changes are + * there are no others. If there are the 2.12 code will trip on + * an enum again and call this code anyways. + */ + for (TimeOutCnt = 0; TimeOutCnt < 5; TimeOutCnt++) { + for (Bus = 0; Bus < CpciInfos->MaxBusNum; Bus++) { + if (!CpciBuses[Bus].Allocated) { + continue; + } + + for (Slot = CpciInfos->StartSlotNum[Bus]; + Slot <= CpciInfos->EndSlotNum[Bus]; Slot++) { + if (CpciSlots[Slot].Allocated == CPCI_SLOT_ALLOCATED) { + if (CpciEnumCheckAndClear(Slot, 1) == CPCI_ENUM_EXT) { + spin_lock_irqsave(&CpciPciAccessLock, flags); + CpciDelSlot(Slot); + spin_unlock_irqrestore(&CpciPciAccessLock, flags); + return; + } + } + } + } + + /* Start the timeout sequence going and sleep. */ + CpciHandleEnumTimeOut.data = 1; + CpciHandleEnumTimeOut.expires = jiffies + HZ/30; + add_timer(&CpciHandleEnumTimeOut); + + sleep_on(&CpciHandleEnumWaitQ); + } + + /* Now handle any remaining events. */ + for (Bus = 0; Bus < CpciInfos->MaxBusNum; Bus++) { + if (!CpciBuses[Bus].Allocated) { + continue; + } + + for (Slot = CpciInfos->StartSlotNum[Bus]; + Slot <= CpciInfos->EndSlotNum[Bus]; Slot++) { + switch (CpciEnumCheckAndClear(Slot, 0)) { + case CPCI_ENUM_INS: + /* As a sanity check see if it has already + * been allocated. This error condition + * appears on cpv8540 boards when the the + * system is booted and the latch is in + * the down posiiton. + */ + if (CpciSlots[Slot].Allocated == CPCI_SLOT_ALLOCATED) { + return; + } + + spin_lock_irqsave(&CpciPciAccessLock, flags); + CpciAddSlot(Slot); + spin_unlock_irqrestore(&CpciPciAccessLock, flags); + return; + + case CPCI_ENUM_EXT: + spin_lock_irqsave(&CpciPciAccessLock, flags); + CpciDelSlot(Slot); + spin_unlock_irqrestore(&CpciPciAccessLock, flags); + return; + } + } + } + return; +} + +void +CpciHandleEnumTimeOutFunc(unsigned long arg) +{ + wake_up(&CpciHandleEnumWaitQ); + return; +} + +void +CpciFindDriver(struct pci_dev *dev) +{ + struct pci_driver *Drv; + struct list_head *ln; + + for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) { + Drv = list_entry(ln, struct pci_driver, node); + if (Drv->remove && pci_announce_device(Drv, dev)) { + return; + } + } + + /* Did not find an existing device driver so request one be inserted */ + EventSendEvent(CpciEventId, 0, + CpciHsiEventClass, CPCI_EVENT_INSERT, + dev->vendor, dev->device, + dev->subsystem_vendor, dev->subsystem_device, + 0, NULL); + + return; +} + +char * +CpciGetName(struct pci_dev *dev) +{ + struct net_device *net_dev; + + if ((dev->class >> 8) == PCI_CLASS_NET_ETH) { + if ((net_dev = (struct net_device *)dev->driver_data) != NULL) { + return net_dev->name; + } + } + + return "dummy"; +} + +void +CpciRegisterDevice(struct pci_dev *dev) +{ + int Slot = dev->cpci_location >> 16; + char *name; + + if (dev->bus->number < CpciBuses[0].FirstBusNo) { + /* Not a cPCI device so do not register */ + return; + } + + CpciSlots[Slot].UseCount++; + + name = CpciGetName(dev); + + EventSendEvent(CpciEventId, 0, + CpciHsiEventClass, CPCI_EVENT_AVAIL, + Slot, dev->cpci_location & 0xffff, dev->class >> 8, 0, + strlen(name) + 1, name); + return; +} + +void +CpciUnRegisterDevice(struct pci_dev *dev) +{ + int Bus = 0; + struct pci_dev *Dev; + int Slot = dev->cpci_location >> 16; + char *name; + + CpciSlots[Slot].UseCount--; + + if (!(CpciSlots[Slot].UseCount & CPCI_ENUM_EXTRACT)) { + return; + } + + name = CpciGetName(dev); + + EventSendEvent(CpciEventId, 0, + CpciHsiEventClass, CPCI_EVENT_CLOSED, + Slot, dev->cpci_location & 0xffff, dev->class >> 8, 0, + strlen(name) + 1, name); + + /* if this is a device only card with no bride this will be deleted + * below because use count will go to zero. + */ + if (!((dev->bus->number == CpciSlots[Slot].Bus) && + (dev->devfn == CpciSlots[Slot].DevFn))) { +#ifdef CONFIG_PROC_FS + pci_proc_detach_device(dev); +#endif + list_del(&dev->bus_list); + list_del(&dev->global_list); + CpciFreeResources(dev); + kfree(dev); + } + + if ((CpciSlots[Slot].UseCount & 0xffff) == 0) { + + if ((Slot >= CpciInfos->StartSlotNum[0]) && + (Slot <= CpciInfos->EndSlotNum[0])) { + Bus = 0; + } else if ((Slot >= CpciInfos->StartSlotNum[1]) && + (Slot <= CpciInfos->EndSlotNum[1])) { + Bus = 1; + } + + Dev = pci_find_slot(CpciBuses[Bus].FirstBusNo, CpciSlots[Slot].DevFn); + +#ifdef CONFIG_PROC_FS + pci_proc_detach_device(Dev); +#endif + list_del(&Dev->bus_list); + list_del(&Dev->global_list); + CpciFreeResources(Dev); + kfree(Dev); + + CpciSlots[Slot].Allocated = CPCI_SLOT_FREE; + + EventSendEvent(CpciEventId, 0, CpciHsiEventClass, CPCI_BOARD_REM_SUCC, + Slot, 0, 0, 0, 0, NULL); + CpciTurnBlueLedOn(Slot); + } + + return; +} + +int +CpciFindSlotFromDev(struct pci_dev *dev) +{ + int Slot; + + for (Slot = 0; Slot < 16; Slot++) { + if (((dev->bus->number >= CpciSlots[Slot].FirstBusNo) && + (dev->bus->number <= CpciSlots[Slot].LastBusNo)) || + ((dev->bus->number == CpciSlots[Slot].Bus) && + (dev->devfn == CpciSlots[Slot].DevFn))) { + return Slot; + } + } + + return -1; +} + +void +CpciSendAddSlotFail(int slot, int domain, int code) +{ + struct pci_controller *Hose = CpciSlots[slot].Hose; + int Bus = CpciBuses[domain].FirstBusNo; + int ProbeDevFn = CpciSlots[slot].DevFn; + unsigned short Command; + unsigned char SubBus; + + /* Disable access to io and memory space to prevent this board from + * responding. + */ + early_read_config_word(Hose, Bus, ProbeDevFn, PCI_COMMAND, &Command); + Command &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + early_write_config_word(Hose, Bus, ProbeDevFn, PCI_COMMAND, Command); + + early_read_config_byte(Hose, Bus, ProbeDevFn, PCI_SECONDARY_BUS, &SubBus); + early_write_config_byte(Hose, Bus, ProbeDevFn, PCI_SUBORDINATE_BUS, SubBus); + CpciSlots[slot].Allocated = CPCI_SLOT_INSFAILED; + CpciSlots[slot].Allocated |= code << 8; + + EventSendEvent(CpciEventId, 0, CpciHsiEventClass, CPCI_BOARD_INS_FAIL, + slot, code, 0, 0, 0, NULL); + + return; +} + +int +CpciFillInSlotInfo(CpciIoctlSlotInfo *slotInfo) +{ + struct pci_dev *Dev; + int Domain = slotInfo->Domain; + int Slot = slotInfo->Slot; + int SubDev = 0; + + if ((Domain < 0) || (Domain >= CpciInfos->MaxBusNum)) { + return -EINVAL; + } + + if ((Slot < CpciInfos->StartSlotNum[Domain]) || + (Slot > CpciInfos->EndSlotNum[Domain])) { + return -EINVAL; + } + + pci_for_each_dev(Dev) { + if (Slot == CpciFindSlotFromDev(Dev)) { + if ((Dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + continue; + } + + slotInfo->DevInfo[SubDev].Vendor = Dev->vendor; + slotInfo->DevInfo[SubDev].Device = Dev->device; + slotInfo->DevInfo[SubDev].SubSystemVendor = Dev->subsystem_vendor; + slotInfo->DevInfo[SubDev].SubSystemDevice = Dev->subsystem_device; + slotInfo->DevInfo[SubDev].Class = Dev->class >> 8; + slotInfo->DevInfo[SubDev].Name[0] = '\0'; + + if (Dev->driver && Dev->driver->remove) { + if (Dev->driver_data != NULL) { + strncpy (slotInfo->DevInfo[SubDev].Name, CpciGetName(Dev), CPCI_MAX_NAME_LEN); + } + slotInfo->DevInfo[SubDev].DriverStatus = CPCI_DRIVER_INSTALLED; + } else { + slotInfo->DevInfo[SubDev].DriverStatus = CPCI_DRIVER_NEEDED; + } + SubDev++; + + if (SubDev == CPCI_MAX_SLOT_INFO) { + slotInfo->NumSubDevs = CPCI_MAX_SLOT_INFO; + return 0; + } + } + } + + slotInfo->NumSubDevs = SubDev; + return 0; +} + +/* Functions to be accessed from modules. */ +EXPORT_SYMBOL(CpciRegisterDevice); +EXPORT_SYMBOL(CpciUnRegisterDevice); diff -u -r --new-file linux/drivers/ha/cpci/cpci_core.h ha/drivers/ha/cpci/cpci_core.h --- linux/drivers/ha/cpci/cpci_core.h Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/cpci_core.h Thu Dec 13 13:03:13 2001 @@ -0,0 +1,118 @@ +/* + * cpci_core.h + * + * Header file defining dependencies in most of the core cPCI routines. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + */ + +/* We currently handle ... */ +#define CPCI_MAX_BUSNUM 2 /* Mot 8221 chassis has 2 busses */ +#define CPCI_MAX_SLOTNUM 16 /* Mot 8216 chassis has 16 slots */ + +/* A couple of useful defines */ +#define CPCI_BIT_SET 1 +#define CPCI_BIT_CLEAR 0 + +/* Possible types of ENUM values */ +#define CPCI_ENUM_NONE 0 +#define CPCI_ENUM_INS 1 +#define CPCI_ENUM_EXT 2 + +/* Calls to the enum control routines. */ +int CpciEnumInsCheckAndClear(int); +int CpciEnumExtCheckAndClear(int); +int CpciTurnBlueLedOn(int); +int CpciEnumCheckAndClear(int, int); + +/* Core cPCI functionality that may be used by device dependant routines. */ +int CpciConfigCpciBridge(struct pci_controller *, int, int, int); +int CpciConfigSlot(int, struct pci_controller *, int); +void CpciSetupBus(int); +void CpciFreeResources(struct pci_dev *); +void CpciHssdFindDriver(struct pci_dev *); +int CpciFindSlotFromDev(struct pci_dev *); +void CpciRegisterOpenCheck(struct pci_dev *); +void CpciHssdPostInsert(unsigned short, unsigned short, unsigned short, + unsigned short, unsigned short); + +/* Debug functions. */ +void dump_bridge_reg(struct pci_controller *, int, int); +void dump_busses(struct list_head *, int); +void dump_devices(void); + +/* This structure defines the device dependant cPCI functions + * required by the core cPCI code. + */ +typedef struct cpci_func { + int (*AllocAndInitBus)(int); + void (*DeallocAndShutdownBus)(int); + int (*SetEnumMask)(int, int); + int (*CheckHealthy)(int); + void (*MapIrq)(struct pci_dev *); +} CpciFunc; + +extern CpciFunc *CpciFunctions; + +/* Define system dependent PCI node info to be fed to the system independant + * routines. + */ +typedef struct _CpciNodeInfo { + struct pci_controller *Hose; + int Bus; + int DevFn; + int Allocated; + int UseCount; /* High bit indicates enum extract. */ + int FirstBusNo; + int LastBusNo; + unsigned int IoStart; + unsigned int IoEnd; + unsigned int MemStart; + unsigned int MemEnd; +} CpciNodeInfo; + +#define CPCI_ENUM_EXTRACT 0x80000000 + +/* General system dependent info about chassis needed. */ +typedef struct _CpciInfo { + int ChassisType; + int MaxBusNum; + int StartSlotNum[CPCI_MAX_BUSNUM]; + int EndSlotNum[CPCI_MAX_BUSNUM]; +} CpciInfo; + +/* Pointers to be filled out by system dependat code giving access to + * independant routines. + */ +extern CpciNodeInfo *CpciBuses; +extern CpciNodeInfo *CpciSlots; +extern CpciInfo *CpciInfos; + +#define PCI_CLASS_NET_ETH 0x0200 + diff -u -r --new-file linux/drivers/ha/cpci/cpci_debug.c ha/drivers/ha/cpci/cpci_debug.c --- linux/drivers/ha/cpci/cpci_debug.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/cpci_debug.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,189 @@ +#include +#include +#include +#include +#include +#include +#include +#include "cpci_core.h" + +extern struct list_head pci_devices; + +void +dump_bridge_reg(struct pci_controller *hose, int bus, int devfn) +{ + unsigned char tbt; + unsigned short twd; + unsigned int tdwd; + + printk("Dump registers for bride at hose 0x%x bus 0x%x devfn 0x%x\n", + (unsigned int)hose, bus, devfn); + + early_read_config_word(hose, bus, devfn, PCI_VENDOR_ID, &twd); + printk("Vendor: 0x%x\n", twd); + + early_read_config_word(hose, bus, devfn, PCI_DEVICE_ID, &twd); + printk("Device: 0x%x\n", twd); + + early_read_config_word(hose, bus, devfn, PCI_COMMAND, &twd); + printk("Command: 0x%x\n", twd); + + early_read_config_word(hose, bus, devfn, PCI_STATUS, &twd); + printk("Status: 0x%x\n", twd); + + early_read_config_dword(hose, bus, devfn, PCI_CLASS_REVISION, &tdwd); + printk("Class: 0x%x\n", tdwd >> 16); + + early_read_config_byte(hose, bus, devfn, PCI_CACHE_LINE_SIZE, &tbt); + printk("Cache Line: 0x%x\n", tbt); + + early_read_config_byte(hose, bus, devfn, PCI_LATENCY_TIMER, &tbt); + printk("Latency: 0x%x\n", tbt); + + early_read_config_byte(hose, bus, devfn, PCI_HEADER_TYPE, &tbt); + printk("Header: 0x%x\n", tbt); + + early_read_config_byte(hose, bus, devfn, PCI_BIST, &tbt); + printk("Bist: 0x%x\n", tbt); + + early_read_config_dword(hose, bus, devfn, PCI_BASE_ADDRESS_0, &tdwd); + printk("Bar0: 0x%x\n", tdwd); + + early_read_config_dword(hose, bus, devfn, PCI_BASE_ADDRESS_1, &tdwd); + printk("Bar1: 0x%x\n", tdwd); + + early_read_config_byte(hose, bus, devfn, PCI_PRIMARY_BUS, &tbt); + printk("Primary: 0x%x\n", tbt); + + early_read_config_byte(hose, bus, devfn, PCI_SECONDARY_BUS, &tbt); + printk("Second: 0x%x\n", tbt); + + early_read_config_byte(hose, bus, devfn, PCI_SUBORDINATE_BUS , &tbt); + printk("Subord: 0x%x\n", tbt); + + early_read_config_byte(hose, bus, devfn, PCI_SEC_LATENCY_TIMER, &tbt); + printk("Sec Lat: 0x%x\n", tbt); + + early_read_config_byte(hose, bus, devfn, PCI_IO_BASE, &tbt); + printk("IO Base: 0x%x\n", tbt); + + early_read_config_byte(hose, bus, devfn, PCI_IO_LIMIT, &tbt); + printk("IO Limit: 0x%x\n", tbt); + + early_read_config_word(hose, bus, devfn, PCI_SEC_STATUS, &twd); + printk("Sec status: 0x%x\n", twd); + + early_read_config_word(hose, bus, devfn, PCI_MEMORY_BASE, &twd); + printk("Mem Base: 0x%x\n", twd); + + early_read_config_word(hose, bus, devfn, PCI_MEMORY_LIMIT, &twd); + printk("Mem Limit: 0x%x\n", twd); + + early_read_config_word(hose, bus, devfn, PCI_PREF_MEMORY_BASE, &twd); + printk("Pre Mem Base: 0x%x\n", twd); + + early_read_config_word(hose, bus, devfn, PCI_PREF_MEMORY_LIMIT, &twd); + printk("Pre Mem Limit: 0x%x\n", twd); + + early_read_config_dword(hose, bus, devfn, PCI_PREF_BASE_UPPER32, &tdwd); + printk("Pre Upper Base: 0x%x\n", tdwd); + + early_read_config_dword(hose, bus, devfn, PCI_PREF_LIMIT_UPPER32, &tdwd); + printk("Pre Upper Limit: 0x%x\n", tdwd); + + early_read_config_word(hose, bus, devfn, PCI_IO_BASE_UPPER16, &twd); + printk("IO Upper Base: 0x%x\n", twd); + + early_read_config_word(hose, bus, devfn, PCI_IO_LIMIT_UPPER16, &twd); + printk("IO Upper Limit: 0x%x\n", twd); + + early_read_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, &twd); + printk("Bridge Control: 0x%x\n", twd); + +} + +void +dump_busses(struct list_head *plh, int level) +{ + struct list_head *ln, *devln; + struct pci_bus *check_bus; + struct pci_dev *check_dev; + int lev; + int i; + + for (ln = plh->next; ln != plh; ln=ln->next) { + check_bus = pci_bus_b(ln); + for (lev = 0; lev < level; lev++) { + printk(" "); + } + + printk("***** Bus vend 0x%x device 0x%x number 0x%x primary 0x%x second 0x%x subord 0x%x\n", + check_bus->vendor, check_bus->device, check_bus->number, + check_bus->primary, check_bus->secondary, check_bus->subordinate); + + for (lev = 0; lev < level; lev++) { + printk(" "); + } + + + printk("resources "); + for (i=0; i < 4; i++) { + if (check_bus->resource[i]) { + printk("0x%x:0x%x ", + (unsigned int)check_bus->resource[i]->start, + (unsigned int)check_bus->resource[i]->end); + } + } + printk("\n"); + + printk("Devices on bus:\n"); + for (devln = check_bus->devices.next; + devln != &check_bus->devices; devln = devln->next) { + check_dev = pci_dev_b(devln); + printk("name '%s' bus 0x%x devfn 0x%x vendor 0x%x device 0x%x\n", + check_dev->name, check_dev->bus->number, + check_dev->devfn, check_dev->vendor, + check_dev->device); + printk("Resources 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n", + (unsigned int)check_dev->resource[0].start, + (unsigned int)check_dev->resource[0].end, + (unsigned int)check_dev->resource[1].start, + (unsigned int)check_dev->resource[1].end, + (unsigned int)check_dev->resource[2].start, + (unsigned int)check_dev->resource[2].end, + (unsigned int)check_dev->resource[3].start, + (unsigned int)check_dev->resource[3].end); + } + + dump_busses(&check_bus->children, level + 1); + } +} + +void +dump_devices(void) +{ + struct list_head *n = pci_devices.next; + struct pci_dev *check_dev; + + printk("Dump Devices\n"); + while (n != &pci_devices) { + check_dev = pci_dev_g(n); + + printk("name '%s' bus 0x%x devfn 0x%x vendor 0x%x device 0x%x\n", + check_dev->name, check_dev->bus->number, + check_dev->devfn, check_dev->vendor, + check_dev->device); + printk("Resources 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n", + (unsigned int)check_dev->resource[0].start, + (unsigned int)check_dev->resource[0].end, + (unsigned int)check_dev->resource[1].start, + (unsigned int)check_dev->resource[1].end, + (unsigned int)check_dev->resource[2].start, + (unsigned int)check_dev->resource[2].end, + (unsigned int)check_dev->resource[3].start, + (unsigned int)check_dev->resource[3].end); + + n = n->next; + } +} + diff -u -r --new-file linux/drivers/ha/cpci/cpci_enum.c ha/drivers/ha/cpci/cpci_enum.c --- linux/drivers/ha/cpci/cpci_enum.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/cpci_enum.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,352 @@ +/* + * cpci_carrier.c + * + * Routines for recognizing the type and controlling ENUM for cPCI carriers. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + * + */ +#include +#include +#include +#include +#include +#include +#include +#include "cpci_core.h" + +#define CPCI_BOARD_TYPE_UNKNOWN 0 +#define CPCI_BOARD_TYPE_2_12_STANDARD 1 +#define CPCI_BOARD_TYPE_ALT_CPV8540 2 + +#define CPCI_HS_CAPABILITY_ID 0x6 + +#define CPCI_BRD_TYPE(x) ((x) & 0xff) +#define CPCI_BRD_CAPPTR(x) ((x >> 8) & 0xff) + +/* Prototypes for 2.12 compliant boards. */ +static int picmg2_12_clear_ins_enum(struct pci_controller *, int, int, unsigned char); +static int picmg2_12_clear_ext_enum(struct pci_controller *, int, int, unsigned char); +static void picmg2_12_blue_led_on(struct pci_controller *, int, int, unsigned char); + +/* Prototypes for Motorola CPV8540 carrier boards. */ +static int cpv8540_clear_ins_enum(struct pci_controller *, int, int, unsigned char); +static int cpv8540_clear_ext_enum(struct pci_controller *, int, int, unsigned char); +static void cpv8540_blue_led_on(struct pci_controller *, int, int, unsigned char); + +/* Board specific function array. */ +typedef struct cpci_carrier_board_info { + int (*ClearInsEnum)(struct pci_controller *, int, int, unsigned char); + int (*ClearExtEnum)(struct pci_controller *, int, int, unsigned char); + void (*BlueLightOn)(struct pci_controller *, int, int, unsigned char); +} CpciCarrierInfoStruct; + +CpciCarrierInfoStruct CpciCarrierInfo[] = { + {NULL, NULL, NULL}, /* Element 0 is an error condition */ + {picmg2_12_clear_ins_enum, picmg2_12_clear_ext_enum, picmg2_12_blue_led_on}, + {cpv8540_clear_ins_enum, cpv8540_clear_ext_enum, cpv8540_blue_led_on} +}; + +/* + * Return the board type. At the moment the only board we have is + * the Mot CPV8540. If the bridge found is a Dec 211454 assume it is + * this board. + */ +int +CpciEnumGetBrdType(struct pci_controller *hose, int bus, int devfn) +{ + unsigned short Status; + unsigned short Vendor; + unsigned short Device; + unsigned short SubVendor; + unsigned short SubDevice; + unsigned char CapPtr; + int Capability; + + early_read_config_word(hose, bus, devfn, PCI_VENDOR_ID, &Vendor); + early_read_config_word(hose, bus, devfn, PCI_DEVICE_ID, &Device); + early_read_config_word(hose, bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &SubVendor); + early_read_config_word(hose, bus, devfn, PCI_SUBSYSTEM_ID, &SubDevice); + + if ((Vendor == PCI_VENDOR_ID_DEC) && (Device == PCI_DEVICE_ID_DEC_21154)) { + return CPCI_BOARD_TYPE_ALT_CPV8540; + } + + early_read_config_word(hose, bus, devfn, PCI_STATUS, &Status); + + if (Status == 0xffff) { + /* Nothing to read in this slot. */ + return CPCI_BOARD_TYPE_UNKNOWN; + } + + if (Status & PCI_STATUS_CAP_LIST) { + early_read_config_byte(hose, bus, devfn, PCI_CAPABILITY_LIST, &CapPtr); + while (CapPtr) { + early_read_config_dword(hose, bus, devfn, CapPtr, &Capability); + if ((Capability & 0xff) == CPCI_HS_CAPABILITY_ID) { + return ((CapPtr << 8) | CPCI_BOARD_TYPE_2_12_STANDARD); + } + + CapPtr = (Capability >> 8) & 0xff; + } + } + + return CPCI_BOARD_TYPE_UNKNOWN; +} + +/* + * Check and see if an insert enum exists and clear it if so. + */ +int +CpciEnumCheckAndClear(int slot, int extractOnly) +{ + int BrdType; + + BrdType = CpciEnumGetBrdType(CpciSlots[slot].Hose, + CpciSlots[slot].Bus, CpciSlots[slot].DevFn); + + if (CPCI_BRD_TYPE(BrdType) == CPCI_BOARD_TYPE_UNKNOWN) { + return 0; + } + + if (CpciCarrierInfo[CPCI_BRD_TYPE(BrdType)].ClearExtEnum(CpciSlots[slot].Hose, + CpciSlots[slot].Bus, CpciSlots[slot].DevFn, + CPCI_BRD_CAPPTR(BrdType))) { + return CPCI_ENUM_EXT; + } + + if (extractOnly) { + return CPCI_ENUM_NONE; + } + + if (CpciCarrierInfo[CPCI_BRD_TYPE(BrdType)].ClearInsEnum(CpciSlots[slot].Hose, + CpciSlots[slot].Bus, CpciSlots[slot].DevFn, + CPCI_BRD_CAPPTR(BrdType))) { + return CPCI_ENUM_INS; + } + + return CPCI_ENUM_NONE; +} + +/* + * Turn the blue light on to signal extraction OK. + */ +int +CpciTurnBlueLedOn(int slot) +{ + int BrdType; + + BrdType = CpciEnumGetBrdType(CpciSlots[slot].Hose, + CpciSlots[slot].Bus, CpciSlots[slot].DevFn); + + if (CPCI_BRD_TYPE(BrdType) == CPCI_BOARD_TYPE_UNKNOWN) { + return 0; + } + + CpciCarrierInfo[CPCI_BRD_TYPE(BrdType)].BlueLightOn(CpciSlots[slot].Hose, + CpciSlots[slot].Bus, CpciSlots[slot].DevFn, + CPCI_BRD_CAPPTR(BrdType)); + return 0; +} + +#define CPCI_HS_DEV_HIDE_BIT 0x10000 +#define CPCI_HS_ENUMSIG_BIT 0x20000 +#define CPCI_HS_PEND_BIT 0x40000 +#define CPCI_HS_BLUELED_BIT 0x80000 +#define CPCI_HS_PIE_BIT 0x100000 +#define CPCI_HS_EXT_ENUM_BIT 0x400000 +#define CPCI_HS_INS_ENUM_BIT 0x800000 + +static int +picmg2_12_clear_ins_enum(struct pci_controller *hose, + int bus, int devfn, unsigned char capPtr) +{ + int Capability; + + early_read_config_dword(hose, bus, devfn, capPtr, &Capability); + + if((Capability & 0xff) != CPCI_HS_CAPABILITY_ID) { + /* Something strange has happened */ + return 0; + } + + if (Capability & CPCI_HS_INS_ENUM_BIT) { + /* Found an insert enum */ + early_write_config_dword(hose, bus, devfn, capPtr, CPCI_HS_INS_ENUM_BIT); + + return 1; + } + + return 0; +} + +static int +picmg2_12_clear_ext_enum(struct pci_controller *hose, + int bus, int devfn, unsigned char capPtr) +{ + int Capability; + + early_read_config_dword(hose, bus, devfn, capPtr, &Capability); + + if((Capability & 0xff) != CPCI_HS_CAPABILITY_ID) { + /* Something strange has happened */ + return 0; + } + + if (Capability & CPCI_HS_EXT_ENUM_BIT) { + /* Found an extract enum. Turn off the extract enum + * bit but leave the blue light off and mask the enum + * signal generation from this slot. The blue light + * will be turned off and enum signal restored when] + * the drivers have quiesed and returned. + */ + early_read_config_dword(hose, bus, devfn, capPtr, &Capability); + if (Capability & CPCI_HS_BLUELED_BIT) { + early_write_config_dword(hose, bus, devfn, capPtr, CPCI_HS_BLUELED_BIT); + early_read_config_dword(hose, bus, devfn, capPtr, &Capability); + } + + if (!(Capability & CPCI_HS_ENUMSIG_BIT)) { + early_write_config_dword(hose, bus, devfn, capPtr, CPCI_HS_ENUMSIG_BIT); + } + + return 1; + } + + return 0; +} + +static void +picmg2_12_blue_led_on(struct pci_controller *hose, + int bus, int devfn, unsigned char capPtr) +{ + int Capability; + + early_read_config_dword(hose, bus, devfn, capPtr, &Capability); + + if((Capability & 0xff) != CPCI_HS_CAPABILITY_ID) { + /* Something strange has happened */ + return; + } + + if (!(Capability & CPCI_HS_BLUELED_BIT)) { + early_write_config_dword(hose, bus, devfn, capPtr, CPCI_HS_BLUELED_BIT); + } + + if (Capability & CPCI_HS_ENUMSIG_BIT) { + early_write_config_dword(hose, bus, devfn, capPtr, CPCI_HS_ENUMSIG_BIT); + } + + early_write_config_dword(hose, bus, devfn, capPtr, CPCI_HS_EXT_ENUM_BIT); + + return; +} + +#define CPV8540_INIT_BYTE 0x65 +#define CPV8540_ENUM_CONTROL 0x66 +#define CPV8540_ENUM_STATUS 0x67 + +#define CPV8540_INS 0x80 +#define CPV8540_EXT 0x40 + +#define CPV8540_INIT1 0x0f +#define CPV8540_INIT2 0x3c +#define CPV8540_INS_RESET 0x08 +#define CPV8540_EXT_RESET 0x04 + +#define CPV8540_BLUELED_ON 0x20 +#define CPV8540_BLUELED_OFF 0x02 + +#define CPV8540_ENUM_ENABLE 0x01 +#define CPV8540_ENUM_DISABLE 0x10 + +static int +cpv8540_clear_ins_enum(struct pci_controller *hose, + int bus, int devfn, unsigned char capPtr) +{ + unsigned char HSBits; + + early_write_config_byte(hose, bus, devfn, CPV8540_ENUM_CONTROL, CPV8540_INIT2); + + early_read_config_byte(hose, bus, devfn, CPV8540_ENUM_STATUS, &HSBits); + + if (HSBits & CPV8540_INS) { + early_write_config_byte(hose, bus, devfn, + CPV8540_ENUM_CONTROL, CPV8540_INS); + early_write_config_byte(hose, bus, devfn, + CPV8540_ENUM_CONTROL, CPV8540_INS_RESET); + + early_write_config_byte(hose, bus, devfn, CPV8540_INIT_BYTE, CPV8540_INIT1); + return 1; + } + + return 0; +} + +static int +cpv8540_clear_ext_enum(struct pci_controller *hose, + int bus, int devfn, unsigned char capPtr) +{ + unsigned char HSBits; + + early_read_config_byte(hose, bus, devfn, CPV8540_ENUM_STATUS, &HSBits); + + if (HSBits & CPV8540_EXT) { + early_write_config_byte(hose, bus, devfn, + CPV8540_ENUM_CONTROL, CPV8540_EXT); + early_write_config_byte(hose, bus, devfn, + CPV8540_ENUM_CONTROL, CPV8540_EXT_RESET); + + /* Turn the Blue light back off. We wanted to clear the enum + * but not the blue light. Blue light will be cleared when + * the drivers have queiesced and it is OK to pull the board. + */ + early_write_config_byte(hose, bus, devfn, + CPV8540_INIT_BYTE, CPV8540_BLUELED_OFF); + + /* While quiesce in in progress inhibit ENUM generation. */ + early_write_config_byte(hose, bus, devfn, + CPV8540_INIT_BYTE, CPV8540_ENUM_DISABLE); + + return 1; + } + + return 0; +} + +static void +cpv8540_blue_led_on(struct pci_controller *hose, + int bus, int devfn, unsigned char capPtr) +{ + early_write_config_byte(hose, bus, devfn, + CPV8540_INIT_BYTE, CPV8540_BLUELED_ON); + + early_write_config_byte(hose, bus, devfn, + CPV8540_INIT_BYTE, CPV8540_ENUM_ENABLE); +} diff -u -r --new-file linux/drivers/ha/cpci/mot82XXhsc.c ha/drivers/ha/cpci/mot82XXhsc.c --- linux/drivers/ha/cpci/mot82XXhsc.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/mot82XXhsc.c Thu Dec 13 13:26:13 2001 @@ -0,0 +1,2483 @@ +/* + * mot82XXhsc.c + * + * Motorola 82XX hot swap controller driver. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mot82XXhsc.h" +#include "phs.h" + +/* Driver entrance function prototypes. */ +static ssize_t mot82XXhsc_read(struct file *, char *, size_t, loff_t *); +static int mot82XXhsc_ioctl(struct inode *, struct file *, + unsigned int, unsigned long); +static int mot82XXhsc_open(struct inode *, struct file *); +static int mot82XXhsc_release(struct inode *, struct file *); +static int mot82XXhsc_fasync(int, struct file *, int); +static void mot82XXhsc_intr(int, void *, struct pt_regs *); + +/* Functions used for interrupt handling. */ +static void mot82XXhscMapIntBitsToRegisters(void); +static void mot82XXhscHandleSlotInt(volatile unsigned int *, int); +static void mot82XXhscHandleHostInt(volatile unsigned int *, int); +static void mot82XXhscHandleHSCInt(volatile unsigned int *, int); +static void mot82XXhscHandlePbayInt(volatile unsigned int *, int); +static void mot82XXhscHandleMaskInt(volatile unsigned int *, int); +static void mot82XXhscHandlePSInt(volatile unsigned int *, int); +static void mot82XXhscHandleAlarmInt(volatile unsigned int *, int); +static void mot82XXhscHandleBusInt(volatile unsigned int *, int); + +/* Sub functions called by the ioctl system call */ +static int mot82XXhscGetRegs(unsigned long); +static int mot82XXhscGetEvents(unsigned long); +static int mot82XXhscSetAlarm(unsigned int, unsigned int); +static int mot82XXhscGetAlarm(unsigned long); +static int mot82XXhscSetLed(unsigned int, unsigned int); +static int mot82XXhscGetLed(unsigned long); +static int mot82XXhscSetPBay(unsigned long); +static int mot82XXhscGetPBay(unsigned long); +static int mot82XXhscSetPS(unsigned long); +static int mot82XXhscGetPS(unsigned long); +static int mot82XXhscGetLocalHost(unsigned long); +static int mot82XXhscGetBusState(unsigned long); +static int mot82XXhscTakeBus(unsigned long); +static int mot82XXhscFreeBus(unsigned long); +static int mot82XXhscAllowBusTake(unsigned long); +static int mot82XXhscGetEnumMask(unsigned long); +static int mot82XXhscGetEnum(unsigned long); +static int mot82XXhscGetNonHost(unsigned long); +static int mot82XXhscSetNonHost(unsigned long); +static int mot82XXhscGetHost(unsigned long); +static int mot82XXhscSetHostst(unsigned long); +static int mot82XXhscGetHsc(unsigned long); +static int mot82XXhscSetHsc(unsigned long); + +/* Generally used suport functions */ +static int mot82XXhscAttachBus(int, int); +static int mot82XXhscReleaseBus(int); +void mot82XXhscTakeTimeOutFunc(unsigned long); + +/* Functions to support the PICMG 2.12 ENUM# functionality. */ +int mot82XXhscHsiInit(void); +BOOLEAN mot82XXhscHsiCheckEnumInterrupt(void *); +BOOLEAN mot82XXhscHsiQueryEnumState(void); +HSI_STATUS mot82XXhscHsiEnableEnums(void); +HSI_STATUS mot82XXhscHsiDisableEnums(void); +int mot82XXhscHsiConvertStatus(HSI_STATUS); + +/* Functions to be accessed from the PICMG 2.12 independent code */ +int HsiThreadRegister(void); +void HsiPlatformEnumHandler(int, void *, struct pt_regs *); + +/* Functions to support the generic chassis managment API. */ +int mot82xxChassisStatusFunc(unsigned int, unsigned int); +int mot82xxChassisAlarmFunc(unsigned int, unsigned int); + +/* Functions supporting delivery of events to user level requesters. */ +HscMessage *mot82XXhscAllocMessage(void); +void mot82XXhscFreeMessage(HscMessage *); +void mot82XXhscSendEvent(int, int, int, int); + +/* Accessing the registers on the board. */ +static void mot82XXhscClrBits(volatile unsigned int *, unsigned int); +static void mot82XXhscSetBits(volatile unsigned int *, unsigned int); + +/* Used in the bus status interrupt. */ +void motCpciSetDomainTakeover(int); + +/* Driver fops interface/ */ +static struct file_operations mot82XXhsc_fops = { + read: mot82XXhsc_read, + ioctl: mot82XXhsc_ioctl, + open: mot82XXhsc_open, + release: mot82XXhsc_release, + fasync: mot82XXhsc_fasync, +}; + +/* General driver internal information. */ +HscInfo MotHscInfo; +HscStats MotHscStats; + +/* Eventing mechanism support data structures. */ +HscEventRequesters MotEventRequesters[MOTHSC_MAX_EVENT_REQUESTERS]; +HscEventRequesters *MotEventRequestersList = NULL; +HscEventRequesters *MotEventRequestersFreeList; +HscMessage *MotMessageFreeList; + +/* Bus take over time out control structure. */ +struct timer_list mot82XXhscTakeTimeOut; + +/* + * Driver init routine. + */ +int +mot82XXhsc_init(void) +{ + int loop; + HscMessage *TmpMessPtr; + unsigned long Bits; + int State; + + printk("Initialize the Motorola 82XX Hot Swap Controller\n"); + + /* Find the devices location information. */ + MotHscInfo.Device = pci_find_device(PCI_VENDOR_ID_MOTOROLA, + PCI_DEVICE_ID_MOTOROLA_CPX8216, NULL); + + if (!MotHscInfo.Device) { + MotHscInfo.Device = pci_find_device(PCI_VENDOR_ID_MOTOROLA, + PCI_DEVICE_ID_MOTOROLA_CPX8216T, NULL); + } + + if (!MotHscInfo.Device) { + MotHscInfo.Device = pci_find_device(PCI_VENDOR_ID_MOTOROLA, + PCI_DEVICE_ID_MOTOROLA_CPX8216A, NULL); + } + + if (!MotHscInfo.Device) { + MotHscInfo.Device = pci_find_device(PCI_VENDOR_ID_MOTOROLA, + PCI_DEVICE_ID_MOTOROLA_CPX8221, NULL); + + if (MotHscInfo.Device) { + printk("mot82XXhsc: Motoroal 8221 Chassis not supported\n"); + return -ENODEV; + } + } + + if (!MotHscInfo.Device) { + printk("mot82XXhsc: Failed to find 82XX Hot Swap Controller\n"); + return -ENODEV; + } + + if ((MotHscInfo.Regs = (HscRegs *)ioremap( + pci_resource_start(MotHscInfo.Device, 0), + pci_resource_len(MotHscInfo.Device, 0))) == NULL) { + printk("mot82XXhsc: Ioremap failed\n"); + return -EIO; + } + + if (request_irq(MotHscInfo.Device->irq, (void *)&mot82XXhsc_intr, + SA_SHIRQ, "82XX HSC", &mot82XXhsc_fops)) { + printk("mot82XXhsc: Interrupt request failed\n"); + iounmap((void *)MotHscInfo.Regs); + return -EIO; + } + + if ((MotHscInfo.Major = register_chrdev(0, "82XX Hot Swap Controller", + &mot82XXhsc_fops)) < 0) { + printk("mot82XXhsc: Failed to register 82XX HSC\n"); + free_irq(MotHscInfo.Device->irq, &mot82XXhsc_fops); + iounmap((void *)MotHscInfo.Regs); + return -ENODEV; + } + + /* Initialize the event requesters free list */ + for (loop = 0; loop Event = 0; + TmpMessPtr->Unit = 0; + TmpMessPtr->Val = 0; + TmpMessPtr->Next = TmpMessPtr + 1; + TmpMessPtr++; + } + TmpMessPtr->Event = 0; + TmpMessPtr->Unit = 0; + TmpMessPtr->Val = 0; + TmpMessPtr->Next = NULL; + + /* Set up some pointers needed for interrupt handling. */ + mot82XXhscMapIntBitsToRegisters(); + + /* Byt default do not allow the other host to take bus. */ + MotHscInfo.BusTakeoverAllowed[0] = 0; + MotHscInfo.BusTakeoverAllowed[1] = 0; + + /* Keep track of the last bus control register for later use */ + MotHscInfo.LastBusControl[0] = MOTHSC_READREG(BusControl[0]); + MotHscInfo.LastBusControl[1] = MOTHSC_READREG(BusControl[1]); + + /* Get the host for future information */ + MotHscInfo.Host = (MotHscInfo.LastBusControl[0] & + MOTHSC_HOST_DOMAIN) >> 7; + + /* Clear enum events for the moment */ + mot82XXhscClrBits(&MotHscInfo.Regs->IntMask, MOTHSC_ENUMA); + mot82XXhscClrBits(&MotHscInfo.Regs->IntMask, MOTHSC_ENUMB); + + /* Turn off the enum propigate bit */ + mot82XXhscClrBits(&MotHscInfo.Regs->IntMask, MOTHSC_PROP_ENUM); + + /* Save the state of the ENUM bits for future use */ + MotHscInfo.EnumOldState[0] = MOTHSC_READREG(IntMask) & MOTHSC_A_STATE; + MotHscInfo.EnumOldState[1] = MOTHSC_READREG(IntMask) & MOTHSC_B_STATE; + + /* Indicate that enums are disabled */ + MotHscInfo.EnumEnabled[0] = 0; + MotHscInfo.EnumEnabled[1] = 0; + + /* + * SANITY CHECK: + * Do a little consistancy check. If the bus state indicates the + * bus is being taken away from us then give it up. In the same + * way, if We we in bus take over then finish the take over. As + * soon as this is all finishished the configuration software can + * continue to get or give busses as needed. + */ + State = MOTHSC_READREG(BusControl[0]); + if ((State & (MOTHSC_XFR_CTL1|MOTHSC_XFR_CTL2)) == MOTHSC_XFR_CTL1) { + /* Currently in bus A being taken over by this host */ + mot82XXhscSetBits(&MotHscInfo.Regs->BusControl[0], + MOTHSC_XFR_CTL2); + } + + if ((State & (MOTHSC_XFR_STS1|MOTHSC_XFR_STS2)) == MOTHSC_XFR_STS1) { + /* Currently bus A being taken over by other host */ + mot82XXhscClrBits(&MotHscInfo.Regs->BusControl[0], + MOTHSC_XFR_CTL1|MOTHSC_XFR_CTL2); + } + + State = MOTHSC_READREG(BusControl[1]); + if ((State & (MOTHSC_XFR_CTL1|MOTHSC_XFR_CTL2)) == MOTHSC_XFR_CTL1) { + /* Currently in bus B being taken over by this host */ + mot82XXhscSetBits(&MotHscInfo.Regs->BusControl[1], + MOTHSC_XFR_CTL2); + } + + if ((State & (MOTHSC_XFR_STS1|MOTHSC_XFR_STS2)) == MOTHSC_XFR_STS1) { + /* Currently bus B being taken over by other host */ + mot82XXhscClrBits(&MotHscInfo.Regs->BusControl[1], + MOTHSC_XFR_CTL1|MOTHSC_XFR_CTL2); + } + + /* Set the host slots to generate interrupts and set the history */ + mot82XXhscClrBits(&MotHscInfo.Regs->Slot[6], MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->Slot[6], MOTHSC_INTA_ENABLE); + + mot82XXhscClrBits(&MotHscInfo.Regs->Slot[8], MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->Slot[8], MOTHSC_INTA_ENABLE); + + Bits = MOTHSC_READREG(Slot[6]); + MotHscInfo.HostOldBits[6] = ((Bits & 0x7f) + + ((Bits & MOTHSC_ACTIVE) >> 14) + + ((Bits & 0x700) >> 1)) & ~MOTHSC_HOSTINT; + MotHscInfo.HostOldIntBits[6] = Bits & MOTHSC_HOSTINT; + + Bits = MOTHSC_READREG(Slot[8]); + MotHscInfo.HostOldBits[8] = ((Bits & 0x7f) + + ((Bits & MOTHSC_ACTIVE) >> 14) + + ((Bits & 0x700) >> 1)) & ~MOTHSC_HOSTINT; + MotHscInfo.HostOldIntBits[8] = Bits & MOTHSC_HOSTINT; + + /* Do the same for the HSC slots */ + mot82XXhscClrBits(&MotHscInfo.Regs->Slot[7], MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->Slot[7], MOTHSC_INTA_ENABLE); + + mot82XXhscClrBits(&MotHscInfo.Regs->Slot[9], MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->Slot[9], MOTHSC_INTA_ENABLE); + + Bits = MOTHSC_READREG(Slot[7]); + MotHscInfo.HscOldBits[7] = ((Bits & 0x7f) + + ((Bits & MOTHSC_ACTIVE) >> 14) + + ((Bits & 0x700) >> 1)) & ~MOTHSC_HSCINT; + MotHscInfo.HscOldIntBits[7] = Bits & MOTHSC_HOSTINT; + + Bits = MOTHSC_READREG(Slot[9]); + MotHscInfo.HscOldBits[9] = ((Bits & 0x7f) + + ((Bits & MOTHSC_ACTIVE) >> 14) + + ((Bits & 0x700) >> 1)) & ~MOTHSC_HSCINT; + MotHscInfo.HscOldIntBits[9] = Bits & MOTHSC_HOSTINT; + + /* Set interrupts to occure from status register */ + mot82XXhscClrBits(&MotHscInfo.Regs->IntMask, MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->IntMask, MOTHSC_INTA_ENABLE | MOTHSC_INTA); + + /* Set interrupts to occur from alarm register */ + mot82XXhscClrBits(&MotHscInfo.Regs->Alarm, MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->Alarm, MOTHSC_INTA_ENABLE); + + /* Set interrupts to occur from system led register */ + mot82XXhscClrBits(&MotHscInfo.Regs->SysLed, MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->SysLed, MOTHSC_INTA_ENABLE); + + /* Set interrupts to occur from Peripheral bay registers */ + for (loop = 0; loop < MOTHSC_NUM_PBAY; loop++) { + mot82XXhscClrBits(&MotHscInfo.Regs->PBay[loop], MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->PBay[loop], MOTHSC_INTA_ENABLE); + + /* Keep track of the last bits in the peripheral bay registers */ + MotHscInfo.PBayOldBits[loop] = MOTHSC_READREG(PBay[loop]); + MotHscInfo.PBayOldBits[loop] = + (MotHscInfo.PBayOldBits[loop] & 0x7) + + ((MotHscInfo.PBayOldBits[loop] & 0x300) >> 5); + } + + /* Set interrupts to occur from Power Supply registers */ + for (loop = 0; loop < MOTHSC_NUM_PS; loop++) { + mot82XXhscClrBits(&MotHscInfo.Regs->Ps[loop], MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->Ps[loop], MOTHSC_INTA_ENABLE); + + /* Keep track of the last bits in the power supply registers */ + MotHscInfo.PowerOldBits[loop] = MOTHSC_READREG(Ps[loop]); + MotHscInfo.PowerOldBits[loop] = + (MotHscInfo.PBayOldBits[loop] & 0x1f) + + ((MotHscInfo.PBayOldBits[loop] & 0x7f00) >> 3); + } + + /* Save off the status bits for slot controls. */ + for (loop = 0; loop < MOTHSC_NUM_SLOTS; loop++) { + if ((loop > 5) && (loop < 10)) { + continue; + } + + Bits = MOTHSC_READREG(Slot[loop]) & ~MOTHSC_SLOTINT; + MotHscInfo.SlotOldBits[loop] = ((Bits & 0x7f) + + ((Bits & MOTHSC_ACTIVE) >> 14) + + ((Bits & 0x700) >> 1)) & ~MOTHSC_SLOTINT; + MotHscInfo.SlotOldIntBits[loop] = ((Bits & 0x7f) + + ((Bits & MOTHSC_ACTIVE) >> 14) + + ((Bits & 0x700) >> 1)) & MOTHSC_SLOTINT; + } + + /* Set up the timer queue for delayed take over of a bus */ + init_timer(&mot82XXhscTakeTimeOut); + mot82XXhscTakeTimeOut.function = mot82XXhscTakeTimeOutFunc; + + /* If the PICMG 2.12 interface has been enabled then init it. */ + if (mot82XXhscHsiInit()) { + unregister_chrdev(MotHscInfo.Major, "82XX Hot Swap Controller"); + free_irq(MotHscInfo.Device->irq, &mot82XXhsc_fops); + iounmap((void *)MotHscInfo.Regs); + return -ESRCH; + } + + /* Start the PICMG 2.12 handling thread. */ + HsiThreadRegister(); + +#ifdef CONFIG_CHASSIS_CONTROL + /* Register chassis managment functions. */ + ChassisRegSystemStatusFunc(mot82xxChassisStatusFunc); + ChassisRegAlarmFunc(mot82xxChassisAlarmFunc); +#endif + return 0; +} + +/* + * Linux read interface. + * + * Currently a null function. Needs to be updated to provide some + * basic driver information. + */ +static ssize_t +mot82XXhsc_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + return (ssize_t)0; +} + +/* + * Linux ioctl interface. + * + * Most of the functionality of the driver is controlled through this + * interface. The argument variable is passed directly to the sub + * functionality for most cases. The exception is the ENUM mask set + * operation. It is different to allow the function to used from other + * locations. + */ +static int +mot82XXhsc_ioctl(struct inode *inode, + struct file *file, unsigned int cmd, unsigned long arg) +{ + unsigned int EnumUser; + int bus; + int flag; + MotHscAlarmLedSet AlarmUser; + + switch (cmd) { + case HSC_GET_REGISTERS: + return mot82XXhscGetRegs(arg); + case HSC_GET_EVENTS: + return mot82XXhscGetEvents(arg); + case HSC_SET_ALARM: + if (copy_from_user((void *)&AlarmUser, (void *)arg, + sizeof(MotHscAlarmLedSet))) { + return -EFAULT; + } + + return mot82XXhscSetAlarm(AlarmUser.MasBits, AlarmUser.MasFlag); + + case HSC_GET_ALARM_STAT: + return mot82XXhscGetAlarm(arg); + case HSC_SET_LED: + if (copy_from_user((void *)&AlarmUser, (void *)arg, + sizeof(MotHscAlarmLedSet))) { + return -EFAULT; + } + + return mot82XXhscSetLed(AlarmUser.MasBits, AlarmUser.MasFlag); + + case HSC_GET_LED_STAT: + return mot82XXhscGetLed(arg); + case HSC_SET_PBAY: + return mot82XXhscSetPBay(arg); + case HSC_GET_PBAY_STAT: + return mot82XXhscGetPBay(arg); + case HSC_SET_POWER: + return mot82XXhscSetPS(arg); + case HSC_GET_POWER_STAT: + return mot82XXhscGetPS(arg); + case HSC_GET_LOCALHOST: + return mot82XXhscGetLocalHost(arg); + case HSC_GET_BUS_STATE: + return mot82XXhscGetBusState(arg); + case HSC_TAKE_BUS: + return mot82XXhscTakeBus(arg); + case HSC_FREE_BUS: + return mot82XXhscFreeBus(arg); + case HSC_ALLOW_BUS_TAKE: + return mot82XXhscAllowBusTake(arg); + case HSC_SET_ENUMMASK: + if (copy_from_user((void *)&EnumUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + bus = (EnumUser & 0x3) - 1; + flag = (EnumUser & 0x4) >> 2; + + return mot82XXhscSetEnumMask(bus, flag); + case HSC_GET_ENUMMASK: + return mot82XXhscGetEnumMask(arg); + case HSC_GET_ENUM: + return mot82XXhscGetEnum(arg); + case HSC_GET_NONHOST: + return mot82XXhscGetNonHost(arg); + case HSC_SET_NONHOST: + return mot82XXhscSetNonHost(arg); + case HSC_GET_HOST: + return mot82XXhscGetHost(arg); + case HSC_SET_HOST: + return mot82XXhscSetHostst(arg); + case HSC_GET_HSC: + return mot82XXhscGetHsc(arg); + case HSC_SET_HSC: + return mot82XXhscSetHsc(arg); + default: + MotHscStats.BogusCmds++; + return -EINVAL; + } + + return 0; +} + +/* + * Linux driver open function. + * + * Driver itself does not do much with this function. Mostly + * exists to allow the kernel code to complete the open. + */ +static int +mot82XXhsc_open(struct inode *inode, struct file *file) +{ + MotHscStats.TotalOpens++; + MotHscStats.CurOpens++; + + return 0; +} + +/* + * Linux driver close function. + * + * Closeing the driver must ensure the data structures for the + * process have been properly freed. + */ +static int +mot82XXhsc_release(struct inode *inode, struct file *file) +{ + HscEventRequesters *TempEvReq; + HscEventRequesters *DelEvReq = NULL; + + MotHscStats.CurOpens--; + + /* Check to see if this process is listed with the event + * requesters. + */ + TempEvReq = MotEventRequestersList; + + if (TempEvReq == NULL) { + return 0; + } + + if (TempEvReq->Pid == current->pid) { + MotEventRequestersList = MotEventRequestersList->Next; + DelEvReq = TempEvReq; + } else { + while (TempEvReq->Next) { + if (TempEvReq->Next->Pid == current->pid) { + DelEvReq = TempEvReq->Next; + TempEvReq->Next = DelEvReq->Next; + } + if (TempEvReq->Next) { + TempEvReq = TempEvReq->Next; + } + } + } + + if (DelEvReq) { + DelEvReq->Pid = 0; + DelEvReq->Fasyncptr = 0; + DelEvReq->Next = MotEventRequestersFreeList; + MotEventRequestersFreeList = DelEvReq; + } + + return 0; +} + +/* + * Linux driver asynchronous notification function. + * + * Correctly register or deregister from the event notification list. + */ +static int +mot82XXhsc_fasync(int fd, struct file *fp, int on) +{ + HscEventRequesters *TempEvReq; + HscEventRequesters *DelEvReq = NULL; + int rv; + + if (on) { + if (MotEventRequestersFreeList == NULL) { + return -ENOSPC; + } + + TempEvReq = MotEventRequestersFreeList; + MotEventRequestersFreeList = MotEventRequestersFreeList->Next; + + TempEvReq->Pid = current->pid; + + if ((rv = fasync_helper(fd, fp, on, &TempEvReq->Fasyncptr)) < 1) { + TempEvReq->Next = MotEventRequestersFreeList; + MotEventRequestersFreeList = TempEvReq; + return rv; + } + + TempEvReq->Next = MotEventRequestersList; + MotEventRequestersList = TempEvReq; + } else { + TempEvReq = MotEventRequestersList; + if (TempEvReq->Pid == current->pid) { + MotEventRequestersList = MotEventRequestersList->Next; + DelEvReq = TempEvReq; + } else { + while (TempEvReq->Next) { + if (TempEvReq->Next->Pid == current->pid) { + DelEvReq = TempEvReq->Next; + TempEvReq->Next = DelEvReq->Next; + } + if (TempEvReq->Next) { + TempEvReq = TempEvReq->Next; + } + } + } + + if (DelEvReq) { + DelEvReq->Pid = 0; + DelEvReq->Next = MotEventRequestersFreeList; + MotEventRequestersFreeList = DelEvReq; + + if ((rv = fasync_helper(fd, fp, on, &TempEvReq->Fasyncptr)) < 1) { + return rv; + } + } else { + return -EPERM; + } + } + + return 0; +}; + +/* Information for each bit in the interrupt register. */ +HscRegInfo MotHscRegInfo[32] = { + {(unsigned int *)0, 0, mot82XXhscHandleSlotInt}, /* Bit 0 */ + {(unsigned int *)0, 1, mot82XXhscHandleSlotInt}, /* Bit 1 */ + {(unsigned int *)0, 2, mot82XXhscHandleSlotInt}, /* Bit 2 */ + {(unsigned int *)0, 3, mot82XXhscHandleSlotInt}, /* Bit 3 */ + {(unsigned int *)0, 4, mot82XXhscHandleSlotInt}, /* Bit 4 */ + {(unsigned int *)0, 5, mot82XXhscHandleSlotInt}, /* Bit 5 */ + {(unsigned int *)0, 0, mot82XXhscHandleHostInt}, /* Bit 6 */ + {(unsigned int *)0, 0, mot82XXhscHandleHSCInt}, /* Bit 7 */ + {(unsigned int *)0, 1, mot82XXhscHandleHostInt}, /* Bit 8 */ + {(unsigned int *)0, 1, mot82XXhscHandleHSCInt}, /* Bit 9 */ + {(unsigned int *)0, 10, mot82XXhscHandleSlotInt}, /* Bit 10 */ + {(unsigned int *)0, 11, mot82XXhscHandleSlotInt}, /* Bit 11 */ + {(unsigned int *)0, 12, mot82XXhscHandleSlotInt}, /* Bit 12 */ + {(unsigned int *)0, 13, mot82XXhscHandleSlotInt}, /* Bit 13 */ + {(unsigned int *)0, 14, mot82XXhscHandleSlotInt}, /* Bit 14 */ + {(unsigned int *)0, 15, mot82XXhscHandleSlotInt}, /* Bit 15 */ + {(unsigned int *)0, 0, mot82XXhscHandlePbayInt}, /* Bit 16 */ + {(unsigned int *)0, 1, mot82XXhscHandlePbayInt}, /* Bit 17 */ + {(unsigned int *)0, 2, mot82XXhscHandlePbayInt}, /* Bit 18 */ + {(unsigned int *)0, 3, mot82XXhscHandlePbayInt}, /* Bit 19 */ + {(unsigned int *)0, 0, NULL}, /* Bit 20 */ + {(unsigned int *)0, 0, NULL}, /* Bit 21 */ + {(unsigned int *)0, 0, NULL}, /* Bit 22 */ + {(unsigned int *)0, 0, mot82XXhscHandleMaskInt}, /* Bit 23 */ + {(unsigned int *)0, 0, NULL}, /* Bit 24 */ + {(unsigned int *)0, 0, NULL}, /* Bit 25 */ + {(unsigned int *)0, 0, mot82XXhscHandlePSInt}, /* Bit 26 */ + {(unsigned int *)0, 1, mot82XXhscHandlePSInt}, /* Bit 27 */ + {(unsigned int *)0, 2, mot82XXhscHandlePSInt}, /* Bit 28 */ + {(unsigned int *)0, 0, mot82XXhscHandleAlarmInt}, /* Bit 29 */ + {(unsigned int *)0, 0, mot82XXhscHandleBusInt}, /* Bit 30 */ + {(unsigned int *)0, 1, mot82XXhscHandleBusInt} /* Bit 31 */ +}; + +/* + * Linux driver interrupt routine. + * + * At interrupt this routine calls the associated function for each + * bit in the interrupt register that is set. + */ +static void +mot82XXhsc_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int status_reg; + int status_bit; + HscRegInfo *int_reg; + + /* Insure the interrupt is for this driver. */ + if (dev_id != (void *)&mot82XXhsc_fops) { + return; + } + + /* Check for bogus interrupts */ + if (!(status_reg = MOTHSC_READREG(IntStatus[0]))) { + return; + } + + for (status_bit = 0; status_bit < MOTHSC_REG_SIZE; status_bit++) { + /* Bit not set - interrupt not present */ + if (!((1 << status_bit) & status_reg)) { + continue; + } + + int_reg = MOTHSC_GET_REG_FROM_BIT(status_bit); + + mot82XXhscClrBits(int_reg->Reg, MOTHSC_INT_STATUS); + + MOT_HSC_CALL_INT_HANDLER(status_bit, int_reg); + } +} + +/* + * Interrupt handling sub routine for the non host slot control + * registers. Routine will generate an event for each bit changed that + * can result in an interrupt being posted. + */ +static void +mot82XXhscHandleSlotInt(volatile unsigned int *reg, int slot) +{ + unsigned int Bits; + unsigned int OldBits; + int loop; + + Bits = MOTHSC_READREG(Slot[slot]) & MOTHSC_SLOTINT; + OldBits = MotHscInfo.SlotOldIntBits[slot]; + + for (loop = 0; loop < 7; loop++) { + if ((Bits & (0x1 << loop)) && !(OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + slot, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + slot, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + MotHscInfo.SlotOldIntBits[slot] = Bits; +} + +/* + * Interrupt handling sub routine for the host slot control + * registers. Routine will generate an event for each bit changed that + * can result in an interrupt being posted. + */ +static void +mot82XXhscHandleHostInt(volatile unsigned int *reg, int host) +{ + unsigned int Bits; + unsigned int OldBits; + int loop; + int slot; + + slot = (host * 2) + 6; + + Bits = MOTHSC_READREG(Slot[slot]) & MOTHSC_HOSTINT; + OldBits = MotHscInfo.HostOldIntBits[slot]; + + for (loop = 0; loop < 7; loop++) { + if ((Bits & (0x1 << loop)) && !(OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + slot, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + slot, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + MotHscInfo.HostOldIntBits[slot] = Bits; +} + +/* + * Interrupt handling sub routine for the bridge slot control + * registers. Routine will generate an event for each bit changed that + * can result in an interrupt being posted. + */ +static void +mot82XXhscHandleHSCInt(volatile unsigned int *reg, int hsc) +{ + unsigned int Bits; + unsigned int OldBits; + int loop; + int slot; + + slot = (hsc * 2) + 7; + + Bits = MOTHSC_READREG(Slot[slot]) & MOTHSC_HSCINT; + OldBits = MotHscInfo.HscOldIntBits[slot]; + + for (loop = 0; loop < 6; loop++) { + if ((Bits & (0x1 << loop)) && !(OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + slot, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + slot, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + MotHscInfo.HscOldIntBits[slot] = Bits; +} + +/* + * Interrupt handling sub routine for the peripheral bay control + * registers. Routine will generate an event for each bit changed that + * can result in an interrupt being posted. + */ +static void +mot82XXhscHandlePbayInt(volatile unsigned int *reg, int bay) +{ + unsigned int Bits; + int loop; + + Bits = MOTHSC_READREG(PBay[bay]); + Bits = (Bits & 0x7) + ((Bits & 0x300) >> 5); + + for (loop = 0; loop < 5; loop++) { + if ((Bits & (0x1 << loop)) && + !(MotHscInfo.PBayOldBits[bay] & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_PBAY1 + bay, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (MotHscInfo.PBayOldBits[bay] & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_PBAY1 + bay, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + MotHscInfo.PBayOldBits[bay] = Bits; + return; +} + +/* + * Interrupt handling sub routine for the interrupt mask control + * registers. Routine will generate an event for each bit changed that + * can result in an interrupt being posted. + */ +static void +mot82XXhscHandleMaskInt(volatile unsigned int *reg, int unused) +{ + int EnumState = MOTHSC_READREG(IntMask); + int OldMaskState; + + if (EnumState & MOTHSC_A_STATE) { + /* Bus A has generated an ENUM interrupt. */ + OldMaskState = EnumState & MOTHSC_ENUMA; + + /* Disable ENUM generation on this bus until the ENUM clears. */ + mot82XXhscClrBits(&MotHscInfo.Regs->IntMask, MOTHSC_ENUMA); + if (OldMaskState) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_ENUMMASK, + MOT82XXHSC_BUS_A, MOT82XXHSC_EVENT_OFF); + } + + /* If the old state was off then this is a new enum. */ + if (!MotHscInfo.EnumOldState[0]) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_ENUM, + MOT82XXHSC_BUS_A, MOT82XXHSC_EVENT_ON); + /* IF the PICMG 2.12 is configured then call its + * interrupt routine. + */ + HsiPlatformEnumHandler(0, NULL, NULL); + } + } + + if (EnumState & MOTHSC_B_STATE) { + /* Bus B has generated an ENUM interrupt. */ + OldMaskState = EnumState & MOTHSC_ENUMB; + + /* Disable ENUM generation on this bus until the ENUM clears. */ + mot82XXhscClrBits(&MotHscInfo.Regs->IntMask, MOTHSC_ENUMB); + if (OldMaskState) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_ENUMMASK, + MOT82XXHSC_BUS_B, MOT82XXHSC_EVENT_OFF); + } + + /* If the old state was off then this is a new enum. */ + if (!MotHscInfo.EnumOldState[1]) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_ENUM, + MOT82XXHSC_BUS_B, MOT82XXHSC_EVENT_ON); + /* IF the PICMG 2.12 is configured then call its + * interrupt routine. + */ + HsiPlatformEnumHandler(0, NULL, NULL); + } + } + + /* Update the history information. */ + MotHscInfo.EnumOldState[0] = MOTHSC_READREG(IntMask) & MOTHSC_A_STATE; + MotHscInfo.EnumOldState[1] = MOTHSC_READREG(IntMask) & MOTHSC_B_STATE; +} + +/* + * Interrupt handling sub routine for the power supply control + * registers. Routine will generate an event for each bit changed that + * can result in an interrupt being posted. + */ +static void +mot82XXhscHandlePSInt(volatile unsigned int *reg, int supply) +{ + unsigned int Bits; + int loop; + + Bits = MOTHSC_READREG(Ps[supply]); + Bits = (Bits & 0x1f) + ((Bits & 0x7f00) >> 3); + + for (loop = 0; loop < 12; loop++) { + if ((Bits & (0x1 << loop)) && + !(MotHscInfo.PowerOldBits[supply] & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_PS1 + supply, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (MotHscInfo.PowerOldBits[supply] & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_PS1 + supply, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + MotHscInfo.PowerOldBits[supply] = Bits; +} + +/* + * Interrupt handling sub routine for the chassis alarm control + * registers. Routine will generate an event for each bit changed that + * can result in an interrupt being posted. + */ +static void +mot82XXhscHandleAlarmInt(volatile unsigned int *reg, int unused) +{ + return; +} + +/* + * Interrupt handling sub routine for the bus control + * registers. Routine will generate an event for each bit changed that + * can result in an interrupt being posted. + */ +static void +mot82XXhscHandleBusInt(volatile unsigned int *reg, int bus) +{ + unsigned int check_val1; + unsigned int check_val2 = (MotHscInfo.LastBusControl[bus] & + (MOTHSC_XFR_CTL1 | MOTHSC_XFR_CTL2 | + MOTHSC_XFR_STS1 | MOTHSC_XFR_STS2)) >> 1; + + /* Is the other side requesting the bus */ + if (MOTHSC_READREG(BusControl[bus]) & MOTHSC_XFR_STS1) { + /* Does the other side now posses the bus. */ + if ((MOTHSC_READREG(BusControl[bus]) & MOTHSC_XFR_STS2) && + (check_val2 == HSC_STATE_MINE)) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_BUS_RELEASED, + bus + MOT82XXHSC_BUS_A, 0); + MotHscInfo.BusTakeoverAllowed[bus] = 0; + MotHscInfo.LastBusControl[bus] = + MOTHSC_READREG(BusControl[bus]); + motCpciSetDomainTakeover(bus); + return; + } + + /* If we have allowed the other side to take over the bus + * then let him have it. Else send an event to use software + * requesting the bus. */ + if (MotHscInfo.BusTakeoverAllowed[bus]) { + /* Grant the takeover */ + mot82XXhscClrBits(&MotHscInfo.Regs->BusControl[bus], + MOTHSC_XFR_CTL1); + } else { + /* Send event indicating take over request */ + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_BUS_TAKE_REQ, + bus + MOT82XXHSC_BUS_A, 0); + } + + MotHscInfo.LastBusControl[bus] = + MOTHSC_READREG(BusControl[bus]); + return; + } + + check_val1 = (MOTHSC_READREG(BusControl[bus]) & + (MOTHSC_XFR_CTL1 | MOTHSC_XFR_CTL2 | + MOTHSC_XFR_STS1 | MOTHSC_XFR_STS2)) >> 1; + check_val2 = (MotHscInfo.LastBusControl[bus] & + (MOTHSC_XFR_CTL1 | MOTHSC_XFR_CTL2 | + MOTHSC_XFR_STS1 | MOTHSC_XFR_STS2)) >> 1; + + /* Check to see if the transitions have competed. */ + switch (check_val1) { + case HSC_STATE_MINE: + switch(check_val2) { + case HSC_STATE_OTHER: + case HSC_STATE_FREE: + /* Notify event the bus take over has compeleted. */ + del_timer(&mot82XXhscTakeTimeOut); + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_BUS_TAKE_DONE, + bus + MOT82XXHSC_BUS_A, 0); + break; + } + break; + default: + switch(check_val2) { + case HSC_STATE_MINE: + case HSC_STATE_OTHER: + /* Notify event the other host has taken the bus. */ + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_BUS_RELEASED, + bus + MOT82XXHSC_BUS_A, 0); + MotHscInfo.BusTakeoverAllowed[bus] = 0; + break; + } + break; + } + MotHscInfo.LastBusControl[bus] = MOTHSC_READREG(BusControl[bus]); + return; +} + +/* + * Fill in the register pointers in the driver instance information. Since + * the registers exist on ioremaped space this cannot be done at compile time. + */ +static void +mot82XXhscMapIntBitsToRegisters(void) +{ + + MotHscRegInfo[0].Reg = &MotHscInfo.Regs->Slot[0]; /* Bit 0 */ + MotHscRegInfo[1].Reg = &MotHscInfo.Regs->Slot[1]; /* Bit 1 */ + MotHscRegInfo[2].Reg = &MotHscInfo.Regs->Slot[2]; /* Bit 2 */ + MotHscRegInfo[3].Reg = &MotHscInfo.Regs->Slot[3]; /* Bit 3 */ + MotHscRegInfo[4].Reg = &MotHscInfo.Regs->Slot[4]; /* Bit 4 */ + MotHscRegInfo[5].Reg = &MotHscInfo.Regs->Slot[5]; /* Bit 5 */ + MotHscRegInfo[6].Reg = &MotHscInfo.Regs->Slot[6]; /* Bit 6 */ + MotHscRegInfo[7].Reg = &MotHscInfo.Regs->Slot[7]; /* Bit 7 */ + MotHscRegInfo[8].Reg = &MotHscInfo.Regs->Slot[8]; /* Bit 8 */ + MotHscRegInfo[9].Reg = &MotHscInfo.Regs->Slot[9]; /* Bit 9 */ + MotHscRegInfo[10].Reg = &MotHscInfo.Regs->Slot[10]; /* Bit 10 */ + MotHscRegInfo[11].Reg = &MotHscInfo.Regs->Slot[11]; /* Bit 11 */ + MotHscRegInfo[12].Reg = &MotHscInfo.Regs->Slot[12]; /* Bit 12 */ + MotHscRegInfo[13].Reg = &MotHscInfo.Regs->Slot[13]; /* Bit 13 */ + MotHscRegInfo[14].Reg = &MotHscInfo.Regs->Slot[14]; /* Bit 14 */ + MotHscRegInfo[15].Reg = &MotHscInfo.Regs->Slot[15]; /* Bit 15 */ + MotHscRegInfo[16].Reg = &MotHscInfo.Regs->PBay[0]; /* Bit 16 */ + MotHscRegInfo[17].Reg = &MotHscInfo.Regs->PBay[1]; /* Bit 17 */ + MotHscRegInfo[18].Reg = &MotHscInfo.Regs->PBay[2]; /* Bit 18 */ + MotHscRegInfo[19].Reg = &MotHscInfo.Regs->PBay[3]; /* Bit 19 */ + MotHscRegInfo[23].Reg = &MotHscInfo.Regs->IntMask; /* Bit 23 */ + MotHscRegInfo[26].Reg = &MotHscInfo.Regs->Ps[0]; /* Bit 26 */ + MotHscRegInfo[27].Reg = &MotHscInfo.Regs->Ps[1]; /* Bit 27 */ + MotHscRegInfo[28].Reg = &MotHscInfo.Regs->Ps[2]; /* Bit 28 */ + MotHscRegInfo[29].Reg = &MotHscInfo.Regs->Alarm; /* Bit 29 */ + MotHscRegInfo[30].Reg = &MotHscInfo.Regs->BusControl[0]; /* Bit 30 */ + MotHscRegInfo[31].Reg = &MotHscInfo.Regs->BusControl[1]; /* Bit 31 */ +} + +/* + * Ioctl sub function to retrieve hot swap controller register + * contents. Helps with debug. + */ +static int +mot82XXhscGetRegs(unsigned long arg) +{ + MotHscRegisters ToUser; + int loop; + + for (loop = 0; loop < MOTHSC_NUM_SLOTS; loop++) { + ToUser.MhrSlot[loop] = MOTHSC_READREG(Slot[loop]); + } + + for (loop = 0; loop < MOTHSC_NUM_SLOTS; loop++) { + ToUser.MhrPower[loop] = MOTHSC_READREG(Ps[loop]); + } + + for (loop = 0; loop < MOTHSC_NUM_PBAY; loop++) { + ToUser.MhrPBay[loop] = MOTHSC_READREG(PBay[loop]); + } + + ToUser.MhrIntStatMask = MOTHSC_READREG(IntStatMask); + + for (loop = 0; loop < MOTHSC_NUM_INTSTAT; loop++) { + ToUser.MhrIntStatus[loop] = MOTHSC_READREG(IntStatus[loop]); + } + + for (loop = 0; loop < MOTHSC_NUM_BUS; loop++) { + ToUser.MhrBusControl[loop] = MOTHSC_READREG(BusControl[loop]); + } + + ToUser.MhrEEprom = MOTHSC_READREG(EEprom); + ToUser.MhrSysLed = MOTHSC_READREG(SysLed); + ToUser.MhrAlarm = MOTHSC_READREG(Alarm); + ToUser.MhrIntMask = MOTHSC_READREG(IntMask); + + return copy_to_user((void *)arg, &ToUser, sizeof(MotHscRegisters)); +} + +/* + * Retrieve event information sub ioctl. + */ +static int +mot82XXhscGetEvents(unsigned long arg) +{ + MotHscEvents ToUser; + HscEventRequesters *Requester = MotEventRequestersList; + HscMessage *Message; + HscMessage *OldMessage; + + /* Find the reqestors id from the list of valid requestors. */ + while(Requester) { + if (current->pid != Requester->Pid) { + Requester = Requester->Next; + continue; + } + + Message = Requester->Head; + ToUser.Count = 0; + + /* For each message up to max, fill in the return info. */ + while (Message && (ToUser.Count < MOTHSC_EVENTS_MAX)) { + ToUser.Events[ToUser.Count].Event = Message->Event; + ToUser.Events[ToUser.Count].Unit = Message->Unit; + ToUser.Events[ToUser.Count].Val = Message->Val; + ToUser.Count++; + + OldMessage = Message; + Message = Message->Next; + mot82XXhscFreeMessage(OldMessage); + } + + if ((Requester->Head = Message) == NULL) { + Requester->Tail = NULL; + } + + return copy_to_user((void *)arg, &ToUser, sizeof(MotHscEvents)); + } + + return -EIO; +} + +/* + * Sub ioclt functionality to control the alarm register settings. + */ +static int +mot82XXhscSetAlarm(unsigned int bits, unsigned int flag) +{ + unsigned int Bits; + unsigned int OldBits; + int loop; + + if (bits & ~MOT82XXHSC_ALARM_MASK) { + return -EINVAL; + } + + Bits = bits << 8; + OldBits = MOTHSC_READREG(Alarm) >> 8; + + if (flag) { + mot82XXhscSetBits(&MotHscInfo.Regs->Alarm, Bits); + } else { + mot82XXhscClrBits(&MotHscInfo.Regs->Alarm, Bits); + } + + Bits = MOTHSC_READREG(Alarm) >> 8; + + /* Check register for any bit changes and return resulting events. */ + for (loop = 0; loop < 4; loop++) { + if ((Bits & (0x1 << loop)) && + !(OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_ALARM, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_ALARM, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + return 0; +} + +/* + * Sub ioctl to return current alarm bit settings. + */ +static int +mot82XXhscGetAlarm(unsigned long arg) +{ + int ToUser; + + ToUser = (MOTHSC_READREG(Alarm) >> 8) & MOT82XXHSC_ALARM_MASK; + + return copy_to_user((void *)arg, &ToUser, sizeof(int)); +} + +/* + * Ioctl sub function to set chassis LED control bits. + */ +static int +mot82XXhscSetLed(unsigned int bits, int unsigned flag) +{ + unsigned int Bits; + unsigned int OldBits; + int loop; + + if (bits & ~MOT82XXHSC_LED_MASK) { + return -EINVAL; + } + + Bits = bits << 8; + OldBits = MOTHSC_READREG(SysLed) >> 8; + + if (flag) { + mot82XXhscSetBits(&MotHscInfo.Regs->SysLed, bits); + } else { + mot82XXhscClrBits(&MotHscInfo.Regs->SysLed, bits); + } + + Bits = MOTHSC_READREG(SysLed) >> 8; + + for (loop = 0; loop < 4; loop++) { + if ((Bits & (0x1 << loop)) && + !(OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_LED, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_LED, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + return 0; +} + +/* + * Sub ioctl function to return the current chassis LED settings. + */ +static int +mot82XXhscGetLed(unsigned long arg) +{ + int ToUser; + + ToUser = (MOTHSC_READREG(SysLed) >> 8) & MOT82XXHSC_LED_MASK; + + return copy_to_user((void *)arg, &ToUser, sizeof(int)); +} + +/* + * Sub ioctl to set peripheral bay controls. + */ +static int +mot82XXhscSetPBay(unsigned long arg) +{ + MotHscPBayInfo FromUser; + unsigned int Bits; + int loop; + int bay; + + if (copy_from_user((void *)&FromUser, (void *)arg, + sizeof(MotHscPBayInfo))) { + return -EFAULT; + } + + if (FromUser.MpbiBits & ~MOT82XXHSC_PBAY_MASK) { + return -EINVAL; + } + + bay = FromUser.MpbiBay - 1; + + if ((bay < 0) || (bay > 3)) { + return -EINVAL; + } + + Bits = (FromUser.MpbiBits & 0x7) + ((FromUser.MpbiBits & 0x18) << 5); + + if (FromUser.MpbiFlag) { + mot82XXhscSetBits(&MotHscInfo.Regs->PBay[bay], Bits); + } else { + mot82XXhscClrBits(&MotHscInfo.Regs->PBay[bay], Bits); + } + + Bits = MOTHSC_READREG(PBay[bay]); + Bits = (Bits & 0x7) + ((Bits & 0x300) >> 5); + + for (loop = 0; loop < 5; loop++) { + if ((Bits & (0x1 << loop)) && + !(MotHscInfo.PBayOldBits[bay] & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_PBAY1 + bay, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (MotHscInfo.PBayOldBits[bay] & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_PBAY1 + bay, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + MotHscInfo.PBayOldBits[bay] = Bits; + return 0; +} + +/* + * Ioctl sub function to return the setting for the peripheral bay. + */ +static int +mot82XXhscGetPBay(unsigned long arg) +{ + int ToUser; + int FromUser; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + if ((FromUser < 1) || (FromUser > 4)) { + return -EINVAL; + } + + ToUser = MOTHSC_READREG(PBay[FromUser-1]); + ToUser = (ToUser & 0x7) | ((ToUser & 0x300) >> 5); + + return copy_to_user((void *)arg, &ToUser, sizeof(int)); +} + +/* + * Sub ioctl to control power supply settings. + */ +static int +mot82XXhscSetPS(unsigned long arg) +{ + MotHscPsInfo FromUser; + unsigned int Bits; + int loop; + int supply; + + if (copy_from_user((void *)&FromUser, (void *)arg, + sizeof(MotHscPsInfo))) { + return -EFAULT; + } + + if (FromUser.MpsiBits & ~MOT82XXHSC_PS_MASK) { + return -EINVAL; + } + + supply = FromUser.MpsiPS - 1; + + if ((supply < 0) || (supply > 2)) { + return -EINVAL; + } + + Bits = (FromUser.MpsiBits & 0x1f) + + ((FromUser.MpsiBits & 0xfe0) << 3); + + if (FromUser.MpsiFlag) { + mot82XXhscSetBits(&MotHscInfo.Regs->Ps[supply], Bits); + } else { + mot82XXhscClrBits(&MotHscInfo.Regs->Ps[supply], Bits); + } + + Bits = MOTHSC_READREG(Ps[supply]); + Bits = (Bits & 0x1f) + ((Bits & 0x7f00) >> 3); + + for (loop = 0; loop < 12; loop++) { + if ((Bits & (0x1 << loop)) && + !(MotHscInfo.PowerOldBits[supply] & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_PS1 + supply, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (MotHscInfo.PowerOldBits[supply] & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_PS1 + supply, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + MotHscInfo.PowerOldBits[supply] = Bits; + return 0; +} + +/* + * Ioctl sub function to return power supply control settings. + */ +static int +mot82XXhscGetPS(unsigned long arg) +{ + int ToUser; + int FromUser; + unsigned int Bits; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + if ((FromUser < 1) || (FromUser > 3)) { + return -EINVAL; + } + + Bits = MOTHSC_READREG(Ps[FromUser-1]); + ToUser = (Bits & 0x1f) | ((Bits & 0x7f00) >> 3); + + return copy_to_user((void *)arg, &ToUser, sizeof(int)); +} + +/* + * Return idication of which host (A or B) the software is executing on. + */ +static int +mot82XXhscGetLocalHost(unsigned long arg) +{ + return copy_to_user((void *)arg, &MotHscInfo.Host, sizeof(int)); +} + +/* + * Sub ioctl to return the bus state. + */ +static int +mot82XXhscGetBusState(unsigned long arg) +{ + unsigned int FromUser; + unsigned int ToUser; + int state; + int bus; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + bus = FromUser - 1; + state = (MOTHSC_READREG(BusControl[bus]) & 0x1e) >> 1; + + switch (state) { + case HSC_STATE_FREE: + ToUser = MOT82XXHSC_BUS_FREE; + break; + case HSC_STATE_OTHER: + ToUser = MOT82XXHSC_BUS_OTHER; + break; + case HSC_STATE_REQUESTED: + ToUser = MOT82XXHSC_BUS_REQUESTED; + break; + case HSC_STATE_TRAN_STRT: + ToUser = MOT82XXHSC_BUS_TRAN_START; + break; + case HSC_STATE_STOPED: + ToUser = MOT82XXHSC_BUS_STOPED; + break; + case HSC_STATE_TRAN_ACK: + ToUser = MOT82XXHSC_BUS_TRAN_ACK; + break; + case HSC_STATE_ENABLE: + ToUser = MOT82XXHSC_BUS_ENABLE; + break; + case HSC_STATE_TRAN_DONE: + ToUser = MOT82XXHSC_BUS_TRAN_DONE; + break; + case HSC_STATE_MINE: + ToUser = MOT82XXHSC_BUS_MINE; + break; + } + + if (MotHscInfo.BusTakeoverAllowed[bus]) { + ToUser |= MOT82XXHSC_BUS_ALLOWTO; + } + + return copy_to_user((void *)arg, &ToUser, sizeof(int)); +} + +/* + * Ioctl sub function to take over the specified bus. + */ +static int +mot82XXhscTakeBus(unsigned long arg) +{ + unsigned int FromUser; + int bus; + int timeout; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + bus = (FromUser & MOT82XXHSC_BUS_MASK) - 1; + + if ((bus < 0) || (bus > 1)) { + return -EINVAL; + } + + timeout = (FromUser & MOT82XXHSC_BUS_TIMEO_MASK) >> 16; + + return mot82XXhscAttachBus(bus, timeout); +} + +/* + * Ioctl sub function to free the specified bus. + */ +static int +mot82XXhscFreeBus(unsigned long arg) +{ + unsigned int FromUser; + int bus; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + bus = (FromUser & MOT82XXHSC_BUS_MASK) - 1; + + if ((bus < 0) || (bus > 1)) { + return -EINVAL; + } + + return mot82XXhscReleaseBus(bus); +} + +/* + * Ioctl sub function to allow the other host to take the bus. + */ +static int +mot82XXhscAllowBusTake(unsigned long arg) +{ + unsigned int FromUser; + int bus; + int flag; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + bus = (FromUser & MOT82XXHSC_BUS_MASK) - 1; + flag = FromUser & MOT82XXHSC_BUS_ALLOWTO; + + if (!(MotHscInfo.LastBusControl[bus] & + (MOTHSC_XFR_CTL1 | MOTHSC_XFR_CTL2))) { + /* Cannot grant allow a a bus thet is not owned by this + * processor. */ + return -EINVAL; + + } + + MotHscInfo.BusTakeoverAllowed[bus] = flag; + + if (!flag) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_BUS_DISALLOW, + bus + MOT82XXHSC_BUS_A, 0); + return 0; + } + + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_BUS_ALLOW, + bus + MOT82XXHSC_BUS_A, 0); + + /* Take over now allowed so check to see if take over has been + * requested. + */ + if (MOTHSC_READREG(BusControl[bus]) & MOTHSC_XFR_STS1) { + mot82XXhscClrBits(&MotHscInfo.Regs->BusControl[bus], + MOTHSC_XFR_CTL1); + MotHscInfo.LastBusControl[bus] = + MOTHSC_READREG(BusControl[bus]); + } + return 0; +} + +/* + * Sub ioctl to get the current enum bask setting for the specified bus. + */ +static int +mot82XXhscGetEnumMask(unsigned long arg) +{ + unsigned int FromUser; + unsigned int ToUser; + int bus; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + bus = (FromUser & 0x3) - 1; + + if ((bus < 0) || (bus > 1)) { + return -EINVAL; + } + + if (MOTHSC_READREG(IntMask) & (MOTHSC_ENUMA << bus)) { + ToUser = 1; + } else { + ToUser = 0; + } + + return copy_to_user((void *)arg, &ToUser, sizeof(int)); +} + +/* + * Sbu ioctl to set the enum bask for the specified bus. + */ +int +mot82XXhscSetEnumMask(int bus, int flag) +{ + int Stat; + int OldStat; + unsigned long flags; + + if ((bus < 0) || (bus > 1)) { + return -EINVAL; + } + + save_flags(flags); + cli(); + + OldStat = MOTHSC_READREG(IntMask) & (MOTHSC_ENUMA << bus); + + if (flag) { + MotHscInfo.EnumEnabled[bus] = 1; + mot82XXhscSetBits(&MotHscInfo.Regs->IntMask, + (MOTHSC_ENUMA << bus)); + /* Ensure that an enum event will be transmited if an enum + * exists. */ + if (MotHscInfo.EnumOldState[bus]) { + MotHscInfo.EnumOldState[bus] = 0; + + /* If the enum mask has changed the send event up. */ + if (!OldStat) { + mot82XXhscSendEvent(0, + MOT82XXHSC_EVENT_ENUM, + MOT82XXHSC_BUS_A + bus, + MOT82XXHSC_EVENT_OFF); + } + } + } else { + MotHscInfo.EnumEnabled[bus] = 0; + mot82XXhscClrBits(&MotHscInfo.Regs->IntMask, + (MOTHSC_ENUMA << bus)); + } + + Stat = MOTHSC_READREG(IntMask) & (MOTHSC_ENUMA << bus); + + if (Stat && !OldStat) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_ENUMMASK, + MOT82XXHSC_BUS_A + bus, MOT82XXHSC_EVENT_ON); + } else if (!Stat && OldStat) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_ENUMMASK, + MOT82XXHSC_BUS_A + bus, MOT82XXHSC_EVENT_OFF); + } + + restore_flags(flags); + return 0; +} + +/* + * Sub ioctl to return current enum status for the specified bus. + */ +static int +mot82XXhscGetEnum(unsigned long arg) +{ + unsigned int FromUser; + unsigned int ToUser; + int bus; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + bus = (FromUser & 0x3) - 1; + + if ((bus < 0) || (bus > 1)) { + return -EINVAL; + } + + if (MOTHSC_READREG(IntMask) & (MOTHSC_A_STATE << bus)) { + ToUser = 1; + } else { + ToUser = 0; + } + + return copy_to_user((void *)arg, &ToUser, sizeof(int)); +} + +/* + * Sub ioctl to get the current status bits for non host slot controls. + */ +static int +mot82XXhscGetNonHost(unsigned long arg) +{ + unsigned int FromUser; + unsigned int ToUser; + int slot; + int bits; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + slot = FromUser - 1; + + if ((slot < 0) || (slot > 15) || ((slot > 5) && (slot < 10))) { + return -EINVAL; + } + + bits = MOTHSC_READREG(Slot[slot]); + + ToUser = (bits & 0x7f) + ((bits & 0x700) >> 1) + + ((bits & MOTHSC_ACTIVE) >> 14); + + return copy_to_user((void *)arg, &ToUser, sizeof(int)); +} + +/* + * Sub ioctl to set the current status bits for non host slot controls. + */ +static int +mot82XXhscSetNonHost(unsigned long arg) +{ + MotHscSlotInfo FromUser; + unsigned int Bits; + unsigned int OldBits; + unsigned long flags; + int loop; + int slot; + int bus; + int OldEnumVal = 0; + + if (copy_from_user((void *)&FromUser, (void *)arg, + sizeof(MotHscSlotInfo))) { + return -EFAULT; + } + + if (FromUser.MsiBits & ~MOT82XXHSC_NH_MASK) { + return -EINVAL; + } + + slot = FromUser.MsiSlot - 1; + + if ((slot >= 0) && (slot < 6)) { + bus = 0; + } else if ((slot > 9) && (slot < 16)) { + bus = 1; + } else { + return -EINVAL; + } + + Bits = (FromUser.MsiBits & 0x7f) + ((FromUser.MsiBits & 0x380) << 1); + + if ((Bits & MOTHSC_CONNECT) && !FromUser.MsiFlag) { + /* We are turning of connect so indicate if we need to check + * if ENUM cleare. */ + OldEnumVal = MOTHSC_READREG(IntMask) & (MOTHSC_A_STATE << bus); + } + + save_flags(flags); + cli(); + + if (FromUser.MsiFlag) { + mot82XXhscSetBits(&MotHscInfo.Regs->Slot[slot], Bits); + } else { + mot82XXhscClrBits(&MotHscInfo.Regs->Slot[slot], Bits); + } + + Bits = MOTHSC_READREG(Slot[slot]) & ~MOTHSC_SLOTINT; + Bits = (Bits & 0x7f) + ((Bits & MOTHSC_ACTIVE) >> 14) + + ((Bits & 0x700) >> 1); + OldBits = MotHscInfo.SlotOldBits[slot]; + + /* Return events for changed no interrup controled bits. */ + for (loop = 0; loop < 11; loop++) { + if ((Bits & (0x1 << loop)) && !(OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + slot, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + slot, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + MotHscInfo.SlotOldBits[slot] = Bits; + + /* If enum was set see if it has been cleared */ + if (OldEnumVal && !(MOTHSC_READREG(IntMask) & (MOTHSC_A_STATE << bus ))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_ENUM, + MOT82XXHSC_BUS_A + bus, MOT82XXHSC_EVENT_OFF); + MotHscInfo.EnumOldState[bus] = 0; + + if (MotHscInfo.EnumEnabled[bus]) { + mot82XXhscSetBits(&MotHscInfo.Regs->IntMask, MOTHSC_ENUMA+bus); + + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_ENUMMASK, + MOT82XXHSC_BUS_A + bus, MOT82XXHSC_EVENT_ON); + } + } + + restore_flags(flags); + return 0; +} + +/* + * Sub ioctl to get the current status bits for host slot controls. + */ +static int +mot82XXhscGetHost(unsigned long arg) +{ + unsigned int FromUser; + unsigned int ToUser; + int host; + int bits; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + host = (FromUser & 0x3) - 1; + + if ((host < 0) || (host > 1)) { + return -ENODEV; + } + + host = (host * 2) + 6; + + bits = MOTHSC_READREG(Slot[host]); + + ToUser = (bits & 0x7f) + ((bits & 0x700) >> 1) + + ((bits & MOTHSC_ACTIVE) >> 14); + + return copy_to_user((void *)arg, &ToUser, sizeof(int)); +} + +/* + * Sub ioctl to set the current status bits for host slot controls. + */ +static int +mot82XXhscSetHostst(unsigned long arg) +{ + MotHscSlotInfo FromUser; + unsigned int Bits; + unsigned int OldBits; + unsigned long flags; + int loop; + int host; + + if (copy_from_user((void *)&FromUser, (void *)arg, + sizeof(MotHscSlotInfo))) { + return -EFAULT; + } + + if (FromUser.MsiBits & ~MOT82XXHSC_HOST_MASK) { + return -EINVAL; + } + + host = (FromUser.MsiSlot & 0x3) - 1; + + if ((host < 0) || (host > 1)) { + return -ENODEV; + } + + host = (host * 2) + 6; + + Bits = (FromUser.MsiBits & 0x7f) + ((FromUser.MsiBits & 0x380) << 1); + + save_flags(flags); + cli(); + + if (FromUser.MsiFlag) { + mot82XXhscSetBits(&MotHscInfo.Regs->Slot[host], Bits); + } else { + mot82XXhscClrBits(&MotHscInfo.Regs->Slot[host], Bits); + } + + Bits = MOTHSC_READREG(Slot[host]) & ~MOTHSC_HOSTINT; + Bits = (Bits & 0x7f) + ((Bits & 0x700) >> 1) + + ((Bits & MOTHSC_ACTIVE) >> 14); + + OldBits = MotHscInfo.HostOldBits[host]; + + for (loop = 0; loop < 11; loop++) { + if ((Bits & (0x1 << loop)) && !(OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + host, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + host, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + MotHscInfo.HostOldBits[host] = Bits; + + restore_flags(flags); + return 0; +} + +/* + * Sub ioctl to get the current status bits for bridge slot controls. + */ +static int +mot82XXhscGetHsc(unsigned long arg) +{ + unsigned int FromUser; + unsigned int ToUser; + int hsc; + int bits; + + if (copy_from_user((void *)&FromUser, (void *)arg, sizeof(int))) { + return -EFAULT; + } + + hsc = (FromUser & 0x3) - 1; + + if ((hsc < 0) || (hsc > 1)) { + return -ENODEV; + } + + hsc = (hsc * 2) + 7; + + bits = MOTHSC_READREG(Slot[hsc]); + + ToUser = (bits & 0x7f) + ((bits & 0x700) >> 1) + + ((bits & MOTHSC_ACTIVE) >> 14); + + return copy_to_user((void *)arg, &ToUser, sizeof(int)); +} + +/* + * Sub ioctl to get the current status bits for bridge slot controls. + */ +static int +mot82XXhscSetHsc(unsigned long arg) +{ + MotHscSlotInfo FromUser; + unsigned int Bits; + unsigned int OldBits; + unsigned long flags; + int loop; + int hsc; + + if (copy_from_user((void *)&FromUser, (void *)arg, + sizeof(MotHscSlotInfo))) { + return -EFAULT; + } + + if (FromUser.MsiBits & ~MOT82XXHSC_HSC_MASK) { + return -EINVAL; + } + + hsc = (FromUser.MsiSlot & 0x3) - 1; + + if ((hsc < 0) || (hsc > 1)) { + return -ENODEV; + } + + hsc = (hsc * 2) + 7; + + Bits = (FromUser.MsiBits & 0x7f) + ((FromUser.MsiBits & 0x380) << 1); + + save_flags(flags); + cli(); + + if (FromUser.MsiFlag) { + mot82XXhscSetBits(&MotHscInfo.Regs->Slot[hsc], Bits); + } else { + mot82XXhscClrBits(&MotHscInfo.Regs->Slot[hsc], Bits); + } + + Bits = MOTHSC_READREG(Slot[hsc]) & ~MOTHSC_HSCINT; + Bits = (Bits & 0x7f) + ((Bits & 0x700) >> 1) + + ((Bits & MOTHSC_ACTIVE) >> 14); + + OldBits = MotHscInfo.HscOldBits[hsc]; + + for (loop = 0; loop < 11; loop++) { + if ((Bits & (0x1 << loop)) && !(OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + hsc, + 0x1 << loop, MOT82XXHSC_EVENT_ON); + } else if (!(Bits & (0x1 << loop)) && + (OldBits & (0x1 << loop))) { + mot82XXhscSendEvent(0, MOT82XXHSC_EVENT_SLOT1 + hsc, + 0x1 << loop, MOT82XXHSC_EVENT_OFF); + } + } + + MotHscInfo.HscOldBits[hsc] = Bits; + + restore_flags(flags); + return 0; +} + +/* + * Clear the bits specified by the bit mask in the requested register. + */ +static void +mot82XXhscClrBits(volatile unsigned int *reg, unsigned int bits) +{ + *reg = cpu_to_le32(bits | MOTHSC_CMD_CLEAR); + udelay(10); +} + +/* + * Set the bits specified by the bit mask in the requested register. + */ +static void +mot82XXhscSetBits(volatile unsigned int *reg, unsigned int bits) +{ + *reg = cpu_to_le32(bits | MOTHSC_CMD_SET); + udelay(10); +} + +/* + * Sub function of take over routine to turn on interrupts to the + * non host slots and recored the history information. + */ +void +mot82XXhscSlotOn(int bus) +{ + unsigned int Bits; + int startslot = 0; + int slot; + + if (bus) { + startslot = 10; + } + + for (slot = startslot; slot < startslot + 6; slot++) { + mot82XXhscClrBits(&MotHscInfo.Regs->Slot[slot], + MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->Slot[slot], + MOTHSC_INTA_ENABLE); + Bits = MOTHSC_READREG(Slot[slot]) & ~MOTHSC_SLOTINT; + MotHscInfo.SlotOldBits[slot] = ((Bits & 0x7f) + + ((Bits & MOTHSC_ACTIVE) >> 14) + + ((Bits & 0x700) >> 1)) & ~MOTHSC_SLOTINT; + MotHscInfo.SlotOldIntBits[slot] = ((Bits & 0x7f) + + ((Bits & MOTHSC_ACTIVE) >> 14) + + ((Bits & 0x700) >> 1)) & MOTHSC_SLOTINT; + } + + return; +} + +/* + * Time out function used for bus takeover. This function is scheduled to + * run at the time out value. At time out it completes the take over whether + * the other host has allowed it or not. This function is also called + * directly by this host when the other host has allowed takeover. + */ +void +mot82XXhscTakeTimeOutFunc(unsigned long bus) +{ + /* Seting XFR_CTL1 enables all controls */ + mot82XXhscSetBits(&MotHscInfo.Regs->BusControl[bus], MOTHSC_XFR_CTL2); + + MotHscInfo.LastBusControl[bus] = MOTHSC_READREG(BusControl[bus]); + + /* If we allocated the A bus then enable interrupts for the Alarms */ + if (!bus) { + mot82XXhscClrBits(&MotHscInfo.Regs->Alarm, MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->Alarm, MOTHSC_INTA_ENABLE); + } + + /* Turn on interrupts to all the slots on this bus */ + mot82XXhscSlotOn(bus); + + return; +} + +/* + * Functionality to take over the specified bus. + */ +static int +mot82XXhscAttachBus(int bus, int timeout) +{ + /* Set this bus to generate interrupts on INT A */ + mot82XXhscClrBits(&MotHscInfo.Regs->BusControl[bus], MOTHSC_INTC_ENABLE); + mot82XXhscSetBits(&MotHscInfo.Regs->BusControl[bus], MOTHSC_INTA_ENABLE); + + /* First set XFR_CTL1 to request bus.2 */ + mot82XXhscSetBits(&MotHscInfo.Regs->BusControl[bus], MOTHSC_XFR_CTL1); + + /* if timeout value not zero then wait that long for the other host + * to give up the bus. At timeout force the takeover. + */ + if ((timeout != 0) && + (MOTHSC_READREG(BusControl[bus]) & MOTHSC_XFR_STS1)) { + mot82XXhscTakeTimeOut.data = (unsigned long)bus; + mot82XXhscTakeTimeOut.expires = jiffies + timeout; + add_timer(&mot82XXhscTakeTimeOut); + return 0; + } + + mot82XXhscTakeTimeOutFunc(bus); + return 0; +} + +/* + * Release the bus. + */ +static int +mot82XXhscReleaseBus(int bus) +{ + mot82XXhscClrBits(&MotHscInfo.Regs->BusControl[bus], + MOTHSC_XFR_CTL1 | MOTHSC_XFR_CTL2); + return 0; +} + +/* + * The function retrieves an event message data structure fromt he free + * list. If the free list is empty it will kmalloc a new chunck of memory + * from the OS, format it and add it to the list of free elements. This + * memory is only returned to the OS at system reboot. + */ +HscMessage * +mot82XXhscAllocMessage(void) +{ + HscMessage *NewMessPtr; + HscMessage *TmpMessPtr = MotMessageFreeList; + int loop; + + MotMessageFreeList = MotMessageFreeList->Next; + TmpMessPtr->Next = NULL; + + if (MotMessageFreeList == NULL) { + MotMessageFreeList = kmalloc(MOTHSC_MESSAGE_CHUNK_SIZE * + sizeof(HscMessage), GFP_ATOMIC); + + NewMessPtr = MotMessageFreeList; + for (loop = 0; loop < MOTHSC_MESSAGE_CHUNK_SIZE-1; loop++) { + NewMessPtr->Event = 0; + NewMessPtr->Unit = 0; + NewMessPtr->Val = 0; + NewMessPtr->Next = NewMessPtr + 1; + NewMessPtr++; + } + NewMessPtr->Event = 0; + NewMessPtr->Unit = 0; + NewMessPtr->Val = 0; + NewMessPtr->Next = NULL; + } + + return TmpMessPtr; +} + +/* + * Place an event message back on the free list. + */ +void +mot82XXhscFreeMessage(HscMessage *message) +{ + message->Event = 0; + message->Unit = 0; + message->Val = 0; + message->Next = MotMessageFreeList; + MotMessageFreeList = message; +} + +/* + * Allocate, format and fill in the event message data. It is + * then placed on the specified PID's event queue or all event + * queues and the controlling process{s} are notified events + * are waiting. + */ +void +mot82XXhscSendEvent(int pid, int event, int unit, int val) +{ + HscEventRequesters *Requester = MotEventRequestersList; + + while(Requester) { + if (pid && (Requester->Pid != pid)) { + Requester = Requester->Next; + continue; + } + + if (Requester->Head == (HscMessage *)NULL) { + Requester->Head = mot82XXhscAllocMessage(); + Requester->Tail = Requester->Head; + } else { + Requester->Tail->Next = mot82XXhscAllocMessage(); + Requester->Tail = Requester->Tail->Next; + } + + Requester->Tail->Event = event; + Requester->Tail->Unit = unit; + Requester->Tail->Val = val; + + /* Send a SIGIO to the requesting process. */ + kill_fasync(&Requester->Fasyncptr, SIGIO, POLL_IN); + Requester = Requester->Next; + } +} + +int +mot82XXhscReportHostID(void) +{ + return MotHscInfo.Host; +} + +int +mot82XXhscBusStatus(int bus) +{ + int state; + + state = (MOTHSC_READREG(BusControl[bus]) & 0x1e) >> 1; + + if (state == HSC_STATE_MINE) { + return 1; + } + + return 0; +} + +int +mot82XXhscEnumStatus(int bus) +{ + if (MOTHSC_READREG(IntMask) & (MOTHSC_ENUMA << bus)) { + return 1; + } else { + return 0; + } +} + +void +mot82XXhscSetSlotBits(int slot, int bits, int state) +{ + if (state) { + mot82XXhscSetBits(&MotHscInfo.Regs->Slot[slot], bits); + } else { + mot82XXhscClrBits(&MotHscInfo.Regs->Slot[slot], bits); + } + return; +} + +int +mot82XXhscCheckHealthy(int slot) +{ + if (MOTHSC_READREG(Slot[slot]) & MOTHSC_HEALTHY) { + return 1; + } + + return 0; +} + +int +mot82XXhscCheckSlotBits(int slot, int bits) +{ + if (MOTHSC_READREG(Slot[slot]) & bits) { + return 1; + } + + return 0; +} + +/* + * This is the external function to allocate a bus and set power and + * connect on all its slots. In an earlier version this code was + * called directly from the HSC init function. + */ +int +mot82XXhscAllocateAndInitBus(int bus) +{ + int slot, start_slot; + int state; + int retval; + + /* Disable enum processing while doing this */ + mot82XXhscSetEnumMask(MOTHSC_BUSA + bus, MOT82XXHSC_CLEAR); + + if (bus) + start_slot = 10; + else + start_slot = 0; + + state = (MOTHSC_READREG(BusControl[bus]) & 0x1e) >> 1; + if (state == HSC_STATE_MINE) { + retval = MOTHSC_BUS_WAS_PRESENT; + } else { + mot82XXhscAttachBus(bus, 0); + retval = MOTHSC_BUS_NOW_PRESENT; + } + + for (slot = start_slot; slot < start_slot + 6; slot++) { + mot82XXhscSetBits(&MotHscInfo.Regs->Slot[slot], + MOTHSC_POWER_ON | MOTHSC_CONNECT); + udelay(10); + } + + return retval; +} + +/* + * Deallocat the same bus as allocated above. + */ +void +mot82XXhscDeallocateAndShutdownBus(int bus) +{ + int slot, start_slot; + int state; + + /* Disable enum processing while doing this */ + mot82XXhscSetEnumMask(MOTHSC_BUSA + bus, MOT82XXHSC_CLEAR); + + if (bus) + start_slot = 10; + else + start_slot = 0; + + state = (MOTHSC_READREG(BusControl[bus]) & 0x1e) >> 1; + if (state != HSC_STATE_MINE) { + return; + } + + + for (slot = start_slot; slot < start_slot + 6; slot++) { + mot82XXhscClrBits(&MotHscInfo.Regs->Slot[slot], + MOTHSC_POWER_ON | MOTHSC_CONNECT); + } + + mot82XXhscReleaseBus(bus); + + return; +} + +static HSI_INIT initData; + +/* + * The following functions are part of the PICMG 2.12 control functionality. + * They are used by functionality in the piphs.c file. + */ + +/* + * Initialize the 2.12 functionality with this drivers informations. + */ +int +mot82XXhscHsiInit(void) +{ + HSI_STATUS status; + void * pExt; + struct tq_struct noDpc; + + /* Initialize the PICMG 2.12 Driver */ + noDpc.sync = 0; + noDpc.routine = NULL; + noDpc.data = NULL; + + initData.DevExtSize = 0; + initData.Intr = 0; + initData.IntrFlags = 0; + initData.pDevId = NULL; + initData.QueryEnumState = mot82XXhscHsiQueryEnumState; + initData.CheckEnumInterrupt = mot82XXhscHsiCheckEnumInterrupt; + initData.Enable = mot82XXhscHsiEnableEnums; + initData.Disable = mot82XXhscHsiDisableEnums; + initData.Isr = (INTERRUPT_SERVICE_ROUTINE) NULL; + initData.Dpc = noDpc; + + if ((status = HsiPlatformInitialize(&initData, &pExt)) != 0) { + return mot82XXhscHsiConvertStatus(status); + } + return HSI_STATUS_SUCCESS; +} + +/* + * Verify this is the correct driver. + */ +BOOLEAN +mot82XXhscHsiCheckEnumInterrupt(void *pDeviceId) +{ + return (pDeviceId == hsi_platform_data.pDevId); +} + +/* + * Return an indication of whether the ENUM signal is set or not. + */ +BOOLEAN +mot82XXhscHsiQueryEnumState(void) +{ + unsigned int StateA, StateB; + unsigned int IntReg = MOTHSC_READREG(IntMask); + + StateA = (MOTHSC_READREG(BusControl[0]) & 0x1e) >> 1; + StateB = (MOTHSC_READREG(BusControl[1]) & 0x1e) >> 1; + + if (((IntReg & MOTHSC_A_STATE) && (StateA == HSC_STATE_MINE)) || + ((IntReg & MOTHSC_B_STATE) && (StateB == HSC_STATE_MINE))) { + return TRUE; + } + + return FALSE; +} + +/* + * Enable the ENUM interrupts. Must not forget to check and see of we + * own the bus first. + */ +HSI_STATUS +mot82XXhscHsiEnableEnums(void) +{ + int chk_val = MOTHSC_XFR_CTL1|MOTHSC_XFR_CTL2; + + if ((MOTHSC_READREG(BusControl[MOTHSC_BUSA]) & chk_val) == chk_val) { + if (mot82XXhscSetEnumMask(MOTHSC_BUSA, MOT82XXHSC_SET)) { + return HSI_STATUS_FAILURE; + } + } + + if ((MOTHSC_READREG(BusControl[MOTHSC_BUSB]) & chk_val) == chk_val) { + if (mot82XXhscSetEnumMask(MOTHSC_BUSB, MOT82XXHSC_SET)) { + return HSI_STATUS_FAILURE; + } + } + + return HSI_STATUS_SUCCESS; +} + +/* + * Disable the ENUM interrupts. Must not forget to check and see of we + * own the bus first. + */ +HSI_STATUS +mot82XXhscHsiDisableEnums(void) +{ + int chk_val = MOTHSC_XFR_CTL1|MOTHSC_XFR_CTL2; + + if ((MOTHSC_READREG(BusControl[MOTHSC_BUSA]) & chk_val) == chk_val) { + if (mot82XXhscSetEnumMask(MOTHSC_BUSA, MOT82XXHSC_CLEAR)) { + return HSI_STATUS_FAILURE; + } + } + + if ((MOTHSC_READREG(BusControl[MOTHSC_BUSB]) & chk_val) == chk_val) { + if (mot82XXhscSetEnumMask(MOTHSC_BUSB, MOT82XXHSC_CLEAR)) { + return HSI_STATUS_FAILURE; + } + } + + return HSI_STATUS_SUCCESS; +} + +/* + * Convert status values from piphs to values the driver can + * return to user level errno's. + */ +int +mot82XXhscHsiConvertStatus(HSI_STATUS status) +{ + switch (status) { + case HSI_STATUS_SUCCESS : + return 0; + case HSI_STATUS_NO_MEMORY : + return -ENOMEM; + case HSI_STATUS_INVALID_PARAMETER : + return -EINVAL; + case HSI_STATUS_NOT_IMPLEMENTED : + return -ENOSYS; + case HSI_STATUS_NO_SUCH_DEVICE : + return -ENODEV; + case HSI_STATUS_NO_DATA_DETECTED : + return -ENODATA; + case HSI_STATUS_OPERATION_NOT_APPLICABLE : + return -EPERM; + case HSI_STATUS_NOT_AVAILABLE : + return -EBUSY; + default : + return -EPERM; // HSI_STATUS_FAILURE goes here too + } +} + +#ifdef CONFIG_CHASSIS_CONTROL +int +mot82xxChassisStatusFunc(unsigned int arg, unsigned int mode) +{ + return mot82XXhscSetLed(arg, mode); +} + +int +mot82xxChassisAlarmFunc(unsigned int arg, unsigned int mode) +{ + return mot82XXhscSetAlarm(arg, mode); +} +#endif + diff -u -r --new-file linux/drivers/ha/cpci/mot82XXhsc.h ha/drivers/ha/cpci/mot82XXhsc.h --- linux/drivers/ha/cpci/mot82XXhsc.h Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/mot82XXhsc.h Thu Dec 13 13:03:13 2001 @@ -0,0 +1,272 @@ +/* + * mot82XXhsc.h + * + * Motorola 82XX hot swap controller driver. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef MOT82XXHSC_DRIVER_H +#define MOT82XXHSC_DRIVER_H + +#include + +/* Couple of prototypes usefull to other files. */ +int mot82XXhscReportHostID(void); +int mot82XXhscBusStatus(int); +int mot82XXhscEnumStatus(int); +void mot82XXhscSetSlotBits(int, int, int); +int mot82XXhscCheckSlotBits(int, int); +int mot82XXhscSetEnumMask(int, int); + +/* Number of bits to check in the interrupt register. */ +#define MOTHSC_REG_SIZE 32 + +#define MOTHSC_BUSA 0 +#define MOTHSC_BUSB 1 + +/* Standard bits in control registers */ +#define MOTHSC_PRESENT 0x1 +#define MOTHSC_POWER_ON 0x2 +#define MOTHSC_IGN_HEALTHY 0x4 +#define MOTHSC_RESET 0x8 +#define MOTHSC_CONNECT 0x10 +#define MOTHSC_CONNECTED 0x20 +#define MOTHSC_HEALTHY 0x40 +#define MOTHSC_LED1 0x100 +#define MOTHSC_LED2 0x200 +#define MOTHSC_LED3 0x400 +#define MOTHSC_H110_RESET 0x1000 +#define MOTHSC_ACTIVE 0x1000000 +#define MOTHSC_INT_STATUS 0x4000000 +#define MOTHSC_INTA_ENABLE 0x8000000 +#define MOTHSC_INTB_ENABLE 0x10000000 +#define MOTHSC_INTC_ENABLE 0x18000000 +#define MOTHSC_CMD_CLEAR 0x20000000 +#define MOTHSC_CMD_SET 0x40000000 +#define MOTHSC_CMD_WRITE 0x60000000 + +/* Masks defining bits that cause interrupts in the specified registers. */ +#define MOTHSC_SLOTINT (MOTHSC_PRESENT|MOTHSC_CONNECTED|MOTHSC_HEALTHY) +#define MOTHSC_HOSTINT (MOTHSC_CONNECTED|MOTHSC_HEALTHY) +#define MOTHSC_HSCINT (MOTHSC_INSERTION|MOTHSC_REMOVAL|MOTHSC_CONNECTED) + +/* Special bits for HSC/Bridge slots */ +#define MOTHSC_INSERTION 0x2 +#define MOTHSC_REMOVAL 0x4 +#define MOTHSC_INSTALLED 0x8 +#define MOTHSC_EJECTOR 0x10 +#define MOTHSC_HSC_H110_RES 0x40 + +/* Special bits for Power Supply */ +#define MOTHSC_PS_ON 0x2 +#define MOTHSC_PS_GOOD 0x4 +#define MOTHSC_COOL_ALARM 0x8 +#define MOTHSC_COOL_FAULT 0x10 +#define MOTHSC_PS_LED1 0x100 +#define MOTHSC_PS_LED2 0x200 +#define MOTHSC_FAN_LED1 0x400 +#define MOTHSC_FAN_LED2 0x800 +#define MOTHSC_FAN_PRESENT 0x1000 +#define MOTHSC_FAN_LOW 0x2000 +#define MOTHSC_FAN_FAULT 0x4000 + +/* Special bits for peripheral bays */ +#define MOTHSC_PBAY_OWNDEV 0x4 +#define MOTHSC_PBAY_LED1 0x100 +#define MOTHSC_PBAY_LED2 0x200 + +/* Special bits for LED register */ +#define MOTHSC_LED4 0x800 + +/* Speical bits for alarm register */ +#define MOTHSC_ALRM_CRIT 0x100 +#define MOTHSC_ALRM_MAJOR 0x200 +#define MOTHSC_ALRM_MINOR 0x400 +#define MOTHSC_ALRM_RACK 0x800 + +/* Bus control register bits */ +#define MOTHSC_XFR_CTL1 0x2 +#define MOTHSC_XFR_CTL2 0x4 +#define MOTHSC_XFR_STS1 0x8 +#define MOTHSC_XFR_STS2 0x10 +#define MOTHSC_SOFT_TRANS 0x20 +#define MOTHSC_LOCK 0x40 +#define MOTHSC_HOST_DOMAIN 0x80 +#define MOTHSC_STATE_12 0xc000 +#define MOTHSC_STATE_MASK 0xf000 +#define MOTHSC_ALLOW 0x10000 + +/* Bus states */ +#define HSC_STATE_FREE 0x0 +#define HSC_STATE_OTHER 0xc +#define HSC_STATE_REQUESTED 0xe +#define HSC_STATE_TRAN_STRT 0x7 +#define HSC_STATE_STOPED 0x9 +#define HSC_STATE_TRAN_ACK 0x6 +#define HSC_STATE_ENABLE 0xb +#define HSC_STATE_TRAN_DONE 0xf +#define HSC_STATE_MINE 0x3 + +/* Bits bir eeprom register */ +#define MOTHSC_FPGA_DOUT 0x2 +#define MOTHSC_FPGA_CLK 0x4 +#define MOTHSC_FPGA_PROG 0x8 +#define MOTHSC_FPGA_RESET 0x10 +#define MOTHSC_FPGA_CE 0x20 +#define MOTHSC_FPGA_SER_EN 0x40 +#define MOTHSC_FPGA_DIN 0x80 + +/* Interrupt mask register bits */ +#define MOTHSC_INTA 0x2 +#define MOTHSC_INTB 0x4 +#define MOTHSC_INTC 0x8 +#define MOTHSC_ENUMA 0x10 +#define MOTHSC_ENUMB 0x20 +#define MOTHSC_H110_GLOB 0x40 +#define MOTHSC_A_STATE 0x2000 +#define MOTHSC_B_STATE 0x4000 +#define MOTHSC_PROP_ENUM 0x8000 + +/* Bits in the interrupt status registers */ +#define MOTHSC_INT_SLOT1 0x1 +#define MOTHSC_INT_SLOT2 0x2 +#define MOTHSC_INT_SLOT3 0x4 +#define MOTHSC_INT_SLOT4 0x8 +#define MOTHSC_INT_SLOT5 0x10 +#define MOTHSC_INT_SLOT6 0x20 +#define MOTHSC_INT_HOST1 0x40 +#define MOTHSC_INT_HSC2 0x80 +#define MOTHSC_INT_HOST2 0x100 +#define MOTHSC_INT_HSC1 0x200 +#define MOTHSC_INT_SLOT11 0x400 +#define MOTHSC_INT_SLOT12 0x800 +#define MOTHSC_INT_SLOT13 0x1000 +#define MOTHSC_INT_SLOT14 0x2000 +#define MOTHSC_INT_SLOT15 0x4000 +#define MOTHSC_INT_SLOT16 0x8000 +#define MOTHSC_INT_PBAY1 0x10000 +#define MOTHSC_INT_PBAY2 0x20000 +#define MOTHSC_INT_PBAY3 0x40000 +#define MOTHSC_INT_PBAY4 0x80000 +#define MOTHSC_INT_MASK 0x800000 +#define MOTHSC_INT_PS1 0x4000000 +#define MOTHSC_INT_PS2 0x8000000 +#define MOTHSC_INT_PS3 0x10000000 +#define MOTHSC_INT_ALARM 0x20000000 +#define MOTHSC_INT_BUSA 0x40000000 +#define MOTHSC_INT_BUSB 0x80000000 + +/* Return values for exported allocate bus routine */ +#define MOTHSC_BUS_WAS_PRESENT 0 +#define MOTHSC_BUS_NOW_PRESENT 1 + + +/* Various stats for the hsc driver. This could use more work. */ + +typedef struct mot9216hsc_stats { + int TotalOpens; + int CurOpens; + int BogusCmds; +} HscStats; + +/* Register access control data structure. */ +typedef struct mot82XXhsc_regs { + volatile unsigned int Slot[MOTHSC_NUM_SLOTS]; /* 0x0 - 0x3c cPCI slots */ + volatile unsigned int unused1[16]; /* 0x40 - 0x7c Not implement */ + volatile unsigned int Ps[MOTHSC_NUM_PS]; /* 0x80 - 0x8c Power Supply */ + volatile unsigned int unused2; + volatile unsigned int PBay[MOTHSC_NUM_PBAY]; /* 0x90 - 0x9c Peripheral bay */ + volatile unsigned int unsused3[12]; /* 0xa0 - 0acc Not implement */ + volatile unsigned int IntStatMask; + volatile unsigned int IntStatus[MOTHSC_NUM_INTSTAT]; + volatile unsigned int unused3[2]; + volatile unsigned int BusControl[MOTHSC_NUM_BUS]; + volatile unsigned int EEprom; + volatile unsigned int SysLed; + volatile unsigned int Alarm; + volatile unsigned int IntMask; +} HscRegs; + +/* Driver instance information. */ +typedef struct mot82XXhsc_info { + struct pci_dev *Device; + int Major; + int Irq; + int Host; + HscRegs *Regs; + unsigned int PBayOldBits[MOTHSC_NUM_PBAY]; + unsigned int PowerOldBits[MOTHSC_NUM_PS]; + unsigned int SlotOldBits[MOTHSC_NUM_SLOTS]; + unsigned int SlotOldIntBits[MOTHSC_NUM_SLOTS]; + unsigned int HostOldBits[MOTHSC_NUM_SLOTS]; + unsigned int HostOldIntBits[MOTHSC_NUM_SLOTS]; + unsigned int HscOldBits[MOTHSC_NUM_SLOTS]; + unsigned int HscOldIntBits[MOTHSC_NUM_SLOTS]; + int EnumOldState[2]; + int EnumEnabled[2]; + int BusTakeoverAllowed[2]; + int LastBusControl[2]; +} HscInfo; + +/* Event message data structures. */ +#define MOTHSC_MESSAGE_CHUNK_SIZE 128 + +typedef struct mot82XXhsc_message { + struct mot82XXhsc_message *Next; + int Event; + int Unit; + int Val; +} HscMessage; + +/* Event requestors control. */ +#define MOTHSC_MAX_EVENT_REQUESTERS 32 + +typedef struct mot82XXhsc_event_users { + struct mot82XXhsc_event_users *Next; + pid_t Pid; + HscMessage *Head; + HscMessage *Tail; + struct fasync_struct *Fasyncptr; +} HscEventRequesters; + +/* Interrupt bit <=> sub control function mapping data. */ +typedef struct mot82XXhsc_reginfo { + volatile unsigned int *Reg; + int SubInfo; + void (*IntHandler)(volatile unsigned int *, int); +} HscRegInfo; + +/* Some macros used in the drivers. */ +#define MOTHSC_READREG(Reg) le32_to_cpu(MotHscInfo.Regs->Reg) + +#define MOTHSC_GET_REG_FROM_BIT(bit) &MotHscRegInfo[(bit)]; + +#define MOT_HSC_CALL_INT_HANDLER(bit, arg2) \ + (MotHscRegInfo[(bit)].IntHandler)((arg2)->Reg, (arg2)->SubInfo) + +#endif /* MOT82XXHSC_DRIVER_H */ diff -u -r --new-file linux/drivers/ha/cpci/mot_cpci.c ha/drivers/ha/cpci/mot_cpci.c --- linux/drivers/ha/cpci/mot_cpci.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/mot_cpci.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,753 @@ +/* + * mot_cpci.c + * + * Motorola MCP750 and CPV5350 specific cPCI control routines. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + * + */ +#include +#include +#include +#include +#include +#include +#include +#include "mot82XXhsc.h" +#include "mot_enum.h" +#include "cpci_core.h" + +int motCpci_early_config_bus(struct pci_controller *, int, int); +void motCpci_find_driver(int); + +int mot82XXhsc_init(void); +int motEnum_init(void); + +int CpciDelBus(int, int); + +#ifdef CONFIG_X86 +struct pci_ops *pci_check_direct(void); +struct pci_ops *pci_find_bios(void); + +extern struct pci_ops *pci_root_ops; +#endif + +#ifdef CONFIG_PPC +#define MOTHSC_BUS1_DEVFN PCI_DEVFN(0x14, 0) +#define MOTHSC_BUS2_DEVFN PCI_DEVFN(0x18, 0) +#define HSC_DEVFN PCI_DEVFN(0x16, 0) +#else +#define MOTHSC_BUS1_DEVFN PCI_DEVFN(0x11, 0) +#define MOTHSC_BUS2_DEVFN PCI_DEVFN(0x0d, 0) +#define HSC_DEVFN PCI_DEVFN(0xb, 0) +#define AGP_DEVFN PCI_DEVFN(0x1, 0) +#define PIXX4_HB_DEVFN PCI_DEVFN(0x7, 0) +#endif + +#define NUM_HA_SLOTS 16 + +unsigned int CpciHaIoSize[] = { + CONFIG_MOT_82XX_SLOT1_IO_SIZE, + CONFIG_MOT_82XX_SLOT2_IO_SIZE, + CONFIG_MOT_82XX_SLOT3_IO_SIZE, + CONFIG_MOT_82XX_SLOT4_IO_SIZE, + CONFIG_MOT_82XX_SLOT5_IO_SIZE, + CONFIG_MOT_82XX_SLOT6_IO_SIZE, + 0, 0, 0, 0, + CONFIG_MOT_82XX_SLOT11_IO_SIZE, + CONFIG_MOT_82XX_SLOT12_IO_SIZE, + CONFIG_MOT_82XX_SLOT13_IO_SIZE, + CONFIG_MOT_82XX_SLOT14_IO_SIZE, + CONFIG_MOT_82XX_SLOT15_IO_SIZE, + CONFIG_MOT_82XX_SLOT16_IO_SIZE, +}; + +unsigned int CpciHaMemSize[] = { + CONFIG_MOT_82XX_SLOT1_MEM_SIZE, + CONFIG_MOT_82XX_SLOT2_MEM_SIZE, + CONFIG_MOT_82XX_SLOT3_MEM_SIZE, + CONFIG_MOT_82XX_SLOT4_MEM_SIZE, + CONFIG_MOT_82XX_SLOT5_MEM_SIZE, + CONFIG_MOT_82XX_SLOT6_MEM_SIZE, + 0, 0, 0, 0, + CONFIG_MOT_82XX_SLOT11_MEM_SIZE, + CONFIG_MOT_82XX_SLOT12_MEM_SIZE, + CONFIG_MOT_82XX_SLOT13_MEM_SIZE, + CONFIG_MOT_82XX_SLOT14_MEM_SIZE, + CONFIG_MOT_82XX_SLOT15_MEM_SIZE, + CONFIG_MOT_82XX_SLOT16_MEM_SIZE, +}; + +CpciNodeInfo MotHaBusInfo[] = { + {NULL, 0x0, 0x0, 0, 0, 0x07, 0x37, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x0, 0x0, 0, 0, 0x47, 0x77, 0x0, 0x0, 0x0, 0x0} +}; + +CpciNodeInfo MotHaSlotInfo[] = { + {NULL, 0X7, PCI_DEVFN(0xe,0), 0, 0, 0x08, 0x0f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xd,0), 0, 0, 0x10, 0x17, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xc,0), 0, 0, 0x18, 0x1f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xb,0), 0, 0, 0x20, 0x27, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xa,0), 0, 0, 0x28, 0x2f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0x9,0), 0, 0, 0x30, 0x37, 0x0, 0x0, 0x0, 0x0}, + + {NULL, 0x0, 0x0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x0, 0x0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x0, 0x0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x0, 0x0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + + {NULL, 0x47, PCI_DEVFN(0xe,0), 0, 0, 0x48, 0x4f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x47, PCI_DEVFN(0xd,0), 0, 0, 0x50, 0x57, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x47, PCI_DEVFN(0xc,0), 0, 0, 0x58, 0x5f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x47, PCI_DEVFN(0xb,0), 0, 0, 0x60, 0x67, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x47, PCI_DEVFN(0xa,0), 0, 0, 0x68, 0x6f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x47, PCI_DEVFN(0x9,0), 0, 0, 0x70, 0x77, 0x0, 0x0, 0x0, 0x0} +}; + +CpciInfo MotHaCpciInfo = {0, /* Chassis type to filled in below */ + 2, /* Number of buses. */ + {0, 10}, /* Bus start slot numbers. */ + {5, 15} /* Bus end slot numbers. */ + }; + +#define NUM_HS_SLOTS 7 + +unsigned int CpciHsIoSize[] = { + CONFIG_MOT_GEN_SLOT1_IO_SIZE, + CONFIG_MOT_GEN_SLOT2_IO_SIZE, + CONFIG_MOT_GEN_SLOT3_IO_SIZE, + CONFIG_MOT_GEN_SLOT4_IO_SIZE, + CONFIG_MOT_GEN_SLOT5_IO_SIZE, + CONFIG_MOT_GEN_SLOT6_IO_SIZE, + CONFIG_MOT_GEN_SLOT7_IO_SIZE, +}; + +unsigned int CpciHsMemSize[] = { + CONFIG_MOT_GEN_SLOT1_MEM_SIZE, + CONFIG_MOT_GEN_SLOT2_MEM_SIZE, + CONFIG_MOT_GEN_SLOT3_MEM_SIZE, + CONFIG_MOT_GEN_SLOT4_MEM_SIZE, + CONFIG_MOT_GEN_SLOT5_MEM_SIZE, + CONFIG_MOT_GEN_SLOT6_MEM_SIZE, + CONFIG_MOT_GEN_SLOT7_MEM_SIZE, +}; + +CpciNodeInfo MotHsBusInfo[] = { + {NULL, 0x0, 0x0, 0, 0, 0x07, 0x3f, 0x0, 0x0, 0x0, 0x0} +}; + +CpciNodeInfo MotHsSlotInfo[] = { + {NULL, 0x7, PCI_DEVFN(0xf,0), 0, 0, 0x08, 0x0f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xe,0), 0, 0, 0x10, 0x17, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xd,0), 0, 0, 0x18, 0x1f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xc,0), 0, 0, 0x20, 0x27, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xb,0), 0, 0, 0x28, 0x2f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xa,0), 0, 0, 0x30, 0x37, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0x9,0), 0, 0, 0x38, 0x3f, 0x0, 0x0, 0x0, 0x0} +}; + +CpciInfo MotHsCpciInfo = {CPCI_CHASSIS_GEN_HOTSWAP, /* Chassis type */ + 1, /* Number of buses. */ + {0, 0}, /* Bus start slot numbers. */ + {6, 0} /* Bus end slot numbers. */ + }; + +static struct pci_controller* MainHose; + +#ifdef CONFIG_PPC +unsigned char MotCpciIrqs[2][4] = { + {24, 25, 26, 27}, + {28, 29, 30, 31} +}; +#endif +#ifdef CONFIG_X86 +unsigned char MotCpciIrqs[2][4]; +#endif + +int MotCpciNumSlots; + +#ifdef CONFIG_PPC +#define PCI_LOWER_IO 0x00000000 +#define PCI_UPPER_IO 0x0fffffff +#define PCI_LOWER_MEM 0x00000000 +#define PCI_UPPER_MEM 0x3cfbffff +#define ISA_IO_BASE PREP_ISA_IO_BASE +#define ISA_MEM_BASE PREP_ISA_MEM_BASE + +#define PCI_IO_CPCI_START 0x3ff8000 +#define PCI_MEM_CPCI_START 0x38000000 +#endif +#ifdef CONFIG_X86 +#define PCI_LOWER_IO 0x3000 +#define PCI_UPPER_IO 0x10000 +#define PCI_LOWER_MEM 0x50000000 +#define PCI_UPPER_MEM 0xf4000000 +#define ISA_IO_BASE 0x0 +#define ISA_MEM_BASE 0x0 + +#define PCI_IO_CPCI_START 0x010000 +#define PCI_MEM_CPCI_START 0xe8000000 + +int +motCpci_ignore_agp(struct pci_controller *hose, int bus, int devfn) +{ + return 0; +} +#endif + +struct pci_auto_addrs PciAddrs = { + PCI_LOWER_IO, PCI_UPPER_IO, PCI_LOWER_MEM, PCI_UPPER_MEM +}; + +/* + * Provide the find bridges functionality needed from the architecture + * specific boot code. Instead of the old method of using the firmware + * set value, do pci autoscan and with exceptions for the cPCI bridge chips. + */ +void __init +motCpci_find_bridges(void) +{ + unsigned int Bar0; + unsigned short Vendor; + unsigned short Device; + unsigned int * HscRegs; + unsigned short Command; + int MotCpciHostID = -1; + int loop; + int LastIo; + int LastMem; +#ifdef CONFIG_X86 + unsigned char Pirq; +#endif + +#ifdef CONFIG_X86 + printk("Initialize the PCI bridge tree for the Motorola CPV5350 cPCI Host Processor Board\n"); +#else + printk("Initialize the PCI bridge tree for the Motorola MPC750 cPCI Host Processor Board\n"); +#endif + +#ifdef CONFIG_PPC + MainHose = pcibios_alloc_controller(); +#endif +#ifdef CONFIG_X86 + MainHose = pciauto_alloc_controller(); +#endif + if (!MainHose) + return; + + MainHose->first_busno = 0; + MainHose->last_busno = 0xff; + MainHose->pci_mem_offset = ISA_MEM_BASE; + MainHose->mem_space.start = PciAddrs.mem_start; + MainHose->mem_space.end = PciAddrs.mem_end; + MainHose->io_base_virt = (void *)ISA_IO_BASE; + MainHose->io_space.start = PciAddrs.io_start; + MainHose->io_space.end = PciAddrs.io_end; + MainHose->mem_resources[0].end = 0xffffffff; + +#ifdef CONFIG_X86 + MainHose->ops = pci_root_ops; + MainHose->cfg_addr = (unsigned int *)NULL; /* Not used on intel arch */ + MainHose->cfg_data = (unsigned char *)NULL; + + /* Need to get the PIRQ values and set eny not initilaized */ + for (loop = 0; loop < 4; loop++) { + early_read_config_byte(MainHose, 0, PIXX4_HB_DEVFN, + 0x60 + loop, &Pirq); + + if (Pirq == 0x80) { + Pirq = 5; + early_write_config_byte(MainHose, 0, PIXX4_HB_DEVFN, + 0x60 + loop, Pirq); + } + + MotCpciIrqs[0][loop] = Pirq; + MotCpciIrqs[1][loop] = Pirq; + } +#endif + +#ifdef CONFIG_PPC + pplus_init_resource(&MainHose->io_resource, 0x00000000, 0x0fffffff, IORESOURCE_IO); + pplus_init_resource(&MainHose->mem_resources[0], 0xc0000000, 0xfdffffff, IORESOURCE_MEM); + + setup_indirect_pci(MainHose, 0x80000cf8, 0x80000cfc); + pplus_set_VIA_IDE_legacy(); +#endif + + early_read_config_word(MainHose, 0, HSC_DEVFN, PCI_VENDOR_ID, &Vendor); + early_read_config_word(MainHose, 0, HSC_DEVFN, PCI_DEVICE_ID, &Device); + + /* Set the chassis type and number of slots variables. */ + if (Vendor == PCI_VENDOR_ID_MOTOROLA) { + switch (Device) { + case PCI_DEVICE_ID_MOTOROLA_CPX8216: + MotCpciNumSlots = NUM_HA_SLOTS; + MotHaCpciInfo.ChassisType = CPCI_CHASSIS_MOT_CPX8216; + break; + case PCI_DEVICE_ID_MOTOROLA_CPX8216A: + MotCpciNumSlots = NUM_HA_SLOTS; + MotHaCpciInfo.ChassisType = CPCI_CHASSIS_MOT_CPX8216A; + break; + case PCI_DEVICE_ID_MOTOROLA_CPX8216T: + MotCpciNumSlots = NUM_HA_SLOTS; + MotHaCpciInfo.ChassisType = CPCI_CHASSIS_MOT_CPX8216T; + break; + case PCI_DEVICE_ID_MOTOROLA_CPX8221: + MotCpciNumSlots = NUM_HA_SLOTS; + MotHaCpciInfo.ChassisType = CPCI_CHASSIS_MOT_CPX8221; + break; + default: + MotCpciNumSlots = NUM_HS_SLOTS; + } + } else { + MotCpciNumSlots = NUM_HS_SLOTS; + } + + if (MotCpciNumSlots == NUM_HA_SLOTS) { + /* Before changing the PCI values, map in the hotswap controller + * and find out which host (A or B) linux is running on. This + * information is needed to decide bus numbering on the cPCI + * busses. + */ + early_read_config_dword(MainHose, 0, HSC_DEVFN, PCI_BASE_ADDRESS_0, &Bar0); +#ifdef CONFIG_PPC + Bar0 += 0xc0000000; +#endif + + HscRegs = (unsigned int *)ioremap(Bar0, 0xff); + + if (le32_to_cpu(HscRegs[58]) & MOTHSC_HOST_DOMAIN) { + MotCpciHostID = 1; + } else { + MotCpciHostID = 0; + } + + iounmap((void *)HscRegs); + + if (!MotCpciHostID) { + MotHaBusInfo[0].DevFn = MOTHSC_BUS1_DEVFN; /* Bus A */ + MotHaBusInfo[1].DevFn = MOTHSC_BUS2_DEVFN; /* Bus B */ + } else { + MotHaBusInfo[0].DevFn = MOTHSC_BUS2_DEVFN; /* Bus A */ + MotHaBusInfo[1].DevFn = MOTHSC_BUS1_DEVFN; /* Bus B */ + } + + /* Tell the cPCI core routines where the slot table exists. */ + CpciBuses = MotHaBusInfo; + CpciSlots = MotHaSlotInfo; + CpciInfos = &MotHaCpciInfo; + + /* Set some values for the two top level bridges. These + * are config cycles so ignore failures. + */ + early_read_config_word(MainHose, 0, MotHaBusInfo[0].DevFn, + PCI_COMMAND, &Command); + Command &= ~(PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + early_write_config_word(MainHose, 0, MotHaBusInfo[0].DevFn, + PCI_COMMAND, Command); + + early_write_config_byte(MainHose, 0, MotHaBusInfo[0].DevFn, + PCI_SECONDARY_BUS, MotHaBusInfo[0].FirstBusNo); + + early_write_config_byte(MainHose, 0, MotHaBusInfo[0].DevFn, + PCI_SUBORDINATE_BUS, MotHaBusInfo[0].LastBusNo); + + early_read_config_word(MainHose, 0, MotHaBusInfo[1].DevFn, + PCI_COMMAND, &Command); + Command &= ~(PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + early_write_config_word(MainHose, 0, MotHaBusInfo[1].DevFn, + PCI_COMMAND, Command); + + early_write_config_byte(MainHose, 0, MotHaBusInfo[1].DevFn, + PCI_SECONDARY_BUS, MotHaBusInfo[1].FirstBusNo); + + early_write_config_byte(MainHose, 0, MotHaBusInfo[1].DevFn, + PCI_SUBORDINATE_BUS, MotHaBusInfo[1].LastBusNo); + } else { + MotHsBusInfo[0].DevFn = MOTHSC_BUS1_DEVFN; + + /* Tell the cPCI core routines where the slot table exists. */ + CpciBuses = MotHsBusInfo; + CpciSlots = MotHsSlotInfo; + CpciInfos = &MotHsCpciInfo; + } + + /* Do not scan the cPCI bus bridget. Let the hot insert do that later */ + pci_excpt_setup_bridge_bdev(MainHose, 0, MOTHSC_BUS1_DEVFN, + motCpci_early_config_bus); + pci_excpt_setup_bridge_bdev(MainHose, 0, MOTHSC_BUS2_DEVFN, + motCpci_early_config_bus); +#ifdef CONFIG_X86 + pci_excpt_setup_bridge_bdev(MainHose, 0, AGP_DEVFN, + motCpci_ignore_agp); +#endif + + LastIo = PCI_IO_CPCI_START; + LastMem = PCI_MEM_CPCI_START; + if (MotCpciNumSlots == NUM_HA_SLOTS) { + for (loop = MotCpciNumSlots - 1; loop > -1; loop--) { + + MotHaSlotInfo[loop].IoEnd = LastIo; + LastIo -= CpciHaIoSize[loop] * 1024; + + if (LastIo < PciAddrs.io_start) { + panic("PCI system has too much IO space allocated\n"); + } + + MotHaSlotInfo[loop].IoStart = LastIo; + + MotHaSlotInfo[loop].MemEnd = LastMem; + LastMem -= CpciHaMemSize[loop] * 1024 * 1024; + + if (LastMem < PciAddrs.mem_start) { + panic("PCI system has too much Memory space allocated\n"); + } + + MotHaSlotInfo[loop].MemStart = LastMem; + } + + /* Set the bus start and end address based on the correct slot addresses */ + MotHaBusInfo[0].IoStart = MotHaSlotInfo[0].IoStart; + MotHaBusInfo[0].IoEnd = MotHaSlotInfo[5].IoEnd; + MotHaBusInfo[0].MemStart = MotHaSlotInfo[0].MemStart; + MotHaBusInfo[0].MemEnd = MotHaSlotInfo[5].MemEnd; + + MotHaBusInfo[1].IoStart = MotHaSlotInfo[10].IoStart; + MotHaBusInfo[1].IoEnd = MotHaSlotInfo[15].IoEnd; + MotHaBusInfo[1].MemStart = MotHaSlotInfo[10].MemStart; + MotHaBusInfo[1].MemEnd = MotHaSlotInfo[15].MemEnd; + } else { + for (loop = MotCpciNumSlots - 1; loop > -1; loop--) { + + MotHsSlotInfo[loop].IoEnd = LastIo; + LastIo -= CpciHsIoSize[loop] * 1024; + + if (LastIo < PciAddrs.io_start) { + panic("PCI system has too much IO space allocated\n"); + } + + MotHsSlotInfo[loop].IoStart = LastIo; + + MotHsSlotInfo[loop].MemEnd = LastMem; + LastMem -= CpciHsMemSize[loop] * 1024 * 1024; + + if (LastMem < PciAddrs.mem_start) { + panic("PCI system has too much Memory space allocated\n"); + } + + MotHsSlotInfo[loop].MemStart = LastMem; + } + + /* Set the bus start and end address based on the correct slot addresses */ + MotHsBusInfo[0].IoStart = MotHsSlotInfo[0].IoStart; + MotHsBusInfo[0].IoEnd = MotHsSlotInfo[6].IoEnd; + MotHsBusInfo[0].MemStart = MotHsSlotInfo[0].MemStart; + MotHsBusInfo[0].MemEnd = MotHsSlotInfo[6].MemEnd; + } + + if ((pciauto_bus_scan(MainHose, MainHose->first_busno, &PciAddrs)) == -1) { + panic("PCI system needs more than the available PCI address space\n"); + } + + if (MotCpciNumSlots == NUM_HA_SLOTS) { + MainHose->last_busno = MotHaBusInfo[1].LastBusNo; + + /* Set the host bridge to properly cover the whole pci address space. */ + PciAddrs.io_end = MotHaBusInfo[0].IoStart; + PciAddrs.mem_end = MotHaBusInfo[0].MemStart; + pciauto_postscan_setup_bridge(MainHose, 0, 0, MotHaBusInfo[1].LastBusNo, &PciAddrs); + + /* Recode the Hose info for each slot for later use. */ + MotHaBusInfo[0].Hose = MainHose; + MotHaBusInfo[1].Hose = MainHose; + } else { + MainHose->last_busno = MotHsBusInfo[0].LastBusNo; + + /* Set the host bridge to properly cover the whole pci address space. */ + PciAddrs.io_end = MotHsBusInfo[0].IoStart; + PciAddrs.mem_end = MotHsBusInfo[0].MemStart; + pciauto_postscan_setup_bridge(MainHose, 0, 0, MotHsBusInfo[0].LastBusNo, &PciAddrs); + + /* Recode the Hose info for each slot for later use. */ + MotHsBusInfo[0].Hose = MainHose; + } + + for (loop = 0; loop < MotCpciNumSlots; loop++) { + CpciSlots[loop].Hose = MainHose; + } +} + +/* + * This function is called from the pci autoscan routine when the cPCI + * bridges are found. + */ +int +motCpci_early_config_bus(struct pci_controller *hose, int bus, int devfn) +{ + int MotBus; + int Slot; + int RetVal; + unsigned char SubBus; + unsigned short Command; + + if (devfn == CpciBuses[0].DevFn) { + MotBus = 0; + } else { + MotBus = 1; + } + + CpciConfigCpciBridge(hose, bus, devfn, MotBus); + CpciBuses[MotBus].Allocated = CPCI_SLOT_ALLOCATED; + + for (Slot = CpciInfos->StartSlotNum[MotBus]; + Slot <= CpciInfos->EndSlotNum[MotBus]; Slot++) { + if ((RetVal = CpciConfigSlot(Slot, MainHose, CpciBuses[MotBus].FirstBusNo)) < 0) { + if (RetVal == -ENOENT) { + /* Nothing in the slot. */ + continue; + } + + /* config problems on this slot so disable access */ + early_read_config_word(hose, + CpciBuses[MotBus].FirstBusNo, + CpciSlots[Slot].DevFn, + PCI_COMMAND, &Command); + Command &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + early_write_config_word(hose, + CpciBuses[MotBus].FirstBusNo, + CpciSlots[Slot].DevFn, + PCI_COMMAND, Command); + + early_read_config_byte(hose, + CpciBuses[MotBus].FirstBusNo, + CpciSlots[Slot].DevFn, + PCI_SECONDARY_BUS, &SubBus); + + early_write_config_byte(hose, + CpciBuses[MotBus].FirstBusNo, + CpciSlots[Slot].DevFn, + PCI_SUBORDINATE_BUS, SubBus); + + CpciSlots[Slot].Allocated = CPCI_SLOT_INSFAILED; + } + } + + return 0; +} + +void +motRouteNon0Irq(struct pci_dev *dev) +{ + struct pci_bus *TempBus = dev->bus; + unsigned int DevNum = PCI_SLOT(dev->devfn); + + while (TempBus->parent->primary != TempBus->parent->secondary) { + DevNum += PCI_SLOT((TempBus->self)->devfn); + TempBus = TempBus->parent; + } + + DevNum &= 0x03; + + if (dev->bus->number > CpciBuses[0].LastBusNo) { + if (CpciBuses[0].DevFn == MOTHSC_BUS1_DEVFN) { + dev->irq = MotCpciIrqs[1][DevNum]; + } else { + dev->irq = MotCpciIrqs[0][DevNum]; + } + } else { + if (CpciBuses[0].DevFn == MOTHSC_BUS1_DEVFN) { + dev->irq = MotCpciIrqs[0][DevNum]; + } else { + dev->irq = MotCpciIrqs[1][DevNum]; + } + } + + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (unsigned char)dev->irq); +} + +/* Prototypes Mot specific functions needed externally */ +int mot82XXhscAllocateAndInitBus(int); +void mot82XXhscDeallocateAndShutdownBus(int); +int mot82XXhscSetEnumMask(int, int); +int mot82XXhscCheckHealthy(int); + +/* This data structure contains the hardware dependent functions to + * provide functionality for independent code segments. + * */ +CpciFunc MotHaCpciFuncs = { + mot82XXhscAllocateAndInitBus, + mot82XXhscDeallocateAndShutdownBus, + mot82XXhscSetEnumMask, + mot82XXhscCheckHealthy, + motRouteNon0Irq +}; + +CpciFunc MotHsCpciFuncs = { + NULL, + NULL, + motEnumEnable, + NULL, + motRouteNon0Irq +}; + +wait_queue_head_t motCpciDomainWaitQ; +int motCpciDomainTakeBusNums; +extern spinlock_t CpciPciAccessLock; + +void +motCpciSetDomainTakeover(int bus) +{ + motCpciDomainTakeBusNums |= 0x1 << bus; + wake_up_interruptible(&motCpciDomainWaitQ); + + return; +} + +int +motCpciCatchDomainTakeover(void *arg) +{ + unsigned long flags; + int Bus; + + exit_mm(current); // release some unneeded resources + exit_files(current); + exit_fs(current); + + strcpy(current->comm, "tDto"); + + init_waitqueue_head(&motCpciDomainWaitQ); + + spin_lock_irqsave(&CpciPciAccessLock, flags); + + for(;;) { + if (!motCpciDomainTakeBusNums) { + spin_unlock_irqrestore(&CpciPciAccessLock, flags); + interruptible_sleep_on(&motCpciDomainWaitQ); + spin_lock_irqsave(&CpciPciAccessLock, flags); + } + + for (Bus = 0; Bus < CpciInfos->MaxBusNum; Bus++) { + if (motCpciDomainTakeBusNums & (0x1 << Bus)) { + motCpciDomainTakeBusNums &= ~(0x1 << Bus); + CpciDelBus(Bus, 0); + } + } + } +} + +extern struct list_head pci_root_buses; +extern struct pci_controller* hose_head; + +void +motCpci_init(void) +{ + struct pci_bus *HeadBus; + + /* Check to see if this is a hot swap and not a HA chassis. */ + if (MotCpciNumSlots != NUM_HA_SLOTS) { + /* Set up to receive the ENUM signal. */ + motEnum_init(); + + /* Export dependent function structure. */ + CpciFunctions = &MotHsCpciFuncs; + + /* Reset the hose and top level bus info to reality for HA numbers */ + hose_head->last_busno = CpciBuses[0].LastBusNo; + + HeadBus = pci_bus_b(pci_root_buses.next); + HeadBus->subordinate = CpciBuses[0].LastBusNo; + + motCpci_find_driver(MOTHSC_BUSA); + return; + } + + /* We now know this is an 82XX chassis so we need to be able + * to catch the other host taking a bus domain away from this + * host. + */ + kernel_thread(motCpciCatchDomainTakeover, NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + + /* Initialize the hot swap controller. */ + mot82XXhsc_init(); + + /* Export dependent function structure. */ + CpciFunctions = &MotHaCpciFuncs; + + /* Reset the hose and top level bus info to reality for HA numbers */ + hose_head->last_busno = CpciBuses[1].LastBusNo; + + HeadBus = pci_bus_b(pci_root_buses.next); + HeadBus->subordinate = CpciBuses[1].LastBusNo; + + if (mot82XXhscBusStatus(MOTHSC_BUSA)) { + /* Bus was powered on at boot. Need to allert + * system to download driver if needed. */ + motCpci_find_driver(MOTHSC_BUSA); + } + + if (mot82XXhscBusStatus(MOTHSC_BUSB)) { + /* Bus was powered on at boot. Need to allert + * system to download driver if needed. */ + motCpci_find_driver(MOTHSC_BUSB); + } +} + +void +motCpci_find_driver(int bus) +{ + struct pci_dev *Dev; + int Slot, LastSlot = -1, SlotSubDev = 0; + + pci_for_each_dev(Dev) { + if ((Dev->bus->number >= CpciBuses[bus].FirstBusNo) && + (Dev->bus->number <= CpciBuses[bus].LastBusNo)) { + + if ((Slot = CpciFindSlotFromDev(Dev)) < 0) { + continue; + } + + if ((Dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + continue; + } + + if (Slot != LastSlot) { + LastSlot = Slot; + SlotSubDev = 0; + } + + CpciFunctions->MapIrq(Dev); + Dev->cpci_location = (Slot << 16) | SlotSubDev++; + + CpciRegisterOpenCheck(Dev); + } + } +} diff -u -r --new-file linux/drivers/ha/cpci/mot_enum.c ha/drivers/ha/cpci/mot_enum.c --- linux/drivers/ha/cpci/mot_enum.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/mot_enum.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,599 @@ +/* + * mot_enum.c + * + * Motorola non HSC enum hardware access. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mot_enum.h" +#include "phs.h" + +/* Driver functions. */ +void motEnum_intr(int, void *, struct pt_regs *); + +int motEnumInit(void); +int motEnumEnable(int, int); +void motEnumDisable(void); +void motEnumIntClear(void); +BOOLEAN motEnumInterruptCheck(void); +BOOLEAN motEnumQuery(void); + +int motEnumHsiInit(void); +BOOLEAN motEnumHsiQueryEnumState(void); +BOOLEAN motEnumHsiCheckEnumInterrupt(void *); +HSI_STATUS motEnumHsiEnableEnums(void); +HSI_STATUS motEnumHsiDisableEnums(void); +int motEnumHsiConvertStatus(HSI_STATUS); + +/* Functions to be accessed from the PICMG 2.12 independent code */ +int HsiThreadRegister(void); +void HsiPlatformEnumHandler(int, void *, struct pt_regs *); + +#ifdef CONFIG_PPC +#define ENUM_IRQ 9 + +#define Z8536_BASE 0x844 +#define Z8536_DATA_A 0x844 +#define Z8536_DATA_B 0x845 +#define Z8536_DATA_C 0x846 +#define Z8536_CTL 0x847 +#define ZBUS_INT_ACK 0x84F +#else +#define ENUM_IRQ 11 +#endif + +int +motEnum_init(void) +{ + printk("Initialize the Motorola Non HSC Enum controller\n"); + +#ifdef CONFIG_PPC + if (check_region(Z8536_BASE, 8)) { + printk("Error allocating I/O space address 0x%x for enum handling\n", Z8536_BASE); + return -ENODEV; + } + + request_region(Z8536_BASE, 4, "Enum"); + + if (request_irq(ENUM_IRQ, (void *)&motEnum_intr, SA_SHIRQ, + "Enum", &motEnum_init)) { + release_region(Z8536_BASE, 4); + return -EIO; + } +#else + if (request_irq(ENUM_IRQ, (void *)&motEnum_intr, SA_SHIRQ, + "Enum", &motEnum_init)) { + return -EIO; + } +#endif + + /* If the PICMG 2.12 interface has been enabled then init it. */ + if (motEnumHsiInit()) { + return -ESRCH; + } + + HsiThreadRegister(); + + motEnumInit(); + + return 0; +} + +void +motEnum_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + /* IF the PICMG 2.12 is configured then call its + * interrupt routine. + */ + HsiPlatformEnumHandler(0, NULL, NULL); +} + +#ifdef CONFIG_PPC + +/* some register definitions for the Zilog CIO */ +/* Master Interrupt Control Register */ +#define MASTER_INT_CTL 0x00 + +#define MIC_MASTER_INT_ENABLE 0x80 +#define MIC_DISABLE_LOWER_CHAIN 0x40 +#define MIC_NO_VECTOR 0x20 +#define MIC_VECTOR_A_INCL_STS 0x10 +#define MIC_VECTOR_B_INCL_STS 0x08 +#define MIC_VECTOR_C_INCL_STS 0x04 +#define MIC_RIGHT_JUSTIFIED_ADDR 0x02 +#define MIC_RESET 0x01 + +/* Master Configuration Control Register */ +#define MAIN_CC 0x01 + +#define MCC_PORT_B_ENABLE 0x80 +#define MCC_CNTR_1_ENABLE 0x40 +#define MCC_CNTR_2_ENABLE 0x20 +#define MCC_PORT_C_ENABLE 0x10 +#define MCC_PORT_A_B_LINK 0x08 +#define MCC_PORT_A_ENABLE 0x04 +#define MCC_CNTR_MODE_MASK 0x03 + +/* Interrupt Vector Registers */ +#define PORT_A_IV 0x02 +#define PORT_B_IV 0x03 +#define PORT_C_IV 0x04 + +#define PORTB_CS 0x9 + +#define PORTA_DR 0xd +#define PORTB_DR 0xe +#define PORTC_DR 0xf + +#define CURRENT_VECTOR 0x1f + +#define PORTA_MS 0x20 +#define PORTB_MS 0x28 + +#define PORTB_DPP 0x2a +#define PORTB_DD 0x2b +#define PORTB_SIO 0x2c +#define PORTB_PP 0x2d +#define PORTB_PT 0x2e +#define PORTB_PM 0x2f + +#define INTR_CLR 0x20 +#define INTR_SET 0xc0 + +#define MAIN_LAT_PM 0x1 +#define MAIN_OR_MODE 0x04 + +#define ENUM_BIT 0x40 /* Bit 6 */ +#define INT_PEND 0x20 /* Bit 5 */ +#define PATTERN_MATCH_FLAG 0x02 /* Bit 1 of PORTx_CS register */ + +#define MOT_ENUM_IN_CTL() inb(Z8536_CTL); eieio() +#define MOT_ENUM_OUT_CTL(x) outb((x),Z8536_CTL); eieio(); udelay(2) + +static volatile unsigned int +read_z8536( unsigned char reg ) +{ + uint temp; + + (void) inb( Z8536_CTL ); //set state machine to known state + outb( reg, Z8536_CTL); // point to the register + temp = inb( Z8536_CTL ); // get register value + + return temp; +} + +static void +write_z8536( unsigned char reg, unsigned char val ) +{ + (void) inb(Z8536_CTL); //set state machine to known state + outb( reg, Z8536_CTL ); // point to the register and arm write + outb( val, Z8536_CTL ); // do data transfer to the target register + + return; +} + +int +motEnumInit(void) +{ + unsigned int RetVal; + unsigned long flags; + + /* Disable Port B in Config Control Reg */ + RetVal = read_z8536( MAIN_CC ); + write_z8536( MAIN_CC, (RetVal & ~MCC_PORT_B_ENABLE) ); + (void) read_z8536( MAIN_CC ); + (void) read_z8536( PORTB_DR ); + + /* now setup some interrupt pseudo-vectors for this part */ + if ( 0 == read_z8536( PORT_A_IV ) ) + { + write_z8536( PORT_A_IV, 0xa0 ); + (void) read_z8536( PORT_A_IV ); + } + + if ( 0 == read_z8536( PORT_B_IV ) ) + { + write_z8536( PORT_B_IV, 0xb0 ); + (void) read_z8536( PORT_B_IV ); + } + else + { + write_z8536( PORT_B_IV, 0xb0 ); + (void) read_z8536( PORT_B_IV ); + } + + if ( 0 == read_z8536( PORT_C_IV ) ) + { + write_z8536( PORT_C_IV, 0xc0 ); + (void) read_z8536( PORT_C_IV ); + } + + + /* Port Mode */ + write_z8536(PORTB_MS, MAIN_OR_MODE); // set as bit port with pattern or + (void) read_z8536( PORTB_MS ); + (void) read_z8536( PORTB_DR ); + + /* Set pattern transition for zero */ + RetVal = read_z8536( PORTB_PM ); + write_z8536( PORTB_PM, (RetVal | ENUM_BIT) ); // enable pattern on enum bit + (void) read_z8536( PORTB_PM ); + (void) read_z8536( PORTB_DR ); + + RetVal = read_z8536( PORTB_PT ); + write_z8536( PORTB_PT, (RetVal & ~ENUM_BIT) ); // set for level, not transition + (void) read_z8536( PORTB_PT ); + (void) read_z8536( PORTB_DR ); + + RetVal = read_z8536( PORTB_PP ); + write_z8536( PORTB_PP, (RetVal & ~ENUM_BIT) ); // look for zero level + (void) read_z8536( PORTB_PP ); + (void) read_z8536( PORTB_DR ); + + /* set up PortB enum bit data path */ + RetVal = read_z8536( PORTB_DPP ); + write_z8536( PORTB_DPP, (RetVal & ~ENUM_BIT) ); // set data path to normal + (void) read_z8536( PORTB_DPP ); + (void) read_z8536( PORTB_DR ); + + RetVal = read_z8536( PORTB_DD ); + write_z8536( PORTB_DD, (RetVal | ENUM_BIT) ); // set input for enum bit + (void) read_z8536( PORTB_DD ); + (void) read_z8536( PORTB_DR ); + + RetVal = read_z8536( PORTB_SIO ); + write_z8536( PORTB_SIO, (RetVal & ~ENUM_BIT) ); // turn off the ones catcher + (void) read_z8536( PORTB_SIO ); + (void) read_z8536( PORTB_DR ); + + /* Enable Port B in Config Control Reg */ + RetVal = read_z8536( MAIN_CC ); + write_z8536( MAIN_CC, (RetVal | MCC_PORT_B_ENABLE) ); + (void) read_z8536( MAIN_CC ); + (void) read_z8536( PORTB_DR ); + + /* Set interrupt enable for port B */ + RetVal = read_z8536( PORTB_CS ); + write_z8536( PORTB_CS, INTR_SET ); + (void) read_z8536( PORTB_CS ); + (void) read_z8536( PORTB_DR ); + + /* Set master interrupt enable */ + RetVal = read_z8536( MASTER_INT_CTL ); + + save_flags( flags ); // debug - so state prior to interrupt prints + cli(); + + write_z8536( MASTER_INT_CTL, + ( RetVal | MIC_MASTER_INT_ENABLE | MIC_VECTOR_B_INCL_STS ) ); + (void) read_z8536( MASTER_INT_CTL ); + (void) read_z8536( PORTB_DR ); + (void) read_z8536( CURRENT_VECTOR ); + + restore_flags( flags ); + + return 0; +} + +int +motEnumEnable(int bus, int flag) +{ + unsigned int RetVal; + unsigned long flags; + + if (bus != 0) { + return -EINVAL; + } + + /* Disable Port B in Config Control Reg */ + RetVal = read_z8536( MAIN_CC ); + write_z8536( MAIN_CC, (RetVal & ~MCC_PORT_B_ENABLE) ); + + /* Set pattern transition back to 1. */ + (void) read_z8536( PORTB_CS ); + RetVal = read_z8536( PORTB_PM ); + write_z8536( PORTB_PM, (RetVal | ENUM_BIT) ); // enable pattern on enum bit + (void) read_z8536( PORTB_PM ); + (void) read_z8536( PORTB_DR ); + (void) read_z8536( PORTB_CS ); + + /* Enable Port B in Config Control Reg */ + save_flags( flags ); + cli(); + RetVal = read_z8536( MAIN_CC ); + write_z8536( MAIN_CC, (RetVal | MCC_PORT_B_ENABLE) ); + (void) read_z8536( CURRENT_VECTOR ); + restore_flags( flags ); + + return 0; +} + +void +motEnumDisable(void) +{ + unsigned int RetVal; + + /* Set pattern transition mode to 0 mask enum off. */ + (void) read_z8536( PORTB_CS ); + RetVal = read_z8536( PORTB_PM ); + write_z8536( PORTB_PM, (RetVal & ~ENUM_BIT) ); // disable pattern on enum bit + (void) read_z8536( PORTB_PM ); + (void) read_z8536( PORTB_DR ); + (void) read_z8536( PORTB_CS ); + motEnumIntClear(); + + return; +} + +void +motEnumIntClear(void) +{ + (void) read_z8536( PORTB_CS ); + write_z8536( PORTB_CS, INTR_CLR ); // clear the pending interrupt indication + (void) read_z8536( PORTB_DR ); + (void) read_z8536( PORTB_CS ); + + return; +} + +int b_direct = 0; +int old_aval = 0; +int old_bval = 0; +int old_cval = 0; + +BOOLEAN +motEnumInterruptCheck(void) +{ + unsigned int RetVal; + + RetVal = read_z8536( PORTB_CS ); + + return ( (RetVal & (INT_PEND|PATTERN_MATCH_FLAG))==(INT_PEND|PATTERN_MATCH_FLAG)); +} + +BOOLEAN +motEnumQuery(void) +{ + unsigned int RetVal; + + RetVal = read_z8536( PORTB_DR ); + + if ( (~RetVal) & ENUM_BIT) + { + return TRUE; + } + else + { + return FALSE; + } + +} + +#else /* PPC_CONFIG */ + +#define ENUM_DEV_SELECT 0x0f + +#define ENUM_STAT 0x00 +#define ENUM_INT_SELECT 0x04 +#define ENUM_INT_ENABLE 0x07 +#define ENUM_LATCH_ENABLE 0x09 + +#define ENUM_ENABLE_INT 0x90 +#define ENUM_RESET_LATCH 0x10 + +#define FPGA_INDEX 0x5d +#define FPGA_DATA 0x5f + +#define FPGA_OUT(reg, data) outb(reg, FPGA_INDEX); \ + outb(data, FPGA_DATA) + +#define FPGA_IN(reg, data) outb(reg, FPGA_INDEX); \ + data = inb(FPGA_DATA) + +int +motEnumInit(void) +{ + unsigned char IntEnableReg; + + FPGA_OUT(ENUM_DEV_SELECT, 0x00); /* Select legacy device */ + FPGA_OUT(ENUM_INT_SELECT, ENUM_IRQ); /* Set signal to generate */ + + /* Clear the latch on the ENUM if set */ + FPGA_OUT(ENUM_LATCH_ENABLE, ENUM_RESET_LATCH); + + /* Enable IRQ */ + FPGA_IN(ENUM_INT_ENABLE, IntEnableReg); + FPGA_OUT(ENUM_INT_ENABLE, IntEnableReg | ENUM_ENABLE_INT); + + return 0; +} + +int +motEnumEnable(int bus, int flag) +{ + unsigned char IntEnableReg; + + FPGA_OUT(ENUM_DEV_SELECT, 0x00); /* Select legacy device */ + + /* Clear the latch on the ENUM if set */ + FPGA_OUT(ENUM_LATCH_ENABLE, ENUM_RESET_LATCH); + + /* Disable IRQ */ + FPGA_IN(ENUM_INT_ENABLE, IntEnableReg); + FPGA_OUT(ENUM_INT_ENABLE, IntEnableReg | ENUM_ENABLE_INT); + + return 0; +} + +void +motEnumDisable(void) +{ + motEnumIntClear(); + return; +} + +void +motEnumIntClear(void) +{ + unsigned char IntEnableReg; + + FPGA_OUT(ENUM_DEV_SELECT, 0x00); /* Select legacy device */ + + /* Clear the latch on the ENUM if set */ + FPGA_OUT(ENUM_LATCH_ENABLE, ENUM_RESET_LATCH); + + /* Disable IRQ */ + FPGA_IN(ENUM_INT_ENABLE, IntEnableReg); + FPGA_OUT(ENUM_INT_ENABLE, IntEnableReg & ~ENUM_ENABLE_INT); + + return; +} + +BOOLEAN +motEnumQuery(void) +{ + unsigned char EnumStat; + + /* Clear the latch on the ENUM if set */ + FPGA_OUT(ENUM_LATCH_ENABLE, ENUM_RESET_LATCH); + + FPGA_IN(ENUM_STAT, EnumStat); + + /* Set means no enum. */ + if (EnumStat & 0x10) { + return FALSE; + } else { + return TRUE; + } +} + +#endif /* CONFIG_PPC */ + +static HSI_INIT initData; + +int +motEnumHsiInit(void) +{ + HSI_STATUS status; + void * pExt; + struct tq_struct noDpc; + + /* Initialize the PICMG 2.12 Driver */ + noDpc.sync = 0; + noDpc.routine = NULL; + noDpc.data = NULL; + + initData.DevExtSize = 0; + initData.Intr = 0; + initData.IntrFlags = 0; + initData.pDevId = NULL; + initData.QueryEnumState = motEnumHsiQueryEnumState; + initData.CheckEnumInterrupt = motEnumHsiCheckEnumInterrupt; + initData.Enable = motEnumHsiEnableEnums; + initData.Disable = motEnumHsiDisableEnums; + initData.Isr = (INTERRUPT_SERVICE_ROUTINE) NULL; + initData.Dpc = noDpc; + + if ((status = HsiPlatformInitialize(&initData, &pExt)) != 0) { + return motEnumHsiConvertStatus(status); + } + return HSI_STATUS_SUCCESS; +} + +BOOLEAN +motEnumHsiQueryEnumState(void) +{ + return motEnumQuery(); +} + +BOOLEAN +motEnumHsiCheckEnumInterrupt(void *pDeviceId) +{ +#ifdef CONFIG_PPC + return motEnumInterruptCheck(); + +#else + return (pDeviceId == hsi_platform_data.pDevId); +#endif /* CONFIG_PPC */ + +} + +HSI_STATUS +motEnumHsiEnableEnums(void) +{ + motEnumEnable(0, 0); + return HSI_STATUS_SUCCESS; +} + +HSI_STATUS +motEnumHsiDisableEnums(void) +{ + motEnumDisable(); + return HSI_STATUS_SUCCESS; +} + +int +motEnumHsiConvertStatus(HSI_STATUS status) +{ + switch (status) { + case HSI_STATUS_SUCCESS : + return 0; + case HSI_STATUS_NO_MEMORY : + return -ENOMEM; + case HSI_STATUS_INVALID_PARAMETER : + return -EINVAL; + case HSI_STATUS_NOT_IMPLEMENTED : + return -ENOSYS; + case HSI_STATUS_NO_SUCH_DEVICE : + return -ENODEV; + case HSI_STATUS_NO_DATA_DETECTED : + return -ENODATA; + case HSI_STATUS_OPERATION_NOT_APPLICABLE : + return -EPERM; + case HSI_STATUS_NOT_AVAILABLE : + return -EBUSY; + default : + return -EPERM; // HSI_STATUS_FAILURE goes here too + } +} diff -u -r --new-file linux/drivers/ha/cpci/mot_enum.h ha/drivers/ha/cpci/mot_enum.h --- linux/drivers/ha/cpci/mot_enum.h Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/mot_enum.h Thu Dec 13 13:03:13 2001 @@ -0,0 +1,42 @@ +/* + * mot_enum.h + * + * Header file for access to the Motorola non HSC enum hardware access. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + */ + +#ifndef MOT_ENUM_H +#define MOT_ENUM_H + +int motEnum_init(void); +int motEnumEnable(int, int); + + +#endif /* MOT_ENUM_H */ diff -u -r --new-file linux/drivers/ha/cpci/pdphs_zt5550.c ha/drivers/ha/cpci/pdphs_zt5550.c --- linux/drivers/ha/cpci/pdphs_zt5550.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/pdphs_zt5550.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,460 @@ +/* + * pdphs_zt5550.c + * + * Ziatech 5550 Platform dependent routines for PICMG 2.12 compatible hot swap. + * + * Author: MontaVista Software, Inc. + * support@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + * 2001Mar02 jfm - Added most of the platform-specific stuff for ZT5550 + * 2000Nov08 jfm - Original Version + */ + +#include +#include +#include +#include +#include + +#include "phs.h" +#include "phs_zt5550.h" + + +/* + * Prototype: + * HSI_STATUS ZT5550_config ( + * OUT SATURN_PARAMS *hcDevice ); + * + * Arguments: + * hcDevice - The struct containing register numbers for the registers + * which are used in the host controller + * + * Return Value: + * HSI_STATUS_SUCCESS - registers were successfully retrieved + * HSI_STATUS_NO_SUCH_DEVICE - The host controller was not found + * HSI_STATUS_NO_MEMORY - The host controller could not be mapped in + * + * Synopsis: + * This routine returns the configuration data for the ZT5550 host + * controller, along with the addresses of the host controller + * configuration and status registers. + * + * NOTE that the SATURN_PARAMS struct is a subset of the SATURN_HC_PARAMS + * struct used by the full RSS driver. The field names remain the same, + * so that the base code need not be changed if this is merged with the + * RSS driver. + * + * Algorithm: + * First, find the host controller in PCI space, then retrieve the data. + * + */ + +HSI_STATUS ZT5550_config ( + OUT SATURN_PARAMS *hcDevice ) +{ + unsigned long ioBase; + unsigned long memBase; + struct pci_dev * pci_device; + uint32 intReg; /* Interrupt mask register address */ + +/* look for first device matching vendor and device IDs */ + + if (!(pci_device = pci_find_device(ZIATECH_VENDOR_ID, + ZT5550_HOSTCNTRL_DEVICE_ID, NULL))) { + return HSI_STATUS_NO_SUCH_DEVICE; + } + + /* the low order bits of the address base registers + * must be masked out. */ + + ioBase = pci_resource_start(pci_device, 0) & PCI_IOBASE_MASK; + memBase = pci_resource_start(pci_device, 1) & PCI_MEMBASE_MASK; + +/* + * Get access to I/O addresses. Note that the size is the highest + * address which will be read. Since things are page aligned and + * only entire pages are mapped, you should not need to add anything. + */ + + if (hcDevice->baseAddrPtr) { + iounmap((void*)hcDevice->baseAddrPtr); + } + + if (!(hcDevice->baseAddrPtr = (uint32)ioremap(memBase, PAGE_SIZE))) { + return HSI_STATUS_NO_MEMORY; + } + + hcDevice->pci.bus = pci_device->bus->number; + hcDevice->pci.device = PCI_SLOT(pci_device->devfn); + hcDevice->pci.function = PCI_FUNC(pci_device->devfn); + + hcDevice->intLevel = pci_device->irq; + + hcDevice->csr_hcindex = hcDevice->baseAddrPtr + 0x00; + hcDevice->csr_hcdata = hcDevice->baseAddrPtr + 0x04; + hcDevice->csr_intstat = hcDevice->baseAddrPtr + 0x08; + hcDevice->csr_intmask = hcDevice->baseAddrPtr + 0x09; + +/* + * Disable host control, fault and serial interrupts + */ + intReg = hcDevice->csr_hcindex; + writeb((uint8)0x08,intReg); + intReg = hcDevice->csr_hcdata; + writeb((uint8)0x07,intReg); + +/* + * Disable timer0, timer1 and ENUM interrupts + */ + intReg = hcDevice->csr_intmask; + writeb((uint8)0x07,intReg); + + return HSI_STATUS_SUCCESS; +} + +/* + * Prototype: + * int convert_status ( + * IN HSI_STATUS status ); + * + * Arguments: + * status - the HSI_STATUS value to convert + * + * Return Value: + * The equivalent errno for the status value + * + * Synopsis: + * Converts an HSI_STATUS value to the equivalent Linux errno + * + * Algorithm: + * It's just a giant switch statement + * + */ + +int convert_status ( + IN HSI_STATUS status) +{ + switch (status) { + case HSI_STATUS_SUCCESS : + return 0; + case HSI_STATUS_NO_MEMORY : + return -ENOMEM; + case HSI_STATUS_INVALID_PARAMETER : + return -EINVAL; + case HSI_STATUS_NOT_IMPLEMENTED : + return -ENOSYS; + case HSI_STATUS_NO_SUCH_DEVICE : + return -ENODEV; + case HSI_STATUS_NO_DATA_DETECTED : + return -ENODATA; + case HSI_STATUS_OPERATION_NOT_APPLICABLE : + return -EPERM; + case HSI_STATUS_NOT_AVAILABLE : + return -EBUSY; + default : + return -EPERM; // HSI_STATUS_FAILURE goes here too + } +} + +/* + * Prototype: + * int ZT5550_init ( + * void); + * + * Arguments: + * none + * + * Return Value: + * 0 - module installation succeeded + * <0 - error code from errno.h + * + * Synopsis: + * This is the init_module routine called by the kernel when the module + * is installed. It initializes the platform data structures. + * + * Algorithm: + * Get the parameters out of PCI Configuration Space, then call + * HsiPlatformInitialize + * + */ + +int +ZT5550_init ( + void) +{ + HSI_INIT initData; + HSI_STATUS status; + SATURN_PARAMS hcDevice; + void * pExt; + struct tq_struct noDpc; + +// +// Initialize the initData struct +// + +/* + * There is kind of a chicken/egg problem here, in that you must + * have the device specific information to initialize the platform, + * but the allocation of the device specific data area is done + * during platform initialization. Rather than spoof it, we + * create the initial struct on the stack, and then copy it to + * the allocated area after platform initialization. + */ + + status = ZT5550_config(&hcDevice); // Get Host Controller specifics + + if (status != HSI_STATUS_SUCCESS) { + return convert_status(status); + } + + noDpc.sync = 0; + noDpc.routine = NULL; + noDpc.data = NULL; + + initData.DevExtSize = sizeof(hcDevice); // platform specific data area + initData.Intr = hcDevice.intLevel; // irq requested by config space + initData.IntrFlags = SA_SAMPLE_RANDOM; // ENUM# interrupts are random +//* initData.IntrFlags = SA_SHIRQ; // ENUM# interrupts are random + initData.pDevId = NULL; // irq not shared +//* initData.pDevId = &EnableRoutine; + initData.QueryEnumState = QueryEnumStateRoutine; + initData.CheckEnumInterrupt = CheckEnumInterruptRoutine; + initData.Enable = EnableRoutine; + initData.Disable = DisableRoutine; + initData.Isr = (INTERRUPT_SERVICE_ROUTINE) NULL; + initData.Dpc = noDpc; + + status = HsiPlatformInitialize(&initData, &pExt); + + if (status != HSI_STATUS_SUCCESS) { + return convert_status(status); + } + + /* copy the platform specific data */ + *(SATURN_PARAMS *)hsi_instance_data = hcDevice; + return HSI_STATUS_SUCCESS; +} + +/* + * Prototype: void cleanup_module + * ( void); + * + * Arguments: + * none + * + * Return Value: + * none + * + * Synopsis: + * This is the cleanup_module routine called by the kernel when the + * module is removed. It is responsible for returning all system + * resources allocated by the Platform Driver in preparation for + * unloading the module. Most implementations will just call the + * platform-independent function HsiPlatformTerminate() from this + * routine. + * + */ + +module_init(ZT5550_init); +module_exit(HsiPlatformTerminate); + + +/* + * Prototype: + * BOOLEAN QueryEnumStateRoutine ( + * void ); + * + * Arguments: + * none + * + * Return Value: + * TRUE if ENUM# is active + * FALSE if ENUM# is inactive + * + * Synopsis: + * This function returns the current state of the hardware signal ENUM# + * on the CPci backplane. It is independent of whether ENUM# interrupts + * are currently masked on the system board. + * + * Algorithm: Read the state of the ENUM# signal from the IO port. + * + */ + +BOOLEAN QueryEnumStateRoutine ( + void ) +{ + uint8 IOdata; + + /* read the I/O port containing ENUM# */ + IOdata = inb_p(ZT5550_PortNum); + + /* is ENUM# asserted? */ + return ((IOdata & ZT5550_EnumMask) == ZT5550_EnumMask); +} + +/* + * Prototype: + * BOOLEAN CheckEnumInterruptRoutine ( + * IN void *pDeviceID ); + * + * Arguments: + * pDeviceID - The interrupting device ID sent in from the interrupt + * dispatcher. + * + * Return Value: + * TRUE if the current interrupt was caused by the ENUM# signal + * FALSE otherwise + * + * Synopsis: + * This function verifies that the current interrupt was caused by + * the ENUM# signal. It is only necessary to call this function if + * the ENUM# IRQ is shared. + * + * Algorithm: + * Check to see if the device ID passed in is the one used when + * registering the ENUM# interrupt handler. + * NOTE that no check is made whether the interrupt is shared, but + * this algorithm should work in any case. + */ + +BOOLEAN CheckEnumInterruptRoutine ( + void *pDeviceId) +{ +BOOLEAN ret; +SATURN_PARAMS *hcDevice = (SATURN_PARAMS *)hsi_instance_data; +uint32 intReg; /* Interrupt status register address */ +uint8 reg; + + ret = FALSE; + if (pDeviceId == hsi_platform_data.pDevId) { + intReg = hcDevice->csr_intstat; + reg = readb(intReg); + if (reg) + ret = TRUE; + } + return ret; +} + +/* + * Prototype: + * HSI_STATUS EnableRoutine ( + * void); + * + * Arguments: + * none + * + * Return Value: + * HSI_STATUS_SUCCESS ENUM# events have been enabled + * HSI_STATUS_FAILURE ENUM# events were already enabled + * HSI_STATUS_NOT_IMPLEMENTED ENUM# events are not supported by this platform + * Other HSI_STATUS values Other errors occurred during execution of this + * function + * + * Synopsis: + * This function enables the generation of ENUM# events. It is typically + * called by the platform-independent part after handling an ENUM# event + * to re-enable ENUM# events. + * + * Implementation of this function is optional. + * + * Algorithm: + * Write the control register masking ENUM# interrupts to unmask ENUM#. + * + */ + +HSI_STATUS EnableRoutine ( + void ) +{ + uint8 reg; /* temporary holding area */ + uint32 intReg; /* Interrupt mask register address */ + SATURN_PARAMS *hcDevice = (SATURN_PARAMS *)hsi_instance_data; + + if(hcDevice == NULL) { + return HSI_STATUS_NOT_AVAILABLE; + } + + intReg = hcDevice->csr_intmask; + + reg = readb(intReg); // read the interrupt mask register + if (!(reg & ZT5550_EnumEnableBit)) { + return HSI_STATUS_FAILURE; // ENUM# ints already enabled + } + + reg = reg & ~ZT5550_EnumEnableBit; + writeb(reg, intReg); // write the new interrupt mask out + + return HSI_STATUS_SUCCESS; +} + +/* + * Prototype: + * HSI_STATUS DisableRoutine ( + * void); + * + * Arguments: + * none + * + * Return Value: + * HSI_STATUS_SUCCESS ENUM# events have been enabled + * HSI_STATUS_FAILURE ENUM# events were already enabled + * HSI_STATUS_NOT_IMPLEMENTED ENUM# events are not supported by this platform + * Other HSI_STATUS values Other errors occurred during execution of this + * function + * + * Synopsis: + * This function disables the generation of ENUM# events. It is typically + * called by the platform-independent ISR when handling an ENUM# interrupt. + * + * Implementation of this function is optional. + * + * Algorithm: + * Write the control register masking ENUM# interrupts to mask ENUM#. + * + */ + +HSI_STATUS DisableRoutine ( + void ) +{ + uint8 reg; /* temporary holding area */ + uint32 intReg; /* Interrupt mask register address */ + SATURN_PARAMS *hcDevice = (SATURN_PARAMS *)hsi_instance_data; + + if(hcDevice == NULL) { + return HSI_STATUS_NOT_AVAILABLE; + } + + intReg = hcDevice->csr_intmask; + + reg = readb(intReg); // read then interrupt mask register + if (reg & ZT5550_EnumEnableBit) { + return HSI_STATUS_FAILURE; // ENUM# ints already disabled + } + + reg = reg | ZT5550_EnumEnableBit; + writeb(reg, intReg); // write the new interrupt mask out + + return HSI_STATUS_SUCCESS; +} diff -u -r --new-file linux/drivers/ha/cpci/phs.h ha/drivers/ha/cpci/phs.h --- linux/drivers/ha/cpci/phs.h Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/phs.h Thu Dec 13 13:25:22 2001 @@ -0,0 +1,377 @@ +/* + * phs.h + * + * Include file for PICMG compatible hot swap operations + * + * Author: MontaVista Software, Inc. + * support@mvista.com + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + * 2000Oct30 jfm - Original Version + */ + +#ifndef LINUX_PICMG_HOTSWAP_H +#define LINUX_PICMG_HOTSWAP_H + +// the macros IN and OUT are used to help comprehension in +// the following function prototypes, and have no other purpose +#define IN +#define OUT + +#define FALSE 0 +#define TRUE !FALSE + +// OS-dependent types used by the PICMG 2.12 spec. +#include +#include +#include +#include + +typedef __s8 int8; +typedef __s16 int16; +typedef __s32 int32; +typedef __u8 uint8; +typedef __u16 uint16; +typedef __u32 uint32; +typedef struct file HSI_DEVICE; +typedef struct file * HSI_SLOT_CONTROL_HANDLE; +typedef int BOOLEAN; +typedef int HSI_STATUS; + +// Main Function table definition +typedef void (*PLATFORM_ENUM_EVENT_CALLBACK)( + IN void *pContext ); + +typedef BOOLEAN (*QUERY_ENUM_STATE_ROUTINE)( + IN HSI_DEVICE *pDevice ); + +typedef HSI_STATUS (*SET_ENUM_EVENT_CALLBACK)( + IN HSI_DEVICE *pDevice, + IN PLATFORM_ENUM_EVENT_CALLBACK Callback, + IN void *pContext ); + +typedef BOOLEAN (*ENABLE_ENUM_ROUTINE)( + IN HSI_DEVICE *pDevice, + IN BOOLEAN State ); + +typedef struct HSI_PLATFORM_FTABLE_STRUCT { + // Function table header + uint16 Version; + uint16 Size; + QUERY_ENUM_STATE_ROUTINE QueryEnumStateFunc; + SET_ENUM_EVENT_CALLBACK SetEnumEventCallbackFunc; + ENABLE_ENUM_ROUTINE EnableEnumEventsFunc; +} HSI_PLATFORM_FTABLE; + +BOOLEAN QueryEnumState( + IN HSI_DEVICE *pDevice ); + +HSI_STATUS SetEnumEventCallback( + IN HSI_DEVICE *pDevice, + IN PLATFORM_ENUM_EVENT_CALLBACK Callback, + IN void *pContext ); + +BOOLEAN EnableEnumEvents( + IN HSI_DEVICE *pDevice, + IN BOOLEAN State ); + +// +// HS_CSR definitions +// + +typedef struct HSI_SLOT_CONFIG_INTERFACE_STRUCT HSI_SLOT_CONFIG_INTERFACE; + +typedef int32 (*READ_CONFIG_ROUTINE) ( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *Buffer, + IN uint32 Offset, + IN uint32 Size ); + +typedef int32 (*WRITE_CONFIG_ROUTINE) ( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *Buffer, + IN uint32 Offset, + IN uint32 Size ); + +int32 ReadConfigRoutine( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + OUT void *Buffer, + IN uint32 Offset, + IN uint32 Size ); + +int32 WriteConfigRoutine( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *Buffer, + IN uint32 Offset, + IN uint32 Size ); + +struct HSI_SLOT_CONFIG_INTERFACE_STRUCT { + uint16 Version; + uint16 Size; // Should be sizeof(HSI_SLOT_CONFIG_INTERFACE) + READ_CONFIG_ROUTINE ReadConfig; // Function to read config space + WRITE_CONFIG_ROUTINE WriteConfig; // Function to write config space + // Other private fields go here +}; + +// Function pointer typedefs for handling alternative HS_CSR operations + +typedef HSI_STATUS (*OPEN_HS_CSR_FUNCTION)( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + OUT void **ppContext ); + +typedef HSI_STATUS (*CLOSE_HS_CSR_FUNCTION)( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *pContext ); + +typedef HSI_STATUS (*GET_HS_CSR_FUNCTION)( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *pContext, + OUT uint8 *pResult ); + +typedef HSI_STATUS (*SET_HS_CSR_FUNCTION)( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *pContext, + IN uint8 Mask ); + +typedef HSI_STATUS (*CLEAR_HS_CSR_FUNCTION)( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *pContext, + IN uint8 Mask ); + +// Function table for handling HS_CSR operations +typedef struct HSI_HSCSR_FTABLE_STRUCT { + // Function table header + uint16 Version; + uint16 Size; // Should be sizeof(HSI_HSCSR_FTABLE) + uint32 VendorID; // Board descriptor: Vendor ID + uint32 DeviceID; // Board descriptor: Device ID + uint32 SubVendorID; // Board descriptor: Subsystem Vendor ID + uint32 SubSystemID; // Board descriptor: Subsystem ID + uint8 StartRevID; // Board descriptor: starting Revision ID + uint8 EndRevID; // Board descriptor: ending Revision ID + // The function table + OPEN_HS_CSR_FUNCTION OpenHsCsr; // Open function + CLOSE_HS_CSR_FUNCTION CloseHsCsr; // Close function + GET_HS_CSR_FUNCTION GetHsCsrBits; // Get bits function + SET_HS_CSR_FUNCTION SetHsCsrBits; // Set bits function + CLEAR_HS_CSR_FUNCTION ClearHsCsrBits; // Clear bits function +} HSI_HSCSR_FTABLE; + +HSI_STATUS OpenHsCsrRoutine( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + OUT void **ppContext ); + +HSI_STATUS CloseHsCsrRoutine( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *pContext ); + +HSI_STATUS GetHsCsrBitsRoutine( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *pContext, + OUT uint8 *pResult ); + +HSI_STATUS SetHsCsrBitsRoutine( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *pContext, + IN uint8 Mask ); + +HSI_STATUS ClearHsCsrBitsRoutine( + IN HSI_SLOT_CONFIG_INTERFACE *pSlotInterface, + IN void *pContext, + IN uint8 Mask ); + +HSI_STATUS HsiRegisterAlternateCsrHandler( + IN HSI_HSCSR_FTABLE *pFtable ); + +// +// High Availailability Slot Control definitions +// +HSI_STATUS HsiOpenSlotControl( + OUT HSI_SLOT_CONTROL_HANDLE *pHandle ); + +HSI_STATUS HsiCloseSlotControl( + IN HSI_SLOT_CONTROL_HANDLE Handle ); + +HSI_STATUS HsiGetSlotCount( + IN HSI_SLOT_CONTROL_HANDLE Handle, + OUT uint32 *pCount ); + +HSI_STATUS HsiGetBoardPresent( + IN HSI_SLOT_CONTROL_HANDLE Handle, + IN uint32 Slot, + OUT BOOLEAN *pPresent ); + +HSI_STATUS HsiGetBoardHealthy( + IN HSI_SLOT_CONTROL_HANDLE Handle, + IN uint32 Slot, + OUT BOOLEAN *pHealthy ); + +HSI_STATUS HsiGetSlotPower( + IN HSI_SLOT_CONTROL_HANDLE Handle, + IN uint32 Slot, + OUT BOOLEAN *pPower ); + +HSI_STATUS HsiSetSlotPower( + IN HSI_SLOT_CONTROL_HANDLE Handle, + IN uint32 Slot, + IN BOOLEAN Power ); + +HSI_STATUS HsiGetSlotReset( + IN HSI_SLOT_CONTROL_HANDLE Handle, + IN uint32 Slot, + OUT BOOLEAN *pReset ); + +HSI_STATUS HsiSetSlotReset( + IN HSI_SLOT_CONTROL_HANDLE Handle, + IN uint32 Slot, + IN BOOLEAN Reset ); + +typedef struct HSI_SLOT_EVENT_INFO_STRUCT { + uint32 SlotNumber; + BOOLEAN Present; + BOOLEAN Powered; + BOOLEAN Healthy; + BOOLEAN InReset; +} HSI_SLOT_EVENT_INFO; + +typedef void (*HSI_SLOT_EVENT_CALLBACK) ( + IN void *pContext, + IN BOOLEAN HscError, + IN HSI_SLOT_EVENT_INFO *pSlotInfo ); + +HSI_STATUS HsiSetSlotEventCallback( + IN HSI_SLOT_CONTROL_HANDLE Handle, + IN HSI_SLOT_EVENT_CALLBACK Callback, + IN void *pContext ); + +// +// LINUX OS-dependent definitions +// + +HSI_STATUS HsiPlatformGetFunctionTable ( + OUT HSI_PLATFORM_FTABLE *pFtable ); + +// Platform independent interface definitions +typedef BOOLEAN (*QUERY_ENUM_ROUTINE)( + void ); + +typedef BOOLEAN (*IS_ENUM_INTERRUPT_ROUTINE)( + IN void *pDeviceId ); + +typedef HSI_STATUS (*ENABLE_ROUTINE)( + void ); + +typedef HSI_STATUS (*DISABLE_ROUTINE)( + void ); + +typedef void (*INTERRUPT_SERVICE_ROUTINE)( + IN int Interrupt, + IN void *pDeviceID, + IN struct pt_regs *pRegisters ); + +typedef struct HSI_INITIALIZATION_STRUCT { + uint32 DevExtSize; + int32 Intr; + uint32 IntrFlags; + void *pDevId; + QUERY_ENUM_ROUTINE QueryEnumState; + IS_ENUM_INTERRUPT_ROUTINE CheckEnumInterrupt; + ENABLE_ROUTINE Enable; + DISABLE_ROUTINE Disable; + INTERRUPT_SERVICE_ROUTINE Isr; + struct tq_struct Dpc; +} HSI_INIT; + +HSI_STATUS HsiPlatformInitialize ( + IN HSI_INIT *pInitData, + OUT void **ppExt ); + +HSI_STATUS HsiPlatformTerminate ( + void ); + +HSI_STATUS HsiPlatformGetInstanceData ( + void **ppExt ); + +HSI_STATUS HsiPlatformSignalEnum ( + void ); + +HSI_STATUS HsiPlatformGetEnumIrq ( + IN uint32 IrqSet, + OUT uint32 *pEnumIrq ); + +// Platform dependent interface definitions +BOOLEAN QueryEnumStateRoutine ( + void ); + +BOOLEAN CheckEnumInterruptRoutine ( + IN void *pDeviceID ); + +HSI_STATUS EnableRoutine ( + void ); + +HSI_STATUS DisableRoutine ( + void ); + +void IsrRoutine ( + int Interrupt, + void *pDeviceID, + struct pt_regs *pRegisters ); + +// +// Global variables +// +extern spinlock_t hsi_lock; +extern wait_queue_head_t hsi_platform_queue; +extern BOOLEAN hsi_platform_initialized; + +extern int hsi_pid; +extern int hsi_thread_registered; + +extern HSI_INIT hsi_platform_data; +extern void *hsi_instance_data; +extern void *hsi_enum_context; +extern PLATFORM_ENUM_EVENT_CALLBACK hsi_EnumEventCallback; +extern HSI_PLATFORM_FTABLE hsi_PlatformFtable; + +// +// Constants +// +#define HSI_STATUS_SUCCESS 0 +#define HSI_STATUS_NO_MEMORY 1 +#define HSI_STATUS_INVALID_PARAMETER 2 +#define HSI_STATUS_NOT_IMPLEMENTED 3 +#define HSI_STATUS_NO_SUCH_DEVICE 4 +#define HSI_STATUS_NO_DATA_DETECTED 5 +#define HSI_STATUS_OPERATION_NOT_APPLICABLE 6 +#define HSI_STATUS_NOT_AVAILABLE 7 +#define HSI_STATUS_FAILURE 255 + +#define HSI_MATCH_ANY_ID 0xA11C0DE // Must be >65535 +#define HSI_FTABLE_VERSION 0x0200 +#define HSI_SLOT_CONFIG_VERSION 0x0100 +#define HSI_HSCSR_FTABLE_VERSION 0x0200 + +#endif + diff -u -r --new-file linux/drivers/ha/cpci/phs_zt5550.h ha/drivers/ha/cpci/phs_zt5550.h --- linux/drivers/ha/cpci/phs_zt5550.h Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/phs_zt5550.h Thu Dec 13 13:03:13 2001 @@ -0,0 +1,86 @@ +/* + * phs_zt5550.h + * + * Ziatech 5550 platform-dependent include file for PICMG compatible + * hot swap operations + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + * 2001Mar02 jfm - Original Version + */ + +#ifndef LINUX_PICMG_HOTSWAP_ZT5550_H +#define LINUX_PICMG_HOTSWAP_ZT5550_H + +#define ZIATECH_VENDOR_ID 0x1138 +#define ZT5550_HOSTCNTRL_DEVICE_ID 0x5550 +#define PCI_IOBASE_MASK ~0x3 /* mask for IO base address */ +#define PCI_MEMBASE_MASK ~0xf /* mask for memory base address */ + +#define ZT5550_EnumMask 0x40 /* Mask to get to the ENUM# bit on the bus */ +#define ZT5550_PortNum 0xe1 /* digital I/O port storing ENUM# */ + +#define ZT5550_EnumEnableBit 0x04 /* Mask to get to ENUM# bit in HC register */ + +/* + * defined handling that is unique to the version of LINUX + * that is used. + */ + +#ifndef pci_resource_start +#define pci_resource_start(dev, num) (dev->base_address[num]) +#endif + +#ifndef module_init +#define module_init(x) int init_module(void) { return x(); } +#endif +#ifndef module_exit +#define module_exit(x) void cleanup_module(void) { x(); } +#endif + +typedef struct +{ + int16 bus; + uint8 device; + uint8 function; +} pciLocation; + +typedef struct +{ + uint32 baseAddrPtr; + uint16 intLevel; + pciLocation pci; + + /* Host controller register addresses */ + uint32 csr_hcindex; + uint32 csr_hcdata; + uint32 csr_intstat; + uint32 csr_intmask; +} SATURN_PARAMS; + +#endif /* LINUX_PICMG_HOTSWAP_ZT5550_H */ + diff -u -r --new-file linux/drivers/ha/cpci/piphs.c ha/drivers/ha/cpci/piphs.c --- linux/drivers/ha/cpci/piphs.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/piphs.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,777 @@ +/* + * piphs.c + * + * Platform independent routines for PICMG 2.12 compatible hot swap. + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + * 2001Mar13 jfm - Added Infrastructure requirements routines + * 2000Oct31 jfm - Original Version + * + */ + +#include +#include +#include +#include +#include + +#include "phs.h" + +int HsiThreadRegister(void); +int HsiThreadUnregister(void); + +// +// Global variables +// +spinlock_t hsi_lock = SPIN_LOCK_UNLOCKED; // hsi mutex +BOOLEAN hsi_platform_initialized = FALSE; // True when HsiPlatformInitialize + // has succeeded +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +wait_queue_head_t hsi_platform_queue; // platform thread waits here +#else +struct wait_queue *hsi_platform_queue; // platform thread waits here +#endif + +int hsi_pid = 0; // PID for ENUM interrupt thread +int hsi_thread_registered = 0; // Number of registered users of platform thread + +HSI_INIT hsi_platform_data; // contains copy of HSI_INIT struct +void *hsi_instance_data; // pointer to platform dependent data +void *hsi_enum_context; // value passed in to SetEnumEventCallback +PLATFORM_ENUM_EVENT_CALLBACK hsi_EnumEventCallback; + // Callback routine for ENUM events +HSI_PLATFORM_FTABLE hsi_PlatformFtable; // Function table for PI part + + +/* + * Prototype: + * void HsiPlatformEnumHandler( + * IN int Interrupt, + * IN void *pDeviceId, + * IN struct pt_regs *pRegisters ); + * + * Arguments: + * Interrupt - The interrupt number (e.g. IRQ) which caused the Interrupt + * Service Routine to be entered + * pDeviceID - The unique device pointer used when the ISR was registered, + * i.e. the pDevID parameter from HsiPlatformInitialize() + * pRegisters - A copy of the contents of the registers at the point of + * interrupt + * + * Return Value: + * none + * + * Synopsis: + * This is the default platform ENUM# interrupt handler. + * It is called with interrupts off, and exits with interrupts still + * off and the ENUM# interrupt disabled. + * + * Note that the bottom half is run on the immediate queue - this is + * for flexibility. If you want to wake up a thread, you will have to + * write your bottom half appropriately. + * + * Algorithm: + * This function wakes up the ENUM interrupt handling thread. + * and marks a bottom half, if one has been identified. + * Note that this is called in interrupt mode (ints off). + * + */ + +void HsiPlatformEnumHandler ( + IN int Interrupt, + IN void *pDeviceId, + IN struct pt_regs *pRegisters ) +{ + if (hsi_platform_data.CheckEnumInterrupt(pDeviceId)) { // is it our int? + hsi_platform_data.Disable(); // yes, disable ENUM ints + wake_up_interruptible(&hsi_platform_queue); // and wake up the thread + if (hsi_platform_data.Dpc.routine != NULL) { // do we have a DPC? + queue_task(&hsi_platform_data.Dpc, &tq_immediate); // queue it + mark_bh(IMMEDIATE_BH); // mark it for execution + } + } else { + // spurious, or not our int, ignore + } +} + + +/* + * Prototype: + * BOOLEAN QueryEnumState( + * IN HSI_DEVICE *pDevice ); + * + * Arguments: + * pDevice pointer to the specific instance of the platform device + * + * Return value: + * TRUE if ENUM# is active + * FALSE if ENUM# is inactive + * + * Synopsis: + * This function returns the current state of the ENUM# signal. + * It may be called periodically by the Hot Swap System Driver to + * retrieve the current ENUM# signal state. + * + * Algorithm: + * Returns the result of the platform-dependent QueryEnumState routine. + */ + +BOOLEAN QueryEnumState( + IN HSI_DEVICE *pDevice ) +{ + return hsi_platform_data.QueryEnumState(); +} + + +/* + * Prototype: + * HSI_STATUS SetEnumEventCallback( + * IN HSI_DEVICE *pDevice, + * IN PLATFORM_ENUM_EVENT_CALLBACK Callback, + * IN void *pContext ); + * + * Arguments: + * pDevice pointer to the specific instance of the platform device. + * Callback the address of the callback to call; NULL should be passed + * to cancel callback; + * pContext an opaque pointer that will be passed unchanged to the + * callback routine. + * + * Return value: + * HSI_STATUS_SUCCESS returned in the case of success + * Other HSI_STATUS values if errors occurred during execution of this + * function + * + * Synopsis: + * This function is used by the client to specify the callback routine + * that will be called when an ENUM# event occurs. The callback routine + * should have the following prototype: + * void Callback( IN void *pContext ); + * The client should pass NULL to cancel the callback. This function + * shall not be implemented by the Platform Driver if the platform does + * not support ENUM# events. + * + */ + +HSI_STATUS SetEnumEventCallback( + IN HSI_DEVICE *pDevice, + IN PLATFORM_ENUM_EVENT_CALLBACK Callback, + IN void *pContext ) +{ +printk("JSPJSP: SetEnumEventCallback %p\n", Callback); + hsi_enum_context = pContext; + hsi_EnumEventCallback = Callback; + + if (hsi_platform_initialized) { + /* If initialized the wake the sleeping thread to + * check for enums again. + */ + wake_up_interruptible(&hsi_platform_queue); + } + return HSI_STATUS_SUCCESS; +} + + +/* + * Prototype: + * BOOLEAN EnableEnumEvents( + * IN HSI_DEVICE *pDevice, + * IN BOOLEAN State ); + * + * Arguments: + * pDevice pointer to the specific instance of the platform device + * State TRUE to enable ENUM# events; FALSE to disable ENUM# events + * + * Return value: TRUE If ENUM# events were enabled prior to the call + * FALSE If ENUM# events were disabled prior to the call + * + * Synopsis: + * If the platform implements level-sensitive ENUM# interrupts, the + * interrupt request will be active as long as the ENUM# signal stays + * active. Since the ENUM# signal is not de-asserted by a device until + * both INS and EXT bits are cleared in its HS_CSR, it may stay active + * for a long time. To prevent infinite interrupt loops, ENUM# interrupts + * should be disabled using this function inside the event handler. + * + * This function should be used to re-enable ENUM# events after the client + * has processed all devices asserting ENUM# and has either cleared the + * INS and EXT bits, or masked the ENUM# assertion by setting the EIM bit + * in the HS_CSR. + * + * This function shall not be implemented by the Platform Driver if the + * platform does not support ENUM# events. + * + */ + +BOOLEAN EnableEnumEvents( + IN HSI_DEVICE *pDevice, + IN BOOLEAN State ) +{ + HSI_STATUS status; + + if (State) { // Enable ENUM events + status = hsi_platform_data.Enable(); + if (status == HSI_STATUS_SUCCESS) { + return FALSE; // ENUM events were disabled prior to call + } + } else { // Disable ENUM events + status = hsi_platform_data.Disable(); + if (status != HSI_STATUS_SUCCESS) { + return FALSE; // ENUM events were disabled prior to call + } + } + return TRUE; // ENUM events were enabled prior to call +} + + +/* + * Prototype: + * HSI_STATUS HsiPlatformInitialize ( + * IN HSI_INIT *pInitData, + * OUT PVOID *ppExt ); + * + * Arguments: + * pInitData - pointer to the initialization structure of type HSI_INIT + * ppExt - returns a pointer to a private data area for use by the + * platform-dependent part of the driver. If pInitData->DevExtSize + * is 0, this pointer will be returned with a value of NULL. + * + * The HSI_INIT structure fields are defined as follows: + * + * DevExtSize - The number of bytes to allocate for private + * platform-dependent data + * Intr - The interrupt number (e.g. IRQ) of the ENUM# interrupt, + * or -1 if ENUM# interrupts are not implemented by the platform + * IntrFlags - Interrupt mode flags (SA_INTERRUPT, SA_SAMPLE_RANDOM, + * SA_SHIRQ, etc), or 0 + * pDevID - Unique pointer for the device. May be NULL if the ENUM# + * interrupt is not shared, if Isr is NULL, or if ENUM# interrupts + * are not implemented. This pointer is returned when the ISR is + * called + * QueryEnumState - Address of the function in the platform-dependent + * part that returns the current state of the ENUM# signal (mandatory) + * CheckEnumInterrupt - Address of the function in the platform-dependent + * part that can check if the current interrupt is an ENUM# interrupt, + * or NULL if ENUM# interrupts are not implemented by the platform + * Enable - Address of the function in the platform-dependent part which + * enables ENUM# events, or NULL if ENUM# events are not implemented + * by the platform + * Disable - Address of the function in the platform-dependent part which + * disables ENUM# events, or NULL if ENUM# events are not implemented + * by the platform + * Isr - The ENUM# interrupt service routine address, or NULL to use the + * default platform-independent ISR + * Dpc - The routine defined by Dpc will be added to the tq_immediate + * task queue for execution after any platform-independent bottom-half + * task. If the developer wishes to have this routine replace the + * platform-independent task, or have it attached to a different queue, + * they will have to implement their own isr routine. + * + * Return Value: + * HSI_STATUS_SUCCESS Platform initialization succeeded + * HSI_STATUS_NO_MEMORY The routine could not allocate the requested + * amount of memory for the private data area + * HSI_STATUS_INVALID_PARAMETER One of the parameters was invalid or + * out of range + * HSI_STATUS_NOT_AVAILABLE The interrupt number requested is already + * in use + * Other HSI_STATUS values Other errors occurred during execution of + * this function + * + * Synopsis: + * This function initializes the platform-independent part of the + * Platform Driver. It performs the following tasks: + * - Fills in the function callback table for the + * HsiPlatformGetFunctionTable() function + * - If the Interrupt number is not -1, attaches the appropriate + * ISR to the specified interrupt line + * - Allocates the requested private data block + * + * Optional callbacks are included to do the following tasks for + * platforms that implement ENUM# events; platforms that do not + * implement ENUM# events should set these callbacks to NULL: + * + * - Enable ENUM# events ; this function will be called indirectly + * by the Hot Swap System Driver via the EnableEnumEvents function + * after the current event has been processed. Only necessary on + * platforms that have ENUM# events. + * - Disable ENUM# events ; this function will be called from the + * event handler to disable further generation of ENUM# events. + * Only necessary on platforms that have ENUM# events. + * - Check if the current interrupt was caused by ENUM#. Only necessary + * on platforms that have ENUM# interrupts. This function will only + * be called if the ENUM# interrupt line is shared (SA_SHIRQ flag + * was set). + * + * The other optional callbacks represent the interrupt service routine + * and the function to call from the immediate bottom half handler that + * is called after an ENUM# interrupt. It is recommended that you should + * not specify these callbacks explicitly; default implementations + * provided by the platform-independent part are sufficient for most cases. + * The private memory allocated by this function is an area for storing + * platform-dependent data. Its address is returned to the caller in the + * output parameter ppExt. + * + */ + +HSI_STATUS HsiPlatformInitialize ( + IN HSI_INIT *pInitData, + OUT void **ppExt ) +{ + int error; // function return code + INTERRUPT_SERVICE_ROUTINE intr_routine; // temp variable + + if (hsi_platform_initialized) { + return HSI_STATUS_OPERATION_NOT_APPLICABLE; + } + + hsi_platform_data = *pInitData; // save the struct for later use + if (pInitData->DevExtSize !=0) { // allocate the private data area + if ((hsi_instance_data = (void *) + kmalloc(hsi_platform_data.DevExtSize, + GFP_KERNEL)) == NULL) { + return HSI_STATUS_NO_MEMORY; // kmalloc failed! + } + } else { // no private data area requested + hsi_instance_data = NULL; // spec says to null the pointer + } + + *ppExt = hsi_instance_data; + + if (pInitData->Intr > 0) { + if (pInitData->Isr) { // assign ENUM# handler + intr_routine = pInitData->Isr; + } else { + intr_routine = HsiPlatformEnumHandler; + HsiThreadRegister(); + } + + // Get the requested IRQ + error = request_irq((uint32)pInitData->Intr, intr_routine, + pInitData->IntrFlags, "hotswap", + pInitData->pDevId); + if (error < 0) { + if ((error = -EINVAL)) return HSI_STATUS_INVALID_PARAMETER; + if ((error = -ENOMEM)) return HSI_STATUS_NO_MEMORY; + if ((error = -EBUSY)) return HSI_STATUS_NOT_AVAILABLE; + return HSI_STATUS_FAILURE; + } + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + init_waitqueue_head(&hsi_platform_queue); +#endif + + hsi_PlatformFtable.Version = HSI_FTABLE_VERSION; + hsi_PlatformFtable.Size = sizeof(HSI_PLATFORM_FTABLE); + hsi_PlatformFtable.QueryEnumStateFunc = QueryEnumState; + hsi_PlatformFtable.SetEnumEventCallbackFunc = SetEnumEventCallback; + hsi_PlatformFtable.EnableEnumEventsFunc = EnableEnumEvents; + + + // perform any other initialization here + + hsi_platform_initialized = TRUE; + + return HSI_STATUS_SUCCESS; // all done! +} + + +/* + * Prototype: + * HSI_STATUS HsiPlatformGetFunctionTable ( + * OUT HSI_PLATFORM_FTABLE *pFtable ) + * + * Arguments: + * pFtable Pointer to the HSI_PLATFORM_FTABLE struct that will hold the + * function table implemented by the Platform Driver + * + * Return Value: + * HSI_STATUS_SUCCESS This function always succeeds + * + * Synopsis: + * This function obtains the set of functions implemented by the Platform + * Driver for use by the kernel space client (Hot Swap System Driver). + * + */ + +HSI_STATUS HsiPlatformGetFunctionTable ( + OUT HSI_PLATFORM_FTABLE *pFtable ) +{ + *pFtable = hsi_PlatformFtable; + return HSI_STATUS_SUCCESS; +} + + +/* + * Prototype: + * HSI_STATUS HsiPlatformTerminate( + * void ); + * + * Arguments: + * none + * + * Return Value: + * HSI_STATUS_SUCCESS - This function always succeeds + * + * Synopsis: + * This function prepares the platform-independent part of the + * Platform Driver for graceful termination. It should be called from the + * cleanup_module() routine of the platform-dependent part. The + * HsiPlatformTerminate() routine will free any allocated IRQ (if not + * currently shared), free the platform-dependent data area (if any), + * and release all other resources allocated by the HsiPlatformInitialize() + * function. + * + */ + +HSI_STATUS HsiPlatformTerminate ( + void ) +{ + if (hsi_platform_data.Intr > 0) { + free_irq(hsi_platform_data.Intr, hsi_platform_data.pDevId); + if (hsi_platform_data.Isr == NULL) { + HsiThreadUnregister(); // Unregister the default handler + } + } + + if (hsi_instance_data) { // private data area allocated? + kfree(hsi_instance_data); // yes, free it + hsi_instance_data = NULL; + } + + hsi_platform_initialized = FALSE; + + return HSI_STATUS_SUCCESS; // All done! +} + + +/* + * Prototype: + * HSI_STATUS HsiPlatformGetInstanceData ( + * void **ppExt ); + * + * Arguments: + * ppExt - Pointer to the private block of memory for use by the + * platform-dependent part of the driver. If none was allocated, + * this pointer will be null + * + * Return Value: + * HSI_STATUS_SUCCESS - The function succeeded + * HSI_STATUS_NOT_AVAILABLE - The platform is not currently initialized + * Other HSI_STATUS values - Other errors occurred during execution of + * this function + * + * Synopsis: + * This function makes it possible for the platform-dependent part to get + * access to the private data area allocated by the HsiPlatformInitialize() + * function. The size of this area is specified by the DevExtSize parameter + * when calling HsiPlatformInitialize(). + * + */ + +HSI_STATUS HsiPlatformGetInstanceData ( + void **ppExt ) +{ + if (!hsi_platform_initialized) { // oops! + return HSI_STATUS_NOT_AVAILABLE; + } + + *ppExt = hsi_instance_data; + return HSI_STATUS_SUCCESS; +} + + +/* + * Prototype: + * HSI_STATUS HsiPlatformSignalEnum ( + * void ); + * + * Arguments: + * none + * + * Return Value: + * HSI_STATUS_SUCCESS - This function always succeeds + * + * Synopsis: + * This function is called by the platform-dependent part to notify + * the platform-independent part that an ENUM# event has occurred. + * In response, the platform-independent part propagates this notification + * to the clients of the platform driver. The platform-dependent part will + * call this function if it performs ENUM# detection in a non-standard way + * (other than by an edge-triggered or level-sensitive interrupt). + * One possible scenario where this function might be useful is the + * ACPI-based ENUM# detection, where the ENUM# signal is mapped onto an + * ACPI event. An alternative scenario is that the platform-dependent part + * performs its own handling of ENUM# interrupts, but still needs to notify + * the client about the ENUM# event. + * + */ + +HSI_STATUS HsiPlatformSignalEnum ( + void ) +{ + if (hsi_EnumEventCallback != NULL) { + /* Call the callback */ + hsi_EnumEventCallback(hsi_enum_context); + } else { + /* If there is not function to process the enum then + * sleep waiting until it is set. + */ + interruptible_sleep_on(&hsi_platform_queue); + } + return HSI_STATUS_SUCCESS; +} + + +/* + * Prototype: + * HSI_STATUS HsiPlatformGetEnumIrq ( + * IN ULONG IrqSet, + * OUT ULONG *pEnumIrq ); + * + * Arguments: + * IrqSet - A set of bits corresponding to IRQ values to try. A 1 means + * try the IRQ value corresponding to that bit position, a 0 means + * don't try that IRQ + * pEnumIrq - An output parameter which receives the IRQ value assigned + * by the system + * + * Return Value: + * HSI_STATUS_SUCCESS - An available IRQ was found + * HSI_STATUS_NOT_AVAILABLE - no unused IRQs were available in the set + * specified + * HSI_STATUS_INVALID_PARAMETER - Bits were set in IrqSet which don't + * correspond to a valid IRQ + * Other HSI_STATUS values - Other errors occurred during execution of + * this function + * + * Synopsis: + * This function can be called by the platform-dependent part if the + * platform has a choice of several IRQs to be used for the ENUM# signal. + * In that case, this function will select an available IRQ from the pool + * of unused IRQs. The platform-dependent part obtains the IRQ prior to + * calling the HsiPlatformInitialize() function. If the platform-dependent + * part uses a fixed IRQ, it need not call HsiPlatformGetEnumIrq(), but + * may directly pass this fixed value to the HsiPlatformInitialize() + * function. Note that this function does not allocate or reserve the IRQ, + * that must be done by the HsiPlatformInitialize() function. + * HsiPlatformTerminate() is responsible for de-allocating and returning + * all resources claimed by HsiPlatformInitialize() + * + * Algorithm: + * Try all IRQs in the set to find the first which has no action list, + * and thus is free. Note that this is architecture dependent, and + * probably OS revision dependent as well. An alternative method would + * be to use probe_irq_on and use the set returned, but that is a lot + * more overhead. Another alternative would be to try all irqs in the + * set with request_irq, but that is pretty wasteful as well. + * + * Note that this is not done with ints off, and so might return a + * result which is in fact no longer available. This possibility should + * be dealt with by the code in HsiPlatformInitialize(). This code does + * not deal with the possibility of shared interrupts, but could be + * extended to do so. That is left as an exercise to the interested + * reader. + */ + +HSI_STATUS HsiPlatformGetEnumIrq ( + IN uint32 IrqSet, + OUT uint32 *pEnumIrq ) +{ +#if !defined(CONFIG_PPC) + uint32 try_irq; + + for (try_irq=1; try_irq < 32; try_irq++) { + if ((1<comm, "tHsi"); // give the thread a name + + while (TRUE) { + spin_lock_irqsave(&hsi_lock, flags); + if (!hsi_platform_data.QueryEnumState()) { + hsi_platform_data.Enable(); // re-enable ENUM interrupts + interruptible_sleep_on(&hsi_platform_queue); + } + spin_unlock_irqrestore(&hsi_lock, flags); + + // If we were woken up by a signal, see if it's useful, otherwise exit. + if (signal_pending(current)) { + /* sending SIGUSR1 makes us print out some info */ + spin_lock_irq(¤t->sigmask_lock); + sig_num = dequeue_signal(¤t->blocked, &sig_info); + spin_unlock_irq(¤t->sigmask_lock); + + if(sig_num == SIGUSR1) { + printk(KERN_DEBUG "tHsiEnum: could dump some useful info here\n"); + } else { + /* unknown signal, exit the thread */ + break; + } + } + // check if ENUM signal is asserted + while (hsi_platform_data.QueryEnumState()) { + HsiPlatformSignalEnum(); + } + } // while TRUE + return -1; +} + + +/* + * Prototype: + * int HsiThreadRegister ( + * void ); + * + * Arguments: + * none + * + * Return Value: + * none + * + * Synopsis: + * This routine starts the Hsi platform thread. Currently, the + * Hsi Platform thread only does ENUM interrupts, but if other + * services use the thread, they should register here as well. + * Only the first call actually creates the thread. + * + * Algorithm: + * Check to see if thread already created. If the thread is not + * already created, create the thread. In either case, increment the + * hsi_thread_registered counter + * + */ + +int HsiThreadRegister( + void ) +{ + unsigned long flags; + + spin_lock_irqsave(&hsi_lock, flags); + if (hsi_pid<=0) { + spin_unlock_irqrestore(&hsi_lock, flags); + hsi_pid = kernel_thread(HsiPlatformThread, NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + spin_lock_irqsave(&hsi_lock, flags); + } + if (hsi_pid>0) { + hsi_thread_registered++; + } + spin_unlock_irqrestore(&hsi_lock, flags); + return hsi_pid; +} + + +/* + * Prototype: + * void HsiThreadUnregister ( + * void); + * + * Arguments: + * none + * + * Return Value: + * none + * + * Synopsis: + * This routine stops the Hsi platform thread. Currently, the + * Hsi Platform thread only does ENUM interrupts, but if other + * services use the thread, they should unregister here as well. + * The thread will only be killed when the last user unregisters. + * + * Algorithm: + * Decrement the hsi_thread_registered counter. If it is now 0, + * kill the Hsi Platform Thread. + * + */ + +int HsiThreadUnregister ( + void ) +{ + unsigned long flags; + + spin_lock_irqsave(&hsi_lock, flags); +/* how paranoid should we be? check for 0 first? */ + if (!--hsi_thread_registered) { + /* This may be a long time to hold a spin lock, but + * you don't want the thread to try to restart while you + * are killing it. + */ + kill_proc_info(SIGSTOP, (void *)1L, hsi_pid); + } + spin_unlock_irqrestore(&hsi_lock, flags); + + return HSI_STATUS_SUCCESS; +} diff -u -r --new-file linux/drivers/ha/cpci/zia5083cpci.c ha/drivers/ha/cpci/zia5083cpci.c --- linux/drivers/ha/cpci/zia5083cpci.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/cpci/zia5083cpci.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,475 @@ +/* + * zia5083cpci.c + * + * Ziatech zt5083 specific cPCI control routines. + * + * Author: MontaVista Software, Inc. + * tsa@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision History (most recent first) + * + */ +#include +#include +#include +#include +#include +#include +#include +#include "cpci_core.h" + +int zia5083cpci_early_config_bus(struct pci_controller *, int, int); +void zia5083cpci_find_driver(int); +struct pci_ops *pci_check_direct(void); +struct pci_ops *pci_find_bios(void); + +int ZT5550_init(void); + +extern struct pci_ops *pci_root_ops; + +#define ZIAHSC_BUS1_DEVFN PCI_DEVFN(0x08, 0) +#define ZIAHSC_BUS2_DEVFN PCI_DEVFN(0x0c, 0) +#define HSC_DEVFN PCI_DEVFN(0xb, 0) +#define AGP_DEVFN PCI_DEVFN(0x1, 0) +#define PIXX4_HB_DEVFN PCI_DEVFN(0x7, 0) + +#define ZIA_NUM_SLOTS 16 + +unsigned int ZiaIoSize[] = { + CONFIG_ZIA_5083_SLOT1_IO_SIZE, + CONFIG_ZIA_5083_SLOT2_IO_SIZE, + CONFIG_ZIA_5083_SLOT3_IO_SIZE, + CONFIG_ZIA_5083_SLOT4_IO_SIZE, + CONFIG_ZIA_5083_SLOT5_IO_SIZE, + CONFIG_ZIA_5083_SLOT6_IO_SIZE, + 0, 0, 0, 0, + CONFIG_ZIA_5083_SLOT11_IO_SIZE, + CONFIG_ZIA_5083_SLOT12_IO_SIZE, + CONFIG_ZIA_5083_SLOT13_IO_SIZE, + CONFIG_ZIA_5083_SLOT14_IO_SIZE, + CONFIG_ZIA_5083_SLOT15_IO_SIZE, + CONFIG_ZIA_5083_SLOT16_IO_SIZE, +}; + +unsigned int ZiaMemSize[] = { + CONFIG_ZIA_5083_SLOT1_MEM_SIZE, + CONFIG_ZIA_5083_SLOT2_MEM_SIZE, + CONFIG_ZIA_5083_SLOT3_MEM_SIZE, + CONFIG_ZIA_5083_SLOT4_MEM_SIZE, + CONFIG_ZIA_5083_SLOT5_MEM_SIZE, + CONFIG_ZIA_5083_SLOT6_MEM_SIZE, + 0, 0, 0, 0, + CONFIG_ZIA_5083_SLOT11_MEM_SIZE, + CONFIG_ZIA_5083_SLOT12_MEM_SIZE, + CONFIG_ZIA_5083_SLOT13_MEM_SIZE, + CONFIG_ZIA_5083_SLOT14_MEM_SIZE, + CONFIG_ZIA_5083_SLOT15_MEM_SIZE, + CONFIG_ZIA_5083_SLOT16_MEM_SIZE, +}; + +CpciNodeInfo ZiaBusInfo[] = { + {NULL, 0x0, 0x0, 0, 0, 0x07, 0x37, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x0, 0x0, 0, 0, 0x47, 0x77, 0x0, 0x0, 0x0, 0x0} +}; + +CpciNodeInfo ZiaSlotInfo[] = { + {NULL, 0X7, PCI_DEVFN(0xa,0), 0, 0, 0x08, 0x0f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xb,0), 0, 0, 0x10, 0x17, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xc,0), 0, 0, 0x18, 0x1f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xd,0), 0, 0, 0x20, 0x27, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xe,0), 0, 0, 0x28, 0x2f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x7, PCI_DEVFN(0xf,0), 0, 0, 0x30, 0x37, 0x0, 0x0, 0x0, 0x0}, + + {NULL, 0x0, 0x0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x0, 0x0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x0, 0x0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x0, 0x0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + + {NULL, 0x47, PCI_DEVFN(0xf,0), 0, 0, 0x48, 0x4f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x47, PCI_DEVFN(0xe,0), 0, 0, 0x50, 0x57, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x47, PCI_DEVFN(0xd,0), 0, 0, 0x58, 0x5f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x47, PCI_DEVFN(0xc,0), 0, 0, 0x60, 0x67, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x47, PCI_DEVFN(0xb,0), 0, 0, 0x68, 0x6f, 0x0, 0x0, 0x0, 0x0}, + {NULL, 0x47, PCI_DEVFN(0xa,0), 0, 0, 0x70, 0x77, 0x0, 0x0, 0x0, 0x0} +}; + +CpciInfo ZiaCpciInfo = {CPCI_CHASSIS_ZIA_5083, /* Chassis type */ + 2, /* Number of buses. */ + {0, 10}, /* Bus start slot numbers. */ + {5, 15} /* Bus end slot numbers. */ + }; + +static struct pci_controller* MainHose; + +unsigned char zia5083CpciIrqs[2][4]; + +#define PCI_LOWER_IO 0x1000 +#define PCI_UPPER_IO 0xf000 +#define PCI_LOWER_MEM 0x50000000 +#define PCI_UPPER_MEM 0xf4000000 +#define ISA_IO_BASE 0x0 +#define ISA_MEM_BASE 0x0 + +#define PCI_IO_CPCI_START 0x010000 +#define PCI_MEM_CPCI_START 0xe8000000 + +int +zia5083cpci_ignore_agp(struct pci_controller *hose, int bus, int devfn) +{ + return 0; +} + +struct pci_auto_addrs PciAddrs = { + PCI_LOWER_IO, PCI_UPPER_IO, PCI_LOWER_MEM, PCI_UPPER_MEM +}; + +/* + * Provide the find bridges functionality needed from the architecture + * specific boot code. Instead of the old method of using the firmware + * set value, do pci autoscan and with exceptions for the cPCI bridge chips. + */ +void __init +zia5083cpci_find_bridges(void) +{ + int loop; + unsigned char Pirq; + int LastIo; + int LastMem; + + printk("Initialize the PCI bridge tree for the Ziatech ZT5083 cPCI chassis\n"); + + MainHose = pciauto_alloc_controller(); + + if (!MainHose) + return; + + MainHose->first_busno = 0; + MainHose->last_busno = 0xff; + MainHose->pci_mem_offset = ISA_MEM_BASE; + MainHose->mem_space.start = PciAddrs.mem_start; + MainHose->mem_space.end = PciAddrs.mem_end; + MainHose->io_base_virt = (void *)ISA_IO_BASE; + MainHose->io_space.start = PciAddrs.io_start; + MainHose->io_space.end = PciAddrs.io_end; + MainHose->mem_resources[0].end = 0xffffffff; + + MainHose->ops = pci_root_ops; + MainHose->cfg_addr = (unsigned int *)NULL; /* Not used on intel arch */ + MainHose->cfg_data = (unsigned char *)NULL; + + /* Need to get the PIRQ values and set eny not initilaized */ + for (loop = 0; loop < 4; loop++) { + early_read_config_byte(MainHose, 0, PIXX4_HB_DEVFN, + 0x60 + loop, &Pirq); + + if (Pirq == 0x80) { + Pirq = 5; + early_write_config_byte(MainHose, 0, PIXX4_HB_DEVFN, + 0x60 + loop, Pirq); + } + + zia5083CpciIrqs[0][loop] = Pirq; + zia5083CpciIrqs[1][loop] = Pirq; + } + + + ZiaBusInfo[0].DevFn = ZIAHSC_BUS1_DEVFN; /* Bus A */ + ZiaBusInfo[1].DevFn = ZIAHSC_BUS2_DEVFN; /* Bus B */ + + /* Tell the cPCI core routines where the slot table exists. */ + CpciBuses = ZiaBusInfo; + CpciSlots = ZiaSlotInfo; + CpciInfos = &ZiaCpciInfo; + + /* Do not scan the cPCI bus bridges. Let the hot insert do that later */ + pci_excpt_setup_bridge_bdev(MainHose, 0, ZIAHSC_BUS1_DEVFN, + zia5083cpci_early_config_bus); + pci_excpt_setup_bridge_bdev(MainHose, 0, ZIAHSC_BUS2_DEVFN, + zia5083cpci_early_config_bus); + pci_excpt_setup_bridge_bdev(MainHose, 0, AGP_DEVFN, + zia5083cpci_ignore_agp); + + LastIo = PCI_IO_CPCI_START; + LastMem = PCI_MEM_CPCI_START; + + for (loop = ZIA_NUM_SLOTS - 1; loop > -1; loop--) { + ZiaSlotInfo[loop].IoEnd = LastIo; + LastIo -= ZiaIoSize[loop] * 1024; + + if (LastIo < PciAddrs.io_start) { + panic("PCI system has too much IO space allocated\n"); + } + + ZiaSlotInfo[loop].IoStart = LastIo; + + ZiaSlotInfo[loop].MemEnd = LastMem; + LastMem -= ZiaMemSize[loop] * 1024 * 1024; + + if (LastMem < PciAddrs.mem_start) { + panic("PCI system has too much Memory space allocated\n"); + } + + ZiaSlotInfo[loop].MemStart = LastMem; + } + + /* Set the bus start and end address based on the correct slot addresses */ + ZiaBusInfo[0].IoStart = ZiaSlotInfo[0].IoStart; + ZiaBusInfo[0].IoEnd = ZiaSlotInfo[5].IoEnd; + ZiaBusInfo[0].MemStart = ZiaSlotInfo[0].MemStart; + ZiaBusInfo[0].MemEnd = ZiaSlotInfo[5].MemEnd; + + ZiaBusInfo[1].IoStart = ZiaSlotInfo[10].IoStart; + ZiaBusInfo[1].IoEnd = ZiaSlotInfo[15].IoEnd; + ZiaBusInfo[1].MemStart = ZiaSlotInfo[10].MemStart; + ZiaBusInfo[1].MemEnd = ZiaSlotInfo[15].MemEnd; + + if ((pciauto_bus_scan(MainHose, MainHose->first_busno, + &PciAddrs)) == -1) { + panic("PCI system needs more than the available PCI address space\n"); + } + + MainHose->last_busno = ZiaBusInfo[1].LastBusNo; + + /* Set the host bridge to properly cover the whole pci address space. */ + PciAddrs.io_end = ZiaBusInfo[0].IoStart; + PciAddrs.mem_end = ZiaBusInfo[0].MemStart; + pciauto_postscan_setup_bridge(MainHose, 0, 0, ZiaBusInfo[1].LastBusNo, &PciAddrs); + + /* Recode the Hose info for each slot for later use. */ + ZiaBusInfo[0].Hose = MainHose; + ZiaBusInfo[1].Hose = MainHose; + + for (loop = 0; loop < ZIA_NUM_SLOTS; loop++) { + ZiaSlotInfo[loop].Hose = MainHose; + } +} + +/* + * This function is called from the pci autoscan routine when the cPCI + * bridges are found. + */ +int +zia5083cpci_early_config_bus(struct pci_controller *hose, int bus, int devfn) +{ + int ZiaBus; + int Slot; + int RetVal; + unsigned short Command; + + if (devfn == CpciBuses[0].DevFn) { + ZiaBus = 0; + } else { + ZiaBus = 1; + } + + CpciConfigCpciBridge(hose, bus, devfn, ZiaBus); + CpciBuses[ZiaBus].Allocated = 1; + + for (Slot = CpciInfos->StartSlotNum[ZiaBus]; + Slot <= CpciInfos->EndSlotNum[ZiaBus]; Slot++) { + if ((RetVal = CpciConfigSlot(Slot, MainHose, CpciBuses[ZiaBus].FirstBusNo)) < 0) { + if (RetVal == -ENOENT) { + /* Nothing in the slot. */ + continue; + } + + /* config problems on this slot so disable access */ + early_read_config_word(hose, + CpciBuses[ZiaBus].FirstBusNo, + CpciSlots[Slot].DevFn, + PCI_COMMAND, &Command); + Command &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + early_write_config_word(hose, + CpciBuses[ZiaBus].FirstBusNo, + CpciSlots[Slot].DevFn, + PCI_COMMAND, Command); + CpciSlots[Slot].Allocated = CPCI_SLOT_INSFAILED; + } + } + + return 0; +} + +void +zia5083routeNon0Irq(struct pci_dev *dev) +{ + struct pci_bus *TempBus = dev->bus; + unsigned int DevNum = PCI_SLOT(dev->devfn); + + while (TempBus->parent->primary != TempBus->parent->secondary) { + DevNum += PCI_SLOT((TempBus->self)->devfn); + TempBus = TempBus->parent; + } + + DevNum &= 0x03; + + if (dev->bus->number > CpciBuses[0].LastBusNo) { + if (ZiaBusInfo[0].DevFn == ZIAHSC_BUS1_DEVFN) { + dev->irq = zia5083CpciIrqs[1][DevNum]; + } else { + dev->irq = zia5083CpciIrqs[0][DevNum]; + } + } else { + if (ZiaBusInfo[0].DevFn == ZIAHSC_BUS1_DEVFN) { + dev->irq = zia5083CpciIrqs[0][DevNum]; + } else { + dev->irq = zia5083CpciIrqs[1][DevNum]; + } + } + + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (unsigned char)dev->irq); +} + +/* Prototypes Zia specific functions needed externally */ +//int zia5083hscAllocateAndInitBus(int); +//void zia5083hscDeallocateAndShutdownBus(int); +//int zia5083hscSetEnumMask(int, int); +//int zia5083hscCheckHealthy(int); + +static int +ReturnTrue1(int arg) +{ + return 1; +} + +static int +ReturnTrue2(int arg1, int arg2) +{ + return 1; +} + +static int +ReturnFalse(int arg) +{ + return 0; +} + +void Powerplus_Map_Non0(struct pci_dev *); + +/* This data structure contains the hardware dependent functions to + * provide functionality for independent code segments. + * */ +CpciFunc ZiaCpciFuncs = { + /* + zia5083hscAllocateAndInitBus, + zia5083hscDeallocateAndShutdownBus, + zia5083hscSetEnumMask, + zia5083hscCheckHealthy, + */ + ReturnTrue1, + ReturnTrue1, + ReturnTrue2, + ReturnTrue1, + zia5083routeNon0Irq +}; + +extern struct list_head pci_root_buses; +extern struct pci_controller* hose_head; + +void +zia5083cpci_init(void) +{ + struct pci_bus *HeadBus; +// int StatusBusA = 0, StatusBusB = 0; +// int delay_count; + + /* Initialize enum control. */ + ZT5550_init(); + + /* Export dependent function structure. */ + CpciFunctions = &ZiaCpciFuncs; + + /* Reset the hose and top level bus info to reality for HA numbers */ + hose_head->last_busno = CpciBuses[1].LastBusNo; + + HeadBus = pci_bus_b(pci_root_buses.next); + HeadBus->subordinate = CpciBuses[1].LastBusNo; + + /* For each bus, power on and connect each slot to the bus. At this + * time check to see if healthy has been set on the slot and + * set up the pci tree if it has. + */ + +// StatusBusA = zia5083hscAllocateAndInitBus(ZIAHSC_BUSA); +// StatusBusB = zia5083hscAllocateAndInitBus(ZIAHSC_BUSB); +// +// for (delay_count = 0; delay_count < 500; delay_count++) { +// udelay(10); +// } +// +// if (zia5083hscBusStatus(ZIAHSC_BUSA)) { +// if (StatusBusA) { +// /* This bus was just added */ +// CpciSetupBus(ZIAHSC_BUSA); +// } else { +// /* Bus was powered on at boot. Need to allert +// * system to download driver if needed. */ +// zia5083cpci_find_driver(ZIAHSC_BUSA); +// } +// } +// +// if (zia5083hscBusStatus(ZIAHSC_BUSB)) { +// if (StatusBusB) { +// /* This bus was just added */ +// CpciSetupBus(ZIAHSC_BUSB); +// } else { +// /* Bus was powered on at boot. Need to allert +// * system to download driver if needed. */ +// zia5083cpci_find_driver(ZIAHSC_BUSB); +// } +// } +} + +void +zia5083cpci_find_driver(int bus) +{ + struct pci_dev *Dev; + int Slot, LastSlot = -1, SlotSubDev = 0; + + pci_for_each_dev(Dev) { + if ((Dev->bus->number >= CpciBuses[bus].FirstBusNo) && + (Dev->bus->number <= CpciBuses[bus].LastBusNo)) { + + if ((Slot = CpciFindSlotFromDev(Dev)) < 0) { + continue; + } + + if ((Dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + continue; + } + + if (Slot != LastSlot) { + LastSlot = Slot; + SlotSubDev = 0; + } + + CpciFunctions->MapIrq(Dev); + Dev->cpci_location = (Slot << 16) | SlotSubDev++; + + CpciRegisterOpenCheck(Dev); + } + } +} diff -u -r --new-file linux/drivers/ha/event/Makefile ha/drivers/ha/event/Makefile --- linux/drivers/ha/event/Makefile Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/event/Makefile Thu Dec 13 13:03:13 2001 @@ -0,0 +1,15 @@ +# +# Makefile for the Eventing Mechanism implementation. +# + +O_TARGET := event.o + +obj-y := event_core.o user_api.o kernel_api.o debug.o +obj-m := +obj-n := +obj- := + +export-objs := event_core.o kernel_api.o + +include $(TOPDIR)/Rules.make + diff -u -r --new-file linux/drivers/ha/event/debug.c ha/drivers/ha/event/debug.c --- linux/drivers/ha/event/debug.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/event/debug.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,97 @@ +/* + * debug.c + * + * Routines used to debug various problems with the eventing mechanism. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "event_core.h" + +void +DumpClassList(void) +{ + int Hash; + KernelClassInfo *HashBase; + EventDestBase *EventBase; + EventDest *Dest; + + printk(" Dump Class List:\n"); + for (Hash = 0; Hash < NUM_EVENT_HASHES; Hash++) { + HashBase = &KernelClassHash[Hash]; + + while (HashBase->Next) { + printk(" 0x%x Hash %d Class %d Name \"%s\"\n", HashBase, Hash, + HashBase->Class, HashBase->ClassString); + + EventBase = HashBase->EventQ; + while (EventBase->Next != NULL) { + printk(" Event %d count %d\n", EventBase->Event, EventBase->UseCount); + + Dest = &EventBase->DestQ; + while (Dest->Next != NULL) { + printk(" User Id %d Priority %d Callback %p UserInfo %p KernelInfo %p\n", + Dest->Id, Dest->Pri, Dest->KernelCB, + Dest->UserInfo, Dest->KernelInfo); + Dest = Dest->Next; + } + + EventBase = EventBase->Next; + } + + HashBase = HashBase->Next; + } + } + + return; +} + +void +DumpUsersList(void) +{ + KernelUserInfo *TmpUser = KernelUsersHead; + + while (TmpUser) { + printk("Dumping users list\n"); + printk(" User %d is \"%s\"\n", TmpUser->Id, TmpUser->IdString); + TmpUser = TmpUser->Next; + } +} + diff -u -r --new-file linux/drivers/ha/event/event_core.c ha/drivers/ha/event/event_core.c --- linux/drivers/ha/event/event_core.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/event/event_core.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,858 @@ +/* + * event_core.c + * + * Core intialization and driver access routines for the eventing mechanism. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "event_core.h" + +#define MODVERSIONS + +/* Linux Driver prototypes. */ +static int event_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +static int event_open(struct inode *, struct file *); +static int event_release(struct inode *, struct file *); +static int event_fasync(int, struct file *, int); + +static struct file_operations event_fops = { + ioctl: event_ioctl, + open: event_open, + release: event_release, + fasync: event_fasync, +}; + +int EventUserSubscribeEventByType(UserEventInfo *, EventReq *); +int EventUserUnSubscribeEventByType(UserEventInfo *, EventReq *); +int EventUserSendEvent(UserEventInfo *, EventReq *); + +void EventFillFreeList(void); +EventPacket *EventAllocate(void); +spinlock_t EventAllocLock = SPIN_LOCK_UNLOCKED; + +KernelClassInfo KernelClassHash[NUM_EVENT_HASHES]; + +EventPacket *EventFreeList; + +int EventMajor; + +#ifdef CONFIG_PROC_FS +/* /proc entry routines. */ +static int EventUserReadProc(char *, char **, off_t, int); +static int EventEventsReadProc(char *, char **, off_t, int); + +struct proc_dir_entry *EventProcDir; +#endif + +int +event_init(void) +{ + int loop; + + printk("Initializing the eventing mechanism\n"); + + for (loop = 0; loop < NUM_EVENT_HASHES; loop++) { + KernelClassHash[loop].Lock = SPIN_LOCK_UNLOCKED; + KernelClassHash[loop].Next = NULL; + } + + /* Event packets will be often used and reused, To prevent memory + * fragmentation a bucket of them will be allocated 1 page memory + * usage at a time and placed on a free list. If the list gets empty + * a new bucket will be allocated in addition. + */ + EventFillFreeList(); + + if ((EventMajor = register_chrdev(0, "Event Manager", &event_fops)) < 0) { + printk("Cound not register the event manager\n"); + return -ENODEV; + } + +#ifdef CONFIG_PROC_FS + EventProcDir = proc_mkdir("events", NULL); + EventProcDir->owner = THIS_MODULE; + create_proc_info_entry("users", 0, EventProcDir, EventUserReadProc); + create_proc_info_entry("events", 0, EventProcDir, EventEventsReadProc); +#endif + return 0; +} + +/* Linux Driver prototypes. */ +static int +event_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + EventReq EventInfo; + UserEventInfo *UserInfo = (UserEventInfo *)file->private_data; + EventIdPacket EventId; + EventPacket Packet; + EventPacket *TmpPacket; + char *TmpString = NULL; + int RetVal; + void *FreeData; + + switch (cmd) { + case EVENT_REG_ID: + if (UserInfo->Id != 0) { + return -EBUSY; + } + + if (copy_from_user((int *)&EventId, (void *)arg, sizeof(EventIdPacket))) { + return -EFAULT; + } + + EventId.Id = EventRegisterId(EventId.IdString); + UserInfo->Id = EventId.Id; + + if (copy_to_user((void *)arg, (int *)&EventId, sizeof(EventIdPacket))) { + return -EFAULT; + } + return 0; + + case EVENT_UNREG_ID: + if (UserInfo->Id == 0) { + return -ENOENT; + } + + if (copy_from_user((int *)&EventId, (void *)arg, sizeof(EventIdPacket))) { + return -EFAULT; + } + + UserInfo->Id = 0; + return EventUnRegisterId(EventId.Id); + + case EVENT_GET_ID: + if (copy_from_user((int *)&EventId, (void *)arg, sizeof(EventIdPacket))) { + return -EFAULT; + } + + if ((EventId.Id = EventGetId(EventId.IdString)) < 0) { + return EventId.Id; + } + + if (copy_to_user((void *)arg, (int *)&EventId, sizeof(EventIdPacket))) { + return -EFAULT; + } + return 0; + + case EVENT_GET_ID_STRING: + if (copy_from_user((int *)&EventId, (void *)arg, sizeof(EventIdPacket))) { + return -EFAULT; + } + + if ((RetVal = EventGetIdString(EventId.Id, EventId.IdString)) <0) { + return RetVal; + } + + if (copy_to_user((void *)arg, (int *)&EventId, sizeof(EventIdPacket))) { + return -EFAULT; + } + return 0; + + case EVENT_REG_EVENT_CLASS: + if (copy_from_user((int *)&EventId, (void *)arg, sizeof(EventIdPacket))) { + return -EFAULT; + } + + if ((RetVal = EventRegisterEventClass(EventId.IdString, &EventId.Id)) == -ENOSPC) { + return RetVal; + } + + if (copy_to_user((void *)arg, (int *)&EventId, sizeof(EventIdPacket))) { + return -EFAULT; + } + return RetVal; + + case EVENT_UNREG_EVENT_CLASS: + return EventUnRegisterEventClass(arg); + + case EVENT_GET_EVENT_CLASS: + if (copy_from_user((int *)&EventId, (void *)arg, sizeof(EventIdPacket))) { + return -EFAULT; + } + + if ((EventId.Id = EventGetEventClass(EventId.IdString)) < 0) { + return EventId.Id; + } + + if (copy_to_user((void *)arg, (int *)&EventId, sizeof(EventIdPacket))) { + return -EFAULT; + } + return 0; + + case EVENT_GET_EVENT_CLASS_STRING: + if (copy_from_user((int *)&EventId, (void *)arg, sizeof(EventIdPacket))) { + return -EFAULT; + } + + if ((RetVal = EventGetEventClassString(EventId.Id, EventId.IdString)) < 0) { + return RetVal; + } + + if (copy_to_user((void *)arg, (int *)&EventId, sizeof(EventIdPacket))) { + return -EFAULT; + } + return 0; + + case EVENT_SUBSCRIBE_EVENT_BY_TYPE: + if (copy_from_user((int *)&EventInfo, (void *)arg, sizeof(EventReq))) { + return -EFAULT; + } + + return EventUserSubscribeEventByType(UserInfo, &EventInfo); + + case EVENT_UNSUBSCRIBE_EVENT_BY_TYPE: + if (copy_from_user((int *)&EventInfo, (void *)arg, sizeof(EventReq))) { + return -EFAULT; + } + + return EventUserUnSubscribeEventByType(UserInfo, &EventInfo); + + case EVENT_SUBSCRIBE_EVENT_BY_CLASS: + EventInfo.Id = UserInfo->Id; + EventInfo.Pri = 1; + EventInfo.Class = (int)arg; + EventInfo.Event = 0; + return EventUserSubscribeEventByType(UserInfo, &EventInfo); + + case EVENT_UNSUBSCRIBE_EVENT_BY_CLASS: + EventInfo.Id = UserInfo->Id; + EventInfo.Pri = 1; + EventInfo.Class = (int)arg; + EventInfo.Event = 0; + return EventUserUnSubscribeEventByType(UserInfo, &EventInfo); + + case EVENT_SEND_EVENT: + if (copy_from_user((int *)&Packet, (void *)arg, sizeof(EventPacket))) { + return -EFAULT; + } + + if ((Packet.DataLen != 0) && (Packet.Data != NULL)) { + TmpString = kmalloc(Packet.DataLen + 1, GFP_KERNEL); + + if (copy_from_user((int *)TmpString, (void *)Packet.Data, Packet.DataLen)) { + return -ENXIO; + } + } + + return EventSendEvent(Packet.Id, Packet.Pri, + Packet.Class, Packet.Event, + Packet.Info[0], Packet.Info[1], + Packet.Info[2], Packet.Info[3], + Packet.DataLen, TmpString); + + case EVENT_GET_EVENT: + if (copy_from_user((int *)&Packet, (void *)arg, sizeof(EventPacket))) { + return -EFAULT; + } + + /* While wait for event is indicated and this is a polled device. */ + do { + unsigned long flags; + + spin_lock_irqsave(&UserInfo->Lock, flags); + TmpPacket = UserInfo->Head; + + if (TmpPacket) { + if ((TmpPacket->DataLen != 0) && (TmpPacket->Data != NULL) && + (Packet.Data != NULL)) { + if (Packet.DataLen < TmpPacket->DataLen) { + TmpPacket->DataLen = Packet.DataLen; + } + + if (copy_to_user((void *)Packet.Data, (int *)TmpPacket->Data, + TmpPacket->DataLen)) { + spin_unlock_irqrestore(&UserInfo->Lock, flags); + return -ENXIO; + } + FreeData = TmpPacket->Data; + TmpPacket->Data = Packet.Data; + + kfree(FreeData); + } + + if (copy_to_user((void *)arg, (int *)TmpPacket, + sizeof(EventPacket))) { + spin_unlock_irqrestore(&UserInfo->Lock, flags); + return -EFAULT; + } + UserInfo->Head = TmpPacket->Next; + if (UserInfo->Head == NULL) { + UserInfo->Tail = NULL; + } + + spin_unlock_irqrestore(&UserInfo->Lock, flags); + EventFree(TmpPacket, 0); + return 0; + } + if (!Packet.Flag) { + spin_unlock_irqrestore(&UserInfo->Lock, flags); + return -EAGAIN; + } + + spin_unlock_irqrestore(&UserInfo->Lock, flags); + interruptible_sleep_on(&UserInfo->WaitQ); + spin_lock_irqsave(&UserInfo->Lock, flags); + + if (UserInfo->Head == NULL) { + spin_unlock_irqrestore(&UserInfo->Lock, flags); + return -EINTR; + } + } while (Packet.Flag); + default: + return -EINVAL; + } +} + +static int +event_open(struct inode *inode, struct file *file) +{ + UserEventInfo *UserInfo = (UserEventInfo *)kmalloc(sizeof(UserEventInfo), GFP_KERNEL); + + UserInfo->Id = 0; + UserInfo->Type = ED_USER_POLL; + init_waitqueue_head(&UserInfo->WaitQ); + UserInfo->FasyncPtr = (struct fasync_struct *)NULL; + UserInfo->Head = (EventPacket *)NULL; + UserInfo->Tail = (EventPacket *)NULL; + UserInfo->Lock = SPIN_LOCK_UNLOCKED; + + file->private_data = (void *)UserInfo; + return 0; +} + +static int +event_release(struct inode *inode, struct file *file) +{ + EventPacket *Tmp1EventPtr; + EventPacket *Tmp2EventPtr; + UserEventInfo *UserInfo = (UserEventInfo *)file->private_data; + + /* It the user had registered an ID then get his information + * out of the system. + */ + if (UserInfo->Id != 0) { + EventUnRegisterId(UserInfo->Id); + + /* Free any pending events scheduled for this user. */ + Tmp1EventPtr = UserInfo->Head; + while (Tmp1EventPtr) { + Tmp2EventPtr = Tmp1EventPtr; + Tmp1EventPtr = Tmp1EventPtr->Next; + EventFree(Tmp2EventPtr, 1); + } + } + + /* Make him gone. */ + kfree(UserInfo); + return 0; +} + +static int +event_fasync(int fd, struct file *fp, int on) +{ + unsigned long flags; + UserEventInfo *UserInfo = (UserEventInfo *)fp->private_data; + + spin_lock_irqsave(&UserInfo->Lock, flags); + fasync_helper(fd, fp, on, &UserInfo->FasyncPtr); + + if (on) { + UserInfo->Type = ED_USER_ASYNC; + } else { + UserInfo->Type = ED_USER_POLL; + } + + spin_unlock_irqrestore(&UserInfo->Lock, flags); + return 0; +} + +#ifdef CONFIG_PROC_FS +static int +EventUserReadProc(char * buf, char ** start, off_t offset, int len) +{ + char *Page = buf; + KernelUserInfo *TmpUser; + unsigned long flags; + + read_lock_irqsave(&KernelUsersLock, flags); + TmpUser = KernelUsersHead; + Page += sprintf(Page, "\nEvent Users List\n"); + Page += sprintf(Page, "------------------------------\n"); + while (TmpUser) { + Page += sprintf(Page, "%3d: %s\n", TmpUser->Id, TmpUser->IdString); + TmpUser = TmpUser->Next; + } + + read_unlock_irqrestore(&KernelUsersLock, flags); + Page += sprintf(Page, "\n"); + + return (int)(Page - buf); +} + +static int +EventEventsReadProc(char * buf, char ** start, off_t offset, int len) +{ + int Hash; + KernelClassInfo *HashBase; + EventDestBase *EventBase; + EventDest *Dest; + EventPacket *Packet; + char *Page = buf; + char Scratch[64]; + + Page += sprintf(Page, "\nDump Class List:\n"); + Page += sprintf(Page, "------------------------------\n"); + for (Hash = 0; Hash < NUM_EVENT_HASHES; Hash++) { + HashBase = &KernelClassHash[Hash]; + + while (HashBase->Next) { + Page += sprintf(Page, "Class %d Name \"%s\" Use %d\n", + HashBase->Class, HashBase->ClassString, + HashBase->UseCount); + + EventBase = HashBase->EventQ; + while (EventBase->Next != NULL) { + Page += sprintf(Page, " Event %d count %d\n", + EventBase->Event, EventBase->UseCount); + + Dest = &EventBase->DestQ; + while (Dest->Next != NULL) { + EventGetIdString(Dest->Id, Scratch); + Page += sprintf(Page, " User %d \"%s\" Priority %d ", + Dest->Id, Scratch, Dest->Pri); + + if (Dest->UserInfo) { + Page += sprintf(Page, "User Application\n"); + Packet = Dest->UserInfo->Head; + + while (Packet) { + Page += sprintf(Page, "Sender %d info 0x%x:0x%x:0x%x:0x%x data len %d\n", + Packet->Id, Packet->Info[0], Packet->Info[1], Packet->Info[2], Packet->Info[3], Packet->DataLen); + } + } else if (Dest->KernelCB) { + Page += sprintf(Page, "Kernel Call Back\n"); + } else { + Page += sprintf(Page, "Kernel Queued\n"); + Packet = Dest->KernelInfo->Head; + + while (Packet) { + Page += sprintf(Page, "Sender %d info 0x%x:0x%x:0x%x:0x%x data len %d\n", + Packet->Id, Packet->Info[0], Packet->Info[1], Packet->Info[2], Packet->Info[3], Packet->DataLen); + } + } + + Dest = Dest->Next; + } + + EventBase = EventBase->Next; + } + + HashBase = HashBase->Next; + } + } + return (int)(Page - buf); +} +#endif + +void +EventFillFreeList(void) +{ + int loop; + EventPacket *TmpBase; + + EventFreeList = kmalloc(4096, GFP_KERNEL); + TmpBase = EventFreeList; + + for (loop = 0; loop < (4096 / sizeof(EventPacket))-1; loop++) { + TmpBase->Event = 0; + TmpBase->Class = 0; + TmpBase->TimeStamp.tv_sec = 0; + TmpBase->TimeStamp.tv_usec = 0; + TmpBase->Info[0] = 0; + TmpBase->Info[1] = 0; + TmpBase->Info[2] = 0; + TmpBase->Info[3] = 0; + TmpBase->Pri = 0; + TmpBase->DataLen = 0; + TmpBase->Data = NULL; + TmpBase->Next = TmpBase + 1; + TmpBase++; + } + TmpBase->Event = 0; + TmpBase->Class = 0; + TmpBase->TimeStamp.tv_sec = 0; + TmpBase->TimeStamp.tv_usec = 0; + TmpBase->Info[0] = 0; + TmpBase->Info[1] = 0; + TmpBase->Info[2] = 0; + TmpBase->Info[3] = 0; + TmpBase->Pri = 0; + TmpBase->DataLen = 0; + TmpBase->Data = NULL; + TmpBase->Next = NULL; +} + +EventPacket * +EventAllocate(void) +{ + EventPacket *TmpBase; + + spin_lock(&EventAllocLock); + TmpBase = EventFreeList; + if ((TmpBase = kmalloc(sizeof(EventPacket), GFP_KERNEL)) != NULL) { + /* Still enough memory to not worry about using it. */ + TmpBase->Flag = 0; + spin_unlock(&EventAllocLock); + return TmpBase; + } + + /* Get a packet from the reserved list. */ + TmpBase = EventFreeList; + EventFreeList = EventFreeList->Next; + TmpBase->Flag = EF_EMERGENCY_PACKET; + + if (EventFreeList == NULL) { + EventFillFreeList(); + } + + spin_unlock(&EventAllocLock); + return TmpBase; +} + +void +EventFree(EventPacket *eventPtr, int flag) +{ + unsigned long flags; + + spin_lock_irqsave(&EventAllocLock, flags); + if (flag && (eventPtr->DataLen > 0) && (eventPtr->Data != NULL)) { + kfree(eventPtr->Data); + } + + if (eventPtr->Flag & EF_EMERGENCY_PACKET) { + eventPtr->Next = EventFreeList; + EventFreeList = eventPtr; + } else { + kfree(eventPtr); + } + + spin_unlock_irqrestore(&EventAllocLock, flags); + return; +} + +void +EventGenEvent(int id, int pri, int class, int event, + int info0, int info1, int info2, int info3, + EventDest *EventDestP, int dataLen, void *data) +{ + EventPacket *Packet; + EventPacket *TmpPacket; + EventPacket *EndPacket; + + Packet = EventAllocate(); + + Packet->Id = id; + Packet->Pri = pri; + Packet->Class = class; + Packet->Event = event; + do_gettimeofday(&Packet->TimeStamp); + Packet->Info[0] = info0; + Packet->Info[1] = info1; + Packet->Info[2] = info2; + Packet->Info[3] = info3; + Packet->DataLen = dataLen; + + if ((dataLen != 0) && (data != NULL)) { + if ((Packet->Data = kmalloc(dataLen + 1, GFP_KERNEL)) == NULL) { + Packet->DataLen = 0; + Packet->Data = NULL; + Packet->Flag |= EF_DATA_FAILURE; + } else { + strncpy(Packet->Data, data, dataLen); + Packet->Flag |= EF_DATA_AVAIL; + } + } else { + Packet->Data = NULL; + Packet->Flag &= ~(EF_DATA_AVAIL|EF_DATA_FAILURE); + } + + if (EventDestP->UserInfo == NULL) { + /* Queue in kernel */ + spin_lock(&EventDestP->KernelInfo->Lock); + TmpPacket = EventDestP->KernelInfo->Head; + EndPacket = EventDestP->KernelInfo->Tail; + + if ((TmpPacket == NULL) || (TmpPacket->Pri < pri)) { + /* Goes to head of the list. */ + Packet->Next = TmpPacket; + EventDestP->KernelInfo->Head = Packet; + } else if (EndPacket->Pri >= pri) { + /* Place on tail of list */ + EndPacket->Next = Packet; + Packet->Next = NULL; + EventDestP->KernelInfo->Tail = Packet; + } else { + /* Got to find the middle somewhere. */ + while (TmpPacket) { + if (TmpPacket->Pri > pri) { + Packet->Next = TmpPacket->Next; + TmpPacket->Next = Packet; + break; + } + TmpPacket = TmpPacket->Next; + } + } + + wake_up_interruptible(&EventDestP->KernelInfo->WaitQ); + spin_unlock(&EventDestP->KernelInfo->Lock); + return; + } + + /* Send up to a processes */ + spin_lock(&EventDestP->UserInfo->Lock); + TmpPacket = EventDestP->UserInfo->Head; + EndPacket = EventDestP->UserInfo->Tail; + + if ((TmpPacket == NULL) || (TmpPacket->Pri < pri)) { + /* Goes to head of the list. */ + Packet->Next = TmpPacket; + EventDestP->UserInfo->Head = Packet; + EventDestP->UserInfo->Tail = Packet; + } else if (EndPacket->Pri >= pri) { + /* Place on tail of list */ + EndPacket->Next = Packet; + Packet->Next = NULL; + EventDestP->UserInfo->Tail = Packet; + } else { + /* Got to find the middle somewhere. */ + while (TmpPacket) { + if (TmpPacket->Pri > pri) { + Packet->Next = TmpPacket->Next; + TmpPacket->Next = Packet; + break; + } + TmpPacket = TmpPacket->Next; + } + } + + /* First check to see if this is polled file descriptor. */ + if (EventDestP->UserInfo->Type == ED_USER_POLL) { + wake_up_interruptible(&EventDestP->UserInfo->WaitQ); + return; + } + + wake_up_interruptible(&EventDestP->UserInfo->WaitQ); + kill_fasync(&EventDestP->UserInfo->FasyncPtr, SIGIO, POLL_IN); + spin_unlock(&EventDestP->UserInfo->Lock); + return; +} + +int +EventSendEvent(int id, int pri, int class, int event, + int info0, int info1, int info2, int info3, + int dataLen, void *data) +{ + EventDest *EventDestP = NULL; + EventDestBase *EventBase; + int EventTakers = 0; + unsigned long flags; + int Hash = class % NUM_EVENT_HASHES; + KernelClassInfo *HashBase = &KernelClassHash[Hash]; + + read_lock_irqsave(&KernelUsersLock, flags); + if (EventCheckId(id) == NULL) { + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ENOENT; + } + + spin_lock(&HashBase->Lock); + + /* Find the top level entry for this class of events. */ + if ((EventBase = EventFindEventBase(class, HashBase)) == NULL) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -EINVAL; + } + + while (EventBase->Next != NULL) { + if ((EventBase->Event != event) && + (EventBase->Event != 0)) { + EventBase = EventBase->Next; + continue; + } + + EventDestP = &EventBase->DestQ; + + while (EventDestP->Next != NULL) { + EventTakers++; + if (EventDestP->KernelCB != NULL) { + if ((*EventDestP->KernelCB)(id, pri, class, + event, info0, info1, info2, info3, + dataLen, data) == 0) { + kfree(data); + } + } else { + EventGenEvent(id, pri, class, event, + info0, info1, info2, info3, + EventDestP, dataLen, data); + } + + EventDestP = EventDestP->Next; + } + + EventBase = EventBase->Next; + } + + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + + if (EventTakers) { + return 0; + } + + return -ENXIO; +} + +EventDestBase * +EventFindEventBase(int class, KernelClassInfo *HashBase) +{ + /* Find the top level entry for this class of events. */ + while(HashBase->Next != NULL) { + if (HashBase->Class == class) { + break; + } + HashBase = HashBase->Next; + } + + while(HashBase->Next == NULL) { + return NULL; + } + + return HashBase->EventQ; +} + +void +EventUnReqAllEventsByClass(int id, EventDestBase *EventBase) +{ + EventDest *EventDestP = NULL; + EventDest *FreeDest = NULL; + EventDestBase *SaveBase = EventBase; + EventDestBase *LastEventBase = NULL; + + /* Search all event types in this class. */ + while (EventBase->Next != NULL) { + EventDestP = &EventBase->DestQ; + + /* Search the chain of destinations for this user. */ + while (EventDestP->Next->Next != NULL) { + if (EventDestP->Next->Id == id) { + FreeDest = EventDestP->Next; + EventDestP->Next = EventDestP->Next->Next; + EventBase->UseCount--; + kfree(FreeDest); + } else { + EventDestP = EventDestP->Next; + } + } + + /* Reset the top pointer */ + EventDestP = &EventBase->DestQ; + + /* Top element treated special. */ + if (EventDestP->Id == id) { + EventDestP->UserInfo = EventDestP->Next->UserInfo; + EventDestP->KernelCB = EventDestP->Next->KernelCB; + EventDestP->Id = EventDestP->Next->Id; + EventDestP->KernelInfo = EventDestP->Next->KernelInfo; + FreeDest = EventDestP->Next; + EventDestP->Next = EventDestP->Next->Next; + EventBase->UseCount--; + + kfree(FreeDest); + } + + if (EventBase->UseCount == 0) { + if (EventBase == SaveBase) { + /* Free the top element */ + EventBase->Event = EventBase->Next->Event; + EventBase->UseCount = EventBase->Next->UseCount; + EventBase->DestQ = EventBase->Next->DestQ; + LastEventBase = EventBase->Next; + EventBase->Next = LastEventBase->Next; + kfree(LastEventBase); + } else { + LastEventBase->Next = EventBase->Next; + kfree(EventBase); + EventBase = LastEventBase->Next; + } + } else { + /* Go to the next event type. */ + LastEventBase = EventBase; + EventBase = EventBase->Next; + } + } + + return; +} + +void +EventUnReqAllEvents(int id) +{ + int hash; + KernelClassInfo *HashBase; + + for (hash = 0; hash < NUM_EVENT_HASHES; hash++) { + HashBase = &KernelClassHash[hash]; + + spin_lock(&HashBase->Lock); + while(HashBase->Next != NULL) { + EventUnReqAllEventsByClass(id, HashBase->EventQ); + HashBase = HashBase->Next; + } + spin_unlock(&HashBase->Lock); + } + + return; +} + +EXPORT_SYMBOL(EventFree); +EXPORT_SYMBOL(EventSendEvent); diff -u -r --new-file linux/drivers/ha/event/event_core.h ha/drivers/ha/event/event_core.h --- linux/drivers/ha/event/event_core.h Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/event/event_core.h Thu Dec 13 13:03:13 2001 @@ -0,0 +1,103 @@ +/* + * event_core.h + * + * Data structures and values needed internaly for the eventing mechanism. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef EVENT_CORE_H +#define EVENT_CORE_H + +/* Currently know types of event accesses. */ +#define ED_USER_ASYNC 1 +#define ED_USER_POLL 2 + + +typedef struct kernel_user_info { + int Id; + char IdString[16]; + wait_queue_head_t WaitQ; + EventPacket *Head; + EventPacket *Tail; + spinlock_t Lock; + struct kernel_user_info *Next; +} KernelUserInfo; + +typedef struct user_event_info { + int Type; + int Id; + wait_queue_head_t WaitQ; + struct fasync_struct *FasyncPtr; + EventPacket *Head; + EventPacket *Tail; + spinlock_t Lock; +} UserEventInfo; + +typedef struct event_destination { + int Pri; + int Id; + int (*KernelCB)(int, int, int, int, int, int, int, int, int, void *); + UserEventInfo *UserInfo; + KernelUserInfo *KernelInfo; + struct event_destination *Next; +} EventDest; + +typedef struct event_destination_base { + int Event; + int UseCount; + EventDest DestQ; + struct event_destination_base *Next; +} EventDestBase; + +typedef struct kernel_class_info { + int Class; + char ClassString[16]; + int UseCount; + EventDestBase *EventQ; + spinlock_t Lock; + struct kernel_class_info *Next; +} KernelClassInfo; + +/* Kernel uses for the Flag in KernelEventPacket. */ +#define EF_EMERGENCY_PACKET 0x1 + +#define NUM_EVENT_HASHES 10 +extern KernelClassInfo KernelClassHash[NUM_EVENT_HASHES]; +extern KernelUserInfo *KernelClassHead; +extern KernelUserInfo *KernelUsersHead; + +extern rwlock_t KernelUsersLock; + +EventDestBase * EventFindEventBase(int class, KernelClassInfo *); +KernelUserInfo *EventCheckId(int); +void EventUnReqAllEvents(int); + +/* Debug routines. */ +void DumpEventReg(void); +void DumpClassList(void); +#endif /* EVENT_CORE_H */ diff -u -r --new-file linux/drivers/ha/event/kernel_api.c ha/drivers/ha/event/kernel_api.c --- linux/drivers/ha/event/kernel_api.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/event/kernel_api.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,690 @@ +/* + * kernel_api.c + * + * Interface routines for the eventing mechasism made available to + * other kernel code. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "event_core.h" + +#define MODVERSIONS + +int _EventGetEventClass(char *); + +KernelUserInfo *KernelUsersHead = NULL; +unsigned int KernelNextId = 1; /* Just so its not zero. */ +rwlock_t KernelUsersLock = RW_LOCK_UNLOCKED; + +KernelUserInfo *KernelClassHead = NULL; +KernelUserInfo *KernelClassTail = NULL; +unsigned int KernelNextClass = 1; /* Just so its not zero. */ +spinlock_t ClassSearchLock = SPIN_LOCK_UNLOCKED; + +/* + * This is sort of equivelent to the user level open call. + */ +int +EventRegisterId(char *idstring) +{ + KernelUserInfo *TmpUser; + unsigned long flags; + + write_lock_irqsave(&KernelUsersLock, flags); + + if (KernelUsersHead == NULL) { + if ((KernelUsersHead = kmalloc(sizeof(KernelUserInfo), GFP_KERNEL)) == NULL) { + /* System is in immenent danger of dying at this point. */ + write_unlock_irqrestore(&KernelUsersLock, flags); + return -ENOSPC; + } + TmpUser = KernelUsersHead; + } else { + TmpUser = KernelUsersHead; + + while (TmpUser->Next) { + TmpUser = TmpUser->Next; + } + if ((TmpUser->Next = kmalloc(sizeof(KernelUserInfo), GFP_KERNEL)) == NULL) { + /* System is in immenent danger of dying at this point. */ + write_unlock_irqrestore(&KernelUsersLock, flags); + return -ENOSPC; + } + TmpUser = TmpUser->Next; + } + + TmpUser->Id = KernelNextId++; + strncpy(TmpUser->IdString, idstring, 16); + init_waitqueue_head(&TmpUser->WaitQ); + TmpUser->Head = NULL; + TmpUser->Tail = NULL; + TmpUser->Next = NULL; + TmpUser->Lock = SPIN_LOCK_UNLOCKED; + + write_unlock_irqrestore(&KernelUsersLock, flags); + + return TmpUser->Id; +} + +int +EventUnRegisterId(int id) +{ + KernelUserInfo *TmpUser; + KernelUserInfo *FreeUser; + unsigned long flags; + + write_lock_irqsave(&KernelUsersLock, flags); + + if (KernelUsersHead == NULL) { + write_unlock_irqrestore(&KernelUsersLock, flags); + return -ENOENT; + } + + if (KernelUsersHead->Id == id) { + FreeUser = KernelUsersHead; + KernelUsersHead = KernelUsersHead->Next; + + spin_lock(&FreeUser->Lock); + write_unlock(&KernelUsersLock); + EventUnReqAllEvents(id); + spin_unlock_irqrestore(&FreeUser->Lock, flags); + + kfree(FreeUser); + + return 0; + } + + TmpUser = KernelUsersHead; + + while(TmpUser->Next) { + if (TmpUser->Next->Id == id) { + FreeUser = TmpUser->Next; + TmpUser->Next = FreeUser->Next; + + spin_lock(&FreeUser->Lock); + write_unlock(&KernelUsersLock); + EventUnReqAllEvents(id); + spin_unlock_irqrestore(&FreeUser->Lock, flags); + + kfree(FreeUser); + + return 0; + } + TmpUser = TmpUser->Next; + } + + write_unlock_irqrestore(&KernelUsersLock, flags); + return -ESRCH; +} + +int +EventGetId(char *idstring) +{ + KernelUserInfo *TmpUser; + unsigned long flags; + + read_lock_irqsave(&KernelUsersLock, flags); + TmpUser = KernelUsersHead; + + while (TmpUser) { + if (!strcmp(TmpUser->IdString, idstring)) { + read_unlock_irqrestore(&KernelUsersLock, flags); + return TmpUser->Id; + } + TmpUser = TmpUser->Next; + } + + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ESRCH; +} + +int +EventGetIdString(int id, char *idstring) +{ + KernelUserInfo *TmpUser; + unsigned long flags; + + read_lock_irqsave(&KernelUsersLock, flags); + TmpUser = KernelUsersHead; + + while (TmpUser) { + if (TmpUser->Id == id) { + strncpy(idstring, TmpUser->IdString, 16); + read_unlock_irqrestore(&KernelUsersLock, flags); + return 0; + } + TmpUser = TmpUser->Next; + } + + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ESRCH; +} + +KernelUserInfo * +EventCheckId(int id) +{ + KernelUserInfo *TmpUser; + + TmpUser = KernelUsersHead; + + while (TmpUser) { + if (TmpUser->Id == id) { + return TmpUser; + } + TmpUser = TmpUser->Next; + } + + return NULL; +} + +int +EventFillInHashInfo(KernelClassInfo *HashBase, char *classString, int *class) +{ + HashBase->Class = KernelNextClass++; + strncpy(HashBase->ClassString, classString, 16); + + if ((HashBase->EventQ = kmalloc(sizeof(EventDestBase), GFP_KERNEL)) == NULL) { + return -ENOSPC; + } + + HashBase->EventQ->Next = NULL; + + if ((HashBase->Next = kmalloc(sizeof(KernelClassInfo), GFP_KERNEL)) == NULL) { + kfree(HashBase->EventQ); + HashBase->EventQ = NULL; + return -ENOSPC; + } + + HashBase->Next->Next = NULL; + HashBase->UseCount = 0; + + *class = HashBase->Class; + return 0; +} + +int +EventRegisterEventClass(char *classString, int *class) +{ + int RetVal; + unsigned long flags; + int Hash = KernelNextClass % NUM_EVENT_HASHES; + KernelClassInfo *HashBase = &KernelClassHash[Hash]; + + spin_lock_irqsave(&ClassSearchLock, flags); + /* First search all classes to find out if it already exists */ + if ((*class = _EventGetEventClass(classString)) > 0) { + spin_unlock_irqrestore(&ClassSearchLock, flags); + return -EBUSY; + } + + spin_lock(&HashBase->Lock); + + while (HashBase->Next != NULL) { + HashBase = HashBase->Next; + } + + RetVal = EventFillInHashInfo(HashBase, classString, class); + spin_unlock(&HashBase->Lock); + spin_unlock_irqrestore(&ClassSearchLock, flags); + return RetVal; +} + +int +EventUnRegisterEventClass(int class) +{ + unsigned long flags; + int Hash = class % NUM_EVENT_HASHES; + KernelClassInfo *HashBase = &KernelClassHash[Hash]; + KernelClassInfo* HashDel; + + spin_lock_irqsave(&ClassSearchLock, flags); + if (HashBase->Next == NULL) { + spin_unlock_irqrestore(&ClassSearchLock, flags); + return -ESRCH; + } + + spin_lock(&HashBase->Lock); + + if (HashBase->Class == class) { + if (HashBase->UseCount != 0) { + spin_unlock(&HashBase->Lock); + spin_unlock_irqrestore(&ClassSearchLock, flags); + return -EBUSY; + } + + HashDel = HashBase->Next; + + goto EventDelHashInfo; + } + + HashDel = HashBase->Next; + + while(HashDel->Next != NULL) { + if (HashDel->Class == class) { + break; + } + HashBase = HashDel; + HashDel = HashDel->Next; + } + + if (HashDel->Next == NULL) { + spin_unlock(&HashBase->Lock); + spin_unlock_irqrestore(&ClassSearchLock, flags); + return -ESRCH; + } + + if (HashDel->UseCount != 0) { + spin_unlock(&HashBase->Lock); + spin_unlock_irqrestore(&ClassSearchLock, flags); + return -EBUSY; + } + + +EventDelHashInfo: + kfree(HashBase->EventQ); + + HashBase->Class = HashDel->Class; + strncpy(HashBase->ClassString, HashDel->ClassString, 16); + HashBase->EventQ = HashDel->EventQ; + HashBase->Next = HashDel->Next; + HashBase->UseCount--; + + kfree(HashDel); + spin_unlock(&HashBase->Lock); + spin_unlock_irqrestore(&ClassSearchLock, flags); + return 0; +} + +int +EventGetEventClass(char *classString) +{ + int RetVal; + unsigned long flags; + + spin_lock_irqsave(&ClassSearchLock, flags); + RetVal = _EventGetEventClass(classString); + spin_unlock_irqrestore(&ClassSearchLock, flags); + return RetVal; +} + +int +_EventGetEventClass(char *classString) +{ + int Hash; + unsigned long flags; + KernelClassInfo *HashBase; + + for (Hash = 0; Hash < NUM_EVENT_HASHES; Hash++) { + HashBase = &KernelClassHash[Hash]; + + spin_lock_irqsave(&HashBase->Lock, flags); + while (HashBase->Next) { + if (!strcmp(HashBase->ClassString, classString)) { + spin_unlock_irqrestore(&HashBase->Lock, flags); + return HashBase->Class; + } + HashBase = HashBase->Next; + } + spin_unlock_irqrestore(&HashBase->Lock, flags); + } + + return -ESRCH; +} + +int +EventGetEventClassString(int class, char *classString) +{ + int Hash = class % NUM_EVENT_HASHES; + KernelClassInfo *HashBase = &KernelClassHash[Hash]; + unsigned long flags; + + spin_lock_irqsave(&HashBase->Lock, flags); + while (HashBase->Next) { + if (HashBase->Class == class) { + strncpy(classString, HashBase->ClassString, 16); + spin_unlock_irqrestore(&HashBase->Lock, flags); + return 0; + } + HashBase = HashBase->Next; + } + + spin_unlock_irqrestore(&HashBase->Lock, flags); + return -ESRCH; +} + +int +EventSubscribeEventByType(int id, int pri, int class, int event, + int (*kernelCB)(int, int, int, int, int, int, int, int, int, void *)) +{ + EventDest *EventDestP = NULL; + EventDest *TmpDestP = NULL; + EventDest *LastEventDestP = NULL; + EventDestBase *EventBase; + KernelUserInfo *EventUser; + int Hash = class % NUM_EVENT_HASHES; + KernelClassInfo *HashBase = &KernelClassHash[Hash]; + unsigned long flags; + + read_lock_irqsave(&KernelUsersLock, flags); + if ((EventUser = EventCheckId(id)) == NULL) { + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ESRCH; + } + + spin_lock(&HashBase->Lock); + + /* Find the top level entry for this class of events. */ + if ((EventBase = EventFindEventBase(class, HashBase)) == NULL) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -EINVAL; + } + + /* search until the event is found in this catagory or until the + * last blank element on the list if found. + */ + while (EventBase->Next != NULL) { + if (EventBase->Event == event) { + EventDestP = &EventBase->DestQ; + break; + } + EventBase = EventBase->Next; + } + + /* If not destination pointer has been identified for a chain + * search then this event type has not yet been registered by anybody + * so fill in the last empty list element and create a new empty one + * to inidcate end of list. + */ + if (EventDestP == NULL) { + EventBase->Event = event; + EventBase->UseCount = 0; + + /* Create the next empty element to indicate end of list. */ + if ((EventBase->Next = kmalloc(sizeof(EventDestBase), GFP_KERNEL)) == NULL) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ENOSPC; + } + + EventBase->Next->Next = NULL; + + EventDestP = &EventBase->DestQ; + EventDestP->Next = NULL; + + goto EventFillInKernelRequestPacket; + } + + /* Now search to see if this file descriptor already has registered + * for this event type. + */ + while (EventDestP->Next != NULL) { + if (EventDestP->Id == id) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -EBUSY; + + } + + LastEventDestP = EventDestP; + EventDestP = EventDestP->Next; + } + + /* Now record the destination and create a new empty element to + * indicate end of list. + */ + + /* Most registrations go at the end of the list. */ + if ((LastEventDestP != NULL) && (LastEventDestP->Pri >= pri)) { + if ((EventDestP->Next = kmalloc(sizeof(EventDest), GFP_KERNEL)) == NULL) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ENOSPC; + } + + EventDestP->Next->Next = NULL; + goto EventFillInKernelRequestPacket; + } + + EventDestP = &EventBase->DestQ; + + /* Check the priority against the top element */ + if (EventDestP->Pri >= pri) { + /* Priority of event places it somewhere in the middle */ + while (EventDestP->Next->Pri >= pri) { + EventDestP = EventDestP->Next; + } + } + + if ((TmpDestP = kmalloc(sizeof(EventDest), GFP_KERNEL)) == NULL) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ENOSPC; + } + + TmpDestP->Pri = EventDestP->Pri; + TmpDestP->UserInfo = EventDestP->UserInfo; + TmpDestP->KernelCB = EventDestP->KernelCB; + TmpDestP->Id = EventDestP->Id; + TmpDestP->KernelInfo = EventDestP->KernelInfo; + TmpDestP->Next = EventDestP->Next; + EventDestP->Next = TmpDestP; + +EventFillInKernelRequestPacket: + EventBase->UseCount++; + EventDestP->Pri = pri; + EventDestP->UserInfo = NULL; + EventDestP->Id = id; + EventDestP->KernelCB = kernelCB; + EventDestP->KernelInfo = EventUser; + + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return 0; +} + +int +EventUnSubscribeEventByType(int id, int class, int event) +{ + EventDest *EventDestP = NULL; + EventDest *FreeDest = NULL; + EventDestBase *EventBase; + EventDestBase *LastEventBase = NULL; + KernelUserInfo *EventUser; + int Hash = class % NUM_EVENT_HASHES; + KernelClassInfo *HashBase = &KernelClassHash[Hash]; + unsigned long flags; + + read_lock_irqsave(&KernelUsersLock, flags); + if ((EventUser = EventCheckId(id)) == NULL) { + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ENOENT; + } + + spin_lock_irqsave(&HashBase->Lock, flags); + + /* Find the top level entry for this class of events. */ + if ((EventBase = EventFindEventBase(class, HashBase)) == NULL) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -EINVAL; + } + + /* search until the event is found in this catagory or until the + * last blank element on the list if found. + */ + while (EventBase->Next != NULL) { + if (EventBase->Event == event) { + EventDestP = &EventBase->DestQ; + break; + } + + LastEventBase = EventBase; + EventBase = EventBase->Next; + } + + /* If event type not found then the user process was obviously not + * registered for this event. + */ + if (EventDestP == NULL) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ESRCH; + } + + if (EventDestP->Id == id) { + EventDestP->UserInfo = EventDestP->Next->UserInfo; + EventDestP->KernelCB = EventDestP->Next->KernelCB; + EventDestP->Id = EventDestP->Next->Id; + EventDestP->KernelInfo = EventDestP->Next->KernelInfo; + FreeDest = EventDestP->Next; + EventDestP->Next = EventDestP->Next->Next; + + goto EventUnRegFreeBase; + } + + /* Allways search one ahead to help with single link list removal. */ + while (EventDestP->Next->Next != NULL) { + if (EventDestP->Next->Id == id) { + FreeDest = EventDestP->Next; + EventDestP->Next = EventDestP->Next->Next; + + goto EventUnRegFreeBase; + } + EventDestP = EventDestP->Next; + } + + /* Entry not found in list. */ + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ESRCH; + +EventUnRegFreeBase: + EventBase->UseCount--; + + if (EventBase->UseCount == 0) { + /* Nobody is registered to receive this event. */ + if (LastEventBase == NULL) { + /* Free the top element */ + EventBase->Event = EventBase->Next->Event; + EventBase->UseCount = EventBase->Next->UseCount; + EventBase->DestQ = EventBase->Next->DestQ; + LastEventBase = EventBase->Next; + EventBase->Next = LastEventBase->Next; + kfree(LastEventBase); + } else { + LastEventBase->Next = EventBase->Next; + kfree(EventBase); + } + } + + kfree(FreeDest); + + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return 0; +} + +int +EventSubscribeEventByClass(int id, int pri, int class, + int (*kernelCB)(int, int, int, int, int, int, int, int, int, void *)) +{ + return EventSubscribeEventByType(id, pri, class, 0, kernelCB); +} + +int +EventUnSubscribeEventByClass(int id, int class) +{ + return EventUnSubscribeEventByType(id, class, 0); +} + +int +EventGetEvent(int id, int waitFlag, EventPacket *packet) +{ + EventPacket *TmpPacket; + KernelUserInfo *EventUser; + unsigned long flags; + + for (;;) { + read_lock_irqsave(&KernelUsersLock, flags); + if ((EventUser = EventCheckId(id)) == NULL) { + read_unlock_irqrestore(&KernelUsersLock, flags); + packet = NULL; + return -ENOENT; + } + + spin_lock(&EventUser->Lock); + read_unlock(&KernelUsersLock); + TmpPacket = EventUser->Head; + + if (TmpPacket) { + EventUser->Head = TmpPacket->Next; + if (EventUser->Head == NULL) { + EventUser->Tail = NULL; + } + spin_unlock_irqrestore(&EventUser->Lock, flags); + packet = TmpPacket; + return 0; + } + + if (!waitFlag) { + spin_unlock_irqrestore(&EventUser->Lock, flags); + packet = NULL; + return -EAGAIN; + } + + spin_unlock_irqrestore(&EventUser->Lock, flags); + interruptible_sleep_on(&EventUser->WaitQ); + } +} + +EXPORT_SYMBOL(EventRegisterId); +EXPORT_SYMBOL(EventUnRegisterId); +EXPORT_SYMBOL(EventGetId); +EXPORT_SYMBOL(EventRegisterEventClass); +EXPORT_SYMBOL(EventUnRegisterEventClass); +EXPORT_SYMBOL(EventGetEventClass); +EXPORT_SYMBOL(EventGetEventClassString); +EXPORT_SYMBOL(EventSubscribeEventByType); +EXPORT_SYMBOL(EventUnSubscribeEventByType); +EXPORT_SYMBOL(EventSubscribeEventByClass); +EXPORT_SYMBOL(EventUnSubscribeEventByClass); +EXPORT_SYMBOL(EventGetEvent); diff -u -r --new-file linux/drivers/ha/event/user_api.c ha/drivers/ha/event/user_api.c --- linux/drivers/ha/event/user_api.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/ha/event/user_api.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,261 @@ +/* + * user_api.c + * + * User process interface routines for the eventing mechanism. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "event_core.h" + +int +EventUserSubscribeEventByType(UserEventInfo* userInfo, EventReq *eventInfo) +{ + EventDest *EventDestP = NULL; + EventDest *TmpDestP = NULL; + EventDest *LastEventDestP = NULL; + EventDestBase *EventBase; + int Hash = eventInfo->Class % NUM_EVENT_HASHES; + KernelClassInfo *HashBase = &KernelClassHash[Hash]; + unsigned long flags; + + read_lock_irqsave(&KernelUsersLock, flags); + if (EventCheckId(eventInfo->Id) == NULL) { + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ENOENT; + } + + spin_lock(&HashBase->Lock); + + /* Find the top level entry for this class of events. */ + if ((EventBase = EventFindEventBase(eventInfo->Class, HashBase)) == NULL) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ESRCH; + } + + /* search until the event is found in this catagory or until the + * last blank element on the list if found. + */ + while (EventBase->Next != NULL) { + if (EventBase->Event == eventInfo->Event) { + EventDestP = &EventBase->DestQ; + break; + } + EventBase = EventBase->Next; + } + + /* If not destination pointer has been identified for a chain + * search then this event type has not yet been registered by anybody + * so fill in the last empty list element and create a new empty one + * to inidcate end of list. + */ + if (EventDestP == NULL) { + EventBase->Event = eventInfo->Event; + EventBase->UseCount = 0; + + /* Create the next empty element to indicate end of list. */ + EventBase->Next = kmalloc(sizeof(EventDestBase), GFP_KERNEL); + EventBase->Next->Next = NULL; + + EventDestP = &EventBase->DestQ; + EventDestP->Next = kmalloc(sizeof(EventDest), GFP_KERNEL); + EventDestP->Next->Next = NULL; + + goto EventFillInRequestPacket; + } + + /* Now search to see if this file descriptor already has registered + * for this event type. + */ + while (EventDestP->Next != NULL) { + if (EventDestP->Id == eventInfo->Id) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -EBUSY; + } + LastEventDestP = EventDestP; + EventDestP = EventDestP->Next; + } + + /* Now record the destination and create a new empty element to + * indicate end of list. + */ + + /* Most registrations go at the end of the list. */ + if ((LastEventDestP != NULL) && (LastEventDestP->Pri >= eventInfo->Pri)) { + EventDestP->Next = kmalloc(sizeof(EventDest), GFP_KERNEL); + EventDestP->Next->Next = NULL; + goto EventFillInRequestPacket; + } + + /* Check the priority against the top element */ + EventDestP = &EventBase->DestQ; + if (eventInfo->Pri <= EventDestP->Pri) { + /* Priority of event places it somewhere in the middle */ + while (EventDestP->Next->Pri >= eventInfo->Pri) { + EventDestP = EventDestP->Next; + } + } + + TmpDestP = kmalloc(sizeof(EventDest), GFP_KERNEL); + TmpDestP->Pri = EventDestP->Pri; + TmpDestP->UserInfo = EventDestP->UserInfo; + TmpDestP->KernelCB = EventDestP->KernelCB; + TmpDestP->Id = EventDestP->Id; + TmpDestP->KernelInfo = EventDestP->KernelInfo; + TmpDestP->Next = EventDestP->Next; + EventDestP->Next = TmpDestP; + +EventFillInRequestPacket: + EventBase->UseCount++; + EventDestP->Pri = eventInfo->Pri; + EventDestP->UserInfo = userInfo; + EventDestP->KernelCB = NULL; + EventDestP->Id = userInfo->Id; + EventDestP->KernelInfo = NULL; + + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return 0; +} + +int +EventUserUnSubscribeEventByType(UserEventInfo* userInfo, EventReq *eventInfo) +{ + EventDest *EventDestP = NULL; + EventDest *FreeDest = NULL; + EventDestBase *EventBase; + EventDestBase *LastEventBase = NULL; + int Hash = eventInfo->Class % NUM_EVENT_HASHES; + KernelClassInfo *HashBase = &KernelClassHash[Hash]; + unsigned long flags; + + read_lock_irqsave(&KernelUsersLock, flags); + if (EventCheckId(eventInfo->Id) == NULL) { + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ENOENT; + } + + spin_lock(&HashBase->Lock); + + /* Find the top level entry for this class of events. */ + if ((EventBase = EventFindEventBase(eventInfo->Class, HashBase)) == NULL) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ESRCH; + } + + /* search until the event is found in this catagory or until the + * last blank element on the list if found. + */ + while (EventBase->Next != NULL) { + if (EventBase->Event == eventInfo->Event) { + EventDestP = &EventBase->DestQ; + break; + } + + LastEventBase = EventBase; + EventBase = EventBase->Next; + } + + /* If event type not found then the user process was obviously not + * registered for this event. + */ + if (EventDestP == NULL) { + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ESRCH; + } + + /* Check the top element first */ + if (EventDestP->Id == eventInfo->Id) { + EventDestP->UserInfo = EventDestP->Next->UserInfo; + EventDestP->KernelCB = EventDestP->Next->KernelCB; + EventDestP->Id = EventDestP->Next->Id; + EventDestP->KernelInfo = EventDestP->Next->KernelInfo; + FreeDest = EventDestP->Next; + EventDestP->Next = EventDestP->Next->Next; + + goto EventUnRegFreeBase; + } + + /* Allways search one ahead to help with single link list removal. */ + while (EventDestP->Next->Next != NULL) { + if (EventDestP->Next->Id == eventInfo->Id) { + FreeDest = EventDestP->Next; + EventDestP->Next = EventDestP->Next->Next; + + goto EventUnRegFreeBase; + } + EventDestP = EventDestP->Next; + } + + /* Entry not found in list. */ + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return -ESRCH; + +EventUnRegFreeBase: + EventBase->UseCount--; + + if (EventBase->UseCount == 0) { + /* Nobody is registered to receive this event. */ + if (LastEventBase == NULL) { + /* Free the top element */ + EventBase->Event = EventBase->Next->Event; + EventBase->UseCount = EventBase->Next->UseCount; + EventBase->DestQ = EventBase->Next->DestQ; + LastEventBase = EventBase->Next; + EventBase->Next = LastEventBase->Next; + kfree(LastEventBase); + } else { + LastEventBase->Next = EventBase->Next; + kfree(EventBase); + } + } + + kfree(FreeDest); + + spin_unlock(&HashBase->Lock); + read_unlock_irqrestore(&KernelUsersLock, flags); + return 0; +} diff -u -r --new-file linux/drivers/net/Config.in ha/drivers/net/Config.in --- linux/drivers/net/Config.in Mon Nov 19 16:19:42 2001 +++ ha/drivers/net/Config.in Thu Dec 13 13:03:13 2001 @@ -160,6 +160,7 @@ dep_tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT $CONFIG_ISA dep_tristate ' CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA dep_tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI + dep_mbool ' Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO $CONFIG_TULIP if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then dep_bool ' New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL bool ' Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO diff -u -r --new-file linux/drivers/net/eepro100.c ha/drivers/net/eepro100.c --- linux/drivers/net/eepro100.c Mon Nov 12 10:47:18 2001 +++ ha/drivers/net/eepro100.c Thu Dec 13 13:03:13 2001 @@ -625,6 +625,7 @@ else goto err_out_iounmap; + CpciRegisterDevice(pdev); return 0; err_out_iounmap: ; @@ -2258,6 +2259,8 @@ sp->tx_ring, sp->tx_ring_dma); pci_disable_device(pdev); kfree(dev); + + CpciUnRegisterDevice(pdev); } static struct pci_device_id eepro100_pci_tbl[] __devinitdata = { diff -u -r --new-file linux/drivers/net/tulip/tulip_core.c ha/drivers/net/tulip/tulip_core.c --- linux/drivers/net/tulip/tulip_core.c Mon Nov 19 16:19:42 2001 +++ ha/drivers/net/tulip/tulip_core.c Thu Dec 13 13:03:13 2001 @@ -1801,6 +1801,7 @@ /* put the chip in snooze mode until opened */ tulip_set_power_state (tp, 0, 1); + CpciRegisterDevice(pdev); return 0; err_out_free_ring: @@ -1879,6 +1880,9 @@ #endif kfree (dev); pci_release_regions (pdev); + + CpciUnRegisterDevice(pdev); + pci_set_drvdata (pdev, NULL); /* pci_power_off (pdev, -1); */ diff -u -r --new-file linux/drivers/pci/Makefile ha/drivers/pci/Makefile --- linux/drivers/pci/Makefile Sun Sep 9 10:50:48 2001 +++ ha/drivers/pci/Makefile Thu Dec 13 13:03:13 2001 @@ -30,6 +30,7 @@ obj-$(CONFIG_ALL_PPC) += setup-bus.o obj-$(CONFIG_DDB5476) += setup-bus.o obj-$(CONFIG_SGI_IP27) += setup-irq.o +obj-$(CONFIG_CPCI_HOTSWAP) += pci_auto.o ifndef CONFIG_X86 obj-y += syscall.o diff -u -r --new-file linux/drivers/pci/pci.c ha/drivers/pci/pci.c --- linux/drivers/pci/pci.c Tue Nov 20 22:53:29 2001 +++ ha/drivers/pci/pci.c Thu Dec 13 13:03:13 2001 @@ -538,7 +538,11 @@ * Registration of PCI drivers and handling of hot-pluggable devices. */ +#ifdef CONFIG_CPCI_HOTSWAP +LIST_HEAD(pci_drivers); +#else static LIST_HEAD(pci_drivers); +#endif /** * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure @@ -564,7 +568,7 @@ return NULL; } -static int +int pci_announce_device(struct pci_driver *drv, struct pci_dev *dev) { const struct pci_device_id *id; @@ -936,7 +940,9 @@ (((unsigned long) ~sz) << 32); #else if (l) { +#ifndef CONFIG_CPCI_HOTSWAP printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name); +#endif res->start = 0; res->flags = 0; continue; @@ -1003,7 +1009,9 @@ * Ugh. We don't know enough about this bridge. Just assume * that it's entirely transparent. */ +#ifndef CONFIG_CPCI_HOTSWAP printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0); +#endif child->resource[0] = child->parent->resource[0]; } @@ -1019,7 +1027,9 @@ res->name = child->name; } else { /* See comment above. Same thing */ +#ifndef CONFIG_CPCI_HOTSWAP printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1); +#endif child->resource[1] = child->parent->resource[1]; } @@ -1038,7 +1048,9 @@ limit |= ((long) mem_limit_hi) << 32; #else if (mem_base_hi || mem_limit_hi) { +#ifndef CONFIG_CPCI_HOTSWAP printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name); +#endif return; } #endif @@ -1050,7 +1062,9 @@ res->name = child->name; } else { /* See comments above */ +#ifndef CONFIG_CPCI_HOTSWAP printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2); +#endif child->resource[2] = child->parent->resource[2]; } } @@ -1111,6 +1125,11 @@ * already configured by the BIOS and after we are done with all of * them, we proceed to assigning numbers to the remaining buses in * order to avoid overlaps between old and new bus numbers. + * + * For hotswap there is a new consideration. Due to resource limitations (namely + * Intel legacy hardware often has a limit of 64k for PCI IO space) the bridge + * may be disabled by turning off the IO, MEM and BUS MASTER bits in the command + * register. In this case simple do not create entries for this bridge. */ static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass) { @@ -1187,7 +1206,7 @@ * Read interrupt line and base address registers. * The architecture-dependent code can tweak these, of course. */ -static void pci_read_irq(struct pci_dev *dev) +void pci_read_irq(struct pci_dev *dev) { unsigned char irq; @@ -1341,6 +1360,9 @@ unsigned int devfn, max, pass; struct list_head *ln; struct pci_dev *dev, dev0; +#ifdef CONFIG_CPCI_HOTSWAP + unsigned short Command; +#endif DBG("Scanning bus %02x\n", bus->number); max = bus->secondary; @@ -1353,6 +1375,13 @@ /* Go find them, Rover! */ for (devfn = 0; devfn < 0x100; devfn += 8) { dev0.devfn = devfn; +#ifdef CONFIG_CPCI_HOTSWAP + pci_read_config_word(&dev0, PCI_COMMAND, &Command); + if ((Command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER)) == 0) { + continue; + } +#endif pci_scan_slot(&dev0); } diff -u -r --new-file linux/drivers/pci/pci_auto.c ha/drivers/pci/pci_auto.c --- linux/drivers/pci/pci_auto.c Wed Dec 31 17:00:00 1969 +++ ha/drivers/pci/pci_auto.c Thu Dec 13 13:03:13 2001 @@ -0,0 +1,555 @@ +/* + * arch/ppc/kernel/pci_auto.c + * + * PCI autoconfiguration library + * + * Author: Matt Porter + * Johnnie Peters + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +struct pci_controller* hose_head; +struct pci_controller** hose_tail = &hose_head; + +struct pci_exception exception_list[64]; +int pci_next_exception = 0; + +void +pciauto_excpt_exclude_bdev(int bus, int devfn) +{ + exception_list[pci_next_exception].type = PCI_EXCPT_SKIP_DEV; + exception_list[pci_next_exception].val1 = (void *)bus; + exception_list[pci_next_exception].val2 = (void *)devfn; + pci_next_exception++; + return; +} + +void +pci_excpt_setup_bridge_bdev(struct pci_controller *hose, int bus, int devfn, + int(*func)(struct pci_controller *, int, int)) +{ + exception_list[pci_next_exception].type = PCI_EXCPT_SETUP_BRIDGE_DEV; + exception_list[pci_next_exception].val1 = (void *)hose; + exception_list[pci_next_exception].val2 = (void *)bus; + exception_list[pci_next_exception].val3 = (void *)devfn; + exception_list[pci_next_exception].val4 = (void *)func; + pci_next_exception++; + return; +} + +void +pci_excpt_setup_device_bdev(struct pci_controller *hose, int bus, int devfn, + int(*func)(struct pci_controller *, int, int)) +{ + exception_list[pci_next_exception].type = PCI_EXCPT_SETUP_DEVICE_DEV; + exception_list[pci_next_exception].val1 = (void *)hose; + exception_list[pci_next_exception].val2 = (void *)bus; + exception_list[pci_next_exception].val3 = (void *)devfn; + exception_list[pci_next_exception].val4 = (void *)func; + pci_next_exception++; + return; +} + +int +pciauto_exception_check_exclude(struct pci_controller *hose, int bus, int devfn) +{ + int loop; + + for (loop = 0; loop < pci_next_exception; loop++) { + switch (exception_list[loop].type) { + case PCI_EXCPT_SKIP_DEV: + if ((bus == (int)exception_list[loop].val1) && + (devfn == (int)exception_list[loop].val2)) { + return PCI_EXCPT_IGNORE; + } + break; + case PCI_EXCPT_SETUP_BRIDGE_DEV: + case PCI_EXCPT_SETUP_BRIDGE_TYPE: + continue; + default: + continue; + } + + } + return 0; +} + +void * +pciauto_exception_check_device(struct pci_controller *hose, int bus, int devfn) +{ + int loop; + int(*func)(struct pci_controller *, int, int); + + for (loop = 0; loop < pci_next_exception; loop++) { + switch (exception_list[loop].type) { + case PCI_EXCPT_SETUP_DEVICE_DEV: + if ((hose == (struct pci_controller *) + exception_list[loop].val1) && + (bus == (int)exception_list[loop].val2) && + (devfn == (int)exception_list[loop].val3)) { + func = (int(*)(struct pci_controller *, int, int)) exception_list[loop].val4; + return func; + } + case PCI_EXCPT_SETUP_DEVICE_TYPE: + continue; + default: + continue; + } + + } + return NULL; +} + +void * +pciauto_exception_check_bridge(struct pci_controller *hose, int bus, int devfn) +{ + int loop; + int(*func)(struct pci_controller *, int, int); + + for (loop = 0; loop < pci_next_exception; loop++) { + switch (exception_list[loop].type) { + case PCI_EXCPT_SETUP_BRIDGE_DEV: + if ((hose == (struct pci_controller *) + exception_list[loop].val1) && + (bus == (int)exception_list[loop].val2) && + (devfn == (int)exception_list[loop].val3)) { + func = (int(*)(struct pci_controller *, int, int)) exception_list[loop].val4; + return func; + } + case PCI_EXCPT_SETUP_BRIDGE_TYPE: + continue; + default: + continue; + } + + } + return NULL; +} + +int pciauto_setup_bars(struct pci_controller *hose, + int current_bus, + int pci_devfn, + struct pci_auto_addrs *pci_addrs) +{ + unsigned int bar_response, bar_size, bar_value; + int bar, bar_nr = 0; + unsigned int addr_mask; + unsigned int * upper_limit; + unsigned int * lower_limit; + int found_mem64 = 0; + + DBG("PCI Autoconfig: Found Bus 0x%x, Device 0x%x, Function %d\n", + current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) ); + + for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar+=4) + { + /* Tickle the BAR and get the response */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0xffffffff); + early_read_config_dword(hose, + current_bus, + pci_devfn, + bar, + &bar_response); + + /* If BAR is not implemented go to the next BAR */ + if (!bar_response) + continue; + + /* Check the BAR type and set our address mask */ + if (bar_response & PCI_BASE_ADDRESS_SPACE) + { + addr_mask = PCI_BASE_ADDRESS_IO_MASK; + upper_limit = &pci_addrs->io_end; + lower_limit = &pci_addrs->io_start; + DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr); + } + else + { + if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + addr_mask = PCI_BASE_ADDRESS_MEM_MASK; + upper_limit = &pci_addrs->mem_end; + lower_limit = &pci_addrs->mem_start; + DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr); + } + + /* Calculate requested size */ + bar_size = ~(bar_response & addr_mask) + 1; + + /* This is probably a hack but seems to be neccessary on + * the only Intel processor based machine I have to test + * on. + */ + if (bar_size < 128) + bar_size = 128; + + /* Allocate a base address */ + bar_value = (*upper_limit - bar_size) & ~(bar_size - 1); + + if (bar_value < *lower_limit) { + return -1; + } + + /* Write it out and update our limit */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + bar_value); + + *upper_limit = bar_value; + + /* + * If we are a 64-bit decoder then increment to the + * upper 32 bits of the bar and force it to locate + * in the lower 4GB of memory. + */ + if (found_mem64) + { + bar += 4; + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0x00000000); + } + + bar_nr++; + + DBG("size=0x%x, address=0x%x\n", + bar_size, bar_value); + } + return 0; +} + +void pciauto_prescan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + struct pci_auto_addrs *pci_addrs) +{ + unsigned short bridgestat; + int cmdstat; + + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_PRIMARY_BUS, + current_bus); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SECONDARY_BUS, + sub_bus); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + 0xff); + + /* Round memory allocator to 1MB boundary */ + pci_addrs->mem_end &= ~(0x100000 - 1); + + /* Round I/O allocator to 4KB boundary */ + pci_addrs->io_end &= ~(0x1000 - 1); + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_LIMIT, + ((pci_addrs->mem_end - 1) & 0xfff00000) >> 16); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT, + ((pci_addrs->io_end - 1) & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT_UPPER16, + ((pci_addrs->io_end - 1) & 0xffff0000) >> 16); + + /* We don't support prefetchable memory for now, so disable */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_BASE, + 0x1000); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_LIMIT, + 0x1000); + + /* Disable Io and Mem space before messing with the BARs */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat & + ~(PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER)); + + /* Disable ISA I/O port translation. This may need to become + * a configurable parameter in the future as some machines may + * require this. + */ + early_read_config_word(hose, + current_bus, + pci_devfn, + PCI_BRIDGE_CONTROL, + &bridgestat); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_BRIDGE_CONTROL, + bridgestat & ~PCI_BRIDGE_CTL_NO_ISA); +} + +void pciauto_postscan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + struct pci_auto_addrs *pci_addrs) +{ + int cmdstat; + + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + sub_bus); + + /* Round memory allocator to 1MB boundary */ + pci_addrs->mem_end &= ~(0x100000 - 1); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_BASE, + pci_addrs->mem_end >> 16); + + /* Round I/O allocator to 4KB boundary */ + pci_addrs->io_end &= ~(0x1000 - 1); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_BASE, + (pci_addrs->io_end & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_BASE_UPPER16, + pci_addrs->io_end >> 16); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +int pciauto_bus_scan(struct pci_controller *hose, int current_bus, + struct pci_auto_addrs *pci_addrs) +{ + int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0; + unsigned short vid; + unsigned char header_type; + int(*func)(struct pci_controller *, int, int); + + sub_bus = current_bus; + + for (pci_devfn=0; pci_devfn<0xff; pci_devfn++) + { + /* Skip our host bridge */ + if (hose && (current_bus == hose->first_busno) && (pci_devfn == 0) ) + continue; + + if (PCI_FUNC(pci_devfn) && !found_multi) + continue; + + early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_HEADER_TYPE, + &header_type); + + if (!PCI_FUNC(pci_devfn)) + found_multi = header_type & 0x80; + + early_read_config_word(hose, + current_bus, + pci_devfn, + PCI_VENDOR_ID, + &vid); + + if (vid != 0xffff) + { + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_CLASS_REVISION, &pci_class); + + if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) + { + DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn)); + if ((func = pciauto_exception_check_bridge( + hose, current_bus, pci_devfn))) { + (*func)(hose, current_bus, pci_devfn); + continue; + } + + pciauto_prescan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus+1, + pci_addrs); + + if ((sub_bus = pciauto_bus_scan(hose, + sub_bus+1, pci_addrs)) == -1) { + return -1; + } + + pciauto_postscan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + pci_addrs); + } + else + { + + if ((func = pciauto_exception_check_device( + hose, current_bus, pci_devfn))) { + (*func)(hose, current_bus, pci_devfn); + continue; + } + + if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) + { + unsigned char prg_iface; + + early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_CLASS_PROG, + &prg_iface); + if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) + { + DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n"); + continue; + } + } + /* Disable Io and Mem before messing with + * the BARS. + */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat & + ~(PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER)); + + /* Allocate PCI I/O and/or memory space */ + if (pciauto_setup_bars(hose, + current_bus, + pci_devfn, + pci_addrs)) { + return -1; + } + + /* + * Found a peripheral, enable some standard + * settings + */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_LATENCY_TIMER, + 0x80); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_CACHE_LINE_SIZE, + 0x0); + } + } + } + return sub_bus; +} + +struct pci_controller * +pciauto_alloc_controller(void) +{ + struct pci_controller *hose; + + hose = (struct pci_controller *)kmalloc(sizeof(*hose), GFP_KERNEL); + memset(hose, 0, sizeof(struct pci_controller)); + + *hose_tail = hose; + hose_tail = &hose->next; + + return hose; +} diff -u -r --new-file linux/drivers/pci/quirks.c ha/drivers/pci/quirks.c --- linux/drivers/pci/quirks.c Sun Nov 11 11:09:33 2001 +++ ha/drivers/pci/quirks.c Thu Dec 13 13:03:13 2001 @@ -23,7 +23,7 @@ /* Deal with broken BIOS'es that neglect to enable passive release, which can cause problems in combination with the 82441FX/PPro MTRRs */ -static void __init quirk_passive_release(struct pci_dev *dev) +static void __devinit quirk_passive_release(struct pci_dev *dev) { struct pci_dev *d = NULL; unsigned char dlc; @@ -50,7 +50,7 @@ int isa_dma_bridge_buggy; /* Exported */ -static void __init quirk_isa_dma_hangs(struct pci_dev *dev) +static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev) { if (!isa_dma_bridge_buggy) { isa_dma_bridge_buggy=1; @@ -64,7 +64,7 @@ * Chipsets where PCI->PCI transfers vanish or hang */ -static void __init quirk_nopcipci(struct pci_dev *dev) +static void __devinit quirk_nopcipci(struct pci_dev *dev) { if((pci_pci_problems&PCIPCI_FAIL)==0) { @@ -77,7 +77,7 @@ * Triton requires workarounds to be used by the drivers */ -static void __init quirk_triton(struct pci_dev *dev) +static void __devinit quirk_triton(struct pci_dev *dev) { if((pci_pci_problems&PCIPCI_TRITON)==0) { @@ -96,7 +96,7 @@ * Updated based on further information from the site and also on * information provided by VIA */ -static void __init quirk_vialatency(struct pci_dev *dev) +static void __devinit quirk_vialatency(struct pci_dev *dev) { struct pci_dev *p; u8 rev; @@ -150,7 +150,7 @@ * VIA Apollo VP3 needs ETBF on BT848/878 */ -static void __init quirk_viaetbf(struct pci_dev *dev) +static void __devinit quirk_viaetbf(struct pci_dev *dev) { if((pci_pci_problems&PCIPCI_VIAETBF)==0) { @@ -158,7 +158,7 @@ pci_pci_problems|=PCIPCI_VIAETBF; } } -static void __init quirk_vsfx(struct pci_dev *dev) +static void __devinit quirk_vsfx(struct pci_dev *dev) { if((pci_pci_problems&PCIPCI_VSFX)==0) { @@ -173,7 +173,7 @@ * at least */ -static void __init quirk_natoma(struct pci_dev *dev) +static void __devinit quirk_natoma(struct pci_dev *dev) { if((pci_pci_problems&PCIPCI_NATOMA)==0) { @@ -187,7 +187,7 @@ * If it's needed, re-allocate the region. */ -static void __init quirk_s3_64M(struct pci_dev *dev) +static void __devinit quirk_s3_64M(struct pci_dev *dev) { struct resource *r = &dev->resource[0]; @@ -197,7 +197,7 @@ } } -static void __init quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr) +static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr) { region &= ~(size-1); if (region) { @@ -222,7 +222,7 @@ * 0xE0 (64 bytes of ACPI registers) * 0xE2 (32 bytes of SMB registers) */ -static void __init quirk_ali7101_acpi(struct pci_dev *dev) +static void __devinit quirk_ali7101_acpi(struct pci_dev *dev) { u16 region; @@ -237,7 +237,7 @@ * 0x40 (64 bytes of ACPI registers) * 0x90 (32 bytes of SMB registers) */ -static void __init quirk_piix4_acpi(struct pci_dev *dev) +static void __devinit quirk_piix4_acpi(struct pci_dev *dev) { u32 region; @@ -251,7 +251,7 @@ * VIA ACPI: One IO region pointed to by longword at * 0x48 or 0x20 (256 bytes of ACPI registers) */ -static void __init quirk_vt82c586_acpi(struct pci_dev *dev) +static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev) { u8 rev; u32 region; @@ -270,7 +270,7 @@ * 0x70 (128 bytes of hardware monitoring register) * 0x90 (16 bytes of SMB registers) */ -static void __init quirk_vt82c686_acpi(struct pci_dev *dev) +static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev) { u16 hm; u32 smb; @@ -297,7 +297,7 @@ * TODO: When we have device-specific interrupt routers, * this code will go away from quirks. */ -static void __init quirk_via_ioapic(struct pci_dev *dev) +static void __devinit quirk_via_ioapic(struct pci_dev *dev) { u8 tmp; @@ -338,7 +338,7 @@ * value of the ACPI SCI interrupt is only done for convenience. * -jgarzik */ -static void __init quirk_via_acpi(struct pci_dev *d) +static void __devinit quirk_via_acpi(struct pci_dev *d) { /* * VIA ACPI device: SCI IRQ line in PCI config byte 0x42 @@ -350,7 +350,7 @@ d->irq = irq; } -static void __init quirk_via_irqpic(struct pci_dev *dev) +static void __devinit quirk_via_irqpic(struct pci_dev *dev) { u8 irq, new_irq = dev->irq & 0xf; @@ -377,7 +377,7 @@ * * We mask out all r/wc bits, too. */ -static void __init quirk_piix3_usb(struct pci_dev *dev) +static void __devinit quirk_piix3_usb(struct pci_dev *dev) { u16 legsup; @@ -392,7 +392,7 @@ * We need to switch it off to be able to recognize the real * type of the chip. */ -static void __init quirk_vt82c598_id(struct pci_dev *dev) +static void __devinit quirk_vt82c598_id(struct pci_dev *dev) { pci_write_config_byte(dev, 0xfc, 0); pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device); @@ -404,7 +404,7 @@ * do this even if the Linux CardBus driver is not loaded, because * the Linux i82365 driver does not (and should not) handle CardBus. */ -static void __init quirk_cardbus_legacy(struct pci_dev *dev) +static void __devinit quirk_cardbus_legacy(struct pci_dev *dev) { if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class) return; @@ -421,7 +421,7 @@ * of course. However the advice is demonstrably good even if so.. */ -static void __init quirk_amd_ioapic(struct pci_dev *dev) +static void __devinit quirk_amd_ioapic(struct pci_dev *dev) { u8 rev; @@ -441,7 +441,7 @@ * who turn it off! */ -static void __init quirk_amd_ordering(struct pci_dev *dev) +static void __devinit quirk_amd_ordering(struct pci_dev *dev) { u32 pcic; @@ -458,7 +458,7 @@ * The main table of quirks. */ -static struct pci_fixup pci_fixups[] __initdata = { +static struct pci_fixup pci_fixups[] __devinitdata = { { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release }, /* diff -u -r --new-file linux/include/asm-i386/pci-bridge.h ha/include/asm-i386/pci-bridge.h --- linux/include/asm-i386/pci-bridge.h Wed Dec 31 17:00:00 1969 +++ ha/include/asm-i386/pci-bridge.h Thu Dec 13 13:25:22 2001 @@ -0,0 +1,67 @@ +/* + */ +#ifdef __KERNEL__ +#ifndef _ASM_PCI_BRIDGE_H +#define _ASM_PCI_BRIDGE_H + +#include +#include + +struct device_node; +struct pci_controller; + +/* + * Structure of a PCI controller (host bridge) + */ +struct pci_controller { + int index; /* used for pci_controller_num */ + struct pci_controller *next; + struct pci_bus *bus; + void *arch_data; + + int first_busno; + int last_busno; + int bus_offset; + + void *io_base_virt; + unsigned long io_base_phys; + + /* Some machines (PReP) have a non 1:1 mapping of + * the PCI memory space in the CPU bus space + */ + unsigned long pci_mem_offset; + + struct pci_ops *ops; + volatile unsigned int *cfg_addr; + volatile unsigned char *cfg_data; + + /* Currently, we limit ourselves to 1 IO range and 3 mem + * ranges since the common pci_bus structure can't handle more + */ + struct resource io_resource; + struct resource mem_resources[3]; + int mem_resource_count; + + /* Host bridge I/O and Memory space + * Used for BAR placement algorithms + */ + struct resource io_space; + struct resource mem_space; +}; + +/* These are used for config access before all the PCI probing + has been done. */ +int early_read_config_byte(struct pci_controller *hose, int bus, int dev_fn, + int where, u8 *val); +int early_read_config_word(struct pci_controller *hose, int bus, int dev_fn, + int where, u16 *val); +int early_read_config_dword(struct pci_controller *hose, int bus, int dev_fn, + int where, u32 *val); +int early_write_config_byte(struct pci_controller *hose, int bus, int dev_fn, + int where, u8 val); +int early_write_config_word(struct pci_controller *hose, int bus, int dev_fn, + int where, u16 val); +int early_write_config_dword(struct pci_controller *hose, int bus, int dev_fn, + int where, u32 val); +#endif +#endif /* __KERNEL__ */ diff -u -r --new-file linux/include/linux/cpci.h ha/include/linux/cpci.h --- linux/include/linux/cpci.h Wed Dec 31 17:00:00 1969 +++ ha/include/linux/cpci.h Thu Dec 13 13:03:13 2001 @@ -0,0 +1,110 @@ +/* + * cpci.h + * + * Common access routines for cPCI interface. + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CPCI_H +#define CPCI_H + +/* Events currently defined. */ +#define CPCI_EVENT_INSERT 1 +#define CPCI_EVENT_REMOVE 2 +#define CPCI_EVENT_AVAIL 3 +#define CPCI_EVENT_SHUTDOWN 4 +#define CPCI_EVENT_CLOSED 5 + +#define CPCI_BOARD_INS_SUCC 6 +#define CPCI_BOARD_INS_FAIL 7 +#define CPCI_BI_FAIL_BUSY 1 /* Slot already alloced */ +#define CPCI_BI_FAIL_HEALTH 2 /* Healthy not set */ +#define CPCI_BI_FAIL_CONFIG 3 /* PCI bus config failed */ +#define CPCI_BI_FAIL_NODEV 4 /* No device found in slot. */ +#define CPCI_BI_FAIL_NOSUB 5 /* No subordinate device fount */ +#define CPCI_BI_FAIL_SCAN 6 /* PCI bus scan failed */ +#define CPCI_BOARD_REM_SUCC 8 +#define CPCI_BOARD_REM_FAIL 9 + +/* cPCI chassis types currently known. */ +#define CPCI_CHASSIS_UNKNOWN 0x0 +#define CPCI_CHASSIS_GEN_HOTSWAP 0x10001 +#define CPCI_CHASSIS_MOT_CPX8216 0x20002 +#define CPCI_CHASSIS_MOT_CPX8216A 0x20003 +#define CPCI_CHASSIS_MOT_CPX8216T 0x20004 +#define CPCI_CHASSIS_MOT_CPX8221 0x30005 +#define CPCI_CHASSIS_ZIA_5083 0x20006 + +/* Board allocate status codes. */ +#define CPCI_SLOT_FREE 0 /* Slot empty */ +#define CPCI_SLOT_ALLOCATED 1 /* Slot Allocated */ +#define CPCI_SLOT_INSFAILED 2 /* Slot insert failed with reasin below. */ + +#define MAX_SLOT_NUM 7 /* PCI bus cannot be bigger than this on any one segment. */ + +typedef struct _CpciIoctlBusInfo { + int Bus; + int StartSlot; + int EndSlot; + int Allocated[MAX_SLOT_NUM]; +} CpciIoctlBusInfo; + +#define CPCI_MAX_NAME_LEN 16 +#define CPCI_MAX_SLOT_INFO 32 + +#define CPCI_DRIVER_NEEDED 0 +#define CPCI_DRIVER_INSTALLED 1 + +typedef struct _CpciIoctlDevInfo { + int Vendor; + int Device; + int SubSystemVendor; + int SubSystemDevice; + int Class; + int DriverStatus; + char Name[CPCI_MAX_NAME_LEN]; +} CpciIoctlDevInfo; + +typedef struct _CpciIoctlSlotInfo { + int Domain; + int Slot; + int NumSubDevs; + CpciIoctlDevInfo DevInfo[CPCI_MAX_SLOT_INFO]; +} CpciIoctlSlotInfo; + +/* cPCI ioctl calls currently available */ +#define CPCI_MAGIC 0xc0 + +#define CPCI_ADD_BUS _IOW(CPCI_MAGIC, 1, int) +#define CPCI_DEL_BUS _IOW(CPCI_MAGIC, 2, int) +#define CPCI_ADD_SLOT _IOW(CPCI_MAGIC, 3, int) +#define CPCI_DEL_SLOT _IOW(CPCI_MAGIC, 4, int) +#define CPCI_GET_CHASSIS_TYPE _IOR(CPCI_MAGIC, 5, int) +#define CPCI_GET_BUS_INFO _IOWR(CPCI_MAGIC, 6, CpciIoctlBusInfo) +#define CPCI_GET_SLOT_INFO _IOWR(CPCI_MAGIC, 7, CpciIoctlSlotInfo) + +#endif /* CPCI_H */ diff -u -r --new-file linux/include/linux/event.h ha/include/linux/event.h --- linux/include/linux/event.h Wed Dec 31 17:00:00 1969 +++ ha/include/linux/event.h Thu Dec 13 13:03:13 2001 @@ -0,0 +1,114 @@ +/* + * event.h + * + * Kernel event access routines and data structures. + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef EVENT_H +#define EVENT_H + +/* User request uses for the Flag in EventPacket */ +#define EF_WAIT_FOR_EVENT 0x1 + +/* Flag values to indicate the status of the extra data field. */ +#define EF_DATA_AVAIL 0x2 +#define EF_DATA_FAILURE 0x4 + +/* Structure of an event packet. */ +typedef struct event_packet { + int Flag; /* Used to indicate sleep wait or not. */ + int Id; + int Pri; + int Class; + int Event; + struct timeval TimeStamp; + int Info[4]; + int DataLen; + void *Data; + struct event_packet *Next; +} EventPacket; + +/* Structure used to request and event to be sent to a process or not. */ +typedef struct event_req_info { + int Id; + int Pri; + int Class; + int Event; +} EventReq; + +/* Data structure used by EVENT_REG_ID, EVENT_UNREG_ID and EVENT_GET_ID. */ +typedef struct event_id { + int Id; + char IdString[16]; +} EventIdPacket; + +/* User level ioctl cmd identifiers. */ +#define EVENT_MAGIC 0xd0 + +#define EVENT_REG_ID _IOWR(EVENT_MAGIC, 1, EventIdPacket) +#define EVENT_UNREG_ID _IOW(EVENT_MAGIC, 2, EventIdPacket) +#define EVENT_GET_ID _IOWR(EVENT_MAGIC, 3, EventIdPacket) +#define EVENT_GET_ID_STRING _IOWR(EVENT_MAGIC, 4, EventIdPacket) + +#define EVENT_REG_EVENT_CLASS _IOWR(EVENT_MAGIC, 5, EventIdPacket) +#define EVENT_UNREG_EVENT_CLASS _IOW(EVENT_MAGIC, 6, EventIdPacket) +#define EVENT_GET_EVENT_CLASS _IOWR(EVENT_MAGIC, 7, EventIdPacket) +#define EVENT_GET_EVENT_CLASS_STRING _IOWR(EVENT_MAGIC, 8, EventIdPacket) + +#define EVENT_SUBSCRIBE_EVENT_BY_TYPE _IOW(EVENT_MAGIC, 9, EventReq) +#define EVENT_UNSUBSCRIBE_EVENT_BY_TYPE _IOW(EVENT_MAGIC, 10, EventReq) +#define EVENT_SUBSCRIBE_EVENT_BY_CLASS _IOW(EVENT_MAGIC, 11, int) +#define EVENT_UNSUBSCRIBE_EVENT_BY_CLASS _IOW(EVENT_MAGIC, 12, int) + +#define EVENT_GET_EVENT _IOWR(EVENT_MAGIC, 13, EventPacket) +#define EVENT_SEND_EVENT _IOW(EVENT_MAGIC, 14, EventPacket) + +/* Kernel interface access function prototypes. */ +int EventRegisterId(char *); +int EventUnRegisterId(int); +int EventGetId(char *); +int EventGetIdString(int, char *); + +int EventRegisterEventClass(char *, int *); +int EventUnRegisterEventClass(int); +int EventGetEventClass(char *); +int EventGetEventClassString(int, char *); + +int EventSubscribeEventByType(int, int, int, int, + int (*)(int, int, int, int, int, int, int, int, int, void *)); +int EventUnSubscribeEventByType(int, int, int); +int EventSubscribeEventByClass(int, int, int, + int (*)(int, int, int, int, int, int, int, int, int, void *)); +int EventUnSubscribeEventByClass(int, int); + +int EventGetEvent(int, int, EventPacket *); +void EventFree(EventPacket *, int); + +int EventSendEvent(int, int, int, int, int, int, int, int, int, void *); + +#endif /* EVENT_H */ diff -u -r --new-file linux/include/linux/init.h ha/include/linux/init.h --- linux/include/linux/init.h Thu Nov 22 12:46:18 2001 +++ ha/include/linux/init.h Thu Dec 13 13:23:46 2001 @@ -143,7 +143,7 @@ #endif -#ifdef CONFIG_HOTPLUG +#if defined(CONFIG_HOTPLUG) || defined(CONFIG_CPCI_HOTSWAP) #define __devinit #define __devinitdata #define __devexit diff -u -r --new-file linux/include/linux/mot82XXhsc.h ha/include/linux/mot82XXhsc.h --- linux/include/linux/mot82XXhsc.h Wed Dec 31 17:00:00 1969 +++ ha/include/linux/mot82XXhsc.h Thu Dec 13 13:03:13 2001 @@ -0,0 +1,277 @@ +/* + * mot82XXhsc.h + * + * Motorola 82XX hot swap controller driver. + * + * Author: MontaVista Software, Inc. + * jpeters@mvista.com + * source@mvista.com + * + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef MOT82XXHSC_H +#define MOT82XXHSC_H + +/* How many of each exists. */ +#define MOTHSC_NUM_SLOTS 16 /* number of card slots */ +#define MOTHSC_NUM_PS 3 /* number of power supplies */ +#define MOTHSC_NUM_PBAY 4 /* number of peripherl bays */ +#define MOTHSC_NUM_INTSTAT 3 /* number of interrupt status regs */ +#define MOTHSC_NUM_BUS 2 /* number of buses. */ + +/* Data structure of events to be returned. */ +typedef struct mot82XXEvent { + int Event; /* Event happinging. */ + int Unit; /* Particular device. */ + int Val; /* More info - normally on or off */ +} MotHscEvent; + +/* Max number of events to return at one time. */ +#define MOTHSC_EVENTS_MAX 16 + +/* Ioctl data structure for events. */ +typedef struct mot82XXEvents { + int Count; + MotHscEvent Events[MOTHSC_EVENTS_MAX]; +} MotHscEvents; + +/* specification for enableing or disableing events. */ +#define MOT82XXHSC_EVENT_ON 1 +#define MOT82XXHSC_EVENT_OFF 0 + +/* Known event types. */ +#define MOT82XXHSC_EVENT_ALARM 1 + +#define MOT82XXHSC_EVENT_LED 2 + +#define MOT82XXHSC_EVENT_PBAY1 3 +#define MOT82XXHSC_EVENT_PBAY2 4 +#define MOT82XXHSC_EVENT_PBAY3 5 +#define MOT82XXHSC_EVENT_PBAY4 6 + +#define MOT82XXHSC_EVENT_PS1 7 +#define MOT82XXHSC_EVENT_PS2 8 +#define MOT82XXHSC_EVENT_PS3 9 + +#define MOT82XXHSC_EVENT_BUS_UNKNOWN 10 +#define MOT82XXHSC_EVENT_BUS_TAKE_REQ 11 +#define MOT82XXHSC_EVENT_BUS_TAKE_DONE 12 +#define MOT82XXHSC_EVENT_BUS_RELEASED 13 +#define MOT82XXHSC_EVENT_BUS_ALLOW 14 +#define MOT82XXHSC_EVENT_BUS_DISALLOW 15 + +#define MOT82XXHSC_EVENT_SLOT1 16 +#define MOT82XXHSC_EVENT_SLOT2 17 +#define MOT82XXHSC_EVENT_SLOT3 18 +#define MOT82XXHSC_EVENT_SLOT4 19 +#define MOT82XXHSC_EVENT_SLOT5 20 +#define MOT82XXHSC_EVENT_SLOT6 21 +#define MOT82XXHSC_EVENT_HOSTA 22 +#define MOT82XXHSC_EVENT_HSCA 23 +#define MOT82XXHSC_EVENT_HOSTB 24 +#define MOT82XXHSC_EVENT_HSCB 25 +#define MOT82XXHSC_EVENT_SLOT11 26 +#define MOT82XXHSC_EVENT_SLOT12 27 +#define MOT82XXHSC_EVENT_SLOT13 28 +#define MOT82XXHSC_EVENT_SLOT14 29 +#define MOT82XXHSC_EVENT_SLOT15 30 +#define MOT82XXHSC_EVENT_SLOT16 31 + +#define MOT82XXHSC_EVENT_ENUM 32 +#define MOT82XXHSC_EVENT_ENUMMASK 33 + +/* Structure used to return current register setting. For debug onlty. */ +typedef struct mot82XXRegisters { + unsigned int MhrSlot[MOTHSC_NUM_SLOTS]; + unsigned int MhrPower[MOTHSC_NUM_PS]; + unsigned int MhrPBay[MOTHSC_NUM_PBAY]; + unsigned int MhrIntStatMask; + unsigned int MhrIntStatus[MOTHSC_NUM_INTSTAT]; + unsigned int MhrBusControl[MOTHSC_NUM_BUS]; + unsigned int MhrEEprom; + unsigned int MhrSysLed; + unsigned int MhrAlarm; + unsigned int MhrIntMask; +} MotHscRegisters; + +/* Specify the particular bit should be set or cleared. */ +#define MOT82XXHSC_SET 1 +#define MOT82XXHSC_CLEAR 0 + +/* Data structure for alarm control ioctl and the bits to be used. */ +typedef struct mot82XXAlarmLedSet { + int MasFlag; + unsigned int MasBits; +} MotHscAlarmLedSet; + +#define MOT82XXHSC_ALARM_CRITICAL 0x1 +#define MOT82XXHSC_ALARM_MAJOR 0x2 +#define MOT82XXHSC_ALARM_MINOR 0x4 +#define MOT82XXHSC_ALARM_RACK 0x8 +#define MOT82XXHSC_ALARM_MASK 0xf + +/* Bits for chassis LED controls. Alarm data structure used. */ +#define MOT82XXHSC_LED1 0x1 +#define MOT82XXHSC_LED2 0x2 +#define MOT82XXHSC_LED3 0x4 +#define MOT82XXHSC_LED4 0x8 +#define MOT82XXHSC_LED_MASK 0xf + +/* Structure und bits sed for peripheal bay controls. */ +typedef struct mot82XXPBayInfo { + int MpbiFlag; + int MpbiBay; + unsigned int MpbiBits; +} MotHscPBayInfo; + +#define MOT82XXHSC_PBAY_PRESENT 0x1 +#define MOT82XXHSC_PBAY_POWER 0x2 +#define MOT82XXHSC_PBAY_OWNDEVICE 0x4 +#define MOT82XXHSC_PBAY_LED1 0x8 +#define MOT82XXHSC_PBAY_LED2 0x10 +#define MOT82XXHSC_PBAY_MASK 0x1f + +/* Structure und bits sed for power supply controls. */ +typedef struct mot82XXPsInfo { + int MpsiFlag; + int MpsiPS; + unsigned int MpsiBits; +} MotHscPsInfo; + +#define MOT82XXHSC_PS_PRESENT 0x1 +#define MOT82XXHSC_PS_POWER 0x2 +#define MOT82XXHSC_PS_TOLERANCE 0x4 +#define MOT82XXHSC_PS_COOL_ALARM 0x8 +#define MOT82XXHSC_PS_COOL_FAIL 0x10 +#define MOT82XXHSC_PS_LED1 0x20 +#define MOT82XXHSC_PS_LED2 0x40 +#define MOT82XXHSC_PS_FAN_LED1 0x80 +#define MOT82XXHSC_PS_FAN_LED2 0x100 +#define MOT82XXHSC_PS_FAN_PRESENT 0x200 +#define MOT82XXHSC_PS_FAN_SPEED 0x400 +#define MOT82XXHSC_PS_FAN_FAIL 0x800 +#define MOT82XXHSC_PS_MASK 0xfff + +/* Bit fields used for bus control. */ +#define MOT82XXHSC_DOMAIN_A 0x1 +#define MOT82XXHSC_DOMAIN_B 0x2 + +#define MOT82XXHSC_BUS_TIMEO_MASK 0xffff0000 +#define MOT82XXHSC_BUS_A 0x1 +#define MOT82XXHSC_BUS_B 0x2 +#define MOT82XXHSC_BUS_MASK 0x3 +#define MOT82XXHSC_BUS_RELEASE 0x4 +#define MOT82XXHSC_BUS_MODEMASK 0xc +#define MOT82XXHSC_BUS_ALLOWTO 0x10000 + +#define MOT82XXHSC_BUS_FREE 1 +#define MOT82XXHSC_BUS_OTHER 2 +#define MOT82XXHSC_BUS_REQUESTED 3 +#define MOT82XXHSC_BUS_TRAN_START 4 +#define MOT82XXHSC_BUS_STOPED 5 +#define MOT82XXHSC_BUS_TRAN_ACK 6 +#define MOT82XXHSC_BUS_ENABLE 7 +#define MOT82XXHSC_BUS_TRAN_DONE 8 +#define MOT82XXHSC_BUS_MINE 9 + +/* Date structure used to secify controls for slot registers. */ +typedef struct mot82XXSlotInfo { + int MsiFlag; + int MsiSlot; + unsigned int MsiBits; +} MotHscSlotInfo; + +/* Bits for slot control. Most of these are the same whether they + * are host, non host or hsc slots. */ +#define MOT82XXHSC_SLOT_PRESENT 0x1 +#define MOT82XXHSC_SLOT_POWER 0x2 +#define MOT82XXHSC_SLOT_IGN_HLTH 0x4 +#define MOT82XXHSC_SLOT_RESET 0x8 +#define MOT82XXHSC_SLOT_CONNECT 0x10 +#define MOT82XXHSC_SLOT_CONNED 0x20 +#define MOT82XXHSC_SLOT_HEALTHY 0x40 +#define MOT82XXHSC_SLOT_LED1 0x80 +#define MOT82XXHSC_SLOT_LED2 0x100 +#define MOT82XXHSC_SLOT_LED3 0x200 +#define MOT82XXHSC_SLOT_ACTIVE 0x400 + +/* The bridge slots have a few different bit defines. */ +#define MOT82XXHSC_HSC_INSERT 0x2 +#define MOT82XXHSC_HSC_REMOVE 0x4 +#define MOT82XXHSC_HSC_INSTALL 0x8 +#define MOT82XXHSC_HSC_EJECTOR 0x10 + +/* Bit bask of setable fits for slot registers. */ +#define MOT82XXHSC_NH_MASK 0x396 /*Only valid setable bits */ +#define MOT82XXHSC_HOST_MASK 0x382 +#define MOT82XXHSC_HSC_MASK 0x386 + +/* Specify the correct arguments for variois slot control functions. */ +#define MOT82XXHSC_SLOT1 1 +#define MOT82XXHSC_SLOT2 2 +#define MOT82XXHSC_SLOT3 3 +#define MOT82XXHSC_SLOT4 4 +#define MOT82XXHSC_SLOT5 5 +#define MOT82XXHSC_SLOT6 6 +#define MOT82XXHSC_SLOT11 11 +#define MOT82XXHSC_SLOT12 12 +#define MOT82XXHSC_SLOT13 13 +#define MOT82XXHSC_SLOT14 14 +#define MOT82XXHSC_SLOT15 15 +#define MOT82XXHSC_SLOT16 16 + +#define MOT82XXHSC_HOSTA 1 +#define MOT82XXHSC_HOSTB 2 + +#define MOT82XXHSC_HSCA 1 +#define MOT82XXHSC_HSCB 2 + +/* Ioctl command identifiers. */ +#define MOT82XXHSC_MAGIC 0xb0 +#define HSC_GET_REGISTERS _IOR(MOT82XXHSC_MAGIC, 1, MotHscRegisters) +#define HSC_GET_EVENTS _IOR(MOT82XXHSC_MAGIC, 2, MotHscEvents) +#define HSC_SET_ALARM _IOW(MOT82XXHSC_MAGIC, 3, MotHscAlarmLedSet) +#define HSC_GET_ALARM_STAT _IOR(MOT82XXHSC_MAGIC, 4, int) +#define HSC_SET_LED _IOW(MOT82XXHSC_MAGIC, 5, MotHscAlarmLedSet) +#define HSC_GET_LED_STAT _IOR(MOT82XXHSC_MAGIC, 6, int) +#define HSC_SET_PBAY _IOW(MOT82XXHSC_MAGIC, 7, MotHscPBayInfo) +#define HSC_GET_PBAY_STAT _IOWR(MOT82XXHSC_MAGIC, 8, int) +#define HSC_SET_POWER _IOW(MOT82XXHSC_MAGIC, 9, MotHscPsInfo) +#define HSC_GET_POWER_STAT _IOWR(MOT82XXHSC_MAGIC, 10, int) +#define HSC_GET_LOCALHOST _IOR(MOT82XXHSC_MAGIC, 11, int) +#define HSC_GET_BUS_STATE _IOWR(MOT82XXHSC_MAGIC, 12, int) +#define HSC_TAKE_BUS _IOW(MOT82XXHSC_MAGIC, 13, int) +#define HSC_FREE_BUS _IOW(MOT82XXHSC_MAGIC, 14, int) +#define HSC_ALLOW_BUS_TAKE _IOW(MOT82XXHSC_MAGIC, 15, int) +#define HSC_SET_ENUMMASK _IOW(MOT82XXHSC_MAGIC, 16, int) +#define HSC_GET_ENUMMASK _IOR(MOT82XXHSC_MAGIC, 17, int) +#define HSC_GET_ENUM _IOR(MOT82XXHSC_MAGIC, 18, int) +#define HSC_GET_NONHOST _IOWR(MOT82XXHSC_MAGIC, 19, int) +#define HSC_SET_NONHOST _IOW(MOT82XXHSC_MAGIC, 20, MotHscSlotInfo) +#define HSC_GET_HOST _IOWR(MOT82XXHSC_MAGIC, 21, int) +#define HSC_SET_HOST _IOW(MOT82XXHSC_MAGIC, 22, MotHscSlotInfo) +#define HSC_GET_HSC _IOWR(MOT82XXHSC_MAGIC, 23, int) +#define HSC_SET_HSC _IOW(MOT82XXHSC_MAGIC, 24, MotHscSlotInfo) + +#endif /* MOT82XXHSC_H */ diff -u -r --new-file linux/include/linux/pci.h ha/include/linux/pci.h --- linux/include/linux/pci.h Thu Nov 22 12:46:30 2001 +++ ha/include/linux/pci.h Thu Dec 13 13:25:12 2001 @@ -381,7 +381,9 @@ int active; /* ISAPnP: device is active */ int ro; /* ISAPnP: read only */ unsigned short regs; /* ISAPnP: supported registers */ - +#ifdef CONFIG_CPCI_HOTSWAP + int cpci_location; /* cPCI slot this device is in */ +#endif int (*prepare)(struct pci_dev *dev); /* ISAPnP hooks */ int (*activate)(struct pci_dev *dev); int (*deactivate)(struct pci_dev *dev); @@ -595,6 +597,11 @@ unsigned int pci_do_scan_bus(struct pci_bus *bus); struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); +/* Additional functions exported for use by the cPCI Hotswap routines */ +struct pci_dev *pci_scan_device(struct pci_dev *); +void pci_read_bridge_bases(struct pci_bus *); +int pci_announce_device(struct pci_driver *, struct pci_dev *); + /* kmem_cache style wrapper around pci_alloc_consistent() */ struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev, size_t size, size_t align, size_t allocation, int flags); @@ -691,6 +698,10 @@ if (rc == 0) rc = -ENODEV; #endif +#ifdef CONFIG_CPCI_HOTSWAP + if (rc == 0) + return 0; +#endif /* if we get here, we need to clean up pci driver instance * and return some sort of error */ @@ -755,5 +766,13 @@ #define PCIPCI_VIAETBF 8 #define PCIPCI_VSFX 16 +#ifdef CONFIG_CPCI_HOTSWAP +void CpciRegisterDevice(struct pci_dev *); +void CpciUnRegisterDevice(struct pci_dev *); +#else +#define CpciRegisterDevice(x); +#define CpciUnRegisterDevice(x); + +#endif /* CONFIG_CPCI_HOTSWAP */ #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ diff -u -r --new-file linux/include/linux/pci_auto.h ha/include/linux/pci_auto.h --- linux/include/linux/pci_auto.h Wed Dec 31 17:00:00 1969 +++ ha/include/linux/pci_auto.h Thu Dec 13 13:25:22 2001 @@ -0,0 +1,64 @@ +/* + * include/linux/pci_auto.h + * + * PCI autoconfiguration library definitions + * + * Author: Matt Porter + * Johnnie Peters + +struct pci_exception { + int type; + void *val1; + void *val2; + void *val3; + void *val4; +}; + +#define PCI_EXCPT_SKIP_DEV 1 /* skip bus, devfn */ +#define PCI_EXCPT_SETUP_BRIDGE_DEV 2 /* setup bus, devfn */ +#define PCI_EXCPT_SETUP_BRIDGE_TYPE 3 /* setup vendor, device */ +#define PCI_EXCPT_SETUP_DEVICE_DEV 4 /* setup bus, devfn */ +#define PCI_EXCPT_SETUP_DEVICE_TYPE 5 /* setup vendor, device */ + +#define PCI_EXCPT_IGNORE 1 +#define PCI_EXCPT_DONT_SCAN 2 + +struct pci_auto_addrs { + unsigned int io_start; + unsigned int io_end; + unsigned int mem_start; + unsigned int mem_end; +}; + +void pciauto_excpt_exclude_bdev(int, int); +void pci_excpt_setup_bridge_bdev(struct pci_controller *, int, int, + int(*)(struct pci_controller *, int, int)); +void pci_excpt_setup_device_bdev(struct pci_controller *, int, int, + int(*)(struct pci_controller *, int, int)); + +int pciauto_setup_bars(struct pci_controller *, int, int, + struct pci_auto_addrs *); +void pciauto_prescan_setup_bridge(struct pci_controller *, int, int, int, + struct pci_auto_addrs *); +void pciauto_postscan_setup_bridge(struct pci_controller *, int, int, int, + struct pci_auto_addrs *); +int pciauto_bus_scan(struct pci_controller *, int, + struct pci_auto_addrs *); +struct pci_controller *pciauto_alloc_controller(void); + +#define PCIAUTO_IDE_MODE_MASK 0x05 + +#endif /* __PCI_AUTO_H */ diff -u -r --new-file linux/include/linux/pci_ids.h ha/include/linux/pci_ids.h --- linux/include/linux/pci_ids.h Fri Nov 9 15:11:15 2001 +++ ha/include/linux/pci_ids.h Thu Dec 13 13:03:13 2001 @@ -314,6 +314,7 @@ #define PCI_DEVICE_ID_DEC_21152 0x0024 #define PCI_DEVICE_ID_DEC_21153 0x0025 #define PCI_DEVICE_ID_DEC_21154 0x0026 +#define PCI_DEVICE_ID_DEC_21554 0x0046 #define PCI_DEVICE_ID_DEC_21285 0x1065 #define PCI_DEVICE_ID_COMPAQ_42XX 0x0046 @@ -595,6 +596,9 @@ #define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 #define PCI_DEVICE_ID_MOTOROLA_FALCON 0x4802 #define PCI_DEVICE_ID_MOTOROLA_CPX8216 0x4806 +#define PCI_DEVICE_ID_MOTOROLA_CPX8221 0x4807 +#define PCI_DEVICE_ID_MOTOROLA_CPX8216T 0x4809 +#define PCI_DEVICE_ID_MOTOROLA_CPX8216A 0x480a #define PCI_VENDOR_ID_PROMISE 0x105a #define PCI_DEVICE_ID_PROMISE_20265 0x0d30 diff -u -r --new-file linux/init/main.c ha/init/main.c --- linux/init/main.c Fri Nov 9 15:15:00 2001 +++ ha/init/main.c Thu Dec 13 13:15:25 2001 @@ -107,6 +107,13 @@ extern void ipc_init(void); #endif +#ifdef CONFIG_EVENT_BROKER +extern int event_init(void); +#endif +#ifdef CONFIG_CPCI_HOTSWAP +extern int cpci_init(void); +#endif + /* * Boot command-line arguments */ @@ -700,6 +707,12 @@ #endif #if defined(CONFIG_PPC) ppc_init(); +#endif +#ifdef CONFIG_EVENT_BROKER + event_init(); +#endif +#ifdef CONFIG_CPCI_HOTSWAP + cpci_init(); #endif #ifdef CONFIG_MCA mca_init(); +