diff -Nur linux-git/arch/mips/Kconfig linux-git-mit-R10k-patches/arch/mips/Kconfig --- linux-git/arch/mips/Kconfig 2005-10-15 16:01:06.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/Kconfig 2005-10-16 13:21:56.000000000 +0200 @@ -527,6 +527,25 @@ workstations. To compile a Linux kernel that runs on these, say Y here. +config SGI_IP28 + bool "Support for SGI IP28 (Indigo2 R10k) (EXPERIMENTAL)" + depends EXPERIMENTAL + select ARC + select ARC64 + select DMA_NONCOHERENT + select IRQ_CPU + select SWAP_IO_SPACE + select HW_HAS_EISA + select CPU_R10000 + select XKPHYS_KERNEL + select BUILD_ELF64 + select BOOT_ELF64 + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN + help + This is the SGI Indigo2 with R10000 processor. To compile a Linux + kernel that runs on these, say Y here. + config SGI_IP32 bool "Support for SGI IP32 (O2) (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -942,7 +961,7 @@ config ARC_CONSOLE bool "ARC console support" - depends on SGI_IP22 || SNI_RM200_PCI + depends on SGI_IP22 || SNI_RM200_PCI || SGI_IP28 config ARC_MEMORY bool @@ -951,7 +970,7 @@ config ARC_PROMLIB bool - depends on MACH_JAZZ || SNI_RM200_PCI || SGI_IP22 || SGI_IP32 + depends on MACH_JAZZ || SNI_RM200_PCI || SGI_IP22 || SGI_IP28 || SGI_IP32 default y config ARC64 @@ -1319,6 +1338,14 @@ bool "Support for 64-bit physical address space" depends on (CPU_R4X00 || CPU_R5000 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 || CPU_SB1 || CPU_MIPS32_R1 || CPU_MIPS64_R1) && 32BIT +config XKPHYS_KERNEL + bool "Allow kernel to run from 64-bit segments" + depends on MIPS64 + help + This option allows to locate the kernel in 64-bit unmapped memory + space (xkphys). This is required for Octane (IP30) or Indigo2 R10k + (IP28) machines. + config CPU_ADVANCED bool "Override CPU Options" depends on 32BIT @@ -1643,6 +1670,9 @@ and the task is only allowed to execute a few safe syscalls defined by each seccomp mode. +# Revision 1.145, Tue Apr 19 00:00:45 2005 +# Jun/Dec 2004 - IP28 + If unsure, say Y. Only embedded should say N here. config PM diff -Nur linux-git/arch/mips/kernel/gdb-low.S linux-git-mit-R10k-patches/arch/mips/kernel/gdb-low.S --- linux-git/arch/mips/kernel/gdb-low.S 2005-10-15 16:01:06.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/kernel/gdb-low.S 2005-10-16 13:21:56.000000000 +0200 @@ -52,7 +52,11 @@ /* * Called from user mode, go somewhere else. */ +#ifdef CONFIG_XKPHYS_KERNEL + dla k1, saved_vectors +#else lui k1, %hi(saved_vectors) +#endif mfc0 k0, CP0_CAUSE andi k0, k0, 0x7c add k1, k1, k0 @@ -61,7 +65,11 @@ nop 1: move k0, sp +#ifdef CONFIG_MIPS64 + dsubu sp, k1, GDB_FR_SIZE*2 # see comment above +#else subu sp, k1, GDB_FR_SIZE*2 # see comment above +#endif LONG_S k0, GDB_FR_REG29(sp) LONG_S $2, GDB_FR_REG2(sp) @@ -368,3 +376,7 @@ kgdbfault: li v0, -EFAULT jr ra .end kgdbfault +/* + * Revision 1.17, Mon Nov 17 17:19:39 2003 + * Wed May 12 21:21:49 2004 xkphys kernel addresses + */ diff -Nur linux-git/arch/mips/kernel/setup.c linux-git-mit-R10k-patches/arch/mips/kernel/setup.c --- linux-git/arch/mips/kernel/setup.c 2005-10-15 16:01:06.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/kernel/setup.c 2005-10-16 13:25:04.000000000 +0200 @@ -302,7 +302,7 @@ * Partially used pages are not usable - thus * we are rounding upwards. */ - start_pfn = PFN_UP(CPHYSADDR(reserved_end)); + start_pfn = PFN_UP(kernel_physaddr(reserved_end)); #ifndef CONFIG_SGI_IP27 /* Find the highest page frame number we have available. */ @@ -426,11 +426,11 @@ printk("Initial ramdisk at: 0x%p (%lu bytes)\n", (void *)initrd_start, initrd_size); - if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) { + if (kernel_physaddr(initrd_end) > PFN_PHYS(max_low_pfn)) { printk("initrd extends beyond end of memory " "(0x%0*Lx > 0x%0*Lx)\ndisabling initrd\n", sizeof(long) * 2, - (unsigned long long)CPHYSADDR(initrd_end), + (unsigned long long)kernel_physaddr(initrd_end), sizeof(long) * 2, (unsigned long long)PFN_PHYS(max_low_pfn)); initrd_start = initrd_end = 0; @@ -438,7 +438,7 @@ } if (initrd_reserve_bootmem) - reserve_bootmem(CPHYSADDR(initrd_start), initrd_size); + reserve_bootmem(kernel_physaddr(initrd_start), initrd_size); } #endif /* CONFIG_BLK_DEV_INITRD */ } @@ -452,10 +452,10 @@ * The 64bit code in 32bit object format trick can't represent * 64bit wide relocations for linker script symbols. */ - code_resource.start = CPHYSADDR(&_text); - code_resource.end = CPHYSADDR(&_etext) - 1; - data_resource.start = CPHYSADDR(&_etext); - data_resource.end = CPHYSADDR(&_edata) - 1; + code_resource.start = kernel_physaddr(&_text); + code_resource.end = kernel_physaddr(&_etext) - 1; + data_resource.start = kernel_physaddr(&_etext); + data_resource.end = kernel_physaddr(&_edata) - 1; #else code_resource.start = virt_to_phys(&_text); code_resource.end = virt_to_phys(&_etext) - 1; @@ -559,3 +559,9 @@ } __setup("nodsp", dsp_disable); + +/* + * Revision 1.179, Tue Apr 19 00:06:09 2005 + * Apr 2004/2005 pf - xkphys kernel addresses + */ + diff -Nur linux-git/arch/mips/lib/memcpy.S linux-git-mit-R10k-patches/arch/mips/lib/memcpy.S --- linux-git/arch/mips/lib/memcpy.S 2005-10-15 16:01:06.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/lib/memcpy.S 2005-10-16 13:21:56.000000000 +0200 @@ -17,6 +17,14 @@ #include #include +#ifdef CONFIG_SGI_IP28 +/* Inhibit speculative stores to volatile (e.g.DMA) or invalid addresses. */ +# include +# define R10KCBARRIER(addr) cache Cache_Barrier, addr; +#else +# define R10KCBARRIER(addr) +#endif + #define dst a0 #define src a1 #define len a2 @@ -180,6 +188,7 @@ */ #define rem t8 + R10KCBARRIER(0(ra)) /* hopefully inhibits speculative store prefetch */ /* * The "issue break"s below are very approximate. * Issue delays for dcache fills will perturb the schedule, as will @@ -212,6 +221,7 @@ PREF( 1, 3*32(dst) ) .align 4 1: + R10KCBARRIER(0(ra)) /* ra must be valid anyway */ EXC( LOAD t0, UNIT(0)(src), l_exc) EXC( LOAD t1, UNIT(1)(src), l_exc_copy) EXC( LOAD t2, UNIT(2)(src), l_exc_copy) @@ -253,6 +263,7 @@ EXC( LOAD t3, UNIT(3)(src), l_exc_copy) SUB len, len, 4*NBYTES ADD src, src, 4*NBYTES + R10KCBARRIER(0(ra)) EXC( STORE t0, UNIT(0)(dst), s_exc_p4u) EXC( STORE t1, UNIT(1)(dst), s_exc_p3u) EXC( STORE t2, UNIT(2)(dst), s_exc_p2u) @@ -266,6 +277,7 @@ beq rem, len, copy_bytes nop 1: + R10KCBARRIER(0(ra)) EXC( LOAD t0, 0(src), l_exc) ADD src, src, NBYTES SUB len, len, NBYTES @@ -311,6 +323,7 @@ EXC( LDREST t3, REST(0)(src), l_exc_copy) SUB t2, t2, t1 # t2 = number of bytes copied xor match, t0, t1 + R10KCBARRIER(0(ra)) EXC( STFIRST t3, FIRST(0)(dst), s_exc) beq len, t2, done SUB len, len, t2 @@ -331,6 +344,7 @@ * It's OK to load FIRST(N+1) before REST(N) because the two addresses * are to the same unit (unless src is aligned, but it's not). */ + R10KCBARRIER(0(ra)) EXC( LDFIRST t0, FIRST(0)(src), l_exc) EXC( LDFIRST t1, FIRST(1)(src), l_exc_copy) SUB len, len, 4*NBYTES @@ -359,6 +373,7 @@ beq rem, len, copy_bytes nop 1: + R10KCBARRIER(0(ra)) EXC( LDFIRST t0, FIRST(0)(src), l_exc) EXC( LDREST t0, REST(0)(src), l_exc_copy) ADD src, src, NBYTES @@ -372,6 +387,7 @@ nop copy_bytes: /* 0 < len < NBYTES */ + R10KCBARRIER(0(ra)) #define COPY_BYTE(N) \ EXC( lb t0, N(src), l_exc); \ SUB len, len, 1; \ @@ -484,6 +500,7 @@ ADD a1, a2 # src = src + len r_end_bytes: + R10KCBARRIER(0(ra)) lb t0, -1(a1) SUB a2, a2, 0x1 sb t0, -1(a0) @@ -496,6 +513,7 @@ move a2, zero r_end_bytes_up: + R10KCBARRIER(0(ra)) lb t0, (a1) SUB a2, a2, 0x1 sb t0, (a0) @@ -506,3 +524,7 @@ jr ra move a2, zero END(__rmemcpy) +/* + * Revision 1.18, Sat Jul 26 12:00:12 2003 + * Sat Aug 7 01:11:52 2004 pf - r10k cache barrier + */ diff -Nur linux-git/arch/mips/lib/strncpy_user.S linux-git-mit-R10k-patches/arch/mips/lib/strncpy_user.S --- linux-git/arch/mips/lib/strncpy_user.S 2005-10-15 16:01:06.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/lib/strncpy_user.S 2005-10-16 13:30:49.000000000 +0200 @@ -5,11 +5,20 @@ * * Copyright (c) 1996, 1999 by Ralf Baechle */ +#include #include #include #include #include +#ifdef CONFIG_SGI_IP28 +/* Inhibit speculative stores to volatile (e.g.DMA) or invalid addresses. */ +# include +# define R10KCBARRIER(addr) cache Cache_Barrier, addr; +#else +# define R10KCBARRIER(addr) +#endif + #define EX(insn,reg,addr,handler) \ 9: insn reg, addr; \ .section __ex_table,"a"; \ @@ -38,6 +47,7 @@ .set noreorder 1: EX(lbu, t0, (v1), fault) PTR_ADDIU v1, 1 + R10KCBARRIER(0(ra)) beqz t0, 2f sb t0, (a0) PTR_ADDIU v0, 1 @@ -56,3 +66,7 @@ .section __ex_table,"a" PTR 1b, fault .previous +/* + * Revision 1.9, Wed Nov 19 14:03:13 2003 + * Wed Aug 11 02:21:01 2004 pf - r10k cache barrier + */ diff -Nur linux-git/arch/mips/lib-64/memset.S linux-git-mit-R10k-patches/arch/mips/lib-64/memset.S --- linux-git/arch/mips/lib-64/memset.S 2005-10-15 16:01:06.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/lib-64/memset.S 2005-10-16 13:29:04.000000000 +0200 @@ -6,10 +6,19 @@ * Copyright (C) 1998, 1999, 2000 by Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ +#include #include #include #include +#ifdef CONFIG_SGI_IP28 +/* Inhibit speculative stores to volatile (e.g.DMA) or invalid addresses. */ +# include +# define R10KCBARRIER(addr) cache Cache_Barrier, addr; +#else +# define R10KCBARRIER(addr) +#endif + #define EX(insn,reg,addr,handler) \ 9: insn reg, addr; \ .section __ex_table,"a"; \ @@ -57,6 +66,7 @@ beqz t0, 1f PTR_SUBU t0, LONGSIZE /* alignment in bytes */ + R10KCBARRIER(0(ra)) #ifdef __MIPSEB__ EX(sdl, a1, (a0), first_fixup) /* make dword aligned */ #endif @@ -74,11 +84,13 @@ PTR_ADDU t1, a0 /* end address */ .set reorder 1: PTR_ADDIU a0, 64 + R10KCBARRIER(0(ra)) f_fill64 a0, -64, a1, fwd_fixup bne t1, a0, 1b .set noreorder memset_partial: + R10KCBARRIER(0(ra)) PTR_LA t1, 2f /* where to start */ .set noat dsrl AT, t0, 1 @@ -96,6 +108,7 @@ beqz a2, 1f PTR_ADDU a0, a2 /* What's left */ + R10KCBARRIER(0(ra)) #ifdef __MIPSEB__ EX(sdr, a1, -1(a0), last_fixup) #endif @@ -110,6 +123,7 @@ PTR_ADDU t1, a0, a2 1: PTR_ADDIU a0, 1 /* fill bytewise */ + R10KCBARRIER(0(ra)) bne t1, a0, 1b sb a1, -1(a0) @@ -140,3 +154,7 @@ last_fixup: jr ra andi v1, a2, LONGMASK +/* + * Revision 1.1, Mon Jul 21 00:11:39 2003 + * Wed Aug 11 01:52:59 2004 pf - r10k cache barrier + */ diff -Nur linux-git/arch/mips/Makefile linux-git-mit-R10k-patches/arch/mips/Makefile --- linux-git/arch/mips/Makefile 2005-10-15 16:01:06.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/Makefile 2005-10-16 13:21:56.000000000 +0200 @@ -628,6 +628,19 @@ endif # +# SGI IP28 (Indigo2 R10k) +# +# Set the load address to >= 0xa800000020080000 if you want to leave space for +# symmon, 0xa800000020004000 for production kernels ? Note that the value must +# be 16kb aligned or the handling of the current variable will break. +# Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys +# +#core-$(CONFIG_SGI_IP28) += arch/mips/sgi-ip22/ arch/mips/arc/arc_con.o +core-$(CONFIG_SGI_IP28) += arch/mips/sgi-ip22/ +cflags-$(CONFIG_SGI_IP28) += -mip28-cache-barrier -Iinclude/asm-mips/mach-ip28 +load-$(CONFIG_SGI_IP28) += 0xa800000020004000 + +# # SGI-IP32 (O2) # # Set the load address to >= 80069000 if you want to leave space for symmon, @@ -814,3 +827,6 @@ CLEAN_FILES += vmlinux.32 \ vmlinux.64 \ vmlinux.ecoff + +# Revision 1.193, Tue Apr 19 00:00:49 2005 +# Jun/Dec 2004 - IP28 diff -Nur linux-git/arch/mips/mm/c-r4k.c linux-git-mit-R10k-patches/arch/mips/mm/c-r4k.c --- linux-git/arch/mips/mm/c-r4k.c 2005-10-15 16:01:07.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/mm/c-r4k.c 2005-10-16 13:21:56.000000000 +0200 @@ -712,6 +712,27 @@ bc_inv(addr, size); } + +#ifdef CONFIG_CPU_R10000 +static void r10k_dma_cache_inv(unsigned long addr, unsigned long size) +{ + unsigned long sc_lsize = current_cpu_data.scache.linesz; + unsigned long end, a; + + /* Catch bad driver code */ + BUG_ON(size == 0); + //BUG_ON(!cpu_has_subset_pcaches); + + a = addr & ~(sc_lsize - 1); + end = (addr + size - 1) & ~(sc_lsize - 1); + while (1) { + invalidate_scache_line(a); /* Hit_Invalidate_SD/S */ + if (a == end) + break; + a += sc_lsize; + } +} +#endif /* CONFIG_CPU_R10000 */ #endif /* CONFIG_DMA_NONCOHERENT */ /* @@ -1269,7 +1290,16 @@ #ifdef CONFIG_DMA_NONCOHERENT _dma_cache_wback_inv = r4k_dma_cache_wback_inv; _dma_cache_wback = r4k_dma_cache_wback_inv; - _dma_cache_inv = r4k_dma_cache_inv; + switch (current_cpu_data.cputype) { +#ifdef CONFIG_CPU_R10000 + case CPU_R10000: + case CPU_R12000: + _dma_cache_inv = r10k_dma_cache_inv; + break; +#endif + default: + _dma_cache_inv = r4k_dma_cache_inv; + } #endif build_clear_page(); @@ -1277,3 +1307,7 @@ local_r4k___flush_cache_all(NULL); coherency_setup(); } +/* + * Revision 1.107, Tue Apr 19 00:06:40 2005 + * Sat Apr 9 00:06:16 2005 pf - r10k_dma_cache_inv (really dma invalidate) + */ diff -Nur linux-git/arch/mips/mm/init.c linux-git-mit-R10k-patches/arch/mips/mm/init.c --- linux-git/arch/mips/mm/init.c 2005-10-15 16:01:07.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/mm/init.c 2005-10-16 13:33:09.000000000 +0200 @@ -225,6 +225,7 @@ if (PageReserved(mem_map+tmp)) reservedpages++; } + num_physpages = ram; #ifdef CONFIG_HIGHMEM for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { @@ -241,6 +242,7 @@ set_page_count(page, 1); __free_page(page); totalhigh_pages++; + ++num_physpages; } totalram_pages += totalhigh_pages; #endif @@ -266,8 +268,8 @@ { #ifdef CONFIG_64BIT /* Switch from KSEG0 to XKPHYS addresses */ - start = (unsigned long)phys_to_virt(CPHYSADDR(start)); - end = (unsigned long)phys_to_virt(CPHYSADDR(end)); + start = (unsigned long)phys_to_virt(kernel_physaddr(start)); + end = (unsigned long)phys_to_virt(kernel_physaddr(end)); #endif if (start < end) printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", @@ -293,7 +295,7 @@ addr = (unsigned long) &__init_begin; while (addr < (unsigned long) &__init_end) { #ifdef CONFIG_64BIT - page = PAGE_OFFSET | CPHYSADDR(addr); + page = PAGE_OFFSET | kernel_physaddr(addr); #else page = addr; #endif @@ -307,3 +309,7 @@ printk(KERN_INFO "Freeing unused kernel memory: %ldk freed\n", freed >> 10); } +/* + * Revision 1.75, Tue Apr 19 00:06:47 2005 + * Jun 2004 pf - XKPHYS + */ diff -Nur linux-git/arch/mips/sgi-ip22/ip22-mc.c linux-git-mit-R10k-patches/arch/mips/sgi-ip22/ip22-mc.c --- linux-git/arch/mips/sgi-ip22/ip22-mc.c 2005-10-15 16:01:07.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/sgi-ip22/ip22-mc.c 2005-10-16 13:21:56.000000000 +0200 @@ -4,6 +4,7 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes * Copyright (C) 2003 Ladislav Michl (ladis@linux-mips.org) + * Copyright (C) 2004 Peter Fuerst (pf@net.alphadv.de) - IP28 */ #include @@ -16,6 +17,8 @@ #include #include #include +#include +#include struct sgimc_regs *sgimc; @@ -112,6 +115,10 @@ sgimc = (struct sgimc_regs *) ioremap(SGIMC_BASE, sizeof(struct sgimc_regs)); +#ifdef CONFIG_SGI_IP28 + printk(KERN_INFO "Silicon Graphics Indigo2 R10k (IP28)" + " support: (c) 2004 peter fuerst.\n"); +#endif printk(KERN_INFO "MC: SGI memory controller Revision %d\n", (int) sgimc->systemid & SGIMC_SYSID_MASKREV); @@ -138,8 +145,21 @@ * zero. */ tmp = sgimc->cpuctrl0; - tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM | - SGIMC_CCTRL0_R4KNOCHKPARR); + tmp |= SGIMC_CCTRL0_R4KNOCHKPARR; +#ifdef CONFIG_SGI_IP28 + /* IP28 prom left us cpuctrl0 set to 3d802412: + * SGIMC_CCTRL0_GIOBTOB, SGIMC_CCTRL0_R4KNOCHKPARR, + * SGIMC_CCTRL0_GFXRESET, SGIMC_CCTRL0_EREFRESH, 31800002 + * FIXME: + * We do not attempt to override IP28-prom's parity checking, + * since SGIMC_CCTRL0_EPERRGIO will trigger a CPU parity error + * (IP[6]) on reading sgioc->sysid below, while ..EPERRMEM will + * trigger the same somewhere in prom-code (ffffffff9fc431cc) + * when ArcGetEnvironmentVariable() is called :-( + */ +#else + tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM); +#endif sgimc->cpuctrl0 = tmp; /* Step 3: Setup the MC write buffer depth, this is controlled @@ -147,7 +167,14 @@ */ tmp = sgimc->cpuctrl1; tmp &= ~0xf; +#ifdef CONFIG_SGI_IP28 + /* IP28 prom left us cpuctrl1 set to 00000016: + * SGIMC_CCTRL1_EGIOTIMEO | 00000006 + */ + tmp |= 0xd; /* ? 0x6:0xd */ +#else tmp |= 0xd; +#endif sgimc->cpuctrl1 = tmp; /* Step 4: Initialize the RPSS divider register to run as fast @@ -164,7 +191,12 @@ * registers value increases at each 'tick'. Thus, * for IP22 we get INCREMENT=1, DIVIDER=1 == 0x101 */ +#ifdef CONFIG_SGI_IP28 + /* IP28 prom left us divider set to 00000104 */ + sgimc->divider = 0x101; /* ? 0x104:0x101 */ +#else sgimc->divider = 0x101; +#endif /* Step 5: Initialize GIO64 arbitrator configuration register. * @@ -177,6 +209,20 @@ tmp = SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits */ tmp |= SGIMC_GIOPAR_ONEBUS; /* Only one physical GIO bus exists */ +#ifdef CONFIG_SGI_IP28 + /* IP28 prom left us giopar set to 0000ce23: + * SGIMC_GIOPAR_PLINEEXP0, SGIMC_GIOPAR_PLINEEXP1, + * SGIMC_GIOPAR_MASTERGFX, SGIMC_GIOPAR_MASTEREISA, + * SGIMC_GIOPAR_ONEBUS, SGIMC_GIOPAR_GFX64, + * SGIMC_GIOPAR_HPC264, SGIMC_GIOPAR_HPC64 + */ + tmp |= SGIMC_GIOPAR_HPC264; /* 2nd HPC at 64bits */ + tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp0 pipelines */ + tmp |= SGIMC_GIOPAR_PLINEEXP1; /* exp1 pipelines */ + tmp |= SGIMC_GIOPAR_MASTERGFX; /* GFX can act as a bus master */ + tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA bus can act as bus master */ + tmp |= SGIMC_GIOPAR_GFX64; /* GFX talks to GIO using 64-bits */ +#else if (ip22_is_fullhouse()) { /* Fullhouse specific settings. */ if (SGIOC_SYSID_BOARDREV(sgioc->sysid) < 2) { @@ -196,9 +242,14 @@ tmp |= SGIMC_GIOPAR_EISA64; /* MC talks to EISA at 64bits */ tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA bus can act as master */ } +#endif sgimc->giopar = tmp; /* poof */ + printk(KERN_INFO "MC: Boardrev. %d, Chiprev. %d\n", + SGIOC_SYSID_BOARDREV(sgioc->sysid), + SGIOC_SYSID_CHIPREV(sgioc->sysid)); probe_memory(); + ip2628_return_ucmem(0); /* see below. */ } void __init prom_meminit(void) {} @@ -206,3 +257,99 @@ { return 0; } + +#if defined(CONFIG_SGI_IP28) || defined(CONFIG_SGI_IP26) +/* + * Handling uncached writes on IP26/IP28, see IRIX man-page ip26_ucmem(D3) + * and Device Driver Programmer's Guide (007-0911-210), Chapter I.1. + */ + +static inline int _r10k_real_sync ( volatile struct sgimc_regs *sgimc ) +{ + /* See MIPS R10000 User's Manual (SGI 007-2490-001), Chapter 4.5 */ + int dummy = sgimc->cstat; + __asm__ __volatile__ ("sync"); + return dummy; +} + +static unsigned long +ip28_set_ucmem ( volatile struct sgimc_regs *sgimc, unsigned short enable ) +{ /* + * Reading `modereg' only provides random values, so we start with + * guessing (from WR_COL), which state the machine is initially in + * and do our own bookkeeping from then on. + */ + const unsigned long modereg = PHYS_TO_XKSEG_UNCACHED(0x60000000); + static unsigned oldstate = -1; + unsigned long flags; + unsigned tmp; + spinlock_t lock; + u32 mconfig1, cmacc, oldcmacc; + + if (enable == oldstate) + return (long)enable; + + /* This has to be done as early as possible ! */ + spin_lock_irqsave(&lock, flags); + + oldcmacc = sgimc->cmacc; + cmacc = (enable ? 6:4) | (oldcmacc & ~0xf); + + /* increase WR_COL before (if at all) */ + sgimc->cmacc = cmacc | 7; + + /* enable memory bank 3 at 0x60000000 */ + mconfig1 = sgimc->mconfig1; + sgimc->mconfig1 = mconfig1 & 0xffff0000 | 0x2060; + _r10k_real_sync(sgimc); + + /* set mode to "slow" or "normal" */ + *(volatile unsigned long*)modereg = enable ? 0x10000:0; + _r10k_real_sync(sgimc); + + /* restore memory bank configuration */ + sgimc->mconfig1 = mconfig1; + + /* decrease WR_COL only after */ + sgimc->cmacc = cmacc; + _r10k_real_sync(sgimc); + + if (-1 == oldstate) + oldstate = (oldcmacc & 0xf) > 4; + + tmp = oldstate; + oldstate = enable; + _r10k_real_sync(sgimc); + + spin_unlock_irqrestore(&lock, flags); + return tmp; +} +#endif + +unsigned long ip2628_enable_ucmem (void) +{ +#if defined(CONFIG_SGI_IP28) || defined(CONFIG_SGI_IP26) + if (!sgimc) + sgimc = (struct sgimc_regs *) + ioremap(SGIMC_BASE, sizeof(struct sgimc_regs)); + return ip28_set_ucmem(sgimc,1); +#else + return 0; +#endif +} + +void ip2628_return_ucmem ( unsigned long oldstate ) +{ +#if defined(CONFIG_SGI_IP28) || defined(CONFIG_SGI_IP26) + if (!sgimc) + sgimc = (struct sgimc_regs *) + ioremap(SGIMC_BASE, sizeof(struct sgimc_regs)); + ip28_set_ucmem(sgimc,!!oldstate); +#else + (void)oldstate; +#endif +} +/* + * Revision 1.12, Tue Nov 18 05:15:20 2003 + * Jun 2004/2005 pf - IP28 + */ diff -Nur linux-git/arch/mips/sgi-ip22/ip22-setup.c linux-git-mit-R10k-patches/arch/mips/sgi-ip22/ip22-setup.c --- linux-git/arch/mips/sgi-ip22/ip22-setup.c 2005-10-15 16:01:07.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/sgi-ip22/ip22-setup.c 2005-10-16 13:21:56.000000000 +0200 @@ -119,6 +119,34 @@ } } #endif +#if defined(CONFIG_FB_IMPACT) || defined(CONFIG_SGI_IP28) + { + /* Get graphics info before it is overwritten... + * E.g. @ 9000000020f02f78: ffffffff9fc6d770,900000001f000000 + */ + ULONG* (*__vec)(void) = (typeof(__vec)) +#ifdef CONFIG_ARC64 + ((ULONG*)PROMBLOCK->pvector)[8]; +#else + (long) ((int*)PROMBLOCK->pvector)[8]; +#endif + ULONG *gfxinfo = (*__vec)(); + ULONG a = gfxinfo[1]; + + if ((a & 0xffffffff80000000L) == 0xffffffff80000000L) + sgi_gfxaddr = a & (6L<<28) ? 0:CPHYSADDR(a); /* CKSEG[01] */ + else if ((a & (1L<<63)) && (a & 0xb80000001fffffffL) == a) + sgi_gfxaddr = XPHYSADDR(a); /* lower 512MB of XKPHYS */ + else /* rubbish... */ + sgi_gfxaddr = 0; + if (sgi_gfxaddr < 0x1f000000) + sgi_gfxaddr = 0; + + printk(KERN_DEBUG "ARCS gfx info @ %08lx: %08lx,%08lx\n", + gfxinfo, gfxinfo[0], gfxinfo[1]); + printk(KERN_INFO "SGI graphics system @ 0x%08lx\n", sgi_gfxaddr); + } +#endif #if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE) { diff -Nur linux-git/arch/mips/sgi-ip22/ip28-berr.c linux-git-mit-R10k-patches/arch/mips/sgi-ip22/ip28-berr.c --- linux-git/arch/mips/sgi-ip22/ip28-berr.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-git-mit-R10k-patches/arch/mips/sgi-ip22/ip28-berr.c 2005-10-16 13:22:04.000000000 +0200 @@ -0,0 +1,600 @@ +/* + * ip28-berr.c: Bus error handling. + * + * Copyright (C) 2002, 2003 Ladislav Michl (ladis@linux-mips.org) + * Copyright (C) 2005 Peter Fuerst (pf@net.alphadv.de) - IP28 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int cpu_err_stat; /* Status reg for CPU */ +static unsigned int gio_err_stat; /* Status reg for GIO */ +static unsigned int cpu_err_addr; /* Error address reg for CPU */ +static unsigned int gio_err_addr; /* Error address reg for GIO */ +static unsigned int extio_stat; +static unsigned int hpc3_berr_stat; /* Bus error interrupt status */ + +struct hpc3_stat { + unsigned int addr; + unsigned int ctrl; + unsigned int cbp; + unsigned int ndptr; +}; + +static struct { + struct hpc3_stat pbdma[8]; + struct hpc3_stat scsi[2]; + struct hpc3_stat ethrx, ethtx; +} hpc3; + +static struct { + unsigned long err_addr; + struct { unsigned lo; unsigned hi; } /* Cache tag High/Low */ + tags[1][2], tagd[4][2], tagi[4][2]; /* Way 0/1 */ +} cache_tags; + +static inline void save_cache_tags(unsigned busaddr) +{ + unsigned long addr = CAC_BASE | busaddr; + unsigned i; + cache_tags.err_addr = addr; + + /* + * Starting with a bus-address, save secondary cache (indexed by + * PA[23..18:7..6]) tags first. + */ + addr &= ~1L; + #define tag cache_tags.tags[0] + cache_op(Index_Load_Tag_S, addr); + tag[0].lo = read_c0_taglo(); /* PA[35:18], VA[13:12] */ + tag[0].hi = read_c0_taghi(); /* PA[39:36] */ + cache_op(Index_Load_Tag_S, addr | 1L); + tag[1].lo = read_c0_taglo(); /* PA[35:18], VA[13:12] */ + tag[1].hi = read_c0_taghi(); /* PA[39:36] */ + #undef tag + + /* + * Save all primary data cache (indexed by VA[13:5]) tags which + * might fit to this bus-address, knowing that VA[11:0] == PA[11:0]. + * Saving all tags and evaluating them later is easier and safer + * than relying on VA[13:12] from the secondary cache tags to pick + * matching primary tags here already. + */ + addr &= (0xffL << 56) | ((1 << 12) - 1); + #define tag cache_tags.tagd[i] + for (i = 0; i < 4; ++i, addr += (1 << 12)) + { cache_op(Index_Load_Tag_D, addr); + tag[0].lo = read_c0_taglo(); /* PA[35:12] */ + tag[0].hi = read_c0_taghi(); /* PA[39:36] */ + cache_op(Index_Load_Tag_D, addr | 1L); + tag[1].lo = read_c0_taglo(); /* PA[35:12] */ + tag[1].hi = read_c0_taghi(); /* PA[39:36] */ + } + #undef tag + + /* + * Save primary instruction cache (indexed by VA[13:6]) tags + * the same way. + */ + addr &= (0xffL << 56) | ((1 << 12) - 1); + #define tag cache_tags.tagi[i] + for (i = 0; i < 4; ++i, addr += (1 << 12)) + { cache_op(Index_Load_Tag_I, addr); + tag[0].lo = read_c0_taglo(); /* PA[35:12] */ + tag[0].hi = read_c0_taghi(); /* PA[39:36] */ + cache_op(Index_Load_Tag_I, addr | 1L); + tag[1].lo = read_c0_taglo(); /* PA[35:12] */ + tag[1].hi = read_c0_taghi(); /* PA[39:36] */ + } + #undef tag +} + +#define GIO_ERRMASK 0xff00 +#define CPU_ERRMASK 0x3f00 + +static void save_and_clear_buserr(void) +{ + unsigned i; + + /* save status registers */ + cpu_err_addr = sgimc->cerr; + cpu_err_stat = sgimc->cstat; + gio_err_addr = sgimc->gerr; + gio_err_stat = sgimc->gstat; + //BUG_ON(!ip22_is_fullhouse()); + extio_stat = sgioc->extio; + hpc3_berr_stat = hpc3c0->bestat; + + hpc3.scsi[0].addr = &hpc3c0->scsi_chan0; + hpc3.scsi[0].ctrl = hpc3c0->scsi_chan0.ctrl; /* HPC3_SCTRL_ACTIVE ? */ + hpc3.scsi[0].cbp = hpc3c0->scsi_chan0.cbptr; + hpc3.scsi[0].ndptr = hpc3c0->scsi_chan0.ndptr; + + hpc3.scsi[1].addr = &hpc3c0->scsi_chan1; + hpc3.scsi[1].ctrl = hpc3c0->scsi_chan1.ctrl; /* HPC3_SCTRL_ACTIVE ? */ + hpc3.scsi[1].cbp = hpc3c0->scsi_chan1.cbptr; + hpc3.scsi[1].ndptr = hpc3c0->scsi_chan1.ndptr; + + hpc3.ethrx.addr = &hpc3c0->ethregs.rx_cbptr; + hpc3.ethrx.ctrl = hpc3c0->ethregs.rx_ctrl; /* HPC3_ERXCTRL_ACTIVE ? */ + hpc3.ethrx.cbp = hpc3c0->ethregs.rx_cbptr; + hpc3.ethrx.ndptr = hpc3c0->ethregs.rx_ndptr; + + hpc3.ethtx.addr = &hpc3c0->ethregs.tx_cbptr; + hpc3.ethtx.ctrl = hpc3c0->ethregs.tx_ctrl; /* HPC3_ETXCTRL_ACTIVE ? */ + hpc3.ethtx.cbp = hpc3c0->ethregs.tx_cbptr; + hpc3.ethtx.ndptr = hpc3c0->ethregs.tx_ndptr; + + for (i = 0; i < 8; ++i) { + /* HPC3_PDMACTRL_ISACT ? */ + hpc3.pbdma[i].addr = &hpc3c0->pbdma[i]; + hpc3.pbdma[i].ctrl = hpc3c0->pbdma[i].pbdma_ctrl; + hpc3.pbdma[i].cbp = hpc3c0->pbdma[i].pbdma_bptr; + hpc3.pbdma[i].ndptr = hpc3c0->pbdma[i].pbdma_dptr; + } + i = 0; + if (gio_err_stat & CPU_ERRMASK) + i = gio_err_addr; + if (cpu_err_stat & CPU_ERRMASK) + i = cpu_err_addr; + save_cache_tags(i); + + sgimc->cstat = sgimc->gstat = 0; +} + +static void print_cache_tags(void) +{ + unsigned i, scb, scw; + + printk(KERN_ERR "Cache tags @ %08x:\n", (unsigned)cache_tags.err_addr); + + /* PA[31:12] shifted to PTag0 (PA[35:12]) format */ + scw = (cache_tags.err_addr >> 4) & 0x0fffff00; + + scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 5) - 1); + for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */ + if ((cache_tags.tagd[i][0].lo & 0x0fffff00) != scw && + (cache_tags.tagd[i][1].lo & 0x0fffff00) != scw) + continue; + printk(KERN_ERR "D: 0: %08x %08x, 1: %08x %08x (VA[13:5] %04x)\n", + cache_tags.tagd[i][0].hi, cache_tags.tagd[i][0].lo, + cache_tags.tagd[i][1].hi, cache_tags.tagd[i][1].lo, + scb | (1 << 12)*i); + } + scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 6) - 1); + for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */ + if ((cache_tags.tagi[i][0].lo & 0x0fffff00) != scw && + (cache_tags.tagi[i][1].lo & 0x0fffff00) != scw) + continue; + printk(KERN_ERR "I: 0: %08x %08x, 1: %08x %08x (VA[13:6] %04x)\n", + cache_tags.tagi[i][0].hi, cache_tags.tagi[i][0].lo, + cache_tags.tagi[i][1].hi, cache_tags.tagi[i][1].lo, + scb | (1 << 12)*i); + } + i = read_c0_config(); + scb = i & (1 << 13) ? 7:6; /* scblksize = 2^[7..6] */ + scw = ((i >> 16) & 7) + 19 - 1; /* scwaysize = 2^[24..19] / 2 */ + + i = ((1 << scw) - 1) & ~((1 << scb) - 1); + printk(KERN_ERR "S: 0: %08x %08x, 1: %08x %08x (PA[%u:%u] %05x)\n", + cache_tags.tags[0][0].hi, cache_tags.tags[0][0].lo, + cache_tags.tags[0][1].hi, cache_tags.tags[0][1].lo, + scw-1, scb, i & (unsigned)cache_tags.err_addr); +} + +static void print_buserr(void) +{ + int error = 0; + + if (extio_stat & EXTIO_MC_BUSERR) { + printk(KERN_ERR "MC Bus Error\n"); + error |= 1; + } + if (extio_stat & EXTIO_HPC3_BUSERR) { + printk(KERN_ERR "HPC3 Bus Error 0x%x:\n", + hpc3_berr_stat, + (hpc3_berr_stat & HPC3_BESTAT_PIDMASK) >> + HPC3_BESTAT_PIDSHIFT, + (hpc3_berr_stat & HPC3_BESTAT_CTYPE) ? "PIO" : "DMA", + hpc3_berr_stat & HPC3_BESTAT_BLMASK); + error |= 2; + } + if (extio_stat & EXTIO_EISA_BUSERR) { + printk(KERN_ERR "EISA Bus Error\n"); + error |= 4; + } + if (cpu_err_stat & CPU_ERRMASK) { + printk(KERN_ERR "CPU error 0x%x<%s%s%s%s%s%s> @ 0x%08x\n", + cpu_err_stat, + cpu_err_stat & SGIMC_CSTAT_RD ? "RD " : "", + cpu_err_stat & SGIMC_CSTAT_PAR ? "PAR " : "", + cpu_err_stat & SGIMC_CSTAT_ADDR ? "ADDR " : "", + cpu_err_stat & SGIMC_CSTAT_SYSAD_PAR ? "SYSAD " : "", + cpu_err_stat & SGIMC_CSTAT_SYSCMD_PAR ? "SYSCMD " : "", + cpu_err_stat & SGIMC_CSTAT_BAD_DATA ? "BAD_DATA " : "", + cpu_err_addr); + error |= 8; + } + if (gio_err_stat & GIO_ERRMASK) { + printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x%08x\n", + gio_err_stat, + gio_err_stat & SGIMC_GSTAT_RD ? "RD " : "", + gio_err_stat & SGIMC_GSTAT_WR ? "WR " : "", + gio_err_stat & SGIMC_GSTAT_TIME ? "TIME " : "", + gio_err_stat & SGIMC_GSTAT_PROM ? "PROM " : "", + gio_err_stat & SGIMC_GSTAT_ADDR ? "ADDR " : "", + gio_err_stat & SGIMC_GSTAT_BC ? "BC " : "", + gio_err_stat & SGIMC_GSTAT_PIO_RD ? "PIO_RD " : "", + gio_err_stat & SGIMC_GSTAT_PIO_WR ? "PIO_WR " : "", + gio_err_addr); + error |= 16; + } + if (!error) + printk(KERN_ERR "MC: Hmm, didn't find any error condition.\n"); + else { + printk(KERN_ERR "CP0: config %08x, " + "MC: cpuctrl0/1: %08x/%05x, giopar: %04x\n" + "MC: cpu/gio_memacc: %08x/%05x, memcfg0/1: %08x/%08x\n", + read_c0_config(), + sgimc->cpuctrl0, sgimc->cpuctrl0, sgimc->giopar, + sgimc->cmacc, sgimc->gmacc, + sgimc->mconfig0, sgimc->mconfig1); + print_cache_tags(); + } +} + +/* + * Try to find out, whether the bus error is caused by the instruction + * at EPC, otherwise we have an asynchronous error. + * + * Doc1: "MIPS IV Instruction Set", Rev 3.2 (SGI 007-2597-001) + * Doc2: "MIPS R10000 Microporcessor User's Manual", Ver 2.0 (SGI 007-2490-001) + * Doc3: "MIPS R4000 Microporcessor User's Manual", 2nd Ed. (SGI 007-2489-001) + */ + +#define JMP_INDEX26_OP 1 +#define JMP_REGISTER_OP 2 +#define JMP_PCREL16_OP 3 +#define BASE_OFFSET_OP 4 +#define BASE_IDXREG_OP 5 + +/* Match virtual address in an insn with physical error address */ + +static int match_addr(unsigned paddr, unsigned long vaddr) +{ + unsigned uaddr; + + if ((vaddr & 0xffffffff80000000L) == 0xffffffff80000000L) + uaddr = (unsigned) CPHYSADDR(vaddr); + else if ((vaddr >> 62) == 2) + uaddr = (unsigned) XPHYSADDR(vaddr); + else + { unsigned long eh = vaddr & ~0x1fffL; + eh |= read_c0_entryhi() & 0xff; + write_c0_entryhi(eh); + tlb_probe(); + if (read_c0_index() & 0x80000000) + return 0; + tlb_read(); + if (vaddr & (1L << PAGE_SHIFT)) + uaddr = (unsigned) read_c0_entrylo1(); + else + uaddr = (unsigned) read_c0_entrylo0(); + uaddr <<= 6; + uaddr &= ~PAGE_MASK; + uaddr |= vaddr & PAGE_MASK; + } + return ((uaddr & ~0x7f) == (paddr & ~0x7f)); +} + +/* Check, which kind of memory reference is triggered by `insn' */ + +static int check_special(unsigned insn) +{ + /* See Doc1, page A-180 */ + unsigned func = insn & 0x3f; + + if (8 == func || 8+1 == func) /* JR, JALR */ + return JMP_REGISTER_OP; + + return 0; +} + +static int check_regimm(unsigned insn) +{ + /* See Doc1, page A-180 */ + unsigned rt = (insn >> 19) & 3; /* bits 20..19[..16] */ + + /* BLTZ, BGEZ, BLTZL, BBGEZL || BLTZAL, BGEZAL, BLTZALL, BBGEZALL */ + if (!rt || 2 == rt) + return JMP_PCREL16_OP; + + return 0; +} + +static int check_cop0(unsigned insn) +{ + /* See Doc2, pages 287 ff., 187 ff. */ + if ((insn >> 26) == 5*8+7) /* CACHE */ + switch ((insn >> 16) & 0x1f) { + case Index_Writeback_Inv_D: + case Hit_Writeback_Inv_D: + case Index_Writeback_Inv_S: + case Hit_Writeback_Inv_S: + return BASE_OFFSET_OP; + } + return 0; +} + +static int check_cop1(unsigned insn) +{ + /* See Doc1, pages B-108 ff. */ + unsigned fmt = (insn >> 21) & 0x1f; /* bits 25..21 */ + + if (8 == fmt) /* BC1* */ + return JMP_PCREL16_OP; + + return 0; +} + +static int check_cop1x(unsigned insn) +{ + /* See Doc1, pages B-108 ff. */ + switch (insn & 0x3f) { + case 0: /* LWXC1 */ + case 1: /* LDXC1 */ + case 8: /* SWXC1 */ + case 8+1: /* SDXC1 */ + return BASE_IDXREG_OP; + } + return 0; +} + +static int check_plain(unsigned insn) +{ + /* See Doc1, page A-180 */ + unsigned opcode = insn >> 26; + + if (2 == opcode || 3 == opcode) /* J, JAL */ + return JMP_INDEX26_OP; + + if (4 <= opcode && opcode <= 7 || /* BEQ, BNE, BLEZ, BGTZ */ + 4+2*8 <= opcode && opcode <= 7+2*8) /* BEQL, BNEL, BLEZL, BGTZL */ + return JMP_PCREL16_OP; + + if (6*8+3 == opcode) /* PREF */ + return 0; + + if (3*8+2 == opcode || 3*8+3 == opcode || /* LDL, LDR */ + 4*8 <= opcode) /* misc. LOAD, STORE */ + return BASE_OFFSET_OP; + + return 0; +} + +/* Check, whether the insn at EPC causes a memory access at `paddr' */ + +static int check_addr_in_insn(unsigned paddr, struct pt_regs *regs) +{ + unsigned long epc; + unsigned insn; + int typ; + + epc = regs->cp0_cause & CAUSEF_BD ? regs->cp0_epc:regs->cp0_epc+4; + + /* show_code() from kernel/traps.c */ + if (__get_user(insn, (unsigned*) epc)) + return 1; + + /* See Doc1, pages A-180, B-108 ff. */ + switch (insn >> 26) + { case 0: + typ = check_special(insn); + break; + case 1: + typ = check_regimm(insn); + break; + case 2*8: /* COP0 */ + case 5*8+7: /* CACHE */ + typ = check_cop0(insn); + break; + case 2*8+1: + typ = check_cop1(insn); + break; + case 2*8+3: + typ = check_cop1x(insn); + break; + default: + typ = check_plain(insn); + } + switch (typ) + { unsigned long a; + case JMP_INDEX26_OP: + a = (regs->cp0_epc + 4) & ~0xfffffff; + a |= (insn & 0x3ffffff) << 2; + return match_addr(paddr, a); + case JMP_REGISTER_OP: + a = regs->regs[(insn >> 21) & 0x1f]; + return match_addr(paddr, a); + case JMP_PCREL16_OP: + a = regs->cp0_epc + 4 + ((insn & 0xffff) << 2); + return match_addr(paddr, a); + case BASE_OFFSET_OP: + a = regs->regs[(insn >> 21) & 0x1f] + (insn & 0xffff); + return match_addr(paddr, a); + case BASE_IDXREG_OP: + a = regs->regs[(insn >> 21) & 0x1f]; + a += regs->regs[(insn >> 16) & 0x1f]; + return match_addr(paddr, a); + case 0: + return 0; + } + /* Assume it would be too dangerous to continue ... */ + return 1; +} + +/* Check, whether MC's (virtual) DMA address caused the bus error. */ + +static int check_vdma_memaddr (void) +{ + /* Deferred until needed. */ + return 0; +} + +static int check_vdma_gioaddr (void) +{ + /* Deferred until needed. */ + return 0; +} + +static inline const char *cause_excode_text(int cause) +{ + static const char *txt[32] = + { "Interrupt", + "TLB modification", + "TLB (load or instruction fetch)", + "TLB (store)", + "Address error (load or instruction fetch)", + "Address error (store)", + "Bus error (instruction fetch)", + "Bus error (data: load or store)", + "Syscall", + "Breakpoint", + "Reserved instruction", + "Coprocessor unusable", + "Arithmetic Overflow", + "Trap", + "14", + "Floating-Point", + "16", "17", "18", "19", "20", "21", "22", + "Watch Hi/Lo", + "24", "25", "26", "27", "28", "29", "30", "31", + }; + return txt[(cause & 0x7c) >> 2]; +} + +/* + * MC sends an interrupt whenever bus or parity errors occur. In addition, + * if the error happened during a CPU read, it also asserts the bus error + * pin on the R4K. Code in bus error handler save the MC bus error registers + * and then clear the interrupt when this happens. + */ + +static int ip28_be_interrupt(struct pt_regs *regs) +{ + const int field = 2 * sizeof(unsigned long); + unsigned i; + + save_and_clear_buserr(); + print_buserr(); + printk(KERN_ALERT "%s, epc == %0*lx, ra == %0*lx\n", + cause_excode_text(regs->cp0_cause), + field, regs->cp0_epc, field, regs->regs[31]); + /* + * Try to find out, whether we got here by a mispredicted speculative + * load/store operation. If so, it's not fatal, we can go on. + */ + /* Any cause other than "Interrupt" (ExcCode 0) is fatal. */ + if (regs->cp0_cause & CAUSEF_EXCCODE) + return MIPS_BE_FATAL; + + /* Any cause other than "Bus error interrupt" (IP6) is weird. */ + if ((regs->cp0_cause & CAUSEF_IP6) != CAUSEF_IP6) + return MIPS_BE_FATAL; + + if (extio_stat & (EXTIO_HPC3_BUSERR | EXTIO_EISA_BUSERR)) + return MIPS_BE_FATAL; + + /* Any state other than "Memory bus error" is fatal. */ + if (cpu_err_stat & CPU_ERRMASK & ~SGIMC_CSTAT_ADDR) + return MIPS_BE_FATAL; + + /* Any state other than "GIO transaction bus timed out" is fatal. */ + if (gio_err_stat & GIO_ERRMASK & ~SGIMC_GSTAT_TIME) + return MIPS_BE_FATAL; + + /* Finding `cpu_err_addr' in the insn at EPC is fatal. */ + if ((cpu_err_stat & CPU_ERRMASK) && check_addr_in_insn(cpu_err_addr,regs)) + return MIPS_BE_FATAL; + + /* Finding `gio_err_addr' in the insn at EPC is fatal. */ + if ((gio_err_stat & GIO_ERRMASK) && check_addr_in_insn(gio_err_addr,regs)) + return MIPS_BE_FATAL; + /* + * Now we have an asynchronous bus error, speculatively or DMA caused. + * Need to search all DMA descriptors for the error address. + */ + for (i = 0; i < sizeof(hpc3)/sizeof(struct hpc3_stat); ++i) { + struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i; + if ((cpu_err_stat & CPU_ERRMASK) && + (cpu_err_addr == hp->ndptr || cpu_err_addr == hp->cbp)) + break; + if ((gio_err_stat & GIO_ERRMASK) && + (gio_err_addr == hp->ndptr || gio_err_addr == hp->cbp)) + break; + } + if (i < sizeof(hpc3)/sizeof(struct hpc3_stat)) { + struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i; + printk(KERN_ERR "at DMA addresses: HPC3 @ %08lx:" + " ctl %08x, ndp %08x, cbp %08x\n", + CPHYSADDR(hp->addr), hp->ctrl, hp->ndptr, hp->cbp); + return MIPS_BE_FATAL; + } + /* Check MC's virtual DMA stuff. */ + if ( check_vdma_memaddr() ) { + printk(KERN_ERR "at GIO DMA: mem address 0x%08x.\n", + sgimc->maddronly); + return MIPS_BE_FATAL; + } + if ( check_vdma_gioaddr() ) { + printk(KERN_ERR "at GIO DMA: gio address 0x%08x.\n", + sgimc->gmaddronly); + return MIPS_BE_FATAL; + } + /* A speculative bus error... */ + printk(KERN_ERR "discarded!\n"); + return MIPS_BE_DISCARD; +} + +void ip22_be_interrupt(int irq, struct pt_regs *regs) +{ + if (ip28_be_interrupt(regs) != MIPS_BE_DISCARD) { + /* Assume it would be too dangerous to continue ... */ + die_if_kernel("Oops", regs); + force_sig(SIGBUS, current); + } else { + show_regs(regs); + show_code((unsigned int *) regs->cp0_epc); + } +} + +static int ip28_be_handler(struct pt_regs *regs, int is_fixup) +{ + /* + * We arrive here only in the unusual case of do_be() invocation, + * i.e. by a bus error exception without a bus error interrupt. + */ + if (is_fixup) { + save_and_clear_buserr(); + return MIPS_BE_FIXUP; + } + return ip28_be_interrupt(regs); +} + +void __init ip22_be_init(void) +{ + board_be_handler = ip28_be_handler; +} diff -Nur linux-git/arch/mips/sgi-ip22/Makefile linux-git-mit-R10k-patches/arch/mips/sgi-ip22/Makefile --- linux-git/arch/mips/sgi-ip22/Makefile 2005-10-15 16:01:07.000000000 +0200 +++ linux-git-mit-R10k-patches/arch/mips/sgi-ip22/Makefile 2005-10-16 13:21:56.000000000 +0200 @@ -3,9 +3,13 @@ # under Linux. # -obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-irq.o ip22-berr.o \ +obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-irq.o \ ip22-time.o ip22-nvram.o ip22-reset.o ip22-setup.o +obj-$(CONFIG_SGI_IP28) += ip28-berr.o +obj-$(CONFIG_SGI_IP22) += ip22-berr.o obj-$(CONFIG_EISA) += ip22-eisa.o EXTRA_AFLAGS := $(CFLAGS) + +# Revision 1.19, Tue Nov 18 05:15:20 2003 diff -Nur linux-git/drivers/char/Kconfig linux-git-mit-R10k-patches/drivers/char/Kconfig --- linux-git/drivers/char/Kconfig 2005-10-15 16:01:11.000000000 +0200 +++ linux-git-mit-R10k-patches/drivers/char/Kconfig 2005-10-16 13:21:56.000000000 +0200 @@ -762,7 +762,7 @@ config SGI_DS1286 tristate "SGI DS1286 RTC support" - depends on SGI_IP22 + depends on (SGI_IP22 || SGI_IP28) help If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff -Nur linux-git/drivers/char/tty_io.c linux-git-mit-R10k-patches/drivers/char/tty_io.c --- linux-git/drivers/char/tty_io.c 2005-10-15 16:01:12.000000000 +0200 +++ linux-git-mit-R10k-patches/drivers/char/tty_io.c 2005-10-16 13:21:56.000000000 +0200 @@ -744,6 +744,7 @@ void tty_wakeup(struct tty_struct *tty) { + if (tty) { struct tty_ldisc *ld; if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { @@ -755,6 +756,7 @@ } } wake_up_interruptible(&tty->write_wait); + } } EXPORT_SYMBOL_GPL(tty_wakeup); @@ -3014,3 +3016,7 @@ return 0; } module_init(tty_init); +/* + * Revision 1.133, Tue Apr 19 00:39:02 2005 + * Wed Jan 5 02:16:41 2005 + */ diff -Nur linux-git/drivers/char/watchdog/Kconfig linux-git-mit-R10k-patches/drivers/char/watchdog/Kconfig --- linux-git/drivers/char/watchdog/Kconfig 2005-10-15 16:01:12.000000000 +0200 +++ linux-git-mit-R10k-patches/drivers/char/watchdog/Kconfig 2005-10-16 13:21:56.000000000 +0200 @@ -427,7 +427,7 @@ config INDYDOG tristate "Indy/I2 Hardware Watchdog" - depends on WATCHDOG && SGI_IP22 + depends on WATCHDOG && (SGI_IP22 || SGI_IP28) help Hardwaredriver for the Indy's/I2's watchdog. This is a watchdog timer that will reboot the machine after a 60 second diff -Nur linux-git/drivers/input/serio/i8042.c linux-git-mit-R10k-patches/drivers/input/serio/i8042.c --- linux-git/drivers/input/serio/i8042.c 2005-10-15 16:01:13.000000000 +0200 +++ linux-git-mit-R10k-patches/drivers/input/serio/i8042.c 2005-10-16 13:21:56.000000000 +0200 @@ -656,7 +656,13 @@ if (i8042_command(¶m, I8042_CMD_AUX_ENABLE)) return -1; if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS)) +#ifdef CONFIG_SGI_IP28 + /* Seems we need to invert the CTR_AUXDIS-test on this machine: + * CMD_AUX_DISABLE -> rctr 0xcf, CMD_AUX_ENABLE -> rctr 0xef */ + printk(KERN_WARNING "Failed to enable AUX port, but continuing anyway... ;)\n"); +#else return -1; +#endif /* * Disable the interface. diff -Nur linux-git/drivers/input/serio/i8042.h linux-git-mit-R10k-patches/drivers/input/serio/i8042.h --- linux-git/drivers/input/serio/i8042.h 2005-10-15 16:01:13.000000000 +0200 +++ linux-git-mit-R10k-patches/drivers/input/serio/i8042.h 2005-10-16 13:21:56.000000000 +0200 @@ -17,7 +17,7 @@ #if defined(CONFIG_MACH_JAZZ) #include "i8042-jazzio.h" -#elif defined(CONFIG_SGI_IP22) +#elif defined(CONFIG_SGI_IP22) || defined(CONFIG_SGI_IP28) #include "i8042-ip22io.h" #elif defined(CONFIG_PPC) #include "i8042-ppcio.h" @@ -131,3 +131,7 @@ #endif #endif /* _I8042_H */ +/* + * Revision 1.10, Tue Apr 19 00:50:01 2005 + * Tue Dec 7 19:43:43 2004 - IP28 + */ diff -Nur linux-git/drivers/net/Kconfig linux-git-mit-R10k-patches/drivers/net/Kconfig --- linux-git/drivers/net/Kconfig 2005-10-15 16:01:16.000000000 +0200 +++ linux-git-mit-R10k-patches/drivers/net/Kconfig 2005-10-16 13:21:56.000000000 +0200 @@ -1728,7 +1728,7 @@ config SGISEEQ tristate "SGI Seeq ethernet controller support" - depends on NET_ETHERNET && SGI_IP22 + depends on NET_ETHERNET && (SGI_IP22 || SGI_IP26 || SGI_IP28) help Say Y here if you have an Seeq based Ethernet network card. This is used in many Silicon Graphics machines. diff -Nur linux-git/drivers/scsi/Kconfig linux-git-mit-R10k-patches/drivers/scsi/Kconfig --- linux-git/drivers/scsi/Kconfig 2005-10-15 16:01:20.000000000 +0200 +++ linux-git-mit-R10k-patches/drivers/scsi/Kconfig 2005-10-16 13:21:56.000000000 +0200 @@ -249,7 +249,7 @@ config SGIWD93_SCSI tristate "SGI WD93C93 SCSI Driver" - depends on SGI_IP22 && SCSI + depends on (SGI_IP22 || SGI_IP26 || SGI_IP28) && SCSI help If you have a Western Digital WD93 SCSI controller on an SGI MIPS system, say Y. Otherwise, say N. diff -Nur linux-git/drivers/scsi/wd33c93.c linux-git-mit-R10k-patches/drivers/scsi/wd33c93.c --- linux-git/drivers/scsi/wd33c93.c 2005-10-15 16:01:23.000000000 +0200 +++ linux-git-mit-R10k-patches/drivers/scsi/wd33c93.c 2005-10-16 13:21:56.000000000 +0200 @@ -1460,7 +1460,7 @@ const wd33c93_regs regs = hostdata->regs; uchar sr; -#ifdef CONFIG_SGI_IP22 +#if defined(CONFIG_SGI_IP22) || defined(CONFIG_SGI_IP28) { int busycount = 0; extern void sgiwd93_reset(unsigned long); diff -Nur linux-git/drivers/serial/ip22zilog.c linux-git-mit-R10k-patches/drivers/serial/ip22zilog.c --- linux-git/drivers/serial/ip22zilog.c 2005-10-15 16:01:24.000000000 +0200 +++ linux-git-mit-R10k-patches/drivers/serial/ip22zilog.c 2005-10-16 13:44:41.000000000 +0200 @@ -1015,9 +1015,9 @@ spin_lock_irqsave(&up->port.lock, flags); for (i = 0; i < count; i++, s++) { - ip22zilog_put_char(channel, *s); if (*s == 10) ip22zilog_put_char(channel, 13); + ip22zilog_put_char(channel, *s); } udelay(2); spin_unlock_irqrestore(&up->port.lock, flags); diff -Nur linux-git/drivers/serial/Kconfig linux-git-mit-R10k-patches/drivers/serial/Kconfig --- linux-git/drivers/serial/Kconfig 2005-10-15 16:01:24.000000000 +0200 +++ linux-git-mit-R10k-patches/drivers/serial/Kconfig 2005-10-16 13:21:56.000000000 +0200 @@ -555,16 +555,18 @@ config SERIAL_IP22_ZILOG tristate "IP22 Zilog8530 serial support" - depends on SGI_IP22 + depends on (SGI_IP22 || SGI_IP28) select SERIAL_CORE + default y if SGI_IP28 help - This driver supports the Zilog8530 serial ports found on SGI IP22 + This driver supports the Zilog8530 serial ports found on SGI IP22-IP28 systems. Say Y or M if you want to be able to these serial ports. config SERIAL_IP22_ZILOG_CONSOLE - bool "Console on IP22 Zilog8530 serial port" + bool "Console on IP22/28 Zilog8530 serial port" depends on SERIAL_IP22_ZILOG=y select SERIAL_CORE_CONSOLE + default y if SGI_IP28 config V850E_UART bool "NEC V850E on-chip UART support" diff -Nur linux-git/drivers/video/impact.c linux-git-mit-R10k-patches/drivers/video/impact.c --- linux-git/drivers/video/impact.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-git-mit-R10k-patches/drivers/video/impact.c 2005-10-16 13:22:04.000000000 +0200 @@ -0,0 +1,906 @@ +/* + * linux/drivers/video/impactsr.c -- SGI Octane MardiGras (IMPACTSR) graphics + * linux/drivers/video/impact.c -- SGI Indigo2 MardiGras (IMPACT) graphics + * + * Copyright (c) 2004 by Stanislaw Skowronek + * Adapted to Indigo2 by pf, 2005 + * + * Based on linux/drivers/video/skeletonfb.c + * + * This driver, as most of the IP30 (SGI Octane) port, is a result of massive + * amounts of reverse engineering and trial-and-error. If anyone is interested + * in helping with it, please contact me: . + * + * The basic functions of this driver are filling and blitting rectangles. + * To achieve the latter, two DMA operations are used on Impact. It is unclear + * to me, why is it so, but even Xsgi (the IRIX X11 server) does it this way. + * It seems that fb->fb operations are not operational on these cards. + * + * For this purpose, a kernel DMA pool is allocated (pool number 0). This pool + * is (by default) 64kB in size. An ioctl could be used to set the value at + * run-time. Applications can use this pool, however proper locking has to be + * guaranteed. Kernel should be locked out from this pool by an ioctl. + * + * The IMPACTSR is quite well worked-out currently, except for the Geometry + * Engines (GE11). Any information about use of those devices would be very + * useful. It would enable a Linux OpenGL driver, as most of OpenGL calls are + * supported directly by the hardware. So far, I can't initialize the GE11. + * Verification of microcode crashes the graphics. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include