summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/pmac_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel/pmac_pci.c')
-rw-r--r--arch/ppc/kernel/pmac_pci.c69
1 files changed, 63 insertions, 6 deletions
diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c
index 7763059f7..089169e37 100644
--- a/arch/ppc/kernel/pmac_pci.c
+++ b/arch/ppc/kernel/pmac_pci.c
@@ -21,6 +21,9 @@
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
struct bridge_data **bridges, *bridge_list;
static int max_bus;
@@ -84,7 +87,12 @@ int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* Bus number once again taken into consideration.
+ * Change applied from 2.1.24. This makes devices located
+ * behind PCI-PCI bridges visible.
+ * -Ranjit Deshpande, 01/20/99
+ */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
*val = in_8(bp->cfg_data + (offset & 3));
@@ -109,7 +117,8 @@ int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
*val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
@@ -134,7 +143,8 @@ int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ offset);
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + offset + 1);
}
udelay(2);
*val = in_le32((volatile unsigned int *)bp->cfg_data);
@@ -156,7 +166,8 @@ int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
out_8(bp->cfg_data + (offset & 3), val);
@@ -180,7 +191,8 @@ int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
@@ -204,7 +216,8 @@ int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ offset);
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
out_le32((volatile unsigned int *)bp->cfg_data, val);
@@ -429,3 +442,47 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p
}
}
+__initfunc(
+void
+pmac_pcibios_fixup(void))
+{
+ struct pci_dev *dev;
+
+ /*
+ * FIXME: This is broken: We should not assign IRQ's to IRQless
+ * devices (look at PCI_INTERRUPT_PIN) and we also should
+ * honor the existence of multi-function devices where
+ * different functions have different interrupt pins. [mj]
+ */
+ for(dev=pci_devices; dev; dev=dev->next)
+ {
+ /*
+ * Open Firmware often doesn't initialize the,
+ * PCI_INTERRUPT_LINE config register properly, so we
+ * should find the device node and se if it has an
+ * AAPL,interrupts property.
+ */
+ struct bridge_data *bp = bridges[dev->bus->number];
+ unsigned char pin;
+
+ if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
+ !pin)
+ continue; /* No interrupt generated -> no fixup */
+ fix_intr(bp->node->child, dev);
+ }
+}
+
+__initfunc(
+void
+pmac_setup_pci_ptrs(void))
+{
+ if (find_devices("pci") != 0) {
+ /* looks like a G3 powermac */
+ set_config_access_method(grackle);
+ } else {
+ set_config_access_method(pmac);
+ }
+
+ ppc_md.pcibios_fixup = pmac_pcibios_fixup;
+}
+