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