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