summaryrefslogtreecommitdiffstats
path: root/arch/mips/pci/ops-sni.c
diff options
context:
space:
mode:
authorThomas Bogendoerfer <tsbogend@alpha.franken.de>2006-12-28 18:22:32 +0100
committerRalf Baechle <ralf@linux-mips.org>2007-02-18 21:31:37 +0000
commitc066a32a890c50ce59e91f8cea8eb5fd8d5821b9 (patch)
treed129af235d11d44c649f0743bc38535c3a229e41 /arch/mips/pci/ops-sni.c
parent5759906ca9e5201c3fd40d61c861ec1e441d3a24 (diff)
[MIPS] Support for several more SNI RM models.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/pci/ops-sni.c')
-rw-r--r--arch/mips/pci/ops-sni.c77
1 files changed, 76 insertions, 1 deletions
diff --git a/arch/mips/pci/ops-sni.c b/arch/mips/pci/ops-sni.c
index 2b0ccd6d9dc..fa2d2c60f79 100644
--- a/arch/mips/pci/ops-sni.c
+++ b/arch/mips/pci/ops-sni.c
@@ -83,7 +83,82 @@ static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg,
return 0;
}
-struct pci_ops sni_pci_ops = {
+struct pci_ops sni_pcimt_ops = {
.read = pcimt_read,
.write = pcimt_write,
};
+
+static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int reg)
+{
+ if ((devfn > 255) || (reg > 255) || (busno > 255))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ outl ((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg,
+ int size, u32 * val)
+{
+ int res;
+
+ /*
+ * on bus 0 we need to check, whether there is a device answering
+ * for the devfn by doing a config write and checking the result. If
+ * we don't do it, we will get a data bus error
+ */
+ if (bus->number == 0) {
+ pcit_set_config_address (0, 0, 0x68);
+ outl (inl (0xcfc) | 0xc0000000, 0xcfc);
+ if ((res = pcit_set_config_address(0, devfn, 0)))
+ return res;
+ outl (0xffffffff, 0xcfc);
+ pcit_set_config_address (0, 0, 0x68);
+ if (inl(0xcfc) & 0x100000)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ if ((res = pcit_set_config_address(bus->number, devfn, reg)))
+ return res;
+
+ switch (size) {
+ case 1:
+ *val = inb(PCIMT_CONFIG_DATA + (reg & 3));
+ break;
+ case 2:
+ *val = inw(PCIMT_CONFIG_DATA + (reg & 2));
+ break;
+ case 4:
+ *val = inl(PCIMT_CONFIG_DATA);
+ break;
+ }
+ return 0;
+}
+
+static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg,
+ int size, u32 val)
+{
+ int res;
+
+ if ((res = pcit_set_config_address(bus->number, devfn, reg)))
+ return res;
+
+ switch (size) {
+ case 1:
+ outb (val, PCIMT_CONFIG_DATA + (reg & 3));
+ break;
+ case 2:
+ outw (val, PCIMT_CONFIG_DATA + (reg & 2));
+ break;
+ case 4:
+ outl (val, PCIMT_CONFIG_DATA);
+ break;
+ }
+
+ return 0;
+}
+
+
+struct pci_ops sni_pcit_ops = {
+ .read = pcit_read,
+ .write = pcit_write,
+};