xref: /openbmc/linux/arch/alpha/kernel/core_t2.c (revision 3eb66e91a25497065c5322b1268cbc3953642227)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	linux/arch/alpha/kernel/core_t2.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Written by Jay A Estabrook (jestabro@amt.tay1.dec.com).
61da177e4SLinus Torvalds  * December 1996.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * based on CIA code by David A Rusling (david.rusling@reo.mts.dec.com)
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * Code common to all T2 core logic chips.
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds #define __EXTERN_INLINE
141da177e4SLinus Torvalds #include <asm/io.h>
151da177e4SLinus Torvalds #include <asm/core_t2.h>
161da177e4SLinus Torvalds #undef __EXTERN_INLINE
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include <linux/types.h>
191da177e4SLinus Torvalds #include <linux/pci.h>
201da177e4SLinus Torvalds #include <linux/sched.h>
211da177e4SLinus Torvalds #include <linux/init.h>
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #include <asm/ptrace.h>
241da177e4SLinus Torvalds #include <asm/delay.h>
25ec221208SDavid Howells #include <asm/mce.h>
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds #include "proto.h"
281da177e4SLinus Torvalds #include "pci_impl.h"
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds /* For dumping initial DMA window settings. */
311da177e4SLinus Torvalds #define DEBUG_PRINT_INITIAL_SETTINGS 0
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds /* For dumping final DMA window settings. */
341da177e4SLinus Torvalds #define DEBUG_PRINT_FINAL_SETTINGS 0
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds /*
371da177e4SLinus Torvalds  * By default, we direct-map starting at 2GB, in order to allow the
381da177e4SLinus Torvalds  * maximum size direct-map window (2GB) to match the maximum amount of
391da177e4SLinus Torvalds  * memory (2GB) that can be present on SABLEs. But that limits the
401da177e4SLinus Torvalds  * floppy to DMA only via the scatter/gather window set up for 8MB
411da177e4SLinus Torvalds  * ISA DMA, since the maximum ISA DMA address is 2GB-1.
421da177e4SLinus Torvalds  *
431da177e4SLinus Torvalds  * For now, this seems a reasonable trade-off: even though most SABLEs
441da177e4SLinus Torvalds  * have less than 1GB of memory, floppy usage/performance will not
451da177e4SLinus Torvalds  * really be affected by forcing it to go via scatter/gather...
461da177e4SLinus Torvalds  */
471da177e4SLinus Torvalds #define T2_DIRECTMAP_2G 1
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds #if T2_DIRECTMAP_2G
501da177e4SLinus Torvalds # define T2_DIRECTMAP_START	0x80000000UL
511da177e4SLinus Torvalds # define T2_DIRECTMAP_LENGTH	0x80000000UL
521da177e4SLinus Torvalds #else
531da177e4SLinus Torvalds # define T2_DIRECTMAP_START	0x40000000UL
541da177e4SLinus Torvalds # define T2_DIRECTMAP_LENGTH	0x40000000UL
551da177e4SLinus Torvalds #endif
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds /* The ISA scatter/gather window settings. */
581da177e4SLinus Torvalds #define T2_ISA_SG_START		0x00800000UL
591da177e4SLinus Torvalds #define T2_ISA_SG_LENGTH	0x00800000UL
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /*
621da177e4SLinus Torvalds  * NOTE: Herein lie back-to-back mb instructions.  They are magic.
631da177e4SLinus Torvalds  * One plausible explanation is that the i/o controller does not properly
641da177e4SLinus Torvalds  * handle the system transaction.  Another involves timing.  Ho hum.
651da177e4SLinus Torvalds  */
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds /*
681da177e4SLinus Torvalds  * BIOS32-style PCI interface:
691da177e4SLinus Torvalds  */
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds #define DEBUG_CONFIG 0
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds #if DEBUG_CONFIG
741da177e4SLinus Torvalds # define DBG(args)	printk args
751da177e4SLinus Torvalds #else
761da177e4SLinus Torvalds # define DBG(args)
771da177e4SLinus Torvalds #endif
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds static volatile unsigned int t2_mcheck_any_expected;
801da177e4SLinus Torvalds static volatile unsigned int t2_mcheck_last_taken;
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds /* Place to save the DMA Window registers as set up by SRM
831da177e4SLinus Torvalds    for restoration during shutdown. */
841da177e4SLinus Torvalds static struct
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds 	struct {
871da177e4SLinus Torvalds 		unsigned long wbase;
881da177e4SLinus Torvalds 		unsigned long wmask;
891da177e4SLinus Torvalds 		unsigned long tbase;
901da177e4SLinus Torvalds 	} window[2];
911da177e4SLinus Torvalds 	unsigned long hae_1;
921da177e4SLinus Torvalds   	unsigned long hae_2;
931da177e4SLinus Torvalds 	unsigned long hae_3;
941da177e4SLinus Torvalds 	unsigned long hae_4;
951da177e4SLinus Torvalds 	unsigned long hbase;
961da177e4SLinus Torvalds } t2_saved_config __attribute((common));
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds /*
991da177e4SLinus Torvalds  * Given a bus, device, and function number, compute resulting
1001da177e4SLinus Torvalds  * configuration space address and setup the T2_HAXR2 register
1011da177e4SLinus Torvalds  * accordingly.  It is therefore not safe to have concurrent
1021da177e4SLinus Torvalds  * invocations to configuration space access routines, but there
1031da177e4SLinus Torvalds  * really shouldn't be any need for this.
1041da177e4SLinus Torvalds  *
1051da177e4SLinus Torvalds  * Type 0:
1061da177e4SLinus Torvalds  *
1071da177e4SLinus 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
1081da177e4SLinus 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
1091da177e4SLinus Torvalds  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1101da177e4SLinus 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|
1111da177e4SLinus Torvalds  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1121da177e4SLinus Torvalds  *
1131da177e4SLinus Torvalds  *	31:11	Device select bit.
1141da177e4SLinus Torvalds  * 	10:8	Function number
1151da177e4SLinus Torvalds  * 	 7:2	Register number
1161da177e4SLinus Torvalds  *
1171da177e4SLinus Torvalds  * Type 1:
1181da177e4SLinus Torvalds  *
1191da177e4SLinus 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
1201da177e4SLinus 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
1211da177e4SLinus Torvalds  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1221da177e4SLinus 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|
1231da177e4SLinus Torvalds  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1241da177e4SLinus Torvalds  *
1251da177e4SLinus Torvalds  *	31:24	reserved
1261da177e4SLinus Torvalds  *	23:16	bus number (8 bits = 128 possible buses)
1271da177e4SLinus Torvalds  *	15:11	Device number (5 bits)
1281da177e4SLinus Torvalds  *	10:8	function number
1291da177e4SLinus Torvalds  *	 7:2	register number
1301da177e4SLinus Torvalds  *
1311da177e4SLinus Torvalds  * Notes:
1321da177e4SLinus Torvalds  *	The function number selects which function of a multi-function device
1331da177e4SLinus Torvalds  *	(e.g., SCSI and Ethernet).
1341da177e4SLinus Torvalds  *
1351da177e4SLinus Torvalds  *	The register selects a DWORD (32 bit) register offset.  Hence it
1361da177e4SLinus Torvalds  *	doesn't get shifted by 2 bits as we want to "drop" the bottom two
1371da177e4SLinus Torvalds  *	bits.
1381da177e4SLinus Torvalds  */
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds static int
mk_conf_addr(struct pci_bus * pbus,unsigned int device_fn,int where,unsigned long * pci_addr,unsigned char * type1)1411da177e4SLinus Torvalds mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where,
1421da177e4SLinus Torvalds 	     unsigned long *pci_addr, unsigned char *type1)
1431da177e4SLinus Torvalds {
1441da177e4SLinus Torvalds 	unsigned long addr;
1451da177e4SLinus Torvalds 	u8 bus = pbus->number;
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 	DBG(("mk_conf_addr(bus=%d, dfn=0x%x, where=0x%x,"
1481da177e4SLinus Torvalds 	     " addr=0x%lx, type1=0x%x)\n",
1491da177e4SLinus Torvalds 	     bus, device_fn, where, pci_addr, type1));
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds 	if (bus == 0) {
1521da177e4SLinus Torvalds 		int device = device_fn >> 3;
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 		/* Type 0 configuration cycle.  */
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 		if (device > 8) {
1571da177e4SLinus Torvalds 			DBG(("mk_conf_addr: device (%d)>20, returning -1\n",
1581da177e4SLinus Torvalds 			     device));
1591da177e4SLinus Torvalds 			return -1;
1601da177e4SLinus Torvalds 		}
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 		*type1 = 0;
1631da177e4SLinus Torvalds 		addr = (0x0800L << device) | ((device_fn & 7) << 8) | (where);
1641da177e4SLinus Torvalds 	} else {
1651da177e4SLinus Torvalds 		/* Type 1 configuration cycle.  */
1661da177e4SLinus Torvalds 		*type1 = 1;
1671da177e4SLinus Torvalds 		addr = (bus << 16) | (device_fn << 8) | (where);
1681da177e4SLinus Torvalds 	}
1691da177e4SLinus Torvalds 	*pci_addr = addr;
1701da177e4SLinus Torvalds 	DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
1711da177e4SLinus Torvalds 	return 0;
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds 
1741da177e4SLinus Torvalds /*
1751da177e4SLinus Torvalds  * NOTE: both conf_read() and conf_write() may set HAE_3 when needing
1761da177e4SLinus Torvalds  *       to do type1 access. This is protected by the use of spinlock IRQ
1771da177e4SLinus Torvalds  *       primitives in the wrapper functions pci_{read,write}_config_*()
1781da177e4SLinus Torvalds  *       defined in drivers/pci/pci.c.
1791da177e4SLinus Torvalds  */
1801da177e4SLinus Torvalds static unsigned int
conf_read(unsigned long addr,unsigned char type1)1811da177e4SLinus Torvalds conf_read(unsigned long addr, unsigned char type1)
1821da177e4SLinus Torvalds {
1831da177e4SLinus Torvalds 	unsigned int value, cpu, taken;
1841da177e4SLinus Torvalds 	unsigned long t2_cfg = 0;
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds 	cpu = smp_processor_id();
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 	DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	/* If Type1 access, must set T2 CFG.  */
1911da177e4SLinus Torvalds 	if (type1) {
1921da177e4SLinus Torvalds 		t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL;
1931da177e4SLinus Torvalds 		*(vulp)T2_HAE_3 = 0x40000000UL | t2_cfg;
1941da177e4SLinus Torvalds 		mb();
1951da177e4SLinus Torvalds 	}
1961da177e4SLinus Torvalds 	mb();
1971da177e4SLinus Torvalds 	draina();
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	mcheck_expected(cpu) = 1;
2001da177e4SLinus Torvalds 	mcheck_taken(cpu) = 0;
2011da177e4SLinus Torvalds 	t2_mcheck_any_expected |= (1 << cpu);
2021da177e4SLinus Torvalds 	mb();
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	/* Access configuration space. */
2051da177e4SLinus Torvalds 	value = *(vuip)addr;
2061da177e4SLinus Torvalds 	mb();
2071da177e4SLinus Torvalds 	mb();  /* magic */
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	/* Wait for possible mcheck. Also, this lets other CPUs clear
2101da177e4SLinus Torvalds 	   their mchecks as well, as they can reliably tell when
2111da177e4SLinus Torvalds 	   another CPU is in the midst of handling a real mcheck via
2121da177e4SLinus Torvalds 	   the "taken" function. */
2131da177e4SLinus Torvalds 	udelay(100);
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 	if ((taken = mcheck_taken(cpu))) {
2161da177e4SLinus Torvalds 		mcheck_taken(cpu) = 0;
2171da177e4SLinus Torvalds 		t2_mcheck_last_taken |= (1 << cpu);
2181da177e4SLinus Torvalds 		value = 0xffffffffU;
2191da177e4SLinus Torvalds 		mb();
2201da177e4SLinus Torvalds 	}
2211da177e4SLinus Torvalds 	mcheck_expected(cpu) = 0;
2221da177e4SLinus Torvalds 	t2_mcheck_any_expected = 0;
2231da177e4SLinus Torvalds 	mb();
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	/* If Type1 access, must reset T2 CFG so normal IO space ops work.  */
2261da177e4SLinus Torvalds 	if (type1) {
2271da177e4SLinus Torvalds 		*(vulp)T2_HAE_3 = t2_cfg;
2281da177e4SLinus Torvalds 		mb();
2291da177e4SLinus Torvalds 	}
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	return value;
2321da177e4SLinus Torvalds }
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds static void
conf_write(unsigned long addr,unsigned int value,unsigned char type1)2351da177e4SLinus Torvalds conf_write(unsigned long addr, unsigned int value, unsigned char type1)
2361da177e4SLinus Torvalds {
2371da177e4SLinus Torvalds 	unsigned int cpu, taken;
2381da177e4SLinus Torvalds 	unsigned long t2_cfg = 0;
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 	cpu = smp_processor_id();
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 	/* If Type1 access, must set T2 CFG.  */
2431da177e4SLinus Torvalds 	if (type1) {
2441da177e4SLinus Torvalds 		t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL;
2451da177e4SLinus Torvalds 		*(vulp)T2_HAE_3 = t2_cfg | 0x40000000UL;
2461da177e4SLinus Torvalds 		mb();
2471da177e4SLinus Torvalds 	}
2481da177e4SLinus Torvalds 	mb();
2491da177e4SLinus Torvalds 	draina();
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	mcheck_expected(cpu) = 1;
2521da177e4SLinus Torvalds 	mcheck_taken(cpu) = 0;
2531da177e4SLinus Torvalds 	t2_mcheck_any_expected |= (1 << cpu);
2541da177e4SLinus Torvalds 	mb();
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	/* Access configuration space.  */
2571da177e4SLinus Torvalds 	*(vuip)addr = value;
2581da177e4SLinus Torvalds 	mb();
2591da177e4SLinus Torvalds 	mb();  /* magic */
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 	/* Wait for possible mcheck. Also, this lets other CPUs clear
2621da177e4SLinus Torvalds 	   their mchecks as well, as they can reliably tell when
2631da177e4SLinus Torvalds 	   this CPU is in the midst of handling a real mcheck via
2641da177e4SLinus Torvalds 	   the "taken" function. */
2651da177e4SLinus Torvalds 	udelay(100);
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	if ((taken = mcheck_taken(cpu))) {
2681da177e4SLinus Torvalds 		mcheck_taken(cpu) = 0;
2691da177e4SLinus Torvalds 		t2_mcheck_last_taken |= (1 << cpu);
2701da177e4SLinus Torvalds 		mb();
2711da177e4SLinus Torvalds 	}
2721da177e4SLinus Torvalds 	mcheck_expected(cpu) = 0;
2731da177e4SLinus Torvalds 	t2_mcheck_any_expected = 0;
2741da177e4SLinus Torvalds 	mb();
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 	/* If Type1 access, must reset T2 CFG so normal IO space ops work.  */
2771da177e4SLinus Torvalds 	if (type1) {
2781da177e4SLinus Torvalds 		*(vulp)T2_HAE_3 = t2_cfg;
2791da177e4SLinus Torvalds 		mb();
2801da177e4SLinus Torvalds 	}
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds static int
t2_read_config(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 * value)2841da177e4SLinus Torvalds t2_read_config(struct pci_bus *bus, unsigned int devfn, int where,
2851da177e4SLinus Torvalds 	       int size, u32 *value)
2861da177e4SLinus Torvalds {
2871da177e4SLinus Torvalds 	unsigned long addr, pci_addr;
2881da177e4SLinus Torvalds 	unsigned char type1;
2891da177e4SLinus Torvalds 	int shift;
2901da177e4SLinus Torvalds 	long mask;
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 	if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1))
2931da177e4SLinus Torvalds 		return PCIBIOS_DEVICE_NOT_FOUND;
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 	mask = (size - 1) * 8;
2961da177e4SLinus Torvalds 	shift = (where & 3) * 8;
2971da177e4SLinus Torvalds 	addr = (pci_addr << 5) + mask + T2_CONF;
2981da177e4SLinus Torvalds 	*value = conf_read(addr, type1) >> (shift);
2991da177e4SLinus Torvalds 	return PCIBIOS_SUCCESSFUL;
3001da177e4SLinus Torvalds }
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds static int
t2_write_config(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 value)3031da177e4SLinus Torvalds t2_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size,
3041da177e4SLinus Torvalds 		u32 value)
3051da177e4SLinus Torvalds {
3061da177e4SLinus Torvalds 	unsigned long addr, pci_addr;
3071da177e4SLinus Torvalds 	unsigned char type1;
3081da177e4SLinus Torvalds 	long mask;
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1))
3111da177e4SLinus Torvalds 		return PCIBIOS_DEVICE_NOT_FOUND;
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 	mask = (size - 1) * 8;
3141da177e4SLinus Torvalds 	addr = (pci_addr << 5) + mask + T2_CONF;
3151da177e4SLinus Torvalds 	conf_write(addr, value << ((where & 3) * 8), type1);
3161da177e4SLinus Torvalds 	return PCIBIOS_SUCCESSFUL;
3171da177e4SLinus Torvalds }
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds struct pci_ops t2_pci_ops =
3201da177e4SLinus Torvalds {
3211da177e4SLinus Torvalds 	.read =		t2_read_config,
3221da177e4SLinus Torvalds 	.write =	t2_write_config,
3231da177e4SLinus Torvalds };
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds static void __init
t2_direct_map_window1(unsigned long base,unsigned long length)3261da177e4SLinus Torvalds t2_direct_map_window1(unsigned long base, unsigned long length)
3271da177e4SLinus Torvalds {
3281da177e4SLinus Torvalds 	unsigned long temp;
3291da177e4SLinus Torvalds 
3301da177e4SLinus Torvalds 	__direct_map_base = base;
3311da177e4SLinus Torvalds 	__direct_map_size = length;
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	temp = (base & 0xfff00000UL) | ((base + length - 1) >> 20);
3341da177e4SLinus Torvalds 	*(vulp)T2_WBASE1 = temp | 0x80000UL; /* OR in ENABLE bit */
3351da177e4SLinus Torvalds 	temp = (length - 1) & 0xfff00000UL;
3361da177e4SLinus Torvalds 	*(vulp)T2_WMASK1 = temp;
3371da177e4SLinus Torvalds 	*(vulp)T2_TBASE1 = 0;
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds #if DEBUG_PRINT_FINAL_SETTINGS
3401da177e4SLinus Torvalds 	printk("%s: setting WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
341bbb8d343SHarvey Harrison 	       __func__, *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1);
3421da177e4SLinus Torvalds #endif
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds static void __init
t2_sg_map_window2(struct pci_controller * hose,unsigned long base,unsigned long length)3461da177e4SLinus Torvalds t2_sg_map_window2(struct pci_controller *hose,
3471da177e4SLinus Torvalds 		  unsigned long base,
3481da177e4SLinus Torvalds 		  unsigned long length)
3491da177e4SLinus Torvalds {
3501da177e4SLinus Torvalds 	unsigned long temp;
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 	/* Note we can only do 1 SG window, as the other is for direct, so
3531da177e4SLinus Torvalds 	   do an ISA SG area, especially for the floppy. */
354*7e1c4e27SMike Rapoport 	hose->sg_isa = iommu_arena_new(hose, base, length, SMP_CACHE_BYTES);
3551da177e4SLinus Torvalds 	hose->sg_pci = NULL;
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	temp = (base & 0xfff00000UL) | ((base + length - 1) >> 20);
3581da177e4SLinus Torvalds 	*(vulp)T2_WBASE2 = temp | 0xc0000UL; /* OR in ENABLE/SG bits */
3591da177e4SLinus Torvalds 	temp = (length - 1) & 0xfff00000UL;
3601da177e4SLinus Torvalds 	*(vulp)T2_WMASK2 = temp;
3611da177e4SLinus Torvalds 	*(vulp)T2_TBASE2 = virt_to_phys(hose->sg_isa->ptes) >> 1;
3621da177e4SLinus Torvalds 	mb();
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds 	t2_pci_tbi(hose, 0, -1); /* flush TLB all */
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds #if DEBUG_PRINT_FINAL_SETTINGS
3671da177e4SLinus Torvalds 	printk("%s: setting WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
368bbb8d343SHarvey Harrison 	       __func__, *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2);
3691da177e4SLinus Torvalds #endif
3701da177e4SLinus Torvalds }
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds static void __init
t2_save_configuration(void)3731da177e4SLinus Torvalds t2_save_configuration(void)
3741da177e4SLinus Torvalds {
3751da177e4SLinus Torvalds #if DEBUG_PRINT_INITIAL_SETTINGS
376bbb8d343SHarvey Harrison 	printk("%s: HAE_1 was 0x%lx\n", __func__, srm_hae); /* HW is 0 */
377bbb8d343SHarvey Harrison 	printk("%s: HAE_2 was 0x%lx\n", __func__, *(vulp)T2_HAE_2);
378bbb8d343SHarvey Harrison 	printk("%s: HAE_3 was 0x%lx\n", __func__, *(vulp)T2_HAE_3);
379bbb8d343SHarvey Harrison 	printk("%s: HAE_4 was 0x%lx\n", __func__, *(vulp)T2_HAE_4);
380bbb8d343SHarvey Harrison 	printk("%s: HBASE was 0x%lx\n", __func__, *(vulp)T2_HBASE);
3811da177e4SLinus Torvalds 
382bbb8d343SHarvey Harrison 	printk("%s: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n", __func__,
3831da177e4SLinus Torvalds 	       *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1);
384bbb8d343SHarvey Harrison 	printk("%s: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n", __func__,
3851da177e4SLinus Torvalds 	       *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2);
3861da177e4SLinus Torvalds #endif
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	/*
3891da177e4SLinus Torvalds 	 * Save the DMA Window registers.
3901da177e4SLinus Torvalds 	 */
3911da177e4SLinus Torvalds 	t2_saved_config.window[0].wbase = *(vulp)T2_WBASE1;
3921da177e4SLinus Torvalds 	t2_saved_config.window[0].wmask = *(vulp)T2_WMASK1;
3931da177e4SLinus Torvalds 	t2_saved_config.window[0].tbase = *(vulp)T2_TBASE1;
3941da177e4SLinus Torvalds 	t2_saved_config.window[1].wbase = *(vulp)T2_WBASE2;
3951da177e4SLinus Torvalds 	t2_saved_config.window[1].wmask = *(vulp)T2_WMASK2;
3961da177e4SLinus Torvalds 	t2_saved_config.window[1].tbase = *(vulp)T2_TBASE2;
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 	t2_saved_config.hae_1 = srm_hae; /* HW is already set to 0 */
3991da177e4SLinus Torvalds 	t2_saved_config.hae_2 = *(vulp)T2_HAE_2;
4001da177e4SLinus Torvalds 	t2_saved_config.hae_3 = *(vulp)T2_HAE_3;
4011da177e4SLinus Torvalds 	t2_saved_config.hae_4 = *(vulp)T2_HAE_4;
4021da177e4SLinus Torvalds 	t2_saved_config.hbase = *(vulp)T2_HBASE;
4031da177e4SLinus Torvalds }
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds void __init
t2_init_arch(void)4061da177e4SLinus Torvalds t2_init_arch(void)
4071da177e4SLinus Torvalds {
4081da177e4SLinus Torvalds 	struct pci_controller *hose;
40998c532ecSIvan Kokshaysky 	struct resource *hae_mem;
4101da177e4SLinus Torvalds 	unsigned long temp;
4111da177e4SLinus Torvalds 	unsigned int i;
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 	for (i = 0; i < NR_CPUS; i++) {
4141da177e4SLinus Torvalds 		mcheck_expected(i) = 0;
4151da177e4SLinus Torvalds 		mcheck_taken(i) = 0;
4161da177e4SLinus Torvalds 	}
4171da177e4SLinus Torvalds 	t2_mcheck_any_expected = 0;
4181da177e4SLinus Torvalds 	t2_mcheck_last_taken = 0;
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds 	/* Enable scatter/gather TLB use.  */
4211da177e4SLinus Torvalds 	temp = *(vulp)T2_IOCSR;
4221da177e4SLinus Torvalds 	if (!(temp & (0x1UL << 26))) {
4231da177e4SLinus Torvalds 		printk("t2_init_arch: enabling SG TLB, IOCSR was 0x%lx\n",
4241da177e4SLinus Torvalds 		       temp);
4251da177e4SLinus Torvalds 		*(vulp)T2_IOCSR = temp | (0x1UL << 26);
4261da177e4SLinus Torvalds 		mb();
4271da177e4SLinus Torvalds 		*(vulp)T2_IOCSR; /* read it back to make sure */
4281da177e4SLinus Torvalds 	}
4291da177e4SLinus Torvalds 
4301da177e4SLinus Torvalds 	t2_save_configuration();
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 	/*
4331da177e4SLinus Torvalds 	 * Create our single hose.
4341da177e4SLinus Torvalds 	 */
4351da177e4SLinus Torvalds 	pci_isa_hose = hose = alloc_pci_controller();
4361da177e4SLinus Torvalds 	hose->io_space = &ioport_resource;
43798c532ecSIvan Kokshaysky 	hae_mem = alloc_resource();
43898c532ecSIvan Kokshaysky 	hae_mem->start = 0;
43998c532ecSIvan Kokshaysky 	hae_mem->end = T2_MEM_R1_MASK;
44098c532ecSIvan Kokshaysky 	hae_mem->name = pci_hae0_name;
44198c532ecSIvan Kokshaysky 	if (request_resource(&iomem_resource, hae_mem) < 0)
44298c532ecSIvan Kokshaysky 		printk(KERN_ERR "Failed to request HAE_MEM\n");
44398c532ecSIvan Kokshaysky 	hose->mem_space = hae_mem;
4441da177e4SLinus Torvalds 	hose->index = 0;
4451da177e4SLinus Torvalds 
4461da177e4SLinus Torvalds 	hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
4471da177e4SLinus Torvalds 	hose->dense_mem_base = T2_DENSE_MEM - IDENT_ADDR;
4481da177e4SLinus Torvalds 	hose->sparse_io_base = T2_IO - IDENT_ADDR;
4491da177e4SLinus Torvalds 	hose->dense_io_base = 0;
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds 	/*
4521da177e4SLinus Torvalds 	 * Set up the PCI->physical memory translation windows.
4531da177e4SLinus Torvalds 	 *
4541da177e4SLinus Torvalds 	 * Window 1 is direct mapped.
4551da177e4SLinus Torvalds 	 * Window 2 is scatter/gather (for ISA).
4561da177e4SLinus Torvalds 	 */
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds 	t2_direct_map_window1(T2_DIRECTMAP_START, T2_DIRECTMAP_LENGTH);
4591da177e4SLinus Torvalds 
4601da177e4SLinus Torvalds 	/* Always make an ISA DMA window. */
4611da177e4SLinus Torvalds 	t2_sg_map_window2(hose, T2_ISA_SG_START, T2_ISA_SG_LENGTH);
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 	*(vulp)T2_HBASE = 0x0; /* Disable HOLES. */
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds 	/* Zero HAE.  */
4661da177e4SLinus Torvalds 	*(vulp)T2_HAE_1 = 0; mb(); /* Sparse MEM HAE */
4671da177e4SLinus Torvalds 	*(vulp)T2_HAE_2 = 0; mb(); /* Sparse I/O HAE */
4681da177e4SLinus Torvalds 	*(vulp)T2_HAE_3 = 0; mb(); /* Config Space HAE */
4691da177e4SLinus Torvalds 
4701da177e4SLinus Torvalds 	/*
4711da177e4SLinus Torvalds 	 * We also now zero out HAE_4, the dense memory HAE, so that
4721da177e4SLinus Torvalds 	 * we need not account for its "offset" when accessing dense
4731da177e4SLinus Torvalds 	 * memory resources which we allocated in our normal way. This
4741da177e4SLinus Torvalds 	 * HAE would need to stay untouched were we to keep the SRM
4751da177e4SLinus Torvalds 	 * resource settings.
4761da177e4SLinus Torvalds 	 *
4771da177e4SLinus Torvalds 	 * Thus we can now run standard X servers on SABLE/LYNX. :-)
4781da177e4SLinus Torvalds 	 */
4791da177e4SLinus Torvalds 	*(vulp)T2_HAE_4 = 0; mb();
4801da177e4SLinus Torvalds }
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds void
t2_kill_arch(int mode)4831da177e4SLinus Torvalds t2_kill_arch(int mode)
4841da177e4SLinus Torvalds {
4851da177e4SLinus Torvalds 	/*
4861da177e4SLinus Torvalds 	 * Restore the DMA Window registers.
4871da177e4SLinus Torvalds 	 */
4881da177e4SLinus Torvalds 	*(vulp)T2_WBASE1 = t2_saved_config.window[0].wbase;
4891da177e4SLinus Torvalds 	*(vulp)T2_WMASK1 = t2_saved_config.window[0].wmask;
4901da177e4SLinus Torvalds 	*(vulp)T2_TBASE1 = t2_saved_config.window[0].tbase;
4911da177e4SLinus Torvalds 	*(vulp)T2_WBASE2 = t2_saved_config.window[1].wbase;
4921da177e4SLinus Torvalds 	*(vulp)T2_WMASK2 = t2_saved_config.window[1].wmask;
4931da177e4SLinus Torvalds 	*(vulp)T2_TBASE2 = t2_saved_config.window[1].tbase;
4941da177e4SLinus Torvalds 	mb();
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds 	*(vulp)T2_HAE_1 = srm_hae;
4971da177e4SLinus Torvalds 	*(vulp)T2_HAE_2 = t2_saved_config.hae_2;
4981da177e4SLinus Torvalds 	*(vulp)T2_HAE_3 = t2_saved_config.hae_3;
4991da177e4SLinus Torvalds 	*(vulp)T2_HAE_4 = t2_saved_config.hae_4;
5001da177e4SLinus Torvalds 	*(vulp)T2_HBASE = t2_saved_config.hbase;
5011da177e4SLinus Torvalds 	mb();
5021da177e4SLinus Torvalds 	*(vulp)T2_HBASE; /* READ it back to ensure WRITE occurred. */
5031da177e4SLinus Torvalds }
5041da177e4SLinus Torvalds 
5051da177e4SLinus Torvalds void
t2_pci_tbi(struct pci_controller * hose,dma_addr_t start,dma_addr_t end)5061da177e4SLinus Torvalds t2_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
5071da177e4SLinus Torvalds {
5081da177e4SLinus Torvalds 	unsigned long t2_iocsr;
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds 	t2_iocsr = *(vulp)T2_IOCSR;
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds 	/* set the TLB Clear bit */
5131da177e4SLinus Torvalds 	*(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 28);
5141da177e4SLinus Torvalds 	mb();
5151da177e4SLinus Torvalds 	*(vulp)T2_IOCSR; /* read it back to make sure */
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds 	/* clear the TLB Clear bit */
5181da177e4SLinus Torvalds 	*(vulp)T2_IOCSR = t2_iocsr & ~(0x1UL << 28);
5191da177e4SLinus Torvalds 	mb();
5201da177e4SLinus Torvalds 	*(vulp)T2_IOCSR; /* read it back to make sure */
5211da177e4SLinus Torvalds }
5221da177e4SLinus Torvalds 
5231da177e4SLinus Torvalds #define SIC_SEIC (1UL << 33)    /* System Event Clear */
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds static void
t2_clear_errors(int cpu)5261da177e4SLinus Torvalds t2_clear_errors(int cpu)
5271da177e4SLinus Torvalds {
5281da177e4SLinus Torvalds 	struct sable_cpu_csr *cpu_regs;
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds 	cpu_regs = (struct sable_cpu_csr *)T2_CPUn_BASE(cpu);
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 	cpu_regs->sic &= ~SIC_SEIC;
5331da177e4SLinus Torvalds 
5341da177e4SLinus Torvalds 	/* Clear CPU errors.  */
5351da177e4SLinus Torvalds 	cpu_regs->bcce |= cpu_regs->bcce;
5361da177e4SLinus Torvalds 	cpu_regs->cbe  |= cpu_regs->cbe;
5371da177e4SLinus Torvalds 	cpu_regs->bcue |= cpu_regs->bcue;
5381da177e4SLinus Torvalds 	cpu_regs->dter |= cpu_regs->dter;
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds 	*(vulp)T2_CERR1 |= *(vulp)T2_CERR1;
5411da177e4SLinus Torvalds 	*(vulp)T2_PERR1 |= *(vulp)T2_PERR1;
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds 	mb();
5441da177e4SLinus Torvalds 	mb();  /* magic */
5451da177e4SLinus Torvalds }
5461da177e4SLinus Torvalds 
5471da177e4SLinus Torvalds /*
5481da177e4SLinus Torvalds  * SABLE seems to have a "broadcast" style machine check, in that all
5491da177e4SLinus Torvalds  * CPUs receive it. And, the issuing CPU, in the case of PCI Config
5501da177e4SLinus Torvalds  * space read/write faults, will also receive a second mcheck, upon
5511da177e4SLinus Torvalds  * lowering IPL during completion processing in pci_read_config_byte()
5521da177e4SLinus Torvalds  * et al.
5531da177e4SLinus Torvalds  *
5541da177e4SLinus Torvalds  * Hence all the taken/expected/any_expected/last_taken stuff...
5551da177e4SLinus Torvalds  */
5561da177e4SLinus Torvalds void
t2_machine_check(unsigned long vector,unsigned long la_ptr)5574fa1970aSAl Viro t2_machine_check(unsigned long vector, unsigned long la_ptr)
5581da177e4SLinus Torvalds {
5591da177e4SLinus Torvalds 	int cpu = smp_processor_id();
5601da177e4SLinus Torvalds #ifdef CONFIG_VERBOSE_MCHECK
5611da177e4SLinus Torvalds 	struct el_common *mchk_header = (struct el_common *)la_ptr;
5621da177e4SLinus Torvalds #endif
5631da177e4SLinus Torvalds 
5641da177e4SLinus Torvalds 	/* Clear the error before any reporting.  */
5651da177e4SLinus Torvalds 	mb();
5661da177e4SLinus Torvalds 	mb();  /* magic */
5671da177e4SLinus Torvalds 	draina();
5681da177e4SLinus Torvalds 	t2_clear_errors(cpu);
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds 	/* This should not actually be done until the logout frame is
5711da177e4SLinus Torvalds 	   examined, but, since we don't do that, go on and do this... */
5721da177e4SLinus Torvalds 	wrmces(0x7);
5731da177e4SLinus Torvalds 	mb();
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 	/* Now, do testing for the anomalous conditions. */
5761da177e4SLinus Torvalds 	if (!mcheck_expected(cpu) && t2_mcheck_any_expected) {
5771da177e4SLinus Torvalds 		/*
5781da177e4SLinus Torvalds 		 * FUNKY: Received mcheck on a CPU and not
5791da177e4SLinus Torvalds 		 * expecting it, but another CPU is expecting one.
5801da177e4SLinus Torvalds 		 *
5811da177e4SLinus Torvalds 		 * Just dismiss it for now on this CPU...
5821da177e4SLinus Torvalds 		 */
5831da177e4SLinus Torvalds #ifdef CONFIG_VERBOSE_MCHECK
5841da177e4SLinus Torvalds 		if (alpha_verbose_mcheck > 1) {
5851da177e4SLinus Torvalds 			printk("t2_machine_check(cpu%d): any_expected 0x%x -"
5861da177e4SLinus Torvalds 			       " (assumed) spurious -"
5871da177e4SLinus Torvalds 			       " code 0x%x\n", cpu, t2_mcheck_any_expected,
5881da177e4SLinus Torvalds 			       (unsigned int)mchk_header->code);
5891da177e4SLinus Torvalds 		}
5901da177e4SLinus Torvalds #endif
5911da177e4SLinus Torvalds 		return;
5921da177e4SLinus Torvalds 	}
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds 	if (!mcheck_expected(cpu) && !t2_mcheck_any_expected) {
5951da177e4SLinus Torvalds 		if (t2_mcheck_last_taken & (1 << cpu)) {
5961da177e4SLinus Torvalds #ifdef CONFIG_VERBOSE_MCHECK
5971da177e4SLinus Torvalds 		    if (alpha_verbose_mcheck > 1) {
5981da177e4SLinus Torvalds 			printk("t2_machine_check(cpu%d): last_taken 0x%x - "
5991da177e4SLinus Torvalds 			       "unexpected mcheck - code 0x%x\n",
6001da177e4SLinus Torvalds 			       cpu, t2_mcheck_last_taken,
6011da177e4SLinus Torvalds 			       (unsigned int)mchk_header->code);
6021da177e4SLinus Torvalds 		    }
6031da177e4SLinus Torvalds #endif
6041da177e4SLinus Torvalds 		    t2_mcheck_last_taken = 0;
6051da177e4SLinus Torvalds 		    mb();
6061da177e4SLinus Torvalds 		    return;
6071da177e4SLinus Torvalds 		} else {
6081da177e4SLinus Torvalds 			t2_mcheck_last_taken = 0;
6091da177e4SLinus Torvalds 			mb();
6101da177e4SLinus Torvalds 		}
6111da177e4SLinus Torvalds 	}
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds #ifdef CONFIG_VERBOSE_MCHECK
6141da177e4SLinus Torvalds 	if (alpha_verbose_mcheck > 1) {
6151da177e4SLinus Torvalds 		printk("%s t2_mcheck(cpu%d): last_taken 0x%x - "
6161da177e4SLinus Torvalds 		       "any_expected 0x%x - code 0x%x\n",
6171da177e4SLinus Torvalds 		       (mcheck_expected(cpu) ? "EX" : "UN"), cpu,
6181da177e4SLinus Torvalds 		       t2_mcheck_last_taken, t2_mcheck_any_expected,
6191da177e4SLinus Torvalds 		       (unsigned int)mchk_header->code);
6201da177e4SLinus Torvalds 	}
6211da177e4SLinus Torvalds #endif
6221da177e4SLinus Torvalds 
6234fa1970aSAl Viro 	process_mcheck_info(vector, la_ptr, "T2", mcheck_expected(cpu));
6241da177e4SLinus Torvalds }
625