aboutsummaryrefslogtreecommitdiffstats
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 91a94747eda9..9d571e749098 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -49,14 +49,9 @@
49 * Forward declares of prototypes. 49 * Forward declares of prototypes.
50 */ 50 */
51static struct device_node *find_Device_Node(int bus, int devfn); 51static struct device_node *find_Device_Node(int bus, int devfn);
52static void scan_PHB_slots(struct pci_controller *Phb);
53static void scan_EADS_bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel);
54static int scan_bridge_slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo *Info);
55 52
56LIST_HEAD(iSeries_Global_Device_List); 53LIST_HEAD(iSeries_Global_Device_List);
57 54
58static int DeviceCount;
59
60static int Pci_Retry_Max = 3; /* Only retry 3 times */ 55static int Pci_Retry_Max = 3; /* Only retry 3 times */
61static int Pci_Error_Flag = 1; /* Set Retry Error on. */ 56static int Pci_Error_Flag = 1; /* Set Retry Error on. */
62 57
@@ -162,32 +157,6 @@ static void pci_Log_Error(char *Error_Text, int Bus, int SubBus,
162} 157}
163 158
164/* 159/*
165 * build_device_node(u16 Bus, int SubBus, u8 DevFn)
166 */
167static struct device_node *build_device_node(HvBusNumber Bus,
168 HvSubBusNumber SubBus, int AgentId, int Function)
169{
170 struct device_node *node;
171 struct pci_dn *pdn;
172
173 node = kzalloc(sizeof(struct device_node), GFP_KERNEL);
174 if (node == NULL)
175 return NULL;
176 pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
177 if (pdn == NULL) {
178 kfree(node);
179 return NULL;
180 }
181 node->data = pdn;
182 pdn->node = node;
183 list_add_tail(&pdn->Device_List, &iSeries_Global_Device_List);
184 pdn->busno = Bus;
185 pdn->bussubno = SubBus;
186 pdn->devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function);
187 return node;
188}
189
190/*
191 * iSeries_pcibios_init 160 * iSeries_pcibios_init
192 * 161 *
193 * Description: 162 * Description:
@@ -199,33 +168,86 @@ static struct device_node *build_device_node(HvBusNumber Bus,
199void iSeries_pcibios_init(void) 168void iSeries_pcibios_init(void)
200{ 169{
201 struct pci_controller *phb; 170 struct pci_controller *phb;
202 HvBusNumber bus; 171 struct device_node *node;
203 172 struct device_node *dn;
204 /* Check all possible buses. */ 173
205 for (bus = 0; bus < 256; bus++) { 174 for_each_node_by_type(node, "pci") {
206 int ret = HvCallXm_testBus(bus); 175 HvBusNumber bus;
207 if (ret == 0) { 176 u32 *busp;
208 printk("bus %d appears to exist\n", bus); 177
209 178 busp = (u32 *)get_property(node, "bus-range", NULL);
210 phb = pcibios_alloc_controller(NULL); 179 if (busp == NULL)
211 if (phb == NULL) 180 continue;
212 return -ENOMEM; 181 bus = *busp;
182 printk("bus %d appears to exist\n", bus);
183 phb = pcibios_alloc_controller(node);
184 if (phb == NULL)
185 continue;
186
187 phb->pci_mem_offset = phb->local_number = bus;
188 phb->first_busno = bus;
189 phb->last_busno = bus;
190 phb->ops = &iSeries_pci_ops;
191
192 /* Find and connect the devices. */
193 for (dn = NULL; (dn = of_get_next_child(node, dn)) != NULL;) {
194 struct pci_dn *pdn;
195 u8 irq;
196 int err;
197 u32 *agent;
198 u32 *reg;
199 u32 *lsn;
200
201 reg = (u32 *)get_property(dn, "reg", NULL);
202 if (reg == NULL) {
203 printk(KERN_DEBUG "no reg property!\n");
204 continue;
205 }
206 busp = (u32 *)get_property(dn, "linux,subbus", NULL);
207 if (busp == NULL) {
208 printk(KERN_DEBUG "no subbus property!\n");
209 continue;
210 }
211 agent = (u32 *)get_property(dn, "linux,agent-id", NULL);
212 if (agent == NULL) {
213 printk(KERN_DEBUG "no agent-id\n");
214 continue;
215 }
216 lsn = (u32 *)get_property(dn,
217 "linux,logical-slot-number", NULL);
218 if (lsn == NULL) {
219 printk(KERN_DEBUG "no logical-slot-number\n");
220 continue;
221 }
213 222
214 phb->pci_mem_offset = phb->local_number = bus; 223 irq = iSeries_allocate_IRQ(bus, 0, *busp);
215 phb->first_busno = bus; 224 err = HvCallXm_connectBusUnit(bus, *busp, *agent, irq);
216 phb->last_busno = bus; 225 if (err) {
217 phb->ops = &iSeries_pci_ops; 226 pci_Log_Error("Connect Bus Unit",
227 bus, *busp, *agent, err);
228 continue;
229 }
230 err = HvCallPci_configStore8(bus, *busp, *agent,
231 PCI_INTERRUPT_LINE, irq);
232 if (err) {
233 pci_Log_Error("PciCfgStore Irq Failed!",
234 bus, *busp, *agent, err);
235 continue;
236 }
218 237
219 /* Find and connect the devices. */ 238 pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
220 scan_PHB_slots(phb); 239 if (pdn == NULL)
240 return;
241 dn->data = pdn;
242 pdn->node = dn;
243 pdn->busno = bus;
244 pdn->devfn = (reg[0] >> 8) & 0xff;
245 pdn->bussubno = *busp;
246 pdn->Irq = irq;
247 pdn->LogicalSlot = *lsn;
248 list_add_tail(&pdn->Device_List,
249 &iSeries_Global_Device_List);
221 } 250 }
222 /*
223 * Check for Unexpected Return code, a clue that something
224 * has gone wrong.
225 */
226 else if (ret != 0x0301)
227 printk(KERN_ERR "Unexpected Return on Probe(0x%04X): 0x%04X",
228 bus, ret);
229 } 251 }
230} 252}
231 253
@@ -272,147 +294,6 @@ void pcibios_fixup_resources(struct pci_dev *pdev)
272} 294}
273 295
274/* 296/*
275 * Loop through each node function to find usable EADs bridges.
276 */
277static void scan_PHB_slots(struct pci_controller *Phb)
278{
279 struct HvCallPci_DeviceInfo *DevInfo;
280 HvBusNumber bus = Phb->local_number; /* System Bus */
281 const HvSubBusNumber SubBus = 0; /* EADs is always 0. */
282 int HvRc = 0;
283 int IdSel;
284 const int MaxAgents = 8;
285
286 DevInfo = kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL);
287 if (DevInfo == NULL)
288 return;
289
290 /*
291 * Probe for EADs Bridges
292 */
293 for (IdSel = 1; IdSel < MaxAgents; ++IdSel) {
294 HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel,
295 iseries_hv_addr(DevInfo),
296 sizeof(struct HvCallPci_DeviceInfo));
297 if (HvRc == 0) {
298 if (DevInfo->deviceType == HvCallPci_NodeDevice)
299 scan_EADS_bridge(bus, SubBus, IdSel);
300 else
301 printk("PCI: Invalid System Configuration(0x%02X)"
302 " for bus 0x%02x id 0x%02x.\n",
303 DevInfo->deviceType, bus, IdSel);
304 }
305 else
306 pci_Log_Error("getDeviceInfo", bus, SubBus, IdSel, HvRc);
307 }
308 kfree(DevInfo);
309}
310
311static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus,
312 int IdSel)
313{
314 struct HvCallPci_BridgeInfo *BridgeInfo;
315 HvAgentId AgentId;
316 int Function;
317 int HvRc;
318
319 BridgeInfo = (struct HvCallPci_BridgeInfo *)
320 kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL);
321 if (BridgeInfo == NULL)
322 return;
323
324 /* Note: hvSubBus and irq is always be 0 at this level! */
325 for (Function = 0; Function < 8; ++Function) {
326 AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
327 HvRc = HvCallXm_connectBusUnit(bus, SubBus, AgentId, 0);
328 if (HvRc == 0) {
329 printk("found device at bus %d idsel %d func %d (AgentId %x)\n",
330 bus, IdSel, Function, AgentId);
331 /* Connect EADs: 0x18.00.12 = 0x00 */
332 HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId,
333 iseries_hv_addr(BridgeInfo),
334 sizeof(struct HvCallPci_BridgeInfo));
335 if (HvRc == 0) {
336 printk("bridge info: type %x subbus %x maxAgents %x maxsubbus %x logslot %x\n",
337 BridgeInfo->busUnitInfo.deviceType,
338 BridgeInfo->subBusNumber,
339 BridgeInfo->maxAgents,
340 BridgeInfo->maxSubBusNumber,
341 BridgeInfo->logicalSlotNumber);
342 if (BridgeInfo->busUnitInfo.deviceType ==
343 HvCallPci_BridgeDevice) {
344 /* Scan_Bridge_Slot...: 0x18.00.12 */
345 scan_bridge_slot(bus, BridgeInfo);
346 } else
347 printk("PCI: Invalid Bridge Configuration(0x%02X)",
348 BridgeInfo->busUnitInfo.deviceType);
349 }
350 } else if (HvRc != 0x000B)
351 pci_Log_Error("EADs Connect",
352 bus, SubBus, AgentId, HvRc);
353 }
354 kfree(BridgeInfo);
355}
356
357/*
358 * This assumes that the node slot is always on the primary bus!
359 */
360static int scan_bridge_slot(HvBusNumber Bus,
361 struct HvCallPci_BridgeInfo *BridgeInfo)
362{
363 struct device_node *node;
364 HvSubBusNumber SubBus = BridgeInfo->subBusNumber;
365 u16 VendorId = 0;
366 int HvRc = 0;
367 u8 Irq = 0;
368 int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
369 int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
370 HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function);
371
372 /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */
373 Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel);
374
375 /*
376 * Connect all functions of any device found.
377 */
378 for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) {
379 for (Function = 0; Function < 8; ++Function) {
380 HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
381 HvRc = HvCallXm_connectBusUnit(Bus, SubBus,
382 AgentId, Irq);
383 if (HvRc != 0) {
384 pci_Log_Error("Connect Bus Unit",
385 Bus, SubBus, AgentId, HvRc);
386 continue;
387 }
388
389 HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId,
390 PCI_VENDOR_ID, &VendorId);
391 if (HvRc != 0) {
392 pci_Log_Error("Read Vendor",
393 Bus, SubBus, AgentId, HvRc);
394 continue;
395 }
396 printk("read vendor ID: %x\n", VendorId);
397
398 /* FoundDevice: 0x18.28.10 = 0x12AE */
399 HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId,
400 PCI_INTERRUPT_LINE, Irq);
401 if (HvRc != 0)
402 pci_Log_Error("PciCfgStore Irq Failed!",
403 Bus, SubBus, AgentId, HvRc);
404
405 ++DeviceCount;
406 node = build_device_node(Bus, SubBus, EADsIdSel, Function);
407 PCI_DN(node)->Irq = Irq;
408 PCI_DN(node)->LogicalSlot = BridgeInfo->logicalSlotNumber;
409
410 } /* for (Function = 0; Function < 8; ++Function) */
411 } /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */
412 return HvRc;
413}
414
415/*
416 * I/0 Memory copy MUST use mmio commands on iSeries 297 * I/0 Memory copy MUST use mmio commands on iSeries
417 * To do; For performance, include the hv call directly 298 * To do; For performance, include the hv call directly
418 */ 299 */