xref: /openbmc/linux/arch/alpha/kernel/core_mcpcia.c (revision 280da4e4)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	linux/arch/alpha/kernel/core_mcpcia.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Code common to all MCbus-PCI Adaptor core logic chipsets
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #define __EXTERN_INLINE inline
101da177e4SLinus Torvalds #include <asm/io.h>
111da177e4SLinus Torvalds #include <asm/core_mcpcia.h>
121da177e4SLinus Torvalds #undef __EXTERN_INLINE
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <linux/types.h>
151da177e4SLinus Torvalds #include <linux/pci.h>
161da177e4SLinus Torvalds #include <linux/sched.h>
171da177e4SLinus Torvalds #include <linux/init.h>
181da177e4SLinus Torvalds #include <linux/delay.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include <asm/ptrace.h>
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #include "proto.h"
231da177e4SLinus Torvalds #include "pci_impl.h"
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds /*
261da177e4SLinus Torvalds  * NOTE: Herein lie back-to-back mb instructions.  They are magic.
271da177e4SLinus Torvalds  * One plausible explanation is that the i/o controller does not properly
281da177e4SLinus Torvalds  * handle the system transaction.  Another involves timing.  Ho hum.
291da177e4SLinus Torvalds  */
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds /*
321da177e4SLinus Torvalds  * BIOS32-style PCI interface:
331da177e4SLinus Torvalds  */
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds #define DEBUG_CFG 0
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds #if DEBUG_CFG
381da177e4SLinus Torvalds # define DBG_CFG(args)	printk args
391da177e4SLinus Torvalds #else
401da177e4SLinus Torvalds # define DBG_CFG(args)
411da177e4SLinus Torvalds #endif
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds /*
441da177e4SLinus Torvalds  * Given a bus, device, and function number, compute resulting
451da177e4SLinus Torvalds  * configuration space address and setup the MCPCIA_HAXR2 register
461da177e4SLinus Torvalds  * accordingly.  It is therefore not safe to have concurrent
471da177e4SLinus Torvalds  * invocations to configuration space access routines, but there
481da177e4SLinus Torvalds  * really shouldn't be any need for this.
491da177e4SLinus Torvalds  *
501da177e4SLinus Torvalds  * Type 0:
511da177e4SLinus Torvalds  *
521da177e4SLinus Torvalds  *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
531da177e4SLinus Torvalds  *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
541da177e4SLinus Torvalds  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
551da177e4SLinus Torvalds  * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
561da177e4SLinus Torvalds  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
571da177e4SLinus Torvalds  *
581da177e4SLinus Torvalds  *	31:11	Device select bit.
591da177e4SLinus Torvalds  * 	10:8	Function number
601da177e4SLinus Torvalds  * 	 7:2	Register number
611da177e4SLinus Torvalds  *
621da177e4SLinus Torvalds  * Type 1:
631da177e4SLinus Torvalds  *
641da177e4SLinus Torvalds  *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
651da177e4SLinus Torvalds  *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
661da177e4SLinus Torvalds  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
671da177e4SLinus Torvalds  * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
681da177e4SLinus Torvalds  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
691da177e4SLinus Torvalds  *
701da177e4SLinus Torvalds  *	31:24	reserved
711da177e4SLinus Torvalds  *	23:16	bus number (8 bits = 128 possible buses)
721da177e4SLinus Torvalds  *	15:11	Device number (5 bits)
731da177e4SLinus Torvalds  *	10:8	function number
741da177e4SLinus Torvalds  *	 7:2	register number
751da177e4SLinus Torvalds  *
761da177e4SLinus Torvalds  * Notes:
771da177e4SLinus Torvalds  *	The function number selects which function of a multi-function device
781da177e4SLinus Torvalds  *	(e.g., SCSI and Ethernet).
791da177e4SLinus Torvalds  *
801da177e4SLinus Torvalds  *	The register selects a DWORD (32 bit) register offset.  Hence it
811da177e4SLinus Torvalds  *	doesn't get shifted by 2 bits as we want to "drop" the bottom two
821da177e4SLinus Torvalds  *	bits.
831da177e4SLinus Torvalds  */
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds static unsigned int
861da177e4SLinus Torvalds conf_read(unsigned long addr, unsigned char type1,
871da177e4SLinus Torvalds 	  struct pci_controller *hose)
881da177e4SLinus Torvalds {
891da177e4SLinus Torvalds 	unsigned long flags;
901da177e4SLinus Torvalds 	unsigned long mid = MCPCIA_HOSE2MID(hose->index);
91280da4e4SRichard Henderson 	unsigned int stat0, value, cpu;
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 	cpu = smp_processor_id();
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds 	local_irq_save(flags);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	DBG_CFG(("conf_read(addr=0x%lx, type1=%d, hose=%d)\n",
981da177e4SLinus Torvalds 		 addr, type1, mid));
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	/* Reset status register to avoid losing errors.  */
1011da177e4SLinus Torvalds 	stat0 = *(vuip)MCPCIA_CAP_ERR(mid);
1021da177e4SLinus Torvalds 	*(vuip)MCPCIA_CAP_ERR(mid) = stat0;
1031da177e4SLinus Torvalds 	mb();
104280da4e4SRichard Henderson 	*(vuip)MCPCIA_CAP_ERR(mid);
1051da177e4SLinus Torvalds 	DBG_CFG(("conf_read: MCPCIA_CAP_ERR(%d) was 0x%x\n", mid, stat0));
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 	mb();
1081da177e4SLinus Torvalds 	draina();
1091da177e4SLinus Torvalds 	mcheck_expected(cpu) = 1;
1101da177e4SLinus Torvalds 	mcheck_taken(cpu) = 0;
1111da177e4SLinus Torvalds 	mcheck_extra(cpu) = mid;
1121da177e4SLinus Torvalds 	mb();
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	/* Access configuration space.  */
1151da177e4SLinus Torvalds 	value = *((vuip)addr);
1161da177e4SLinus Torvalds 	mb();
1171da177e4SLinus Torvalds 	mb();  /* magic */
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 	if (mcheck_taken(cpu)) {
1201da177e4SLinus Torvalds 		mcheck_taken(cpu) = 0;
1211da177e4SLinus Torvalds 		value = 0xffffffffU;
1221da177e4SLinus Torvalds 		mb();
1231da177e4SLinus Torvalds 	}
1241da177e4SLinus Torvalds 	mcheck_expected(cpu) = 0;
1251da177e4SLinus Torvalds 	mb();
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	DBG_CFG(("conf_read(): finished\n"));
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds 	local_irq_restore(flags);
1301da177e4SLinus Torvalds 	return value;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds static void
1341da177e4SLinus Torvalds conf_write(unsigned long addr, unsigned int value, unsigned char type1,
1351da177e4SLinus Torvalds 	   struct pci_controller *hose)
1361da177e4SLinus Torvalds {
1371da177e4SLinus Torvalds 	unsigned long flags;
1381da177e4SLinus Torvalds 	unsigned long mid = MCPCIA_HOSE2MID(hose->index);
139280da4e4SRichard Henderson 	unsigned int stat0, cpu;
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	cpu = smp_processor_id();
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 	local_irq_save(flags);	/* avoid getting hit by machine check */
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 	/* Reset status register to avoid losing errors.  */
1461da177e4SLinus Torvalds 	stat0 = *(vuip)MCPCIA_CAP_ERR(mid);
1471da177e4SLinus Torvalds 	*(vuip)MCPCIA_CAP_ERR(mid) = stat0; mb();
148280da4e4SRichard Henderson 	*(vuip)MCPCIA_CAP_ERR(mid);
1491da177e4SLinus Torvalds 	DBG_CFG(("conf_write: MCPCIA CAP_ERR(%d) was 0x%x\n", mid, stat0));
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds 	draina();
1521da177e4SLinus Torvalds 	mcheck_expected(cpu) = 1;
1531da177e4SLinus Torvalds 	mcheck_extra(cpu) = mid;
1541da177e4SLinus Torvalds 	mb();
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	/* Access configuration space.  */
1571da177e4SLinus Torvalds 	*((vuip)addr) = value;
1581da177e4SLinus Torvalds 	mb();
1591da177e4SLinus Torvalds 	mb();  /* magic */
160280da4e4SRichard Henderson 	*(vuip)MCPCIA_CAP_ERR(mid); /* read to force the write */
1611da177e4SLinus Torvalds 	mcheck_expected(cpu) = 0;
1621da177e4SLinus Torvalds 	mb();
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 	DBG_CFG(("conf_write(): finished\n"));
1651da177e4SLinus Torvalds 	local_irq_restore(flags);
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds static int
1691da177e4SLinus Torvalds mk_conf_addr(struct pci_bus *pbus, unsigned int devfn, int where,
1701da177e4SLinus Torvalds 	     struct pci_controller *hose, unsigned long *pci_addr,
1711da177e4SLinus Torvalds 	     unsigned char *type1)
1721da177e4SLinus Torvalds {
1731da177e4SLinus Torvalds 	u8 bus = pbus->number;
1741da177e4SLinus Torvalds 	unsigned long addr;
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds 	DBG_CFG(("mk_conf_addr(bus=%d,devfn=0x%x,hose=%d,where=0x%x,"
1771da177e4SLinus Torvalds 		 " pci_addr=0x%p, type1=0x%p)\n",
1781da177e4SLinus Torvalds 		 bus, devfn, hose->index, where, pci_addr, type1));
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	/* Type 1 configuration cycle for *ALL* busses.  */
1811da177e4SLinus Torvalds 	*type1 = 1;
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds 	if (!pbus->parent) /* No parent means peer PCI bus. */
1841da177e4SLinus Torvalds 		bus = 0;
1851da177e4SLinus Torvalds 	addr = (bus << 16) | (devfn << 8) | (where);
1861da177e4SLinus Torvalds 	addr <<= 5; /* swizzle for SPARSE */
1871da177e4SLinus Torvalds 	addr |= hose->config_space_base;
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 	*pci_addr = addr;
1901da177e4SLinus Torvalds 	DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
1911da177e4SLinus Torvalds 	return 0;
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds static int
1951da177e4SLinus Torvalds mcpcia_read_config(struct pci_bus *bus, unsigned int devfn, int where,
1961da177e4SLinus Torvalds 		   int size, u32 *value)
1971da177e4SLinus Torvalds {
1981da177e4SLinus Torvalds 	struct pci_controller *hose = bus->sysdata;
1991da177e4SLinus Torvalds 	unsigned long addr, w;
2001da177e4SLinus Torvalds 	unsigned char type1;
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	if (mk_conf_addr(bus, devfn, where, hose, &addr, &type1))
2031da177e4SLinus Torvalds 		return PCIBIOS_DEVICE_NOT_FOUND;
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 	addr |= (size - 1) * 8;
2061da177e4SLinus Torvalds 	w = conf_read(addr, type1, hose);
2071da177e4SLinus Torvalds 	switch (size) {
2081da177e4SLinus Torvalds 	case 1:
2091da177e4SLinus Torvalds 		*value = __kernel_extbl(w, where & 3);
2101da177e4SLinus Torvalds 		break;
2111da177e4SLinus Torvalds 	case 2:
2121da177e4SLinus Torvalds 		*value = __kernel_extwl(w, where & 3);
2131da177e4SLinus Torvalds 		break;
2141da177e4SLinus Torvalds 	case 4:
2151da177e4SLinus Torvalds 		*value = w;
2161da177e4SLinus Torvalds 		break;
2171da177e4SLinus Torvalds 	}
2181da177e4SLinus Torvalds 	return PCIBIOS_SUCCESSFUL;
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds static int
2221da177e4SLinus Torvalds mcpcia_write_config(struct pci_bus *bus, unsigned int devfn, int where,
2231da177e4SLinus Torvalds 		    int size, u32 value)
2241da177e4SLinus Torvalds {
2251da177e4SLinus Torvalds 	struct pci_controller *hose = bus->sysdata;
2261da177e4SLinus Torvalds 	unsigned long addr;
2271da177e4SLinus Torvalds 	unsigned char type1;
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 	if (mk_conf_addr(bus, devfn, where, hose, &addr, &type1))
2301da177e4SLinus Torvalds 		return PCIBIOS_DEVICE_NOT_FOUND;
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	addr |= (size - 1) * 8;
2331da177e4SLinus Torvalds 	value = __kernel_insql(value, where & 3);
2341da177e4SLinus Torvalds 	conf_write(addr, value, type1, hose);
2351da177e4SLinus Torvalds 	return PCIBIOS_SUCCESSFUL;
2361da177e4SLinus Torvalds }
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds struct pci_ops mcpcia_pci_ops =
2391da177e4SLinus Torvalds {
2401da177e4SLinus Torvalds 	.read =		mcpcia_read_config,
2411da177e4SLinus Torvalds 	.write =	mcpcia_write_config,
2421da177e4SLinus Torvalds };
2431da177e4SLinus Torvalds 
2441da177e4SLinus Torvalds void
2451da177e4SLinus Torvalds mcpcia_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
2461da177e4SLinus Torvalds {
2471da177e4SLinus Torvalds 	wmb();
2481da177e4SLinus Torvalds 	*(vuip)MCPCIA_SG_TBIA(MCPCIA_HOSE2MID(hose->index)) = 0;
2491da177e4SLinus Torvalds 	mb();
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds static int __init
2531da177e4SLinus Torvalds mcpcia_probe_hose(int h)
2541da177e4SLinus Torvalds {
2551da177e4SLinus Torvalds 	int cpu = smp_processor_id();
2561da177e4SLinus Torvalds 	int mid = MCPCIA_HOSE2MID(h);
2571da177e4SLinus Torvalds 	unsigned int pci_rev;
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 	/* Gotta be REAL careful.  If hose is absent, we get an mcheck.  */
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 	mb();
2621da177e4SLinus Torvalds 	mb();
2631da177e4SLinus Torvalds 	draina();
2641da177e4SLinus Torvalds 	wrmces(7);
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	mcheck_expected(cpu) = 2;	/* indicates probing */
2671da177e4SLinus Torvalds 	mcheck_taken(cpu) = 0;
2681da177e4SLinus Torvalds 	mcheck_extra(cpu) = mid;
2691da177e4SLinus Torvalds 	mb();
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	/* Access the bus revision word. */
2721da177e4SLinus Torvalds 	pci_rev = *(vuip)MCPCIA_REV(mid);
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds 	mb();
2751da177e4SLinus Torvalds 	mb();  /* magic */
2761da177e4SLinus Torvalds 	if (mcheck_taken(cpu)) {
2771da177e4SLinus Torvalds 		mcheck_taken(cpu) = 0;
2781da177e4SLinus Torvalds 		pci_rev = 0xffffffff;
2791da177e4SLinus Torvalds 		mb();
2801da177e4SLinus Torvalds 	}
2811da177e4SLinus Torvalds 	mcheck_expected(cpu) = 0;
2821da177e4SLinus Torvalds 	mb();
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 	return (pci_rev >> 16) == PCI_CLASS_BRIDGE_HOST;
2851da177e4SLinus Torvalds }
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds static void __init
2881da177e4SLinus Torvalds mcpcia_new_hose(int h)
2891da177e4SLinus Torvalds {
2901da177e4SLinus Torvalds 	struct pci_controller *hose;
2911da177e4SLinus Torvalds 	struct resource *io, *mem, *hae_mem;
2921da177e4SLinus Torvalds 	int mid = MCPCIA_HOSE2MID(h);
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 	hose = alloc_pci_controller();
2951da177e4SLinus Torvalds 	if (h == 0)
2961da177e4SLinus Torvalds 		pci_isa_hose = hose;
2971da177e4SLinus Torvalds 	io = alloc_resource();
2981da177e4SLinus Torvalds 	mem = alloc_resource();
2991da177e4SLinus Torvalds 	hae_mem = alloc_resource();
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 	hose->io_space = io;
3021da177e4SLinus Torvalds 	hose->mem_space = hae_mem;
3031da177e4SLinus Torvalds 	hose->sparse_mem_base = MCPCIA_SPARSE(mid) - IDENT_ADDR;
3041da177e4SLinus Torvalds 	hose->dense_mem_base = MCPCIA_DENSE(mid) - IDENT_ADDR;
3051da177e4SLinus Torvalds 	hose->sparse_io_base = MCPCIA_IO(mid) - IDENT_ADDR;
3061da177e4SLinus Torvalds 	hose->dense_io_base = 0;
3071da177e4SLinus Torvalds 	hose->config_space_base = MCPCIA_CONF(mid);
3081da177e4SLinus Torvalds 	hose->index = h;
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	io->start = MCPCIA_IO(mid) - MCPCIA_IO_BIAS;
3111da177e4SLinus Torvalds 	io->end = io->start + 0xffff;
3121da177e4SLinus Torvalds 	io->name = pci_io_names[h];
3131da177e4SLinus Torvalds 	io->flags = IORESOURCE_IO;
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	mem->start = MCPCIA_DENSE(mid) - MCPCIA_MEM_BIAS;
3161da177e4SLinus Torvalds 	mem->end = mem->start + 0xffffffff;
3171da177e4SLinus Torvalds 	mem->name = pci_mem_names[h];
3181da177e4SLinus Torvalds 	mem->flags = IORESOURCE_MEM;
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	hae_mem->start = mem->start;
3211da177e4SLinus Torvalds 	hae_mem->end = mem->start + MCPCIA_MEM_MASK;
3221da177e4SLinus Torvalds 	hae_mem->name = pci_hae0_name;
3231da177e4SLinus Torvalds 	hae_mem->flags = IORESOURCE_MEM;
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds 	if (request_resource(&ioport_resource, io) < 0)
3261da177e4SLinus Torvalds 		printk(KERN_ERR "Failed to request IO on hose %d\n", h);
3271da177e4SLinus Torvalds 	if (request_resource(&iomem_resource, mem) < 0)
3281da177e4SLinus Torvalds 		printk(KERN_ERR "Failed to request MEM on hose %d\n", h);
3291da177e4SLinus Torvalds 	if (request_resource(mem, hae_mem) < 0)
3301da177e4SLinus Torvalds 		printk(KERN_ERR "Failed to request HAE_MEM on hose %d\n", h);
3311da177e4SLinus Torvalds }
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds static void
3341da177e4SLinus Torvalds mcpcia_pci_clr_err(int mid)
3351da177e4SLinus Torvalds {
3361da177e4SLinus Torvalds 	*(vuip)MCPCIA_CAP_ERR(mid);
3371da177e4SLinus Torvalds 	*(vuip)MCPCIA_CAP_ERR(mid) = 0xffffffff;   /* Clear them all.  */
3381da177e4SLinus Torvalds 	mb();
3391da177e4SLinus Torvalds 	*(vuip)MCPCIA_CAP_ERR(mid);  /* Re-read for force write.  */
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds static void __init
3431da177e4SLinus Torvalds mcpcia_startup_hose(struct pci_controller *hose)
3441da177e4SLinus Torvalds {
3451da177e4SLinus Torvalds 	int mid = MCPCIA_HOSE2MID(hose->index);
3461da177e4SLinus Torvalds 	unsigned int tmp;
3471da177e4SLinus Torvalds 
3481da177e4SLinus Torvalds 	mcpcia_pci_clr_err(mid);
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 	/*
3511da177e4SLinus Torvalds 	 * Set up error reporting.
3521da177e4SLinus Torvalds 	 */
3531da177e4SLinus Torvalds 	tmp = *(vuip)MCPCIA_CAP_ERR(mid);
3541da177e4SLinus Torvalds 	tmp |= 0x0006;		/* master/target abort */
3551da177e4SLinus Torvalds 	*(vuip)MCPCIA_CAP_ERR(mid) = tmp;
3561da177e4SLinus Torvalds 	mb();
3571da177e4SLinus Torvalds 	tmp = *(vuip)MCPCIA_CAP_ERR(mid);
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	/*
3601da177e4SLinus Torvalds 	 * Set up the PCI->physical memory translation windows.
3611da177e4SLinus Torvalds 	 *
3621da177e4SLinus Torvalds 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
3631da177e4SLinus Torvalds 	 * Window 1 is scatter-gather (up to) 1GB at 1GB (for pci)
3641da177e4SLinus Torvalds 	 * Window 2 is direct access 2GB at 2GB
3651da177e4SLinus Torvalds 	 */
3661da177e4SLinus Torvalds 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
3671da177e4SLinus Torvalds 	hose->sg_pci = iommu_arena_new(hose, 0x40000000,
3681da177e4SLinus Torvalds 				       size_for_memory(0x40000000), 0);
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	__direct_map_base = 0x80000000;
3711da177e4SLinus Torvalds 	__direct_map_size = 0x80000000;
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 	*(vuip)MCPCIA_W0_BASE(mid) = hose->sg_isa->dma_base | 3;
3741da177e4SLinus Torvalds 	*(vuip)MCPCIA_W0_MASK(mid) = (hose->sg_isa->size - 1) & 0xfff00000;
3751da177e4SLinus Torvalds 	*(vuip)MCPCIA_T0_BASE(mid) = virt_to_phys(hose->sg_isa->ptes) >> 8;
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	*(vuip)MCPCIA_W1_BASE(mid) = hose->sg_pci->dma_base | 3;
3781da177e4SLinus Torvalds 	*(vuip)MCPCIA_W1_MASK(mid) = (hose->sg_pci->size - 1) & 0xfff00000;
3791da177e4SLinus Torvalds 	*(vuip)MCPCIA_T1_BASE(mid) = virt_to_phys(hose->sg_pci->ptes) >> 8;
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 	*(vuip)MCPCIA_W2_BASE(mid) = __direct_map_base | 1;
3821da177e4SLinus Torvalds 	*(vuip)MCPCIA_W2_MASK(mid) = (__direct_map_size - 1) & 0xfff00000;
3831da177e4SLinus Torvalds 	*(vuip)MCPCIA_T2_BASE(mid) = 0;
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	*(vuip)MCPCIA_W3_BASE(mid) = 0x0;
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds 	mcpcia_pci_tbi(hose, 0, -1);
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	*(vuip)MCPCIA_HBASE(mid) = 0x0;
3901da177e4SLinus Torvalds 	mb();
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 	*(vuip)MCPCIA_HAE_MEM(mid) = 0U;
3931da177e4SLinus Torvalds 	mb();
3941da177e4SLinus Torvalds 	*(vuip)MCPCIA_HAE_MEM(mid); /* read it back. */
3951da177e4SLinus Torvalds 	*(vuip)MCPCIA_HAE_IO(mid) = 0;
3961da177e4SLinus Torvalds 	mb();
3971da177e4SLinus Torvalds 	*(vuip)MCPCIA_HAE_IO(mid);  /* read it back. */
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds 
4001da177e4SLinus Torvalds void __init
4011da177e4SLinus Torvalds mcpcia_init_arch(void)
4021da177e4SLinus Torvalds {
4031da177e4SLinus Torvalds 	/* With multiple PCI busses, we play with I/O as physical addrs.  */
4041da177e4SLinus Torvalds 	ioport_resource.end = ~0UL;
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds 	/* Allocate hose 0.  That's the one that all the ISA junk hangs
4071da177e4SLinus Torvalds 	   off of, from which we'll be registering stuff here in a bit.
4081da177e4SLinus Torvalds 	   Other hose detection is done in mcpcia_init_hoses, which is
4091da177e4SLinus Torvalds 	   called from init_IRQ.  */
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	mcpcia_new_hose(0);
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds /* This is called from init_IRQ, since we cannot take interrupts
4151da177e4SLinus Torvalds    before then.  Which means we cannot do this in init_arch.  */
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds void __init
4181da177e4SLinus Torvalds mcpcia_init_hoses(void)
4191da177e4SLinus Torvalds {
4201da177e4SLinus Torvalds 	struct pci_controller *hose;
4211da177e4SLinus Torvalds 	int hose_count;
4221da177e4SLinus Torvalds 	int h;
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 	/* First, find how many hoses we have.  */
4251da177e4SLinus Torvalds 	hose_count = 0;
4261da177e4SLinus Torvalds 	for (h = 0; h < MCPCIA_MAX_HOSES; ++h) {
4271da177e4SLinus Torvalds 		if (mcpcia_probe_hose(h)) {
4281da177e4SLinus Torvalds 			if (h != 0)
4291da177e4SLinus Torvalds 				mcpcia_new_hose(h);
4301da177e4SLinus Torvalds 			hose_count++;
4311da177e4SLinus Torvalds 		}
4321da177e4SLinus Torvalds 	}
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 	printk("mcpcia_init_hoses: found %d hoses\n", hose_count);
4351da177e4SLinus Torvalds 
4361da177e4SLinus Torvalds 	/* Now do init for each hose.  */
4371da177e4SLinus Torvalds 	for (hose = hose_head; hose; hose = hose->next)
4381da177e4SLinus Torvalds 		mcpcia_startup_hose(hose);
4391da177e4SLinus Torvalds }
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds static void
4421da177e4SLinus Torvalds mcpcia_print_uncorrectable(struct el_MCPCIA_uncorrected_frame_mcheck *logout)
4431da177e4SLinus Torvalds {
4441da177e4SLinus Torvalds 	struct el_common_EV5_uncorrectable_mcheck *frame;
4451da177e4SLinus Torvalds 	int i;
4461da177e4SLinus Torvalds 
4471da177e4SLinus Torvalds 	frame = &logout->procdata;
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds 	/* Print PAL fields */
4501da177e4SLinus Torvalds 	for (i = 0; i < 24; i += 2) {
4511da177e4SLinus Torvalds 		printk("  paltmp[%d-%d] = %16lx %16lx\n",
4521da177e4SLinus Torvalds 		       i, i+1, frame->paltemp[i], frame->paltemp[i+1]);
4531da177e4SLinus Torvalds 	}
4541da177e4SLinus Torvalds 	for (i = 0; i < 8; i += 2) {
4551da177e4SLinus Torvalds 		printk("  shadow[%d-%d] = %16lx %16lx\n",
4561da177e4SLinus Torvalds 		       i, i+1, frame->shadow[i],
4571da177e4SLinus Torvalds 		       frame->shadow[i+1]);
4581da177e4SLinus Torvalds 	}
4591da177e4SLinus Torvalds 	printk("  Addr of excepting instruction  = %16lx\n",
4601da177e4SLinus Torvalds 	       frame->exc_addr);
4611da177e4SLinus Torvalds 	printk("  Summary of arithmetic traps    = %16lx\n",
4621da177e4SLinus Torvalds 	       frame->exc_sum);
4631da177e4SLinus Torvalds 	printk("  Exception mask                 = %16lx\n",
4641da177e4SLinus Torvalds 	       frame->exc_mask);
4651da177e4SLinus Torvalds 	printk("  Base address for PALcode       = %16lx\n",
4661da177e4SLinus Torvalds 	       frame->pal_base);
4671da177e4SLinus Torvalds 	printk("  Interrupt Status Reg           = %16lx\n",
4681da177e4SLinus Torvalds 	       frame->isr);
4691da177e4SLinus Torvalds 	printk("  CURRENT SETUP OF EV5 IBOX      = %16lx\n",
4701da177e4SLinus Torvalds 	       frame->icsr);
4711da177e4SLinus Torvalds 	printk("  I-CACHE Reg %s parity error   = %16lx\n",
4721da177e4SLinus Torvalds 	       (frame->ic_perr_stat & 0x800L) ?
4731da177e4SLinus Torvalds 	       "Data" : "Tag",
4741da177e4SLinus Torvalds 	       frame->ic_perr_stat);
4751da177e4SLinus Torvalds 	printk("  D-CACHE error Reg              = %16lx\n",
4761da177e4SLinus Torvalds 	       frame->dc_perr_stat);
4771da177e4SLinus Torvalds 	if (frame->dc_perr_stat & 0x2) {
4781da177e4SLinus Torvalds 		switch (frame->dc_perr_stat & 0x03c) {
4791da177e4SLinus Torvalds 		case 8:
4801da177e4SLinus Torvalds 			printk("    Data error in bank 1\n");
4811da177e4SLinus Torvalds 			break;
4821da177e4SLinus Torvalds 		case 4:
4831da177e4SLinus Torvalds 			printk("    Data error in bank 0\n");
4841da177e4SLinus Torvalds 			break;
4851da177e4SLinus Torvalds 		case 20:
4861da177e4SLinus Torvalds 			printk("    Tag error in bank 1\n");
4871da177e4SLinus Torvalds 			break;
4881da177e4SLinus Torvalds 		case 10:
4891da177e4SLinus Torvalds 			printk("    Tag error in bank 0\n");
4901da177e4SLinus Torvalds 			break;
4911da177e4SLinus Torvalds 		}
4921da177e4SLinus Torvalds 	}
4931da177e4SLinus Torvalds 	printk("  Effective VA                   = %16lx\n",
4941da177e4SLinus Torvalds 	       frame->va);
4951da177e4SLinus Torvalds 	printk("  Reason for D-stream            = %16lx\n",
4961da177e4SLinus Torvalds 	       frame->mm_stat);
4971da177e4SLinus Torvalds 	printk("  EV5 SCache address             = %16lx\n",
4981da177e4SLinus Torvalds 	       frame->sc_addr);
4991da177e4SLinus Torvalds 	printk("  EV5 SCache TAG/Data parity     = %16lx\n",
5001da177e4SLinus Torvalds 	       frame->sc_stat);
5011da177e4SLinus Torvalds 	printk("  EV5 BC_TAG_ADDR                = %16lx\n",
5021da177e4SLinus Torvalds 	       frame->bc_tag_addr);
5031da177e4SLinus Torvalds 	printk("  EV5 EI_ADDR: Phys addr of Xfer = %16lx\n",
5041da177e4SLinus Torvalds 	       frame->ei_addr);
5051da177e4SLinus Torvalds 	printk("  Fill Syndrome                  = %16lx\n",
5061da177e4SLinus Torvalds 	       frame->fill_syndrome);
5071da177e4SLinus Torvalds 	printk("  EI_STAT reg                    = %16lx\n",
5081da177e4SLinus Torvalds 	       frame->ei_stat);
5091da177e4SLinus Torvalds 	printk("  LD_LOCK                        = %16lx\n",
5101da177e4SLinus Torvalds 	       frame->ld_lock);
5111da177e4SLinus Torvalds }
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds static void
5141da177e4SLinus Torvalds mcpcia_print_system_area(unsigned long la_ptr)
5151da177e4SLinus Torvalds {
5161da177e4SLinus Torvalds 	struct el_common *frame;
5171da177e4SLinus Torvalds 	struct pci_controller *hose;
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds 	struct IOD_subpacket {
5201da177e4SLinus Torvalds 	  unsigned long base;
5211da177e4SLinus Torvalds 	  unsigned int whoami;
5221da177e4SLinus Torvalds 	  unsigned int rsvd1;
5231da177e4SLinus Torvalds 	  unsigned int pci_rev;
5241da177e4SLinus Torvalds 	  unsigned int cap_ctrl;
5251da177e4SLinus Torvalds 	  unsigned int hae_mem;
5261da177e4SLinus Torvalds 	  unsigned int hae_io;
5271da177e4SLinus Torvalds 	  unsigned int int_ctl;
5281da177e4SLinus Torvalds 	  unsigned int int_reg;
5291da177e4SLinus Torvalds 	  unsigned int int_mask0;
5301da177e4SLinus Torvalds 	  unsigned int int_mask1;
5311da177e4SLinus Torvalds 	  unsigned int mc_err0;
5321da177e4SLinus Torvalds 	  unsigned int mc_err1;
5331da177e4SLinus Torvalds 	  unsigned int cap_err;
5341da177e4SLinus Torvalds 	  unsigned int rsvd2;
5351da177e4SLinus Torvalds 	  unsigned int pci_err1;
5361da177e4SLinus Torvalds 	  unsigned int mdpa_stat;
5371da177e4SLinus Torvalds 	  unsigned int mdpa_syn;
5381da177e4SLinus Torvalds 	  unsigned int mdpb_stat;
5391da177e4SLinus Torvalds 	  unsigned int mdpb_syn;
5401da177e4SLinus Torvalds 	  unsigned int rsvd3;
5411da177e4SLinus Torvalds 	  unsigned int rsvd4;
5421da177e4SLinus Torvalds 	  unsigned int rsvd5;
5431da177e4SLinus Torvalds 	} *iodpp;
5441da177e4SLinus Torvalds 
5451da177e4SLinus Torvalds 	frame = (struct el_common *)la_ptr;
5461da177e4SLinus Torvalds 	iodpp = (struct IOD_subpacket *) (la_ptr + frame->sys_offset);
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	for (hose = hose_head; hose; hose = hose->next, iodpp++) {
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	  printk("IOD %d Register Subpacket - Bridge Base Address %16lx\n",
5511da177e4SLinus Torvalds 		 hose->index, iodpp->base);
5521da177e4SLinus Torvalds 	  printk("  WHOAMI      = %8x\n", iodpp->whoami);
5531da177e4SLinus Torvalds 	  printk("  PCI_REV     = %8x\n", iodpp->pci_rev);
5541da177e4SLinus Torvalds 	  printk("  CAP_CTRL    = %8x\n", iodpp->cap_ctrl);
5551da177e4SLinus Torvalds 	  printk("  HAE_MEM     = %8x\n", iodpp->hae_mem);
5561da177e4SLinus Torvalds 	  printk("  HAE_IO      = %8x\n", iodpp->hae_io);
5571da177e4SLinus Torvalds 	  printk("  INT_CTL     = %8x\n", iodpp->int_ctl);
5581da177e4SLinus Torvalds 	  printk("  INT_REG     = %8x\n", iodpp->int_reg);
5591da177e4SLinus Torvalds 	  printk("  INT_MASK0   = %8x\n", iodpp->int_mask0);
5601da177e4SLinus Torvalds 	  printk("  INT_MASK1   = %8x\n", iodpp->int_mask1);
5611da177e4SLinus Torvalds 	  printk("  MC_ERR0     = %8x\n", iodpp->mc_err0);
5621da177e4SLinus Torvalds 	  printk("  MC_ERR1     = %8x\n", iodpp->mc_err1);
5631da177e4SLinus Torvalds 	  printk("  CAP_ERR     = %8x\n", iodpp->cap_err);
5641da177e4SLinus Torvalds 	  printk("  PCI_ERR1    = %8x\n", iodpp->pci_err1);
5651da177e4SLinus Torvalds 	  printk("  MDPA_STAT   = %8x\n", iodpp->mdpa_stat);
5661da177e4SLinus Torvalds 	  printk("  MDPA_SYN    = %8x\n", iodpp->mdpa_syn);
5671da177e4SLinus Torvalds 	  printk("  MDPB_STAT   = %8x\n", iodpp->mdpb_stat);
5681da177e4SLinus Torvalds 	  printk("  MDPB_SYN    = %8x\n", iodpp->mdpb_syn);
5691da177e4SLinus Torvalds 	}
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds void
5734fa1970aSAl Viro mcpcia_machine_check(unsigned long vector, unsigned long la_ptr)
5741da177e4SLinus Torvalds {
5751da177e4SLinus Torvalds 	struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout;
5761da177e4SLinus Torvalds 	unsigned int cpu = smp_processor_id();
5771da177e4SLinus Torvalds 	int expected;
5781da177e4SLinus Torvalds 
5791da177e4SLinus Torvalds 	mchk_logout = (struct el_MCPCIA_uncorrected_frame_mcheck *)la_ptr;
5801da177e4SLinus Torvalds 	expected = mcheck_expected(cpu);
5811da177e4SLinus Torvalds 
5821da177e4SLinus Torvalds 	mb();
5831da177e4SLinus Torvalds 	mb();  /* magic */
5841da177e4SLinus Torvalds 	draina();
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds 	switch (expected) {
5871da177e4SLinus Torvalds 	case 0:
5881da177e4SLinus Torvalds 	    {
5891da177e4SLinus Torvalds 		/* FIXME: how do we figure out which hose the
5901da177e4SLinus Torvalds 		   error was on?  */
5911da177e4SLinus Torvalds 		struct pci_controller *hose;
5921da177e4SLinus Torvalds 		for (hose = hose_head; hose; hose = hose->next)
5931da177e4SLinus Torvalds 			mcpcia_pci_clr_err(MCPCIA_HOSE2MID(hose->index));
5941da177e4SLinus Torvalds 		break;
5951da177e4SLinus Torvalds 	    }
5961da177e4SLinus Torvalds 	case 1:
5971da177e4SLinus Torvalds 		mcpcia_pci_clr_err(mcheck_extra(cpu));
5981da177e4SLinus Torvalds 		break;
5991da177e4SLinus Torvalds 	default:
6001da177e4SLinus Torvalds 		/* Otherwise, we're being called from mcpcia_probe_hose
6011da177e4SLinus Torvalds 		   and there's no hose clear an error from.  */
6021da177e4SLinus Torvalds 		break;
6031da177e4SLinus Torvalds 	}
6041da177e4SLinus Torvalds 
6051da177e4SLinus Torvalds 	wrmces(0x7);
6061da177e4SLinus Torvalds 	mb();
6071da177e4SLinus Torvalds 
6084fa1970aSAl Viro 	process_mcheck_info(vector, la_ptr, "MCPCIA", expected != 0);
6091da177e4SLinus Torvalds 	if (!expected && vector != 0x620 && vector != 0x630) {
6101da177e4SLinus Torvalds 		mcpcia_print_uncorrectable(mchk_logout);
6111da177e4SLinus Torvalds 		mcpcia_print_system_area(la_ptr);
6121da177e4SLinus Torvalds 	}
6131da177e4SLinus Torvalds }
614