aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/iseries/pci.c
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2006-05-19 02:46:28 -0400
committerPaul Mackerras <paulus@samba.org>2006-05-24 02:08:56 -0400
commit0d177df15d12926dc2ef7c814f317f02de52ce17 (patch)
treeda10171a931af0ff709016a8ce5111a3c39e83d2 /arch/powerpc/platforms/iseries/pci.c
parent66b3851a6947482987b4c05aa781a33696287648 (diff)
[PATCH] powerpc: move iSeries PCI devices to the device tree
Move the probing of PCI devices to setup.c and put them all into the flattened device tree. The later probing is now done by traversing the device tree. Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Paul Mackerras <paulus@samba.org>
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 */