From: Stephen Rothwell Date: Tue, 27 Sep 2005 16:50:25 +0000 (+1000) Subject: powerpc: Move iSeries_pci.c to powerpc/platform/iseries X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=d387899f3f7092edbafe16d69ea9737846473e99;p=GitHub%2Fmoto-9609%2Fandroid_kernel_motorola_exynos9610.git powerpc: Move iSeries_pci.c to powerpc/platform/iseries and rename it to pci.c. This also required moving arch/ppc64/kernel/pci.h into include/asm-powerpc (called ppc-pci.h. Signed-off-by: Stephen Rothwell --- diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index bf3992bf7ff8..7ee4592f83d3 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1,2 +1,3 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o +obj-$(CONFIG_PCI) += pci.o diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c new file mode 100644 index 000000000000..61a857218bc8 --- /dev/null +++ b/arch/powerpc/platforms/iseries/pci.c @@ -0,0 +1,903 @@ +/* + * Copyright (C) 2001 Allan Trautman, IBM Corporation + * + * iSeries specific routines for PCI. + * + * Based on code from pci.c and iSeries_pci.c 32bit + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +extern unsigned long io_page_mask; + +/* + * Forward declares of prototypes. + */ +static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn); +static void scan_PHB_slots(struct pci_controller *Phb); +static void scan_EADS_bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel); +static int scan_bridge_slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo *Info); + +LIST_HEAD(iSeries_Global_Device_List); + +static int DeviceCount; + +/* Counters and control flags. */ +static long Pci_Io_Read_Count; +static long Pci_Io_Write_Count; +#if 0 +static long Pci_Cfg_Read_Count; +static long Pci_Cfg_Write_Count; +#endif +static long Pci_Error_Count; + +static int Pci_Retry_Max = 3; /* Only retry 3 times */ +static int Pci_Error_Flag = 1; /* Set Retry Error on. */ + +static struct pci_ops iSeries_pci_ops; + +/* + * Table defines + * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space. + */ +#define IOMM_TABLE_MAX_ENTRIES 1024 +#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL +#define BASE_IO_MEMORY 0xE000000000000000UL + +static unsigned long max_io_memory = 0xE000000000000000UL; +static long current_iomm_table_entry; + +/* + * Lookup Tables. + */ +static struct iSeries_Device_Node **iomm_table; +static u8 *iobar_table; + +/* + * Static and Global variables + */ +static char *pci_io_text = "iSeries PCI I/O"; +static DEFINE_SPINLOCK(iomm_table_lock); + +/* + * iomm_table_initialize + * + * Allocates and initalizes the Address Translation Table and Bar + * Tables to get them ready for use. Must be called before any + * I/O space is handed out to the device BARs. + */ +static void iomm_table_initialize(void) +{ + spin_lock(&iomm_table_lock); + iomm_table = kmalloc(sizeof(*iomm_table) * IOMM_TABLE_MAX_ENTRIES, + GFP_KERNEL); + iobar_table = kmalloc(sizeof(*iobar_table) * IOMM_TABLE_MAX_ENTRIES, + GFP_KERNEL); + spin_unlock(&iomm_table_lock); + if ((iomm_table == NULL) || (iobar_table == NULL)) + panic("PCI: I/O tables allocation failed.\n"); +} + +/* + * iomm_table_allocate_entry + * + * Adds pci_dev entry in address translation table + * + * - Allocates the number of entries required in table base on BAR + * size. + * - Allocates starting at BASE_IO_MEMORY and increases. + * - The size is round up to be a multiple of entry size. + * - CurrentIndex is incremented to keep track of the last entry. + * - Builds the resource entry for allocated BARs. + */ +static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) +{ + struct resource *bar_res = &dev->resource[bar_num]; + long bar_size = pci_resource_len(dev, bar_num); + + /* + * No space to allocate, quick exit, skip Allocation. + */ + if (bar_size == 0) + return; + /* + * Set Resource values. + */ + spin_lock(&iomm_table_lock); + bar_res->name = pci_io_text; + bar_res->start = + IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; + bar_res->start += BASE_IO_MEMORY; + bar_res->end = bar_res->start + bar_size - 1; + /* + * Allocate the number of table entries needed for BAR. + */ + while (bar_size > 0 ) { + iomm_table[current_iomm_table_entry] = dev->sysdata; + iobar_table[current_iomm_table_entry] = bar_num; + bar_size -= IOMM_TABLE_ENTRY_SIZE; + ++current_iomm_table_entry; + } + max_io_memory = BASE_IO_MEMORY + + (IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry); + spin_unlock(&iomm_table_lock); +} + +/* + * allocate_device_bars + * + * - Allocates ALL pci_dev BAR's and updates the resources with the + * BAR value. BARS with zero length will have the resources + * The HvCallPci_getBarParms is used to get the size of the BAR + * space. It calls iomm_table_allocate_entry to allocate + * each entry. + * - Loops through The Bar resources(0 - 5) including the ROM + * is resource(6). + */ +static void allocate_device_bars(struct pci_dev *dev) +{ + struct resource *bar_res; + int bar_num; + + for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num) { + bar_res = &dev->resource[bar_num]; + iomm_table_allocate_entry(dev, bar_num); + } +} + +/* + * Log error information to system console. + * Filter out the device not there errors. + * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx + * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx + * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx + */ +static void pci_Log_Error(char *Error_Text, int Bus, int SubBus, + int AgentId, int HvRc) +{ + if (HvRc == 0x0302) + return; + printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X", + Error_Text, Bus, SubBus, AgentId, HvRc); +} + +/* + * build_device_node(u16 Bus, int SubBus, u8 DevFn) + */ +static struct iSeries_Device_Node *build_device_node(HvBusNumber Bus, + HvSubBusNumber SubBus, int AgentId, int Function) +{ + struct iSeries_Device_Node *node; + + PPCDBG(PPCDBG_BUSWALK, + "-build_device_node 0x%02X.%02X.%02X Function: %02X\n", + Bus, SubBus, AgentId, Function); + + node = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL); + if (node == NULL) + return NULL; + + memset(node, 0, sizeof(struct iSeries_Device_Node)); + list_add_tail(&node->Device_List, &iSeries_Global_Device_List); +#if 0 + node->DsaAddr = ((u64)Bus << 48) + ((u64)SubBus << 40) + ((u64)0x10 << 32); +#endif + node->DsaAddr.DsaAddr = 0; + node->DsaAddr.Dsa.busNumber = Bus; + node->DsaAddr.Dsa.subBusNumber = SubBus; + node->DsaAddr.Dsa.deviceId = 0x10; + node->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function); + return node; +} + +/* + * unsigned long __init find_and_init_phbs(void) + * + * Description: + * This function checks for all possible system PCI host bridges that connect + * PCI buses. The system hypervisor is queried as to the guest partition + * ownership status. A pci_controller is built for any bus which is partially + * owned or fully owned by this guest partition. + */ +unsigned long __init find_and_init_phbs(void) +{ + struct pci_controller *phb; + HvBusNumber bus; + + PPCDBG(PPCDBG_BUSWALK, "find_and_init_phbs Entry\n"); + + /* Check all possible buses. */ + for (bus = 0; bus < 256; bus++) { + int ret = HvCallXm_testBus(bus); + if (ret == 0) { + printk("bus %d appears to exist\n", bus); + + phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), GFP_KERNEL); + if (phb == NULL) + return -ENOMEM; + pci_setup_pci_controller(phb); + + phb->pci_mem_offset = phb->local_number = bus; + phb->first_busno = bus; + phb->last_busno = bus; + phb->ops = &iSeries_pci_ops; + + PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n", + phb, bus); + + /* Find and connect the devices. */ + scan_PHB_slots(phb); + } + /* + * Check for Unexpected Return code, a clue that something + * has gone wrong. + */ + else if (ret != 0x0301) + printk(KERN_ERR "Unexpected Return on Probe(0x%04X): 0x%04X", + bus, ret); + } + return 0; +} + +/* + * iSeries_pcibios_init + * + * Chance to initialize and structures or variable before PCI Bus walk. + */ +void iSeries_pcibios_init(void) +{ + PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Entry.\n"); + iomm_table_initialize(); + find_and_init_phbs(); + io_page_mask = -1; + PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Exit.\n"); +} + +/* + * iSeries_pci_final_fixup(void) + */ +void __init iSeries_pci_final_fixup(void) +{ + struct pci_dev *pdev = NULL; + struct iSeries_Device_Node *node; + int DeviceCount = 0; + + PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n"); + + /* Fix up at the device node and pci_dev relationship */ + mf_display_src(0xC9000100); + + printk("pcibios_final_fixup\n"); + for_each_pci_dev(pdev) { + node = find_Device_Node(pdev->bus->number, pdev->devfn); + printk("pci dev %p (%x.%x), node %p\n", pdev, + pdev->bus->number, pdev->devfn, node); + + if (node != NULL) { + ++DeviceCount; + pdev->sysdata = (void *)node; + node->PciDev = pdev; + PPCDBG(PPCDBG_BUSWALK, + "pdev 0x%p <==> DevNode 0x%p\n", + pdev, node); + allocate_device_bars(pdev); + iSeries_Device_Information(pdev, DeviceCount); + iommu_devnode_init_iSeries(node); + } else + printk("PCI: Device Tree not found for 0x%016lX\n", + (unsigned long)pdev); + pdev->irq = node->Irq; + } + iSeries_activate_IRQs(); + mf_display_src(0xC9000200); +} + +void pcibios_fixup_bus(struct pci_bus *PciBus) +{ + PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup_bus(0x%04X) Entry.\n", + PciBus->number); +} + +void pcibios_fixup_resources(struct pci_dev *pdev) +{ + PPCDBG(PPCDBG_BUSWALK, "fixup_resources pdev %p\n", pdev); +} + +/* + * Loop through each node function to find usable EADs bridges. + */ +static void scan_PHB_slots(struct pci_controller *Phb) +{ + struct HvCallPci_DeviceInfo *DevInfo; + HvBusNumber bus = Phb->local_number; /* System Bus */ + const HvSubBusNumber SubBus = 0; /* EADs is always 0. */ + int HvRc = 0; + int IdSel; + const int MaxAgents = 8; + + DevInfo = (struct HvCallPci_DeviceInfo*) + kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL); + if (DevInfo == NULL) + return; + + /* + * Probe for EADs Bridges + */ + for (IdSel = 1; IdSel < MaxAgents; ++IdSel) { + HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel, + ISERIES_HV_ADDR(DevInfo), + sizeof(struct HvCallPci_DeviceInfo)); + if (HvRc == 0) { + if (DevInfo->deviceType == HvCallPci_NodeDevice) + scan_EADS_bridge(bus, SubBus, IdSel); + else + printk("PCI: Invalid System Configuration(0x%02X)" + " for bus 0x%02x id 0x%02x.\n", + DevInfo->deviceType, bus, IdSel); + } + else + pci_Log_Error("getDeviceInfo", bus, SubBus, IdSel, HvRc); + } + kfree(DevInfo); +} + +static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus, + int IdSel) +{ + struct HvCallPci_BridgeInfo *BridgeInfo; + HvAgentId AgentId; + int Function; + int HvRc; + + BridgeInfo = (struct HvCallPci_BridgeInfo *) + kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL); + if (BridgeInfo == NULL) + return; + + /* Note: hvSubBus and irq is always be 0 at this level! */ + for (Function = 0; Function < 8; ++Function) { + AgentId = ISERIES_PCI_AGENTID(IdSel, Function); + HvRc = HvCallXm_connectBusUnit(bus, SubBus, AgentId, 0); + if (HvRc == 0) { + printk("found device at bus %d idsel %d func %d (AgentId %x)\n", + bus, IdSel, Function, AgentId); + /* Connect EADs: 0x18.00.12 = 0x00 */ + PPCDBG(PPCDBG_BUSWALK, + "PCI:Connect EADs: 0x%02X.%02X.%02X\n", + bus, SubBus, AgentId); + HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId, + ISERIES_HV_ADDR(BridgeInfo), + sizeof(struct HvCallPci_BridgeInfo)); + if (HvRc == 0) { + printk("bridge info: type %x subbus %x maxAgents %x maxsubbus %x logslot %x\n", + BridgeInfo->busUnitInfo.deviceType, + BridgeInfo->subBusNumber, + BridgeInfo->maxAgents, + BridgeInfo->maxSubBusNumber, + BridgeInfo->logicalSlotNumber); + PPCDBG(PPCDBG_BUSWALK, + "PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n", + BridgeInfo->busUnitInfo.deviceType, + BridgeInfo->subBusNumber, + BridgeInfo->maxAgents, + BridgeInfo->maxSubBusNumber, + BridgeInfo->logicalSlotNumber); + + if (BridgeInfo->busUnitInfo.deviceType == + HvCallPci_BridgeDevice) { + /* Scan_Bridge_Slot...: 0x18.00.12 */ + scan_bridge_slot(bus, BridgeInfo); + } else + printk("PCI: Invalid Bridge Configuration(0x%02X)", + BridgeInfo->busUnitInfo.deviceType); + } + } else if (HvRc != 0x000B) + pci_Log_Error("EADs Connect", + bus, SubBus, AgentId, HvRc); + } + kfree(BridgeInfo); +} + +/* + * This assumes that the node slot is always on the primary bus! + */ +static int scan_bridge_slot(HvBusNumber Bus, + struct HvCallPci_BridgeInfo *BridgeInfo) +{ + struct iSeries_Device_Node *node; + HvSubBusNumber SubBus = BridgeInfo->subBusNumber; + u16 VendorId = 0; + int HvRc = 0; + u8 Irq = 0; + int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus); + int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus); + HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function); + + /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */ + Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel); + PPCDBG(PPCDBG_BUSWALK, + "PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n", + Bus, 0, EADsIdSel, Irq); + + /* + * Connect all functions of any device found. + */ + for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) { + for (Function = 0; Function < 8; ++Function) { + HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function); + HvRc = HvCallXm_connectBusUnit(Bus, SubBus, + AgentId, Irq); + if (HvRc != 0) { + pci_Log_Error("Connect Bus Unit", + Bus, SubBus, AgentId, HvRc); + continue; + } + + HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId, + PCI_VENDOR_ID, &VendorId); + if (HvRc != 0) { + pci_Log_Error("Read Vendor", + Bus, SubBus, AgentId, HvRc); + continue; + } + printk("read vendor ID: %x\n", VendorId); + + /* FoundDevice: 0x18.28.10 = 0x12AE */ + PPCDBG(PPCDBG_BUSWALK, + "PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X, irq %d\n", + Bus, SubBus, AgentId, VendorId, Irq); + HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId, + PCI_INTERRUPT_LINE, Irq); + if (HvRc != 0) + pci_Log_Error("PciCfgStore Irq Failed!", + Bus, SubBus, AgentId, HvRc); + + ++DeviceCount; + node = build_device_node(Bus, SubBus, EADsIdSel, Function); + node->Irq = Irq; + node->LogicalSlot = BridgeInfo->logicalSlotNumber; + + } /* for (Function = 0; Function < 8; ++Function) */ + } /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */ + return HvRc; +} + +/* + * I/0 Memory copy MUST use mmio commands on iSeries + * To do; For performance, include the hv call directly + */ +void iSeries_memset_io(volatile void __iomem *dest, char c, size_t Count) +{ + u8 ByteValue = c; + long NumberOfBytes = Count; + + while (NumberOfBytes > 0) { + iSeries_Write_Byte(ByteValue, dest++); + -- NumberOfBytes; + } +} +EXPORT_SYMBOL(iSeries_memset_io); + +void iSeries_memcpy_toio(volatile void __iomem *dest, void *source, size_t count) +{ + char *src = source; + long NumberOfBytes = count; + + while (NumberOfBytes > 0) { + iSeries_Write_Byte(*src++, dest++); + -- NumberOfBytes; + } +} +EXPORT_SYMBOL(iSeries_memcpy_toio); + +void iSeries_memcpy_fromio(void *dest, const volatile void __iomem *src, size_t count) +{ + char *dst = dest; + long NumberOfBytes = count; + + while (NumberOfBytes > 0) { + *dst++ = iSeries_Read_Byte(src++); + -- NumberOfBytes; + } +} +EXPORT_SYMBOL(iSeries_memcpy_fromio); + +/* + * Look down the chain to find the matching Device Device + */ +static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn) +{ + struct list_head *pos; + + list_for_each(pos, &iSeries_Global_Device_List) { + struct iSeries_Device_Node *node = + list_entry(pos, struct iSeries_Device_Node, Device_List); + + if ((bus == ISERIES_BUS(node)) && (devfn == node->DevFn)) + return node; + } + return NULL; +} + +#if 0 +/* + * Returns the device node for the passed pci_dev + * Sanity Check Node PciDev to passed pci_dev + * If none is found, returns a NULL which the client must handle. + */ +static struct iSeries_Device_Node *get_Device_Node(struct pci_dev *pdev) +{ + struct iSeries_Device_Node *node; + + node = pdev->sysdata; + if (node == NULL || node->PciDev != pdev) + node = find_Device_Node(pdev->bus->number, pdev->devfn); + return node; +} +#endif + +/* + * Config space read and write functions. + * For now at least, we look for the device node for the bus and devfn + * that we are asked to access. It may be possible to translate the devfn + * to a subbus and deviceid more directly. + */ +static u64 hv_cfg_read_func[4] = { + HvCallPciConfigLoad8, HvCallPciConfigLoad16, + HvCallPciConfigLoad32, HvCallPciConfigLoad32 +}; + +static u64 hv_cfg_write_func[4] = { + HvCallPciConfigStore8, HvCallPciConfigStore16, + HvCallPciConfigStore32, HvCallPciConfigStore32 +}; + +/* + * Read PCI config space + */ +static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int size, u32 *val) +{ + struct iSeries_Device_Node *node = find_Device_Node(bus->number, devfn); + u64 fn; + struct HvCallPci_LoadReturn ret; + + if (node == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset > 255) { + *val = ~0; + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + fn = hv_cfg_read_func[(size - 1) & 3]; + HvCall3Ret16(fn, &ret, node->DsaAddr.DsaAddr, offset, 0); + + if (ret.rc != 0) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; /* or something */ + } + + *val = ret.value; + return 0; +} + +/* + * Write PCI config space + */ + +static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, + int offset, int size, u32 val) +{ + struct iSeries_Device_Node *node = find_Device_Node(bus->number, devfn); + u64 fn; + u64 ret; + + if (node == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset > 255) + return PCIBIOS_BAD_REGISTER_NUMBER; + + fn = hv_cfg_write_func[(size - 1) & 3]; + ret = HvCall4(fn, node->DsaAddr.DsaAddr, offset, val, 0); + + if (ret != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + return 0; +} + +static struct pci_ops iSeries_pci_ops = { + .read = iSeries_pci_read_config, + .write = iSeries_pci_write_config +}; + +/* + * Check Return Code + * -> On Failure, print and log information. + * Increment Retry Count, if exceeds max, panic partition. + * + * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234 + * PCI: Device 23.90 ReadL Retry( 1) + * PCI: Device 23.90 ReadL Retry Successful(1) + */ +static int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode, + int *retry, u64 ret) +{ + if (ret != 0) { + ++Pci_Error_Count; + (*retry)++; + printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", + TextHdr, DevNode->DsaAddr.Dsa.busNumber, DevNode->DevFn, + *retry, (int)ret); + /* + * Bump the retry and check for retry count exceeded. + * If, Exceeded, panic the system. + */ + if (((*retry) > Pci_Retry_Max) && + (Pci_Error_Flag > 0)) { + mf_display_src(0xB6000103); + panic_timeout = 0; + panic("PCI: Hardware I/O Error, SRC B6000103, " + "Automatic Reboot Disabled.\n"); + } + return -1; /* Retry Try */ + } + return 0; +} + +/* + * Translate the I/O Address into a device node, bar, and bar offset. + * Note: Make sure the passed variable end up on the stack to avoid + * the exposure of being device global. + */ +static inline struct iSeries_Device_Node *xlate_iomm_address( + const volatile void __iomem *IoAddress, + u64 *dsaptr, u64 *BarOffsetPtr) +{ + unsigned long OrigIoAddr; + unsigned long BaseIoAddr; + unsigned long TableIndex; + struct iSeries_Device_Node *DevNode; + + OrigIoAddr = (unsigned long __force)IoAddress; + if ((OrigIoAddr < BASE_IO_MEMORY) || (OrigIoAddr >= max_io_memory)) + return NULL; + BaseIoAddr = OrigIoAddr - BASE_IO_MEMORY; + TableIndex = BaseIoAddr / IOMM_TABLE_ENTRY_SIZE; + DevNode = iomm_table[TableIndex]; + + if (DevNode != NULL) { + int barnum = iobar_table[TableIndex]; + *dsaptr = DevNode->DsaAddr.DsaAddr | (barnum << 24); + *BarOffsetPtr = BaseIoAddr % IOMM_TABLE_ENTRY_SIZE; + } else + panic("PCI: Invalid PCI IoAddress detected!\n"); + return DevNode; +} + +/* + * Read MM I/O Instructions for the iSeries + * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal + * else, data is returned in big Endian format. + * + * iSeries_Read_Byte = Read Byte ( 8 bit) + * iSeries_Read_Word = Read Word (16 bit) + * iSeries_Read_Long = Read Long (32 bit) + */ +u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress) +{ + u64 BarOffset; + u64 dsa; + int retry = 0; + struct HvCallPci_LoadReturn ret; + struct iSeries_Device_Node *DevNode = + xlate_iomm_address(IoAddress, &dsa, &BarOffset); + + if (DevNode == NULL) { + static unsigned long last_jiffies; + static int num_printed; + + if ((jiffies - last_jiffies) > 60 * HZ) { + last_jiffies = jiffies; + num_printed = 0; + } + if (num_printed++ < 10) + printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n", IoAddress); + return 0xff; + } + do { + ++Pci_Io_Read_Count; + HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0); + } while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0); + + return (u8)ret.value; +} +EXPORT_SYMBOL(iSeries_Read_Byte); + +u16 iSeries_Read_Word(const volatile void __iomem *IoAddress) +{ + u64 BarOffset; + u64 dsa; + int retry = 0; + struct HvCallPci_LoadReturn ret; + struct iSeries_Device_Node *DevNode = + xlate_iomm_address(IoAddress, &dsa, &BarOffset); + + if (DevNode == NULL) { + static unsigned long last_jiffies; + static int num_printed; + + if ((jiffies - last_jiffies) > 60 * HZ) { + last_jiffies = jiffies; + num_printed = 0; + } + if (num_printed++ < 10) + printk(KERN_ERR "iSeries_Read_Word: invalid access at IO address %p\n", IoAddress); + return 0xffff; + } + do { + ++Pci_Io_Read_Count; + HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa, + BarOffset, 0); + } while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0); + + return swab16((u16)ret.value); +} +EXPORT_SYMBOL(iSeries_Read_Word); + +u32 iSeries_Read_Long(const volatile void __iomem *IoAddress) +{ + u64 BarOffset; + u64 dsa; + int retry = 0; + struct HvCallPci_LoadReturn ret; + struct iSeries_Device_Node *DevNode = + xlate_iomm_address(IoAddress, &dsa, &BarOffset); + + if (DevNode == NULL) { + static unsigned long last_jiffies; + static int num_printed; + + if ((jiffies - last_jiffies) > 60 * HZ) { + last_jiffies = jiffies; + num_printed = 0; + } + if (num_printed++ < 10) + printk(KERN_ERR "iSeries_Read_Long: invalid access at IO address %p\n", IoAddress); + return 0xffffffff; + } + do { + ++Pci_Io_Read_Count; + HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa, + BarOffset, 0); + } while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0); + + return swab32((u32)ret.value); +} +EXPORT_SYMBOL(iSeries_Read_Long); + +/* + * Write MM I/O Instructions for the iSeries + * + * iSeries_Write_Byte = Write Byte (8 bit) + * iSeries_Write_Word = Write Word(16 bit) + * iSeries_Write_Long = Write Long(32 bit) + */ +void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress) +{ + u64 BarOffset; + u64 dsa; + int retry = 0; + u64 rc; + struct iSeries_Device_Node *DevNode = + xlate_iomm_address(IoAddress, &dsa, &BarOffset); + + if (DevNode == NULL) { + static unsigned long last_jiffies; + static int num_printed; + + if ((jiffies - last_jiffies) > 60 * HZ) { + last_jiffies = jiffies; + num_printed = 0; + } + if (num_printed++ < 10) + printk(KERN_ERR "iSeries_Write_Byte: invalid access at IO address %p\n", IoAddress); + return; + } + do { + ++Pci_Io_Write_Count; + rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0); + } while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0); +} +EXPORT_SYMBOL(iSeries_Write_Byte); + +void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress) +{ + u64 BarOffset; + u64 dsa; + int retry = 0; + u64 rc; + struct iSeries_Device_Node *DevNode = + xlate_iomm_address(IoAddress, &dsa, &BarOffset); + + if (DevNode == NULL) { + static unsigned long last_jiffies; + static int num_printed; + + if ((jiffies - last_jiffies) > 60 * HZ) { + last_jiffies = jiffies; + num_printed = 0; + } + if (num_printed++ < 10) + printk(KERN_ERR "iSeries_Write_Word: invalid access at IO address %p\n", IoAddress); + return; + } + do { + ++Pci_Io_Write_Count; + rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0); + } while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0); +} +EXPORT_SYMBOL(iSeries_Write_Word); + +void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress) +{ + u64 BarOffset; + u64 dsa; + int retry = 0; + u64 rc; + struct iSeries_Device_Node *DevNode = + xlate_iomm_address(IoAddress, &dsa, &BarOffset); + + if (DevNode == NULL) { + static unsigned long last_jiffies; + static int num_printed; + + if ((jiffies - last_jiffies) > 60 * HZ) { + last_jiffies = jiffies; + num_printed = 0; + } + if (num_printed++ < 10) + printk(KERN_ERR "iSeries_Write_Long: invalid access at IO address %p\n", IoAddress); + return; + } + do { + ++Pci_Io_Write_Count; + rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0); + } while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0); +} +EXPORT_SYMBOL(iSeries_Write_Long); diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 5988d555d36d..8473a8784567 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -16,7 +16,7 @@ obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o -pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_irq.o \ +pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ iSeries_VpdInfo.o pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o diff --git a/arch/ppc64/kernel/bpa_iommu.c b/arch/ppc64/kernel/bpa_iommu.c index f33a7bccb0d7..0cc463f24539 100644 --- a/arch/ppc64/kernel/bpa_iommu.c +++ b/arch/ppc64/kernel/bpa_iommu.c @@ -39,8 +39,8 @@ #include #include #include +#include -#include "pci.h" #include "bpa_iommu.h" static inline unsigned long diff --git a/arch/ppc64/kernel/bpa_setup.c b/arch/ppc64/kernel/bpa_setup.c index 57b3db66f458..9f915f4222b1 100644 --- a/arch/ppc64/kernel/bpa_setup.c +++ b/arch/ppc64/kernel/bpa_setup.c @@ -43,8 +43,8 @@ #include #include #include +#include -#include "pci.h" #include "bpa_iic.h" #include "bpa_iommu.h" diff --git a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c index ba93fd731222..035d1b14a207 100644 --- a/arch/ppc64/kernel/eeh.c +++ b/arch/ppc64/kernel/eeh.c @@ -33,7 +33,7 @@ #include #include #include -#include "pci.h" +#include #undef DEBUG diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c deleted file mode 100644 index fbc273c32bcc..000000000000 --- a/arch/ppc64/kernel/iSeries_pci.c +++ /dev/null @@ -1,905 +0,0 @@ -/* - * iSeries_pci.c - * - * Copyright (C) 2001 Allan Trautman, IBM Corporation - * - * iSeries specific routines for PCI. - * - * Based on code from pci.c and iSeries_pci.c 32bit - * - * 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 program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "pci.h" - -extern unsigned long io_page_mask; - -/* - * Forward declares of prototypes. - */ -static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn); -static void scan_PHB_slots(struct pci_controller *Phb); -static void scan_EADS_bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel); -static int scan_bridge_slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo *Info); - -LIST_HEAD(iSeries_Global_Device_List); - -static int DeviceCount; - -/* Counters and control flags. */ -static long Pci_Io_Read_Count; -static long Pci_Io_Write_Count; -#if 0 -static long Pci_Cfg_Read_Count; -static long Pci_Cfg_Write_Count; -#endif -static long Pci_Error_Count; - -static int Pci_Retry_Max = 3; /* Only retry 3 times */ -static int Pci_Error_Flag = 1; /* Set Retry Error on. */ - -static struct pci_ops iSeries_pci_ops; - -/* - * Table defines - * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space. - */ -#define IOMM_TABLE_MAX_ENTRIES 1024 -#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL -#define BASE_IO_MEMORY 0xE000000000000000UL - -static unsigned long max_io_memory = 0xE000000000000000UL; -static long current_iomm_table_entry; - -/* - * Lookup Tables. - */ -static struct iSeries_Device_Node **iomm_table; -static u8 *iobar_table; - -/* - * Static and Global variables - */ -static char *pci_io_text = "iSeries PCI I/O"; -static DEFINE_SPINLOCK(iomm_table_lock); - -/* - * iomm_table_initialize - * - * Allocates and initalizes the Address Translation Table and Bar - * Tables to get them ready for use. Must be called before any - * I/O space is handed out to the device BARs. - */ -static void iomm_table_initialize(void) -{ - spin_lock(&iomm_table_lock); - iomm_table = kmalloc(sizeof(*iomm_table) * IOMM_TABLE_MAX_ENTRIES, - GFP_KERNEL); - iobar_table = kmalloc(sizeof(*iobar_table) * IOMM_TABLE_MAX_ENTRIES, - GFP_KERNEL); - spin_unlock(&iomm_table_lock); - if ((iomm_table == NULL) || (iobar_table == NULL)) - panic("PCI: I/O tables allocation failed.\n"); -} - -/* - * iomm_table_allocate_entry - * - * Adds pci_dev entry in address translation table - * - * - Allocates the number of entries required in table base on BAR - * size. - * - Allocates starting at BASE_IO_MEMORY and increases. - * - The size is round up to be a multiple of entry size. - * - CurrentIndex is incremented to keep track of the last entry. - * - Builds the resource entry for allocated BARs. - */ -static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) -{ - struct resource *bar_res = &dev->resource[bar_num]; - long bar_size = pci_resource_len(dev, bar_num); - - /* - * No space to allocate, quick exit, skip Allocation. - */ - if (bar_size == 0) - return; - /* - * Set Resource values. - */ - spin_lock(&iomm_table_lock); - bar_res->name = pci_io_text; - bar_res->start = - IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; - bar_res->start += BASE_IO_MEMORY; - bar_res->end = bar_res->start + bar_size - 1; - /* - * Allocate the number of table entries needed for BAR. - */ - while (bar_size > 0 ) { - iomm_table[current_iomm_table_entry] = dev->sysdata; - iobar_table[current_iomm_table_entry] = bar_num; - bar_size -= IOMM_TABLE_ENTRY_SIZE; - ++current_iomm_table_entry; - } - max_io_memory = BASE_IO_MEMORY + - (IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry); - spin_unlock(&iomm_table_lock); -} - -/* - * allocate_device_bars - * - * - Allocates ALL pci_dev BAR's and updates the resources with the - * BAR value. BARS with zero length will have the resources - * The HvCallPci_getBarParms is used to get the size of the BAR - * space. It calls iomm_table_allocate_entry to allocate - * each entry. - * - Loops through The Bar resources(0 - 5) including the ROM - * is resource(6). - */ -static void allocate_device_bars(struct pci_dev *dev) -{ - struct resource *bar_res; - int bar_num; - - for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num) { - bar_res = &dev->resource[bar_num]; - iomm_table_allocate_entry(dev, bar_num); - } -} - -/* - * Log error information to system console. - * Filter out the device not there errors. - * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx - * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx - * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx - */ -static void pci_Log_Error(char *Error_Text, int Bus, int SubBus, - int AgentId, int HvRc) -{ - if (HvRc == 0x0302) - return; - printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X", - Error_Text, Bus, SubBus, AgentId, HvRc); -} - -/* - * build_device_node(u16 Bus, int SubBus, u8 DevFn) - */ -static struct iSeries_Device_Node *build_device_node(HvBusNumber Bus, - HvSubBusNumber SubBus, int AgentId, int Function) -{ - struct iSeries_Device_Node *node; - - PPCDBG(PPCDBG_BUSWALK, - "-build_device_node 0x%02X.%02X.%02X Function: %02X\n", - Bus, SubBus, AgentId, Function); - - node = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL); - if (node == NULL) - return NULL; - - memset(node, 0, sizeof(struct iSeries_Device_Node)); - list_add_tail(&node->Device_List, &iSeries_Global_Device_List); -#if 0 - node->DsaAddr = ((u64)Bus << 48) + ((u64)SubBus << 40) + ((u64)0x10 << 32); -#endif - node->DsaAddr.DsaAddr = 0; - node->DsaAddr.Dsa.busNumber = Bus; - node->DsaAddr.Dsa.subBusNumber = SubBus; - node->DsaAddr.Dsa.deviceId = 0x10; - node->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function); - return node; -} - -/* - * unsigned long __init find_and_init_phbs(void) - * - * Description: - * This function checks for all possible system PCI host bridges that connect - * PCI buses. The system hypervisor is queried as to the guest partition - * ownership status. A pci_controller is built for any bus which is partially - * owned or fully owned by this guest partition. - */ -unsigned long __init find_and_init_phbs(void) -{ - struct pci_controller *phb; - HvBusNumber bus; - - PPCDBG(PPCDBG_BUSWALK, "find_and_init_phbs Entry\n"); - - /* Check all possible buses. */ - for (bus = 0; bus < 256; bus++) { - int ret = HvCallXm_testBus(bus); - if (ret == 0) { - printk("bus %d appears to exist\n", bus); - - phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), GFP_KERNEL); - if (phb == NULL) - return -ENOMEM; - pci_setup_pci_controller(phb); - - phb->pci_mem_offset = phb->local_number = bus; - phb->first_busno = bus; - phb->last_busno = bus; - phb->ops = &iSeries_pci_ops; - - PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n", - phb, bus); - - /* Find and connect the devices. */ - scan_PHB_slots(phb); - } - /* - * Check for Unexpected Return code, a clue that something - * has gone wrong. - */ - else if (ret != 0x0301) - printk(KERN_ERR "Unexpected Return on Probe(0x%04X): 0x%04X", - bus, ret); - } - return 0; -} - -/* - * iSeries_pcibios_init - * - * Chance to initialize and structures or variable before PCI Bus walk. - */ -void iSeries_pcibios_init(void) -{ - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Entry.\n"); - iomm_table_initialize(); - find_and_init_phbs(); - io_page_mask = -1; - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Exit.\n"); -} - -/* - * iSeries_pci_final_fixup(void) - */ -void __init iSeries_pci_final_fixup(void) -{ - struct pci_dev *pdev = NULL; - struct iSeries_Device_Node *node; - int DeviceCount = 0; - - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n"); - - /* Fix up at the device node and pci_dev relationship */ - mf_display_src(0xC9000100); - - printk("pcibios_final_fixup\n"); - for_each_pci_dev(pdev) { - node = find_Device_Node(pdev->bus->number, pdev->devfn); - printk("pci dev %p (%x.%x), node %p\n", pdev, - pdev->bus->number, pdev->devfn, node); - - if (node != NULL) { - ++DeviceCount; - pdev->sysdata = (void *)node; - node->PciDev = pdev; - PPCDBG(PPCDBG_BUSWALK, - "pdev 0x%p <==> DevNode 0x%p\n", - pdev, node); - allocate_device_bars(pdev); - iSeries_Device_Information(pdev, DeviceCount); - iommu_devnode_init_iSeries(node); - } else - printk("PCI: Device Tree not found for 0x%016lX\n", - (unsigned long)pdev); - pdev->irq = node->Irq; - } - iSeries_activate_IRQs(); - mf_display_src(0xC9000200); -} - -void pcibios_fixup_bus(struct pci_bus *PciBus) -{ - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup_bus(0x%04X) Entry.\n", - PciBus->number); -} - -void pcibios_fixup_resources(struct pci_dev *pdev) -{ - PPCDBG(PPCDBG_BUSWALK, "fixup_resources pdev %p\n", pdev); -} - -/* - * Loop through each node function to find usable EADs bridges. - */ -static void scan_PHB_slots(struct pci_controller *Phb) -{ - struct HvCallPci_DeviceInfo *DevInfo; - HvBusNumber bus = Phb->local_number; /* System Bus */ - const HvSubBusNumber SubBus = 0; /* EADs is always 0. */ - int HvRc = 0; - int IdSel; - const int MaxAgents = 8; - - DevInfo = (struct HvCallPci_DeviceInfo*) - kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL); - if (DevInfo == NULL) - return; - - /* - * Probe for EADs Bridges - */ - for (IdSel = 1; IdSel < MaxAgents; ++IdSel) { - HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel, - ISERIES_HV_ADDR(DevInfo), - sizeof(struct HvCallPci_DeviceInfo)); - if (HvRc == 0) { - if (DevInfo->deviceType == HvCallPci_NodeDevice) - scan_EADS_bridge(bus, SubBus, IdSel); - else - printk("PCI: Invalid System Configuration(0x%02X)" - " for bus 0x%02x id 0x%02x.\n", - DevInfo->deviceType, bus, IdSel); - } - else - pci_Log_Error("getDeviceInfo", bus, SubBus, IdSel, HvRc); - } - kfree(DevInfo); -} - -static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus, - int IdSel) -{ - struct HvCallPci_BridgeInfo *BridgeInfo; - HvAgentId AgentId; - int Function; - int HvRc; - - BridgeInfo = (struct HvCallPci_BridgeInfo *) - kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL); - if (BridgeInfo == NULL) - return; - - /* Note: hvSubBus and irq is always be 0 at this level! */ - for (Function = 0; Function < 8; ++Function) { - AgentId = ISERIES_PCI_AGENTID(IdSel, Function); - HvRc = HvCallXm_connectBusUnit(bus, SubBus, AgentId, 0); - if (HvRc == 0) { - printk("found device at bus %d idsel %d func %d (AgentId %x)\n", - bus, IdSel, Function, AgentId); - /* Connect EADs: 0x18.00.12 = 0x00 */ - PPCDBG(PPCDBG_BUSWALK, - "PCI:Connect EADs: 0x%02X.%02X.%02X\n", - bus, SubBus, AgentId); - HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId, - ISERIES_HV_ADDR(BridgeInfo), - sizeof(struct HvCallPci_BridgeInfo)); - if (HvRc == 0) { - printk("bridge info: type %x subbus %x maxAgents %x maxsubbus %x logslot %x\n", - BridgeInfo->busUnitInfo.deviceType, - BridgeInfo->subBusNumber, - BridgeInfo->maxAgents, - BridgeInfo->maxSubBusNumber, - BridgeInfo->logicalSlotNumber); - PPCDBG(PPCDBG_BUSWALK, - "PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n", - BridgeInfo->busUnitInfo.deviceType, - BridgeInfo->subBusNumber, - BridgeInfo->maxAgents, - BridgeInfo->maxSubBusNumber, - BridgeInfo->logicalSlotNumber); - - if (BridgeInfo->busUnitInfo.deviceType == - HvCallPci_BridgeDevice) { - /* Scan_Bridge_Slot...: 0x18.00.12 */ - scan_bridge_slot(bus, BridgeInfo); - } else - printk("PCI: Invalid Bridge Configuration(0x%02X)", - BridgeInfo->busUnitInfo.deviceType); - } - } else if (HvRc != 0x000B) - pci_Log_Error("EADs Connect", - bus, SubBus, AgentId, HvRc); - } - kfree(BridgeInfo); -} - -/* - * This assumes that the node slot is always on the primary bus! - */ -static int scan_bridge_slot(HvBusNumber Bus, - struct HvCallPci_BridgeInfo *BridgeInfo) -{ - struct iSeries_Device_Node *node; - HvSubBusNumber SubBus = BridgeInfo->subBusNumber; - u16 VendorId = 0; - int HvRc = 0; - u8 Irq = 0; - int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus); - int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus); - HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function); - - /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */ - Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel); - PPCDBG(PPCDBG_BUSWALK, - "PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n", - Bus, 0, EADsIdSel, Irq); - - /* - * Connect all functions of any device found. - */ - for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) { - for (Function = 0; Function < 8; ++Function) { - HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function); - HvRc = HvCallXm_connectBusUnit(Bus, SubBus, - AgentId, Irq); - if (HvRc != 0) { - pci_Log_Error("Connect Bus Unit", - Bus, SubBus, AgentId, HvRc); - continue; - } - - HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId, - PCI_VENDOR_ID, &VendorId); - if (HvRc != 0) { - pci_Log_Error("Read Vendor", - Bus, SubBus, AgentId, HvRc); - continue; - } - printk("read vendor ID: %x\n", VendorId); - - /* FoundDevice: 0x18.28.10 = 0x12AE */ - PPCDBG(PPCDBG_BUSWALK, - "PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X, irq %d\n", - Bus, SubBus, AgentId, VendorId, Irq); - HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId, - PCI_INTERRUPT_LINE, Irq); - if (HvRc != 0) - pci_Log_Error("PciCfgStore Irq Failed!", - Bus, SubBus, AgentId, HvRc); - - ++DeviceCount; - node = build_device_node(Bus, SubBus, EADsIdSel, Function); - node->Irq = Irq; - node->LogicalSlot = BridgeInfo->logicalSlotNumber; - - } /* for (Function = 0; Function < 8; ++Function) */ - } /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */ - return HvRc; -} - -/* - * I/0 Memory copy MUST use mmio commands on iSeries - * To do; For performance, include the hv call directly - */ -void iSeries_memset_io(volatile void __iomem *dest, char c, size_t Count) -{ - u8 ByteValue = c; - long NumberOfBytes = Count; - - while (NumberOfBytes > 0) { - iSeries_Write_Byte(ByteValue, dest++); - -- NumberOfBytes; - } -} -EXPORT_SYMBOL(iSeries_memset_io); - -void iSeries_memcpy_toio(volatile void __iomem *dest, void *source, size_t count) -{ - char *src = source; - long NumberOfBytes = count; - - while (NumberOfBytes > 0) { - iSeries_Write_Byte(*src++, dest++); - -- NumberOfBytes; - } -} -EXPORT_SYMBOL(iSeries_memcpy_toio); - -void iSeries_memcpy_fromio(void *dest, const volatile void __iomem *src, size_t count) -{ - char *dst = dest; - long NumberOfBytes = count; - - while (NumberOfBytes > 0) { - *dst++ = iSeries_Read_Byte(src++); - -- NumberOfBytes; - } -} -EXPORT_SYMBOL(iSeries_memcpy_fromio); - -/* - * Look down the chain to find the matching Device Device - */ -static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn) -{ - struct list_head *pos; - - list_for_each(pos, &iSeries_Global_Device_List) { - struct iSeries_Device_Node *node = - list_entry(pos, struct iSeries_Device_Node, Device_List); - - if ((bus == ISERIES_BUS(node)) && (devfn == node->DevFn)) - return node; - } - return NULL; -} - -#if 0 -/* - * Returns the device node for the passed pci_dev - * Sanity Check Node PciDev to passed pci_dev - * If none is found, returns a NULL which the client must handle. - */ -static struct iSeries_Device_Node *get_Device_Node(struct pci_dev *pdev) -{ - struct iSeries_Device_Node *node; - - node = pdev->sysdata; - if (node == NULL || node->PciDev != pdev) - node = find_Device_Node(pdev->bus->number, pdev->devfn); - return node; -} -#endif - -/* - * Config space read and write functions. - * For now at least, we look for the device node for the bus and devfn - * that we are asked to access. It may be possible to translate the devfn - * to a subbus and deviceid more directly. - */ -static u64 hv_cfg_read_func[4] = { - HvCallPciConfigLoad8, HvCallPciConfigLoad16, - HvCallPciConfigLoad32, HvCallPciConfigLoad32 -}; - -static u64 hv_cfg_write_func[4] = { - HvCallPciConfigStore8, HvCallPciConfigStore16, - HvCallPciConfigStore32, HvCallPciConfigStore32 -}; - -/* - * Read PCI config space - */ -static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int size, u32 *val) -{ - struct iSeries_Device_Node *node = find_Device_Node(bus->number, devfn); - u64 fn; - struct HvCallPci_LoadReturn ret; - - if (node == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset > 255) { - *val = ~0; - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - fn = hv_cfg_read_func[(size - 1) & 3]; - HvCall3Ret16(fn, &ret, node->DsaAddr.DsaAddr, offset, 0); - - if (ret.rc != 0) { - *val = ~0; - return PCIBIOS_DEVICE_NOT_FOUND; /* or something */ - } - - *val = ret.value; - return 0; -} - -/* - * Write PCI config space - */ - -static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int size, u32 val) -{ - struct iSeries_Device_Node *node = find_Device_Node(bus->number, devfn); - u64 fn; - u64 ret; - - if (node == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset > 255) - return PCIBIOS_BAD_REGISTER_NUMBER; - - fn = hv_cfg_write_func[(size - 1) & 3]; - ret = HvCall4(fn, node->DsaAddr.DsaAddr, offset, val, 0); - - if (ret != 0) - return PCIBIOS_DEVICE_NOT_FOUND; - - return 0; -} - -static struct pci_ops iSeries_pci_ops = { - .read = iSeries_pci_read_config, - .write = iSeries_pci_write_config -}; - -/* - * Check Return Code - * -> On Failure, print and log information. - * Increment Retry Count, if exceeds max, panic partition. - * - * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234 - * PCI: Device 23.90 ReadL Retry( 1) - * PCI: Device 23.90 ReadL Retry Successful(1) - */ -static int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode, - int *retry, u64 ret) -{ - if (ret != 0) { - ++Pci_Error_Count; - (*retry)++; - printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", - TextHdr, DevNode->DsaAddr.Dsa.busNumber, DevNode->DevFn, - *retry, (int)ret); - /* - * Bump the retry and check for retry count exceeded. - * If, Exceeded, panic the system. - */ - if (((*retry) > Pci_Retry_Max) && - (Pci_Error_Flag > 0)) { - mf_display_src(0xB6000103); - panic_timeout = 0; - panic("PCI: Hardware I/O Error, SRC B6000103, " - "Automatic Reboot Disabled.\n"); - } - return -1; /* Retry Try */ - } - return 0; -} - -/* - * Translate the I/O Address into a device node, bar, and bar offset. - * Note: Make sure the passed variable end up on the stack to avoid - * the exposure of being device global. - */ -static inline struct iSeries_Device_Node *xlate_iomm_address( - const volatile void __iomem *IoAddress, - u64 *dsaptr, u64 *BarOffsetPtr) -{ - unsigned long OrigIoAddr; - unsigned long BaseIoAddr; - unsigned long TableIndex; - struct iSeries_Device_Node *DevNode; - - OrigIoAddr = (unsigned long __force)IoAddress; - if ((OrigIoAddr < BASE_IO_MEMORY) || (OrigIoAddr >= max_io_memory)) - return NULL; - BaseIoAddr = OrigIoAddr - BASE_IO_MEMORY; - TableIndex = BaseIoAddr / IOMM_TABLE_ENTRY_SIZE; - DevNode = iomm_table[TableIndex]; - - if (DevNode != NULL) { - int barnum = iobar_table[TableIndex]; - *dsaptr = DevNode->DsaAddr.DsaAddr | (barnum << 24); - *BarOffsetPtr = BaseIoAddr % IOMM_TABLE_ENTRY_SIZE; - } else - panic("PCI: Invalid PCI IoAddress detected!\n"); - return DevNode; -} - -/* - * Read MM I/O Instructions for the iSeries - * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal - * else, data is returned in big Endian format. - * - * iSeries_Read_Byte = Read Byte ( 8 bit) - * iSeries_Read_Word = Read Word (16 bit) - * iSeries_Read_Long = Read Long (32 bit) - */ -u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - struct HvCallPci_LoadReturn ret; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n", IoAddress); - return 0xff; - } - do { - ++Pci_Io_Read_Count; - HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0); - } while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0); - - return (u8)ret.value; -} -EXPORT_SYMBOL(iSeries_Read_Byte); - -u16 iSeries_Read_Word(const volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - struct HvCallPci_LoadReturn ret; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Read_Word: invalid access at IO address %p\n", IoAddress); - return 0xffff; - } - do { - ++Pci_Io_Read_Count; - HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa, - BarOffset, 0); - } while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0); - - return swab16((u16)ret.value); -} -EXPORT_SYMBOL(iSeries_Read_Word); - -u32 iSeries_Read_Long(const volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - struct HvCallPci_LoadReturn ret; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Read_Long: invalid access at IO address %p\n", IoAddress); - return 0xffffffff; - } - do { - ++Pci_Io_Read_Count; - HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa, - BarOffset, 0); - } while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0); - - return swab32((u32)ret.value); -} -EXPORT_SYMBOL(iSeries_Read_Long); - -/* - * Write MM I/O Instructions for the iSeries - * - * iSeries_Write_Byte = Write Byte (8 bit) - * iSeries_Write_Word = Write Word(16 bit) - * iSeries_Write_Long = Write Long(32 bit) - */ -void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - u64 rc; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Write_Byte: invalid access at IO address %p\n", IoAddress); - return; - } - do { - ++Pci_Io_Write_Count; - rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0); - } while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0); -} -EXPORT_SYMBOL(iSeries_Write_Byte); - -void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - u64 rc; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Write_Word: invalid access at IO address %p\n", IoAddress); - return; - } - do { - ++Pci_Io_Write_Count; - rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0); - } while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0); -} -EXPORT_SYMBOL(iSeries_Write_Word); - -void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - u64 rc; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Write_Long: invalid access at IO address %p\n", IoAddress); - return; - } - do { - ++Pci_Io_Write_Count; - rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0); - } while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0); -} -EXPORT_SYMBOL(iSeries_Write_Long); diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c index 1d297e0edfc0..0937649f4961 100644 --- a/arch/ppc64/kernel/maple_pci.c +++ b/arch/ppc64/kernel/maple_pci.c @@ -23,8 +23,7 @@ #include #include #include - -#include "pci.h" +#include #ifdef DEBUG #define DBG(x...) printk(x) diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c index 5914f61a152e..9e90d41131d8 100644 --- a/arch/ppc64/kernel/pSeries_iommu.c +++ b/arch/ppc64/kernel/pSeries_iommu.c @@ -47,7 +47,7 @@ #include #include #include -#include "pci.h" +#include #define DBG(fmt...) diff --git a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c index 1f5f141fb7a1..2dd477eb1c53 100644 --- a/arch/ppc64/kernel/pSeries_pci.c +++ b/arch/ppc64/kernel/pSeries_pci.c @@ -29,8 +29,7 @@ #include #include - -#include "pci.h" +#include static int __initdata s7a_workaround = -1; diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index b9bcff21b463..5a9fe96f9f67 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -63,9 +63,9 @@ #include #include #include +#include #include "i8259.h" -#include "pci.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index ff4be1da69d5..feec06bbafc3 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -31,8 +31,7 @@ #include #include #include - -#include "pci.h" +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/ppc64/kernel/pci.h b/arch/ppc64/kernel/pci.h deleted file mode 100644 index 5eb2cc320566..000000000000 --- a/arch/ppc64/kernel/pci.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM Corp - * - * 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. - */ -#ifndef __PPC_KERNEL_PCI_H__ -#define __PPC_KERNEL_PCI_H__ - -#include -#include - -extern unsigned long isa_io_base; - -extern void pci_setup_pci_controller(struct pci_controller *hose); -extern void pci_setup_phb_io(struct pci_controller *hose, int primary); -extern void pci_setup_phb_io_dynamic(struct pci_controller *hose, int primary); - - -extern struct list_head hose_list; -extern int global_phb_number; - -extern unsigned long find_and_init_phbs(void); - -extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */ - -/* PCI device_node operations */ -struct device_node; -typedef void *(*traverse_func)(struct device_node *me, void *data); -void *traverse_pci_devices(struct device_node *start, traverse_func pre, - void *data); - -void pci_devs_phb_init(void); -void pci_devs_phb_init_dynamic(struct pci_controller *phb); - -/* PCI address cache management routines */ -void pci_addr_cache_insert_device(struct pci_dev *dev); -void pci_addr_cache_remove_device(struct pci_dev *dev); - -/* From rtas_pci.h */ -void init_pci_config_tokens (void); -unsigned long get_phb_buid (struct device_node *); - -/* From pSeries_pci.h */ -extern void pSeries_final_fixup(void); -extern void pSeries_irq_bus_setup(struct pci_bus *bus); - -extern unsigned long pci_probe_only; -extern unsigned long pci_assign_all_buses; -extern int pci_read_irq_line(struct pci_dev *pci_dev); - -#endif /* __PPC_KERNEL_PCI_H__ */ diff --git a/arch/ppc64/kernel/pci_direct_iommu.c b/arch/ppc64/kernel/pci_direct_iommu.c index b8f7f58824f4..57980a5674d7 100644 --- a/arch/ppc64/kernel/pci_direct_iommu.c +++ b/arch/ppc64/kernel/pci_direct_iommu.c @@ -27,8 +27,7 @@ #include #include #include - -#include "pci.h" +#include static void *pci_direct_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, unsigned int __nocast flag) diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c index a86389d07d57..493bbe43f5b4 100644 --- a/arch/ppc64/kernel/pci_dn.c +++ b/arch/ppc64/kernel/pci_dn.c @@ -30,8 +30,7 @@ #include #include #include - -#include "pci.h" +#include /* * Traverse_func that inits the PCI fields of the device node. diff --git a/arch/ppc64/kernel/pci_iommu.c b/arch/ppc64/kernel/pci_iommu.c index 14647e09c9cd..19362ea11572 100644 --- a/arch/ppc64/kernel/pci_iommu.c +++ b/arch/ppc64/kernel/pci_iommu.c @@ -37,7 +37,7 @@ #include #include #include -#include "pci.h" +#include #ifdef CONFIG_PPC_ISERIES #include diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c index 1f61aa4746ec..f139fc034199 100644 --- a/arch/ppc64/kernel/pmac_pci.c +++ b/arch/ppc64/kernel/pmac_pci.c @@ -27,8 +27,8 @@ #include #include #include +#include -#include "pci.h" #include "pmac.h" #define DEBUG diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c index 4d920dd41dc6..20361bcd8cfb 100644 --- a/arch/ppc64/kernel/rtas_pci.c +++ b/arch/ppc64/kernel/rtas_pci.c @@ -39,8 +39,7 @@ #include #include #include - -#include "pci.h" +#include /* RTAS tokens */ static int read_pci_config; diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c index e93c13458910..1cacf61f9c91 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/ppc64/kernel/sys_ppc32.c @@ -53,8 +53,7 @@ #include #include #include - -#include "pci.h" +#include /* readdir & getdents */ #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) diff --git a/arch/ppc64/kernel/u3_iommu.c b/arch/ppc64/kernel/u3_iommu.c index df9c775f4955..fba871a1bda5 100644 --- a/arch/ppc64/kernel/u3_iommu.c +++ b/arch/ppc64/kernel/u3_iommu.c @@ -45,8 +45,7 @@ #include #include #include - -#include "pci.h" +#include extern int iommu_force_on; diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h new file mode 100644 index 000000000000..a88728fba8f6 --- /dev/null +++ b/include/asm-powerpc/ppc-pci.h @@ -0,0 +1,54 @@ +/* + * c 2001 PPC 64 Team, IBM Corp + * + * 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. + */ +#ifndef _ASM_POWERPC_PPC_PCI_H +#define _ASM_POWERPC_PPC_PCI_H + +#include +#include + +extern unsigned long isa_io_base; + +extern void pci_setup_pci_controller(struct pci_controller *hose); +extern void pci_setup_phb_io(struct pci_controller *hose, int primary); +extern void pci_setup_phb_io_dynamic(struct pci_controller *hose, int primary); + + +extern struct list_head hose_list; +extern int global_phb_number; + +extern unsigned long find_and_init_phbs(void); + +extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */ + +/* PCI device_node operations */ +struct device_node; +typedef void *(*traverse_func)(struct device_node *me, void *data); +void *traverse_pci_devices(struct device_node *start, traverse_func pre, + void *data); + +void pci_devs_phb_init(void); +void pci_devs_phb_init_dynamic(struct pci_controller *phb); + +/* PCI address cache management routines */ +void pci_addr_cache_insert_device(struct pci_dev *dev); +void pci_addr_cache_remove_device(struct pci_dev *dev); + +/* From rtas_pci.h */ +void init_pci_config_tokens (void); +unsigned long get_phb_buid (struct device_node *); + +/* From pSeries_pci.h */ +extern void pSeries_final_fixup(void); +extern void pSeries_irq_bus_setup(struct pci_bus *bus); + +extern unsigned long pci_probe_only; +extern unsigned long pci_assign_all_buses; +extern int pci_read_irq_line(struct pci_dev *pci_dev); + +#endif /* _ASM_POWERPC_PPC_PCI_H */