aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/iseries/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/iseries/pci.c')
-rw-r--r--arch/powerpc/platforms/iseries/pci.c273
1 files changed, 77 insertions, 196 deletions
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 91a94747eda..9d571e74909 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -49,14 +49,9 @@
* Forward declares of prototypes.
*/
static struct 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;
-
static int Pci_Retry_Max = 3; /* Only retry 3 times */
static int Pci_Error_Flag = 1; /* Set Retry Error on. */
@@ -162,32 +157,6 @@ static void pci_Log_Error(char *Error_Text, int Bus, int SubBus,
}
/*
- * build_device_node(u16 Bus, int SubBus, u8 DevFn)
- */
-static struct device_node *build_device_node(HvBusNumber Bus,
- HvSubBusNumber SubBus, int AgentId, int Function)
-{
- struct device_node *node;
- struct pci_dn *pdn;
-
- node = kzalloc(sizeof(struct device_node), GFP_KERNEL);
- if (node == NULL)
- return NULL;
- pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
- if (pdn == NULL) {
- kfree(node);
- return NULL;
- }
- node->data = pdn;
- pdn->node = node;
- list_add_tail(&pdn->Device_List, &iSeries_Global_Device_List);
- pdn->busno = Bus;
- pdn->bussubno = SubBus;
- pdn->devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function);
- return node;
-}
-
-/*
* iSeries_pcibios_init
*
* Description:
@@ -199,33 +168,86 @@ static struct device_node *build_device_node(HvBusNumber Bus,
void iSeries_pcibios_init(void)
{
struct pci_controller *phb;
- HvBusNumber bus;
-
- /* 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 = pcibios_alloc_controller(NULL);
- if (phb == NULL)
- return -ENOMEM;
+ struct device_node *node;
+ struct device_node *dn;
+
+ for_each_node_by_type(node, "pci") {
+ HvBusNumber bus;
+ u32 *busp;
+
+ busp = (u32 *)get_property(node, "bus-range", NULL);
+ if (busp == NULL)
+ continue;
+ bus = *busp;
+ printk("bus %d appears to exist\n", bus);
+ phb = pcibios_alloc_controller(node);
+ if (phb == NULL)
+ continue;
+
+ phb->pci_mem_offset = phb->local_number = bus;
+ phb->first_busno = bus;
+ phb->last_busno = bus;
+ phb->ops = &iSeries_pci_ops;
+
+ /* Find and connect the devices. */
+ for (dn = NULL; (dn = of_get_next_child(node, dn)) != NULL;) {
+ struct pci_dn *pdn;
+ u8 irq;
+ int err;
+ u32 *agent;
+ u32 *reg;
+ u32 *lsn;
+
+ reg = (u32 *)get_property(dn, "reg", NULL);
+ if (reg == NULL) {
+ printk(KERN_DEBUG "no reg property!\n");
+ continue;
+ }
+ busp = (u32 *)get_property(dn, "linux,subbus", NULL);
+ if (busp == NULL) {
+ printk(KERN_DEBUG "no subbus property!\n");
+ continue;
+ }
+ agent = (u32 *)get_property(dn, "linux,agent-id", NULL);
+ if (agent == NULL) {
+ printk(KERN_DEBUG "no agent-id\n");
+ continue;
+ }
+ lsn = (u32 *)get_property(dn,
+ "linux,logical-slot-number", NULL);
+ if (lsn == NULL) {
+ printk(KERN_DEBUG "no logical-slot-number\n");
+ continue;
+ }
- phb->pci_mem_offset = phb->local_number = bus;
- phb->first_busno = bus;
- phb->last_busno = bus;
- phb->ops = &iSeries_pci_ops;
+ irq = iSeries_allocate_IRQ(bus, 0, *busp);
+ err = HvCallXm_connectBusUnit(bus, *busp, *agent, irq);
+ if (err) {
+ pci_Log_Error("Connect Bus Unit",
+ bus, *busp, *agent, err);
+ continue;
+ }
+ err = HvCallPci_configStore8(bus, *busp, *agent,
+ PCI_INTERRUPT_LINE, irq);
+ if (err) {
+ pci_Log_Error("PciCfgStore Irq Failed!",
+ bus, *busp, *agent, err);
+ continue;
+ }
- /* Find and connect the devices. */
- scan_PHB_slots(phb);
+ pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
+ if (pdn == NULL)
+ return;
+ dn->data = pdn;
+ pdn->node = dn;
+ pdn->busno = bus;
+ pdn->devfn = (reg[0] >> 8) & 0xff;
+ pdn->bussubno = *busp;
+ pdn->Irq = irq;
+ pdn->LogicalSlot = *lsn;
+ list_add_tail(&pdn->Device_List,
+ &iSeries_Global_Device_List);
}
- /*
- * 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);
}
}
@@ -272,147 +294,6 @@ void pcibios_fixup_resources(struct pci_dev *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 = 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 */
- 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);
- 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 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);
-
- /*
- * 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 */
- 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);
- PCI_DN(node)->Irq = Irq;
- PCI_DN(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
*/