/* $Id: pci_common.c,v 1.29 2002/02/01 00:56:03 davem Exp $
* pci_common.c: PCI controller common support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
*/
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <asm/pbm.h>
#include <asm/prom.h>
#include "pci_impl.h"
/* Pass "pci=irq_verbose" on the kernel command line to enable this. */
int pci_irq_verbose;
/* Fix self device of BUS and hook it into BUS->self.
* The pci_scan_bus does not do this for the host bridge.
*/
void __init pci_fixup_host_bridge_self(struct pci_bus *pbus)
{
struct pci_dev *pdev;
list_for_each_entry(pdev, &pbus->devices, bus_list) {
if (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) {
pbus->self = pdev;
return;
}
}
prom_printf("PCI: Critical error, cannot find host bridge PDEV.\n");
prom_halt();
}
/* Find the OBP PROM device tree node for a PCI device. */
static struct device_node * __init
find_device_prom_node(struct pci_pbm_info *pbm, struct pci_dev *pdev,
struct device_node *bus_node,
struct linux_prom_pci_registers **pregs,
int *nregs)
{
struct device_node *dp;
*nregs = 0;
/*
* Return the PBM's PROM node in case we are it's PCI device,
* as the PBM's reg property is different to standard PCI reg
* properties. We would delete this device entry otherwise,
* which confuses XFree86's device probing...
*/
if ((pdev->bus->number == pbm->pci_bus->number) && (pdev->devfn == 0) &&
(pdev->vendor == PCI_VENDOR_ID_SUN) &&
(pdev->device == PCI_DEVICE_ID_SUN_PBM ||
pdev->device == PCI_DEVICE_ID_SUN_SCHIZO ||
pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO ||
pdev->device == PCI_DEVICE_ID_SUN_SABRE ||
pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD))
return bus_node;
dp = bus_node->child;
while (dp) {
struct linux_prom_pci_registers *regs;
struct property *prop;
int len;
prop = of_find_property(dp, "reg", &len);
if (!prop)
goto do_next_sibling;
regs = prop->value;
if (((regs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
*pregs = regs;
*nregs = len / sizeof(struct linux_prom_pci_registers);
return dp;
}
do_next_sibling:
dp = dp->sibling;
}
return NULL;
}
/* Older versions of OBP on PCI systems encode 64-bit MEM
* space assignments incorrectly, this fixes them up. We also
* take the opportunity here to hide other kinds of bogus
* assignments.
*/
static void __init fixup_obp_assignments(struct pci_dev *pdev,
struct pcidev_cookie *pcp)
{
int i;
if (pdev->vendor == PCI_VENDOR_ID_AL &&
(pdev->device == PCI_DEVICE_ID_AL_M7101 ||
pdev->device == PCI_DEVICE_ID_AL_M1533)) {
int i;
/* Zap all of the normal resources, they are
* meaningless and generate bogus resource collision
* messages. This is OpenBoot's ill-fated attempt to
* represent the implicit resources that these devices
* have.
*/
pcp->num_prom_assignments = 0;
for (i = 0; i < 6; i++) {
pdev->resource[i].start =
pdev->resource[i].end =
pdev->resource[i].flags = 0;
}
pdev->resource[PCI_ROM_RESOURCE].start =
pdev->resource[PCI_ROM_RESOURCE].end =
pdev->resource[PCI_ROM_RESOURCE].flags = 0;
return;
}
for (i = 0; i < pcp->num_prom_assignments; i++) {
struct linux_prom_pci_registers *ap;
int space;
ap = &pcp->