*******************************************************************/
struct pci_controller *alloc_phb(struct device_node *dev, char *model,
unsigned int addr_size_words) ;
-static int rtas_fake_read(struct device_node *dn, int offset, int nbytes,
- unsigned long *returnval);
/* RTAS tokens */
static int read_pci_config;
buid = dn->phb->buid;
if (buid) {
ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, size);
- if (ret < 0|| (returnval == 0xffffffff))
- ret = rtas_fake_read(dn, where, size, &returnval);
} else {
ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size);
}
rtas_pci_write_config
};
-/*
- * Handle the case where rtas refuses to do a pci config read.
- * This currently only happens with some PHBs in which case we totally fake
- * out the values (and call it a speedwagaon -- something we could look up
- * in the device tree).
- */
-static int
-rtas_fake_read(struct device_node *dn, int offset, int nbytes, unsigned long *returnval)
-{
- char *device_type = (char *)get_property(dn, "device_type", 0);
- u32 *class_code = (u32 *)get_property(dn, "class-code", 0);
-
- *returnval = ~0; /* float by default */
-
- /* udbg_printf("rtas_fake_read dn=%p, offset=0x%02x, nbytes=%d, device_type=%s\n", dn, offset, nbytes, device_type ? device_type : "<none>"); */
- if (device_type && strcmp(device_type, "pci") != 0)
- return -3; /* Not a phb or bridge */
-
- /* NOTE: class_code != NULL => EADS pci bridge. Else a PHB */
- if (nbytes == 1) {
- if (offset == PCI_HEADER_TYPE)
- *returnval = 0x80; /* multifunction */
- else if (offset == PCI_INTERRUPT_PIN || offset == PCI_INTERRUPT_LINE)
- *returnval = 0;
- } else if (nbytes == 2) {
- if (offset == PCI_SUBSYSTEM_VENDOR_ID || offset == PCI_SUBSYSTEM_ID)
- *returnval = 0;
- else if (offset == PCI_COMMAND)
- *returnval = PCI_COMMAND_PARITY|PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY;
- } else if (nbytes == 4) {
- if (offset == PCI_VENDOR_ID)
- *returnval = 0x1014 | ((class_code ? 0x8b : 0x102) << 16); /* a phb */
- else if (offset == PCI_REVISION_ID)
- *returnval = (class_code ? PCI_CLASS_BRIDGE_PCI : PCI_CLASS_BRIDGE_HOST) << 16; /* revs are zero */
- else if ((offset >= PCI_BASE_ADDRESS_0 && offset <= PCI_BASE_ADDRESS_5) || offset == PCI_ROM_ADDRESS)
- *returnval = 0;
- }
-
- /* printk("fake: %s nbytes=%d, offset=%lx ret=%lx\n", class_code ? "EADS" : "PHB", nbytes, offset, *returnval); */
- return 0;
-}
-
/******************************************************************
* pci_read_irq_line
*
return (devfn == (dn->devfn & 0xf8) && busno == dn->busno) ? dn : NULL;
}
-/* Given an existing EADs (pci bridge) device node create a fake one
- * that will simulate function zero. Make it a sibling of other_eads.
- */
-static struct device_node *
-create_eads_node(struct device_node *other_eads)
-{
- struct device_node *eads = (struct device_node *)kmalloc(sizeof(struct device_node), GFP_KERNEL);
-
- if (!eads) return NULL; /* huh? */
- *eads = *other_eads;
- eads->devfn &= ~7; /* make it function zero */
- eads->tce_table = NULL;
- /*
- * NOTE: share properties. We could copy but for now this should
- * suffice. The full_name is also incorrect...but seems harmless.
- */
- eads->child = NULL;
- eads->next = NULL;
- other_eads->allnext = eads;
- other_eads->sibling = eads;
- return eads;
-}
-
/* This is the "slow" path for looking up a device_node from a
* pci_dev. It will hunt for the device under it's parent's
* phb and then update sysdata for a future fastpath.
if (dn) {
dev->sysdata = dn;
/* ToDo: call some device init hook here */
- } else {
- /* Now it is very possible that we can't find the device
- * because it is not the zero'th device of a mutifunction
- * device and we don't have permission to read the zero'th
- * device. If this is the case, Linux would ordinarily skip
- * all the other functions.
- */
- if ((searchval & 0x7) == 0) {
- struct device_node *thisdevdn;
- /* Ok, we are looking for fn == 0. Let's check for other functions. */
- thisdevdn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_sub_node, NULL, (void *)searchval);
- if (thisdevdn) {
- /* Ah ha! There does exist a sub function.
- * Now this isn't an exact match for
- * searchval, but in order to get Linux to
- * believe the sub functions exist we will
- * need to manufacture a fake device_node for
- * this zero'th function. To keept this
- * simple for now we only handle pci bridges
- * and we just hand back the found node which
- * isn't correct, but Linux won't care.
- */
- char *device_type = (char *)get_property(thisdevdn, "device_type", 0);
- if (device_type && strcmp(device_type, "pci") == 0) {
- return create_eads_node(thisdevdn);
- }
- }
- }
- /* ToDo: device not found...probe for it anyway with a fake dn?
- struct device_node fake_dn;
- memset(&fake_dn, 0, sizeof(fake_dn));
- fake_dn.phb = phb;
- fake_dn.busno = dev->bus->number;
- fake_dn.devfn = dev->devfn;
- ... now do ppc_md.pcibios_read_config_dword(&fake_dn.....)
- ... if ok, alloc a real device_node and dn = real_dn;
- */
}
return dn;
}