#include <asm/ptrace.h>
#include <asm/system.h>
+#include <asm/delay.h>
#define __EXTERN_INLINE
#include <asm/io.h>
#include "proto.h"
#include "pci_impl.h"
+/* For dumping initial DMA window settings. */
+#define DEBUG_PRINT_INITIAL_SETTINGS 0
+
+/* For dumping final DMA window settings. */
+#define DEBUG_PRINT_FINAL_SETTINGS 0
+
/*
* By default, we direct-map starting at 2GB, in order to allow the
* maximum size direct-map window (2GB) to match the maximum amount of
* ISA DMA, since the maximum ISA DMA address is 2GB-1.
*
* For now, this seems a reasonable trade-off: even though most SABLEs
- * have far less than even 1GB of memory, floppy usage/performance will
- * not really be affected by forcing it to go via scatter/gather...
+ * have less than 1GB of memory, floppy usage/performance will not
+ * really be affected by forcing it to go via scatter/gather...
*/
#define T2_DIRECTMAP_2G 1
+#if T2_DIRECTMAP_2G
+# define T2_DIRECTMAP_START 0x80000000UL
+# define T2_DIRECTMAP_LENGTH 0x80000000UL
+#else
+# define T2_DIRECTMAP_START 0x40000000UL
+# define T2_DIRECTMAP_LENGTH 0x40000000UL
+#endif
+
+/* The ISA scatter/gather window settings. */
+#define T2_ISA_SG_START 0x00800000UL
+#define T2_ISA_SG_LENGTH 0x00800000UL
+
/*
* NOTE: Herein lie back-to-back mb instructions. They are magic.
* One plausible explanation is that the i/o controller does not properly
# define DBG(args)
#endif
+static volatile unsigned int t2_mcheck_any_expected;
+static volatile unsigned int t2_mcheck_last_taken;
+
+/* Place to save the DMA Window registers as set up by SRM
+ for restoration during shutdown. */
+static struct
+{
+ struct {
+ unsigned long wbase;
+ unsigned long wmask;
+ unsigned long tbase;
+ } window[2];
+ unsigned long hae_1;
+ unsigned long hae_2;
+ unsigned long hae_3;
+ unsigned long hae_4;
+ unsigned long hbase;
+} t2_saved_config __attribute((common));
/*
* Given a bus, device, and function number, compute resulting
return 0;
}
+/*
+ * NOTE: both conf_read() and conf_write() may set HAE_3 when needing
+ * to do type1 access. This is protected by the use of spinlock IRQ
+ * primitives in the wrapper functions pci_{read,write}_config_*()
+ * defined in drivers/pci/pci.c.
+ */
static unsigned int
conf_read(unsigned long addr, unsigned char type1)
{
- unsigned long flags;
- unsigned int value, cpu;
+ unsigned int value, cpu, taken;
unsigned long t2_cfg = 0;
cpu = smp_processor_id();
- local_irq_save(flags); /* avoid getting hit by machine check */
-
DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
-#if 0
- {
- unsigned long stat0;
- /* Reset status register to avoid losing errors. */
- stat0 = *(vulp)T2_IOCSR;
- *(vulp)T2_IOCSR = stat0;
- mb();
- DBG(("conf_read: T2 IOCSR was 0x%x\n", stat0));
- }
-#endif
-
/* If Type1 access, must set T2 CFG. */
if (type1) {
t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL;
*(vulp)T2_HAE_3 = 0x40000000UL | t2_cfg;
mb();
- DBG(("conf_read: TYPE1 access\n"));
}
mb();
draina();
mcheck_expected(cpu) = 1;
mcheck_taken(cpu) = 0;
+ t2_mcheck_any_expected |= (1 << cpu);
mb();
/* Access configuration space. */
mb();
mb(); /* magic */
- if (mcheck_taken(cpu)) {
+ /* Wait for possible mcheck. Also, this lets other CPUs clear
+ their mchecks as well, as they can reliably tell when
+ another CPU is in the midst of handling a real mcheck via
+ the "taken" function. */
+ udelay(100);
+
+ if ((taken = mcheck_taken(cpu))) {
mcheck_taken(cpu) = 0;
+ t2_mcheck_last_taken |= (1 << cpu);
value = 0xffffffffU;
mb();
}
mcheck_expected(cpu) = 0;
+ t2_mcheck_any_expected = 0;
mb();
/* If Type1 access, must reset T2 CFG so normal IO space ops work. */
*(vulp)T2_HAE_3 = t2_cfg;
mb();
}
- DBG(("conf_read(): finished\n"));
- local_irq_restore(flags);
return value;
}
static void
conf_write(unsigned long addr, unsigned int value, unsigned char type1)
{
- unsigned long flags;
- unsigned int cpu;
+ unsigned int cpu, taken;
unsigned long t2_cfg = 0;
cpu = smp_processor_id();
- local_irq_save(flags); /* avoid getting hit by machine check */
-
-#if 0
- {
- unsigned long stat0;
- /* Reset status register to avoid losing errors. */
- stat0 = *(vulp)T2_IOCSR;
- *(vulp)T2_IOCSR = stat0;
- mb();
- DBG(("conf_write: T2 ERR was 0x%x\n", stat0));
- }
-#endif
-
/* If Type1 access, must set T2 CFG. */
if (type1) {
t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL;
*(vulp)T2_HAE_3 = t2_cfg | 0x40000000UL;
mb();
- DBG(("conf_write: TYPE1 access\n"));
}
mb();
draina();
mcheck_expected(cpu) = 1;
+ mcheck_taken(cpu) = 0;
+ t2_mcheck_any_expected |= (1 << cpu);
mb();
/* Access configuration space. */
mb();
mb(); /* magic */
+ /* Wait for possible mcheck. Also, this lets other CPUs clear
+ their mchecks as well, as they can reliably tell when
+ this CPU is in the midst of handling a real mcheck via
+ the "taken" function. */
+ udelay(100);
+
+ if ((taken = mcheck_taken(cpu))) {
+ mcheck_taken(cpu) = 0;
+ t2_mcheck_last_taken |= (1 << cpu);
+ mb();
+ }
mcheck_expected(cpu) = 0;
+ t2_mcheck_any_expected = 0;
mb();
/* If Type1 access, must reset T2 CFG so normal IO space ops work. */
*(vulp)T2_HAE_3 = t2_cfg;
mb();
}
- DBG(("conf_write(): finished\n"));
- local_irq_restore(flags);
}
static int
.write = t2_write_config,
};
\f
+static void __init
+t2_direct_map_window1(unsigned long base, unsigned long length)
+{
+ unsigned long temp;
+
+ __direct_map_base = base;
+ __direct_map_size = length;
+
+ temp = (base & 0xfff00000UL) | ((base + length - 1) >> 20);
+ *(vulp)T2_WBASE1 = temp | 0x80000UL; /* OR in ENABLE bit */
+ temp = (length - 1) & 0xfff00000UL;
+ *(vulp)T2_WMASK1 = temp;
+ *(vulp)T2_TBASE1 = 0;
+
+#if DEBUG_PRINT_FINAL_SETTINGS
+ printk("%s: setting WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
+ __FUNCTION__,
+ *(vulp)T2_WBASE1,
+ *(vulp)T2_WMASK1,
+ *(vulp)T2_TBASE1);
+#endif
+}
+
+static void __init
+t2_sg_map_window2(struct pci_controller *hose,
+ unsigned long base,
+ unsigned long length)
+{
+ unsigned long temp;
+
+ /* Note we can only do 1 SG window, as the other is for direct, so
+ do an ISA SG area, especially for the floppy. */
+ hose->sg_isa = iommu_arena_new(hose, base, length, 0);
+ hose->sg_pci = NULL;
+
+ temp = (base & 0xfff00000UL) | ((base + length - 1) >> 20);
+ *(vulp)T2_WBASE2 = temp | 0xc0000UL; /* OR in ENABLE/SG bits */
+ temp = (length - 1) & 0xfff00000UL;
+ *(vulp)T2_WMASK2 = temp;
+ *(vulp)T2_TBASE2 = virt_to_phys(hose->sg_isa->ptes) >> 1;
+ mb();
+
+ t2_pci_tbi(hose, 0, -1); /* flush TLB all */
+
+#if DEBUG_PRINT_FINAL_SETTINGS
+ printk("%s: setting WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
+ __FUNCTION__,
+ *(vulp)T2_WBASE2,
+ *(vulp)T2_WMASK2,
+ *(vulp)T2_TBASE2);
+#endif
+}
+
+static void __init
+t2_save_configuration(void)
+{
+#if DEBUG_PRINT_INITIAL_SETTINGS
+ printk("%s: HAE_1 was 0x%lx\n", __FUNCTION__, srm_hae); /* HW is 0 */
+ printk("%s: HAE_2 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_2);
+ printk("%s: HAE_3 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_3);
+ printk("%s: HAE_4 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_4);
+ printk("%s: HBASE was 0x%lx\n", __FUNCTION__, *(vulp)T2_HBASE);
+
+ printk("%s: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n", __FUNCTION__,
+ *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1);
+ printk("%s: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n", __FUNCTION__,
+ *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2);
+#endif
+
+ /*
+ * Save the DMA Window registers.
+ */
+ t2_saved_config.window[0].wbase = *(vulp)T2_WBASE1;
+ t2_saved_config.window[0].wmask = *(vulp)T2_WMASK1;
+ t2_saved_config.window[0].tbase = *(vulp)T2_TBASE1;
+ t2_saved_config.window[1].wbase = *(vulp)T2_WBASE2;
+ t2_saved_config.window[1].wmask = *(vulp)T2_WMASK2;
+ t2_saved_config.window[1].tbase = *(vulp)T2_TBASE2;
+
+ t2_saved_config.hae_1 = srm_hae; /* HW is already set to 0 */
+ t2_saved_config.hae_2 = *(vulp)T2_HAE_2;
+ t2_saved_config.hae_3 = *(vulp)T2_HAE_3;
+ t2_saved_config.hae_4 = *(vulp)T2_HAE_4;
+ t2_saved_config.hbase = *(vulp)T2_HBASE;
+}
+
void __init
t2_init_arch(void)
{
struct pci_controller *hose;
- unsigned long t2_iocsr;
+ unsigned long temp;
unsigned int i;
for (i = 0; i < NR_CPUS; i++) {
mcheck_expected(i) = 0;
mcheck_taken(i) = 0;
}
-
-#if 0
- /* Set up error reporting. */
- t2_iocsr = *(vulp)T2_IOCSR;
- *(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 7); /* TLB error check */
- mb();
- *(vulp)T2_IOCSR; /* read it back to make sure */
-#endif
+ t2_mcheck_any_expected = 0;
+ t2_mcheck_last_taken = 0;
/* Enable scatter/gather TLB use. */
- t2_iocsr = *(vulp)T2_IOCSR;
- if (!(t2_iocsr & (0x1UL << 26))) {
+ temp = *(vulp)T2_IOCSR;
+ if (!(temp & (0x1UL << 26))) {
printk("t2_init_arch: enabling SG TLB, IOCSR was 0x%lx\n",
- t2_iocsr);
- *(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 26);
+ temp);
+ *(vulp)T2_IOCSR = temp | (0x1UL << 26);
mb();
*(vulp)T2_IOCSR; /* read it back to make sure */
}
-#if 0
- printk("t2_init_arch: HBASE was 0x%lx\n", *(vulp)T2_HBASE);
- printk("t2_init_arch: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
- *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1);
- printk("t2_init_arch: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
- *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2);
-#endif
+ t2_save_configuration();
/*
* Create our single hose.
*/
-
pci_isa_hose = hose = alloc_pci_controller();
hose->io_space = &ioport_resource;
hose->mem_space = &iomem_resource;
hose->sparse_io_base = T2_IO - IDENT_ADDR;
hose->dense_io_base = 0;
- /* Note we can only do 1 SG window, as the other is for direct, so
- do an ISA SG area, especially for the floppy. */
- hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
- hose->sg_pci = NULL;
-
/*
* Set up the PCI->physical memory translation windows.
*
- * Window 1 goes at ? GB and is ?GB large, direct mapped.
- * Window 2 goes at 8 MB and is 8MB large, scatter/gather (for ISA).
+ * Window 1 is direct mapped.
+ * Window 2 is scatter/gather (for ISA).
*/
-#if T2_DIRECTMAP_2G
- __direct_map_base = 0x80000000UL;
- __direct_map_size = 0x80000000UL;
+ t2_direct_map_window1(T2_DIRECTMAP_START, T2_DIRECTMAP_LENGTH);
- /* WARNING!! must correspond to the direct map window params!!! */
- *(vulp)T2_WBASE1 = 0x80080fffU;
- *(vulp)T2_WMASK1 = 0x7ff00000U;
- *(vulp)T2_TBASE1 = 0;
-#else /* T2_DIRECTMAP_2G */
- __direct_map_base = 0x40000000UL;
- __direct_map_size = 0x40000000UL;
+ /* Always make an ISA DMA window. */
+ t2_sg_map_window2(hose, T2_ISA_SG_START, T2_ISA_SG_LENGTH);
- /* WARNING!! must correspond to the direct map window params!!! */
- *(vulp)T2_WBASE1 = 0x400807ffU;
- *(vulp)T2_WMASK1 = 0x3ff00000U;
- *(vulp)T2_TBASE1 = 0;
-#endif /* T2_DIRECTMAP_2G */
-
- /* WARNING!! must correspond to the SG arena/window params!!! */
- *(vulp)T2_WBASE2 = 0x008c000fU;
- *(vulp)T2_WMASK2 = 0x00700000U;
- *(vulp)T2_TBASE2 = virt_to_phys(hose->sg_isa->ptes) >> 1;
-
- *(vulp)T2_HBASE = 0x0;
+ *(vulp)T2_HBASE = 0x0; /* Disable HOLES. */
/* Zero HAE. */
- *(vulp)T2_HAE_1 = 0; mb();
- *(vulp)T2_HAE_2 = 0; mb();
- *(vulp)T2_HAE_3 = 0; mb();
+ *(vulp)T2_HAE_1 = 0; mb(); /* Sparse MEM HAE */
+ *(vulp)T2_HAE_2 = 0; mb(); /* Sparse I/O HAE */
+ *(vulp)T2_HAE_3 = 0; mb(); /* Config Space HAE */
#if 0
- *(vulp)T2_HAE_4 = 0; mb(); /* DO NOT TOUCH THIS!!! */
+ /* !!! DO NOT EVER TOUCH THIS !!! */
+ *(vulp)T2_HAE_4 = 0; mb(); /* Dense MEM HAE */
#endif
+}
- t2_pci_tbi(hose, 0, -1); /* flush TLB all */
+void
+t2_kill_arch(int mode)
+{
+ /*
+ * Restore the DMA Window registers.
+ */
+ *(vulp)T2_WBASE1 = t2_saved_config.window[0].wbase;
+ *(vulp)T2_WMASK1 = t2_saved_config.window[0].wmask;
+ *(vulp)T2_TBASE1 = t2_saved_config.window[0].tbase;
+ *(vulp)T2_WBASE2 = t2_saved_config.window[1].wbase;
+ *(vulp)T2_WMASK2 = t2_saved_config.window[1].wmask;
+ *(vulp)T2_TBASE2 = t2_saved_config.window[1].tbase;
+ mb();
+
+ *(vulp)T2_HAE_1 = srm_hae;
+ *(vulp)T2_HAE_2 = t2_saved_config.hae_2;
+ *(vulp)T2_HAE_3 = t2_saved_config.hae_3;
+ *(vulp)T2_HAE_4 = t2_saved_config.hae_4;
+ *(vulp)T2_HBASE = t2_saved_config.hbase;
+ mb();
+ *(vulp)T2_HBASE; /* READ it back to ensure WRITE occurred. */
}
void
{
struct sable_cpu_csr *cpu_regs;
- cpu_regs = (struct sable_cpu_csr *)T2_CPU0_BASE;
- if (cpu == 1)
- cpu_regs = (struct sable_cpu_csr *)T2_CPU1_BASE;
- if (cpu == 2)
- cpu_regs = (struct sable_cpu_csr *)T2_CPU2_BASE;
- if (cpu == 3)
- cpu_regs = (struct sable_cpu_csr *)T2_CPU3_BASE;
+ cpu_regs = (struct sable_cpu_csr *)T2_CPUn_BASE(cpu);
cpu_regs->sic &= ~SIC_SEIC;
mb(); /* magic */
}
+/*
+ * SABLE seems to have a "broadcast" style machine check, in that all
+ * CPUs receive it. And, the issuing CPU, in the case of PCI Config
+ * space read/write faults, will also receive a second mcheck, upon
+ * lowering IPL during completion processing in pci_read_config_byte()
+ * et al.
+ *
+ * Hence all the taken/expected/any_expected/last_taken stuff...
+ */
void
t2_machine_check(unsigned long vector, unsigned long la_ptr,
struct pt_regs * regs)
{
int cpu = smp_processor_id();
+#if DEBUG_MCHECK > 0
+ struct el_common *mchk_header = (struct el_common *)la_ptr;
+#endif /* DEBUG_MCHECK */
/* Clear the error before any reporting. */
mb();
mb(); /* magic */
draina();
t2_clear_errors(cpu);
- wrmces(rdmces()|1); /* ??? */
+
+ /* This should not actually be done until the logout frame is
+ examined, but, since we don't do that, go on and do this... */
+ wrmces(0x7);
mb();
+ /* Now, do testing for the anomalous conditions. */
+ if (!mcheck_expected(cpu) && t2_mcheck_any_expected) {
+ /*
+ * FUNKY: Received mcheck on a CPU and not
+ * expecting it, but another CPU is expecting one.
+ *
+ * Just dismiss it for now on this CPU...
+ */
+#if DEBUG_MCHECK > 0
+ printk("t2_machine_check(cpu%d): any_expected 0x%x -"
+ " (assumed) spurious -"
+ " code 0x%x\n", cpu, t2_mcheck_any_expected,
+ (unsigned int)mchk_header->code);
+#endif /* DEBUG_MCHECK */
+ return;
+ }
+
+ if (!mcheck_expected(cpu) && !t2_mcheck_any_expected) {
+ if (t2_mcheck_last_taken & (1 << cpu)) {
+#if DEBUG_MCHECK > 0
+ printk("t2_machine_check(cpu%d): last_taken 0x%x - "
+ "unexpected mcheck - code 0x%x\n",
+ cpu, t2_mcheck_last_taken,
+ (unsigned int)mchk_header->code);
+#endif /* DEBUG_MCHECK */
+ t2_mcheck_last_taken = 0;
+ mb();
+ return;
+ } else {
+ t2_mcheck_last_taken = 0;
+ mb();
+ }
+ }
+
+#if DEBUG_MCHECK > 0
+ printk("%s t2_mcheck(cpu%d): last_taken 0x%x - "
+ "any_expected 0x%x - code 0x%x\n",
+ (mcheck_expected(cpu) ? "EX" : "UN"), cpu,
+ t2_mcheck_last_taken, t2_mcheck_any_expected,
+ (unsigned int)mchk_header->code);
+#endif /* DEBUG_MCHECK */
+
process_mcheck_info(vector, la_ptr, regs, "T2", mcheck_expected(cpu));
}
* Copyright (C) 1996 Jay A Estabrook
* Copyright (C) 1998, 1999 Richard Henderson
*
- * Code supporting the Sable and Sable-Gamma systems.
+ * Code supporting the Sable, Sable-Gamma, and Lynx systems.
*/
#include <linux/config.h>
#include "pci_impl.h"
#include "machvec_impl.h"
-spinlock_t sable_irq_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t sable_lynx_irq_lock = SPIN_LOCK_UNLOCKED;
+typedef struct irq_swizzle_struct
+{
+ char irq_to_mask[64];
+ char mask_to_irq[64];
+
+ /* Note mask bit is true for DISABLED irqs. */
+ unsigned long shadow_mask;
+
+ void (*update_irq_hw)(unsigned long bit, unsigned long mask);
+ void (*ack_irq_hw)(unsigned long bit);
+
+} irq_swizzle_t;
+
+static irq_swizzle_t *sable_lynx_irq_swizzle;
+
+static void sable_lynx_init_irq(int nr_irqs);
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SABLE)
+
+/***********************************************************************/
/*
* For SABLE, which is really baroque, we manage 40 IRQ's, but the
* hardware really only supports 24, not via normal ISA PIC,
*23 IIC -
*/
-static struct
-{
- char irq_to_mask[40];
- char mask_to_irq[40];
-
- /* Note mask bit is true for DISABLED irqs. */
- unsigned long shadow_mask;
-} sable_irq_swizzle = {
- {
- -1, 6, -1, 8, 15, 12, 7, 9, /* pseudo PIC 0-7 */
- -1, 16, 17, 18, 3, -1, 21, 22, /* pseudo PIC 8-15 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 0-7 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 8-15 */
- 2, 1, 0, 4, 5, -1, -1, -1, /* pseudo PCI */
- },
- {
- 34, 33, 32, 12, 35, 36, 1, 6, /* mask 0-7 */
- 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */
- 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */
- },
- -1
-};
-
-static inline void
+static void
sable_update_irq_hw(unsigned long bit, unsigned long mask)
{
int port = 0x537;
outb(mask, port);
}
-static inline void
+static void
sable_ack_irq_hw(unsigned long bit)
{
int port, val1, val2;
outb(val2, 0x534); /* ack the master */
}
-static inline void
-sable_enable_irq(unsigned int irq)
-{
- unsigned long bit, mask;
-
- bit = sable_irq_swizzle.irq_to_mask[irq];
- spin_lock(&sable_irq_lock);
- mask = sable_irq_swizzle.shadow_mask &= ~(1UL << bit);
- sable_update_irq_hw(bit, mask);
- spin_unlock(&sable_irq_lock);
-}
-
-static void
-sable_disable_irq(unsigned int irq)
-{
- unsigned long bit, mask;
-
- bit = sable_irq_swizzle.irq_to_mask[irq];
- spin_lock(&sable_irq_lock);
- mask = sable_irq_swizzle.shadow_mask |= 1UL << bit;
- sable_update_irq_hw(bit, mask);
- spin_unlock(&sable_irq_lock);
-}
-
-static unsigned int
-sable_startup_irq(unsigned int irq)
-{
- sable_enable_irq(irq);
- return 0;
-}
-
-static void
-sable_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- sable_enable_irq(irq);
-}
-
-static void
-sable_mask_and_ack_irq(unsigned int irq)
-{
- unsigned long bit, mask;
-
- bit = sable_irq_swizzle.irq_to_mask[irq];
- spin_lock(&sable_irq_lock);
- mask = sable_irq_swizzle.shadow_mask |= 1UL << bit;
- sable_update_irq_hw(bit, mask);
- sable_ack_irq_hw(bit);
- spin_unlock(&sable_irq_lock);
-}
-
-static struct hw_interrupt_type sable_irq_type = {
- .typename = "SABLE",
- .startup = sable_startup_irq,
- .shutdown = sable_disable_irq,
- .enable = sable_enable_irq,
- .disable = sable_disable_irq,
- .ack = sable_mask_and_ack_irq,
- .end = sable_end_irq,
+static irq_swizzle_t sable_irq_swizzle = {
+ {
+ -1, 6, -1, 8, 15, 12, 7, 9, /* pseudo PIC 0-7 */
+ -1, 16, 17, 18, 3, -1, 21, 22, /* pseudo PIC 8-15 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 0-7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 8-15 */
+ 2, 1, 0, 4, 5, -1, -1, -1, /* pseudo PCI */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* */
+ -1, -1, -1, -1, -1, -1, -1, -1 /* */
+ },
+ {
+ 34, 33, 32, 12, 35, 36, 1, 6, /* mask 0-7 */
+ 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */
+ 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* */
+ -1, -1, -1, -1, -1, -1, -1, -1 /* */
+ },
+ -1,
+ sable_update_irq_hw,
+ sable_ack_irq_hw
};
-static void
-sable_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
-{
- /* Note that the vector reported by the SRM PALcode corresponds
- to the interrupt mask bits, but we have to manage via more
- normal IRQs. */
-
- int bit, irq;
-
- bit = (vector - 0x800) >> 4;
- irq = sable_irq_swizzle.mask_to_irq[bit];
- handle_irq(irq, regs);
-}
-
static void __init
sable_init_irq(void)
{
- long i;
-
outb(-1, 0x537); /* slave 0 */
outb(-1, 0x53b); /* slave 1 */
outb(-1, 0x53d); /* slave 2 */
outb(0x44, 0x535); /* enable cascades in master */
- for (i = 0; i < 40; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].handler = &sable_irq_type;
- }
-
- common_init_isa_dma();
+ sable_lynx_irq_swizzle = &sable_irq_swizzle;
+ sable_lynx_init_irq(40);
}
-
/*
- * PCI Fixup configuration for ALPHA SABLE (2100) - 2100A is different ??
+ * PCI Fixup configuration for ALPHA SABLE (2100).
*
* The device to slot mapping looks like:
*
static int __init
sable_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
- static char irq_tab[9][5] __initdata = {
+ static char irq_tab[9][5] __initdata = {
/*INT INTA INTB INTC INTD */
{ 32+0, 32+0, 32+0, 32+0, 32+0}, /* IdSel 0, TULIP */
{ 32+1, 32+1, 32+1, 32+1, 32+1}, /* IdSel 1, SCSI */
{ -1, -1, -1, -1, -1}, /* IdSel 5, none */
{ 32+2, 32+2, 32+2, 32+2, 32+2}, /* IdSel 6, slot 0 */
{ 32+3, 32+3, 32+3, 32+3, 32+3}, /* IdSel 7, slot 1 */
- { 32+4, 32+4, 32+4, 32+4, 32+4}, /* IdSel 8, slot 2 */
- };
+ { 32+4, 32+4, 32+4, 32+4, 32+4} /* IdSel 8, slot 2 */
+ };
long min_idsel = 0, max_idsel = 8, irqs_per_slot = 5;
return COMMON_TABLE_LOOKUP;
}
+#endif /* defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SABLE) */
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LYNX)
+/***********************************************************************/
+/* LYNX hardware specifics
+ */
+/*
+ * For LYNX, which is also baroque, we manage 64 IRQs, via a custom IC.
+ *
+ * Bit Meaning Kernel IRQ
+ *------------------------------------------
+ * 0
+ * 1
+ * 2
+ * 3 mouse 12
+ * 4
+ * 5
+ * 6 keyboard 1
+ * 7 floppy 6
+ * 8 COM2 3
+ * 9 parallel port 7
+ *10 EISA irq 3 -
+ *11 EISA irq 4 -
+ *12 EISA irq 5 5
+ *13 EISA irq 6 -
+ *14 EISA irq 7 -
+ *15 COM1 4
+ *16 EISA irq 9 9
+ *17 EISA irq 10 10
+ *18 EISA irq 11 11
+ *19 EISA irq 12 -
+ *20
+ *21 EISA irq 14 14
+ *22 EISA irq 15 15
+ *23 IIC -
+ *24 VGA (builtin) -
+ *25
+ *26
+ *27
+ *28 NCR810 (builtin) 28
+ *29
+ *30
+ *31
+ *32 PCI 0 slot 4 A primary bus 32
+ *33 PCI 0 slot 4 B primary bus 33
+ *34 PCI 0 slot 4 C primary bus 34
+ *35 PCI 0 slot 4 D primary bus
+ *36 PCI 0 slot 5 A primary bus
+ *37 PCI 0 slot 5 B primary bus
+ *38 PCI 0 slot 5 C primary bus
+ *39 PCI 0 slot 5 D primary bus
+ *40 PCI 0 slot 6 A primary bus
+ *41 PCI 0 slot 6 B primary bus
+ *42 PCI 0 slot 6 C primary bus
+ *43 PCI 0 slot 6 D primary bus
+ *44 PCI 0 slot 7 A primary bus
+ *45 PCI 0 slot 7 B primary bus
+ *46 PCI 0 slot 7 C primary bus
+ *47 PCI 0 slot 7 D primary bus
+ *48 PCI 0 slot 0 A secondary bus
+ *49 PCI 0 slot 0 B secondary bus
+ *50 PCI 0 slot 0 C secondary bus
+ *51 PCI 0 slot 0 D secondary bus
+ *52 PCI 0 slot 1 A secondary bus
+ *53 PCI 0 slot 1 B secondary bus
+ *54 PCI 0 slot 1 C secondary bus
+ *55 PCI 0 slot 1 D secondary bus
+ *56 PCI 0 slot 2 A secondary bus
+ *57 PCI 0 slot 2 B secondary bus
+ *58 PCI 0 slot 2 C secondary bus
+ *59 PCI 0 slot 2 D secondary bus
+ *60 PCI 0 slot 3 A secondary bus
+ *61 PCI 0 slot 3 B secondary bus
+ *62 PCI 0 slot 3 C secondary bus
+ *63 PCI 0 slot 3 D secondary bus
+ */
+
+static void
+lynx_update_irq_hw(unsigned long bit, unsigned long mask)
+{
+ /*
+ * Write the AIR register on the T3/T4 with the
+ * address of the IC mask register (offset 0x40)
+ */
+ *(vulp)T2_AIR = 0x40;
+ mb();
+ *(vulp)T2_AIR; /* re-read to force write */
+ mb();
+ *(vulp)T2_DIR = mask;
+ mb();
+ mb();
+}
+
+static void
+lynx_ack_irq_hw(unsigned long bit)
+{
+ *(vulp)T2_VAR = (u_long) bit;
+ mb();
+ mb();
+}
+
+static irq_swizzle_t lynx_irq_swizzle = {
+ { /* irq_to_mask */
+ -1, 6, -1, 8, 15, 12, 7, 9, /* pseudo PIC 0-7 */
+ -1, 16, 17, 18, 3, -1, 21, 22, /* pseudo PIC 8-15 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo */
+ -1, -1, -1, -1, 28, -1, -1, -1, /* pseudo */
+ 32, 33, 34, 35, 36, 37, 38, 39, /* mask 32-39 */
+ 40, 41, 42, 43, 44, 45, 46, 47, /* mask 40-47 */
+ 48, 49, 50, 51, 52, 53, 54, 55, /* mask 48-55 */
+ 56, 57, 58, 59, 60, 61, 62, 63 /* mask 56-63 */
+ },
+ { /* mask_to_irq */
+ -1, -1, -1, 12, -1, -1, 1, 6, /* mask 0-7 */
+ 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */
+ 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */
+ -1, -1, -1, -1, 28, -1, -1, -1, /* mask 24-31 */
+ 32, 33, 34, 35, 36, 37, 38, 39, /* mask 32-39 */
+ 40, 41, 42, 43, 44, 45, 46, 47, /* mask 40-47 */
+ 48, 49, 50, 51, 52, 53, 54, 55, /* mask 48-55 */
+ 56, 57, 58, 59, 60, 61, 62, 63 /* mask 56-63 */
+ },
+ -1,
+ lynx_update_irq_hw,
+ lynx_ack_irq_hw
+};
+
+static void __init
+lynx_init_irq(void)
+{
+ sable_lynx_irq_swizzle = &lynx_irq_swizzle;
+ sable_lynx_init_irq(64);
+}
+
+/*
+ * PCI Fixup configuration for ALPHA LYNX (2100A)
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot Device
+ * 0 none
+ * 1 none
+ * 2 PCI-EISA bridge
+ * 3 PCI-PCI bridge
+ * 4 NCR 810 (Demi-Lynx only)
+ * 5 none
+ * 6 PCI on board slot 4
+ * 7 PCI on board slot 5
+ * 8 PCI on board slot 6
+ * 9 PCI on board slot 7
+ *
+ * And behind the PPB we have:
+ *
+ * 11 PCI on board slot 0
+ * 12 PCI on board slot 1
+ * 13 PCI on board slot 2
+ * 14 PCI on board slot 3
+ */
+/*
+ * NOTE: the IRQ assignments below are arbitrary, but need to be consistent
+ * with the values in the irq swizzling tables above.
+ */
+
+static int __init
+lynx_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ static char irq_tab[19][5] __initdata = {
+ /*INT INTA INTB INTC INTD */
+ { -1, -1, -1, -1, -1}, /* IdSel 13, PCEB */
+ { -1, -1, -1, -1, -1}, /* IdSel 14, PPB */
+ { 28, 28, 28, 28, 28}, /* IdSel 15, NCR demi */
+ { -1, -1, -1, -1, -1}, /* IdSel 16, none */
+ { 32, 32, 33, 34, 35}, /* IdSel 17, slot 4 */
+ { 36, 36, 37, 38, 39}, /* IdSel 18, slot 5 */
+ { 40, 40, 41, 42, 43}, /* IdSel 19, slot 6 */
+ { 44, 44, 45, 46, 47}, /* IdSel 20, slot 7 */
+ { -1, -1, -1, -1, -1}, /* IdSel 22, none */
+ /* The following are actually behind the PPB. */
+ { -1, -1, -1, -1, -1}, /* IdSel 16 none */
+ { 28, 28, 28, 28, 28}, /* IdSel 17 NCR lynx */
+ { -1, -1, -1, -1, -1}, /* IdSel 18 none */
+ { -1, -1, -1, -1, -1}, /* IdSel 19 none */
+ { -1, -1, -1, -1, -1}, /* IdSel 20 none */
+ { -1, -1, -1, -1, -1}, /* IdSel 21 none */
+ { 48, 48, 49, 50, 51}, /* IdSel 22 slot 0 */
+ { 52, 52, 53, 54, 55}, /* IdSel 23 slot 1 */
+ { 56, 56, 57, 58, 59}, /* IdSel 24 slot 2 */
+ { 60, 60, 61, 62, 63} /* IdSel 25 slot 3 */
+ };
+ const long min_idsel = 2, max_idsel = 20, irqs_per_slot = 5;
+ return COMMON_TABLE_LOOKUP;
+}
+
+static u8 __init
+lynx_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+ int slot, pin = *pinp;
+
+ if (dev->bus->number == 0) {
+ slot = PCI_SLOT(dev->devfn);
+ }
+ /* Check for the built-in bridge */
+ else if (PCI_SLOT(dev->bus->self->devfn) == 3) {
+ slot = PCI_SLOT(dev->devfn) + 11;
+ }
+ else
+ {
+ /* Must be a card-based bridge. */
+ do {
+ if (PCI_SLOT(dev->bus->self->devfn) == 3) {
+ slot = PCI_SLOT(dev->devfn) + 11;
+ break;
+ }
+ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)) ;
+
+ /* Move up the chain of bridges. */
+ dev = dev->bus->self;
+ /* Slot of the next bridge. */
+ slot = PCI_SLOT(dev->devfn);
+ } while (dev->bus->self);
+ }
+ *pinp = pin;
+ return slot;
+}
+
+#endif /* defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LYNX) */
+
+/***********************************************************************/
+/* GENERIC irq routines */
+
+static inline void
+sable_lynx_enable_irq(unsigned int irq)
+{
+ unsigned long bit, mask;
+
+ bit = sable_lynx_irq_swizzle->irq_to_mask[irq];
+ spin_lock(&sable_lynx_irq_lock);
+ mask = sable_lynx_irq_swizzle->shadow_mask &= ~(1UL << bit);
+ sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
+ spin_unlock(&sable_lynx_irq_lock);
+#if 0
+ printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n",
+ __FUNCTION__, mask, bit, irq);
+#endif
+}
+
+static void
+sable_lynx_disable_irq(unsigned int irq)
+{
+ unsigned long bit, mask;
+
+ bit = sable_lynx_irq_swizzle->irq_to_mask[irq];
+ spin_lock(&sable_lynx_irq_lock);
+ mask = sable_lynx_irq_swizzle->shadow_mask |= 1UL << bit;
+ sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
+ spin_unlock(&sable_lynx_irq_lock);
+#if 0
+ printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n",
+ __FUNCTION__, mask, bit, irq);
+#endif
+}
+
+static unsigned int
+sable_lynx_startup_irq(unsigned int irq)
+{
+ sable_lynx_enable_irq(irq);
+ return 0;
+}
+
+static void
+sable_lynx_end_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ sable_lynx_enable_irq(irq);
+}
+
+static void
+sable_lynx_mask_and_ack_irq(unsigned int irq)
+{
+ unsigned long bit, mask;
+
+ bit = sable_lynx_irq_swizzle->irq_to_mask[irq];
+ spin_lock(&sable_lynx_irq_lock);
+ mask = sable_lynx_irq_swizzle->shadow_mask |= 1UL << bit;
+ sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
+ sable_lynx_irq_swizzle->ack_irq_hw(bit);
+ spin_unlock(&sable_lynx_irq_lock);
+}
+
+static struct hw_interrupt_type sable_lynx_irq_type = {
+ .typename = "SABLE/LYNX",
+ .startup = sable_lynx_startup_irq,
+ .shutdown = sable_lynx_disable_irq,
+ .enable = sable_lynx_enable_irq,
+ .disable = sable_lynx_disable_irq,
+ .ack = sable_lynx_mask_and_ack_irq,
+ .end = sable_lynx_end_irq,
+};
+
+static void
+sable_lynx_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+ /* Note that the vector reported by the SRM PALcode corresponds
+ to the interrupt mask bits, but we have to manage via the
+ so-called legacy IRQs for many common devices. */
+
+ int bit, irq;
+
+ bit = (vector - 0x800) >> 4;
+ irq = sable_lynx_irq_swizzle->mask_to_irq[bit];
+#if 0
+ printk("%s: vector 0x%lx bit 0x%x irq 0x%x\n",
+ __FUNCTION__, vector, bit, irq);
+#endif
+ handle_irq(irq, regs);
+}
+
+static void __init
+sable_lynx_init_irq(int nr_irqs)
+{
+ long i;
+
+ for (i = 0; i < nr_irqs; ++i) {
+ irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
+ irq_desc[i].handler = &sable_lynx_irq_type;
+ }
+
+ common_init_isa_dma();
+}
+
+static void __init
+sable_lynx_init_pci(void)
+{
+ common_init_pci();
+}
+
+/*****************************************************************/
/*
* The System Vectors
*
* these games with GAMMA_BIAS.
*/
-#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_GAMMA)
+#if defined(CONFIG_ALPHA_GENERIC) || \
+ (defined(CONFIG_ALPHA_SABLE) && !defined(CONFIG_ALPHA_GAMMA))
#undef GAMMA_BIAS
#define GAMMA_BIAS 0
struct alpha_machine_vector sable_mv __initmv = {
.min_mem_address = T2_DEFAULT_MEM_BASE,
.nr_irqs = 40,
- .device_interrupt = sable_srm_device_interrupt,
+ .device_interrupt = sable_lynx_srm_device_interrupt,
.init_arch = t2_init_arch,
.init_irq = sable_init_irq,
.init_rtc = common_init_rtc,
- .init_pci = common_init_pci,
- .kill_arch = NULL,
+ .init_pci = sable_lynx_init_pci,
+ .kill_arch = t2_kill_arch,
.pci_map_irq = sable_map_irq,
.pci_swizzle = common_swizzle,
} }
};
ALIAS_MV(sable)
-#endif
+#endif /* GENERIC || (SABLE && !GAMMA) */
-#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_GAMMA)
+#if defined(CONFIG_ALPHA_GENERIC) || \
+ (defined(CONFIG_ALPHA_SABLE) && defined(CONFIG_ALPHA_GAMMA))
#undef GAMMA_BIAS
#define GAMMA_BIAS _GAMMA_BIAS
struct alpha_machine_vector sable_gamma_mv __initmv = {
.min_mem_address = T2_DEFAULT_MEM_BASE,
.nr_irqs = 40,
- .device_interrupt = sable_srm_device_interrupt,
+ .device_interrupt = sable_lynx_srm_device_interrupt,
.init_arch = t2_init_arch,
.init_irq = sable_init_irq,
.init_rtc = common_init_rtc,
- .init_pci = common_init_pci,
+ .init_pci = sable_lynx_init_pci,
+ .kill_arch = t2_kill_arch,
.pci_map_irq = sable_map_irq,
.pci_swizzle = common_swizzle,
} }
};
ALIAS_MV(sable_gamma)
-#endif
+#endif /* GENERIC || (SABLE && GAMMA) */
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LYNX)
+#undef GAMMA_BIAS
+#define GAMMA_BIAS _GAMMA_BIAS
+struct alpha_machine_vector lynx_mv __initmv = {
+ .vector_name = "Lynx",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_T2_IO,
+ DO_T2_BUS,
+ .machine_check = t2_machine_check,
+ .max_isa_dma_address = ALPHA_SABLE_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = EISA_DEFAULT_IO_BASE,
+ .min_mem_address = T2_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 64,
+ .device_interrupt = sable_lynx_srm_device_interrupt,
+
+ .init_arch = t2_init_arch,
+ .init_irq = lynx_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = sable_lynx_init_pci,
+ .kill_arch = t2_kill_arch,
+ .pci_map_irq = lynx_map_irq,
+ .pci_swizzle = lynx_swizzle,
+
+ .sys = { .t2 = {
+ .gamma_bias = _GAMMA_BIAS
+ } }
+};
+ALIAS_MV(lynx)
+#endif /* GENERIC || LYNX */
#include <linux/config.h>
#include <linux/types.h>
+#include <linux/spinlock.h>
#include <asm/compiler.h>
-
+#include <asm/system.h>
/*
* T2 is the internal name for the core logic chipset which provides
#define T2_MEM_R1_MASK 0x07ffffff /* Mem sparse region 1 mask is 26 bits */
/* GAMMA-SABLE is a SABLE with EV5-based CPUs */
+/* All LYNX machines, EV4 or EV5, use the GAMMA bias also */
#define _GAMMA_BIAS 0x8000000000UL
#if defined(CONFIG_ALPHA_GENERIC)
#define T2_WMASK2 (IDENT_ADDR + GAMMA_BIAS + 0x38e0001c0UL)
#define T2_TBASE2 (IDENT_ADDR + GAMMA_BIAS + 0x38e0001e0UL)
#define T2_TLBBR (IDENT_ADDR + GAMMA_BIAS + 0x38e000200UL)
-
+#define T2_IVR (IDENT_ADDR + GAMMA_BIAS + 0x38e000220UL)
#define T2_HAE_3 (IDENT_ADDR + GAMMA_BIAS + 0x38e000240UL)
#define T2_HAE_4 (IDENT_ADDR + GAMMA_BIAS + 0x38e000260UL)
+/* The CSRs below are T3/T4 only */
+#define T2_WBASE3 (IDENT_ADDR + GAMMA_BIAS + 0x38e000280UL)
+#define T2_WMASK3 (IDENT_ADDR + GAMMA_BIAS + 0x38e0002a0UL)
+#define T2_TBASE3 (IDENT_ADDR + GAMMA_BIAS + 0x38e0002c0UL)
+
+#define T2_TDR0 (IDENT_ADDR + GAMMA_BIAS + 0x38e000300UL)
+#define T2_TDR1 (IDENT_ADDR + GAMMA_BIAS + 0x38e000320UL)
+#define T2_TDR2 (IDENT_ADDR + GAMMA_BIAS + 0x38e000340UL)
+#define T2_TDR3 (IDENT_ADDR + GAMMA_BIAS + 0x38e000360UL)
+#define T2_TDR4 (IDENT_ADDR + GAMMA_BIAS + 0x38e000380UL)
+#define T2_TDR5 (IDENT_ADDR + GAMMA_BIAS + 0x38e0003a0UL)
+#define T2_TDR6 (IDENT_ADDR + GAMMA_BIAS + 0x38e0003c0UL)
+#define T2_TDR7 (IDENT_ADDR + GAMMA_BIAS + 0x38e0003e0UL)
+
+#define T2_WBASE4 (IDENT_ADDR + GAMMA_BIAS + 0x38e000400UL)
+#define T2_WMASK4 (IDENT_ADDR + GAMMA_BIAS + 0x38e000420UL)
+#define T2_TBASE4 (IDENT_ADDR + GAMMA_BIAS + 0x38e000440UL)
+
+#define T2_AIR (IDENT_ADDR + GAMMA_BIAS + 0x38e000460UL)
+#define T2_VAR (IDENT_ADDR + GAMMA_BIAS + 0x38e000480UL)
+#define T2_DIR (IDENT_ADDR + GAMMA_BIAS + 0x38e0004a0UL)
+#define T2_ICE (IDENT_ADDR + GAMMA_BIAS + 0x38e0004c0UL)
+
#define T2_HAE_ADDRESS T2_HAE_1
/* T2 CSRs are in the non-cachable primary IO space from 3.8000.0000 to
#define T2_CPU1_BASE (IDENT_ADDR + GAMMA_BIAS + 0x381000000L)
#define T2_CPU2_BASE (IDENT_ADDR + GAMMA_BIAS + 0x382000000L)
#define T2_CPU3_BASE (IDENT_ADDR + GAMMA_BIAS + 0x383000000L)
+
+#define T2_CPUn_BASE(n) (T2_CPU0_BASE + (((n)&3) * 0x001000000L))
+
#define T2_MEM0_BASE (IDENT_ADDR + GAMMA_BIAS + 0x388000000L)
#define T2_MEM1_BASE (IDENT_ADDR + GAMMA_BIAS + 0x389000000L)
#define T2_MEM2_BASE (IDENT_ADDR + GAMMA_BIAS + 0x38a000000L)
set_hae(msb); \
}
+static spinlock_t t2_hae_lock = SPIN_LOCK_UNLOCKED;
+
__EXTERN_INLINE u8 t2_readb(unsigned long addr)
{
unsigned long result, msb;
+ unsigned long flags;
+ spin_lock_irqsave(&t2_hae_lock, flags);
t2_set_hae;
result = *(vip) ((addr << 5) + T2_SPARSE_MEM + 0x00);
+ spin_unlock_irqrestore(&t2_hae_lock, flags);
return __kernel_extbl(result, addr & 3);
}
__EXTERN_INLINE u16 t2_readw(unsigned long addr)
{
unsigned long result, msb;
+ unsigned long flags;
+ spin_lock_irqsave(&t2_hae_lock, flags);
t2_set_hae;
result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08);
+ spin_unlock_irqrestore(&t2_hae_lock, flags);
return __kernel_extwl(result, addr & 3);
}
-/* On SABLE with T2, we must use SPARSE memory even for 32-bit access. */
+/*
+ * On SABLE with T2, we must use SPARSE memory even for 32-bit access,
+ * because we cannot access all of DENSE without changing its HAE.
+ */
__EXTERN_INLINE u32 t2_readl(unsigned long addr)
{
- unsigned long msb;
+ unsigned long result, msb;
+ unsigned long flags;
+ spin_lock_irqsave(&t2_hae_lock, flags);
t2_set_hae;
- return *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18);
+ result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18);
+ spin_unlock_irqrestore(&t2_hae_lock, flags);
+ return result & 0xffffffffUL;
}
__EXTERN_INLINE u64 t2_readq(unsigned long addr)
{
unsigned long r0, r1, work, msb;
+ unsigned long flags;
+ spin_lock_irqsave(&t2_hae_lock, flags);
t2_set_hae;
work = (addr << 5) + T2_SPARSE_MEM + 0x18;
r0 = *(vuip)(work);
r1 = *(vuip)(work + (4 << 5));
+ spin_unlock_irqrestore(&t2_hae_lock, flags);
return r1 << 32 | r0;
}
__EXTERN_INLINE void t2_writeb(u8 b, unsigned long addr)
{
unsigned long msb, w;
+ unsigned long flags;
+ spin_lock_irqsave(&t2_hae_lock, flags);
t2_set_hae;
w = __kernel_insbl(b, addr & 3);
*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = w;
+ spin_unlock_irqrestore(&t2_hae_lock, flags);
}
__EXTERN_INLINE void t2_writew(u16 b, unsigned long addr)
{
unsigned long msb, w;
+ unsigned long flags;
+ spin_lock_irqsave(&t2_hae_lock, flags);
t2_set_hae;
w = __kernel_inswl(b, addr & 3);
*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = w;
+ spin_unlock_irqrestore(&t2_hae_lock, flags);
}
-/* On SABLE with T2, we must use SPARSE memory even for 32-bit access. */
+/*
+ * On SABLE with T2, we must use SPARSE memory even for 32-bit access,
+ * because we cannot access all of DENSE without changing its HAE.
+ */
__EXTERN_INLINE void t2_writel(u32 b, unsigned long addr)
{
unsigned long msb;
+ unsigned long flags;
+ spin_lock_irqsave(&t2_hae_lock, flags);
t2_set_hae;
*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b;
+ spin_unlock_irqrestore(&t2_hae_lock, flags);
}
__EXTERN_INLINE void t2_writeq(u64 b, unsigned long addr)
{
unsigned long msb, work;
+ unsigned long flags;
+ spin_lock_irqsave(&t2_hae_lock, flags);
t2_set_hae;
work = (addr << 5) + T2_SPARSE_MEM + 0x18;
*(vuip)work = b;
*(vuip)(work + (4 << 5)) = b >> 32;
+ spin_unlock_irqrestore(&t2_hae_lock, flags);
}
__EXTERN_INLINE unsigned long t2_ioremap(unsigned long addr,