|
@@ -49,14 +49,9 @@
|
|
* Forward declares of prototypes.
|
|
* Forward declares of prototypes.
|
|
*/
|
|
*/
|
|
static struct device_node *find_Device_Node(int bus, int devfn);
|
|
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);
|
|
LIST_HEAD(iSeries_Global_Device_List);
|
|
|
|
|
|
-static int DeviceCount;
|
|
|
|
-
|
|
|
|
static int Pci_Retry_Max = 3; /* Only retry 3 times */
|
|
static int Pci_Retry_Max = 3; /* Only retry 3 times */
|
|
static int Pci_Error_Flag = 1; /* Set Retry Error on. */
|
|
static int Pci_Error_Flag = 1; /* Set Retry Error on. */
|
|
|
|
|
|
@@ -161,32 +156,6 @@ static void pci_Log_Error(char *Error_Text, int Bus, int SubBus,
|
|
Error_Text, Bus, SubBus, AgentId, HvRc);
|
|
Error_Text, Bus, SubBus, AgentId, HvRc);
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * 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
|
|
* iSeries_pcibios_init
|
|
*
|
|
*
|
|
@@ -199,33 +168,86 @@ static struct device_node *build_device_node(HvBusNumber Bus,
|
|
void iSeries_pcibios_init(void)
|
|
void iSeries_pcibios_init(void)
|
|
{
|
|
{
|
|
struct pci_controller *phb;
|
|
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);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -271,147 +293,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
|
|
* I/0 Memory copy MUST use mmio commands on iSeries
|
|
* To do; For performance, include the hv call directly
|
|
* To do; For performance, include the hv call directly
|