aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/pci/ops-sni.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/pci/ops-sni.c')
-rw-r--r--arch/mips/pci/ops-sni.c97
1 files changed, 86 insertions, 11 deletions
diff --git a/arch/mips/pci/ops-sni.c b/arch/mips/pci/ops-sni.c
index 62bdd19c7f8..35daa7fe657 100644
--- a/arch/mips/pci/ops-sni.c
+++ b/arch/mips/pci/ops-sni.c
@@ -14,8 +14,8 @@
/*
* It seems that on the RM200 only lower 3 bits of the 5 bit PCI device
- * address are decoded. We therefore manually have to reject attempts at
- * reading outside this range. Being on the paranoid side we only do this
+ * address are decoded. We therefore manually have to reject attempts at
+ * reading outside this range. Being on the paranoid side we only do this
* test for bus 0 and hope forwarding and decoding work properly for any
* subordinated busses.
*
@@ -31,8 +31,8 @@ static int set_config_address(unsigned int busno, unsigned int devfn, int reg)
*(volatile u32 *)PCIMT_CONFIG_ADDRESS =
((busno & 0xff) << 16) |
- ((devfn & 0xff) << 8) |
- (reg & 0xfc);
+ ((devfn & 0xff) << 8) |
+ (reg & 0xfc);
return PCIBIOS_SUCCESSFUL;
}
@@ -47,13 +47,13 @@ static int pcimt_read(struct pci_bus *bus, unsigned int devfn, int reg,
switch (size) {
case 1:
- *val = *(volatile u8 *) (PCIMT_CONFIG_DATA + (reg & 3));
+ *val = inb(PCIMT_CONFIG_DATA + (reg & 3));
break;
case 2:
- *val = *(volatile u16 *) (PCIMT_CONFIG_DATA + (reg & 2));
+ *val = inw(PCIMT_CONFIG_DATA + (reg & 2));
break;
case 4:
- *val = *(volatile u32 *) PCIMT_CONFIG_DATA;
+ *val = inl(PCIMT_CONFIG_DATA);
break;
}
@@ -70,20 +70,95 @@ static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg,
switch (size) {
case 1:
- *(volatile u8 *) (PCIMT_CONFIG_DATA + (reg & 3)) = val;
+ outb(val, PCIMT_CONFIG_DATA + (reg & 3));
break;
case 2:
- *(volatile u16 *) (PCIMT_CONFIG_DATA + (reg & 2)) = val;
+ outw(val, PCIMT_CONFIG_DATA + (reg & 2));
break;
case 4:
- *(volatile u32 *) PCIMT_CONFIG_DATA = val;
+ outl(val, PCIMT_CONFIG_DATA);
break;
}
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,
+};