[MIPS] Support for several more SNI RM models.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
diff --git a/arch/mips/pci/fixup-sni.c b/arch/mips/pci/fixup-sni.c
index a176f2c..0c9a473 100644
--- a/arch/mips/pci/fixup-sni.c
+++ b/arch/mips/pci/fixup-sni.c
@@ -15,7 +15,7 @@
 #include <asm/sni.h>
 
 /*
- * Shortcuts ...
+ * PCIMT Shortcuts ...
  */
 #define SCSI	PCIMT_IRQ_SCSI
 #define ETH	PCIMT_IRQ_ETHERNET
@@ -67,6 +67,50 @@
 	{     0, INTD, INTA, INTB, INTC },	/* Slot 4 */
 };
 
+static char irq_tab_rm300e[5][5] __initdata = {
+	/*       INTA  INTB  INTC  INTD */
+	{     0,    0,    0,    0,    0 },	/* HOST bridge */
+	{  SCSI, SCSI, SCSI, SCSI, SCSI },	/* SCSI */
+	{     0, INTC, INTD, INTA, INTB },	/* Bridge/i960 */
+	{     0, INTD, INTA, INTB, INTC },	/* Slot 1 */
+	{     0, INTA, INTB, INTC, INTD },	/* Slot 2 */
+};
+#undef SCSI
+#undef ETH
+#undef INTA
+#undef INTB
+#undef INTC
+#undef INTD
+
+
+/*
+ * PCIT Shortcuts ...
+ */
+#define SCSI0	PCIT_IRQ_SCSI0
+#define SCSI1	PCIT_IRQ_SCSI1
+#define ETH	PCIT_IRQ_ETHERNET
+#define INTA	PCIT_IRQ_INTA
+#define INTB	PCIT_IRQ_INTB
+#define INTC	PCIT_IRQ_INTC
+#define INTD	PCIT_IRQ_INTD
+
+static char irq_tab_pcit[13][5] __initdata = {
+	/*       INTA  INTB  INTC  INTD */
+	{     0,     0,     0,     0,     0 },	/* HOST bridge */
+	{ SCSI0, SCSI0, SCSI0, SCSI0, SCSI0 },	/* SCSI */
+	{ SCSI1, SCSI1, SCSI1, SCSI1, SCSI1 },	/* SCSI */
+	{   ETH,   ETH,   ETH,   ETH,   ETH },	/* Ethernet */
+	{     0,  INTA,  INTB,  INTC,  INTD },	/* PCI-PCI bridge */
+	{     0,     0,     0,     0,     0 },	/* Unused */
+	{     0,     0,     0,     0,     0 },	/* Unused */
+	{     0,     0,     0,     0,     0 },	/* Unused */
+	{     0,  INTA,  INTB,  INTC,  INTD },	/* Slot 1 */
+	{     0,  INTB,  INTC,  INTD,  INTA },	/* Slot 2 */
+	{     0,  INTC,  INTD,  INTA,  INTB },	/* Slot 3 */
+	{     0,  INTD,  INTA,  INTB,  INTC },	/* Slot 4 */
+	{     0,  INTA,  INTB,  INTC,  INTD },	/* Slot 5 */
+};
+
 static inline int is_rm300_revd(void)
 {
 	unsigned char csmsr = *(volatile unsigned char *)PCIMT_CSMSR;
@@ -76,10 +120,24 @@
 
 int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
-	if (is_rm300_revd())
-		return irq_tab_rm300d[slot][pin];
+	switch (sni_brd_type) {
+	case SNI_BRD_PCI_TOWER:
+	case SNI_BRD_PCI_TOWER_CPLUS:
+	        return irq_tab_pcit[slot][pin];
 
-	return irq_tab_rm200[slot][pin];
+	case SNI_BRD_PCI_MTOWER:
+	        if (is_rm300_revd())
+		        return irq_tab_rm300d[slot][pin];
+	        /* fall through */
+
+	case SNI_BRD_PCI_DESKTOP:
+	        return irq_tab_rm200[slot][pin];
+
+	case SNI_BRD_PCI_MTOWER_CPLUS:
+	        return irq_tab_rm300e[slot][pin];
+	}
+
+	return 0;
 }
 
 /* Do platform specific device initialization at pci_enable_device() time */
diff --git a/arch/mips/pci/ops-sni.c b/arch/mips/pci/ops-sni.c
index 2b0ccd6..fa2d2c6 100644
--- a/arch/mips/pci/ops-sni.c
+++ b/arch/mips/pci/ops-sni.c
@@ -83,7 +83,82 @@
 	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,
+};