/* $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>
/* 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.
* Return zero if not found.
*/
static int __init find_device_prom_node(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
int bus_prom_node,
struct linux_prom_pci_registers *pregs,
int *nregs)
{
int node;
/*
* 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)) {
*nregs = 0;
return bus_prom_node;
}
node = prom_getchild(bus_prom_node);
while (node != 0) {
int err = prom_getproperty(node, "reg",
(char *)pregs,
sizeof(*pregs) * PROMREG_MAX);
if (err == 0 || err == -1)
goto do_next_sibling;
if (((pregs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
*nregs = err / sizeof(*pregs);
return node;
}
do_next_sibling:
node = prom_getsibling(node);
}
return 0;
}
/* 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->prom_assignments[i];
space = ap->phys_hi >> 24;
if ((space & 0x3) == 2 &&
(space & 0x4) != 0) {
ap->phys_hi &= ~(0x7 << 24);
ap->phys_hi |= 0x3 << 24;
}
}
}
/* Fill in the PCI device cookie sysdata for the given
* PCI device. This cookie is the means by which one
* can get to OBP and PCI controller specific information
* for a PCI device.
*/
static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
int bus_prom_node