Commit db63ee4d authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

[PATCH] ppc64: Rework PCI <-> OF node matching

This patch reworks the code that deals with matching PCI devices
with Open Firmware device nodes. This code made several incorrect
assumptions and can be simplified significantly. The main functional
difference now is that PHBs are no longer special cased, but that
shouldn't cause any specific problem.

It also fixes a problem where u3_iommu.c wouldn't work for PCI
devices that lacked a matching OF device node.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 97a71c39
......@@ -46,29 +46,13 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
{
struct pci_controller *phb = data;
u32 *regs;
char *device_type = get_property(dn, "device_type", NULL);
char *model;
dn->phb = phb;
if (device_type && (strcmp(device_type, "pci") == 0) &&
(get_property(dn, "class-code", NULL) == 0)) {
/* special case for PHB's. Sigh. */
regs = (u32 *)get_property(dn, "bus-range", NULL);
dn->busno = regs[0];
model = (char *)get_property(dn, "model", NULL);
if (strstr(model, "U3"))
dn->devfn = -1;
else
dn->devfn = 0; /* assumption */
} else {
regs = (u32 *)get_property(dn, "reg", NULL);
if (regs) {
/* First register entry is addr (00BBSS00) */
dn->busno = (regs[0] >> 16) & 0xff;
dn->devfn = (regs[0] >> 8) & 0xff;
}
regs = (u32 *)get_property(dn, "reg", NULL);
if (regs) {
/* First register entry is addr (00BBSS00) */
dn->busno = (regs[0] >> 16) & 0xff;
dn->devfn = (regs[0] >> 8) & 0xff;
}
return NULL;
}
......@@ -97,20 +81,25 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
struct device_node *dn, *nextdn;
void *ret;
if (pre && ((ret = pre(start, data)) != NULL))
return ret;
/* We started with a phb, iterate all childs */
for (dn = start->child; dn; dn = nextdn) {
u32 *classp, class;
nextdn = NULL;
if (get_property(dn, "class-code", NULL)) {
if (pre && ((ret = pre(dn, data)) != NULL))
return ret;
if (dn->child)
/* Depth first...do children */
nextdn = dn->child;
else if (dn->sibling)
/* ok, try next sibling instead. */
nextdn = dn->sibling;
}
classp = (u32 *)get_property(dn, "class-code", NULL);
class = classp ? *classp : 0;
if (pre && ((ret = pre(dn, data)) != NULL))
return ret;
/* If we are a PCI bridge, go down */
if (dn->child && ((class >> 8) == PCI_CLASS_BRIDGE_PCI ||
(class >> 8) == PCI_CLASS_BRIDGE_CARDBUS))
/* Depth first...do children */
nextdn = dn->child;
else if (dn->sibling)
/* ok, try next sibling instead. */
nextdn = dn->sibling;
if (!nextdn) {
/* Walk up to next valid sibling. */
do {
......@@ -124,26 +113,16 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
return NULL;
}
/*
* Same as traverse_pci_devices except this does it for all phbs.
*/
static void *traverse_all_pci_devices(traverse_func pre)
void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb)
{
struct pci_controller *phb, *tmp;
void *ret;
struct device_node * dn = (struct device_node *) phb->arch_data;
list_for_each_entry_safe(phb, tmp, &hose_list, list_node)
if ((ret = traverse_pci_devices(phb->arch_data, pre, phb))
!= NULL)
return ret;
return NULL;
}
/* PHB nodes themselves must not match */
dn->devfn = dn->busno = -1;
dn->phb = phb;
void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb)
{
/* Update dn->phb ptrs for new phb and children devices */
traverse_pci_devices((struct device_node *)phb->arch_data,
update_dn_pci_info, phb);
traverse_pci_devices(dn, update_dn_pci_info, phb);
}
/*
......@@ -154,6 +133,7 @@ static void *is_devfn_node(struct device_node *dn, void *data)
{
int busno = ((unsigned long)data >> 8) & 0xff;
int devfn = ((unsigned long)data) & 0xff;
return ((devfn == dn->devfn) && (busno == dn->busno)) ? dn : NULL;
}
......@@ -180,10 +160,8 @@ struct device_node *fetch_dev_dn(struct pci_dev *dev)
phb_dn = phb->arch_data;
dn = traverse_pci_devices(phb_dn, is_devfn_node, (void *)searchval);
if (dn) {
if (dn)
dev->sysdata = dn;
/* ToDo: call some device init hook here */
}
return dn;
}
EXPORT_SYMBOL(fetch_dev_dn);
......@@ -195,8 +173,11 @@ EXPORT_SYMBOL(fetch_dev_dn);
*/
void __init pci_devs_phb_init(void)
{
struct pci_controller *phb, *tmp;
/* This must be done first so the device nodes have valid pci info! */
traverse_all_pci_devices(update_dn_pci_info);
list_for_each_entry_safe(phb, tmp, &hose_list, list_node)
pci_devs_phb_init_dynamic(phb);
}
......
......@@ -267,6 +267,7 @@ static int dart_init(struct device_node *dart_node)
void iommu_setup_u3(void)
{
struct pci_controller *phb, *tmp;
struct pci_dev *dev = NULL;
struct device_node *dn;
......@@ -299,6 +300,11 @@ void iommu_setup_u3(void)
if (dn)
dn->iommu_table = &iommu_table_u3;
}
/* We also make sure we set all PHBs ... */
list_for_each_entry_safe(phb, tmp, &hose_list, list_node) {
dn = (struct device_node *)phb->arch_data;
dn->iommu_table = &iommu_table_u3;
}
}
void __init alloc_u3_dart_table(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment